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/VERSION b/VERSION index 1ec57110d..b12c06c18 100644 --- a/VERSION +++ b/VERSION @@ -1,2 +1,2 @@ PRODUCT_ID=Airtime -PRODUCT_RELEASE=1.8.2 +PRODUCT_RELEASE=1.9.0 diff --git a/airtime_mvc/application/configs/ACL.php b/airtime_mvc/application/configs/ACL.php index 0bf2b6d43..5fa4b7a05 100644 --- a/airtime_mvc/application/configs/ACL.php +++ b/airtime_mvc/application/configs/ACL.php @@ -6,7 +6,8 @@ $ccAcl = new Zend_Acl(); $ccAcl->addRole(new Zend_Acl_Role('G')) ->addRole(new Zend_Acl_Role('H'), 'G') - ->addRole(new Zend_Acl_Role('A'), 'H'); + ->addRole(new Zend_Acl_Role('P'), 'H') + ->addRole(new Zend_Acl_Role('A'), 'P'); $ccAcl->add(new Zend_Acl_Resource('library')) ->add(new Zend_Acl_Resource('index')) diff --git a/airtime_mvc/application/controllers/ApiController.php b/airtime_mvc/application/controllers/ApiController.php index dce293b0d..422fa608c 100644 --- a/airtime_mvc/application/controllers/ApiController.php +++ b/airtime_mvc/application/controllers/ApiController.php @@ -63,7 +63,7 @@ class ApiController extends Zend_Controller_Action $this->_helper->viewRenderer->setNoRender(true); $api_key = $this->_getParam('api_key'); - $download = $this->_getParam('download'); + $downlaod = $this->_getParam('download'); if(!in_array($api_key, $CC_CONFIG["apiKey"])) { @@ -100,15 +100,15 @@ class ApiController extends Zend_Controller_Action // !! binary mode !! $fp = fopen($filepath, 'rb'); - + //We can have multiple levels of output buffering. Need to //keep looping until all have been disabled!!! //http://www.php.net/manual/en/function.ob-end-flush.php while (@ob_end_flush()); - + fpassthru($fp); fclose($fp); - + return; } } @@ -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(); @@ -357,8 +366,9 @@ class ApiController extends Zend_Controller_Action } $md = $this->_getParam('md'); - - $file = StoredFile::Recall(null, $md['gunid']); + $filepath = $md['filepath']; + $filepath = str_replace("\\", "", $filepath); + $file = StoredFile::Recall(null, null, null, $filepath); if (PEAR::isError($file) || is_null($file)) { $this->view->response = "File not in Airtime's Database"; return; diff --git a/airtime_mvc/application/controllers/ScheduleController.php b/airtime_mvc/application/controllers/ScheduleController.php index 3ef84548e..2ac07f1c9 100644 --- a/airtime_mvc/application/controllers/ScheduleController.php +++ b/airtime_mvc/application/controllers/ScheduleController.php @@ -59,6 +59,7 @@ class ScheduleController extends Zend_Controller_Action $userInfo = Zend_Auth::getInstance()->getStorage()->read(); $user = new User($userInfo->id); $this->view->isAdmin = $user->isAdmin(); + $this->view->isProgramManager = $user->isUserType('P'); } public function eventFeedAction() @@ -68,7 +69,7 @@ class ScheduleController extends Zend_Controller_Action $userInfo = Zend_Auth::getInstance()->getStorage()->read(); $user = new User($userInfo->id); - if($user->isAdmin()) + if($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER))) $editable = true; else $editable = false; @@ -85,7 +86,7 @@ class ScheduleController extends Zend_Controller_Action $userInfo = Zend_Auth::getInstance()->getStorage()->read(); $user = new User($userInfo->id); - if($user->isAdmin()) { + if($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER))) { $show = new ShowInstance($showInstanceId); $error = $show->moveShow($deltaDay, $deltaMin); } @@ -104,7 +105,7 @@ class ScheduleController extends Zend_Controller_Action $userInfo = Zend_Auth::getInstance()->getStorage()->read(); $user = new User($userInfo->id); - if($user->isAdmin()) { + if($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER))) { $show = new ShowInstance($showInstanceId); $error = $show->resizeShow($deltaDay, $deltaMin); } @@ -120,7 +121,7 @@ class ScheduleController extends Zend_Controller_Action $userInfo = Zend_Auth::getInstance()->getStorage()->read(); $user = new User($userInfo->id); - if($user->isAdmin()) { + if($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER))) { $show = new ShowInstance($showInstanceId); $show->deleteShow(); } @@ -182,10 +183,10 @@ class ScheduleController extends Zend_Controller_Action $show = new ShowInstance($id); $params = '/format/json/id/#id#'; - + if (strtotime($today_timestamp) < strtotime($show->getShowStart())) { - if (($user->isHost($show->getShowId()) || $user->isAdmin()) && !$show->isRecorded() && !$show->isRebroadcast()) { + if ($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER, UTYPE_HOST),$show->getShowId()) && !$show->isRecorded() && !$show->isRebroadcast()) { $menu[] = array('action' => array('type' => 'ajax', 'url' => '/Schedule/schedule-show-dialog'.$params, 'callback' => 'window["buildScheduleDialog"]'), 'title' => 'Add / Remove Content'); @@ -203,6 +204,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)"), @@ -212,7 +214,7 @@ class ScheduleController extends Zend_Controller_Action if (strtotime($show->getShowStart()) <= strtotime($today_timestamp) && strtotime($today_timestamp) < strtotime($show->getShowEnd()) && - $user->isAdmin()) { + $user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER))) { $menu[] = array('action' => array('type' => 'fn', 'callback' => "window['confirmCancelShow']($id)"), 'title' => 'Cancel Current Show'); @@ -220,7 +222,7 @@ class ScheduleController extends Zend_Controller_Action if (strtotime($today_timestamp) < strtotime($show->getShowStart())) { - if ($user->isAdmin()) { + if ($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER))) { $menu[] = array('action' => array('type' => 'ajax', 'url' => '/Schedule/edit-show/format/json/id/'.$id, 'callback' => 'window["beginEditShow"]'), 'title' => 'Edit Show'); @@ -230,7 +232,7 @@ class ScheduleController extends Zend_Controller_Action 'callback' => 'window["scheduleRefetchEvents"]'), 'title' => 'Delete This Instance and All Following'); } } - + //returns format jjmenu is looking for. die(json_encode($menu)); } @@ -249,7 +251,7 @@ class ScheduleController extends Zend_Controller_Action $user = new User($userInfo->id); $show = new ShowInstance($showInstanceId); - if($user->isHost($show->getShowId()) || $user->isAdmin()) { + if($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER, UTYPE_HOST),$show->getShowId())) { $show->scheduleShow(array($plId)); } @@ -268,7 +270,7 @@ class ScheduleController extends Zend_Controller_Action $user = new User($userInfo->id); $show = new ShowInstance($showInstanceId); - if($user->isHost($show->getShowId()) || $user->isAdmin()) + if($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER, UTYPE_HOST),$show->getShowId())) $show->clearShow(); } @@ -298,7 +300,7 @@ class ScheduleController extends Zend_Controller_Action $user = new User($userInfo->id); $show = new ShowInstance($showInstanceId); - if($user->isHost($show->getShowId()) || $user->isAdmin()) { + if($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER, UTYPE_HOST),$show->getShowId())) { $show->removeGroupFromShow($group_id); } @@ -376,7 +378,7 @@ class ScheduleController extends Zend_Controller_Action { $userInfo = Zend_Auth::getInstance()->getStorage()->read(); $user = new User($userInfo->id); - if(!$user->isAdmin()) { + if(!$user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER))) { return; } @@ -596,7 +598,7 @@ class ScheduleController extends Zend_Controller_Action if ($what && $when && $repeats && $who && $style && $record && $rebroadAb && $rebroad) { $userInfo = Zend_Auth::getInstance()->getStorage()->read(); $user = new User($userInfo->id); - if ($user->isAdmin()) { + if ($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER))) { Show::create($data); } @@ -634,7 +636,7 @@ class ScheduleController extends Zend_Controller_Action $userInfo = Zend_Auth::getInstance()->getStorage()->read(); $user = new User($userInfo->id); - if($user->isAdmin()) { + if($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER))) { $showInstanceId = $this->_getParam('id'); $showInstance = new ShowInstance($showInstanceId); @@ -649,7 +651,7 @@ class ScheduleController extends Zend_Controller_Action $userInfo = Zend_Auth::getInstance()->getStorage()->read(); $user = new User($userInfo->id); - if($user->isAdmin()) { + if($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER))) { $showInstanceId = $this->_getParam('id'); $show = new ShowInstance($showInstanceId); $show->clearShow(); diff --git a/airtime_mvc/application/forms/AddUser.php b/airtime_mvc/application/forms/AddUser.php index 58bc91543..4ff63dc12 100644 --- a/airtime_mvc/application/forms/AddUser.php +++ b/airtime_mvc/application/forms/AddUser.php @@ -73,7 +73,8 @@ class Application_Form_AddUser extends Zend_Form $select->setAttrib('style', 'width: 40%'); $select->setMultiOptions(array( "G" => "Guest", - "H" => "Host", + "H" => "DJ", + "P" => "Program Manager", "A" => "Admin" )); $select->setRequired(true); 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 370b27cdb..84556ce78 100644 --- a/airtime_mvc/application/models/StoredFile.php +++ b/airtime_mvc/application/models/StoredFile.php @@ -703,7 +703,7 @@ class StoredFile { * @return StoredFile|Playlist|NULL * Return NULL if the object doesnt exist in the DB. */ - public static function Recall($p_id=null, $p_gunid=null, $p_md5sum=null) + public static function Recall($p_id=null, $p_gunid=null, $p_md5sum=null, $p_filepath=null) { global $CC_DBC; global $CC_CONFIG; @@ -713,6 +713,8 @@ class StoredFile { $cond = "gunid='$p_gunid'"; } elseif (!is_null($p_md5sum)) { $cond = "md5='$p_md5sum'"; + } elseif (!is_null($p_filepath)) { + $cond = "filepath='$p_filepath'"; } else { return null; } @@ -782,6 +784,31 @@ class StoredFile { return $rows; } + private function ensureDir($dir) + { + if (!is_dir($dir)) { + mkdir($dir, 02775); + chmod($dir, 02775); + } + } + + private function createUniqueFilename($base, $ext) + { + if(file_exists("$base.$ext")) { + $i = 1; + while(true) { + if(file_exists("$base($i).$ext")) { + $i = $i+1; + } + else { + return "$base($i).$ext"; + } + } + } + + return "$base.$ext"; + } + /** * Generate the location to store the file. * It creates the subdirectory if needed. @@ -789,14 +816,48 @@ class StoredFile { private function generateFilePath() { global $CC_CONFIG, $CC_DBC; - $resDir = $CC_CONFIG['storageDir']."/".substr($this->gunid, 0, 3); - if (!is_dir($resDir)) { - mkdir($resDir, 02775); - chmod($resDir, 02775); - } + + $storageDir = $CC_CONFIG['storageDir']; $info = pathinfo($this->name); + $origName = $info['filename']; $fileExt = strtolower($info["extension"]); - return "{$resDir}/{$this->gunid}.{$fileExt}"; + + $this->loadMetadata(); + + $artist = $this->md["dc:creator"]; + $album = $this->md["dc:source"]; + $title = $this->md["dc:title"]; + $track_num = $this->md["ls:track_num"]; + + if(isset($artist) && $artist != "") { + $base = "$storageDir/$artist"; + $this->ensureDir($base); + + if(isset($album) && $album != "") { + $base = "$base/$album"; + $this->ensureDir($base); + } + + if(isset($title) && $title != "") { + if(isset($track_num) && $track_num != "") { + if($track_num < 10 && strlen($track_num) == 1) { + $track_num = "0$track_num"; + } + $base = "$base/$track_num - $title"; + } + else { + $base = "$base/$title"; + } + } + else { + $base = "$base/$origName"; + } + } + else { + $base = "$storageDir/$origName"; + } + + return $this->createUniqueFilename($base, $fileExt); } /** @@ -1693,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"); @@ -1704,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 @@ -1721,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)) @@ -1748,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"); @@ -1767,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"); @@ -1783,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); @@ -1812,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/airtime_mvc/application/models/Users.php b/airtime_mvc/application/models/Users.php index 3da349aee..cf836ded8 100644 --- a/airtime_mvc/application/models/Users.php +++ b/airtime_mvc/application/models/Users.php @@ -1,5 +1,10 @@ _userInstance->getDbId(); - return CcShowHostsQuery::create()->filterByDbShow($showId)->filterByDbHost($userId)->count() > 0; + return $this->isUserType(UTYPE_HOST, $showId); } public function isAdmin() { - return $this->_userInstance->getDbType() === 'A'; + return $this->isUserType(UTYPE_ADMIN); + } + + public function isUserType($type, $showId=''){ + if(is_array($type)){ + $result = false; + foreach($type as $t){ + switch($t){ + case UTYPE_ADMIN: + $result = $this->_userInstance->getDbType() === 'A'; + break; + case UTYPE_HOST: + $userId = $this->_userInstance->getDbId(); + $result = CcShowHostsQuery::create()->filterByDbShow($showId)->filterByDbHost($userId)->count() > 0; + break; + case UTYPE_PROGRAM_MANAGER: + $result = $this->_userInstance->getDbType() === 'P'; + break; + } + if($result){ + return $result; + } + } + }else{ + switch($type){ + case UTYPE_ADMIN: + return $this->_userInstance->getDbType() === 'A'; + case UTYPE_HOST: + $userId = $this->_userInstance->getDbId(); + return CcShowHostsQuery::create()->filterByDbShow($showId)->filterByDbHost($userId)->count() > 0; + case UTYPE_PROGRAM_MANAGER: + return $this->_userInstance->getDbType() === 'P'; + } + } } public function setLogin($login){ diff --git a/airtime_mvc/application/views/scripts/schedule/index.phtml b/airtime_mvc/application/views/scripts/schedule/index.phtml index 917180f68..1987f103e 100644 --- a/airtime_mvc/application/views/scripts/schedule/index.phtml +++ b/airtime_mvc/application/views/scripts/schedule/index.phtml @@ -1,4 +1,4 @@ -isAdmin) : ?> +isAdmin || $this->isProgramManager) : ?>
diff --git a/airtime_mvc/public/js/airtime/user/user.js b/airtime_mvc/public/js/airtime/user/user.js index 8d1534519..9eb29096b 100644 --- a/airtime_mvc/public/js/airtime/user/user.js +++ b/airtime_mvc/public/js/airtime/user/user.js @@ -51,6 +51,9 @@ function rowCallback( nRow, aData, iDisplayIndex ){ } else if ( aData[4] == "G" ) { $('td:eq(3)', nRow).html( 'Guest' ); + } else if ( aData[4] == "P" ) + { + $('td:eq(3)', nRow).html( 'Program Manager' ); } return nRow; diff --git a/install/airtime-uninstall b/install/airtime-uninstall index 4168eb8e7..b65700d00 100755 --- a/install/airtime-uninstall +++ b/install/airtime-uninstall @@ -12,12 +12,12 @@ php ${SCRIPTPATH}/airtime-uninstall.php echo -e "\n*** Uninstalling Pypo ***" python ${SCRIPTPATH}/../python_apps/pypo/install/pypo-uninstall.py -#echo -e "\n*** Uninstalling Media Monitor ***" -#python ${SCRIPTPATH}/../python_apps/pytag-fs/install/media-monitor-uninstall.py - echo -e "\n*** Uninstalling Show Recorder ***" python ${SCRIPTPATH}/../python_apps/show-recorder/install/recorder-uninstall.py +echo -e "\n*** Uninstalling Media Monitor ***" +python ${SCRIPTPATH}/../python_apps/media-monitor/install/media-monitor-uninstall.py + echo -e "\n*** Removing Pypo User ***" python ${SCRIPTPATH}/../python_apps/remove-pypo-user.py diff --git a/install/airtime-upgrade.php b/install/airtime-upgrade.php index a568fe9c5..109a978ec 100644 --- a/install/airtime-upgrade.php +++ b/install/airtime-upgrade.php @@ -96,7 +96,8 @@ passthru("python ".__DIR__."/../python_apps/pypo/install/pypo-install.py"); echo PHP_EOL."*** Updating Recorder ***".PHP_EOL; passthru("python ".__DIR__."/../python_apps/show-recorder/install/recorder-install.py"); +echo PHP_EOL."*** Starting Media Monitor ***".PHP_EOL; +passthru("python ".__DIR__."/../python_apps/media-monitor/install/media-monitor-install.py"); + echo "******************************* Update Complete *******************************".PHP_EOL; - - diff --git a/install/include/AirtimeIni.php b/install/include/AirtimeIni.php index 7f2ff24e8..df4a0e5ac 100644 --- a/install/include/AirtimeIni.php +++ b/install/include/AirtimeIni.php @@ -33,7 +33,8 @@ class AirtimeIni $configFiles = array(AirtimeIni::CONF_FILE_AIRTIME, AirtimeIni::CONF_FILE_PYPO, AirtimeIni::CONF_FILE_RECORDER, - AirtimeIni::CONF_FILE_LIQUIDSOAP); + AirtimeIni::CONF_FILE_LIQUIDSOAP, + AirtimeIni::CONF_FILE_MEDIAMONITOR); $exist = false; foreach ($configFiles as $conf) { if (file_exists($conf)) { @@ -102,9 +103,9 @@ class AirtimeIni } //wait until Airtime 1.9.0 - //if (file_exists(AirtimeIni::CONF_FILE_MEDIAMONITOR)){ - // unlink(AirtimeIni::CONF_FILE_MEDIAMONITOR); - //} + if (file_exists(AirtimeIni::CONF_FILE_MEDIAMONITOR)){ + unlink(AirtimeIni::CONF_FILE_MEDIAMONITOR); + } if (file_exists("etc/airtime")){ rmdir("/etc/airtime/"); @@ -156,9 +157,9 @@ class AirtimeIni $n=count($lines); foreach ($lines as &$line) { if ($line[0] != "#"){ - $key_value = split("=", $line); - $key = trim($key_value[0]); - + $key_value = explode("=", $line); + $key = trim($key_value[0]); + if ($key == $p_property){ $line = "$p_property = $p_value".PHP_EOL; } @@ -185,7 +186,7 @@ class AirtimeIni AirtimeIni::UpdateIniValue(AirtimeIni::CONF_FILE_AIRTIME, 'airtime_dir', AirtimeInstall::CONF_DIR_WWW); AirtimeIni::UpdateIniValue(AirtimeIni::CONF_FILE_PYPO, 'api_key', "'$api_key'"); AirtimeIni::UpdateIniValue(AirtimeIni::CONF_FILE_RECORDER, 'api_key', "'$api_key'"); - //AirtimeIni::UpdateIniValue(AirtimeIni::CONF_FILE_MEDIAMONITOR, 'api_key', "'$api_key'"); + AirtimeIni::UpdateIniValue(AirtimeIni::CONF_FILE_MEDIAMONITOR, 'api_key', "'$api_key'"); AirtimeIni::UpdateIniValue(AirtimeInstall::CONF_DIR_WWW.'/build/build.properties', 'project.home', AirtimeInstall::CONF_DIR_WWW); } diff --git a/install/upgrades/airtime-1.9/airtime-upgrade.php b/install/upgrades/airtime-1.9/airtime-upgrade.php index 049962a61..0727c9c64 100644 --- a/install/upgrades/airtime-1.9/airtime-upgrade.php +++ b/install/upgrades/airtime-1.9/airtime-upgrade.php @@ -49,7 +49,6 @@ function UninstallBinaries() exec("/usr/bin/airtime-pypo-stop"); exec("/usr/bin/airtime-show-recorder-stop"); -exec("/usr/bin/airtime-media-monitor-stop"); exec("svc -d /etc/service/pypo"); exec("svc -d /etc/service/pypo/log"); @@ -69,6 +68,7 @@ $pathnames = array("/usr/bin/airtime-pypo-start", "/etc/service/media-monitor", "/etc/service/recorder", "/var/log/airtime/pypo/main", + "/var/log/airtime/pypo-liquidsoap/main", "/var/log/airtime/show-recorder/main" ); diff --git a/python_apps/media-monitor/MediaMonitor.py b/python_apps/media-monitor/MediaMonitor.py index afb249f73..3143307c2 100644 --- a/python_apps/media-monitor/MediaMonitor.py +++ b/python_apps/media-monitor/MediaMonitor.py @@ -8,6 +8,7 @@ import os import sys import hashlib import json +import shutil from subprocess import Popen, PIPE, STDOUT @@ -22,6 +23,9 @@ from kombu.connection import BrokerConnection from kombu.messaging import Exchange, Queue, Consumer, Producer from api_clients import api_client +global storage_directory +storage_directory = "/srv/airtime/stor" + # configure logging try: logging.config.fileConfig("logging.cfg") @@ -42,6 +46,7 @@ list of supported easy tags in mutagen version 1.20 ['albumartistsort', 'musicbrainz_albumstatus', 'lyricist', 'releasecountry', 'date', 'performer', 'musicbrainz_albumartistid', 'composer', 'encodedby', 'tracknumber', 'musicbrainz_albumid', 'album', 'asin', 'musicbrainz_artistid', 'mood', 'copyright', 'author', 'media', 'length', 'version', 'artistsort', 'titlesort', 'discsubtitle', 'website', 'musicip_fingerprint', 'conductor', 'compilation', 'barcode', 'performer:*', 'composersort', 'musicbrainz_discid', 'musicbrainz_albumtype', 'genre', 'isrc', 'discnumber', 'musicbrainz_trmid', 'replaygain_*_gain', 'musicip_puid', 'artist', 'title', 'bpm', 'musicbrainz_trackid', 'arranger', 'albumsort', 'replaygain_*_peak', 'organization'] """ + def checkRabbitMQ(notifier): try: notifier.connection.drain_events(timeout=int(config["check_airtime_events"])) @@ -71,7 +76,7 @@ class AirtimeNotifier(Notifier): "isrc_number": "isrc",\ "copyright": "copyright",\ } - + schedule_exchange = Exchange("airtime-media-monitor", "direct", durable=True, auto_delete=True) schedule_queue = Queue("media-monitor", exchange=schedule_exchange, key="filesystem") self.connection = BrokerConnection(config["rabbitmq_host"], config["rabbitmq_user"], config["rabbitmq_password"], "/") @@ -87,7 +92,7 @@ class AirtimeNotifier(Notifier): logger = logging.getLogger('root') logger.info("Received md from RabbitMQ: " + body) - m = json.loads(message.body) + m = json.loads(message.body) airtime_file = mutagen.File(m['filepath'], easy=True) del m['filepath'] for key in m.keys() : @@ -124,21 +129,89 @@ class MediaMonitor(ProcessEvent): "copyright": "copyright",\ } + self.supported_file_formats = ['mp3', 'ogg'] self.logger = logging.getLogger('root') - self.temp_files = {} + self.imported_renamed_files = {} + + def get_md5(self, filepath): + f = open(filepath, 'rb') + m = hashlib.md5() + m.update(f.read()) + md5 = m.hexdigest() + + return md5 + + def ensure_dir(self, filepath): + + directory = os.path.dirname(filepath) + + if ((not os.path.exists(directory)) or ((os.path.exists(directory) and not os.path.isdir(directory)))): + os.makedirs(directory, 02775) + + def create_unique_filename(self, filepath): + + file_dir = os.path.dirname(filepath) + filename = os.path.basename(filepath).split(".")[0] + file_ext = os.path.splitext(filepath)[1] + + if(os.path.exists(filepath)): + i = 1; + while(True): + new_filepath = "%s/%s(%s).%s" % (file_dir, filename, i, file_ext) + + if(os.path.exists(new_filepath)): + i = i+1; + else: + filepath = new_filepath + + self.imported_renamed_files[filepath] = 0 + + return filepath + + def create_file_path(self, imported_filepath): + + global storage_directory + + original_name = os.path.basename(imported_filepath) + file_ext = os.path.splitext(imported_filepath)[1] + file_info = mutagen.File(imported_filepath, easy=True) + + metadata = {'artist':None, + 'album':None, + 'title':None, + 'tracknumber':None} + + for key in metadata.keys(): + if key in file_info: + metadata[key] = file_info[key][0] + + if metadata['artist'] is not None: + base = "%s/%s" % (storage_directory, metadata['artist']) + if metadata['album'] is not None: + base = "%s/%s" % (base, metadata['album']) + if metadata['title'] is not None: + if metadata['tracknumber'] is not None: + metadata['tracknumber'] = "%02d" % (int(metadata['tracknumber'])) + base = "%s/%s - %s" % (base, metadata['tracknumber'], metadata['title']) + else: + base = "%s/%s" % (base, metadata['title']) + else: + base = "%s/%s" % (base, original_name) + else: + base = "%s/%s" % (storage_directory, original_name) + + base = "%s%s" % (base, file_ext) + + filepath = self.create_unique_filename(base) + self.ensure_dir(filepath) + shutil.move(imported_filepath, filepath) def update_airtime(self, event): self.logger.info("Updating Change to Airtime") - try: - f = open(event.pathname, 'rb') - m = hashlib.md5() - m.update(f.read()) - - md5 = m.hexdigest() - gunid = event.name.split('.')[0] - - md = {'gunid':gunid, 'md5':md5} + try: + md5 = self.get_md5(event.pathname) + md = {'filepath':event.pathname, 'md5':md5} file_info = mutagen.File(event.pathname, easy=True) attrs = self.mutagen2airtime @@ -147,37 +220,55 @@ class MediaMonitor(ProcessEvent): md[attrs[key]] = file_info[key][0] data = {'md': md} - response = self.api_client.update_media_metadata(data) except Exception, e: self.logger.info("%s", e) + def is_renamed_file(self, filename): + if filename in self.imported_renamed_files: + del self.imported_renamed_files[filename] + return True + + return False + + def is_temp_file(self, filename): + info = filename.split(".") + + if(info[-2] in self.supported_file_formats): + return True + else : + return False + + def is_audio_file(self, filename): + info = filename.split(".") + + if(info[-1] in self.supported_file_formats): + return True + else : + return False + + def process_IN_CREATE(self, event): - if not event.dir : - filename_info = event.name.split(".") + if not event.dir: #file created is a tmp file which will be modified and then moved back to the original filename. - if len(filename_info) > 2 : + if self.is_temp_file(event.name) : self.temp_files[event.pathname] = None #This is a newly imported file. else : - pass + #if not is_renamed_file(event.pathname): + self.create_file_path(event.pathname) - self.logger.info("%s: %s", event.maskname, event.pathname) + self.logger.info("%s: %s", event.maskname, event.pathname) - #event.path : /srv/airtime/stor/bd2 - #event.name : bd2aa73b58d9c8abcced989621846e99.mp3 - #event.pathname : /srv/airtime/stor/bd2/bd2aa73b58d9c8abcced989621846e99.mp3 def process_IN_MODIFY(self, event): if not event.dir : - filename_info = event.name.split(".") - #file modified is not a tmp file. - if len(filename_info) == 2 : - self.update_airtime(event) + if self.is_audio_file(event.name) : + self.update_airtime(event) - self.logger.info("%s: path: %s name: %s", event.maskname, event.path, event.name) + self.logger.info("%s: %s", event.maskname, event.pathname) def process_IN_MOVED_FROM(self, event): if event.pathname in self.temp_files : @@ -190,7 +281,7 @@ class MediaMonitor(ProcessEvent): if event.cookie in self.temp_files : del self.temp_files[event.cookie] self.update_airtime(event) - + self.logger.info("%s: %s", event.maskname, event.pathname) def process_default(self, event): @@ -204,12 +295,13 @@ if __name__ == '__main__': #mask = pyinotify.ALL_EVENTS wm = WatchManager() - wdd = wm.add_watch('/srv/airtime/stor', mask, rec=True, auto_add=True) + wdd = wm.add_watch(storage_directory, mask, rec=True, auto_add=True) + + logger = logging.getLogger('root') + logger.info("Added watch to %s", storage_directory) notifier = AirtimeNotifier(wm, MediaMonitor(), read_freq=int(config["check_filesystem_events"]), timeout=1) notifier.coalesce_events() notifier.loop(callback=checkRabbitMQ) except KeyboardInterrupt: notifier.stop() - - diff --git a/python_apps/media-monitor/airtime-media-monitor b/python_apps/media-monitor/airtime-media-monitor index 26c5e7999..c6f892fdf 100755 --- a/python_apps/media-monitor/airtime-media-monitor +++ b/python_apps/media-monitor/airtime-media-monitor @@ -12,6 +12,6 @@ exec 2>&1 export PYTHONPATH=${api_client_path} # Note the -u when calling python! we need it to get unbuffered binary stdout and stderr -exec python -u ${media_monitor_path}${media_monitor_script} +exec python -u ${media_monitor_path}${media_monitor_script} > /var/log/airtime/media-monitor/py-interpreter.log 2>&1 # EOF diff --git a/python_apps/media-monitor/media-monitor.cfg b/python_apps/media-monitor/media-monitor.cfg index 5f2a79a83..38b44cea7 100644 --- a/python_apps/media-monitor/media-monitor.cfg +++ b/python_apps/media-monitor/media-monitor.cfg @@ -32,5 +32,5 @@ rabbitmq_password = 'guest' ############################################ # Media-Monitor preferences # ############################################ -check_filesystem_events = 30 #how long to queue up events performed on the files themselves. +check_filesystem_events = 5 #how long to queue up events performed on the files themselves. check_airtime_events = 30 #how long to queue metadata input from airtime. diff --git a/python_apps/pypo/airtime-playout b/python_apps/pypo/airtime-playout index 995575622..0eb206f1c 100755 --- a/python_apps/pypo/airtime-playout +++ b/python_apps/pypo/airtime-playout @@ -13,6 +13,6 @@ export HOME="/var/tmp/airtime/pypo/" export PYTHONPATH=${api_client_path}:$PYTHONPATH # Note the -u when calling python! we need it to get unbuffered binary stdout and stderr -exec python -u ${pypo_path}${pypo_script} +exec python -u ${pypo_path}${pypo_script} > /var/log/airtime/pypo/py-interpreter.log 2>&1 # EOF diff --git a/python_apps/pypo/pypofetch.py b/python_apps/pypo/pypofetch.py index 616a347aa..368ab269b 100755 --- a/python_apps/pypo/pypofetch.py +++ b/python_apps/pypo/pypofetch.py @@ -61,18 +61,25 @@ class PypoFetch(Thread): self.cue_file = CueFile() self.set_export_source('scheduler') self.queue = q - - logger.info("Initializing RabbitMQ stuff") - schedule_exchange = Exchange("airtime-schedule", "direct", durable=True, auto_delete=True) - schedule_queue = Queue("pypo-fetch", exchange=schedule_exchange, key="foo") - self.connection = BrokerConnection(config["rabbitmq_host"], config["rabbitmq_user"], config["rabbitmq_password"], "/") - channel = self.connection.channel() - consumer = Consumer(channel, schedule_queue) - consumer.register_callback(handle_message) - consumer.consume() - logger.info("PypoFetch: init complete") + def init_rabbit_mq(self): + logger = logging.getLogger('fetch') + logger.info("Initializing RabbitMQ stuff") + try: + schedule_exchange = Exchange("airtime-schedule", "direct", durable=True, auto_delete=True) + schedule_queue = Queue("pypo-fetch", exchange=schedule_exchange, key="foo") + self.connection = BrokerConnection(config["rabbitmq_host"], config["rabbitmq_user"], config["rabbitmq_password"], "/") + channel = self.connection.channel() + consumer = Consumer(channel, schedule_queue) + consumer.register_callback(handle_message) + consumer.consume() + except Exception, e: + logger.error(e) + return False + + return True + def set_export_source(self, export_source): self.export_source = export_source @@ -336,6 +343,10 @@ class PypoFetch(Thread): def run(self): logger = logging.getLogger('fetch') + while not self.init_rabbit_mq(): + logger.error("Error connecting to RabbitMQ Server. Trying again in few seconds") + time.sleep(5) + try: os.mkdir(self.cache_dir) except Exception, e: pass diff --git a/python_apps/show-recorder/airtime-show-recorder b/python_apps/show-recorder/airtime-show-recorder index 97124ff6f..0bd0562e6 100755 --- a/python_apps/show-recorder/airtime-show-recorder +++ b/python_apps/show-recorder/airtime-show-recorder @@ -18,6 +18,6 @@ export PYTHONPATH=${api_client_path} #this line works: su ${recorder_user} -c "python -u ${recorder_path}${recorder_script}" # Note the -u when calling python! we need it to get unbuffered binary stdout and stderr -exec python -u ${recorder_path}${recorder_script} +exec python -u ${recorder_path}${recorder_script} > /var/log/airtime/show-recorder/py-interpreter.log 2>&1 # EOF 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.