diff --git a/Changelog b/Changelog index 0ff1c3f4b..5e2a2e38c 100644 --- a/Changelog +++ b/Changelog @@ -20,6 +20,9 @@ Highlights: - Fixed various editing show problems - Fixed airtime-pypo-stop/start causing playback problems - Fixed incorrect information being occasionally shown in the top panel + - Fixed problem with Record Check box occasionally being greyed-out when creating new show + - Fixed a problem with default genre not being applied to recorded shows + - Fixed a problem where shows repeating bi-weekly or monthly did not update properly when edited. 1.8.1 - May 2, 2011 diff --git a/airtime_mvc/application/controllers/ApiController.php b/airtime_mvc/application/controllers/ApiController.php index 3441668da..422fa608c 100644 --- a/airtime_mvc/application/controllers/ApiController.php +++ b/airtime_mvc/application/controllers/ApiController.php @@ -293,52 +293,61 @@ class ApiController extends Zend_Controller_Action print 'You are not allowed to access this resource.'; exit; } - + + $showCanceled = false; + $show_instance = $this->_getParam('show_instance'); + $upload_dir = ini_get("upload_tmp_dir"); $file = StoredFile::uploadFile($upload_dir); - - $show_instance = $this->_getParam('show_instance'); - + + $show_name = ""; try { $show_inst = new ShowInstance($show_instance); - + $show_inst->setRecordedFile($file->getId()); $show_name = $show_inst->getName(); $show_genre = $show_inst->getGenre(); $show_start_time = $show_inst->getShowStart(); - if(Application_Model_Preference::GetDoSoundCloudUpload()) - { - for($i=0; $i<$CC_CONFIG['soundcloud-connection-retries']; $i++) { - - $show = new Show($show_inst->getShowId()); - $description = $show->getDescription(); - $hosts = $show->getHosts(); - - $tags = array_merge($hosts, array($show_name)); - - try { - $soundcloud = new ATSoundcloud(); - $soundcloud_id = $soundcloud->uploadTrack($file->getRealFilePath(), $file->getName(), $description, $tags, $show_start_time, $show_genre); - $show_inst->setSoundCloudFileId($soundcloud_id); - break; - } - catch (Services_Soundcloud_Invalid_Http_Response_Code_Exception $e) { - $code = $e->getHttpCode(); - if(!in_array($code, array(0, 100))) { - break; - } - } - - sleep($CC_CONFIG['soundcloud-connection-wait']); - } - } - } catch (Exception $e){ + } catch (Exception $e){ //we've reached here probably because the show was //cancelled, and therefore the show instance does not //exist anymore (ShowInstance constructor threw this error). //We've done all we can do (upload the file and put it in //the library), now lets just return. + $showCanceled = true; + } + + $tmpTitle = !(empty($show_name))?$show_name."-":""; + $tmpTitle .= $file->getName(); + + $file->setMetadataValue(UI_MDATA_KEY_TITLE, $tmpTitle); + + if (!$showCanceled && Application_Model_Preference::GetDoSoundCloudUpload()) + { + for ($i=0; $i<$CC_CONFIG['soundcloud-connection-retries']; $i++) { + + $show = new Show($show_inst->getShowId()); + $description = $show->getDescription(); + $hosts = $show->getHosts(); + + $tags = array_merge($hosts, array($show_name)); + + try { + $soundcloud = new ATSoundcloud(); + $soundcloud_id = $soundcloud->uploadTrack($file->getRealFilePath(), $tmpTitle, $description, $tags, $show_start_time, $show_genre); + $show_inst->setSoundCloudFileId($soundcloud_id); + break; + } + catch (Services_Soundcloud_Invalid_Http_Response_Code_Exception $e) { + $code = $e->getHttpCode(); + if(!in_array($code, array(0, 100))) { + break; + } + } + + sleep($CC_CONFIG['soundcloud-connection-wait']); + } } $this->view->id = $file->getId(); diff --git a/airtime_mvc/application/controllers/ScheduleController.php b/airtime_mvc/application/controllers/ScheduleController.php index 3ef84548e..6377f13a2 100644 --- a/airtime_mvc/application/controllers/ScheduleController.php +++ b/airtime_mvc/application/controllers/ScheduleController.php @@ -203,6 +203,7 @@ class ScheduleController extends Zend_Controller_Action if (strtotime($show->getShowEnd()) <= strtotime($today_timestamp) && is_null($show->getSoundCloudFileId()) + && $show->isRecorded() && Application_Model_Preference::GetDoSoundCloudUpload()) { $menu[] = array('action' => array('type' => 'fn', 'callback' => "window['uploadToSoundCloud']($id)"), diff --git a/airtime_mvc/application/models/Shows.php b/airtime_mvc/application/models/Shows.php index 2340a6a1d..fa439406b 100644 --- a/airtime_mvc/application/models/Shows.php +++ b/airtime_mvc/application/models/Shows.php @@ -313,6 +313,26 @@ class Show { $CC_DBC->query($sql); } + /** + * Deletes all future rebroadcast instances of the current + * show object from the show_instances table. + * + */ + public function deleteAllRebroadcasts(){ + global $CC_DBC; + + $date = new DateHelper; + $timestamp = $date->getTimestamp(); + + $showId = $this->getId(); + $sql = "DELETE FROM cc_show_instances" + ." WHERE starts > TIMESTAMP '$timestamp'" + ." AND show_id = $showId" + ." AND rebroadcast = 1"; + + $CC_DBC->query($sql); + } + /** * Deletes all show instances of current show after a * certain date. @@ -556,52 +576,57 @@ class Show { return CcShowInstancesQuery::create()->findPk($row); } - public static function deletePossiblyInvalidInstances($p_data, $p_show, $p_endDate, $isRecorded, $repeatType) + public function deletePossiblyInvalidInstances($p_data, $p_endDate, $isRecorded, $repeatType) { - if (($p_data['add_show_repeats'] != $p_show->isRepeating()) || ($isRecorded && !$p_data['add_show_repeats'])){ - //repeat option was toggled. - $p_show->deleteAllInstances(); - } - if($isRecorded && $p_data['add_show_repeats']) { - $p_show->removeAllInstancesFromDate(); + if ($p_data['add_show_repeats'] != $this->isRepeating()){ + //repeat option was toggled + $this->deleteAllInstances(); } - if ($p_data['add_show_duration'] != $p_show->getDuration()){ + if ($p_data['add_show_duration'] != $this->getDuration()){ //duration has changed - $p_show->updateDurationTime($p_data); + $this->updateDurationTime($p_data); + } + + if ($isRecorded){ + //delete all rebroadcasts. They will simply be recreated later + //in the execution of this PHP script. This simplifies having to + //reason about whether we should keep individual rebroadcasts or + //delete them or move them around etc. + $this->deleteAllRebroadcasts(); } if ($p_data['add_show_repeats']){ - if (($repeatType == 1 || $repeatType == 2) && - $p_data['add_show_start_date'] != $p_show->getStartDate()){ - + if (($repeatType == 1 || $repeatType == 2) && + $p_data['add_show_start_date'] != $this->getStartDate()){ + //start date has changed when repeat type is bi-weekly or monthly. //This screws up the repeating positions of show instances, so lets - //just delete them for now. - - $p_show->deleteAllInstances(); + //just delete them for now. (CC-2351) + + $this->deleteAllInstances(); } - - if ($p_data['add_show_start_date'] != $p_show->getStartDate() - || $p_data['add_show_start_time'] != $p_show->getStartTime()){ + + 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($p_show->getStartDate()); + $oldDate = strtotime($this->getStartDate()); if ($newDate > $oldDate){ - $p_show->removeAllInstancesBeforeDate($p_data['add_show_start_date']); + $this->removeAllInstancesBeforeDate($p_data['add_show_start_date']); } - $p_show->updateStartDateTime($p_data, $p_endDate); + $this->updateStartDateTime($p_data, $p_endDate); } - - if ($repeatType != $p_show->getRepeatType()){ + + if ($repeatType != $this->getRepeatType()){ //repeat type changed. - $p_show->deleteAllInstances(); + $this->deleteAllInstances(); } else { //repeat type is the same, check if the days of the week are the same $repeatingDaysChanged = false; - $showDaysArray = $p_show->getShowDays(); + $showDaysArray = $this->getShowDays(); if (count($p_data['add_show_day_check']) == count($showDaysArray)){ //same number of days checked, lets see if they are the same numbers $intersect = array_intersect($p_data['add_show_day_check'], $showDaysArray); @@ -617,28 +642,28 @@ class Show { $daysRemoved = array_diff($showDaysArray, $p_data['add_show_day_check']); if (count($daysRemoved) > 0){ - $p_show->removeUncheckedDaysInstances($daysRemoved); + $this->removeUncheckedDaysInstances($daysRemoved); } } } //Check if end date for the repeat option has changed. If so, need to take care //of deleting possible invalid Show Instances. - if ((strlen($p_show->getRepeatingEndDate()) == 0) == $p_data['add_show_no_end']){ + if ((strlen($this->getRepeatingEndDate()) == 0) == $p_data['add_show_no_end']){ //show "Never Ends" option was toggled. if ($p_data['add_show_no_end']){ } else { - $p_show->removeAllInstancesFromDate($p_endDate); + $this->removeAllInstancesFromDate($p_endDate); } } - if ($p_show->getRepeatingEndDate() != $p_data['add_show_end_date']){ + if ($this->getRepeatingEndDate() != $p_data['add_show_end_date']){ //end date was changed. $newDate = strtotime($p_data['add_show_end_date']); - $oldDate = strtotime($p_show->getRepeatingEndDate()); + $oldDate = strtotime($this->getRepeatingEndDate()); if ($newDate < $oldDate){ - $p_show->removeAllInstancesFromDate($p_endDate); + $this->removeAllInstancesFromDate($p_endDate); } } } @@ -704,7 +729,7 @@ class Show { $isRecorded = ($data['add_show_record']) ? 1 : 0; if ($data['add_show_id'] != -1){ - Show::deletePossiblyInvalidInstances($data, $show, $endDate, $isRecorded, $repeatType); + $show->deletePossiblyInvalidInstances($data, $endDate, $isRecorded, $repeatType); } //check if we are adding or updating a show, and if updating @@ -908,7 +933,7 @@ class Show { $ccShowInstance = new CcShowInstances(); $newInstance = true; } - + if ($newInstance || $ccShowInstance->getDbStarts() > $currentTimestamp){ $ccShowInstance->setDbShowId($show_id); $ccShowInstance->setDbStarts($start); @@ -986,10 +1011,10 @@ class Show { $ccShowInstance = new CcShowInstances(); $newInstance = true; } - + /* When editing the start/end time of a repeating show, we don't want to - * change shows that started in the past. So check the start time. - */ + * change shows that started in the past. So check the start time. + */ if ($newInstance || $ccShowInstance->getDbStarts() > $currentTimestamp){ $ccShowInstance->setDbShowId($show_id); $ccShowInstance->setDbStarts($start); @@ -1130,7 +1155,6 @@ class Show { public static function getFullCalendarEvents($start, $end, $editable=false) { $events = array(); - $options = array(); $start_range = new DateTime($start); $end_range = new DateTime($end); @@ -1141,13 +1165,15 @@ class Show { $today_timestamp = date("Y-m-d H:i:s"); foreach ($shows as $show) { + $options = array(); + //only bother calculating percent for week or day view. if(intval($days) <= 7) { $show_instance = new ShowInstance($show["instance_id"]); $options["percent"] = $show_instance->getPercentScheduled(); } - if ($editable && strtotime($today_timestamp) < strtotime($show["starts"])) { + if ($editable && (strtotime($today_timestamp) < strtotime($show["starts"]))) { $options["editable"] = true; $events[] = Show::makeFullCalendarEvent($show, $options); } @@ -1357,16 +1383,20 @@ class ShowInstance { $mins = abs($deltaMin%60); + $today_timestamp = date("Y-m-d H:i:s"); $starts = $this->getShowStart(); $ends = $this->getShowEnd(); + if(strtotime($today_timestamp) > strtotime($starts)) { + return "can't move a past show"; + } + $sql = "SELECT timestamp '{$starts}' + interval '{$deltaDay} days' + interval '{$hours}:{$mins}'"; $new_starts = $CC_DBC->GetOne($sql); $sql = "SELECT timestamp '{$ends}' + interval '{$deltaDay} days' + interval '{$hours}:{$mins}'"; $new_ends = $CC_DBC->GetOne($sql); - $today_timestamp = date("Y-m-d H:i:s"); if(strtotime($today_timestamp) > strtotime($new_starts)) { return "can't move show into past"; } @@ -1405,9 +1435,14 @@ class ShowInstance { $mins = abs($deltaMin%60); + $today_timestamp = date("Y-m-d H:i:s"); $starts = $this->getShowStart(); $ends = $this->getShowEnd(); + if(strtotime($today_timestamp) > strtotime($starts)) { + return "can't resize a past show"; + } + $sql = "SELECT timestamp '{$ends}' + interval '{$deltaDay} days' + interval '{$hours}:{$mins}'"; $new_ends = $CC_DBC->GetOne($sql); diff --git a/airtime_mvc/application/models/Soundcloud.php b/airtime_mvc/application/models/Soundcloud.php index bc9f416d1..5e17049b6 100644 --- a/airtime_mvc/application/models/Soundcloud.php +++ b/airtime_mvc/application/models/Soundcloud.php @@ -28,7 +28,7 @@ class ATSoundcloud { return $token; } - public function uploadTrack($filepath, $filename, $description, $tags=array(), $release=null, $genre=null) + public function uploadTrack($filepath, $filename, $description, $tags=array(), $release=null, $genre=null) { if($this->getToken()) { @@ -47,7 +47,7 @@ class ATSoundcloud { 'track[tag_list]' => $tags, 'track[description]' => $description, 'track[downloadable]' => true, - + ); if(isset($release)) { @@ -61,13 +61,13 @@ class ATSoundcloud { $track_data['track[release_month]'] = $release[1]; $track_data['track[release_day]'] = $release[2]; } - + if (isset($genre) && $genre != "") { $track_data['track[genre]'] = $genre; } else { - $default_genre = Application_Model_Preference::GetSoundCloudTrackType(); - if ($genre != "") { + $default_genre = Application_Model_Preference::GetSoundCloudGenre(); + if ($default_genre != "") { $track_data['track[genre]'] = $default_genre; } } @@ -88,7 +88,7 @@ class ATSoundcloud { ); return $response["id"]; - } + } } } diff --git a/airtime_mvc/application/models/StoredFile.php b/airtime_mvc/application/models/StoredFile.php index cdc17423e..84556ce78 100644 --- a/airtime_mvc/application/models/StoredFile.php +++ b/airtime_mvc/application/models/StoredFile.php @@ -1754,8 +1754,8 @@ class StoredFile { return array("sEcho" => intval($data["sEcho"]), "iTotalDisplayRecords" => $totalDisplayRows, "iTotalRecords" => $totalRows, "aaData" => $results); } - public static function uploadFile($targetDir) { - + public static function uploadFile($p_targetDir) + { // HTTP headers for no cache etc header('Content-type: text/plain; charset=UTF-8'); header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); @@ -1765,7 +1765,7 @@ class StoredFile { header("Pragma: no-cache"); // Settings - //$targetDir = ini_get("upload_tmp_dir"); //. DIRECTORY_SEPARATOR . "plupload"; + //$p_targetDir = ini_get("upload_tmp_dir"); //. DIRECTORY_SEPARATOR . "plupload"; $cleanupTargetDir = false; // Remove old files $maxFileAge = 60 * 60; // Temp file age in seconds @@ -1782,13 +1782,13 @@ class StoredFile { //$fileName = preg_replace('/[^\w\._]+/', '', $fileName); // Create target dir - if (!file_exists($targetDir)) - @mkdir($targetDir); + if (!file_exists($p_targetDir)) + @mkdir($p_targetDir); // Remove old temp files - if (is_dir($targetDir) && ($dir = opendir($targetDir))) { + if (is_dir($p_targetDir) && ($dir = opendir($p_targetDir))) { while (($file = readdir($dir)) !== false) { - $filePath = $targetDir . DIRECTORY_SEPARATOR . $file; + $filePath = $p_targetDir . DIRECTORY_SEPARATOR . $file; // Remove temp files if they are older than the max age if (preg_match('/\.tmp$/', $file) && (filemtime($filePath) < time() - $maxFileAge)) @@ -1809,7 +1809,7 @@ class StoredFile { if (strpos($contentType, "multipart") !== false) { if (isset($_FILES['file']['tmp_name']) && is_uploaded_file($_FILES['file']['tmp_name'])) { // Open temp file - $out = fopen($targetDir . DIRECTORY_SEPARATOR . $fileName, $chunk == 0 ? "wb" : "ab"); + $out = fopen($p_targetDir . DIRECTORY_SEPARATOR . $fileName, $chunk == 0 ? "wb" : "ab"); if ($out) { // Read binary input stream and append it to temp file $in = fopen($_FILES['file']['tmp_name'], "rb"); @@ -1828,7 +1828,7 @@ class StoredFile { die('{"jsonrpc" : "2.0", "error" : {"code": 103, "message": "Failed to move uploaded file."}, "id" : "id"}'); } else { // Open temp file - $out = fopen($targetDir . DIRECTORY_SEPARATOR . $fileName, $chunk == 0 ? "wb" : "ab"); + $out = fopen($p_targetDir . DIRECTORY_SEPARATOR . $fileName, $chunk == 0 ? "wb" : "ab"); if ($out) { // Read binary input stream and append it to temp file $in = fopen("php://input", "rb"); @@ -1844,7 +1844,7 @@ class StoredFile { die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}'); } - $audio_file = $targetDir . DIRECTORY_SEPARATOR . $fileName; + $audio_file = $p_targetDir . DIRECTORY_SEPARATOR . $fileName; $md5 = md5_file($audio_file); $duplicate = StoredFile::RecallByMd5($md5); @@ -1873,18 +1873,14 @@ class StoredFile { die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": ' + $metadata->getMessage() + '}}'); } - // #2196 no id tag -> use the original filename - if (basename($audio_file) == $metadata[UI_MDATA_KEY_TITLE]) { + // no id3 title tag -> use the original filename for title + if (empty($metadata[UI_MDATA_KEY_TITLE])) { $metadata[UI_MDATA_KEY_TITLE] = basename($audio_file); $metadata[UI_MDATA_KEY_FILENAME] = basename($audio_file); } - // setMetadataBatch doesnt like these values - unset($metadata['audio']); - unset($metadata['playtime_seconds']); - $values = array( - "filename" => basename($audio_file), + "filename" => basename($audio_file), "filepath" => $audio_file, "filetype" => "audioclip", "mime" => $metadata[UI_MDATA_KEY_FORMAT], diff --git a/python_apps/show-recorder/recorder.py b/python_apps/show-recorder/recorder.py index a6352729a..233f5c8de 100644 --- a/python_apps/show-recorder/recorder.py +++ b/python_apps/show-recorder/recorder.py @@ -48,11 +48,10 @@ def getDateTimeObj(time): class ShowRecorder(Thread): - def __init__ (self, show_instance, filelength, show_name, start_time, filetype): + def __init__ (self, show_instance, filelength, start_time, filetype): Thread.__init__(self) self.api_client = api_client.api_client_factory(config) self.filelength = filelength - self.show_name = show_name self.start_time = start_time self.filetype = filetype self.show_instance = show_instance @@ -61,7 +60,7 @@ class ShowRecorder(Thread): def record_show(self): length = str(self.filelength)+".0" - filename = self.show_name+" "+self.start_time + filename = self.start_time filename = filename.replace(" ", "-") filepath = "%s%s.%s" % (config["base_recorded_files"], filename, self.filetype) @@ -155,9 +154,8 @@ class Record(): show_length = self.shows_to_record[start_time][0] show_instance = self.shows_to_record[start_time][1] - show_name = self.shows_to_record[start_time][2] - self.sr = ShowRecorder(show_instance, show_length.seconds, show_name, start_time, filetype="mp3") + self.sr = ShowRecorder(show_instance, show_length.seconds, start_time, filetype="mp3") self.sr.start() #remove show from shows to record.