Merge branch 'master' of dev.sourcefabric.org:airtime

This commit is contained in:
Martin Konecny 2013-04-07 20:20:57 -04:00
commit f13f6c6a70
56 changed files with 1781 additions and 869 deletions

View File

@ -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()

View File

@ -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()

View File

@ -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);
}
}

View File

@ -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 {}

View File

@ -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"));
}
}

View File

@ -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);
}
}

View File

@ -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));
}
}

View File

@ -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')));
}
}

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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
}

View File

@ -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 {}

View File

@ -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);
}

View File

@ -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.
*

View File

@ -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) {

View File

@ -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.
*

View File

@ -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";

View File

@ -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()

View File

@ -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();

View File

@ -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');
}
}

View File

@ -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
*

View File

@ -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') {

View File

@ -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>

View File

@ -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&#39s title, description, and criteria' type="button" id="save_button"><? echo _("Save") ?></button>
</div>

View File

@ -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">

View File

@ -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>

View File

@ -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")
);

View File

@ -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 {

View File

@ -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();
}
});
});

View File

@ -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>')

View File

@ -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.")

View File

@ -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();

View File

@ -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",

View File

@ -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);

View File

@ -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();

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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();

View File

@ -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");

6
debian/changelog vendored
View File

@ -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

2
debian/control vendored
View File

@ -43,7 +43,7 @@ Depends: apache2,
pwgen,
python,
rabbitmq-server,
silan (>= 0.3.0~),
silan (>= 0.3.1~),
sudo,
sysv-rc,
tar (>= 1.22),

2
debian/postinst vendored
View File

@ -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)

View File

@ -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])

View File

@ -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

View File

@ -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"

View File

@ -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) =

View File

@ -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.",

View File

@ -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()

View File

@ -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

View File

@ -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())

View File

@ -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

View File

@ -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)

View File

@ -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
"""

View File

@ -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

View File

@ -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()

52
utils/airtime-backup.py Normal file
View File

@ -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