diff --git a/airtime_mvc/application/controllers/PreferenceController.php b/airtime_mvc/application/controllers/PreferenceController.php index 83bd44748..54a5ef8f4 100644 --- a/airtime_mvc/application/controllers/PreferenceController.php +++ b/airtime_mvc/application/controllers/PreferenceController.php @@ -198,6 +198,7 @@ class PreferenceController extends Zend_Controller_Action } $values['icecast_vorbis_metadata'] = $form->getValue('icecast_vorbis_metadata'); + $values['output_sound_device_type'] = $form->getValue('output_sound_device_type'); } if(!$error){ Application_Model_StreamSetting::setStreamSetting($values); diff --git a/airtime_mvc/application/controllers/ScheduleController.php b/airtime_mvc/application/controllers/ScheduleController.php index b22cb5659..4a87ace77 100644 --- a/airtime_mvc/application/controllers/ScheduleController.php +++ b/airtime_mvc/application/controllers/ScheduleController.php @@ -46,11 +46,11 @@ class ScheduleController extends Zend_Controller_Action $this->view->headScript()->appendFile($baseUrl.'/js/fullcalendar/fullcalendar.js','text/javascript'); $this->view->headScript()->appendFile($baseUrl.'/js/timepicker/jquery.ui.timepicker-0.0.6.js','text/javascript'); $this->view->headScript()->appendFile($baseUrl.'/js/colorpicker/js/colorpicker.js','text/javascript'); - + //full-calendar-functions.js requires this variable, so that datePicker widget can be offset to server time instead of client time $this->view->headScript()->appendScript("var timezoneOffset = ".date("Z")."; //in seconds"); $this->view->headScript()->appendFile($baseUrl.'/js/airtime/schedule/full-calendar-functions.js','text/javascript'); - + $this->view->headScript()->appendFile($baseUrl.'/js/airtime/schedule/add-show.js','text/javascript'); $this->view->headScript()->appendFile($baseUrl.'/js/airtime/schedule/schedule.js','text/javascript'); $this->view->headScript()->appendFile($baseUrl.'/js/meioMask/jquery.meio.mask.js','text/javascript'); @@ -385,14 +385,6 @@ class ScheduleController extends Zend_Controller_Action $start_timestamp = $show->getShowInstanceStart(); $end_timestamp = $show->getShowInstanceEnd(); - //check to make sure show doesn't overlap. - if(Application_Model_Show::getShows(new DateTime($start_timestamp, new DateTimeZone("UTC")), - new DateTime($end_timestamp, new DateTimeZone("UTC")), - array($showInstanceId))) { - $this->view->error = "cannot schedule an overlapping show."; - return; - } - $dateInfo_s = getDate(strtotime(Application_Model_DateHelper::ConvertToLocalDateTimeString($start_timestamp))); $dateInfo_e = getDate(strtotime(Application_Model_DateHelper::ConvertToLocalDateTimeString($end_timestamp))); @@ -574,7 +566,7 @@ class ScheduleController extends Zend_Controller_Action $i = 1; foreach ($rebroadcastsAbsolute as $rebroadcast){ $rebroadcastAbsoluteFormValues["add_show_rebroadcast_date_absolute_$i"] = $rebroadcast['start_date']; - $rebroadcastAbsoluteFormValues["add_show_rebroadcast_time_absolute_$i"] = Application_Model_DateHelper::removeSecondsFromTime($rebroadcast['start_time']); + $rebroadcastAbsoluteFormValues["add_show_rebroadcast_time_absolute_$i"] = $rebroadcast['start_time']; $i++; } $formAbsoluteRebroadcast->populate($rebroadcastAbsoluteFormValues); diff --git a/airtime_mvc/application/forms/StreamSetting.php b/airtime_mvc/application/forms/StreamSetting.php index c27eea568..afabcd9dd 100644 --- a/airtime_mvc/application/forms/StreamSetting.php +++ b/airtime_mvc/application/forms/StreamSetting.php @@ -25,6 +25,17 @@ class Application_Form_StreamSetting extends Zend_Form $output_sound_device->setAttrib("readonly", true); } $this->addElement($output_sound_device); + + $output_types = array("ALSA"=>"ALSA", "AO"=>"AO", "OSS"=>"OSS", "Portaudio"=>"Portaudio", "Pulseaudio"=>"Pulseaudio"); + $output_type = new Zend_Form_Element_Select('output_sound_device_type'); + $output_type->setLabel("Output Type") + ->setMultiOptions($output_types) + ->setValue($setting['output_sound_device_type']) + ->setDecorators(array('ViewHelper')); + if($setting['output_sound_device'] != "true"){ + $output_type->setAttrib("disabled", "disabled"); + } + $this->addElement($output_type); } $icecast_vorbis_metadata = new Zend_Form_Element_Checkbox('icecast_vorbis_metadata'); @@ -39,7 +50,8 @@ class Application_Form_StreamSetting extends Zend_Form } public function isValid($data){ - $this->populate(array("output_sound_device"=>$data['output_sound_device'], "icecast_vorbis_metadata"=>$data['icecast_vorbis_metadata'])); + $this->populate(array("output_sound_device"=>$data['output_sound_device'], "icecast_vorbis_metadata"=>$data['icecast_vorbis_metadata'], + "output_sound_device_type"=>$data['output_sound_device_type'])); return true; } } diff --git a/airtime_mvc/application/forms/StreamSettingSubForm.php b/airtime_mvc/application/forms/StreamSettingSubForm.php index 7be023f1b..f63825eb8 100644 --- a/airtime_mvc/application/forms/StreamSettingSubForm.php +++ b/airtime_mvc/application/forms/StreamSettingSubForm.php @@ -68,7 +68,6 @@ class Application_Form_StreamSettingSubForm extends Zend_Form_SubForm{ if($disable_all){ $bitrate->setAttrib("disabled", "disabled"); } - $this->addElement($type); $this->addElement($bitrate); $output = new Zend_Form_Element_Select('output'); diff --git a/airtime_mvc/application/models/Show.php b/airtime_mvc/application/models/Show.php index 765d17eda..5fb3ca624 100644 --- a/airtime_mvc/application/models/Show.php +++ b/airtime_mvc/application/models/Show.php @@ -105,6 +105,13 @@ class Application_Model_Show { return $res; } + //remove everything about this show. + public function deleteShow() + { + $show = CcShowQuery::create()->findPK($this->_showId); + $show->delete(); + } + public function resizeShow($deltaDay, $deltaMin) { global $CC_DBC; @@ -183,10 +190,10 @@ class Application_Model_Show { public function removeUncheckedDaysInstances($p_uncheckedDays) { global $CC_DBC; - + //need to convert local doftw to UTC doftw (change made for 2.0 since shows are stored in UTC) $daysRemovedUTC = array(); - + $showDays = CcShowDaysQuery::create() ->filterByDbShowId($this->getId()) ->find(); @@ -195,12 +202,12 @@ class Application_Model_Show { foreach($p_uncheckedDays as $day) { Logging::log($day); } - + foreach($showDays as $showDay) { Logging::log("Local show day is: {$showDay->getDbDay()}"); Logging::log("First show day is: {$showDay->getDbFirstShow()}"); Logging::log("Id show days is: {$showDay->getDbId()}"); - + if (in_array($showDay->getDbDay(), $p_uncheckedDays)) { $showDay->reload(); //Logging::log("Local show day is: {$showDay->getDbDay()}"); @@ -214,7 +221,7 @@ class Application_Model_Show { Logging::log("UTC show day is: {$startDay->format('w')}"); } } - + $uncheckedDaysImploded = implode(",", $daysRemovedUTC); $showId = $this->getId(); @@ -224,7 +231,7 @@ class Application_Model_Show { ." WHERE EXTRACT(DOW FROM starts) IN ($uncheckedDaysImploded)" ." AND starts > TIMESTAMP '$timestamp'" ." AND show_id = $showId"; - + Logging::log($sql); $CC_DBC->query($sql); @@ -278,22 +285,27 @@ class Application_Model_Show { global $CC_DBC; $showId = $this->getId(); - $sql = "SELECT date(starts) " - ."FROM cc_show_instances " - ."WHERE show_id = $showId " - ."AND record = 1 " - ."AND modified_instance != TRUE"; - $baseDate = $CC_DBC->GetOne($sql); - if (is_null($baseDate)){ - return array(); + $sql = "SELECT starts FROM cc_show_instances " + ."WHERE show_id = $showId AND rebroadcast = 1 " + ."ORDER BY starts"; + + $rebroadcasts = $CC_DBC->GetAll($sql); + + $rebroadcastsLocal = array(); + //get each rebroadcast show in cc_show_instances, convert to current timezone to get start date/time. + $i = 0; + foreach ($rebroadcasts as $show) { + $startDateTime = new DateTime($show["starts"], new DateTimeZone("UTC")); + $startDateTime->setTimezone(new DateTimeZone(date_default_timezone_get())); + + $rebroadcastsLocal[$i]["start_date"] = $startDateTime->format("Y-m-d"); + $rebroadcastsLocal[$i]["start_time"] = $startDateTime->format("H:i"); + + $i = $i + 1; } - $sql = "SELECT date(DATE '$baseDate' + day_offset::INTERVAL) as start_date, start_time FROM cc_show_rebroadcast " - ."WHERE show_id = $showId " - ."ORDER BY start_date"; - - return $CC_DBC->GetAll($sql); + return $rebroadcastsLocal; } /** @@ -815,21 +827,21 @@ class Application_Model_Show { $daysRemoved = array_diff($showDaysArray, $p_data['add_show_day_check']); if (count($daysRemoved) > 0){ - + $this->removeUncheckedDaysInstances($daysRemoved); } } - + if ($p_data['add_show_start_date'] != $this->getStartDate() || $p_data['add_show_start_time'] != $this->getStartTime()){ //start date/time has changed - + $newDate = strtotime($p_data['add_show_start_date']); $oldDate = strtotime($this->getStartDate()); if ($newDate > $oldDate){ $this->removeAllInstancesBeforeDate($p_data['add_show_start_date']); } - + $this->updateStartDateTime($p_data, $p_endDate); } } @@ -1224,8 +1236,10 @@ class Application_Model_Show { $showInstance->correctScheduleStartTimes(); } - self::createRebroadcastInstances($rebroadcasts, $currentUtcTimestamp, $show_id, $show_instance_id, $start, $duration, $timezone); - + //don't create rebroadcasts for a deleted recorded show. + if ($ccShowInstance->getDbModifiedInstance() == false) { + self::createRebroadcastInstances($rebroadcasts, $currentUtcTimestamp, $show_id, $show_instance_id, $start, $duration, $timezone); + } if ($p_interval == 'P1M'){ /* When adding months, there is a problem if we are on January 31st and add one month with PHP. @@ -1538,23 +1552,23 @@ class Application_Model_Show { return $event; } - /* Takes in a UTC DateTime object. + /* Takes in a UTC DateTime object. * Converts this to local time, since cc_show days * requires local time. */ public function setShowFirstShow($p_dt){ - + //clone object since we are modifying it and it was passed by reference. $dt = clone $p_dt; - + $dt->setTimezone(new DateTimeZone(date_default_timezone_get())); - + $showDay = CcShowDaysQuery::create() ->filterByDbShowId($this->_showId) ->findOne(); $showDay->setDbFirstShow($dt) ->save(); - + Logging::log("setting show's first show."); } @@ -1562,15 +1576,15 @@ class Application_Model_Show { * Converts this to local time, since cc_show days * requires local time. */ public function setShowLastShow($p_dt){ - + //clone object since we are modifying it and it was passed by reference. $dt = clone $p_dt; - + $dt->setTimezone(new DateTimeZone(date_default_timezone_get())); - + //add one day since the Last Show date in CcShowDays is non-inclusive. $dt->add(new DateInterval("P1D")); - + $showDay = CcShowDaysQuery::create() ->filterByDbShowId($this->_showId) ->findOne(); diff --git a/airtime_mvc/application/models/ShowInstance.php b/airtime_mvc/application/models/ShowInstance.php index f0bd25490..ab31104b3 100644 --- a/airtime_mvc/application/models/ShowInstance.php +++ b/airtime_mvc/application/models/ShowInstance.php @@ -31,7 +31,7 @@ class Application_Model_ShowInstance { /* This function is weird. It should return a boolean, but instead returns * an integer if it is a rebroadcast, or returns null if it isn't. You can convert - * it to boolean by using is_null(isRebroadcast), where true means isn't and false + * it to boolean by using is_null(isRebroadcast), where true means isn't and false * means that it is. */ public function isRebroadcast() { @@ -175,63 +175,104 @@ class Application_Model_ShowInstance { Application_Model_RabbitMq::PushSchedule(); } + /* + * @param $dateTime + * php Datetime object to add deltas to + * + * @param $deltaDay + * php int, delta days show moved + * + * @param $deltaMin + * php int, delta mins show moved + * + * @return $newDateTime + * php DateTime, $dateTime with the added time deltas. + */ + private static function addDeltas($dateTime, $deltaDay, $deltaMin) { + + $newDateTime = clone $dateTime; + + Logging::log("deltaDay: {$deltaDay}"); + Logging::log("deltaMin: {$deltaMin}"); + Logging::log("addDeltas: original time {$newDateTime->format('Y-m-d H:i:s')}"); + + $days = abs($deltaDay); + $mins = abs($deltaMin); + + $dayInterval = new DateInterval("P{$days}D"); + $minInterval = new DateInterval("PT{$mins}M"); + + if ($deltaDay > 0) { + $newDateTime->add($dayInterval); + } + else if ($deltaDay < 0){ + $newDateTime->sub($dayInterval); + } + + if ($deltaMin > 0) { + $newDateTime->add($minInterval); + } + else if ($deltaMin < 0) { + $newDateTime->sub($minInterval); + } + + Logging::log("addDeltas: modified time {$newDateTime->format('Y-m-d H:i:s')}"); + + return $newDateTime; + } + public function moveShow($deltaDay, $deltaMin) { - global $CC_DBC; - if ($this->getShow()->isRepeating()){ return "Can't drag and drop repeating shows"; } - $hours = $deltaMin/60; - if($hours > 0) - $hours = floor($hours); - else - $hours = ceil($hours); - - $mins = abs($deltaMin%60); - $today_timestamp = time(); - $starts = $this->getShowInstanceStart(); - $ends = $this->getShowInstanceEnd(); + $startsDateTime = new DateTime($this->getShowInstanceStart(), new DateTimeZone("UTC")); + $endsDateTime = new DateTime($this->getShowInstanceEnd(), new DateTimeZone("UTC")); - $startsDateTime = new DateTime($starts, new DateTimeZone("UTC")); - - if($today_timestamp > $startsDateTime->getTimestamp()) { + if ($today_timestamp > $startsDateTime->getTimestamp()) { return "Can't move a past show"; } - $sql = "SELECT timestamp '{$starts}' + interval '{$deltaDay} days' + interval '{$hours}:{$mins}'"; - $new_starts = $CC_DBC->GetOne($sql); - $newStartsDateTime = new DateTime($new_starts, new DateTimeZone("UTC")); + //the user is moving the show on the calendar from the perspective of local time. + //incase a show is moved across a time change border offsets should be added to the localtime + //stamp and then converted back to UTC to avoid show time changes! + $startsDateTime->setTimezone(new DateTimeZone(date_default_timezone_get())); + $endsDateTime->setTimezone(new DateTimeZone(date_default_timezone_get())); - $sql = "SELECT timestamp '{$ends}' + interval '{$deltaDay} days' + interval '{$hours}:{$mins}'"; - $new_ends = $CC_DBC->GetOne($sql); - $newEndsDateTime = new DateTime($new_ends, new DateTimeZone("UTC")); + $newStartsDateTime = self::addDeltas($startsDateTime, $deltaDay, $deltaMin); + $newEndsDateTime = self::addDeltas($endsDateTime, $deltaDay, $deltaMin); + //convert our new starts/ends to UTC. + $newStartsDateTime->setTimezone(new DateTimeZone("UTC")); + $newEndsDateTime->setTimezone(new DateTimeZone("UTC")); - if($today_timestamp > $newStartsDateTime->getTimestamp()) { + if ($today_timestamp > $newStartsDateTime->getTimestamp()) { return "Can't move show into past"; } - $overlap = Application_Model_Show::getShows($newStartsDateTime, $newEndsDateTime, array($this->_instanceId)); + if ($this->isRebroadcast()) { - if(count($overlap) > 0) { - return "Should not overlap shows"; - } + try { + $recordedShow = new Application_Model_ShowInstance($this->_showInstance->getDbOriginalShow()); + } + //recorded show doesn't exist. + catch (Exception $e) { + $this->_showInstance->delete(); + return "Show was deleted because recorded show does not exist!"; + } - $rebroadcast = $this->isRebroadcast(); - if($rebroadcast) { - $sql = "SELECT timestamp '{$new_starts}' < (SELECT starts FROM cc_show_instances WHERE id = {$rebroadcast})"; - $isBeforeRecordedOriginal = $CC_DBC->GetOne($sql); + $recordEndDateTime = new DateTime($recordedShow->getShowInstanceEnd(), new DateTimeZone("UTC")); + $newRecordEndDateTime = self::addDeltas($recordEndDateTime, 0, 60); - if($isBeforeRecordedOriginal === 't'){ - return "Cannot move a rebroadcast show before its original show"; + if ($newStartsDateTime->getTimestamp() < $newRecordEndDateTime->getTimestamp()) { + return "Must wait 1 hour to rebroadcast."; } } - $this->setShowStart($new_starts); - $this->setShowEnd($new_ends); + $this->setShowStart($newStartsDateTime); + $this->setShowEnd($newEndsDateTime); $this->correctScheduleStartTimes(); $show = new Application_Model_Show($this->getShowId()); @@ -399,40 +440,55 @@ class Application_Model_ShowInstance { global $CC_DBC; // see if it was recording show - $recording = CcShowInstancesQuery::create() - ->findPK($this->_instanceId) - ->getDbRecord(); + $recording = $this->isRecorded(); // get show id - $showId = CcShowInstancesQuery::create() - ->findPK($this->_instanceId) - ->getDbShowId(); + $showId = $this->getShowId(); - CcShowInstancesQuery::create() - ->findPK($this->_instanceId) - ->setDbModifiedInstance(true) - ->save(); - - /* Automatically delete all files scheduled in cc_schedules table. */ - CcScheduleQuery::create() - ->filterByDbInstanceId($this->_instanceId) - ->delete(); + $show = $this->getShow(); - // check if we can safely delete the show - $showInstancesRow = CcShowInstancesQuery::create() - ->filterByDbShowId($showId) - ->filterByDbModifiedInstance(false) - ->findOne(); - - + $current_timestamp = gmdate("Y-m-d H:i"); - /* If we didn't find any instances of the show that haven't - * been deleted, then just erase everything related to that show. - * We can just delete, the show and the foreign key-constraint should - * take care of deleting all of its instances. */ - if(is_null($showInstancesRow)){ - CcShowQuery::create() - ->filterByDbId($showId) - ->delete(); + if ($current_timestamp < $this->getShowInstanceStart()) { + + if ($show->isRepeating()) { + + CcShowInstancesQuery::create() + ->findPK($this->_instanceId) + ->setDbModifiedInstance(true) + ->save(); + + //delete the rebroadcasts of the removed recorded show. + if ($recording) { + CcShowInstancesQuery::create() + ->filterByDbOriginalShow($this->_instanceId) + ->delete(); + } + + /* Automatically delete all files scheduled in cc_schedules table. */ + CcScheduleQuery::create() + ->filterByDbInstanceId($this->_instanceId) + ->delete(); + + // check if we can safely delete the show + $showInstancesRow = CcShowInstancesQuery::create() + ->filterByDbShowId($showId) + ->filterByDbModifiedInstance(false) + ->findOne(); + + /* If we didn't find any instances of the show that haven't + * been deleted, then just erase everything related to that show. + * We can just delete, the show and the foreign key-constraint should + * take care of deleting all of its instances. */ + if(is_null($showInstancesRow)){ + CcShowQuery::create() + ->filterByDbId($showId) + ->delete(); + } + } + else { + + $show->deleteShow(); + } } Application_Model_RabbitMq::PushSchedule(); diff --git a/airtime_mvc/application/models/StoredFile.php b/airtime_mvc/application/models/StoredFile.php index 0f336555a..852ac60bd 100644 --- a/airtime_mvc/application/models/StoredFile.php +++ b/airtime_mvc/application/models/StoredFile.php @@ -442,10 +442,10 @@ class Application_Model_StoredFile { { $serverName = $_SERVER['SERVER_NAME']; $serverPort = $_SERVER['SERVER_PORT']; - + return $this->constructGetFileUrl($serverName, $serverPort); } - + /** * Get the URL to access this file using the server name/address that * is specified in the airtime.conf config file. If either of these is @@ -453,13 +453,13 @@ class Application_Model_StoredFile { */ public function getFileUrlUsingConfigAddress(){ global $CC_CONFIG; - + if (isset($CC_CONFIG['baseUrl'])){ $serverName = $CC_CONFIG['baseUrl']; } else { $serverName = $_SERVER['SERVER_NAME']; } - + if (isset($CC_CONFIG['basePort'])){ $serverPort = $CC_CONFIG['basePort']; } else { @@ -468,7 +468,7 @@ class Application_Model_StoredFile { return $this->constructGetFileUrl($serverName, $serverPort); } - + private function constructGetFileUrl($p_serverName, $p_serverPort){ return "http://$p_serverName:$p_serverPort/api/get-media/file/".$this->getGunId().".".$this->getFileExtension(); } @@ -604,7 +604,7 @@ class Application_Model_StoredFile { { return Application_Model_StoredFile::Recall(null, null, null, $p_filepath); } - + public static function RecallByPartialFilepath($partial_path){ $path_info = Application_Model_MusicDir::splitFilePath($partial_path); @@ -625,11 +625,11 @@ class Application_Model_StoredFile { } return $res; } - + public static function searchFilesForPlaylistBuilder($datatables) { global $CC_CONFIG; - $displayData = array("track_title", "artist_name", "album_title", "track_number", "length", "ftype"); + $displayData = array("track_title", "artist_name", "album_title", "genre", "length", "ftype"); $plSelect = "SELECT "; $fileSelect = "SELECT "; @@ -812,11 +812,11 @@ class Application_Model_StoredFile { // create temp file name (CC-3086) $command = "mktemp --tmpdir=".$p_targetDir; $tempFilePath= exec($command); - + if($tempFilePath == ""){ die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Unable to create tmp file."}, "id" : "id"}'); } - + if (strpos($contentType, "multipart") !== false) { if (isset($_FILES['file']['tmp_name']) && is_uploaded_file($_FILES['file']['tmp_name'])) { // Open temp file @@ -854,7 +854,7 @@ class Application_Model_StoredFile { } else die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}'); } - + return $tempFilePath; } @@ -919,11 +919,11 @@ class Application_Model_StoredFile { $this->_file->setDbSoundCloudLinkToFile($link_to_file) ->save(); } - + public function getSoundCloudLinkToFile(){ return $this->_file->getDbSoundCloudLinkToFile(); } - + public function setSoundCloudFileId($p_soundcloud_id) { $this->_file->setDbSoundCloudId($p_soundcloud_id) @@ -955,7 +955,7 @@ class Application_Model_StoredFile { public function uploadToSoundCloud() { global $CC_CONFIG; - + $file = $this->_file; if(is_null($file)) { return "File does not exist"; diff --git a/airtime_mvc/application/views/scripts/library/index.phtml b/airtime_mvc/application/views/scripts/library/index.phtml index 866cc48ad..ef4362e0b 100644 --- a/airtime_mvc/application/views/scripts/library/index.phtml +++ b/airtime_mvc/application/views/scripts/library/index.phtml @@ -11,7 +11,7 @@ Title Creator Album - Track + Genre Length Type diff --git a/airtime_mvc/application/views/scripts/preference/stream-setting.phtml b/airtime_mvc/application/views/scripts/preference/stream-setting.phtml index e2e49af59..9ffabfee2 100644 --- a/airtime_mvc/application/views/scripts/preference/stream-setting.phtml +++ b/airtime_mvc/application/views/scripts/preference/stream-setting.phtml @@ -20,6 +20,14 @@
form->getElement('output_sound_device') ?>
+
+ +
+
+ form->getElement('output_sound_device_type') ?> +