Merge branch 'master' of dev.sourcefabric.org:airtime
This commit is contained in:
commit
f13f6c6a70
|
@ -439,7 +439,9 @@ class ApiController extends Zend_Controller_Action
|
|||
$result = Application_Model_StoredFile::copyFileToStor($upload_dir, $fileName, $tempFileName);
|
||||
|
||||
if (!is_null($result)) {
|
||||
die('{"jsonrpc" : "2.0", "error" : {"code": '.$result['code'].', "message" : "'.$result['message'].'"}}');
|
||||
$this->_helper->json->sendJson(
|
||||
array("jsonrpc" => "2.0", "error" => array("code" => $result['code'], "message" => $result['message']))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -628,7 +630,7 @@ class ApiController extends Zend_Controller_Action
|
|||
$response['key'] = $k;
|
||||
array_push($responses, $response);
|
||||
}
|
||||
die( json_encode($responses) );
|
||||
$this->_helper->json->sendJson($responses);
|
||||
}
|
||||
|
||||
public function listAllFilesAction()
|
||||
|
|
|
@ -81,6 +81,17 @@ class LibraryController extends Zend_Controller_Action
|
|||
$this->view->length = $formatter->format();
|
||||
$this->view->type = $obj_sess->type;
|
||||
}
|
||||
|
||||
//get user settings and determine if we need to hide
|
||||
// or show the playlist editor
|
||||
$showPlaylist = false;
|
||||
$data = Application_Model_Preference::getLibraryScreenSettings();
|
||||
if (!is_null($data)) {
|
||||
if ($data["playlist"] == "true") {
|
||||
$showPlaylist = true;
|
||||
}
|
||||
}
|
||||
$this->view->showPlaylist = $showPlaylist;
|
||||
} catch (PlaylistNotFoundException $e) {
|
||||
$this->playlistNotFound($obj_sess->type);
|
||||
} catch (Exception $e) {
|
||||
|
@ -382,32 +393,6 @@ class LibraryController extends Zend_Controller_Action
|
|||
# terrible name for the method below. it does not only search files.
|
||||
$r = Application_Model_StoredFile::searchLibraryFiles($params);
|
||||
|
||||
//TODO move this to the datatables row callback.
|
||||
foreach ($r["aaData"] as &$data) {
|
||||
|
||||
foreach ($data as $k => &$v) {
|
||||
if ($k != "image" && $k != "checkbox") {
|
||||
$v = htmlspecialchars($v);
|
||||
}
|
||||
}
|
||||
//TODO: Replace the above foreach loop with the line below when ticket
|
||||
//CC-4896 is completed.
|
||||
//$data = array_map('htmlspecialchars', $data);
|
||||
|
||||
if ($data['ftype'] == 'audioclip') {
|
||||
$file = Application_Model_StoredFile::Recall($data['id']);
|
||||
$scid = $file->getSoundCloudId();
|
||||
|
||||
if ($scid == "-2") {
|
||||
$data['track_title'] .= '<span class="small-icon progress"/>';
|
||||
} elseif ($scid == "-3") {
|
||||
$data['track_title'] .= '<span class="small-icon sc-error"/>';
|
||||
} elseif (!is_null($scid)) {
|
||||
$data['track_title'] .= '<span class="small-icon soundcloud"/>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->view->sEcho = $r["sEcho"];
|
||||
$this->view->iTotalDisplayRecords = $r["iTotalDisplayRecords"];
|
||||
$this->view->iTotalRecords = $r["iTotalRecords"];
|
||||
|
@ -533,7 +518,7 @@ class LibraryController extends Zend_Controller_Action
|
|||
$id = $this->_getParam('id');
|
||||
Application_Model_Soundcloud::uploadSoundcloud($id);
|
||||
// we should die with ui info
|
||||
die();
|
||||
$this->_helper->json->sendJson(null);
|
||||
}
|
||||
|
||||
public function getUploadToSoundcloudStatusAction()
|
||||
|
|
|
@ -76,6 +76,6 @@ class ListenerstatController extends Zend_Controller_Action
|
|||
$endsDT = DateTime::createFromFormat("U", $ends_epoch, new DateTimeZone("UTC"));
|
||||
|
||||
$data = Application_Model_ListenerStat::getDataPointsWithinRange($startsDT->format("Y-m-d H:i:s"), $endsDT->format("Y-m-d H:i:s"), $mountName);
|
||||
die(json_encode($data));
|
||||
$this->_helper->json->sendJson($data);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ class PlaylistController extends Zend_Controller_Action
|
|||
->addActionContext('new', 'json')
|
||||
->addActionContext('edit', 'json')
|
||||
->addActionContext('delete', 'json')
|
||||
->addActionContext('close-playlist', 'json')
|
||||
->addActionContext('play', 'json')
|
||||
->addActionContext('set-playlist-fades', 'json')
|
||||
->addActionContext('get-playlist-fades', 'json')
|
||||
|
@ -26,6 +27,7 @@ class PlaylistController extends Zend_Controller_Action
|
|||
->addActionContext('smart-block-shuffle', 'json')
|
||||
->addActionContext('get-block-info', 'json')
|
||||
->addActionContext('shuffle', 'json')
|
||||
->addActionContext('empty-content', 'json')
|
||||
->initContext();
|
||||
|
||||
}
|
||||
|
@ -132,7 +134,7 @@ class PlaylistController extends Zend_Controller_Action
|
|||
if (!$p_isJson) {
|
||||
$this->createFullResponse(null);
|
||||
} else {
|
||||
die(json_encode(array("error"=>$this->view->error, "result"=>1, "html"=>$this->createFullResponse(null, $p_isJson))));
|
||||
$this->_helper->json->sendJson(array("error"=>$this->view->error, "result"=>1, "html"=>$this->createFullResponse(null, $p_isJson)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -245,6 +247,13 @@ class PlaylistController extends Zend_Controller_Action
|
|||
}
|
||||
}
|
||||
|
||||
public function closePlaylistAction() {
|
||||
$type = $this->_getParam('type');
|
||||
$obj = null;
|
||||
Application_Model_Library::changePlaylist($obj, $type);
|
||||
$this->createFullResponse($obj);
|
||||
}
|
||||
|
||||
public function addItemsAction()
|
||||
{
|
||||
$ids = $this->_getParam('aItems', array());
|
||||
|
@ -336,6 +345,26 @@ class PlaylistController extends Zend_Controller_Action
|
|||
$this->playlistUnknownError($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function emptyContentAction()
|
||||
{
|
||||
$type = $this->_getParam('obj_type');
|
||||
try {
|
||||
$obj = $this->getPlaylist($type);
|
||||
if ($type == 'playlist') {
|
||||
$obj->deleteAllFilesFromPlaylist();
|
||||
} else {
|
||||
$obj->deleteAllFilesFromBlock();
|
||||
}
|
||||
$this->createUpdateResponse($obj);
|
||||
} catch (PlaylistOutDatedException $e) {
|
||||
$this->playlistOutdated($e);
|
||||
} catch (PlaylistNotFoundException $e) {
|
||||
$this->playlistNotFound($type);
|
||||
} catch (Exception $e) {
|
||||
$this->playlistUnknownError($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function setCueAction()
|
||||
{
|
||||
|
@ -488,7 +517,7 @@ class PlaylistController extends Zend_Controller_Action
|
|||
}
|
||||
|
||||
$result["modified"] = $this->view->modified;
|
||||
die(json_encode($result));
|
||||
$this->_helper->json->sendJson($result);
|
||||
}
|
||||
|
||||
public function smartBlockGenerateAction()
|
||||
|
@ -504,7 +533,7 @@ class PlaylistController extends Zend_Controller_Action
|
|||
$form->startForm($params['obj_id']);
|
||||
if ($form->isValid($params)) {
|
||||
$result = $bl->generateSmartBlock($params['data']);
|
||||
die(json_encode(array("result"=>0, "html"=>$this->createFullResponse($bl, true, true))));
|
||||
$this->_helper->json->sendJson(array("result"=>0, "html"=>$this->createFullResponse($bl, true, true)));
|
||||
} else {
|
||||
$this->view->obj = $bl;
|
||||
$this->view->id = $bl->getId();
|
||||
|
@ -512,7 +541,7 @@ class PlaylistController extends Zend_Controller_Action
|
|||
$viewPath = 'playlist/smart-block.phtml';
|
||||
$result['html'] = $this->view->render($viewPath);
|
||||
$result['result'] = 1;
|
||||
die(json_encode($result));
|
||||
$this->_helper->json->sendJson($result);
|
||||
}
|
||||
} catch (BlockNotFoundException $e) {
|
||||
$this->playlistNotFound('block', true);
|
||||
|
@ -531,9 +560,9 @@ class PlaylistController extends Zend_Controller_Action
|
|||
$result = $bl->shuffleSmartBlock();
|
||||
|
||||
if ($result['result'] == 0) {
|
||||
die(json_encode(array("result"=>0, "html"=>$this->createFullResponse($bl, true))));
|
||||
$this->_helper->json->sendJson(array("result"=>0, "html"=>$this->createFullResponse($bl, true)));
|
||||
} else {
|
||||
die(json_encode($result));
|
||||
$this->_helper->json->sendJson($result);
|
||||
}
|
||||
} catch (BlockNotFoundException $e) {
|
||||
$this->playlistNotFound('block', true);
|
||||
|
@ -551,9 +580,9 @@ class PlaylistController extends Zend_Controller_Action
|
|||
$result = $pl->shuffle();
|
||||
|
||||
if ($result['result'] == 0) {
|
||||
die(json_encode(array("result"=>0, "html"=>$this->createFullResponse($pl, true))));
|
||||
$this->_helper->json->sendJson(array("result"=>0, "html"=>$this->createFullResponse($pl, true)));
|
||||
} else {
|
||||
die(json_encode($result));
|
||||
$this->_helper->json->sendJson($result);
|
||||
}
|
||||
} catch (PlaylistNotFoundException $e) {
|
||||
$this->playlistNotFound('block', true);
|
||||
|
@ -574,7 +603,7 @@ class PlaylistController extends Zend_Controller_Action
|
|||
$out = $bl->getCriteria();
|
||||
$out['isStatic'] = false;
|
||||
}
|
||||
die(json_encode($out));
|
||||
$this->_helper->json->sendJson($out);
|
||||
}
|
||||
}
|
||||
class WrongTypeToBlockException extends Exception {}
|
||||
|
|
|
@ -32,7 +32,7 @@ class PluploadController extends Zend_Controller_Action
|
|||
$tempFilePath = Application_Model_StoredFile::uploadFile($upload_dir);
|
||||
$tempFileName = basename($tempFilePath);
|
||||
|
||||
die('{"jsonrpc" : "2.0", "tempfilepath" : "'.$tempFileName.'" }');
|
||||
$this->_helper->json->sendJson(array("jsonrpc" => "2.0", "tempfilepath" => $tempFileName));
|
||||
}
|
||||
|
||||
public function copyfileAction()
|
||||
|
@ -43,8 +43,8 @@ class PluploadController extends Zend_Controller_Action
|
|||
$result = Application_Model_StoredFile::copyFileToStor($upload_dir,
|
||||
$filename, $tempname);
|
||||
if (!is_null($result))
|
||||
die('{"jsonrpc" : "2.0", "error" : '.json_encode($result).'}');
|
||||
$this->_helper->json->sendJson(array("jsonrpc" => "2.0", "error" => $result));
|
||||
|
||||
die('{"jsonrpc" : "2.0"}');
|
||||
$this->_helper->json->sendJson(array("jsonrpc" => "2.0"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,10 +70,10 @@ class PreferenceController extends Zend_Controller_Action
|
|||
|
||||
$this->view->statusMsg = "<div class='success'>". _("Preferences updated.")."</div>";
|
||||
$this->view->form = $form;
|
||||
die(json_encode(array("valid"=>"true", "html"=>$this->view->render('preference/index.phtml'))));
|
||||
$this->_helper->json->sendJson(array("valid"=>"true", "html"=>$this->view->render('preference/index.phtml')));
|
||||
} else {
|
||||
$this->view->form = $form;
|
||||
die(json_encode(array("valid"=>"false", "html"=>$this->view->render('preference/index.phtml'))));
|
||||
$this->_helper->json->sendJson(array("valid"=>"false", "html"=>$this->view->render('preference/index.phtml')));
|
||||
}
|
||||
}
|
||||
$this->view->form = $form;
|
||||
|
@ -247,12 +247,9 @@ class PreferenceController extends Zend_Controller_Action
|
|||
/* If the admin password values are empty then we should not
|
||||
* set the pseudo password ('xxxxxx') on the front-end
|
||||
*/
|
||||
$s1_set_admin_pass = true;
|
||||
$s2_set_admin_pass = true;
|
||||
$s3_set_admin_pass = true;
|
||||
if (empty($values["s1_data"]["admin_pass"])) $s1_set_admin_pass = false;
|
||||
if (empty($values["s2_data"]["admin_pass"])) $s2_set_admin_pass = false;
|
||||
if (empty($values["s3_data"]["admin_pass"])) $s3_set_admin_pass = false;
|
||||
$s1_set_admin_pass = !empty($values["s1_data"]["admin_pass"]);
|
||||
$s2_set_admin_pass = !empty($values["s2_data"]["admin_pass"]);
|
||||
$s3_set_admin_pass = !empty($values["s3_data"]["admin_pass"]);
|
||||
|
||||
// this goes into cc_pref table
|
||||
Application_Model_Preference::SetStreamLabelFormat($values['streamFormat']);
|
||||
|
@ -319,19 +316,19 @@ class PreferenceController extends Zend_Controller_Action
|
|||
$this->view->form = $form;
|
||||
$this->view->num_stream = $num_of_stream;
|
||||
$this->view->statusMsg = "<div class='success'>"._("Stream Setting Updated.")."</div>";
|
||||
die(json_encode(array(
|
||||
$this->_helper->json->sendJson(array(
|
||||
"valid"=>"true",
|
||||
"html"=>$this->view->render('preference/stream-setting.phtml'),
|
||||
"s1_set_admin_pass"=>$s1_set_admin_pass,
|
||||
"s2_set_admin_pass"=>$s2_set_admin_pass,
|
||||
"s3_set_admin_pass"=>$s3_set_admin_pass,
|
||||
)));
|
||||
));
|
||||
} else {
|
||||
$live_stream_subform->updateVariables();
|
||||
$this->view->enable_stream_conf = Application_Model_Preference::GetEnableStreamConf();
|
||||
$this->view->form = $form;
|
||||
$this->view->num_stream = $num_of_stream;
|
||||
die(json_encode(array("valid"=>"false", "html"=>$this->view->render('preference/stream-setting.phtml'))));
|
||||
$this->_helper->json->sendJson(array("valid"=>"false", "html"=>$this->view->render('preference/stream-setting.phtml')));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -375,7 +372,7 @@ class PreferenceController extends Zend_Controller_Action
|
|||
}
|
||||
ksort($result);
|
||||
//returns format serverBrowse is looking for.
|
||||
die(json_encode($result));
|
||||
$this->_helper->json->sendJson($result);
|
||||
}
|
||||
|
||||
public function changeStorDirectoryAction()
|
||||
|
@ -417,7 +414,7 @@ class PreferenceController extends Zend_Controller_Action
|
|||
Application_Model_RabbitMq::SendMessageToMediaMonitor('rescan_watch', $data);
|
||||
Logging::info("Unhiding all files belonging to:: $dir_path");
|
||||
$dir->unhideFiles();
|
||||
die(); # Get rid of this ugliness later
|
||||
$this->_helper->json->sendJson(null);
|
||||
}
|
||||
|
||||
public function removeWatchDirectoryAction()
|
||||
|
@ -437,7 +434,7 @@ class PreferenceController extends Zend_Controller_Action
|
|||
if (Application_Model_Preference::GetImportTimestamp()+10 > $now) {
|
||||
$res = true;
|
||||
}
|
||||
die(json_encode($res));
|
||||
$this->_helper->json->sendJson($res);
|
||||
}
|
||||
|
||||
public function getLiquidsoapStatusAction()
|
||||
|
@ -452,7 +449,7 @@ class PreferenceController extends Zend_Controller_Action
|
|||
}
|
||||
$out[] = array("id"=>$i, "status"=>$status);
|
||||
}
|
||||
die(json_encode($out));
|
||||
$this->_helper->json->sendJson($out);
|
||||
}
|
||||
|
||||
public function setSourceConnectionUrlAction()
|
||||
|
@ -470,7 +467,7 @@ class PreferenceController extends Zend_Controller_Action
|
|||
Application_Model_Preference::SetLiveDjConnectionUrlOverride($override);
|
||||
}
|
||||
|
||||
die();
|
||||
$this->_helper->json->sendJson(null);
|
||||
}
|
||||
|
||||
public function getAdminPasswordStatusAction()
|
||||
|
@ -483,6 +480,6 @@ class PreferenceController extends Zend_Controller_Action
|
|||
$out["s".$i] = true;
|
||||
}
|
||||
}
|
||||
die(json_encode($out));
|
||||
$this->_helper->json->sendJson($out);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ class ScheduleController extends Zend_Controller_Action
|
|||
->addActionContext('dj-edit-show', 'json')
|
||||
->addActionContext('calculate-duration', 'json')
|
||||
->addActionContext('get-current-show', 'json')
|
||||
->addActionContext('update-future-is-scheduled', 'json')
|
||||
->initContext();
|
||||
|
||||
$this->sched_sess = new Zend_Session_Namespace("schedule");
|
||||
|
@ -245,7 +246,7 @@ class ScheduleController extends Zend_Controller_Action
|
|||
$id = $file->getId();
|
||||
Application_Model_Soundcloud::uploadSoundcloud($id);
|
||||
// we should die with ui info
|
||||
die();
|
||||
$this->_helper->json->sendJson(null);
|
||||
}
|
||||
|
||||
public function makeContextMenuAction()
|
||||
|
@ -629,7 +630,11 @@ class ScheduleController extends Zend_Controller_Action
|
|||
if (!$showInstance->getShow()->isRepeating()) {
|
||||
$formWhen->disableStartDateAndTime();
|
||||
} else {
|
||||
$formWhen->getElement('add_show_start_date')->setOptions(array('disabled' => true));
|
||||
$nextFutureRepeatShow = $show->getNextFutureRepeatShowTime();
|
||||
$formWhen->getElement('add_show_start_date')->setValue($nextFutureRepeatShow["starts"]->format("Y-m-d"));
|
||||
$formWhen->getElement('add_show_start_time')->setValue($nextFutureRepeatShow["starts"]->format("H:i"));
|
||||
$formWhen->getElement('add_show_end_date_no_repeat')->setValue($nextFutureRepeatShow["ends"]->format("Y-m-d"));
|
||||
$formWhen->getElement('add_show_end_time')->setValue($nextFutureRepeatShow["ends"]->format("H:i"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -804,10 +809,16 @@ class ScheduleController extends Zend_Controller_Action
|
|||
}
|
||||
$data['add_show_record'] = $show->isRecorded();
|
||||
|
||||
$origianlShowStartDateTime = Application_Common_DateHelper::ConvertToLocalDateTime($show->getStartDateAndTime());
|
||||
if ($show->isRepeating()) {
|
||||
$nextFutureRepeatShow = $show->getNextFutureRepeatShowTime();
|
||||
$originalShowStartDateTime = $nextFutureRepeatShow["starts"];
|
||||
} else {
|
||||
$originalShowStartDateTime = Application_Common_DateHelper::ConvertToLocalDateTime(
|
||||
$show->getStartDateAndTime());
|
||||
}
|
||||
|
||||
$success = Application_Model_Schedule::addUpdateShow($data, $this,
|
||||
$validateStartDate, $origianlShowStartDateTime, true,
|
||||
$validateStartDate, $originalShowStartDateTime, true,
|
||||
$data['add_show_instance_id']);
|
||||
|
||||
if ($success) {
|
||||
|
@ -897,6 +908,7 @@ class ScheduleController extends Zend_Controller_Action
|
|||
try {
|
||||
$scheduler = new Application_Model_Scheduler();
|
||||
$scheduler->cancelShow($id);
|
||||
Application_Model_StoredFile::updatePastFilesIsScheduled();
|
||||
// send kick out source stream signal to pypo
|
||||
$data = array("sourcename"=>"live_dj");
|
||||
Application_Model_RabbitMq::SendMessageToPypo("disconnect_source", $data);
|
||||
|
@ -927,7 +939,7 @@ class ScheduleController extends Zend_Controller_Action
|
|||
'title' => _('Download'));
|
||||
|
||||
//returns format jjmenu is looking for.
|
||||
die(json_encode($menu));
|
||||
$this->_helper->json->sendJson($menu);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -980,4 +992,11 @@ class ScheduleController extends Zend_Controller_Action
|
|||
echo Zend_Json::encode($result);
|
||||
exit();
|
||||
}
|
||||
|
||||
public function updateFutureIsScheduledAction()
|
||||
{
|
||||
$schedId = $this->_getParam('schedId');
|
||||
$redrawLibTable = Application_Model_StoredFile::setIsScheduled($schedId, false);
|
||||
$this->_helper->json->sendJson(array("redrawLibTable" => $redrawLibTable));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,14 +83,14 @@ class UserController extends Zend_Controller_Action
|
|||
$this->view->successMessage = "<div class='success'>"._("User updated successfully!")."</div>";
|
||||
}
|
||||
|
||||
die(json_encode(array("valid"=>"true", "html"=>$this->view->render('user/add-user.phtml'))));
|
||||
$this->_helper->json->sendJson(array("valid"=>"true", "html"=>$this->view->render('user/add-user.phtml')));
|
||||
} else {
|
||||
$this->view->form = $form;
|
||||
die(json_encode(array("valid"=>"false", "html"=>$this->view->render('user/add-user.phtml'))));
|
||||
$this->_helper->json->sendJson(array("valid"=>"false", "html"=>$this->view->render('user/add-user.phtml')));
|
||||
}
|
||||
} else {
|
||||
$this->view->form = $form;
|
||||
die(json_encode(array("valid"=>"false", "html"=>$this->view->render('user/add-user.phtml'))));
|
||||
$this->_helper->json->sendJson(array("valid"=>"false", "html"=>$this->view->render('user/add-user.phtml')));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ class UsersettingsController extends Zend_Controller_Action
|
|||
->addActionContext('remindme', 'json')
|
||||
->addActionContext('remindme-never', 'json')
|
||||
->addActionContext('donotshowregistrationpopup', 'json')
|
||||
->addActionContext('set-library-screen-settings', 'json')
|
||||
->initContext();
|
||||
}
|
||||
|
||||
|
@ -54,6 +55,7 @@ class UsersettingsController extends Zend_Controller_Action
|
|||
{
|
||||
$request = $this->getRequest();
|
||||
$settings = $request->getParam("settings");
|
||||
|
||||
Application_Model_Preference::setTimelineDatatableSetting($settings);
|
||||
}
|
||||
|
||||
|
@ -91,4 +93,11 @@ class UsersettingsController extends Zend_Controller_Action
|
|||
// unset session
|
||||
Zend_Session::namespaceUnset('referrer');
|
||||
}
|
||||
|
||||
public function setLibraryScreenSettingsAction()
|
||||
{
|
||||
$request = $this->getRequest();
|
||||
$settings = $request->getParam("settings");
|
||||
Application_Model_Preference::setLibraryScreenSettings($settings);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,11 @@ class Application_Form_SmartBlockCriteria extends Zend_Form_SubForm
|
|||
private $stringCriteriaOptions;
|
||||
private $numericCriteriaOptions;
|
||||
private $limitOptions;
|
||||
|
||||
/* We need to know if the criteria value will be a string
|
||||
* or numeric value in order to populate the modifier
|
||||
* select list
|
||||
*/
|
||||
private $criteriaTypes = array(
|
||||
0 => "",
|
||||
"album_title" => "s",
|
||||
|
@ -13,6 +18,8 @@ class Application_Form_SmartBlockCriteria extends Zend_Form_SubForm
|
|||
"composer" => "s",
|
||||
"conductor" => "s",
|
||||
"copyright" => "s",
|
||||
"cuein" => "n",
|
||||
"cueout" => "n",
|
||||
"artist_name" => "s",
|
||||
"encoded_by" => "s",
|
||||
"utime" => "n",
|
||||
|
@ -45,6 +52,8 @@ class Application_Form_SmartBlockCriteria extends Zend_Form_SubForm
|
|||
"composer" => _("Composer"),
|
||||
"conductor" => _("Conductor"),
|
||||
"copyright" => _("Copyright"),
|
||||
"cuein" => _("Cue In"),
|
||||
"cueout" => _("Cue Out"),
|
||||
"artist_name" => _("Creator"),
|
||||
"encoded_by" => _("Encoded By"),
|
||||
"genre" => _("Genre"),
|
||||
|
@ -416,32 +425,34 @@ class Application_Form_SmartBlockCriteria extends Zend_Form_SubForm
|
|||
$isValid = true;
|
||||
$data = $this->preValidation($params);
|
||||
$criteria2PeerMap = array(
|
||||
0 => "Select criteria",
|
||||
"album_title" => "DbAlbumTitle",
|
||||
"artist_name" => "DbArtistName",
|
||||
"bit_rate" => "DbBitRate",
|
||||
"bpm" => "DbBpm",
|
||||
"composer" => "DbComposer",
|
||||
"conductor" => "DbConductor",
|
||||
"copyright" => "DbCopyright",
|
||||
"encoded_by" => "DbEncodedBy",
|
||||
"utime" => "DbUtime",
|
||||
"mtime" => "DbMtime",
|
||||
"lptime" => "DbLPtime",
|
||||
"genre" => "DbGenre",
|
||||
"info_url" => "DbInfoUrl",
|
||||
"isrc_number" => "DbIsrcNumber",
|
||||
"label" => "DbLabel",
|
||||
"language" => "DbLanguage",
|
||||
"length" => "DbLength",
|
||||
"mime" => "DbMime",
|
||||
"mood" => "DbMood",
|
||||
"owner_id" => "DbOwnerId",
|
||||
"replay_gain" => "DbReplayGain",
|
||||
"sample_rate" => "DbSampleRate",
|
||||
"track_title" => "DbTrackTitle",
|
||||
"track_number" => "DbTrackNumber",
|
||||
"year" => "DbYear"
|
||||
0 => "Select criteria",
|
||||
"album_title" => "DbAlbumTitle",
|
||||
"artist_name" => "DbArtistName",
|
||||
"bit_rate" => "DbBitRate",
|
||||
"bpm" => "DbBpm",
|
||||
"composer" => "DbComposer",
|
||||
"conductor" => "DbConductor",
|
||||
"copyright" => "DbCopyright",
|
||||
"cuein" => "DbCuein",
|
||||
"cueout" => "DbCueout",
|
||||
"encoded_by" => "DbEncodedBy",
|
||||
"utime" => "DbUtime",
|
||||
"mtime" => "DbMtime",
|
||||
"lptime" => "DbLPtime",
|
||||
"genre" => "DbGenre",
|
||||
"info_url" => "DbInfoUrl",
|
||||
"isrc_number" => "DbIsrcNumber",
|
||||
"label" => "DbLabel",
|
||||
"language" => "DbLanguage",
|
||||
"length" => "DbLength",
|
||||
"mime" => "DbMime",
|
||||
"mood" => "DbMood",
|
||||
"owner_id" => "DbOwnerId",
|
||||
"replay_gain" => "DbReplayGain",
|
||||
"sample_rate" => "DbSampleRate",
|
||||
"track_title" => "DbTrackTitle",
|
||||
"track_number" => "DbTrackNumber",
|
||||
"year" => "DbYear"
|
||||
);
|
||||
|
||||
// things we need to check
|
||||
|
@ -492,7 +503,7 @@ class Application_Form_SmartBlockCriteria extends Zend_Form_SubForm
|
|||
} else {
|
||||
$column = CcFilesPeer::getTableMap()->getColumnByPhpName($criteria2PeerMap[$d['sp_criteria_field']]);
|
||||
// validation on type of column
|
||||
if ($d['sp_criteria_field'] == 'length') {
|
||||
if (in_array($d['sp_criteria_field'], array('length', 'cuein', 'cueout'))) {
|
||||
if (!preg_match("/^(\d{2}):(\d{2}):(\d{2})/", $d['sp_criteria_value'])) {
|
||||
$element->addError(_("'Length' should be in '00:00:00' format"));
|
||||
$isValid = false;
|
||||
|
|
|
@ -63,6 +63,8 @@ class Application_Model_Block implements Application_Model_LibraryEditable
|
|||
"composer" => "DbComposer",
|
||||
"conductor" => "DbConductor",
|
||||
"copyright" => "DbCopyright",
|
||||
"cuein" => "DbCuein",
|
||||
"cueout" => "DbCueout",
|
||||
"encoded_by" => "DbEncodedBy",
|
||||
"utime" => "DbUtime",
|
||||
"mtime" => "DbMtime",
|
||||
|
@ -483,10 +485,19 @@ SQL;
|
|||
try {
|
||||
if (is_array($ac) && $ac[1] == 'audioclip') {
|
||||
$res = $this->insertBlockElement($this->buildEntry($ac[0], $pos));
|
||||
|
||||
// update is_playlist flag in cc_files to indicate the
|
||||
// file belongs to a playlist or block (in this case a block)
|
||||
$db_file = CcFilesQuery::create()->findPk($ac[0], $this->con);
|
||||
$db_file->setDbIsPlaylist(true)->save($this->con);
|
||||
|
||||
$pos = $pos + 1;
|
||||
} elseif (!is_array($ac)) {
|
||||
$res = $this->insertBlockElement($this->buildEntry($ac, $pos));
|
||||
$pos = $pos + 1;
|
||||
|
||||
$db_file = CcFilesQuery::create()->findPk($ac, $this->con);
|
||||
$db_file->setDbIsPlaylist(true)->save($this->con);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
Logging::info($e->getMessage());
|
||||
|
@ -599,10 +610,21 @@ SQL;
|
|||
|
||||
try {
|
||||
|
||||
// we need to get the file id of the item we are deleting
|
||||
// before the item gets deleted from the block
|
||||
$itemsToDelete = CcBlockcontentsQuery::create()
|
||||
->filterByPrimaryKeys($p_items)
|
||||
->filterByDbFileId(null, Criteria::NOT_EQUAL)
|
||||
->find($this->con);
|
||||
|
||||
CcBlockcontentsQuery::create()
|
||||
->findPKs($p_items)
|
||||
->delete($this->con);
|
||||
|
||||
// now that the items have been deleted we can update the
|
||||
// is_playlist flag in cc_files
|
||||
Application_Model_StoredFile::setIsPlaylist($itemsToDelete, 'block', false);
|
||||
|
||||
$contents = CcBlockcontentsQuery::create()
|
||||
->filterByDbBlockId($this->id)
|
||||
->orderByDbPosition()
|
||||
|
@ -972,16 +994,36 @@ SQL;
|
|||
$user = new Application_Model_User($userInfo->id);
|
||||
$isAdminOrPM = $user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER));
|
||||
|
||||
// get only the files from the blocks
|
||||
// we are about to delete
|
||||
$itemsToDelete = CcBlockcontentsQuery::create()
|
||||
->filterByDbBlockId($p_ids)
|
||||
->filterByDbFileId(null, Criteria::NOT_EQUAL)
|
||||
->find();
|
||||
|
||||
$updateIsPlaylistFlag = false;
|
||||
|
||||
if (!$isAdminOrPM) {
|
||||
$leftOver = self::blocksNotOwnedByUser($p_ids, $p_userId);
|
||||
|
||||
if (count($leftOver) == 0) {
|
||||
CcBlockQuery::create()->findPKs($p_ids)->delete();
|
||||
$updateIsPlaylistFlag = true;
|
||||
} else {
|
||||
throw new BlockNoPermissionException;
|
||||
}
|
||||
} else {
|
||||
CcBlockQuery::create()->findPKs($p_ids)->delete();
|
||||
$updateIsPlaylistFlag = true;
|
||||
}
|
||||
|
||||
if ($updateIsPlaylistFlag) {
|
||||
// update is_playlist flag in cc_files
|
||||
Application_Model_StoredFile::setIsPlaylist(
|
||||
$itemsToDelete,
|
||||
'block',
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1007,8 +1049,26 @@ SQL;
|
|||
*/
|
||||
public function deleteAllFilesFromBlock()
|
||||
{
|
||||
// get only the files from the playlist
|
||||
// we are about to clear out
|
||||
$itemsToDelete = CcBlockcontentsQuery::create()
|
||||
->filterByDbBlockId($this->id)
|
||||
->filterByDbFileId(null, Criteria::NOT_EQUAL)
|
||||
->find();
|
||||
|
||||
CcBlockcontentsQuery::create()->findByDbBlockId($this->id)->delete();
|
||||
$this->block->reload();
|
||||
|
||||
// update is_playlist flag in cc_files
|
||||
Application_Model_StoredFile::setIsPlaylist(
|
||||
$itemsToDelete,
|
||||
'block',
|
||||
false
|
||||
);
|
||||
|
||||
//$this->block->reload();
|
||||
$this->block->setDbMtime(new DateTime("now", new DateTimeZone("UTC")));
|
||||
$this->block->save($this->con);
|
||||
$this->con->commit();
|
||||
}
|
||||
|
||||
// smart block functions start
|
||||
|
@ -1220,6 +1280,8 @@ SQL;
|
|||
"composer" => _("Composer"),
|
||||
"conductor" => _("Conductor"),
|
||||
"copyright" => _("Copyright"),
|
||||
"cuein" => _("Cue In"),
|
||||
"cueout" => _("Cue Out"),
|
||||
"artist_name" => _("Creator"),
|
||||
"encoded_by" => _("Encoded By"),
|
||||
"genre" => _("Genre"),
|
||||
|
@ -1312,7 +1374,7 @@ SQL;
|
|||
* user only sees the rounded version (i.e. 4:02.7 is 4:02.761625
|
||||
* in the database)
|
||||
*/
|
||||
} elseif ($spCriteria == 'length' && $spCriteriaModifier == "is") {
|
||||
} elseif (in_array($spCriteria, array('length', 'cuein', 'cueout')) && $spCriteriaModifier == "is") {
|
||||
$spCriteriaModifier = "starts with";
|
||||
$spCriteria = $spCriteria.'::text';
|
||||
$spCriteriaValue = $criteria['value'];
|
||||
|
@ -1441,6 +1503,20 @@ SQL;
|
|||
|
||||
return $output;
|
||||
}
|
||||
public static function getAllBlockFiles()
|
||||
{
|
||||
$con = Propel::getConnection();
|
||||
$sql = <<<SQL
|
||||
SELECT distinct(file_id)
|
||||
FROM cc_blockcontents
|
||||
SQL;
|
||||
$files = $con->query($sql)->fetchAll();
|
||||
$real_files = array();
|
||||
foreach ($files as $f) {
|
||||
$real_files[] = $f['file_id'];
|
||||
}
|
||||
return $real_files;
|
||||
}
|
||||
// smart block functions end
|
||||
}
|
||||
|
||||
|
|
|
@ -477,6 +477,12 @@ SQL;
|
|||
|
||||
foreach ($p_items as $ac) {
|
||||
$res = $this->insertPlaylistElement($this->buildEntry($ac, $pos));
|
||||
|
||||
// update is_playlist flag in cc_files to indicate the
|
||||
// file belongs to a playlist or block (in this case a playlist)
|
||||
$db_file = CcFilesQuery::create()->findPk($ac[0], $this->con);
|
||||
$db_file->setDbIsPlaylist(true)->save($this->con);
|
||||
|
||||
$pos = $pos + 1;
|
||||
Logging::info("Adding $ac[1] $ac[0]");
|
||||
|
||||
|
@ -585,10 +591,21 @@ SQL;
|
|||
|
||||
try {
|
||||
|
||||
// we need to get the file id of the item we are deleting
|
||||
// before the item gets deleted from the playlist
|
||||
$itemsToDelete = CcPlaylistcontentsQuery::create()
|
||||
->filterByPrimaryKeys($p_items)
|
||||
->filterByDbFileId(null, Criteria::NOT_EQUAL)
|
||||
->find($this->con);
|
||||
|
||||
CcPlaylistcontentsQuery::create()
|
||||
->findPKs($p_items)
|
||||
->delete($this->con);
|
||||
|
||||
// now that the items have been deleted we can update the
|
||||
// is_playlist flag in cc_files
|
||||
Application_Model_StoredFile::setIsPlaylist($itemsToDelete, 'playlist', false);
|
||||
|
||||
$contents = CcPlaylistcontentsQuery::create()
|
||||
->filterByDbPlaylistId($this->id)
|
||||
->orderByDbPosition()
|
||||
|
@ -612,8 +629,6 @@ SQL;
|
|||
|
||||
public function getFadeInfo($pos)
|
||||
{
|
||||
Logging::info("Getting fade info for pos {$pos}");
|
||||
|
||||
$row = CcPlaylistcontentsQuery::create()
|
||||
->joinWith(CcFilesPeer::OM_CLASS)
|
||||
->filterByDbPlaylistId($this->id)
|
||||
|
@ -905,15 +920,36 @@ SQL;
|
|||
$user = new Application_Model_User($userInfo->id);
|
||||
$isAdminOrPM = $user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER));
|
||||
|
||||
// get only the files from the playlists
|
||||
// we are about to delete
|
||||
$itemsToDelete = CcPlaylistcontentsQuery::create()
|
||||
->filterByDbPlaylistId($p_ids)
|
||||
->filterByDbFileId(null, Criteria::NOT_EQUAL)
|
||||
->find();
|
||||
|
||||
$updateIsPlaylistFlag = false;
|
||||
|
||||
if (!$isAdminOrPM) {
|
||||
$leftOver = self::playlistsNotOwnedByUser($p_ids, $p_userId);
|
||||
if (count($leftOver) == 0) {
|
||||
CcPlaylistQuery::create()->findPKs($p_ids)->delete();
|
||||
$updateIsPlaylistFlag = true;
|
||||
|
||||
} else {
|
||||
throw new PlaylistNoPermissionException;
|
||||
}
|
||||
} else {
|
||||
CcPlaylistQuery::create()->findPKs($p_ids)->delete();
|
||||
$updateIsPlaylistFlag = true;
|
||||
}
|
||||
|
||||
if ($updateIsPlaylistFlag) {
|
||||
// update is_playlist flag in cc_files
|
||||
Application_Model_StoredFile::setIsPlaylist(
|
||||
$itemsToDelete,
|
||||
'playlist',
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -940,7 +976,25 @@ SQL;
|
|||
*/
|
||||
public function deleteAllFilesFromPlaylist()
|
||||
{
|
||||
// get only the files from the playlist
|
||||
// we are about to clear out
|
||||
$itemsToDelete = CcPlaylistcontentsQuery::create()
|
||||
->filterByDbPlaylistId($this->id)
|
||||
->filterByDbFileId(null, Criteria::NOT_EQUAL)
|
||||
->find();
|
||||
|
||||
CcPlaylistcontentsQuery::create()->findByDbPlaylistId($this->id)->delete();
|
||||
|
||||
// update is_playlist flag in cc_files
|
||||
Application_Model_StoredFile::setIsPlaylist(
|
||||
$itemsToDelete,
|
||||
'playlist',
|
||||
false
|
||||
);
|
||||
|
||||
$this->pl->setDbMtime(new DateTime("now", new DateTimeZone("UTC")));
|
||||
$this->pl->save($this->con);
|
||||
$this->con->commit();
|
||||
}
|
||||
|
||||
public function shuffle()
|
||||
|
@ -966,6 +1020,38 @@ SQL;
|
|||
return $result;
|
||||
}
|
||||
|
||||
public static function getAllPlaylistFiles()
|
||||
{
|
||||
$con = Propel::getConnection();
|
||||
$sql = <<<SQL
|
||||
SELECT distinct(file_id)
|
||||
FROM cc_playlistcontents
|
||||
WHERE file_id is not null
|
||||
SQL;
|
||||
$files = $con->query($sql)->fetchAll();
|
||||
$real_files = array();
|
||||
foreach ($files as $f) {
|
||||
$real_files[] = $f['file_id'];
|
||||
}
|
||||
return $real_files;
|
||||
}
|
||||
|
||||
public static function getAllPlaylistStreams()
|
||||
{
|
||||
$con = Propel::getConnection();
|
||||
$sql = <<<SQL
|
||||
SELECT distinct(stream_id)
|
||||
FROM cc_playlistcontents
|
||||
WHERE stream_id is not null
|
||||
SQL;
|
||||
$streams = $con->query($sql)->fetchAll();
|
||||
$real_streams = array();
|
||||
foreach ($streams as $s) {
|
||||
$real_streams[] = $s['stream_id'];
|
||||
}
|
||||
return $real_streams;
|
||||
}
|
||||
|
||||
} // class Playlist
|
||||
|
||||
class PlaylistNotFoundException extends Exception {}
|
||||
|
|
|
@ -1223,9 +1223,9 @@ class Application_Model_Preference
|
|||
$num_columns = count(Application_Model_StoredFile::getLibraryColumns());
|
||||
$new_columns_num = count($settings['abVisCols']);
|
||||
|
||||
if ($num_columns != $new_columns_num) {
|
||||
/*if ($num_columns != $new_columns_num) {
|
||||
throw new Exception("Trying to write a user column preference with incorrect number of columns!");
|
||||
}
|
||||
}*/
|
||||
|
||||
$data = serialize($settings);
|
||||
$v = self::setValue("library_datatable", $data, true);
|
||||
|
@ -1262,7 +1262,19 @@ class Application_Model_Preference
|
|||
$data = self::getValue("nowplaying_screen", true);
|
||||
return ($data != "") ? unserialize($data) : null;
|
||||
}
|
||||
|
||||
|
||||
public static function setLibraryScreenSettings($settings)
|
||||
{
|
||||
$data = serialize($settings);
|
||||
self::setValue("library_screen", $data, true);
|
||||
}
|
||||
|
||||
public static function getLibraryScreenSettings()
|
||||
{
|
||||
$data = self::getValue("library_screen", true);
|
||||
return ($data != "") ? unserialize($data) : null;
|
||||
}
|
||||
|
||||
public static function SetEnableReplayGain($value) {
|
||||
self::setValue("enable_replay_gain", $value, false);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,41 @@ SQL;
|
|||
return (is_numeric($count) && ($count != '0'));
|
||||
}
|
||||
|
||||
public static function getAllFutureScheduledFiles()
|
||||
{
|
||||
$con = Propel::getConnection();
|
||||
$sql = <<<SQL
|
||||
SELECT distinct(file_id)
|
||||
FROM cc_schedule
|
||||
WHERE ends > now() AT TIME ZONE 'UTC'
|
||||
AND file_id is not null
|
||||
SQL;
|
||||
$files = $con->query($sql)->fetchAll();
|
||||
$real_files = array();
|
||||
foreach ($files as $f) {
|
||||
$real_files[] = $f['file_id'];
|
||||
}
|
||||
|
||||
return $real_files;
|
||||
}
|
||||
|
||||
public static function getAllFutureScheduledWebstreams()
|
||||
{
|
||||
$con = Propel::getConnection();
|
||||
$sql = <<<SQL
|
||||
SELECT distinct(stream_id)
|
||||
FROM cc_schedule
|
||||
WHERE ends > now() AT TIME ZONE 'UTC'
|
||||
AND stream_id is not null
|
||||
SQL;
|
||||
$streams = $con->query($sql)->fetchAll();
|
||||
$real_streams = array();
|
||||
foreach ($streams as $s) {
|
||||
$real_streams[] = $s['stream_id'];
|
||||
}
|
||||
|
||||
return $real_streams;
|
||||
}
|
||||
/**
|
||||
* Returns data related to the scheduled items.
|
||||
*
|
||||
|
|
|
@ -525,6 +525,13 @@ class Application_Model_Scheduler
|
|||
$instance->updateScheduleStatus($this->con);
|
||||
}
|
||||
|
||||
// update is_scheduled flag for each cc_file
|
||||
foreach ($schedFiles as $file) {
|
||||
$db_file = CcFilesQuery::create()->findPk($file['id'], $this->con);
|
||||
$db_file->setDbIsScheduled(true);
|
||||
$db_file->save($this->con);
|
||||
}
|
||||
|
||||
$endProfile = microtime(true);
|
||||
Logging::debug("updating show instances status.");
|
||||
Logging::debug(floatval($endProfile) - floatval($startProfile));
|
||||
|
@ -729,6 +736,16 @@ class Application_Model_Scheduler
|
|||
} else {
|
||||
$removedItem->delete($this->con);
|
||||
}
|
||||
|
||||
// update is_scheduled in cc_files but only if
|
||||
// the file is not scheduled somewhere else
|
||||
$fileId = $removedItem->getDbFileId();
|
||||
// check if the removed item is scheduled somewhere else
|
||||
$futureScheduledFiles = Application_Model_Schedule::getAllFutureScheduledFiles();
|
||||
if (!is_null($fileId) && !in_array($fileId, $futureScheduledFiles)) {
|
||||
$db_file = CcFilesQuery::create()->findPk($fileId, $this->con);
|
||||
$db_file->setDbIsScheduled(false)->save($this->con);
|
||||
}
|
||||
}
|
||||
|
||||
if ($adjustSched === true) {
|
||||
|
|
|
@ -663,6 +663,30 @@ SQL;
|
|||
$con->exec($sql);
|
||||
}
|
||||
|
||||
public function getNextFutureRepeatShowTime()
|
||||
{
|
||||
$sql = <<<SQL
|
||||
SELECT starts, ends FROM cc_show_instances
|
||||
WHERE ends > now() at time zone 'UTC'
|
||||
AND show_id = :showId
|
||||
ORDER BY starts
|
||||
LIMIT 1
|
||||
SQL;
|
||||
$result = Application_Common_Database::prepareAndExecute( $sql,
|
||||
array( 'showId' => $this->getId() ), 'all' );
|
||||
|
||||
foreach ($result as $r) {
|
||||
$show["starts"] = new DateTime($r["starts"], new DateTimeZone('UTC'));
|
||||
$show["ends"] = new DateTime($r["ends"], new DateTimeZone('UTC'));
|
||||
}
|
||||
$currentUser = Application_Model_User::getCurrentUser();
|
||||
$currentUserId = $currentUser->getId();
|
||||
$userTimezone = Application_Model_Preference::GetUserTimezone($currentUserId);
|
||||
$show["starts"]->setTimezone(new DateTimeZone($userTimezone));
|
||||
$show["ends"]->setTimezone(new DateTimeZone($userTimezone));
|
||||
return $show;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the start date of the current show in UTC timezone.
|
||||
*
|
||||
|
|
|
@ -650,7 +650,8 @@ SQL;
|
|||
"track_number", "mood", "bpm", "composer", "info_url",
|
||||
"bit_rate", "sample_rate", "isrc_number", "encoded_by", "label",
|
||||
"copyright", "mime", "language", "filepath", "owner_id",
|
||||
"conductor", "replay_gain", "lptime" );
|
||||
"conductor", "replay_gain", "lptime", "is_playlist", "is_scheduled",
|
||||
"cuein", "cueout" );
|
||||
}
|
||||
|
||||
public static function searchLibraryFiles($datatables)
|
||||
|
@ -702,6 +703,16 @@ SQL;
|
|||
$blSelect[] = "NULL::TIMESTAMP AS ".$key;
|
||||
$fileSelect[] = $key;
|
||||
$streamSelect[] = $key;
|
||||
} elseif ($key === "is_scheduled" || $key === "is_playlist") {
|
||||
$plSelect[] = "NULL::boolean AS ".$key;
|
||||
$blSelect[] = "NULL::boolean AS ".$key;
|
||||
$fileSelect[] = $key;
|
||||
$streamSelect[] = "NULL::boolean AS ".$key;
|
||||
} elseif ($key === "cuein" || $key === "cueout") {
|
||||
$plSelect[] = "NULL::INTERVAL AS ".$key;
|
||||
$blSelect[] = "NULL::INTERVAL AS ".$key;
|
||||
$fileSelect[] = $key;
|
||||
$streamSelect[] = "NULL::INTERVAL AS ".$key;
|
||||
}
|
||||
//same columns in each table.
|
||||
else if (in_array($key, array("length", "utime", "mtime"))) {
|
||||
|
@ -775,14 +786,22 @@ SQL;
|
|||
$fromTable = $unionTable;
|
||||
}
|
||||
|
||||
// update is_scheduled to false for tracks that
|
||||
// have already played out
|
||||
self::updatePastFilesIsScheduled();
|
||||
$results = Application_Model_Datatables::findEntries($con, $displayColumns, $fromTable, $datatables);
|
||||
|
||||
//Used by the audio preview functionality in the library.
|
||||
foreach ($results['aaData'] as &$row) {
|
||||
$row['id'] = intval($row['id']);
|
||||
|
||||
$formatter = new LengthFormatter($row['length']);
|
||||
$row['length'] = $formatter->format();
|
||||
$len_formatter = new LengthFormatter($row['length']);
|
||||
$row['length'] = $len_formatter->format();
|
||||
|
||||
$cuein_formatter = new LengthFormatter($row["cuein"]);
|
||||
$row["cuein"] = $cuein_formatter->format();
|
||||
|
||||
$cueout_formatter = new LengthFormatter($row["cueout"]);
|
||||
$row["cueout"] = $cueout_formatter->format();
|
||||
|
||||
if ($row['ftype'] === "audioclip") {
|
||||
$formatter = new SamplerateFormatter($row['sample_rate']);
|
||||
|
@ -790,6 +809,15 @@ SQL;
|
|||
|
||||
$formatter = new BitrateFormatter($row['bit_rate']);
|
||||
$row['bit_rate'] = $formatter->format();
|
||||
|
||||
//soundcloud status
|
||||
$file = Application_Model_StoredFile::Recall($row['id']);
|
||||
$row['soundcloud_status'] = $file->getSoundCloudId();
|
||||
|
||||
// for audio preview
|
||||
$row['audioFile'] = $row['id'].".".pathinfo($row['filepath'], PATHINFO_EXTENSION);
|
||||
} else {
|
||||
$row['audioFile'] = $row['id'];
|
||||
}
|
||||
|
||||
//convert mtime and utime to localtime
|
||||
|
@ -800,31 +828,13 @@ SQL;
|
|||
$row['utime']->setTimeZone(new DateTimeZone(date_default_timezone_get()));
|
||||
$row['utime'] = $row['utime']->format('Y-m-d H:i:s');
|
||||
|
||||
// add checkbox row
|
||||
$row['checkbox'] = "<input type='checkbox' name='cb_".$row['id']."'>";
|
||||
// we need to initalize the checkbox and image row because we do not retrieve
|
||||
// any data from the db for these and datatables will complain
|
||||
$row['checkbox'] = "";
|
||||
$row['image'] = "";
|
||||
|
||||
$type = substr($row['ftype'], 0, 2);
|
||||
|
||||
$row['tr_id'] = "{$type}_{$row['id']}";
|
||||
|
||||
//TODO url like this to work on both playlist/showbuilder
|
||||
//screens. datatable stuff really needs to be pulled out and
|
||||
//generalized within the project access to zend view methods
|
||||
//to access url helpers is needed.
|
||||
|
||||
// TODO : why is there inline html here? breaks abstraction and is
|
||||
// ugly
|
||||
if ($type == "au") {
|
||||
$row['audioFile'] = $row['id'].".".pathinfo($row['filepath'], PATHINFO_EXTENSION);
|
||||
$row['image'] = '<img title="'._("Track preview").'" src="'.$baseUrl.'css/images/icon_audioclip.png">';
|
||||
} elseif ($type == "pl") {
|
||||
$row['image'] = '<img title="'._("Playlist preview").'" src="'.$baseUrl.'css/images/icon_playlist.png">';
|
||||
} elseif ($type == "st") {
|
||||
$row['audioFile'] = $row['id'];
|
||||
$row['image'] = '<img title="'._("Webstream preview").'" src="'.$baseUrl.'css/images/icon_webstream.png">';
|
||||
} elseif ($type == "bl") {
|
||||
$row['image'] = '<img title="'._("Smart Block").'" src="'.$baseUrl.'css/images/icon_smart-block.png">';
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
|
@ -1293,6 +1303,57 @@ SQL;
|
|||
}
|
||||
}
|
||||
|
||||
public static function setIsPlaylist($p_playlistItems, $p_type, $p_status) {
|
||||
foreach ($p_playlistItems as $item) {
|
||||
$file = self::Recall($item->getDbFileId());
|
||||
$fileId = $file->_file->getDbId();
|
||||
if ($p_type == 'playlist') {
|
||||
// we have to check if the file is in another playlist before
|
||||
// we can update
|
||||
if (!is_null($fileId) && !in_array($fileId, Application_Model_Playlist::getAllPlaylistFiles())) {
|
||||
$file->_file->setDbIsPlaylist($p_status)->save();
|
||||
}
|
||||
} elseif ($p_type == 'block') {
|
||||
if (!is_null($fileId) && !in_array($fileId, Application_Model_Block::getAllBlockFiles())) {
|
||||
$file->_file->setDbIsPlaylist($p_status)->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function setIsScheduled($p_scheduleItem, $p_status, $p_fileId=null) {
|
||||
if (is_null($p_fileId)) {
|
||||
$fileId = Application_Model_Schedule::GetFileId($p_scheduleItem);
|
||||
} else {
|
||||
$fileId = $p_fileId;
|
||||
}
|
||||
$file = self::Recall($fileId);
|
||||
$updateIsScheduled = false;
|
||||
|
||||
if (!is_null($fileId) && !in_array($fileId, Application_Model_Schedule::getAllFutureScheduledFiles())) {
|
||||
$file->_file->setDbIsScheduled($p_status)->save();
|
||||
$updateIsScheduled = true;
|
||||
}
|
||||
|
||||
return $updateIsScheduled;
|
||||
}
|
||||
|
||||
public static function updatePastFilesIsScheduled()
|
||||
{
|
||||
$con = Propel::getConnection();
|
||||
$sql = <<<SQL
|
||||
SELECT file_id FROM cc_schedule
|
||||
WHERE ends < now() at time zone 'UTC'
|
||||
SQL;
|
||||
$files = $con->query($sql)->fetchAll();
|
||||
foreach ($files as $file) {
|
||||
if (!is_null($file['file_id'])) {
|
||||
self::setIsScheduled(null, false, $file['file_id']);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function getRealClipLength($p_cuein, $p_cueout) {
|
||||
$sql = "SELECT :cueout::INTERVAL - :cuein::INTERVAL";
|
||||
|
||||
|
|
|
@ -106,6 +106,8 @@ class CcFilesTableMap extends TableMap {
|
|||
$this->addColumn('CUEOUT', 'DbCueout', 'VARCHAR', false, null, '00:00:00');
|
||||
$this->addColumn('SILAN_CHECK', 'DbSilanCheck', 'BOOLEAN', false, null, false);
|
||||
$this->addColumn('HIDDEN', 'DbHidden', 'BOOLEAN', false, null, false);
|
||||
$this->addColumn('IS_SCHEDULED', 'DbIsScheduled', 'BOOLEAN', false, null, false);
|
||||
$this->addColumn('IS_PLAYLIST', 'DbIsPlaylist', 'BOOLEAN', false, null, false);
|
||||
// validators
|
||||
} // initialize()
|
||||
|
||||
|
|
|
@ -444,6 +444,20 @@ abstract class BaseCcFiles extends BaseObject implements Persistent
|
|||
*/
|
||||
protected $hidden;
|
||||
|
||||
/**
|
||||
* The value for the is_scheduled field.
|
||||
* Note: this column has a database default value of: false
|
||||
* @var boolean
|
||||
*/
|
||||
protected $is_scheduled;
|
||||
|
||||
/**
|
||||
* The value for the is_playlist field.
|
||||
* Note: this column has a database default value of: false
|
||||
* @var boolean
|
||||
*/
|
||||
protected $is_playlist;
|
||||
|
||||
/**
|
||||
* @var CcSubjs
|
||||
*/
|
||||
|
@ -513,6 +527,8 @@ abstract class BaseCcFiles extends BaseObject implements Persistent
|
|||
$this->cueout = '00:00:00';
|
||||
$this->silan_check = false;
|
||||
$this->hidden = false;
|
||||
$this->is_scheduled = false;
|
||||
$this->is_playlist = false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1297,6 +1313,26 @@ abstract class BaseCcFiles extends BaseObject implements Persistent
|
|||
return $this->hidden;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the [is_scheduled] column value.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function getDbIsScheduled()
|
||||
{
|
||||
return $this->is_scheduled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the [is_playlist] column value.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function getDbIsPlaylist()
|
||||
{
|
||||
return $this->is_playlist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of [id] column.
|
||||
*
|
||||
|
@ -2785,6 +2821,46 @@ abstract class BaseCcFiles extends BaseObject implements Persistent
|
|||
return $this;
|
||||
} // setDbHidden()
|
||||
|
||||
/**
|
||||
* Set the value of [is_scheduled] column.
|
||||
*
|
||||
* @param boolean $v new value
|
||||
* @return CcFiles The current object (for fluent API support)
|
||||
*/
|
||||
public function setDbIsScheduled($v)
|
||||
{
|
||||
if ($v !== null) {
|
||||
$v = (boolean) $v;
|
||||
}
|
||||
|
||||
if ($this->is_scheduled !== $v || $this->isNew()) {
|
||||
$this->is_scheduled = $v;
|
||||
$this->modifiedColumns[] = CcFilesPeer::IS_SCHEDULED;
|
||||
}
|
||||
|
||||
return $this;
|
||||
} // setDbIsScheduled()
|
||||
|
||||
/**
|
||||
* Set the value of [is_playlist] column.
|
||||
*
|
||||
* @param boolean $v new value
|
||||
* @return CcFiles The current object (for fluent API support)
|
||||
*/
|
||||
public function setDbIsPlaylist($v)
|
||||
{
|
||||
if ($v !== null) {
|
||||
$v = (boolean) $v;
|
||||
}
|
||||
|
||||
if ($this->is_playlist !== $v || $this->isNew()) {
|
||||
$this->is_playlist = $v;
|
||||
$this->modifiedColumns[] = CcFilesPeer::IS_PLAYLIST;
|
||||
}
|
||||
|
||||
return $this;
|
||||
} // setDbIsPlaylist()
|
||||
|
||||
/**
|
||||
* Indicates whether the columns in this object are only set to default values.
|
||||
*
|
||||
|
@ -2843,6 +2919,14 @@ abstract class BaseCcFiles extends BaseObject implements Persistent
|
|||
return false;
|
||||
}
|
||||
|
||||
if ($this->is_scheduled !== false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->is_playlist !== false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// otherwise, everything was equal, so return TRUE
|
||||
return true;
|
||||
} // hasOnlyDefaultValues()
|
||||
|
@ -2933,6 +3017,8 @@ abstract class BaseCcFiles extends BaseObject implements Persistent
|
|||
$this->cueout = ($row[$startcol + 65] !== null) ? (string) $row[$startcol + 65] : null;
|
||||
$this->silan_check = ($row[$startcol + 66] !== null) ? (boolean) $row[$startcol + 66] : null;
|
||||
$this->hidden = ($row[$startcol + 67] !== null) ? (boolean) $row[$startcol + 67] : null;
|
||||
$this->is_scheduled = ($row[$startcol + 68] !== null) ? (boolean) $row[$startcol + 68] : null;
|
||||
$this->is_playlist = ($row[$startcol + 69] !== null) ? (boolean) $row[$startcol + 69] : null;
|
||||
$this->resetModified();
|
||||
|
||||
$this->setNew(false);
|
||||
|
@ -2941,7 +3027,7 @@ abstract class BaseCcFiles extends BaseObject implements Persistent
|
|||
$this->ensureConsistency();
|
||||
}
|
||||
|
||||
return $startcol + 68; // 68 = CcFilesPeer::NUM_COLUMNS - CcFilesPeer::NUM_LAZY_LOAD_COLUMNS).
|
||||
return $startcol + 70; // 70 = CcFilesPeer::NUM_COLUMNS - CcFilesPeer::NUM_LAZY_LOAD_COLUMNS).
|
||||
|
||||
} catch (Exception $e) {
|
||||
throw new PropelException("Error populating CcFiles object", $e);
|
||||
|
@ -3578,6 +3664,12 @@ abstract class BaseCcFiles extends BaseObject implements Persistent
|
|||
case 67:
|
||||
return $this->getDbHidden();
|
||||
break;
|
||||
case 68:
|
||||
return $this->getDbIsScheduled();
|
||||
break;
|
||||
case 69:
|
||||
return $this->getDbIsPlaylist();
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
break;
|
||||
|
@ -3670,6 +3762,8 @@ abstract class BaseCcFiles extends BaseObject implements Persistent
|
|||
$keys[65] => $this->getDbCueout(),
|
||||
$keys[66] => $this->getDbSilanCheck(),
|
||||
$keys[67] => $this->getDbHidden(),
|
||||
$keys[68] => $this->getDbIsScheduled(),
|
||||
$keys[69] => $this->getDbIsPlaylist(),
|
||||
);
|
||||
if ($includeForeignObjects) {
|
||||
if (null !== $this->aFkOwner) {
|
||||
|
@ -3916,6 +4010,12 @@ abstract class BaseCcFiles extends BaseObject implements Persistent
|
|||
case 67:
|
||||
$this->setDbHidden($value);
|
||||
break;
|
||||
case 68:
|
||||
$this->setDbIsScheduled($value);
|
||||
break;
|
||||
case 69:
|
||||
$this->setDbIsPlaylist($value);
|
||||
break;
|
||||
} // switch()
|
||||
}
|
||||
|
||||
|
@ -4008,6 +4108,8 @@ abstract class BaseCcFiles extends BaseObject implements Persistent
|
|||
if (array_key_exists($keys[65], $arr)) $this->setDbCueout($arr[$keys[65]]);
|
||||
if (array_key_exists($keys[66], $arr)) $this->setDbSilanCheck($arr[$keys[66]]);
|
||||
if (array_key_exists($keys[67], $arr)) $this->setDbHidden($arr[$keys[67]]);
|
||||
if (array_key_exists($keys[68], $arr)) $this->setDbIsScheduled($arr[$keys[68]]);
|
||||
if (array_key_exists($keys[69], $arr)) $this->setDbIsPlaylist($arr[$keys[69]]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4087,6 +4189,8 @@ abstract class BaseCcFiles extends BaseObject implements Persistent
|
|||
if ($this->isColumnModified(CcFilesPeer::CUEOUT)) $criteria->add(CcFilesPeer::CUEOUT, $this->cueout);
|
||||
if ($this->isColumnModified(CcFilesPeer::SILAN_CHECK)) $criteria->add(CcFilesPeer::SILAN_CHECK, $this->silan_check);
|
||||
if ($this->isColumnModified(CcFilesPeer::HIDDEN)) $criteria->add(CcFilesPeer::HIDDEN, $this->hidden);
|
||||
if ($this->isColumnModified(CcFilesPeer::IS_SCHEDULED)) $criteria->add(CcFilesPeer::IS_SCHEDULED, $this->is_scheduled);
|
||||
if ($this->isColumnModified(CcFilesPeer::IS_PLAYLIST)) $criteria->add(CcFilesPeer::IS_PLAYLIST, $this->is_playlist);
|
||||
|
||||
return $criteria;
|
||||
}
|
||||
|
@ -4215,6 +4319,8 @@ abstract class BaseCcFiles extends BaseObject implements Persistent
|
|||
$copyObj->setDbCueout($this->cueout);
|
||||
$copyObj->setDbSilanCheck($this->silan_check);
|
||||
$copyObj->setDbHidden($this->hidden);
|
||||
$copyObj->setDbIsScheduled($this->is_scheduled);
|
||||
$copyObj->setDbIsPlaylist($this->is_playlist);
|
||||
|
||||
if ($deepCopy) {
|
||||
// important: temporarily setNew(false) because this affects the behavior of
|
||||
|
@ -5121,6 +5227,8 @@ abstract class BaseCcFiles extends BaseObject implements Persistent
|
|||
$this->cueout = null;
|
||||
$this->silan_check = null;
|
||||
$this->hidden = null;
|
||||
$this->is_scheduled = null;
|
||||
$this->is_playlist = null;
|
||||
$this->alreadyInSave = false;
|
||||
$this->alreadyInValidation = false;
|
||||
$this->clearAllReferences();
|
||||
|
|
|
@ -26,7 +26,7 @@ abstract class BaseCcFilesPeer {
|
|||
const TM_CLASS = 'CcFilesTableMap';
|
||||
|
||||
/** The total number of columns. */
|
||||
const NUM_COLUMNS = 68;
|
||||
const NUM_COLUMNS = 70;
|
||||
|
||||
/** The number of lazy-loaded columns. */
|
||||
const NUM_LAZY_LOAD_COLUMNS = 0;
|
||||
|
@ -235,6 +235,12 @@ abstract class BaseCcFilesPeer {
|
|||
/** the column name for the HIDDEN field */
|
||||
const HIDDEN = 'cc_files.HIDDEN';
|
||||
|
||||
/** the column name for the IS_SCHEDULED field */
|
||||
const IS_SCHEDULED = 'cc_files.IS_SCHEDULED';
|
||||
|
||||
/** the column name for the IS_PLAYLIST field */
|
||||
const IS_PLAYLIST = 'cc_files.IS_PLAYLIST';
|
||||
|
||||
/**
|
||||
* An identiy map to hold any loaded instances of CcFiles objects.
|
||||
* This must be public so that other peer classes can access this when hydrating from JOIN
|
||||
|
@ -251,12 +257,12 @@ abstract class BaseCcFilesPeer {
|
|||
* e.g. self::$fieldNames[self::TYPE_PHPNAME][0] = 'Id'
|
||||
*/
|
||||
private static $fieldNames = array (
|
||||
BasePeer::TYPE_PHPNAME => array ('DbId', 'DbName', 'DbMime', 'DbFtype', 'DbDirectory', 'DbFilepath', 'DbState', 'DbCurrentlyaccessing', 'DbEditedby', 'DbMtime', 'DbUtime', 'DbLPtime', 'DbMd5', 'DbTrackTitle', 'DbArtistName', 'DbBitRate', 'DbSampleRate', 'DbFormat', 'DbLength', 'DbAlbumTitle', 'DbGenre', 'DbComments', 'DbYear', 'DbTrackNumber', 'DbChannels', 'DbUrl', 'DbBpm', 'DbRating', 'DbEncodedBy', 'DbDiscNumber', 'DbMood', 'DbLabel', 'DbComposer', 'DbEncoder', 'DbChecksum', 'DbLyrics', 'DbOrchestra', 'DbConductor', 'DbLyricist', 'DbOriginalLyricist', 'DbRadioStationName', 'DbInfoUrl', 'DbArtistUrl', 'DbAudioSourceUrl', 'DbRadioStationUrl', 'DbBuyThisUrl', 'DbIsrcNumber', 'DbCatalogNumber', 'DbOriginalArtist', 'DbCopyright', 'DbReportDatetime', 'DbReportLocation', 'DbReportOrganization', 'DbSubject', 'DbContributor', 'DbLanguage', 'DbFileExists', 'DbSoundcloudId', 'DbSoundcloudErrorCode', 'DbSoundcloudErrorMsg', 'DbSoundcloudLinkToFile', 'DbSoundCloundUploadTime', 'DbReplayGain', 'DbOwnerId', 'DbCuein', 'DbCueout', 'DbSilanCheck', 'DbHidden', ),
|
||||
BasePeer::TYPE_STUDLYPHPNAME => array ('dbId', 'dbName', 'dbMime', 'dbFtype', 'dbDirectory', 'dbFilepath', 'dbState', 'dbCurrentlyaccessing', 'dbEditedby', 'dbMtime', 'dbUtime', 'dbLPtime', 'dbMd5', 'dbTrackTitle', 'dbArtistName', 'dbBitRate', 'dbSampleRate', 'dbFormat', 'dbLength', 'dbAlbumTitle', 'dbGenre', 'dbComments', 'dbYear', 'dbTrackNumber', 'dbChannels', 'dbUrl', 'dbBpm', 'dbRating', 'dbEncodedBy', 'dbDiscNumber', 'dbMood', 'dbLabel', 'dbComposer', 'dbEncoder', 'dbChecksum', 'dbLyrics', 'dbOrchestra', 'dbConductor', 'dbLyricist', 'dbOriginalLyricist', 'dbRadioStationName', 'dbInfoUrl', 'dbArtistUrl', 'dbAudioSourceUrl', 'dbRadioStationUrl', 'dbBuyThisUrl', 'dbIsrcNumber', 'dbCatalogNumber', 'dbOriginalArtist', 'dbCopyright', 'dbReportDatetime', 'dbReportLocation', 'dbReportOrganization', 'dbSubject', 'dbContributor', 'dbLanguage', 'dbFileExists', 'dbSoundcloudId', 'dbSoundcloudErrorCode', 'dbSoundcloudErrorMsg', 'dbSoundcloudLinkToFile', 'dbSoundCloundUploadTime', 'dbReplayGain', 'dbOwnerId', 'dbCuein', 'dbCueout', 'dbSilanCheck', 'dbHidden', ),
|
||||
BasePeer::TYPE_COLNAME => array (self::ID, self::NAME, self::MIME, self::FTYPE, self::DIRECTORY, self::FILEPATH, self::STATE, self::CURRENTLYACCESSING, self::EDITEDBY, self::MTIME, self::UTIME, self::LPTIME, self::MD5, self::TRACK_TITLE, self::ARTIST_NAME, self::BIT_RATE, self::SAMPLE_RATE, self::FORMAT, self::LENGTH, self::ALBUM_TITLE, self::GENRE, self::COMMENTS, self::YEAR, self::TRACK_NUMBER, self::CHANNELS, self::URL, self::BPM, self::RATING, self::ENCODED_BY, self::DISC_NUMBER, self::MOOD, self::LABEL, self::COMPOSER, self::ENCODER, self::CHECKSUM, self::LYRICS, self::ORCHESTRA, self::CONDUCTOR, self::LYRICIST, self::ORIGINAL_LYRICIST, self::RADIO_STATION_NAME, self::INFO_URL, self::ARTIST_URL, self::AUDIO_SOURCE_URL, self::RADIO_STATION_URL, self::BUY_THIS_URL, self::ISRC_NUMBER, self::CATALOG_NUMBER, self::ORIGINAL_ARTIST, self::COPYRIGHT, self::REPORT_DATETIME, self::REPORT_LOCATION, self::REPORT_ORGANIZATION, self::SUBJECT, self::CONTRIBUTOR, self::LANGUAGE, self::FILE_EXISTS, self::SOUNDCLOUD_ID, self::SOUNDCLOUD_ERROR_CODE, self::SOUNDCLOUD_ERROR_MSG, self::SOUNDCLOUD_LINK_TO_FILE, self::SOUNDCLOUD_UPLOAD_TIME, self::REPLAY_GAIN, self::OWNER_ID, self::CUEIN, self::CUEOUT, self::SILAN_CHECK, self::HIDDEN, ),
|
||||
BasePeer::TYPE_RAW_COLNAME => array ('ID', 'NAME', 'MIME', 'FTYPE', 'DIRECTORY', 'FILEPATH', 'STATE', 'CURRENTLYACCESSING', 'EDITEDBY', 'MTIME', 'UTIME', 'LPTIME', 'MD5', 'TRACK_TITLE', 'ARTIST_NAME', 'BIT_RATE', 'SAMPLE_RATE', 'FORMAT', 'LENGTH', 'ALBUM_TITLE', 'GENRE', 'COMMENTS', 'YEAR', 'TRACK_NUMBER', 'CHANNELS', 'URL', 'BPM', 'RATING', 'ENCODED_BY', 'DISC_NUMBER', 'MOOD', 'LABEL', 'COMPOSER', 'ENCODER', 'CHECKSUM', 'LYRICS', 'ORCHESTRA', 'CONDUCTOR', 'LYRICIST', 'ORIGINAL_LYRICIST', 'RADIO_STATION_NAME', 'INFO_URL', 'ARTIST_URL', 'AUDIO_SOURCE_URL', 'RADIO_STATION_URL', 'BUY_THIS_URL', 'ISRC_NUMBER', 'CATALOG_NUMBER', 'ORIGINAL_ARTIST', 'COPYRIGHT', 'REPORT_DATETIME', 'REPORT_LOCATION', 'REPORT_ORGANIZATION', 'SUBJECT', 'CONTRIBUTOR', 'LANGUAGE', 'FILE_EXISTS', 'SOUNDCLOUD_ID', 'SOUNDCLOUD_ERROR_CODE', 'SOUNDCLOUD_ERROR_MSG', 'SOUNDCLOUD_LINK_TO_FILE', 'SOUNDCLOUD_UPLOAD_TIME', 'REPLAY_GAIN', 'OWNER_ID', 'CUEIN', 'CUEOUT', 'SILAN_CHECK', 'HIDDEN', ),
|
||||
BasePeer::TYPE_FIELDNAME => array ('id', 'name', 'mime', 'ftype', 'directory', 'filepath', 'state', 'currentlyaccessing', 'editedby', 'mtime', 'utime', 'lptime', 'md5', 'track_title', 'artist_name', 'bit_rate', 'sample_rate', 'format', 'length', 'album_title', 'genre', 'comments', 'year', 'track_number', 'channels', 'url', 'bpm', 'rating', 'encoded_by', 'disc_number', 'mood', 'label', 'composer', 'encoder', 'checksum', 'lyrics', 'orchestra', 'conductor', 'lyricist', 'original_lyricist', 'radio_station_name', 'info_url', 'artist_url', 'audio_source_url', 'radio_station_url', 'buy_this_url', 'isrc_number', 'catalog_number', 'original_artist', 'copyright', 'report_datetime', 'report_location', 'report_organization', 'subject', 'contributor', 'language', 'file_exists', 'soundcloud_id', 'soundcloud_error_code', 'soundcloud_error_msg', 'soundcloud_link_to_file', 'soundcloud_upload_time', 'replay_gain', 'owner_id', 'cuein', 'cueout', 'silan_check', 'hidden', ),
|
||||
BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, )
|
||||
BasePeer::TYPE_PHPNAME => array ('DbId', 'DbName', 'DbMime', 'DbFtype', 'DbDirectory', 'DbFilepath', 'DbState', 'DbCurrentlyaccessing', 'DbEditedby', 'DbMtime', 'DbUtime', 'DbLPtime', 'DbMd5', 'DbTrackTitle', 'DbArtistName', 'DbBitRate', 'DbSampleRate', 'DbFormat', 'DbLength', 'DbAlbumTitle', 'DbGenre', 'DbComments', 'DbYear', 'DbTrackNumber', 'DbChannels', 'DbUrl', 'DbBpm', 'DbRating', 'DbEncodedBy', 'DbDiscNumber', 'DbMood', 'DbLabel', 'DbComposer', 'DbEncoder', 'DbChecksum', 'DbLyrics', 'DbOrchestra', 'DbConductor', 'DbLyricist', 'DbOriginalLyricist', 'DbRadioStationName', 'DbInfoUrl', 'DbArtistUrl', 'DbAudioSourceUrl', 'DbRadioStationUrl', 'DbBuyThisUrl', 'DbIsrcNumber', 'DbCatalogNumber', 'DbOriginalArtist', 'DbCopyright', 'DbReportDatetime', 'DbReportLocation', 'DbReportOrganization', 'DbSubject', 'DbContributor', 'DbLanguage', 'DbFileExists', 'DbSoundcloudId', 'DbSoundcloudErrorCode', 'DbSoundcloudErrorMsg', 'DbSoundcloudLinkToFile', 'DbSoundCloundUploadTime', 'DbReplayGain', 'DbOwnerId', 'DbCuein', 'DbCueout', 'DbSilanCheck', 'DbHidden', 'DbIsScheduled', 'DbIsPlaylist', ),
|
||||
BasePeer::TYPE_STUDLYPHPNAME => array ('dbId', 'dbName', 'dbMime', 'dbFtype', 'dbDirectory', 'dbFilepath', 'dbState', 'dbCurrentlyaccessing', 'dbEditedby', 'dbMtime', 'dbUtime', 'dbLPtime', 'dbMd5', 'dbTrackTitle', 'dbArtistName', 'dbBitRate', 'dbSampleRate', 'dbFormat', 'dbLength', 'dbAlbumTitle', 'dbGenre', 'dbComments', 'dbYear', 'dbTrackNumber', 'dbChannels', 'dbUrl', 'dbBpm', 'dbRating', 'dbEncodedBy', 'dbDiscNumber', 'dbMood', 'dbLabel', 'dbComposer', 'dbEncoder', 'dbChecksum', 'dbLyrics', 'dbOrchestra', 'dbConductor', 'dbLyricist', 'dbOriginalLyricist', 'dbRadioStationName', 'dbInfoUrl', 'dbArtistUrl', 'dbAudioSourceUrl', 'dbRadioStationUrl', 'dbBuyThisUrl', 'dbIsrcNumber', 'dbCatalogNumber', 'dbOriginalArtist', 'dbCopyright', 'dbReportDatetime', 'dbReportLocation', 'dbReportOrganization', 'dbSubject', 'dbContributor', 'dbLanguage', 'dbFileExists', 'dbSoundcloudId', 'dbSoundcloudErrorCode', 'dbSoundcloudErrorMsg', 'dbSoundcloudLinkToFile', 'dbSoundCloundUploadTime', 'dbReplayGain', 'dbOwnerId', 'dbCuein', 'dbCueout', 'dbSilanCheck', 'dbHidden', 'dbIsScheduled', 'dbIsPlaylist', ),
|
||||
BasePeer::TYPE_COLNAME => array (self::ID, self::NAME, self::MIME, self::FTYPE, self::DIRECTORY, self::FILEPATH, self::STATE, self::CURRENTLYACCESSING, self::EDITEDBY, self::MTIME, self::UTIME, self::LPTIME, self::MD5, self::TRACK_TITLE, self::ARTIST_NAME, self::BIT_RATE, self::SAMPLE_RATE, self::FORMAT, self::LENGTH, self::ALBUM_TITLE, self::GENRE, self::COMMENTS, self::YEAR, self::TRACK_NUMBER, self::CHANNELS, self::URL, self::BPM, self::RATING, self::ENCODED_BY, self::DISC_NUMBER, self::MOOD, self::LABEL, self::COMPOSER, self::ENCODER, self::CHECKSUM, self::LYRICS, self::ORCHESTRA, self::CONDUCTOR, self::LYRICIST, self::ORIGINAL_LYRICIST, self::RADIO_STATION_NAME, self::INFO_URL, self::ARTIST_URL, self::AUDIO_SOURCE_URL, self::RADIO_STATION_URL, self::BUY_THIS_URL, self::ISRC_NUMBER, self::CATALOG_NUMBER, self::ORIGINAL_ARTIST, self::COPYRIGHT, self::REPORT_DATETIME, self::REPORT_LOCATION, self::REPORT_ORGANIZATION, self::SUBJECT, self::CONTRIBUTOR, self::LANGUAGE, self::FILE_EXISTS, self::SOUNDCLOUD_ID, self::SOUNDCLOUD_ERROR_CODE, self::SOUNDCLOUD_ERROR_MSG, self::SOUNDCLOUD_LINK_TO_FILE, self::SOUNDCLOUD_UPLOAD_TIME, self::REPLAY_GAIN, self::OWNER_ID, self::CUEIN, self::CUEOUT, self::SILAN_CHECK, self::HIDDEN, self::IS_SCHEDULED, self::IS_PLAYLIST, ),
|
||||
BasePeer::TYPE_RAW_COLNAME => array ('ID', 'NAME', 'MIME', 'FTYPE', 'DIRECTORY', 'FILEPATH', 'STATE', 'CURRENTLYACCESSING', 'EDITEDBY', 'MTIME', 'UTIME', 'LPTIME', 'MD5', 'TRACK_TITLE', 'ARTIST_NAME', 'BIT_RATE', 'SAMPLE_RATE', 'FORMAT', 'LENGTH', 'ALBUM_TITLE', 'GENRE', 'COMMENTS', 'YEAR', 'TRACK_NUMBER', 'CHANNELS', 'URL', 'BPM', 'RATING', 'ENCODED_BY', 'DISC_NUMBER', 'MOOD', 'LABEL', 'COMPOSER', 'ENCODER', 'CHECKSUM', 'LYRICS', 'ORCHESTRA', 'CONDUCTOR', 'LYRICIST', 'ORIGINAL_LYRICIST', 'RADIO_STATION_NAME', 'INFO_URL', 'ARTIST_URL', 'AUDIO_SOURCE_URL', 'RADIO_STATION_URL', 'BUY_THIS_URL', 'ISRC_NUMBER', 'CATALOG_NUMBER', 'ORIGINAL_ARTIST', 'COPYRIGHT', 'REPORT_DATETIME', 'REPORT_LOCATION', 'REPORT_ORGANIZATION', 'SUBJECT', 'CONTRIBUTOR', 'LANGUAGE', 'FILE_EXISTS', 'SOUNDCLOUD_ID', 'SOUNDCLOUD_ERROR_CODE', 'SOUNDCLOUD_ERROR_MSG', 'SOUNDCLOUD_LINK_TO_FILE', 'SOUNDCLOUD_UPLOAD_TIME', 'REPLAY_GAIN', 'OWNER_ID', 'CUEIN', 'CUEOUT', 'SILAN_CHECK', 'HIDDEN', 'IS_SCHEDULED', 'IS_PLAYLIST', ),
|
||||
BasePeer::TYPE_FIELDNAME => array ('id', 'name', 'mime', 'ftype', 'directory', 'filepath', 'state', 'currentlyaccessing', 'editedby', 'mtime', 'utime', 'lptime', 'md5', 'track_title', 'artist_name', 'bit_rate', 'sample_rate', 'format', 'length', 'album_title', 'genre', 'comments', 'year', 'track_number', 'channels', 'url', 'bpm', 'rating', 'encoded_by', 'disc_number', 'mood', 'label', 'composer', 'encoder', 'checksum', 'lyrics', 'orchestra', 'conductor', 'lyricist', 'original_lyricist', 'radio_station_name', 'info_url', 'artist_url', 'audio_source_url', 'radio_station_url', 'buy_this_url', 'isrc_number', 'catalog_number', 'original_artist', 'copyright', 'report_datetime', 'report_location', 'report_organization', 'subject', 'contributor', 'language', 'file_exists', 'soundcloud_id', 'soundcloud_error_code', 'soundcloud_error_msg', 'soundcloud_link_to_file', 'soundcloud_upload_time', 'replay_gain', 'owner_id', 'cuein', 'cueout', 'silan_check', 'hidden', 'is_scheduled', 'is_playlist', ),
|
||||
BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, )
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -266,12 +272,12 @@ abstract class BaseCcFilesPeer {
|
|||
* e.g. self::$fieldNames[BasePeer::TYPE_PHPNAME]['Id'] = 0
|
||||
*/
|
||||
private static $fieldKeys = array (
|
||||
BasePeer::TYPE_PHPNAME => array ('DbId' => 0, 'DbName' => 1, 'DbMime' => 2, 'DbFtype' => 3, 'DbDirectory' => 4, 'DbFilepath' => 5, 'DbState' => 6, 'DbCurrentlyaccessing' => 7, 'DbEditedby' => 8, 'DbMtime' => 9, 'DbUtime' => 10, 'DbLPtime' => 11, 'DbMd5' => 12, 'DbTrackTitle' => 13, 'DbArtistName' => 14, 'DbBitRate' => 15, 'DbSampleRate' => 16, 'DbFormat' => 17, 'DbLength' => 18, 'DbAlbumTitle' => 19, 'DbGenre' => 20, 'DbComments' => 21, 'DbYear' => 22, 'DbTrackNumber' => 23, 'DbChannels' => 24, 'DbUrl' => 25, 'DbBpm' => 26, 'DbRating' => 27, 'DbEncodedBy' => 28, 'DbDiscNumber' => 29, 'DbMood' => 30, 'DbLabel' => 31, 'DbComposer' => 32, 'DbEncoder' => 33, 'DbChecksum' => 34, 'DbLyrics' => 35, 'DbOrchestra' => 36, 'DbConductor' => 37, 'DbLyricist' => 38, 'DbOriginalLyricist' => 39, 'DbRadioStationName' => 40, 'DbInfoUrl' => 41, 'DbArtistUrl' => 42, 'DbAudioSourceUrl' => 43, 'DbRadioStationUrl' => 44, 'DbBuyThisUrl' => 45, 'DbIsrcNumber' => 46, 'DbCatalogNumber' => 47, 'DbOriginalArtist' => 48, 'DbCopyright' => 49, 'DbReportDatetime' => 50, 'DbReportLocation' => 51, 'DbReportOrganization' => 52, 'DbSubject' => 53, 'DbContributor' => 54, 'DbLanguage' => 55, 'DbFileExists' => 56, 'DbSoundcloudId' => 57, 'DbSoundcloudErrorCode' => 58, 'DbSoundcloudErrorMsg' => 59, 'DbSoundcloudLinkToFile' => 60, 'DbSoundCloundUploadTime' => 61, 'DbReplayGain' => 62, 'DbOwnerId' => 63, 'DbCuein' => 64, 'DbCueout' => 65, 'DbSilanCheck' => 66, 'DbHidden' => 67, ),
|
||||
BasePeer::TYPE_STUDLYPHPNAME => array ('dbId' => 0, 'dbName' => 1, 'dbMime' => 2, 'dbFtype' => 3, 'dbDirectory' => 4, 'dbFilepath' => 5, 'dbState' => 6, 'dbCurrentlyaccessing' => 7, 'dbEditedby' => 8, 'dbMtime' => 9, 'dbUtime' => 10, 'dbLPtime' => 11, 'dbMd5' => 12, 'dbTrackTitle' => 13, 'dbArtistName' => 14, 'dbBitRate' => 15, 'dbSampleRate' => 16, 'dbFormat' => 17, 'dbLength' => 18, 'dbAlbumTitle' => 19, 'dbGenre' => 20, 'dbComments' => 21, 'dbYear' => 22, 'dbTrackNumber' => 23, 'dbChannels' => 24, 'dbUrl' => 25, 'dbBpm' => 26, 'dbRating' => 27, 'dbEncodedBy' => 28, 'dbDiscNumber' => 29, 'dbMood' => 30, 'dbLabel' => 31, 'dbComposer' => 32, 'dbEncoder' => 33, 'dbChecksum' => 34, 'dbLyrics' => 35, 'dbOrchestra' => 36, 'dbConductor' => 37, 'dbLyricist' => 38, 'dbOriginalLyricist' => 39, 'dbRadioStationName' => 40, 'dbInfoUrl' => 41, 'dbArtistUrl' => 42, 'dbAudioSourceUrl' => 43, 'dbRadioStationUrl' => 44, 'dbBuyThisUrl' => 45, 'dbIsrcNumber' => 46, 'dbCatalogNumber' => 47, 'dbOriginalArtist' => 48, 'dbCopyright' => 49, 'dbReportDatetime' => 50, 'dbReportLocation' => 51, 'dbReportOrganization' => 52, 'dbSubject' => 53, 'dbContributor' => 54, 'dbLanguage' => 55, 'dbFileExists' => 56, 'dbSoundcloudId' => 57, 'dbSoundcloudErrorCode' => 58, 'dbSoundcloudErrorMsg' => 59, 'dbSoundcloudLinkToFile' => 60, 'dbSoundCloundUploadTime' => 61, 'dbReplayGain' => 62, 'dbOwnerId' => 63, 'dbCuein' => 64, 'dbCueout' => 65, 'dbSilanCheck' => 66, 'dbHidden' => 67, ),
|
||||
BasePeer::TYPE_COLNAME => array (self::ID => 0, self::NAME => 1, self::MIME => 2, self::FTYPE => 3, self::DIRECTORY => 4, self::FILEPATH => 5, self::STATE => 6, self::CURRENTLYACCESSING => 7, self::EDITEDBY => 8, self::MTIME => 9, self::UTIME => 10, self::LPTIME => 11, self::MD5 => 12, self::TRACK_TITLE => 13, self::ARTIST_NAME => 14, self::BIT_RATE => 15, self::SAMPLE_RATE => 16, self::FORMAT => 17, self::LENGTH => 18, self::ALBUM_TITLE => 19, self::GENRE => 20, self::COMMENTS => 21, self::YEAR => 22, self::TRACK_NUMBER => 23, self::CHANNELS => 24, self::URL => 25, self::BPM => 26, self::RATING => 27, self::ENCODED_BY => 28, self::DISC_NUMBER => 29, self::MOOD => 30, self::LABEL => 31, self::COMPOSER => 32, self::ENCODER => 33, self::CHECKSUM => 34, self::LYRICS => 35, self::ORCHESTRA => 36, self::CONDUCTOR => 37, self::LYRICIST => 38, self::ORIGINAL_LYRICIST => 39, self::RADIO_STATION_NAME => 40, self::INFO_URL => 41, self::ARTIST_URL => 42, self::AUDIO_SOURCE_URL => 43, self::RADIO_STATION_URL => 44, self::BUY_THIS_URL => 45, self::ISRC_NUMBER => 46, self::CATALOG_NUMBER => 47, self::ORIGINAL_ARTIST => 48, self::COPYRIGHT => 49, self::REPORT_DATETIME => 50, self::REPORT_LOCATION => 51, self::REPORT_ORGANIZATION => 52, self::SUBJECT => 53, self::CONTRIBUTOR => 54, self::LANGUAGE => 55, self::FILE_EXISTS => 56, self::SOUNDCLOUD_ID => 57, self::SOUNDCLOUD_ERROR_CODE => 58, self::SOUNDCLOUD_ERROR_MSG => 59, self::SOUNDCLOUD_LINK_TO_FILE => 60, self::SOUNDCLOUD_UPLOAD_TIME => 61, self::REPLAY_GAIN => 62, self::OWNER_ID => 63, self::CUEIN => 64, self::CUEOUT => 65, self::SILAN_CHECK => 66, self::HIDDEN => 67, ),
|
||||
BasePeer::TYPE_RAW_COLNAME => array ('ID' => 0, 'NAME' => 1, 'MIME' => 2, 'FTYPE' => 3, 'DIRECTORY' => 4, 'FILEPATH' => 5, 'STATE' => 6, 'CURRENTLYACCESSING' => 7, 'EDITEDBY' => 8, 'MTIME' => 9, 'UTIME' => 10, 'LPTIME' => 11, 'MD5' => 12, 'TRACK_TITLE' => 13, 'ARTIST_NAME' => 14, 'BIT_RATE' => 15, 'SAMPLE_RATE' => 16, 'FORMAT' => 17, 'LENGTH' => 18, 'ALBUM_TITLE' => 19, 'GENRE' => 20, 'COMMENTS' => 21, 'YEAR' => 22, 'TRACK_NUMBER' => 23, 'CHANNELS' => 24, 'URL' => 25, 'BPM' => 26, 'RATING' => 27, 'ENCODED_BY' => 28, 'DISC_NUMBER' => 29, 'MOOD' => 30, 'LABEL' => 31, 'COMPOSER' => 32, 'ENCODER' => 33, 'CHECKSUM' => 34, 'LYRICS' => 35, 'ORCHESTRA' => 36, 'CONDUCTOR' => 37, 'LYRICIST' => 38, 'ORIGINAL_LYRICIST' => 39, 'RADIO_STATION_NAME' => 40, 'INFO_URL' => 41, 'ARTIST_URL' => 42, 'AUDIO_SOURCE_URL' => 43, 'RADIO_STATION_URL' => 44, 'BUY_THIS_URL' => 45, 'ISRC_NUMBER' => 46, 'CATALOG_NUMBER' => 47, 'ORIGINAL_ARTIST' => 48, 'COPYRIGHT' => 49, 'REPORT_DATETIME' => 50, 'REPORT_LOCATION' => 51, 'REPORT_ORGANIZATION' => 52, 'SUBJECT' => 53, 'CONTRIBUTOR' => 54, 'LANGUAGE' => 55, 'FILE_EXISTS' => 56, 'SOUNDCLOUD_ID' => 57, 'SOUNDCLOUD_ERROR_CODE' => 58, 'SOUNDCLOUD_ERROR_MSG' => 59, 'SOUNDCLOUD_LINK_TO_FILE' => 60, 'SOUNDCLOUD_UPLOAD_TIME' => 61, 'REPLAY_GAIN' => 62, 'OWNER_ID' => 63, 'CUEIN' => 64, 'CUEOUT' => 65, 'SILAN_CHECK' => 66, 'HIDDEN' => 67, ),
|
||||
BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'name' => 1, 'mime' => 2, 'ftype' => 3, 'directory' => 4, 'filepath' => 5, 'state' => 6, 'currentlyaccessing' => 7, 'editedby' => 8, 'mtime' => 9, 'utime' => 10, 'lptime' => 11, 'md5' => 12, 'track_title' => 13, 'artist_name' => 14, 'bit_rate' => 15, 'sample_rate' => 16, 'format' => 17, 'length' => 18, 'album_title' => 19, 'genre' => 20, 'comments' => 21, 'year' => 22, 'track_number' => 23, 'channels' => 24, 'url' => 25, 'bpm' => 26, 'rating' => 27, 'encoded_by' => 28, 'disc_number' => 29, 'mood' => 30, 'label' => 31, 'composer' => 32, 'encoder' => 33, 'checksum' => 34, 'lyrics' => 35, 'orchestra' => 36, 'conductor' => 37, 'lyricist' => 38, 'original_lyricist' => 39, 'radio_station_name' => 40, 'info_url' => 41, 'artist_url' => 42, 'audio_source_url' => 43, 'radio_station_url' => 44, 'buy_this_url' => 45, 'isrc_number' => 46, 'catalog_number' => 47, 'original_artist' => 48, 'copyright' => 49, 'report_datetime' => 50, 'report_location' => 51, 'report_organization' => 52, 'subject' => 53, 'contributor' => 54, 'language' => 55, 'file_exists' => 56, 'soundcloud_id' => 57, 'soundcloud_error_code' => 58, 'soundcloud_error_msg' => 59, 'soundcloud_link_to_file' => 60, 'soundcloud_upload_time' => 61, 'replay_gain' => 62, 'owner_id' => 63, 'cuein' => 64, 'cueout' => 65, 'silan_check' => 66, 'hidden' => 67, ),
|
||||
BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, )
|
||||
BasePeer::TYPE_PHPNAME => array ('DbId' => 0, 'DbName' => 1, 'DbMime' => 2, 'DbFtype' => 3, 'DbDirectory' => 4, 'DbFilepath' => 5, 'DbState' => 6, 'DbCurrentlyaccessing' => 7, 'DbEditedby' => 8, 'DbMtime' => 9, 'DbUtime' => 10, 'DbLPtime' => 11, 'DbMd5' => 12, 'DbTrackTitle' => 13, 'DbArtistName' => 14, 'DbBitRate' => 15, 'DbSampleRate' => 16, 'DbFormat' => 17, 'DbLength' => 18, 'DbAlbumTitle' => 19, 'DbGenre' => 20, 'DbComments' => 21, 'DbYear' => 22, 'DbTrackNumber' => 23, 'DbChannels' => 24, 'DbUrl' => 25, 'DbBpm' => 26, 'DbRating' => 27, 'DbEncodedBy' => 28, 'DbDiscNumber' => 29, 'DbMood' => 30, 'DbLabel' => 31, 'DbComposer' => 32, 'DbEncoder' => 33, 'DbChecksum' => 34, 'DbLyrics' => 35, 'DbOrchestra' => 36, 'DbConductor' => 37, 'DbLyricist' => 38, 'DbOriginalLyricist' => 39, 'DbRadioStationName' => 40, 'DbInfoUrl' => 41, 'DbArtistUrl' => 42, 'DbAudioSourceUrl' => 43, 'DbRadioStationUrl' => 44, 'DbBuyThisUrl' => 45, 'DbIsrcNumber' => 46, 'DbCatalogNumber' => 47, 'DbOriginalArtist' => 48, 'DbCopyright' => 49, 'DbReportDatetime' => 50, 'DbReportLocation' => 51, 'DbReportOrganization' => 52, 'DbSubject' => 53, 'DbContributor' => 54, 'DbLanguage' => 55, 'DbFileExists' => 56, 'DbSoundcloudId' => 57, 'DbSoundcloudErrorCode' => 58, 'DbSoundcloudErrorMsg' => 59, 'DbSoundcloudLinkToFile' => 60, 'DbSoundCloundUploadTime' => 61, 'DbReplayGain' => 62, 'DbOwnerId' => 63, 'DbCuein' => 64, 'DbCueout' => 65, 'DbSilanCheck' => 66, 'DbHidden' => 67, 'DbIsScheduled' => 68, 'DbIsPlaylist' => 69, ),
|
||||
BasePeer::TYPE_STUDLYPHPNAME => array ('dbId' => 0, 'dbName' => 1, 'dbMime' => 2, 'dbFtype' => 3, 'dbDirectory' => 4, 'dbFilepath' => 5, 'dbState' => 6, 'dbCurrentlyaccessing' => 7, 'dbEditedby' => 8, 'dbMtime' => 9, 'dbUtime' => 10, 'dbLPtime' => 11, 'dbMd5' => 12, 'dbTrackTitle' => 13, 'dbArtistName' => 14, 'dbBitRate' => 15, 'dbSampleRate' => 16, 'dbFormat' => 17, 'dbLength' => 18, 'dbAlbumTitle' => 19, 'dbGenre' => 20, 'dbComments' => 21, 'dbYear' => 22, 'dbTrackNumber' => 23, 'dbChannels' => 24, 'dbUrl' => 25, 'dbBpm' => 26, 'dbRating' => 27, 'dbEncodedBy' => 28, 'dbDiscNumber' => 29, 'dbMood' => 30, 'dbLabel' => 31, 'dbComposer' => 32, 'dbEncoder' => 33, 'dbChecksum' => 34, 'dbLyrics' => 35, 'dbOrchestra' => 36, 'dbConductor' => 37, 'dbLyricist' => 38, 'dbOriginalLyricist' => 39, 'dbRadioStationName' => 40, 'dbInfoUrl' => 41, 'dbArtistUrl' => 42, 'dbAudioSourceUrl' => 43, 'dbRadioStationUrl' => 44, 'dbBuyThisUrl' => 45, 'dbIsrcNumber' => 46, 'dbCatalogNumber' => 47, 'dbOriginalArtist' => 48, 'dbCopyright' => 49, 'dbReportDatetime' => 50, 'dbReportLocation' => 51, 'dbReportOrganization' => 52, 'dbSubject' => 53, 'dbContributor' => 54, 'dbLanguage' => 55, 'dbFileExists' => 56, 'dbSoundcloudId' => 57, 'dbSoundcloudErrorCode' => 58, 'dbSoundcloudErrorMsg' => 59, 'dbSoundcloudLinkToFile' => 60, 'dbSoundCloundUploadTime' => 61, 'dbReplayGain' => 62, 'dbOwnerId' => 63, 'dbCuein' => 64, 'dbCueout' => 65, 'dbSilanCheck' => 66, 'dbHidden' => 67, 'dbIsScheduled' => 68, 'dbIsPlaylist' => 69, ),
|
||||
BasePeer::TYPE_COLNAME => array (self::ID => 0, self::NAME => 1, self::MIME => 2, self::FTYPE => 3, self::DIRECTORY => 4, self::FILEPATH => 5, self::STATE => 6, self::CURRENTLYACCESSING => 7, self::EDITEDBY => 8, self::MTIME => 9, self::UTIME => 10, self::LPTIME => 11, self::MD5 => 12, self::TRACK_TITLE => 13, self::ARTIST_NAME => 14, self::BIT_RATE => 15, self::SAMPLE_RATE => 16, self::FORMAT => 17, self::LENGTH => 18, self::ALBUM_TITLE => 19, self::GENRE => 20, self::COMMENTS => 21, self::YEAR => 22, self::TRACK_NUMBER => 23, self::CHANNELS => 24, self::URL => 25, self::BPM => 26, self::RATING => 27, self::ENCODED_BY => 28, self::DISC_NUMBER => 29, self::MOOD => 30, self::LABEL => 31, self::COMPOSER => 32, self::ENCODER => 33, self::CHECKSUM => 34, self::LYRICS => 35, self::ORCHESTRA => 36, self::CONDUCTOR => 37, self::LYRICIST => 38, self::ORIGINAL_LYRICIST => 39, self::RADIO_STATION_NAME => 40, self::INFO_URL => 41, self::ARTIST_URL => 42, self::AUDIO_SOURCE_URL => 43, self::RADIO_STATION_URL => 44, self::BUY_THIS_URL => 45, self::ISRC_NUMBER => 46, self::CATALOG_NUMBER => 47, self::ORIGINAL_ARTIST => 48, self::COPYRIGHT => 49, self::REPORT_DATETIME => 50, self::REPORT_LOCATION => 51, self::REPORT_ORGANIZATION => 52, self::SUBJECT => 53, self::CONTRIBUTOR => 54, self::LANGUAGE => 55, self::FILE_EXISTS => 56, self::SOUNDCLOUD_ID => 57, self::SOUNDCLOUD_ERROR_CODE => 58, self::SOUNDCLOUD_ERROR_MSG => 59, self::SOUNDCLOUD_LINK_TO_FILE => 60, self::SOUNDCLOUD_UPLOAD_TIME => 61, self::REPLAY_GAIN => 62, self::OWNER_ID => 63, self::CUEIN => 64, self::CUEOUT => 65, self::SILAN_CHECK => 66, self::HIDDEN => 67, self::IS_SCHEDULED => 68, self::IS_PLAYLIST => 69, ),
|
||||
BasePeer::TYPE_RAW_COLNAME => array ('ID' => 0, 'NAME' => 1, 'MIME' => 2, 'FTYPE' => 3, 'DIRECTORY' => 4, 'FILEPATH' => 5, 'STATE' => 6, 'CURRENTLYACCESSING' => 7, 'EDITEDBY' => 8, 'MTIME' => 9, 'UTIME' => 10, 'LPTIME' => 11, 'MD5' => 12, 'TRACK_TITLE' => 13, 'ARTIST_NAME' => 14, 'BIT_RATE' => 15, 'SAMPLE_RATE' => 16, 'FORMAT' => 17, 'LENGTH' => 18, 'ALBUM_TITLE' => 19, 'GENRE' => 20, 'COMMENTS' => 21, 'YEAR' => 22, 'TRACK_NUMBER' => 23, 'CHANNELS' => 24, 'URL' => 25, 'BPM' => 26, 'RATING' => 27, 'ENCODED_BY' => 28, 'DISC_NUMBER' => 29, 'MOOD' => 30, 'LABEL' => 31, 'COMPOSER' => 32, 'ENCODER' => 33, 'CHECKSUM' => 34, 'LYRICS' => 35, 'ORCHESTRA' => 36, 'CONDUCTOR' => 37, 'LYRICIST' => 38, 'ORIGINAL_LYRICIST' => 39, 'RADIO_STATION_NAME' => 40, 'INFO_URL' => 41, 'ARTIST_URL' => 42, 'AUDIO_SOURCE_URL' => 43, 'RADIO_STATION_URL' => 44, 'BUY_THIS_URL' => 45, 'ISRC_NUMBER' => 46, 'CATALOG_NUMBER' => 47, 'ORIGINAL_ARTIST' => 48, 'COPYRIGHT' => 49, 'REPORT_DATETIME' => 50, 'REPORT_LOCATION' => 51, 'REPORT_ORGANIZATION' => 52, 'SUBJECT' => 53, 'CONTRIBUTOR' => 54, 'LANGUAGE' => 55, 'FILE_EXISTS' => 56, 'SOUNDCLOUD_ID' => 57, 'SOUNDCLOUD_ERROR_CODE' => 58, 'SOUNDCLOUD_ERROR_MSG' => 59, 'SOUNDCLOUD_LINK_TO_FILE' => 60, 'SOUNDCLOUD_UPLOAD_TIME' => 61, 'REPLAY_GAIN' => 62, 'OWNER_ID' => 63, 'CUEIN' => 64, 'CUEOUT' => 65, 'SILAN_CHECK' => 66, 'HIDDEN' => 67, 'IS_SCHEDULED' => 68, 'IS_PLAYLIST' => 69, ),
|
||||
BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'name' => 1, 'mime' => 2, 'ftype' => 3, 'directory' => 4, 'filepath' => 5, 'state' => 6, 'currentlyaccessing' => 7, 'editedby' => 8, 'mtime' => 9, 'utime' => 10, 'lptime' => 11, 'md5' => 12, 'track_title' => 13, 'artist_name' => 14, 'bit_rate' => 15, 'sample_rate' => 16, 'format' => 17, 'length' => 18, 'album_title' => 19, 'genre' => 20, 'comments' => 21, 'year' => 22, 'track_number' => 23, 'channels' => 24, 'url' => 25, 'bpm' => 26, 'rating' => 27, 'encoded_by' => 28, 'disc_number' => 29, 'mood' => 30, 'label' => 31, 'composer' => 32, 'encoder' => 33, 'checksum' => 34, 'lyrics' => 35, 'orchestra' => 36, 'conductor' => 37, 'lyricist' => 38, 'original_lyricist' => 39, 'radio_station_name' => 40, 'info_url' => 41, 'artist_url' => 42, 'audio_source_url' => 43, 'radio_station_url' => 44, 'buy_this_url' => 45, 'isrc_number' => 46, 'catalog_number' => 47, 'original_artist' => 48, 'copyright' => 49, 'report_datetime' => 50, 'report_location' => 51, 'report_organization' => 52, 'subject' => 53, 'contributor' => 54, 'language' => 55, 'file_exists' => 56, 'soundcloud_id' => 57, 'soundcloud_error_code' => 58, 'soundcloud_error_msg' => 59, 'soundcloud_link_to_file' => 60, 'soundcloud_upload_time' => 61, 'replay_gain' => 62, 'owner_id' => 63, 'cuein' => 64, 'cueout' => 65, 'silan_check' => 66, 'hidden' => 67, 'is_scheduled' => 68, 'is_playlist' => 69, ),
|
||||
BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, )
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -411,6 +417,8 @@ abstract class BaseCcFilesPeer {
|
|||
$criteria->addSelectColumn(CcFilesPeer::CUEOUT);
|
||||
$criteria->addSelectColumn(CcFilesPeer::SILAN_CHECK);
|
||||
$criteria->addSelectColumn(CcFilesPeer::HIDDEN);
|
||||
$criteria->addSelectColumn(CcFilesPeer::IS_SCHEDULED);
|
||||
$criteria->addSelectColumn(CcFilesPeer::IS_PLAYLIST);
|
||||
} else {
|
||||
$criteria->addSelectColumn($alias . '.ID');
|
||||
$criteria->addSelectColumn($alias . '.NAME');
|
||||
|
@ -480,6 +488,8 @@ abstract class BaseCcFilesPeer {
|
|||
$criteria->addSelectColumn($alias . '.CUEOUT');
|
||||
$criteria->addSelectColumn($alias . '.SILAN_CHECK');
|
||||
$criteria->addSelectColumn($alias . '.HIDDEN');
|
||||
$criteria->addSelectColumn($alias . '.IS_SCHEDULED');
|
||||
$criteria->addSelectColumn($alias . '.IS_PLAYLIST');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -74,6 +74,8 @@
|
|||
* @method CcFilesQuery orderByDbCueout($order = Criteria::ASC) Order by the cueout column
|
||||
* @method CcFilesQuery orderByDbSilanCheck($order = Criteria::ASC) Order by the silan_check column
|
||||
* @method CcFilesQuery orderByDbHidden($order = Criteria::ASC) Order by the hidden column
|
||||
* @method CcFilesQuery orderByDbIsScheduled($order = Criteria::ASC) Order by the is_scheduled column
|
||||
* @method CcFilesQuery orderByDbIsPlaylist($order = Criteria::ASC) Order by the is_playlist column
|
||||
*
|
||||
* @method CcFilesQuery groupByDbId() Group by the id column
|
||||
* @method CcFilesQuery groupByDbName() Group by the name column
|
||||
|
@ -143,6 +145,8 @@
|
|||
* @method CcFilesQuery groupByDbCueout() Group by the cueout column
|
||||
* @method CcFilesQuery groupByDbSilanCheck() Group by the silan_check column
|
||||
* @method CcFilesQuery groupByDbHidden() Group by the hidden column
|
||||
* @method CcFilesQuery groupByDbIsScheduled() Group by the is_scheduled column
|
||||
* @method CcFilesQuery groupByDbIsPlaylist() Group by the is_playlist column
|
||||
*
|
||||
* @method CcFilesQuery leftJoin($relation) Adds a LEFT JOIN clause to the query
|
||||
* @method CcFilesQuery rightJoin($relation) Adds a RIGHT JOIN clause to the query
|
||||
|
@ -247,6 +251,8 @@
|
|||
* @method CcFiles findOneByDbCueout(string $cueout) Return the first CcFiles filtered by the cueout column
|
||||
* @method CcFiles findOneByDbSilanCheck(boolean $silan_check) Return the first CcFiles filtered by the silan_check column
|
||||
* @method CcFiles findOneByDbHidden(boolean $hidden) Return the first CcFiles filtered by the hidden column
|
||||
* @method CcFiles findOneByDbIsScheduled(boolean $is_scheduled) Return the first CcFiles filtered by the is_scheduled column
|
||||
* @method CcFiles findOneByDbIsPlaylist(boolean $is_playlist) Return the first CcFiles filtered by the is_playlist column
|
||||
*
|
||||
* @method array findByDbId(int $id) Return CcFiles objects filtered by the id column
|
||||
* @method array findByDbName(string $name) Return CcFiles objects filtered by the name column
|
||||
|
@ -316,6 +322,8 @@
|
|||
* @method array findByDbCueout(string $cueout) Return CcFiles objects filtered by the cueout column
|
||||
* @method array findByDbSilanCheck(boolean $silan_check) Return CcFiles objects filtered by the silan_check column
|
||||
* @method array findByDbHidden(boolean $hidden) Return CcFiles objects filtered by the hidden column
|
||||
* @method array findByDbIsScheduled(boolean $is_scheduled) Return CcFiles objects filtered by the is_scheduled column
|
||||
* @method array findByDbIsPlaylist(boolean $is_playlist) Return CcFiles objects filtered by the is_playlist column
|
||||
*
|
||||
* @package propel.generator.airtime.om
|
||||
*/
|
||||
|
@ -2045,6 +2053,40 @@ abstract class BaseCcFilesQuery extends ModelCriteria
|
|||
return $this->addUsingAlias(CcFilesPeer::HIDDEN, $dbHidden, $comparison);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the query on the is_scheduled column
|
||||
*
|
||||
* @param boolean|string $dbIsScheduled The value to use as filter.
|
||||
* Accepts strings ('false', 'off', '-', 'no', 'n', and '0' are false, the rest is true)
|
||||
* @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL
|
||||
*
|
||||
* @return CcFilesQuery The current query, for fluid interface
|
||||
*/
|
||||
public function filterByDbIsScheduled($dbIsScheduled = null, $comparison = null)
|
||||
{
|
||||
if (is_string($dbIsScheduled)) {
|
||||
$is_scheduled = in_array(strtolower($dbIsScheduled), array('false', 'off', '-', 'no', 'n', '0')) ? false : true;
|
||||
}
|
||||
return $this->addUsingAlias(CcFilesPeer::IS_SCHEDULED, $dbIsScheduled, $comparison);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the query on the is_playlist column
|
||||
*
|
||||
* @param boolean|string $dbIsPlaylist The value to use as filter.
|
||||
* Accepts strings ('false', 'off', '-', 'no', 'n', and '0' are false, the rest is true)
|
||||
* @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL
|
||||
*
|
||||
* @return CcFilesQuery The current query, for fluid interface
|
||||
*/
|
||||
public function filterByDbIsPlaylist($dbIsPlaylist = null, $comparison = null)
|
||||
{
|
||||
if (is_string($dbIsPlaylist)) {
|
||||
$is_playlist = in_array(strtolower($dbIsPlaylist), array('false', 'off', '-', 'no', 'n', '0')) ? false : true;
|
||||
}
|
||||
return $this->addUsingAlias(CcFilesPeer::IS_PLAYLIST, $dbIsPlaylist, $comparison);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the query by a related CcSubjs object
|
||||
*
|
||||
|
|
|
@ -2,7 +2,14 @@
|
|||
<?php echo $this->render('library/library.phtml') ?>
|
||||
</div>
|
||||
|
||||
<div id="side_playlist" class="pl-content ui-widget ui-widget-content block-shadow omega-block padded" style="height:697px; width:720px;">
|
||||
<?php
|
||||
if ($this->showPlaylist) {
|
||||
$display = "";
|
||||
} else {
|
||||
$display = "display:none";
|
||||
}
|
||||
?>
|
||||
<div id="side_playlist" class="pl-content ui-widget ui-widget-content block-shadow omega-block padded" style="height:697px; width:720px;<?php echo $display?>">
|
||||
<?php if ($this->type == 'block') {
|
||||
echo $this->render('playlist/smart-block.phtml');
|
||||
} else if ($this->type == 'playlist') {
|
||||
|
|
|
@ -4,6 +4,7 @@ if (isset($this->obj)) {
|
|||
$count = count($contents);
|
||||
}
|
||||
?>
|
||||
<a href="#" class="close-round" id="lib_pl_close"></a>
|
||||
<div class="btn-toolbar spl-no-top-margin clearfix">
|
||||
<div class="btn-group pull-left">
|
||||
<button id="spl_new" class="btn dropdown-toggle" data-toggle="dropdown" aria-disabled="false">
|
||||
|
@ -16,6 +17,9 @@ if (isset($this->obj)) {
|
|||
</ul>
|
||||
</div>
|
||||
<?php if (isset($this->obj)) : ?>
|
||||
<div class='btn-group pull-right'>
|
||||
<button class="btn btn-inverse" title='<?php echo _("Empty playlist content") ?>' type="button" id="pl-bl-clear-content"><? echo _("Clear") ?></button>
|
||||
</div>
|
||||
<div class='btn-group pull-right'>
|
||||
<button class="btn btn-inverse" title='<?php echo _("Shuffle playlist") ?>' type="button" id="playlist_shuffle_button"><? echo _("Shuffle") ?></button>
|
||||
</div>
|
||||
|
|
|
@ -4,6 +4,7 @@ if (isset($this->obj)) {
|
|||
$count = count($contents);
|
||||
}
|
||||
?>
|
||||
<a href="#" class="close-round" id="lib_pl_close"></a>
|
||||
<div class="btn-toolbar spl-no-top-margin clearfix">
|
||||
<div class="btn-group pull-left">
|
||||
<button id="spl_new" class="btn dropdown-toggle" data-toggle='dropdown' aria-disabled="false">
|
||||
|
@ -16,6 +17,9 @@ if (isset($this->obj)) {
|
|||
</ul>
|
||||
</div>
|
||||
<?php if (isset($this->obj)) : ?>
|
||||
<div class='btn-group pull-right'>
|
||||
<button class="btn btn-inverse" title='<?php echo _("Empty smart block content") ?>' type="button" id="pl-bl-clear-content"><? echo _("Clear") ?></button>
|
||||
</div>
|
||||
<div class='btn-group pull-right'>
|
||||
<button class="btn btn-inverse" title='Save smart block's title, description, and criteria' type="button" id="save_button"><? echo _("Save") ?></button>
|
||||
</div>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<a href="#" class="close-round" id="lib_pl_close"></a>
|
||||
<div class="btn-toolbar spl-no-top-margin clearfix">
|
||||
<div class="btn-group pull-left">
|
||||
<button id="ws_new" class="btn dropdown-toggle" data-toggle="dropdown" aria-disabled="false">
|
||||
|
|
|
@ -80,6 +80,8 @@
|
|||
<column name="cueout" phpName="DbCueout" type="VARCHAR" sqlType="interval" required="false" defaultValue="00:00:00"/>
|
||||
<column name="silan_check" phpName="DbSilanCheck" type="BOOLEAN" defaultValue="false"/>
|
||||
<column name="hidden" phpName="DbHidden" type="BOOLEAN" defaultValue="false"/>
|
||||
<column name="is_scheduled" phpName="DbIsScheduled" type="BOOLEAN" defaultValue="false"/>
|
||||
<column name="is_playlist" phpName="DbIsPlaylist" type="BOOLEAN" defaultValue="false"/>
|
||||
<foreign-key foreignTable="cc_subjs" phpName="FkOwner" name="cc_files_owner_fkey">
|
||||
<reference local="owner_id" foreign="id"/>
|
||||
</foreign-key>
|
||||
|
|
|
@ -98,6 +98,8 @@ CREATE TABLE "cc_files"
|
|||
"cueout" interval default '00:00:00',
|
||||
"silan_check" BOOLEAN default 'f',
|
||||
"hidden" BOOLEAN default 'f',
|
||||
"is_scheduled" BOOLEAN default 'f',
|
||||
"is_playlist" BOOLEAN default 'f',
|
||||
PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
|
|
|
@ -1999,7 +1999,7 @@ span.errors.sp-errors{
|
|||
.small-icon.show-empty {
|
||||
background:url(images/icon_alert_cal_alt.png) no-repeat 0 0;
|
||||
}
|
||||
.small-icon.show-partial-filled {
|
||||
.small-icon.show-partial-filled, .small-icon.media-item-in-use {
|
||||
background:url(images/icon_alert_cal_alt2.png) no-repeat 0 0;
|
||||
}
|
||||
.medium-icon {
|
||||
|
|
|
@ -7,8 +7,13 @@ var AIRTIME = (function(AIRTIME) {
|
|||
LIB_SELECTED_CLASS = "lib-selected",
|
||||
chosenItems = {},
|
||||
visibleChosenItems = {};
|
||||
|
||||
var criteriaTypes = {
|
||||
|
||||
// we need to know whether the criteria value is string or
|
||||
// numeric in order to provide a single textbox or range textboxes
|
||||
// in the advanced search
|
||||
// s => string
|
||||
// n => numberic
|
||||
var libraryColumnTypes = {
|
||||
0 : "",
|
||||
"album_title" : "s",
|
||||
"artist_name" : "s",
|
||||
|
@ -18,6 +23,8 @@ var AIRTIME = (function(AIRTIME) {
|
|||
"composer" : "s",
|
||||
"conductor" : "s",
|
||||
"copyright" : "s",
|
||||
"cuein" : "n",
|
||||
"cueout" : "n",
|
||||
"utime" : "n",
|
||||
"mtime" : "n",
|
||||
"lptime" : "n",
|
||||
|
@ -322,22 +329,40 @@ var AIRTIME = (function(AIRTIME) {
|
|||
};
|
||||
|
||||
mod.fnDeleteSelectedItems = function() {
|
||||
if (confirm($.i18n._('Are you sure you want to delete the selected item(s)?'))) {
|
||||
var aData = AIRTIME.library.getSelectedData(),
|
||||
item,
|
||||
temp,
|
||||
aMedia = [];
|
||||
|
||||
// process selected files/playlists.
|
||||
for (item in aData) {
|
||||
temp = aData[item];
|
||||
if (temp !== null && temp.hasOwnProperty('id') ) {
|
||||
aMedia.push({"id": temp.id, "type": temp.ftype});
|
||||
}
|
||||
}
|
||||
|
||||
AIRTIME.library.fnDeleteItems(aMedia);
|
||||
}
|
||||
if (confirm($.i18n._('Are you sure you want to delete the selected item(s)?'))) {
|
||||
var aData = AIRTIME.library.getSelectedData(),
|
||||
item,
|
||||
temp,
|
||||
aMedia = [],
|
||||
currentObjId = $("#side_playlist").find("#obj_id").val(),
|
||||
currentObjType = $("#side_playlist").find("#obj_type").val(),
|
||||
closeObj = false;
|
||||
|
||||
// process selected files/playlists.
|
||||
for (item in aData) {
|
||||
temp = aData[item];
|
||||
if (temp !== null && temp.hasOwnProperty('id') ) {
|
||||
aMedia.push({"id": temp.id, "type": temp.ftype});
|
||||
if ( (temp.id == currentObjId && temp.ftype === currentObjType) ||
|
||||
temp.id == currentObjId && temp.ftype === "stream" && currentObjType === "webstream") {
|
||||
closeObj = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AIRTIME.library.fnDeleteItems(aMedia);
|
||||
|
||||
// close the object (playlist/block/webstream)
|
||||
// on the right side if it was just deleted
|
||||
// from the library
|
||||
if (closeObj) {
|
||||
$.post(baseUrl+"playlist/close-playlist",
|
||||
{"format": "json", "type": currentObjType},
|
||||
function(json) {
|
||||
$("#side_playlist").empty().append(json.html);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
libraryInit = function() {
|
||||
|
@ -381,7 +406,7 @@ var AIRTIME = (function(AIRTIME) {
|
|||
|
||||
var inputClass = 'filter_column filter_number_text';
|
||||
var labelStyle = "style='margin-right:35px;'";
|
||||
if (criteriaTypes[ele.mDataProp] != "s") {
|
||||
if (libraryColumnTypes[ele.mDataProp] != "s") {
|
||||
inputClass = 'filterColumn filter_number_range';
|
||||
labelStyle = "";
|
||||
}
|
||||
|
@ -400,7 +425,7 @@ var AIRTIME = (function(AIRTIME) {
|
|||
"</div>");
|
||||
}
|
||||
|
||||
if (criteriaTypes[ele.mDataProp] == "s") {
|
||||
if (libraryColumnTypes[ele.mDataProp] == "s") {
|
||||
var obj = { sSelector: "#"+ele.mDataProp }
|
||||
} else {
|
||||
var obj = { sSelector: "#"+ele.mDataProp, type: "number-range" }
|
||||
|
@ -435,10 +460,15 @@ var AIRTIME = (function(AIRTIME) {
|
|||
|
||||
// put hidden columns at the top to insure they can never be visible
|
||||
// on the table through column reordering.
|
||||
|
||||
//IMPORTANT: WHEN ADDING A NEW COLUMN PLEASE CONSULT WITH THE WIKI
|
||||
// https://wiki.sourcefabric.org/display/CC/Adding+a+new+library+datatable+column
|
||||
"aoColumns": [
|
||||
/* ftype */ { "sTitle" : "" , "mDataProp" : "ftype" , "bSearchable" : false , "bVisible" : false } ,
|
||||
/* Checkbox */ { "sTitle" : "" , "mDataProp" : "checkbox" , "bSortable" : false , "bSearchable" : false , "sWidth" : "25px" , "sClass" : "library_checkbox" } ,
|
||||
/* Type */ { "sTitle" : "" , "mDataProp" : "image" , "bSearchable" : false , "sWidth" : "25px" , "sClass" : "library_type" , "iDataSort" : 0 } ,
|
||||
/* Is Scheduled */ { "sTitle" : $.i18n._("Scheduled") , "mDataProp" : "is_scheduled" , "bSearchable" : false , "sWidth" : "90px" , "sClass" : "library_is_scheduled"} ,
|
||||
/* Is Playlist */ { "sTitle" : $.i18n._("Playlist") , "mDataProp" : "is_playlist" , "bSearchable" : false , "sWidth" : "70px" , "sClass" : "library_is_playlist"} ,
|
||||
/* Title */ { "sTitle" : $.i18n._("Title") , "mDataProp" : "track_title" , "sClass" : "library_title" , "sWidth" : "170px" } ,
|
||||
/* Creator */ { "sTitle" : $.i18n._("Creator") , "mDataProp" : "artist_name" , "sClass" : "library_creator" , "sWidth" : "160px" } ,
|
||||
/* Album */ { "sTitle" : $.i18n._("Album") , "mDataProp" : "album_title" , "sClass" : "library_album" , "sWidth" : "150px" } ,
|
||||
|
@ -447,6 +477,8 @@ var AIRTIME = (function(AIRTIME) {
|
|||
/* Composer */ { "sTitle" : $.i18n._("Composer") , "mDataProp" : "composer" , "bVisible" : false , "sClass" : "library_composer" , "sWidth" : "150px" },
|
||||
/* Conductor */ { "sTitle" : $.i18n._("Conductor") , "mDataProp" : "conductor" , "bVisible" : false , "sClass" : "library_conductor" , "sWidth" : "125px" },
|
||||
/* Copyright */ { "sTitle" : $.i18n._("Copyright") , "mDataProp" : "copyright" , "bVisible" : false , "sClass" : "library_copyright" , "sWidth" : "125px" },
|
||||
/* Cue In */ { "sTitle" : $.i18n._("Cue In") , "mDataProp" : "cuein" , "bVisible" : false , "sClass" : "library_length" , "sWidth" : "80px" },
|
||||
/* Cue Out */ { "sTitle" : $.i18n._("Cue Out") , "mDataProp" : "cueout" , "bVisible" : false , "sClass" : "library_length" , "sWidth" : "80px" },
|
||||
/* Encoded */ { "sTitle" : $.i18n._("Encoded By") , "mDataProp" : "encoded_by" , "bVisible" : false , "sClass" : "library_encoded" , "sWidth" : "150px" },
|
||||
/* Genre */ { "sTitle" : $.i18n._("Genre") , "mDataProp" : "genre" , "bVisible" : false , "sClass" : "library_genre" , "sWidth" : "100px" },
|
||||
/* ISRC Number */ { "sTitle" : $.i18n._("ISRC") , "mDataProp" : "isrc_number" , "bVisible" : false , "sClass" : "library_isrc" , "sWidth" : "150px" },
|
||||
|
@ -560,12 +592,46 @@ var AIRTIME = (function(AIRTIME) {
|
|||
},
|
||||
"fnRowCallback": AIRTIME.library.fnRowCallback,
|
||||
"fnCreatedRow": function( nRow, aData, iDataIndex ) {
|
||||
|
||||
//add soundcloud icon
|
||||
if (aData.soundcloud_status !== undefined) {
|
||||
if (aData.soundcloud_status === "-2") {
|
||||
$(nRow).find("td.library_title").append('<span class="small-icon progress"/>');
|
||||
} else if (aData.soundcloud_status === "-3") {
|
||||
$(nRow).find("td.library_title").append('<span class="small-icon sc-error"/>');
|
||||
} else if (aData.soundcloud_status !== null) {
|
||||
$(nRow).find("td.library_title").append('<span class="small-icon soundcloud"/>');
|
||||
}
|
||||
}
|
||||
|
||||
// add checkbox
|
||||
$(nRow).find('td.library_checkbox').html("<input type='checkbox' name='cb_"+aData.id+"'>");
|
||||
|
||||
// add audio preview image/button
|
||||
if (aData.ftype === "audioclip") {
|
||||
$(nRow).find('td.library_type').html('<img title="'+$.i18n._("Track preview")+'" src="'+baseUrl+'css/images/icon_audioclip.png">');
|
||||
} else if (aData.ftype === "playlist") {
|
||||
$(nRow).find('td.library_type').html('<img title="'+$.i18n._("Playlist preview")+'" src="'+baseUrl+'css/images/icon_playlist.png">');
|
||||
} else if (aData.ftype === "block") {
|
||||
$(nRow).find('td.library_type').html('<img title="'+$.i18n._("Smart Block")+'" src="'+baseUrl+'css/images/icon_smart-block.png">');
|
||||
} else if (aData.ftype === "stream") {
|
||||
$(nRow).find('td.library_type').html('<img title="'+$.i18n._("Webstream preview")+'" src="'+baseUrl+'css/images/icon_webstream.png">');
|
||||
}
|
||||
|
||||
if (aData.is_scheduled) {
|
||||
$(nRow).find("td.library_is_scheduled").html('<span class="small-icon media-item-in-use"></span>');
|
||||
} else if (!aData.is_scheduled) {
|
||||
$(nRow).find("td.library_is_scheduled").html('');
|
||||
}
|
||||
if (aData.is_playlist) {
|
||||
$(nRow).find("td.library_is_playlist").html('<span class="small-icon media-item-in-use"></span>');
|
||||
} else if (!aData.is_playlist) {
|
||||
$(nRow).find("td.library_is_playlist").html('');
|
||||
}
|
||||
|
||||
// add the play function to the library_type td
|
||||
$(nRow).find('td.library_type').click(function(){
|
||||
if (aData.ftype === 'playlist' && aData.length !== '0.0'){
|
||||
playlistIndex = $(this).parent().attr('id').substring(3);
|
||||
open_playlist_preview(playlistIndex, 0);
|
||||
open_playlist_preview(aData.audioFile, 0);
|
||||
} else if (aData.ftype === 'audioclip') {
|
||||
if (isAudioSupported(aData.mime)) {
|
||||
open_audio_preview(aData.ftype, aData.audioFile, aData.track_title, aData.artist_name);
|
||||
|
@ -575,8 +641,7 @@ var AIRTIME = (function(AIRTIME) {
|
|||
open_audio_preview(aData.ftype, aData.audioFile, aData.track_title, aData.artist_name);
|
||||
}
|
||||
} else if (aData.ftype == 'block' && aData.bl_type == 'static') {
|
||||
blockIndex = $(this).parent().attr('id').substring(3);
|
||||
open_block_preview(blockIndex, 0);
|
||||
open_block_preview(aData.audioFile, 0);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
@ -611,7 +676,28 @@ var AIRTIME = (function(AIRTIME) {
|
|||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
/*$(nRow).find(".media-item-in-use").qtip({
|
||||
content: {
|
||||
text: aData.status_msg
|
||||
},
|
||||
hide: {
|
||||
delay: 500,
|
||||
fixed: true
|
||||
},
|
||||
style: {
|
||||
border: {
|
||||
width: 0,
|
||||
radius: 4
|
||||
},
|
||||
classes: "ui-tooltip-dark ui-tooltip-rounded"
|
||||
},
|
||||
position: {
|
||||
my: "left bottom",
|
||||
at: "right center"
|
||||
},
|
||||
});*/
|
||||
|
||||
// add a tool tip to appear when the user clicks on the type
|
||||
// icon.
|
||||
$(nRow).find("td:not(.library_checkbox, .library_type)").qtip({
|
||||
|
@ -1270,6 +1356,8 @@ var validationTypes = {
|
|||
"composer" : "s",
|
||||
"conductor" : "s",
|
||||
"copyright" : "s",
|
||||
"cuein" : "l",
|
||||
"cueout" : "l",
|
||||
"encoded_by" : "s",
|
||||
"utime" : "t",
|
||||
"mtime" : "t",
|
||||
|
@ -1301,12 +1389,23 @@ $(document).ready(function() {
|
|||
data = $("#edit-md-dialog form").serializeArray();
|
||||
$.post(baseUrl+'library/edit-file-md', {format: "json", id: file_id, data: data}, function() {
|
||||
$("#edit-md-dialog").dialog().remove();
|
||||
oTable.fnStandingRedraw();
|
||||
|
||||
// don't redraw the library table if we are on calendar page
|
||||
// we would be on calendar if viewing recorded file metadata
|
||||
if ($("#schedule_calendar").length === 0) {
|
||||
oTable.fnStandingRedraw();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#editmdcancel').live("click", function() {
|
||||
$("#edit-md-dialog").dialog().remove();
|
||||
});
|
||||
|
||||
$('#edit-md-dialog').live("keyup", function(event) {
|
||||
if (event.keyCode === 13) {
|
||||
$('#editmdsave').click();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -30,8 +30,7 @@ $(document).ready(function() {
|
|||
var tempFileName = j.tempfilepath;
|
||||
$.get(baseUrl+'Plupload/copyfile/format/json/name/'+
|
||||
encodeURIComponent(file.name)+'/tempname/' +
|
||||
encodeURIComponent(tempFileName), function(json){
|
||||
var jr = jQuery.parseJSON(json);
|
||||
encodeURIComponent(tempFileName), function(jr){
|
||||
if(jr.error !== undefined) {
|
||||
var row = $("<tr/>")
|
||||
.append('<td>' + file.name +'</td>')
|
||||
|
|
|
@ -12,6 +12,7 @@ var AIRTIME = (function(AIRTIME){
|
|||
viewport,
|
||||
$lib,
|
||||
$pl,
|
||||
$togglePl = $("<button id='pl_edit' class='btn btn-small' href='#' title='"+$.i18n._("Open Playlist Editor")+"'>"+$.i18n._("Open Playlist Editor")+"</button>"),
|
||||
widgetHeight,
|
||||
resizeTimeout,
|
||||
width;
|
||||
|
@ -363,6 +364,17 @@ var AIRTIME = (function(AIRTIME){
|
|||
removeButtonCheck();
|
||||
}
|
||||
|
||||
function openPlaylistPanel() {
|
||||
var screenWidth = Math.floor(viewport.width - 40);
|
||||
viewport = AIRTIME.utilities.findViewportDimensions();
|
||||
widgetHeight = viewport.height - 185;
|
||||
|
||||
$lib.width(Math.floor(screenWidth * 0.53));
|
||||
$pl.show().width(Math.floor(screenWidth * 0.44));
|
||||
$pl.height(widgetHeight);
|
||||
$("#pl_edit").hide();
|
||||
}
|
||||
|
||||
//Purpose of this function is to iterate over all playlist elements
|
||||
//and verify whether they can be previewed by the browser or not. If not
|
||||
//then the playlist element is greyed out
|
||||
|
@ -450,9 +462,8 @@ var AIRTIME = (function(AIRTIME){
|
|||
if ($(this).hasClass('close')) {
|
||||
var sUrl = baseUrl+"playlist/get-block-info";
|
||||
mod.disableUI();
|
||||
$.post(sUrl, {format:"json", id:blockId}, function(json){
|
||||
$.post(sUrl, {format:"json", id:blockId}, function(data){
|
||||
$html = "";
|
||||
var data = $.parseJSON(json);
|
||||
var isStatic = data.isStatic;
|
||||
delete data.type;
|
||||
if (isStatic) {
|
||||
|
@ -643,8 +654,7 @@ var AIRTIME = (function(AIRTIME){
|
|||
obj_id = $('input[id="obj_id"]').val();
|
||||
url = baseUrl+"Playlist/shuffle";
|
||||
enableLoadingIcon();
|
||||
$.post(url, {format: "json", obj_id: obj_id}, function(data){
|
||||
var json = $.parseJSON(data)
|
||||
$.post(url, {format: "json", obj_id: obj_id}, function(json){
|
||||
|
||||
if (json.error !== undefined) {
|
||||
alert(json.error);
|
||||
|
@ -711,7 +721,40 @@ var AIRTIME = (function(AIRTIME){
|
|||
|
||||
|
||||
});
|
||||
|
||||
|
||||
$lib.on("click", "#pl_edit", function() {
|
||||
openPlaylistPanel();
|
||||
$.ajax( {
|
||||
url : baseUrl+"usersettings/set-library-screen-settings",
|
||||
type : "POST",
|
||||
data : {
|
||||
settings : {
|
||||
playlist : true
|
||||
},
|
||||
format : "json"
|
||||
},
|
||||
dataType : "json"
|
||||
});
|
||||
});
|
||||
|
||||
$pl.on("click", "#lib_pl_close", function() {
|
||||
var screenWidth = Math.floor(viewport.width - 40);
|
||||
$pl.hide();
|
||||
$lib.width(screenWidth).find("#library_display_length").append($togglePl.show());
|
||||
|
||||
$.ajax( {
|
||||
url : baseUrl+"usersettings/set-library-screen-settings",
|
||||
type : "POST",
|
||||
data : {
|
||||
settings : {
|
||||
playlist : false
|
||||
},
|
||||
format : "json"
|
||||
},
|
||||
dataType : "json"
|
||||
});
|
||||
});
|
||||
|
||||
$('#save_button').live("click", function(event){
|
||||
/* Smart blocks: get name, description, and criteria
|
||||
* Playlists: get name, description
|
||||
|
@ -727,8 +770,7 @@ var AIRTIME = (function(AIRTIME){
|
|||
enableLoadingIcon();
|
||||
$.post(save_action,
|
||||
{format: "json", data: criteria, name: block_name, description: block_desc, obj_id: obj_id, type: obj_type, modified: lastMod},
|
||||
function(data){
|
||||
var json = $.parseJSON(data);
|
||||
function(json){
|
||||
if (json.error !== undefined) {
|
||||
alert(json.error);
|
||||
}
|
||||
|
@ -737,7 +779,7 @@ var AIRTIME = (function(AIRTIME){
|
|||
}
|
||||
setModified(json.modified);
|
||||
if (obj_type == "block") {
|
||||
callback(data, "save");
|
||||
callback(json, "save");
|
||||
} else {
|
||||
$('.success').text($.i18n._('Playlist saved'));
|
||||
$('.success').show();
|
||||
|
@ -749,6 +791,12 @@ var AIRTIME = (function(AIRTIME){
|
|||
}
|
||||
);
|
||||
});
|
||||
|
||||
$("#pl-bl-clear-content").live("click", function(event) {
|
||||
var sUrl = baseUrl+"playlist/empty-content",
|
||||
oData = {};
|
||||
playlistRequest(sUrl, oData);
|
||||
});
|
||||
}
|
||||
|
||||
function setUpPlaylist() {
|
||||
|
@ -884,7 +932,9 @@ var AIRTIME = (function(AIRTIME){
|
|||
};
|
||||
|
||||
mod.fnEdit = function(id, type, url) {
|
||||
|
||||
if ($pl.is(":hidden")) {
|
||||
openPlaylistPanel();
|
||||
}
|
||||
stopAudioPreview();
|
||||
|
||||
$.post(url,
|
||||
|
@ -1049,31 +1099,45 @@ var AIRTIME = (function(AIRTIME){
|
|||
};
|
||||
|
||||
function setWidgetSize() {
|
||||
viewport = AIRTIME.utilities.findViewportDimensions();
|
||||
widgetHeight = viewport.height - 185;
|
||||
width = Math.floor(viewport.width - 80);
|
||||
|
||||
var libTableHeight = widgetHeight - 130;
|
||||
viewport = AIRTIME.utilities.findViewportDimensions();
|
||||
widgetHeight = viewport.height - 185;
|
||||
width = Math.floor(viewport.width - 80);
|
||||
|
||||
$lib.height(widgetHeight)
|
||||
.find(".dataTables_scrolling")
|
||||
.css("max-height", libTableHeight)
|
||||
.end()
|
||||
.width(Math.floor(width * 0.55));
|
||||
|
||||
$pl.height(widgetHeight)
|
||||
.width(Math.floor(width * 0.45));
|
||||
var libTableHeight = widgetHeight - 130;
|
||||
|
||||
if (!$pl.is(':hidden')) {
|
||||
$lib.height(widgetHeight)
|
||||
.find(".dataTables_scrolling")
|
||||
.css("max-height", libTableHeight)
|
||||
.end()
|
||||
.width(Math.floor(width * 0.55));
|
||||
|
||||
$pl.height(widgetHeight)
|
||||
.width(Math.floor(width * 0.45));
|
||||
} else {
|
||||
$lib.height(widgetHeight)
|
||||
.find(".dataTables_scrolling")
|
||||
.css("max-height", libTableHeight)
|
||||
.end()
|
||||
.width(width + 40);
|
||||
}
|
||||
}
|
||||
|
||||
mod.onReady = function() {
|
||||
$lib = $("#library_content");
|
||||
$pl = $("#side_playlist");
|
||||
|
||||
|
||||
|
||||
setWidgetSize();
|
||||
|
||||
AIRTIME.library.libraryInit();
|
||||
AIRTIME.playlist.init();
|
||||
|
||||
|
||||
if ($pl.is(':hidden')) {
|
||||
$lib.find("#library_display_length").append($togglePl.show());
|
||||
}
|
||||
|
||||
$pl.find(".ui-icon-alert").qtip({
|
||||
content: {
|
||||
text: $.i18n._("Airtime is unsure about the status of this file. This can happen when the file is on a remote drive that is unaccessible or the file is in a directory that isn't 'watched' anymore.")
|
||||
|
|
|
@ -23,7 +23,6 @@ $(document).ready(function() {
|
|||
function getDataAndPlot(startTimestamp, endTimestamp){
|
||||
// get data
|
||||
$.get(baseUrl+'Listenerstat/get-data', {startTimestamp: startTimestamp, endTimestamp: endTimestamp}, function(data){
|
||||
data = JSON.parse(data);
|
||||
out = new Object();
|
||||
$.each(data, function(mpName, v){
|
||||
plotData = new Object();
|
||||
|
|
|
@ -351,7 +351,7 @@ function setupUI() {
|
|||
* It is only active if playlist is not empty
|
||||
*/
|
||||
var plContents = $('#spl_sortable').children();
|
||||
var shuffleButton = $('button[id="shuffle_button"], button[id="playlist_shuffle_button"]');
|
||||
var shuffleButton = $('button[id="shuffle_button"], button[id="playlist_shuffle_button"], button[id="pl-bl-clear-content"]');
|
||||
|
||||
if (!plContents.hasClass('spl_empty')) {
|
||||
if (shuffleButton.hasClass('ui-state-disabled')) {
|
||||
|
@ -480,9 +480,8 @@ function getCriteriaOptionType(e) {
|
|||
return criteriaTypes[criteria];
|
||||
}
|
||||
|
||||
function callback(data, type) {
|
||||
var json = $.parseJSON(data),
|
||||
dt = $('table[id="library_display"]').dataTable();
|
||||
function callback(json, type) {
|
||||
var dt = $('table[id="library_display"]').dataTable();
|
||||
|
||||
if (type == 'shuffle' || type == 'generate') {
|
||||
if (json.error !== undefined) {
|
||||
|
@ -560,7 +559,9 @@ function enableLoadingIcon() {
|
|||
function disableLoadingIcon() {
|
||||
$("#side_playlist").unblock()
|
||||
}
|
||||
|
||||
// We need to know if the criteria value will be a string
|
||||
// or numeric value in order to populate the modifier
|
||||
// select list
|
||||
var criteriaTypes = {
|
||||
0 : "",
|
||||
"album_title" : "s",
|
||||
|
@ -569,6 +570,8 @@ var criteriaTypes = {
|
|||
"composer" : "s",
|
||||
"conductor" : "s",
|
||||
"copyright" : "s",
|
||||
"cuein" : "n",
|
||||
"cueout" : "n",
|
||||
"artist_name" : "s",
|
||||
"encoded_by" : "s",
|
||||
"utime" : "n",
|
||||
|
|
|
@ -108,8 +108,7 @@ $(document).ready(function() {
|
|||
var data = $('#pref_form').serialize();
|
||||
var url = baseUrl+'Preference/index';
|
||||
|
||||
$.post(url, {format: "json", data: data}, function(data){
|
||||
var json = $.parseJSON(data);
|
||||
$.post(url, {format: "json", data: data}, function(json){
|
||||
$('#content').empty().append(json.html);
|
||||
$.cookie("default_airtime_locale", $('#locale').val(), {path: '/'});
|
||||
setTimeout(removeSuccessMsg, 5000);
|
||||
|
|
|
@ -77,8 +77,7 @@ function showForIcecast(ele){
|
|||
function checkLiquidsoapStatus(){
|
||||
var url = baseUrl+'Preference/get-liquidsoap-status/format/json';
|
||||
var id = $(this).attr("id");
|
||||
$.post(url, function(json){
|
||||
var json_obj = jQuery.parseJSON(json);
|
||||
$.post(url, function(json_obj){
|
||||
for(var i=0;i<json_obj.length;i++){
|
||||
var obj = json_obj[i];
|
||||
var id;
|
||||
|
@ -443,8 +442,7 @@ $(document).ready(function() {
|
|||
var data = $('#stream_form').serialize();
|
||||
var url = baseUrl+'Preference/stream-setting';
|
||||
|
||||
$.post(url, {format:"json", data: data}, function(data){
|
||||
var json = $.parseJSON(data);
|
||||
$.post(url, {format:"json", data: data}, function(json){
|
||||
$('#content').empty().append(json.html);
|
||||
setupEventListeners();
|
||||
setSliderForReplayGain();
|
||||
|
|
|
@ -401,7 +401,7 @@ $(document).ready(function() {
|
|||
oItems.edit.callback = callback;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//define a content callback.
|
||||
if (oItems.content !== undefined) {
|
||||
|
||||
|
@ -442,9 +442,11 @@ $(document).ready(function() {
|
|||
|
||||
//define a view recorded callback.
|
||||
if (oItems.view_recorded !== undefined) {
|
||||
|
||||
callback = function() {
|
||||
document.location.href = oItems.view_recorded.url;
|
||||
$.get(oItems.view_recorded.url, {format: "json"}, function(json){
|
||||
//in library.js
|
||||
buildEditMetadataDialog(json);
|
||||
});
|
||||
};
|
||||
oItems.view_recorded.callback = callback;
|
||||
}
|
||||
|
|
|
@ -81,9 +81,20 @@ var AIRTIME = (function(AIRTIME){
|
|||
return mod.showInstances;
|
||||
};
|
||||
|
||||
mod.refresh = function() {
|
||||
mod.refresh = function(schedId) {
|
||||
mod.resetTimestamp();
|
||||
oSchedTable.fnDraw();
|
||||
|
||||
// once a track plays out we need to check if we can update
|
||||
// the is_scheduled flag in cc_files
|
||||
if (schedId > 0) {
|
||||
$.post(baseUrl+"schedule/update-future-is-scheduled",
|
||||
{"format": "json", "schedId": schedId}, function(data) {
|
||||
if (data.redrawLibTable !== undefined && data.redrawLibTable) {
|
||||
$("#library_content").find("#library_display").dataTable().fnStandingRedraw();
|
||||
}
|
||||
});
|
||||
oSchedTable.fnDraw();
|
||||
}
|
||||
};
|
||||
|
||||
mod.checkSelectButton = function() {
|
||||
|
@ -251,10 +262,11 @@ var AIRTIME = (function(AIRTIME){
|
|||
mod.fnItemCallback = function(json) {
|
||||
checkError(json);
|
||||
|
||||
mod.getSelectedCursors();
|
||||
mod.getSelectedCursors();
|
||||
oSchedTable.fnDraw();
|
||||
|
||||
|
||||
mod.enableUI();
|
||||
$("#library_content").find("#library_display").dataTable().fnStandingRedraw();
|
||||
};
|
||||
|
||||
mod.getSelectedCursors = function() {
|
||||
|
@ -796,7 +808,7 @@ var AIRTIME = (function(AIRTIME){
|
|||
if(refreshInterval > maxRefreshInterval){
|
||||
refreshInterval = maxRefreshInterval;
|
||||
}
|
||||
mod.timeout = setTimeout(mod.refresh, refreshInterval); //need refresh in milliseconds
|
||||
mod.timeout = setTimeout(function() {mod.refresh(aData.id)}, refreshInterval); //need refresh in milliseconds
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1066,6 +1078,7 @@ var AIRTIME = (function(AIRTIME){
|
|||
url: url,
|
||||
data: {format: "json", id: data.instance},
|
||||
success: function(data){
|
||||
$("#library_content").find("#library_display").dataTable().fnStandingRedraw();
|
||||
var oTable = $sbTable.dataTable();
|
||||
oTable.fnDraw();
|
||||
}
|
||||
|
|
|
@ -189,8 +189,7 @@ $(document).ready(function() {
|
|||
var data = $('#user_form').serialize();
|
||||
var url = baseUrl+'User/add-user';
|
||||
|
||||
$.post(url, {format: "json", data: data}, function(data){
|
||||
var json = $.parseJSON(data);
|
||||
$.post(url, {format: "json", data: data}, function(json){
|
||||
if (json.valid === "true") {
|
||||
$('#content').empty().append(json.html);
|
||||
populateUserTable();
|
||||
|
|
|
@ -187,7 +187,7 @@
|
|||
label = $.i18n._("kbps");
|
||||
} else if (th.attr('id') == "utime" || th.attr('id') == "mtime" || th.attr('id') == "lptime") {
|
||||
label = $.i18n._("yyyy-mm-dd");
|
||||
} else if (th.attr('id') == "length") {
|
||||
} else if (th.attr('id') == "length" || th.attr('id') == "cuein" || th.attr('id') == "cueout") {
|
||||
label = $.i18n._("hh:mm:ss.t");
|
||||
} else if (th.attr('id') == "sample_rate") {
|
||||
label = $.i18n._("kHz");
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
airtime (2.4.0-1) unstable; urgency=low
|
||||
|
||||
* Nightly development snapshot of Airtime 2.4.x series
|
||||
|
||||
-- Daniel James <daniel@64studio.com> Tue, 19 Mar 2013 16:39:23 +0000
|
||||
|
||||
airtime (2.3.0-2) unstable; urgency=low
|
||||
|
||||
* Don't run the airtime-install script if the user has chosen not to
|
||||
|
|
|
@ -43,7 +43,7 @@ Depends: apache2,
|
|||
pwgen,
|
||||
python,
|
||||
rabbitmq-server,
|
||||
silan (>= 0.3.0~),
|
||||
silan (>= 0.3.1~),
|
||||
sudo,
|
||||
sysv-rc,
|
||||
tar (>= 1.22),
|
||||
|
|
|
@ -16,7 +16,7 @@ includefile="${configdir}/apache.conf"
|
|||
a2tplfile="${configdir}/apache.vhost.tpl"
|
||||
phpinifile="${configdir}/airtime.ini"
|
||||
OLDVERSION="$2"
|
||||
NEWVERSION="2.3.1"
|
||||
NEWVERSION="2.4.0"
|
||||
|
||||
case "$1" in
|
||||
configure|reconfigure)
|
||||
|
|
|
@ -116,7 +116,9 @@ class RequestProvider(object):
|
|||
def __init__(self, cfg):
|
||||
self.config = cfg
|
||||
self.requests = {}
|
||||
self.url = ApcUrl("http://%s:%s/%s/%s/%s" \
|
||||
if self.config["base_dir"].startswith("/"):
|
||||
self.config["base_dir"] = self.config["base_dir"][1:]
|
||||
self.url = ApcUrl("http://%s:%s/%s%s/%s" \
|
||||
% (self.config["host"], str(self.config["base_port"]),
|
||||
self.config["base_dir"], self.config["api_base"],
|
||||
'%%action%%'))
|
||||
|
@ -247,7 +249,9 @@ class AirtimeApiClient(object):
|
|||
def construct_url(self,config_action_key):
|
||||
"""Constructs the base url for every request"""
|
||||
# TODO : Make other methods in this class use this this method.
|
||||
url = "http://%s:%s/%s/%s/%s" % \
|
||||
if self.config["base_dir"].startswith("/"):
|
||||
self.config["base_dir"] = self.config["base_dir"][1:]
|
||||
url = "http://%s:%s/%s%s/%s" % \
|
||||
(self.config["host"], str(self.config["base_port"]),
|
||||
self.config["base_dir"], self.config["api_base"],
|
||||
self.config[config_action_key])
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
virtualenv_bin="/usr/lib/airtime/airtime_virtualenv/bin/"
|
||||
. ${virtualenv_bin}activate
|
||||
|
||||
pypo_user="pypo"
|
||||
# Absolute path to this script
|
||||
SCRIPT=`readlink -f $0`
|
||||
# Absolute directory this script is in
|
||||
pypo_path=`dirname $SCRIPT`
|
||||
|
||||
# Location of pypo_cli.py Python script
|
||||
pypo_path="/usr/lib/airtime/pypo/bin/"
|
||||
api_client_path="/usr/lib/airtime/"
|
||||
pypo_script="pypocli.py"
|
||||
cd ${pypo_path}
|
||||
exec 2>&1
|
||||
|
||||
set +e
|
||||
cat /etc/default/locale | grep -i "LANG=.*UTF-\?8"
|
||||
|
@ -26,6 +26,6 @@ export LC_ALL=`cat /etc/default/locale | grep "LANG=" | cut -d= -f2 | tr -d "\n\
|
|||
export TERM=xterm
|
||||
|
||||
|
||||
exec python ${pypo_path}${pypo_script} > /var/log/airtime/pypo/py-interpreter.log 2>&1
|
||||
exec python ${pypo_path}/${pypo_script} > /var/log/airtime/pypo/py-interpreter.log 2>&1
|
||||
|
||||
# EOF
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
FILE = "file"
|
||||
EVENT = "event"
|
||||
STREAM_BUFFER_START = "stream_buffer_start"
|
||||
STREAM_OUTPUT_START = "stream_output_start"
|
||||
STREAM_BUFFER_END = "stream_buffer_end"
|
||||
STREAM_OUTPUT_END = "stream_output_end"
|
|
@ -354,28 +354,32 @@ end
|
|||
# Add a skip function to a source
|
||||
# when it does not have one
|
||||
# by default
|
||||
def add_skip_command(s)
|
||||
# A command to skip
|
||||
def skip(_)
|
||||
# get playing (active) queue and flush it
|
||||
l = list.hd(server.execute("queue.secondary_queue"))
|
||||
l = string.split(separator=" ",l)
|
||||
list.iter(fun (rid) -> ignore(server.execute("queue.remove #{rid}")), l)
|
||||
#def add_skip_command(s)
|
||||
# # A command to skip
|
||||
# def skip(_)
|
||||
# # get playing (active) queue and flush it
|
||||
# l = list.hd(server.execute("queue.secondary_queue"))
|
||||
# l = string.split(separator=" ",l)
|
||||
# list.iter(fun (rid) -> ignore(server.execute("queue.remove #{rid}")), l)
|
||||
#
|
||||
# l = list.hd(server.execute("queue.primary_queue"))
|
||||
# l = string.split(separator=" ", l)
|
||||
# if list.length(l) > 0 then
|
||||
# source.skip(s)
|
||||
# "Skipped"
|
||||
# else
|
||||
# "Not skipped"
|
||||
# end
|
||||
# end
|
||||
# # Register the command:
|
||||
# server.register(namespace="source",
|
||||
# usage="skip",
|
||||
# description="Skip the current song.",
|
||||
# "skip",fun(s) -> begin log("source.skip") skip(s) end)
|
||||
#end
|
||||
|
||||
l = list.hd(server.execute("queue.primary_queue"))
|
||||
l = string.split(separator=" ", l)
|
||||
if list.length(l) > 0 then
|
||||
source.skip(s)
|
||||
"Skipped"
|
||||
else
|
||||
"Not skipped"
|
||||
end
|
||||
end
|
||||
# Register the command:
|
||||
server.register(namespace="source",
|
||||
usage="skip",
|
||||
description="Skip the current song.",
|
||||
"skip",fun(s) -> begin log("source.skip") skip(s) end)
|
||||
def clear_queue(s)
|
||||
source.skip(s)
|
||||
end
|
||||
|
||||
def set_dynamic_source_id(id) =
|
||||
|
|
|
@ -34,8 +34,35 @@ just_switched = ref false
|
|||
|
||||
%include "ls_lib.liq"
|
||||
|
||||
queue = audio_to_stereo(id="queue_src", request.equeue(id="queue", length=0.5))
|
||||
queue = cue_cut(queue)
|
||||
sources = ref []
|
||||
source_id = ref 0
|
||||
|
||||
def create_source()
|
||||
l = request.equeue(id="s#{!source_id}", length=0.5)
|
||||
l = cue_cut(l)
|
||||
sources := list.append([l], !sources)
|
||||
server.register(namespace="queues",
|
||||
"s#{!source_id}_skip",
|
||||
fun (s) -> begin log("queues.s#{!source_id}_skip")
|
||||
clear_queue(l)
|
||||
"Done"
|
||||
end)
|
||||
source_id := !source_id + 1
|
||||
end
|
||||
|
||||
create_source()
|
||||
create_source()
|
||||
create_source()
|
||||
create_source()
|
||||
|
||||
create_source()
|
||||
create_source()
|
||||
create_source()
|
||||
create_source()
|
||||
|
||||
queue = add(!sources)
|
||||
|
||||
queue = audio_to_stereo(id="queue_src", queue)
|
||||
queue = amplify(1., override="replay_gain", queue)
|
||||
|
||||
# the crossfade function controls fade in/out
|
||||
|
@ -247,7 +274,7 @@ end
|
|||
|
||||
|
||||
# Attach a skip command to the source s:
|
||||
add_skip_command(s)
|
||||
#add_skip_command(s)
|
||||
|
||||
server.register(namespace="streams",
|
||||
description="Stop Master DJ source.",
|
||||
|
|
|
@ -13,8 +13,8 @@ import signal
|
|||
import logging
|
||||
import locale
|
||||
import os
|
||||
from Queue import Queue
|
||||
|
||||
from Queue import Queue
|
||||
from threading import Lock
|
||||
|
||||
from pypopush import PypoPush
|
||||
|
@ -63,7 +63,7 @@ try:
|
|||
LogWriter.override_std_err(logger)
|
||||
except Exception, e:
|
||||
print "Couldn't configure logging"
|
||||
sys.exit()
|
||||
sys.exit(1)
|
||||
|
||||
def configure_locale():
|
||||
logger.debug("Before %s", locale.nl_langinfo(locale.CODESET))
|
||||
|
@ -229,7 +229,7 @@ if __name__ == '__main__':
|
|||
stat.start()
|
||||
|
||||
# all join() are commented out because we want to exit entire pypo
|
||||
# if pypofetch is exiting
|
||||
# if pypofetch terminates
|
||||
#pmh.join()
|
||||
#recorder.join()
|
||||
#pp.join()
|
||||
|
|
|
@ -7,17 +7,18 @@ import logging.config
|
|||
import json
|
||||
import telnetlib
|
||||
import copy
|
||||
from threading import Thread
|
||||
import subprocess
|
||||
import signal
|
||||
from datetime import datetime
|
||||
import traceback
|
||||
|
||||
from Queue import Empty
|
||||
from threading import Thread
|
||||
from subprocess import Popen, PIPE
|
||||
from configobj import ConfigObj
|
||||
|
||||
from api_clients import api_client
|
||||
from std_err_override import LogWriter
|
||||
from subprocess import Popen, PIPE
|
||||
|
||||
from configobj import ConfigObj
|
||||
|
||||
# configure logging
|
||||
logging_cfg = os.path.join(os.path.dirname(__file__), "logging.cfg")
|
||||
|
@ -25,6 +26,12 @@ logging.config.fileConfig(logging_cfg)
|
|||
logger = logging.getLogger()
|
||||
LogWriter.override_std_err(logger)
|
||||
|
||||
def keyboardInterruptHandler(signum, frame):
|
||||
logger = logging.getLogger()
|
||||
logger.info('\nKeyboard Interrupt\n')
|
||||
sys.exit(0)
|
||||
signal.signal(signal.SIGINT, keyboardInterruptHandler)
|
||||
|
||||
#need to wait for Python 2.7 for this..
|
||||
#logging.captureWarnings(True)
|
||||
|
||||
|
@ -35,8 +42,6 @@ try:
|
|||
LS_PORT = config['ls_port']
|
||||
#POLL_INTERVAL = int(config['poll_interval'])
|
||||
POLL_INTERVAL = 1800
|
||||
|
||||
|
||||
except Exception, e:
|
||||
logger.error('Error loading config file: %s', e)
|
||||
sys.exit()
|
||||
|
@ -481,6 +486,7 @@ class PypoFetch(Thread):
|
|||
except Exception, e:
|
||||
pass
|
||||
|
||||
media_copy = {}
|
||||
for key in media:
|
||||
media_item = media[key]
|
||||
if (media_item['type'] == 'file'):
|
||||
|
@ -490,12 +496,17 @@ class PypoFetch(Thread):
|
|||
media_item['file_ready'] = False
|
||||
media_filtered[key] = media_item
|
||||
|
||||
media_item['start'] = datetime.strptime(media_item['start'], "%Y-%m-%d-%H-%M-%S")
|
||||
media_item['end'] = datetime.strptime(media_item['end'], "%Y-%m-%d-%H-%M-%S")
|
||||
media_copy[media_item['start']] = media_item
|
||||
|
||||
|
||||
self.media_prepare_queue.put(copy.copy(media_filtered))
|
||||
except Exception, e: self.logger.error("%s", e)
|
||||
|
||||
# Send the data to pypo-push
|
||||
self.logger.debug("Pushing to pypo-push")
|
||||
self.push_queue.put(media)
|
||||
self.push_queue.put(media_copy)
|
||||
|
||||
|
||||
# cleanup
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
from threading import Thread
|
||||
from collections import deque
|
||||
from datetime import datetime
|
||||
|
||||
import traceback
|
||||
import sys
|
||||
import time
|
||||
|
||||
|
||||
from Queue import Empty
|
||||
|
||||
import signal
|
||||
def keyboardInterruptHandler(signum, frame):
|
||||
logger = logging.getLogger()
|
||||
logger.info('\nKeyboard Interrupt\n')
|
||||
sys.exit(0)
|
||||
signal.signal(signal.SIGINT, keyboardInterruptHandler)
|
||||
|
||||
class PypoLiqQueue(Thread):
|
||||
def __init__(self, q, pypo_liquidsoap, logger):
|
||||
Thread.__init__(self)
|
||||
self.queue = q
|
||||
self.logger = logger
|
||||
self.pypo_liquidsoap = pypo_liquidsoap
|
||||
|
||||
def main(self):
|
||||
time_until_next_play = None
|
||||
schedule_deque = deque()
|
||||
media_schedule = None
|
||||
|
||||
while True:
|
||||
try:
|
||||
if time_until_next_play is None:
|
||||
self.logger.info("waiting indefinitely for schedule")
|
||||
media_schedule = self.queue.get(block=True)
|
||||
else:
|
||||
self.logger.info("waiting %ss until next scheduled item" % \
|
||||
time_until_next_play)
|
||||
media_schedule = self.queue.get(block=True, \
|
||||
timeout=time_until_next_play)
|
||||
except Empty, e:
|
||||
#Time to push a scheduled item.
|
||||
media_item = schedule_deque.popleft()
|
||||
self.pypo_liquidsoap.push_item(media_item)
|
||||
if len(schedule_deque):
|
||||
time_until_next_play = \
|
||||
self.date_interval_to_seconds(
|
||||
schedule_deque[0]['start'] - datetime.utcnow())
|
||||
if time_until_next_play < 0:
|
||||
time_until_next_play = 0
|
||||
else:
|
||||
time_until_next_play = None
|
||||
else:
|
||||
self.logger.info("New schedule received: %s", media_schedule)
|
||||
|
||||
#new schedule received. Replace old one with this.
|
||||
schedule_deque.clear()
|
||||
|
||||
keys = sorted(media_schedule.keys())
|
||||
for i in keys:
|
||||
schedule_deque.append(media_schedule[i])
|
||||
|
||||
if len(keys):
|
||||
time_until_next_play = self.date_interval_to_seconds(\
|
||||
keys[0] - datetime.utcnow())
|
||||
else:
|
||||
time_until_next_play = None
|
||||
|
||||
|
||||
def date_interval_to_seconds(self, interval):
|
||||
"""
|
||||
Convert timedelta object into int representing the number of seconds. If
|
||||
number of seconds is less than 0, then return 0.
|
||||
"""
|
||||
seconds = (interval.microseconds + \
|
||||
(interval.seconds + interval.days * 24 * 3600) * 10 ** 6) / float(10 ** 6)
|
||||
if seconds < 0: seconds = 0
|
||||
|
||||
return seconds
|
||||
|
||||
def run(self):
|
||||
try: self.main()
|
||||
except Exception, e:
|
||||
self.logger.error('PypoLiqQueue Exception: %s', traceback.format_exc())
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,230 @@
|
|||
from pypofetch import PypoFetch
|
||||
from telnetliquidsoap import TelnetLiquidsoap
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
|
||||
import eventtypes
|
||||
import time
|
||||
|
||||
class PypoLiquidsoap():
|
||||
def __init__(self, logger, telnet_lock, host, port):
|
||||
self.logger = logger
|
||||
self.liq_queue_tracker = {
|
||||
"s0": None,
|
||||
"s1": None,
|
||||
"s2": None,
|
||||
"s3": None,
|
||||
}
|
||||
|
||||
self.telnet_liquidsoap = TelnetLiquidsoap(telnet_lock, \
|
||||
logger,\
|
||||
host,\
|
||||
port)
|
||||
|
||||
|
||||
def play(self, media_item):
|
||||
if media_item["type"] == eventtypes.FILE:
|
||||
self.handle_file_type(media_item)
|
||||
elif media_item["type"] == eventtypes.EVENT:
|
||||
self.handle_event_type(media_item)
|
||||
elif media_item["type"] == eventtypes.STREAM_BUFFER_START:
|
||||
self.telnet_liquidsoap.start_web_stream_buffer(media_item)
|
||||
elif media_item["type"] == eventtypes.STREAM_OUTPUT_START:
|
||||
if media_item['row_id'] != self.telnet_liquidsoap.current_prebuffering_stream_id:
|
||||
#this is called if the stream wasn't scheduled sufficiently ahead of time
|
||||
#so that the prebuffering stage could take effect. Let's do the prebuffering now.
|
||||
self.telnet_liquidsoap.start_web_stream_buffer(media_item)
|
||||
self.telnet_liquidsoap.start_web_stream(media_item)
|
||||
elif media_item['type'] == eventtypes.STREAM_BUFFER_END:
|
||||
self.telnet_liquidsoap.stop_web_stream_buffer()
|
||||
elif media_item['type'] == eventtypes.STREAM_OUTPUT_END:
|
||||
self.telnet_liquidsoap.stop_web_stream_output()
|
||||
else: raise UnknownMediaItemType(str(media_item))
|
||||
|
||||
def handle_file_type(self, media_item):
|
||||
"""
|
||||
Wait maximum 5 seconds (50 iterations) for file to become ready,
|
||||
otherwise give up on it.
|
||||
"""
|
||||
iter_num = 0
|
||||
while not media_item['file_ready'] and iter_num < 50:
|
||||
time.sleep(0.1)
|
||||
iter_num += 1
|
||||
|
||||
if media_item['file_ready']:
|
||||
available_queue = self.find_available_queue()
|
||||
|
||||
try:
|
||||
self.telnet_liquidsoap.queue_push(available_queue, media_item)
|
||||
self.liq_queue_tracker[available_queue] = media_item
|
||||
except Exception as e:
|
||||
self.logger.error(e)
|
||||
raise
|
||||
else:
|
||||
self.logger.warn("File %s did not become ready in less than 5 seconds. Skipping...", media_item['dst'])
|
||||
|
||||
def handle_event_type(self, media_item):
|
||||
if media_item['event_type'] == "kick_out":
|
||||
PypoFetch.disconnect_source(self.logger, self.telnet_lock, "live_dj")
|
||||
elif media_item['event_type'] == "switch_off":
|
||||
PypoFetch.switch_source(self.logger, self.telnet_lock, "live_dj", "off")
|
||||
|
||||
|
||||
def is_media_item_finished(self, media_item):
|
||||
if media_item is None:
|
||||
return True
|
||||
else:
|
||||
return datetime.utcnow() > media_item['end']
|
||||
|
||||
def find_available_queue(self):
|
||||
available_queue = None
|
||||
for i in self.liq_queue_tracker:
|
||||
mi = self.liq_queue_tracker[i]
|
||||
if mi == None or self.is_media_item_finished(mi):
|
||||
#queue "i" is available. Push to this queue
|
||||
available_queue = i
|
||||
|
||||
if available_queue == None:
|
||||
raise NoQueueAvailableException()
|
||||
|
||||
return available_queue
|
||||
|
||||
def get_queues():
|
||||
return self.liq_queue_tracker
|
||||
|
||||
|
||||
def verify_correct_present_media(self, scheduled_now):
|
||||
#verify whether Liquidsoap is currently playing the correct files.
|
||||
#if we find an item that Liquidsoap is not playing, then push it
|
||||
#into one of Liquidsoap's queues. If Liquidsoap is already playing
|
||||
#it do nothing. If Liquidsoap is playing a track that isn't in
|
||||
#currently_playing then stop it.
|
||||
|
||||
#Check for Liquidsoap media we should source.skip
|
||||
#get liquidsoap items for each queue. Since each queue can only have one
|
||||
#item, we should have a max of 8 items.
|
||||
|
||||
#TODO: Verify start, end, replay_gain is the same
|
||||
|
||||
#2013-03-21-22-56-00_0: {
|
||||
#id: 1,
|
||||
#type: "stream_output_start",
|
||||
#row_id: 41,
|
||||
#uri: "http://stream2.radioblackout.org:80/blackout.ogg",
|
||||
#start: "2013-03-21-22-56-00",
|
||||
#end: "2013-03-21-23-26-00",
|
||||
#show_name: "Untitled Show",
|
||||
#independent_event: true
|
||||
#},
|
||||
|
||||
|
||||
scheduled_now_files = \
|
||||
filter(lambda x: x["type"] == eventtypes.FILE, scheduled_now)
|
||||
|
||||
scheduled_now_webstream = \
|
||||
filter(lambda x: x["type"] == eventtypes.STREAM_OUTPUT_START, \
|
||||
scheduled_now)
|
||||
|
||||
schedule_ids = set(map(lambda x: x["row_id"], scheduled_now_files))
|
||||
|
||||
row_id_map = {}
|
||||
liq_queue_ids = set()
|
||||
for i in self.liq_queue_tracker:
|
||||
mi = self.liq_queue_tracker[i]
|
||||
if not self.is_media_item_finished(mi):
|
||||
liq_queue_ids.add(mi["row_id"])
|
||||
row_id_map[mi["row_id"]] = mi
|
||||
|
||||
to_be_removed = set()
|
||||
to_be_added = set()
|
||||
|
||||
#Iterate over the new files, and compare them to currently scheduled
|
||||
#tracks. If already in liquidsoap queue still need to make sure they don't
|
||||
#have different attributes such replay_gain etc.
|
||||
for i in scheduled_now_files:
|
||||
if i["row_id"] in row_id_map:
|
||||
mi = row_id_map[i["row_id"]]
|
||||
correct = mi['start'] == i['start'] and \
|
||||
mi['end'] == i['end'] and \
|
||||
mi['replay_gain'] == i['replay_gain']
|
||||
|
||||
if not correct:
|
||||
#need to re-add
|
||||
self.logger.info("Track %s found to have new attr." % i)
|
||||
to_be_removed.add(i["row_id"])
|
||||
to_be_added.add(i["row_id"])
|
||||
|
||||
|
||||
to_be_removed.update(liq_queue_ids - schedule_ids)
|
||||
to_be_added.update(schedule_ids - liq_queue_ids)
|
||||
|
||||
if len(to_be_removed):
|
||||
self.logger.info("Need to remove items from Liquidsoap: %s" % \
|
||||
to_be_removed)
|
||||
|
||||
#remove files from Liquidsoap's queue
|
||||
for i in self.liq_queue_tracker:
|
||||
mi = self.liq_queue_tracker[i]
|
||||
if mi is not None and mi["row_id"] in to_be_removed:
|
||||
self.stop(i)
|
||||
|
||||
if len(to_be_added):
|
||||
self.logger.info("Need to add items to Liquidsoap *now*: %s" % \
|
||||
to_be_added)
|
||||
|
||||
for i in scheduled_now:
|
||||
if i["row_id"] in to_be_added:
|
||||
self.modify_cue_point(i)
|
||||
self.play(i)
|
||||
|
||||
#handle webstreams
|
||||
current_stream_id = self.telnet_liquidsoap.get_current_stream_id()
|
||||
if len(scheduled_now_webstream):
|
||||
if current_stream_id != scheduled_now_webstream[0]:
|
||||
self.play(scheduled_now_webstream[0])
|
||||
elif current_stream_id != "-1":
|
||||
#something is playing and it shouldn't be.
|
||||
self.telnet_liquidsoap.stop_web_stream_buffer()
|
||||
self.telnet_liquidsoap.stop_web_stream_output()
|
||||
|
||||
def stop(self, queue):
|
||||
self.telnet_liquidsoap.queue_remove(queue)
|
||||
self.liq_queue_tracker[queue] = None
|
||||
|
||||
def is_file(self, media_item):
|
||||
return media_item["type"] == eventtypes.FILE
|
||||
|
||||
def modify_cue_point(self, link):
|
||||
if not self.is_file(link):
|
||||
return
|
||||
|
||||
tnow = datetime.utcnow()
|
||||
|
||||
link_start = link['start']
|
||||
|
||||
diff_td = tnow - link_start
|
||||
diff_sec = self.date_interval_to_seconds(diff_td)
|
||||
|
||||
if diff_sec > 0:
|
||||
self.logger.debug("media item was supposed to start %s ago. Preparing to start..", diff_sec)
|
||||
original_cue_in_td = timedelta(seconds=float(link['cue_in']))
|
||||
link['cue_in'] = self.date_interval_to_seconds(original_cue_in_td) + diff_sec
|
||||
|
||||
def date_interval_to_seconds(self, interval):
|
||||
"""
|
||||
Convert timedelta object into int representing the number of seconds. If
|
||||
number of seconds is less than 0, then return 0.
|
||||
"""
|
||||
seconds = (interval.microseconds + \
|
||||
(interval.seconds + interval.days * 24 * 3600) * 10 ** 6) / float(10 ** 6)
|
||||
if seconds < 0: seconds = 0
|
||||
|
||||
return seconds
|
||||
|
||||
|
||||
class UnknownMediaItemType(Exception):
|
||||
pass
|
||||
|
||||
class NoQueueAvailableException(Exception):
|
||||
pass
|
|
@ -9,10 +9,14 @@ import logging.config
|
|||
import telnetlib
|
||||
import calendar
|
||||
import math
|
||||
import traceback
|
||||
import os
|
||||
from pypofetch import PypoFetch
|
||||
|
||||
from Queue import Empty
|
||||
from pypofetch import PypoFetch
|
||||
from pypoliqqueue import PypoLiqQueue
|
||||
from pypoliquidsoap import PypoLiquidsoap
|
||||
|
||||
from Queue import Empty, Queue
|
||||
|
||||
from threading import Thread
|
||||
|
||||
|
@ -36,7 +40,6 @@ try:
|
|||
LS_HOST = config['ls_host']
|
||||
LS_PORT = config['ls_port']
|
||||
PUSH_INTERVAL = 2
|
||||
MAX_LIQUIDSOAP_QUEUE_LENGTH = 2
|
||||
except Exception, e:
|
||||
logger.error('Error loading config file %s', e)
|
||||
sys.exit()
|
||||
|
@ -58,88 +61,67 @@ class PypoPush(Thread):
|
|||
self.pushed_objects = {}
|
||||
self.logger = logging.getLogger('push')
|
||||
self.current_prebuffering_stream_id = None
|
||||
self.queue_id = 0
|
||||
|
||||
self.future_scheduled_queue = Queue()
|
||||
self.pypo_liquidsoap = PypoLiquidsoap(self.logger, telnet_lock,\
|
||||
LS_HOST, LS_PORT)
|
||||
|
||||
self.plq = PypoLiqQueue(self.future_scheduled_queue, \
|
||||
self.pypo_liquidsoap, \
|
||||
self.logger)
|
||||
self.plq.daemon = True
|
||||
self.plq.start()
|
||||
|
||||
|
||||
def main(self):
|
||||
loops = 0
|
||||
heartbeat_period = math.floor(30 / PUSH_INTERVAL)
|
||||
|
||||
next_media_item_chain = None
|
||||
media_schedule = None
|
||||
time_until_next_play = None
|
||||
chains = None
|
||||
|
||||
while True:
|
||||
try:
|
||||
if time_until_next_play is None:
|
||||
media_schedule = self.queue.get(block=True)
|
||||
else:
|
||||
media_schedule = self.queue.get(block=True, timeout=time_until_next_play)
|
||||
|
||||
chains = self.get_all_chains(media_schedule)
|
||||
|
||||
#We get to the following lines only if a schedule was received.
|
||||
liquidsoap_queue_approx = self.get_queue_items_from_liquidsoap()
|
||||
liquidsoap_stream_id = self.get_current_stream_id_from_liquidsoap()
|
||||
|
||||
tnow = datetime.utcnow()
|
||||
current_event_chain, original_chain = self.get_current_chain(chains, tnow)
|
||||
|
||||
if len(current_event_chain) > 0:
|
||||
try:
|
||||
chains.remove(original_chain)
|
||||
except ValueError, e:
|
||||
self.logger.error(str(e))
|
||||
|
||||
#At this point we know that Liquidsoap is playing something, and that something
|
||||
#is scheduled. We need to verify whether the schedule we just received matches
|
||||
#what Liquidsoap is playing, and if not, correct it.
|
||||
|
||||
self.handle_new_schedule(media_schedule, liquidsoap_queue_approx, liquidsoap_stream_id, current_event_chain)
|
||||
|
||||
|
||||
#At this point everything in the present has been taken care of and Liquidsoap
|
||||
#is playing whatever is scheduled.
|
||||
#Now we need to prepare ourselves for future scheduled events.
|
||||
#
|
||||
next_media_item_chain = self.get_next_schedule_chain(chains, tnow)
|
||||
|
||||
self.logger.debug("Next schedule chain: %s", next_media_item_chain)
|
||||
if next_media_item_chain is not None:
|
||||
try:
|
||||
chains.remove(next_media_item_chain)
|
||||
except ValueError, e:
|
||||
self.logger.error(str(e))
|
||||
|
||||
chain_start = datetime.strptime(next_media_item_chain[0]['start'], "%Y-%m-%d-%H-%M-%S")
|
||||
time_until_next_play = self.date_interval_to_seconds(chain_start - datetime.utcnow())
|
||||
self.logger.debug("Blocking %s seconds until show start", time_until_next_play)
|
||||
else:
|
||||
self.logger.debug("Blocking indefinitely since no show scheduled")
|
||||
time_until_next_play = None
|
||||
except Empty, e:
|
||||
#We only get here when a new chain of tracks are ready to be played.
|
||||
self.push_to_liquidsoap(next_media_item_chain)
|
||||
|
||||
next_media_item_chain = self.get_next_schedule_chain(chains, datetime.utcnow())
|
||||
if next_media_item_chain is not None:
|
||||
try:
|
||||
chains.remove(next_media_item_chain)
|
||||
except ValueError, e:
|
||||
self.logger.error(str(e))
|
||||
chain_start = datetime.strptime(next_media_item_chain[0]['start'], "%Y-%m-%d-%H-%M-%S")
|
||||
time_until_next_play = self.date_interval_to_seconds(chain_start - datetime.utcnow())
|
||||
self.logger.debug("Blocking %s seconds until show start", time_until_next_play)
|
||||
else:
|
||||
self.logger.debug("Blocking indefinitely since no show scheduled next")
|
||||
time_until_next_play = None
|
||||
media_schedule = self.queue.get(block=True)
|
||||
except Exception, e:
|
||||
self.logger.error(str(e))
|
||||
raise
|
||||
else:
|
||||
self.logger.debug(media_schedule)
|
||||
#separate media_schedule list into currently_playing and
|
||||
#scheduled_for_future lists
|
||||
currently_playing, scheduled_for_future = \
|
||||
self.separate_present_future(media_schedule)
|
||||
|
||||
self.pypo_liquidsoap.verify_correct_present_media(currently_playing)
|
||||
self.future_scheduled_queue.put(scheduled_for_future)
|
||||
|
||||
if loops % heartbeat_period == 0:
|
||||
self.logger.info("heartbeat")
|
||||
loops = 0
|
||||
loops += 1
|
||||
|
||||
|
||||
def separate_present_future(self, media_schedule):
|
||||
tnow = datetime.utcnow()
|
||||
|
||||
present = []
|
||||
future = {}
|
||||
|
||||
sorted_keys = sorted(media_schedule.keys())
|
||||
for mkey in sorted_keys:
|
||||
media_item = media_schedule[mkey]
|
||||
|
||||
diff_td = tnow - media_item['start']
|
||||
diff_sec = self.date_interval_to_seconds(diff_td)
|
||||
|
||||
if diff_sec >= 0:
|
||||
present.append(media_item)
|
||||
else:
|
||||
future[media_item['start']] = media_item
|
||||
|
||||
return present, future
|
||||
|
||||
def get_current_stream_id_from_liquidsoap(self):
|
||||
response = "-1"
|
||||
try:
|
||||
|
@ -159,289 +141,24 @@ class PypoPush(Thread):
|
|||
|
||||
return response
|
||||
|
||||
def get_queue_items_from_liquidsoap(self):
|
||||
"""
|
||||
This function connects to Liquidsoap to find what media items are in its queue.
|
||||
"""
|
||||
try:
|
||||
self.telnet_lock.acquire()
|
||||
tn = telnetlib.Telnet(LS_HOST, LS_PORT)
|
||||
|
||||
msg = 'queue.queue\n'
|
||||
tn.write(msg)
|
||||
response = tn.read_until("\r\n").strip(" \r\n")
|
||||
tn.write('exit\n')
|
||||
tn.read_all()
|
||||
except Exception, e:
|
||||
self.logger.error("Error connecting to Liquidsoap: %s", e)
|
||||
response = []
|
||||
finally:
|
||||
self.telnet_lock.release()
|
||||
|
||||
liquidsoap_queue_approx = []
|
||||
|
||||
if len(response) > 0:
|
||||
items_in_queue = response.split(" ")
|
||||
|
||||
self.logger.debug("items_in_queue: %s", items_in_queue)
|
||||
|
||||
for item in items_in_queue:
|
||||
if item in self.pushed_objects:
|
||||
liquidsoap_queue_approx.append(self.pushed_objects[item])
|
||||
else:
|
||||
"""
|
||||
We should only reach here if Pypo crashed and restarted (because self.pushed_objects was reset). In this case
|
||||
let's clear the entire Liquidsoap queue.
|
||||
"""
|
||||
self.logger.error("ID exists in liquidsoap queue that does not exist in our pushed_objects queue: " + item)
|
||||
self.clear_liquidsoap_queue()
|
||||
liquidsoap_queue_approx = []
|
||||
break
|
||||
|
||||
return liquidsoap_queue_approx
|
||||
|
||||
def is_correct_current_item(self, media_item, liquidsoap_queue_approx, liquidsoap_stream_id):
|
||||
correct = False
|
||||
if media_item is None:
|
||||
correct = (len(liquidsoap_queue_approx) == 0 and liquidsoap_stream_id == "-1")
|
||||
else:
|
||||
if is_file(media_item):
|
||||
if len(liquidsoap_queue_approx) == 0:
|
||||
correct = False
|
||||
else:
|
||||
correct = liquidsoap_queue_approx[0]['start'] == media_item['start'] and \
|
||||
liquidsoap_queue_approx[0]['row_id'] == media_item['row_id'] and \
|
||||
liquidsoap_queue_approx[0]['end'] == media_item['end'] and \
|
||||
liquidsoap_queue_approx[0]['replay_gain'] == media_item['replay_gain']
|
||||
elif is_stream(media_item):
|
||||
correct = liquidsoap_stream_id == str(media_item['row_id'])
|
||||
|
||||
self.logger.debug("Is current item correct?: %s", str(correct))
|
||||
return correct
|
||||
|
||||
|
||||
#clear all webstreams and files from Liquidsoap
|
||||
def clear_all_liquidsoap_items(self):
|
||||
self.remove_from_liquidsoap_queue(0, None)
|
||||
self.stop_web_stream_all()
|
||||
|
||||
def handle_new_schedule(self, media_schedule, liquidsoap_queue_approx, liquidsoap_stream_id, current_event_chain):
|
||||
"""
|
||||
This function's purpose is to gracefully handle situations where
|
||||
Liquidsoap already has a track in its queue, but the schedule
|
||||
has changed. If the schedule has changed, this function's job is to
|
||||
call other functions that will connect to Liquidsoap and alter its
|
||||
queue.
|
||||
"""
|
||||
file_chain = filter(lambda item: (item["type"] == "file"), current_event_chain)
|
||||
stream_chain = filter(lambda item: (item["type"] == "stream_output_start"), current_event_chain)
|
||||
|
||||
self.logger.debug(current_event_chain)
|
||||
|
||||
#Take care of the case where the current playing may be incorrect
|
||||
if len(current_event_chain) > 0:
|
||||
|
||||
current_item = current_event_chain[0]
|
||||
if not self.is_correct_current_item(current_item, liquidsoap_queue_approx, liquidsoap_stream_id):
|
||||
self.clear_all_liquidsoap_items()
|
||||
if is_stream(current_item):
|
||||
if current_item['row_id'] != self.current_prebuffering_stream_id:
|
||||
#this is called if the stream wasn't scheduled sufficiently ahead of time
|
||||
#so that the prebuffering stage could take effect. Let's do the prebuffering now.
|
||||
self.start_web_stream_buffer(current_item)
|
||||
self.start_web_stream(current_item)
|
||||
if is_file(current_item):
|
||||
file_chain = self.modify_first_link_cue_point(file_chain)
|
||||
self.push_to_liquidsoap(file_chain)
|
||||
#we've changed the queue, so let's refetch it
|
||||
liquidsoap_queue_approx = self.get_queue_items_from_liquidsoap()
|
||||
|
||||
elif not self.is_correct_current_item(None, liquidsoap_queue_approx, liquidsoap_stream_id):
|
||||
#Liquidsoap is playing something even though it shouldn't be
|
||||
self.clear_all_liquidsoap_items()
|
||||
|
||||
|
||||
#If the current item scheduled is a file, then files come in chains, and
|
||||
#therefore we need to make sure the entire chain is correct.
|
||||
if len(current_event_chain) > 0 and is_file(current_event_chain[0]):
|
||||
problem_at_iteration = self.find_removed_items(media_schedule, liquidsoap_queue_approx)
|
||||
|
||||
if problem_at_iteration is not None:
|
||||
#Items that are in Liquidsoap's queue aren't scheduled anymore. We need to connect
|
||||
#and remove these items.
|
||||
self.logger.debug("Change in link %s of current chain", problem_at_iteration)
|
||||
self.remove_from_liquidsoap_queue(problem_at_iteration, liquidsoap_queue_approx[problem_at_iteration:])
|
||||
|
||||
if problem_at_iteration is None and len(file_chain) > len(liquidsoap_queue_approx):
|
||||
self.logger.debug("New schedule has longer current chain.")
|
||||
problem_at_iteration = len(liquidsoap_queue_approx)
|
||||
|
||||
if problem_at_iteration is not None:
|
||||
self.logger.debug("Change in chain at link %s", problem_at_iteration)
|
||||
|
||||
chain_to_push = file_chain[problem_at_iteration:]
|
||||
if len(chain_to_push) > 0:
|
||||
chain_to_push = self.modify_first_link_cue_point(chain_to_push)
|
||||
self.push_to_liquidsoap(chain_to_push)
|
||||
|
||||
|
||||
"""
|
||||
Compare whats in the liquidsoap_queue to the new schedule we just
|
||||
received in media_schedule. This function only iterates over liquidsoap_queue_approx
|
||||
and finds if every item in that list is still scheduled in "media_schedule". It doesn't
|
||||
take care of the case where media_schedule has more items than liquidsoap_queue_approx
|
||||
"""
|
||||
def find_removed_items(self, media_schedule, liquidsoap_queue_approx):
|
||||
#iterate through the items we got from the liquidsoap queue and
|
||||
#see if they are the same as the newly received schedule
|
||||
iteration = 0
|
||||
problem_at_iteration = None
|
||||
for queue_item in liquidsoap_queue_approx:
|
||||
if queue_item['start'] in media_schedule.keys():
|
||||
media_item = media_schedule[queue_item['start']]
|
||||
if queue_item['row_id'] == media_item['row_id']:
|
||||
if queue_item['end'] == media_item['end']:
|
||||
#Everything OK for this iteration.
|
||||
pass
|
||||
else:
|
||||
problem_at_iteration = iteration
|
||||
break
|
||||
else:
|
||||
#A different item has been scheduled at the same time! Need to remove
|
||||
#all tracks from the Liquidsoap queue starting at this point, and re-add
|
||||
#them.
|
||||
problem_at_iteration = iteration
|
||||
break
|
||||
else:
|
||||
#There are no more items scheduled for this time! The user has shortened
|
||||
#the playlist, so we simply need to remove tracks from the queue.
|
||||
problem_at_iteration = iteration
|
||||
break
|
||||
iteration += 1
|
||||
return problem_at_iteration
|
||||
|
||||
|
||||
|
||||
def get_all_chains(self, media_schedule):
|
||||
chains = []
|
||||
|
||||
current_chain = []
|
||||
|
||||
sorted_keys = sorted(media_schedule.keys())
|
||||
|
||||
for mkey in sorted_keys:
|
||||
media_item = media_schedule[mkey]
|
||||
if media_item['independent_event']:
|
||||
if len(current_chain) > 0:
|
||||
chains.append(current_chain)
|
||||
|
||||
chains.append([media_item])
|
||||
current_chain = []
|
||||
elif len(current_chain) == 0:
|
||||
current_chain.append(media_item)
|
||||
elif media_item['start'] == current_chain[-1]['end']:
|
||||
current_chain.append(media_item)
|
||||
else:
|
||||
#current item is not a continuation of the chain.
|
||||
#Start a new one instead
|
||||
chains.append(current_chain)
|
||||
current_chain = [media_item]
|
||||
|
||||
if len(current_chain) > 0:
|
||||
chains.append(current_chain)
|
||||
|
||||
return chains
|
||||
|
||||
def modify_cue_point(self, link):
|
||||
tnow = datetime.utcnow()
|
||||
|
||||
link_start = datetime.strptime(link['start'], "%Y-%m-%d-%H-%M-%S")
|
||||
|
||||
diff_td = tnow - link_start
|
||||
diff_sec = self.date_interval_to_seconds(diff_td)
|
||||
|
||||
if diff_sec > 0:
|
||||
self.logger.debug("media item was supposed to start %s ago. Preparing to start..", diff_sec)
|
||||
original_cue_in_td = timedelta(seconds=float(link['cue_in']))
|
||||
link['cue_in'] = self.date_interval_to_seconds(original_cue_in_td) + diff_sec
|
||||
|
||||
def modify_first_link_cue_point(self, chain):
|
||||
if not len(chain):
|
||||
return []
|
||||
|
||||
first_link = chain[0]
|
||||
|
||||
self.modify_cue_point(first_link)
|
||||
|
||||
#ATM, we should never have an exception here. However in the future, it
|
||||
#would be nice to allow cue_out to be None which would then allow us to
|
||||
#fallback to the length of the track as the end point.
|
||||
try:
|
||||
end = first_link['cue_out']
|
||||
except TypeError:
|
||||
#cue_out is type None
|
||||
end = first_link['length']
|
||||
|
||||
if float(first_link['cue_in']) >= float(end):
|
||||
chain = chain [1:]
|
||||
|
||||
return chain
|
||||
|
||||
"""
|
||||
Returns two chains, original chain and current_chain. current_chain is a subset of
|
||||
original_chain but can also be equal to original chain.
|
||||
|
||||
We return original chain because the user of this function may want to clean
|
||||
up the input 'chains' list
|
||||
|
||||
chain, original = get_current_chain(chains)
|
||||
|
||||
and
|
||||
chains.remove(chain) can throw a ValueError exception
|
||||
|
||||
but
|
||||
chains.remove(original) won't
|
||||
"""
|
||||
def get_current_chain(self, chains, tnow):
|
||||
current_chain = []
|
||||
original_chain = None
|
||||
|
||||
for chain in chains:
|
||||
iteration = 0
|
||||
for link in chain:
|
||||
link_start = datetime.strptime(link['start'], "%Y-%m-%d-%H-%M-%S")
|
||||
link_end = datetime.strptime(link['end'], "%Y-%m-%d-%H-%M-%S")
|
||||
|
||||
self.logger.debug("tnow %s, chain_start %s", tnow, link_start)
|
||||
if link_start <= tnow and tnow < link_end:
|
||||
current_chain = chain[iteration:]
|
||||
original_chain = chain
|
||||
break
|
||||
iteration += 1
|
||||
|
||||
return current_chain, original_chain
|
||||
|
||||
"""
|
||||
The purpose of this function is to take a look at the last received schedule from
|
||||
pypo-fetch and return the next chain of media_items. A chain is defined as a sequence
|
||||
of media_items where the end time of media_item 'n' is the start time of media_item
|
||||
'n+1'
|
||||
"""
|
||||
def get_next_schedule_chain(self, chains, tnow):
|
||||
#all media_items are now divided into chains. Let's find the one that
|
||||
#starts closest in the future.
|
||||
closest_start = None
|
||||
closest_chain = None
|
||||
for chain in chains:
|
||||
chain_start = datetime.strptime(chain[0]['start'], "%Y-%m-%d-%H-%M-%S")
|
||||
chain_end = datetime.strptime(chain[-1]['end'], "%Y-%m-%d-%H-%M-%S")
|
||||
self.logger.debug("tnow %s, chain_start %s", tnow, chain_start)
|
||||
if (closest_start == None or chain_start < closest_start) and (chain_start > tnow or (chain_start < tnow and chain_end > tnow)):
|
||||
closest_start = chain_start
|
||||
closest_chain = chain
|
||||
|
||||
return closest_chain
|
||||
#def is_correct_current_item(self, media_item, liquidsoap_queue_approx, liquidsoap_stream_id):
|
||||
#correct = False
|
||||
#if media_item is None:
|
||||
#correct = (len(liquidsoap_queue_approx) == 0 and liquidsoap_stream_id == "-1")
|
||||
#else:
|
||||
#if is_file(media_item):
|
||||
#if len(liquidsoap_queue_approx) == 0:
|
||||
#correct = False
|
||||
#else:
|
||||
#correct = liquidsoap_queue_approx[0]['start'] == media_item['start'] and \
|
||||
#liquidsoap_queue_approx[0]['row_id'] == media_item['row_id'] and \
|
||||
#liquidsoap_queue_approx[0]['end'] == media_item['end'] and \
|
||||
#liquidsoap_queue_approx[0]['replay_gain'] == media_item['replay_gain']
|
||||
#elif is_stream(media_item):
|
||||
#correct = liquidsoap_stream_id == str(media_item['row_id'])
|
||||
|
||||
#self.logger.debug("Is current item correct?: %s", str(correct))
|
||||
#return correct
|
||||
|
||||
def date_interval_to_seconds(self, interval):
|
||||
"""
|
||||
|
@ -450,101 +167,9 @@ class PypoPush(Thread):
|
|||
"""
|
||||
seconds = (interval.microseconds + \
|
||||
(interval.seconds + interval.days * 24 * 3600) * 10 ** 6) / float(10 ** 6)
|
||||
if seconds < 0: seconds = 0
|
||||
|
||||
return seconds
|
||||
|
||||
def push_to_liquidsoap(self, event_chain):
|
||||
|
||||
try:
|
||||
for media_item in event_chain:
|
||||
if media_item['type'] == "file":
|
||||
|
||||
"""
|
||||
Wait maximum 5 seconds (50 iterations) for file to become ready, otherwise
|
||||
give up on it.
|
||||
"""
|
||||
iter_num = 0
|
||||
while not media_item['file_ready'] and iter_num < 50:
|
||||
time.sleep(0.1)
|
||||
iter_num += 1
|
||||
|
||||
if media_item['file_ready']:
|
||||
self.telnet_to_liquidsoap(media_item)
|
||||
else:
|
||||
self.logger.warn("File %s did not become ready in less than 5 seconds. Skipping...", media_item['dst'])
|
||||
elif media_item['type'] == "event":
|
||||
if media_item['event_type'] == "kick_out":
|
||||
PypoFetch.disconnect_source(self.logger, self.telnet_lock, "live_dj")
|
||||
elif media_item['event_type'] == "switch_off":
|
||||
PypoFetch.switch_source(self.logger, self.telnet_lock, "live_dj", "off")
|
||||
elif media_item['type'] == 'stream_buffer_start':
|
||||
self.start_web_stream_buffer(media_item)
|
||||
elif media_item['type'] == "stream_output_start":
|
||||
if media_item['row_id'] != self.current_prebuffering_stream_id:
|
||||
#this is called if the stream wasn't scheduled sufficiently ahead of time
|
||||
#so that the prebuffering stage could take effect. Let's do the prebuffering now.
|
||||
self.start_web_stream_buffer(media_item)
|
||||
self.start_web_stream(media_item)
|
||||
elif media_item['type'] == "stream_buffer_end":
|
||||
self.stop_web_stream_buffer(media_item)
|
||||
elif media_item['type'] == "stream_output_end":
|
||||
self.stop_web_stream_output(media_item)
|
||||
except Exception, e:
|
||||
self.logger.error('Pypo Push Exception: %s', e)
|
||||
|
||||
|
||||
def start_web_stream_buffer(self, media_item):
|
||||
try:
|
||||
self.telnet_lock.acquire()
|
||||
tn = telnetlib.Telnet(LS_HOST, LS_PORT)
|
||||
|
||||
msg = 'dynamic_source.id %s\n' % media_item['row_id']
|
||||
self.logger.debug(msg)
|
||||
tn.write(msg)
|
||||
|
||||
#msg = 'dynamic_source.read_start %s\n' % media_item['uri'].encode('latin-1')
|
||||
msg = 'http.restart %s\n' % media_item['uri'].encode('latin-1')
|
||||
self.logger.debug(msg)
|
||||
tn.write(msg)
|
||||
|
||||
show_name = media_item['show_name']
|
||||
msg = 'vars.show_name %s\n' % show_name.encode('utf-8')
|
||||
tn.write(msg)
|
||||
self.logger.debug(msg)
|
||||
|
||||
tn.write("exit\n")
|
||||
self.logger.debug(tn.read_all())
|
||||
|
||||
self.current_prebuffering_stream_id = media_item['row_id']
|
||||
except Exception, e:
|
||||
self.logger.error(str(e))
|
||||
finally:
|
||||
self.telnet_lock.release()
|
||||
|
||||
|
||||
def start_web_stream(self, media_item):
|
||||
try:
|
||||
self.telnet_lock.acquire()
|
||||
tn = telnetlib.Telnet(LS_HOST, LS_PORT)
|
||||
|
||||
#TODO: DO we need this?
|
||||
msg = 'streams.scheduled_play_start\n'
|
||||
tn.write(msg)
|
||||
|
||||
msg = 'dynamic_source.output_start\n'
|
||||
self.logger.debug(msg)
|
||||
tn.write(msg)
|
||||
|
||||
tn.write("exit\n")
|
||||
self.logger.debug(tn.read_all())
|
||||
|
||||
self.current_prebuffering_stream_id = None
|
||||
except Exception, e:
|
||||
self.logger.error(str(e))
|
||||
finally:
|
||||
self.telnet_lock.release()
|
||||
|
||||
def stop_web_stream_all(self):
|
||||
try:
|
||||
self.telnet_lock.acquire()
|
||||
|
@ -571,173 +196,9 @@ class PypoPush(Thread):
|
|||
finally:
|
||||
self.telnet_lock.release()
|
||||
|
||||
def stop_web_stream_buffer(self, media_item):
|
||||
try:
|
||||
self.telnet_lock.acquire()
|
||||
tn = telnetlib.Telnet(LS_HOST, LS_PORT)
|
||||
#dynamic_source.stop http://87.230.101.24:80/top100station.mp3
|
||||
|
||||
#msg = 'dynamic_source.read_stop %s\n' % media_item['row_id']
|
||||
msg = 'http.stop\n'
|
||||
self.logger.debug(msg)
|
||||
tn.write(msg)
|
||||
|
||||
msg = 'dynamic_source.id -1\n'
|
||||
self.logger.debug(msg)
|
||||
tn.write(msg)
|
||||
|
||||
tn.write("exit\n")
|
||||
self.logger.debug(tn.read_all())
|
||||
|
||||
except Exception, e:
|
||||
self.logger.error(str(e))
|
||||
finally:
|
||||
self.telnet_lock.release()
|
||||
|
||||
def stop_web_stream_output(self, media_item):
|
||||
try:
|
||||
self.telnet_lock.acquire()
|
||||
tn = telnetlib.Telnet(LS_HOST, LS_PORT)
|
||||
#dynamic_source.stop http://87.230.101.24:80/top100station.mp3
|
||||
|
||||
msg = 'dynamic_source.output_stop\n'
|
||||
self.logger.debug(msg)
|
||||
tn.write(msg)
|
||||
|
||||
tn.write("exit\n")
|
||||
self.logger.debug(tn.read_all())
|
||||
|
||||
except Exception, e:
|
||||
self.logger.error(str(e))
|
||||
finally:
|
||||
self.telnet_lock.release()
|
||||
|
||||
def clear_liquidsoap_queue(self):
|
||||
self.logger.debug("Clearing Liquidsoap queue")
|
||||
try:
|
||||
self.telnet_lock.acquire()
|
||||
tn = telnetlib.Telnet(LS_HOST, LS_PORT)
|
||||
msg = "source.skip\n"
|
||||
tn.write(msg)
|
||||
tn.write("exit\n")
|
||||
tn.read_all()
|
||||
except Exception, e:
|
||||
self.logger.error(str(e))
|
||||
finally:
|
||||
self.telnet_lock.release()
|
||||
|
||||
def remove_from_liquidsoap_queue(self, problem_at_iteration, liquidsoap_queue_approx):
|
||||
|
||||
try:
|
||||
self.telnet_lock.acquire()
|
||||
tn = telnetlib.Telnet(LS_HOST, LS_PORT)
|
||||
|
||||
if problem_at_iteration == 0:
|
||||
msg = "source.skip\n"
|
||||
self.logger.debug(msg)
|
||||
tn.write(msg)
|
||||
else:
|
||||
# Remove things in reverse order.
|
||||
queue_copy = liquidsoap_queue_approx[::-1]
|
||||
|
||||
for queue_item in queue_copy:
|
||||
msg = "queue.remove %s\n" % queue_item['queue_id']
|
||||
self.logger.debug(msg)
|
||||
tn.write(msg)
|
||||
response = tn.read_until("\r\n").strip("\r\n")
|
||||
|
||||
if "No such request in my queue" in response:
|
||||
"""
|
||||
Cannot remove because Liquidsoap started playing the item. Need
|
||||
to use source.skip instead
|
||||
"""
|
||||
msg = "source.skip\n"
|
||||
self.logger.debug(msg)
|
||||
tn.write(msg)
|
||||
|
||||
msg = "queue.queue\n"
|
||||
self.logger.debug(msg)
|
||||
tn.write(msg)
|
||||
|
||||
tn.write("exit\n")
|
||||
self.logger.debug(tn.read_all())
|
||||
except Exception, e:
|
||||
self.logger.error(str(e))
|
||||
finally:
|
||||
self.telnet_lock.release()
|
||||
|
||||
def sleep_until_start(self, media_item):
|
||||
"""
|
||||
The purpose of this function is to look at the difference between
|
||||
"now" and when the media_item starts, and sleep for that period of time.
|
||||
After waking from sleep, this function returns.
|
||||
"""
|
||||
|
||||
mi_start = media_item['start'][0:19]
|
||||
|
||||
#strptime returns struct_time in local time
|
||||
epoch_start = calendar.timegm(time.strptime(mi_start, '%Y-%m-%d-%H-%M-%S'))
|
||||
|
||||
#Return the time as a floating point number expressed in seconds since the epoch, in UTC.
|
||||
epoch_now = time.time()
|
||||
|
||||
self.logger.debug("Epoch start: %s" % epoch_start)
|
||||
self.logger.debug("Epoch now: %s" % epoch_now)
|
||||
|
||||
sleep_time = epoch_start - epoch_now
|
||||
|
||||
if sleep_time < 0:
|
||||
sleep_time = 0
|
||||
|
||||
self.logger.debug('sleeping for %s s' % (sleep_time))
|
||||
time.sleep(sleep_time)
|
||||
|
||||
def telnet_to_liquidsoap(self, media_item):
|
||||
"""
|
||||
telnets to liquidsoap and pushes the media_item to its queue. Push the
|
||||
show name of every media_item as well, just to keep Liquidsoap up-to-date
|
||||
about which show is playing.
|
||||
"""
|
||||
try:
|
||||
self.telnet_lock.acquire()
|
||||
tn = telnetlib.Telnet(LS_HOST, LS_PORT)
|
||||
|
||||
#tn.write(("vars.pypo_data %s\n"%liquidsoap_data["schedule_id"]).encode('utf-8'))
|
||||
|
||||
annotation = self.create_liquidsoap_annotation(media_item)
|
||||
msg = 'queue.push %s\n' % annotation.encode('utf-8')
|
||||
self.logger.debug(msg)
|
||||
tn.write(msg)
|
||||
queue_id = tn.read_until("\r\n").strip("\r\n")
|
||||
|
||||
#remember the media_item's queue id which we may use
|
||||
#later if we need to remove it from the queue.
|
||||
media_item['queue_id'] = queue_id
|
||||
|
||||
#add media_item to the end of our queue
|
||||
self.pushed_objects[queue_id] = media_item
|
||||
|
||||
show_name = media_item['show_name']
|
||||
msg = 'vars.show_name %s\n' % show_name.encode('utf-8')
|
||||
tn.write(msg)
|
||||
self.logger.debug(msg)
|
||||
|
||||
tn.write("exit\n")
|
||||
self.logger.debug(tn.read_all())
|
||||
except Exception, e:
|
||||
self.logger.error(str(e))
|
||||
finally:
|
||||
self.telnet_lock.release()
|
||||
|
||||
def create_liquidsoap_annotation(self, media):
|
||||
# We need liq_start_next value in the annotate. That is the value that controls overlap duration of crossfade.
|
||||
return 'annotate:media_id="%s",liq_start_next="0",liq_fade_in="%s",liq_fade_out="%s",liq_cue_in="%s",liq_cue_out="%s",schedule_table_id="%s",replay_gain="%s dB":%s' \
|
||||
% (media['id'], float(media['fade_in']) / 1000, float(media['fade_out']) / 1000, float(media['cue_in']), float(media['cue_out']), media['row_id'], media['replay_gain'], media['dst'])
|
||||
|
||||
def run(self):
|
||||
try: self.main()
|
||||
except Exception, e:
|
||||
import traceback
|
||||
top = traceback.format_exc()
|
||||
self.logger.error('Pypo Push Exception: %s', top)
|
||||
|
||||
|
|
|
@ -303,8 +303,6 @@ class Recorder(Thread):
|
|||
heartbeat_period = math.floor(30 / PUSH_INTERVAL)
|
||||
|
||||
while True:
|
||||
if self.loops % heartbeat_period == 0:
|
||||
self.logger.info("heartbeat")
|
||||
if self.loops * PUSH_INTERVAL > 3600:
|
||||
self.loops = 0
|
||||
"""
|
||||
|
|
|
@ -0,0 +1,208 @@
|
|||
import telnetlib
|
||||
|
||||
def create_liquidsoap_annotation(media):
|
||||
# We need liq_start_next value in the annotate. That is the value that controls overlap duration of crossfade.
|
||||
return 'annotate:media_id="%s",liq_start_next="0",liq_fade_in="%s",liq_fade_out="%s",liq_cue_in="%s",liq_cue_out="%s",schedule_table_id="%s",replay_gain="%s dB":%s' \
|
||||
% (media['id'], float(media['fade_in']) / 1000, float(media['fade_out']) / 1000, float(media['cue_in']), float(media['cue_out']), media['row_id'], media['replay_gain'], media['dst'])
|
||||
|
||||
class TelnetLiquidsoap:
|
||||
|
||||
def __init__(self, telnet_lock, logger, ls_host, ls_port):
|
||||
self.telnet_lock = telnet_lock
|
||||
self.ls_host = ls_host
|
||||
self.ls_port = ls_port
|
||||
self.logger = logger
|
||||
self.current_prebuffering_stream_id = None
|
||||
|
||||
def __connect(self):
|
||||
return telnetlib.Telnet(self.ls_host, self.ls_port)
|
||||
|
||||
def __is_empty(self, tn, queue_id):
|
||||
return True
|
||||
|
||||
def queue_remove(self, queue_id):
|
||||
try:
|
||||
self.telnet_lock.acquire()
|
||||
tn = self.__connect()
|
||||
|
||||
msg = 'queues.%s_skip\n' % queue_id
|
||||
self.logger.debug(msg)
|
||||
tn.write(msg)
|
||||
|
||||
tn.write("exit\n")
|
||||
self.logger.debug(tn.read_all())
|
||||
except Exception:
|
||||
raise
|
||||
finally:
|
||||
self.telnet_lock.release()
|
||||
|
||||
|
||||
def queue_push(self, queue_id, media_item):
|
||||
try:
|
||||
self.telnet_lock.acquire()
|
||||
tn = self.__connect()
|
||||
|
||||
if not self.__is_empty(tn, queue_id):
|
||||
raise QueueNotEmptyException()
|
||||
|
||||
annotation = create_liquidsoap_annotation(media_item)
|
||||
msg = '%s.push %s\n' % (queue_id, annotation.encode('utf-8'))
|
||||
self.logger.debug(msg)
|
||||
tn.write(msg)
|
||||
|
||||
show_name = media_item['show_name']
|
||||
msg = 'vars.show_name %s\n' % show_name.encode('utf-8')
|
||||
tn.write(msg)
|
||||
self.logger.debug(msg)
|
||||
|
||||
tn.write("exit\n")
|
||||
self.logger.debug(tn.read_all())
|
||||
except Exception:
|
||||
raise
|
||||
finally:
|
||||
self.telnet_lock.release()
|
||||
|
||||
|
||||
def stop_web_stream_buffer(self):
|
||||
try:
|
||||
self.telnet_lock.acquire()
|
||||
tn = telnetlib.Telnet(self.ls_host, self.ls_port)
|
||||
#dynamic_source.stop http://87.230.101.24:80/top100station.mp3
|
||||
|
||||
msg = 'http.stop\n'
|
||||
self.logger.debug(msg)
|
||||
tn.write(msg)
|
||||
|
||||
msg = 'dynamic_source.id -1\n'
|
||||
self.logger.debug(msg)
|
||||
tn.write(msg)
|
||||
|
||||
tn.write("exit\n")
|
||||
self.logger.debug(tn.read_all())
|
||||
|
||||
except Exception, e:
|
||||
self.logger.error(str(e))
|
||||
finally:
|
||||
self.telnet_lock.release()
|
||||
|
||||
def stop_web_stream_output(self):
|
||||
try:
|
||||
self.telnet_lock.acquire()
|
||||
tn = telnetlib.Telnet(self.ls_host, self.ls_port)
|
||||
#dynamic_source.stop http://87.230.101.24:80/top100station.mp3
|
||||
|
||||
msg = 'dynamic_source.output_stop\n'
|
||||
self.logger.debug(msg)
|
||||
tn.write(msg)
|
||||
|
||||
tn.write("exit\n")
|
||||
self.logger.debug(tn.read_all())
|
||||
|
||||
except Exception, e:
|
||||
self.logger.error(str(e))
|
||||
finally:
|
||||
self.telnet_lock.release()
|
||||
|
||||
def start_web_stream(self, media_item):
|
||||
try:
|
||||
self.telnet_lock.acquire()
|
||||
tn = telnetlib.Telnet(self.ls_host, self.ls_port)
|
||||
|
||||
#TODO: DO we need this?
|
||||
msg = 'streams.scheduled_play_start\n'
|
||||
tn.write(msg)
|
||||
|
||||
msg = 'dynamic_source.output_start\n'
|
||||
self.logger.debug(msg)
|
||||
tn.write(msg)
|
||||
|
||||
tn.write("exit\n")
|
||||
self.logger.debug(tn.read_all())
|
||||
|
||||
self.current_prebuffering_stream_id = None
|
||||
except Exception, e:
|
||||
self.logger.error(str(e))
|
||||
finally:
|
||||
self.telnet_lock.release()
|
||||
|
||||
def start_web_stream_buffer(self, media_item):
|
||||
try:
|
||||
self.telnet_lock.acquire()
|
||||
tn = telnetlib.Telnet(self.ls_host, self.ls_port)
|
||||
|
||||
msg = 'dynamic_source.id %s\n' % media_item['row_id']
|
||||
self.logger.debug(msg)
|
||||
tn.write(msg)
|
||||
|
||||
msg = 'http.restart %s\n' % media_item['uri'].encode('latin-1')
|
||||
self.logger.debug(msg)
|
||||
tn.write(msg)
|
||||
|
||||
tn.write("exit\n")
|
||||
self.logger.debug(tn.read_all())
|
||||
|
||||
self.current_prebuffering_stream_id = media_item['row_id']
|
||||
except Exception, e:
|
||||
self.logger.error(str(e))
|
||||
finally:
|
||||
self.telnet_lock.release()
|
||||
|
||||
def get_current_stream_id(self):
|
||||
try:
|
||||
self.telnet_lock.acquire()
|
||||
tn = telnetlib.Telnet(self.ls_host, self.ls_port)
|
||||
|
||||
msg = 'dynamic_source.get_id\n'
|
||||
self.logger.debug(msg)
|
||||
tn.write(msg)
|
||||
|
||||
tn.write("exit\n")
|
||||
stream_id = tn.read_all().splitlines()[0]
|
||||
self.logger.debug("stream_id: %s" % stream_id)
|
||||
|
||||
return stream_id
|
||||
except Exception, e:
|
||||
self.logger.error(str(e))
|
||||
finally:
|
||||
self.telnet_lock.release()
|
||||
|
||||
class DummyTelnetLiquidsoap:
|
||||
|
||||
def __init__(self, telnet_lock, logger):
|
||||
self.telnet_lock = telnet_lock
|
||||
self.liquidsoap_mock_queues = {}
|
||||
self.logger = logger
|
||||
|
||||
for i in range(4):
|
||||
self.liquidsoap_mock_queues["s"+str(i)] = []
|
||||
|
||||
def queue_push(self, queue_id, media_item):
|
||||
try:
|
||||
self.telnet_lock.acquire()
|
||||
|
||||
self.logger.info("Pushing %s to queue %s" % (media_item, queue_id))
|
||||
from datetime import datetime
|
||||
print "Time now: %s" % datetime.utcnow()
|
||||
|
||||
annotation = create_liquidsoap_annotation(media_item)
|
||||
self.liquidsoap_mock_queues[queue_id].append(annotation)
|
||||
except Exception:
|
||||
raise
|
||||
finally:
|
||||
self.telnet_lock.release()
|
||||
|
||||
def queue_remove(self, queue_id):
|
||||
try:
|
||||
self.telnet_lock.acquire()
|
||||
|
||||
self.logger.info("Purging queue %s" % queue_id)
|
||||
from datetime import datetime
|
||||
print "Time now: %s" % datetime.utcnow()
|
||||
|
||||
except Exception:
|
||||
raise
|
||||
finally:
|
||||
self.telnet_lock.release()
|
||||
|
||||
class QueueNotEmptyException(Exception):
|
||||
pass
|
|
@ -0,0 +1,98 @@
|
|||
from pypoliqqueue import PypoLiqQueue
|
||||
from telnetliquidsoap import DummyTelnetLiquidsoap, TelnetLiquidsoap
|
||||
|
||||
|
||||
from Queue import Queue
|
||||
from threading import Lock
|
||||
|
||||
import sys
|
||||
import signal
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
|
||||
def keyboardInterruptHandler(signum, frame):
|
||||
logger = logging.getLogger()
|
||||
logger.info('\nKeyboard Interrupt\n')
|
||||
sys.exit(0)
|
||||
signal.signal(signal.SIGINT, keyboardInterruptHandler)
|
||||
|
||||
# configure logging
|
||||
format = '%(levelname)s - %(pathname)s - %(lineno)s - %(asctime)s - %(message)s'
|
||||
logging.basicConfig(level=logging.DEBUG, format=format)
|
||||
logging.captureWarnings(True)
|
||||
|
||||
telnet_lock = Lock()
|
||||
pypoPush_q = Queue()
|
||||
|
||||
|
||||
pypoLiq_q = Queue()
|
||||
liq_queue_tracker = {
|
||||
"s0": None,
|
||||
"s1": None,
|
||||
"s2": None,
|
||||
"s3": None,
|
||||
}
|
||||
|
||||
#dummy_telnet_liquidsoap = DummyTelnetLiquidsoap(telnet_lock, logging)
|
||||
dummy_telnet_liquidsoap = TelnetLiquidsoap(telnet_lock, logging, \
|
||||
"localhost", \
|
||||
1234)
|
||||
|
||||
plq = PypoLiqQueue(pypoLiq_q, telnet_lock, logging, liq_queue_tracker, \
|
||||
dummy_telnet_liquidsoap)
|
||||
plq.daemon = True
|
||||
plq.start()
|
||||
|
||||
|
||||
print "Time now: %s" % datetime.utcnow()
|
||||
|
||||
media_schedule = {}
|
||||
|
||||
start_dt = datetime.utcnow() + timedelta(seconds=1)
|
||||
end_dt = datetime.utcnow() + timedelta(seconds=6)
|
||||
|
||||
media_schedule[start_dt] = {"id": 5, \
|
||||
"type":"file", \
|
||||
"row_id":9, \
|
||||
"uri":"", \
|
||||
"dst":"/home/martin/Music/ipod/Hot Chocolate - You Sexy Thing.mp3", \
|
||||
"fade_in":0, \
|
||||
"fade_out":0, \
|
||||
"cue_in":0, \
|
||||
"cue_out":300, \
|
||||
"start": start_dt, \
|
||||
"end": end_dt, \
|
||||
"show_name":"Untitled", \
|
||||
"replay_gain": 0, \
|
||||
"independent_event": True \
|
||||
}
|
||||
|
||||
|
||||
|
||||
start_dt = datetime.utcnow() + timedelta(seconds=2)
|
||||
end_dt = datetime.utcnow() + timedelta(seconds=6)
|
||||
|
||||
media_schedule[start_dt] = {"id": 5, \
|
||||
"type":"file", \
|
||||
"row_id":9, \
|
||||
"uri":"", \
|
||||
"dst":"/home/martin/Music/ipod/Good Charlotte - bloody valentine.mp3", \
|
||||
"fade_in":0, \
|
||||
"fade_out":0, \
|
||||
"cue_in":0, \
|
||||
"cue_out":300, \
|
||||
"start": start_dt, \
|
||||
"end": end_dt, \
|
||||
"show_name":"Untitled", \
|
||||
"replay_gain": 0, \
|
||||
"independent_event": True \
|
||||
}
|
||||
pypoLiq_q.put(media_schedule)
|
||||
|
||||
plq.join()
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
import os
|
||||
import sys
|
||||
import shutil
|
||||
|
||||
#check if root
|
||||
if os.geteuid() != 0:
|
||||
print 'Must be a root user.'
|
||||
sys.exit(1)
|
||||
|
||||
#ask if we should backup config files
|
||||
backup_config = True
|
||||
|
||||
#ask if we should backup database
|
||||
backup_database = True
|
||||
|
||||
#ask if we should backup stor directory
|
||||
backup_stor = True
|
||||
|
||||
#ask if we should backup all watched directories
|
||||
backup_watched = True
|
||||
|
||||
#create airtime-backup directory
|
||||
os.mkdir("airtime_backup")
|
||||
|
||||
if backup_config:
|
||||
backup_config_dir = "airtime_backup/config"
|
||||
os.mkdir(backup_config_dir)
|
||||
#TODO check if directory exists
|
||||
config_dir = "/etc/airtime"
|
||||
files = os.listdir()
|
||||
for f in files:
|
||||
shutil.copy(os.path.join(config_dir, f), \
|
||||
os.path.join(backup_config_dir, f)
|
||||
|
||||
if backup_database:
|
||||
os.mkdir("airtime_backup/database")
|
||||
#TODO: get database name
|
||||
#TODO use abs path
|
||||
"pg_dump airtime > database.dump.sql"
|
||||
|
||||
#TODO this might not be necessary
|
||||
os.mkdir("airtime_backup/files")
|
||||
|
||||
if backup_stor:
|
||||
#TODO use abs path
|
||||
backup_stor_dir = "airtime_backup/files/stor"
|
||||
os.mkdir(backup_stor_dir)
|
||||
shutil.copytree("/srv/airtime/stor", backup_stor_dir)
|
||||
|
||||
if backup_watched:
|
||||
pass
|
||||
|
Loading…
Reference in New Issue