Merge branch 'devel' of dev.sourcefabric.org:airtime into devel

Conflicts:
	airtime_mvc/application/controllers/PlaylistController.php
This commit is contained in:
James 2012-08-23 10:43:28 -04:00
commit c2d475e6d8
57 changed files with 1304 additions and 703 deletions

View File

@ -12,7 +12,6 @@ require_once "DateHelper.php";
require_once "OsPath.php";
require_once __DIR__.'/controllers/plugins/RabbitMqPlugin.php';
//DateTime in PHP 5.3.0+ need a default timezone set. Set to UTC initially
//in case Application_Model_Preference::GetTimezone fails and creates needs to create
//a log entry. This log entry requires a call to date(), which then complains that
@ -67,10 +66,10 @@ class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
$baseUrl = Zend_Controller_Front::getInstance()->getBaseUrl();
$baseDir = dirname($_SERVER['SCRIPT_FILENAME']);
$view->headScript()->appendFile($baseUrl.'/js/libs/jquery-1.7.2.min.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$view->headScript()->appendFile($baseUrl.'/js/libs/jquery-ui-1.8.18.custom.min.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$view->headScript()->appendFile($baseUrl.'/js/libs/jquery.stickyPanel.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$view->headScript()->appendFile($baseUrl.'/js/qtip/jquery.qtip.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$view->headScript()->appendFile($baseUrl.'/js/libs/jquery-1.7.2.min.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$view->headScript()->appendFile($baseUrl.'/js/libs/jquery-ui-1.8.18.custom.min.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$view->headScript()->appendFile($baseUrl.'/js/libs/jquery.stickyPanel.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$view->headScript()->appendFile($baseUrl.'/js/qtip/jquery.qtip.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$view->headScript()->appendFile($baseUrl.'/js/jplayer/jquery.jplayer.min.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$view->headScript()->appendFile($baseUrl.'/js/sprintf/sprintf-0.7-beta1.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$view->headScript()->appendScript("var baseUrl='$baseUrl/'");

View File

@ -8,38 +8,38 @@
* the navigation container below.
*/
$pages = array(
array(
array(
'label' => 'Now Playing',
'module' => 'default',
'controller' => 'Showbuilder',
'action' => 'index',
'resource' => 'showbuilder'
),
array(
'label' => 'Add Media',
'module' => 'default',
'controller' => 'Plupload',
'action' => 'index',
'resource' => 'plupload'
),
array(
'label' => 'Library',
'module' => 'default',
'controller' => 'Playlist',
'action' => 'index',
'resource' => 'playlist'
),
array(
'resource' => 'showbuilder'
),
array(
'label' => 'Add Media',
'module' => 'default',
'controller' => 'Plupload',
'action' => 'index',
'resource' => 'plupload'
),
array(
'label' => 'Library',
'module' => 'default',
'controller' => 'Library',
'action' => 'index',
'resource' => 'playlist'
),
array(
'label' => 'Calendar',
'module' => 'default',
'controller' => 'Schedule',
'action' => 'index',
'resource' => 'schedule'
),
'resource' => 'schedule'
),
array(
'label' => 'System',
'uri' => '#',
'resource' => 'preference',
'uri' => '#',
'resource' => 'preference',
'pages' => array(
array(
'label' => 'Preferences',
@ -51,14 +51,14 @@ $pages = array(
'module' => 'default',
'controller' => 'user',
'action' => 'add-user',
'resource' => 'user'
'resource' => 'user'
),
array(
'label' => 'Media Folders',
'module' => 'default',
'controller' => 'Preference',
'action' => 'directory-config',
'id' => 'manage_folder'
'id' => 'manage_folder'
),
array(
'label' => 'Streams',
@ -77,28 +77,28 @@ $pages = array(
'module' => 'default',
'controller' => 'systemstatus',
'action' => 'index',
'resource' => 'systemstatus'
'resource' => 'systemstatus'
),
array(
'label' => 'Playout History',
'module' => 'default',
'controller' => 'playouthistory',
'action' => 'index',
'resource' => 'playouthistory'
)
array(
'label' => 'Playout History',
'module' => 'default',
'controller' => 'playouthistory',
'action' => 'index',
'resource' => 'playouthistory'
)
)
),
array(
'label' => 'Help',
'uri' => '#',
'resource' => 'dashboard',
array(
'label' => 'Help',
'uri' => '#',
'resource' => 'dashboard',
'pages' => array(
array(
'label' => 'Getting Started',
'module' => 'default',
'controller' => 'dashboard',
'action' => 'help',
'resource' => 'dashboard'
'resource' => 'dashboard'
),
array(
'label' => 'User Manual',
@ -110,10 +110,10 @@ $pages = array(
'module' => 'default',
'controller' => 'dashboard',
'action' => 'about',
'resource' => 'dashboard'
'resource' => 'dashboard'
)
)
)
)
);

View File

@ -318,7 +318,7 @@ class ApiController extends Zend_Controller_Action
}
$result['AIRTIME_API_VERSION'] = AIRTIME_API_VERSION; //used by caller to determine if the airtime they are running or widgets in use is out of date.
header("Content-type: text/javascript");
Logging::log($result);
Logging::info($result);
// If a callback is not given, then just provide the raw JSON.
echo isset($_GET['callback']) ? $_GET['callback'].'('.json_encode($result).')' : json_encode($result);
} else {
@ -359,7 +359,7 @@ class ApiController extends Zend_Controller_Action
$file->setLastPlayedTime($now);
}
} catch (Exception $e) {
Logging::log($e);
Logging::info($e);
}
echo json_encode(array("status"=>1, "message"=>""));
@ -475,8 +475,8 @@ class ApiController extends Zend_Controller_Action
);
}
Application_Model_Preference::SetImportTimestamp();
Logging::log("--->Mode: $mode || file: {$md['MDATA_KEY_FILEPATH']} ");
Logging::log( $md );
Logging::info("--->Mode: $mode || file: {$md['MDATA_KEY_FILEPATH']} ");
Logging::info( $md );
if ($mode == "create") {
$filepath = $md['MDATA_KEY_FILEPATH'];
$filepath = Application_Common_OsPath::normpath($filepath);
@ -547,38 +547,36 @@ class ApiController extends Zend_Controller_Action
public function reloadMetadataGroupAction()
{
$request = $this->getRequest();
// extract all file metadata params from the request.
// The value is a json encoded hash that has all the information related to this action
// The key(mdXXX) does not have any meaning as of yet but it could potentially correspond
// to some unique id.
$responses = array();
$dry = $request->getParam('dry') || false;
$params = $request->getParams();
$request = $this->getRequest();
$responses = array();
$dry = $request->getParam('dry') || false;
$params = $request->getParams();
$valid_modes = array('delete_dir', 'delete', 'moved', 'modify', 'create');
foreach ($request->getParams() as $k => $raw_json) {
// Valid requests must start with mdXXX where XXX represents at least 1 digit
// Valid requests must start with mdXXX where XXX represents at
// least 1 digit
if( !preg_match('/^md\d+$/', $k) ) { continue; }
$info_json = json_decode($raw_json, $assoc=true);
$recorded = $info_json["is_record"];
$info_json = json_decode($raw_json, $assoc = true);
$recorded = $info_json["is_record"];
unset( $info_json["is_record"] );
//unset( $info_json["MDATA_KEY_DURATION"] );
//unset( $info_json["MDATA_KEY_SAMPLERATE"] );
//unset( $info_json["MDATA_KEY_BITRATE"] );
if( !array_key_exists('mode', $info_json) ) { // Log invalid requests
Logging::log("Received bad request(key=$k), no 'mode' parameter. Bad request is:");
Logging::log( $info_json );
// Log invalid requests
if( !array_key_exists('mode', $info_json) ) {
Logging::info("Received bad request(key=$k), no 'mode' parameter. Bad request is:");
Logging::info( $info_json );
array_push( $responses, array(
'error' => "Bad request. no 'mode' parameter passed.",
'key' => $k));
continue;
} elseif ( !in_array($info_json['mode'], $valid_modes) ) {
// A request still has a chance of being invalid even if it exists but it's validated
// by $valid_modes array
// A request still has a chance of being invalid even if it
// exists but it's validated by $valid_modes array
$mode = $info_json['mode'];
Logging::log("Received bad request(key=$k). 'mode' parameter was invalid with value: '$mode'. Request:");
Logging::log( $info_json );
Logging::info("Received bad request(key=$k). 'mode' parameter was invalid with value: '$mode'. Request:");
Logging::info( $info_json );
array_push( $responses, array(
'error' => "Bad request. 'mode' parameter is invalid",
'key' => $k,
@ -588,14 +586,12 @@ class ApiController extends Zend_Controller_Action
// Removing 'mode' key from $info_json might not be necessary...
$mode = $info_json['mode'];
unset( $info_json['mode'] );
$response = $this->dispatchMetadata($info_json, $mode, $dry_run=$dry);
$response = $this->dispatchMetadata($info_json, $mode,
$dry_run=$dry);
// We tack on the 'key' back to every request in case the would like to associate
// his requests with particular responses
$response['key'] = $k;
array_push($responses, $response);
// On recorded show requests we do some extra work here. Not sure what it actually is and it
// was usually called from the python api client. Now we just call it straight from the controller to
// save the http roundtrip
}
die( json_encode($responses) );
}
@ -615,7 +611,7 @@ class ApiController extends Zend_Controller_Action
}
}
Logging::log( $md );
Logging::info( $md );
// update import timestamp
Application_Model_Preference::SetImportTimestamp();
@ -781,7 +777,7 @@ class ApiController extends Zend_Controller_Action
$component = $request->getParam('component');
$remoteAddr = Application_Model_ServiceRegister::GetRemoteIpAddr();
Logging::log("Registered Component: ".$component."@".$remoteAddr);
Logging::info("Registered Component: ".$component."@".$remoteAddr);
Application_Model_ServiceRegister::Register($component, $remoteAddr);
}
@ -902,7 +898,7 @@ class ApiController extends Zend_Controller_Action
public function rabbitmqDoPushAction()
{
$request = $this->getRequest();
Logging::log("Notifying RabbitMQ to send message to pypo");
Logging::info("Notifying RabbitMQ to send message to pypo");
Application_Model_RabbitMq::PushSchedule();
}

View File

@ -7,9 +7,6 @@ require_once 'formatters/BitrateFormatter.php';
class LibraryController extends Zend_Controller_Action
{
protected $obj_sess = null;
protected $search_sess = null;
public function init()
{
$ajaxContext = $this->_helper->getHelper('AjaxContext');
@ -23,10 +20,129 @@ class LibraryController extends Zend_Controller_Action
->addActionContext('set-num-entries', 'json')
->initContext();
$this->obj_sess = new Zend_Session_Namespace(UI_PLAYLISTCONTROLLER_OBJ_SESSNAME);
$this->search_sess = new Zend_Session_Namespace("search");
}
public function indexAction()
{
global $CC_CONFIG;
$request = $this->getRequest();
$baseUrl = $request->getBaseUrl();
$this->view->headScript()->appendFile($baseUrl.'/js/blockui/jquery.blockUI.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/contextmenu/jquery.contextMenu.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/js/jquery.dataTables.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.pluginAPI.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.fnSetFilteringDelay.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.ColVis.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.ColReorder.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.FixedColumns.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/buttons/buttons.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/utilities/utilities.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/library/library.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($this->view->baseUrl('/js/airtime/library/events/library_playlistbuilder.js'), 'text/javascript');
$this->view->headLink()->appendStylesheet($baseUrl.'/css/media_library.css?'.$CC_CONFIG['airtime_version']);
$this->view->headLink()->appendStylesheet($baseUrl.'/css/jquery.contextMenu.css?'.$CC_CONFIG['airtime_version']);
$this->view->headLink()->appendStylesheet($baseUrl.'/css/datatables/css/ColVis.css?'.$CC_CONFIG['airtime_version']);
$this->view->headLink()->appendStylesheet($baseUrl.'/css/datatables/css/ColReorder.css?'.$CC_CONFIG['airtime_version']);
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/library/spl.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/playlist/smart_blockbuilder.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headLink()->appendStylesheet($baseUrl.'/css/playlist_builder.css?'.$CC_CONFIG['airtime_version']);
try {
$obj_sess = new Zend_Session_Namespace(UI_PLAYLISTCONTROLLER_OBJ_SESSNAME);
if (isset($obj_sess->id)) {
$objInfo = Application_Model_Library::getObjInfo($obj_sess->type);
Logging::info($obj_sess->id);
Logging::info($obj_sess->type);
$objInfo = Application_Model_Library::getObjInfo($obj_sess->type);
$obj = new $objInfo['className']($obj_sess->id);
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
$user = new Application_Model_User($userInfo->id);
$isAdminOrPM = $user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER));
if ($isAdminOrPM || $obj->getCreatorId() == $userInfo->id) {
$this->view->obj = $obj;
if ($obj_sess->type == "block") {
$form = new Application_Form_SmartBlockCriteria();
$form->startForm($obj_sess->id);
$this->view->form = $form;
}
}
$formatter = new LengthFormatter($obj->getLength());
$this->view->length = $formatter->format();
$this->view->type = $obj_sess->type;
}
} catch (PlaylistNotFoundException $e) {
$this->playlistNotFound($obj_sess->type);
} catch (Exception $e) {
$this->playlistNotFound($obj_sess->type);
Logging::info($e->getMessage());
//$this->playlistUnknownError($e);
}
}
protected function playlistNotFound($p_type)
{
$this->view->error = "{$p_type} not found";
Logging::info("{$p_type} not found");
Application_Model_Library::changePlaylist(null, $p_type);
$this->createFullResponse(null);
}
protected function playlistUnknownError($e)
{
$this->view->error = "Something went wrong.";
Logging::info("{$e->getFile()}");
Logging::info("{$e->getLine()}");
Logging::info("{$e->getMessage()}");
}
protected function createFullResponse($obj = null, $isJson = false)
{
$isBlock = false;
$viewPath = 'playlist/playlist.phtml';
if ($obj instanceof Application_Model_Block) {
$isBlock = true;
$viewPath = 'playlist/smart-block.phtml';
}
if (isset($obj)) {
$formatter = new LengthFormatter($obj->getLength());
$this->view->length = $formatter->format();
if ($isBlock) {
$form = new Application_Form_SmartBlockCriteria();
$form->removeDecorator('DtDdWrapper');
$form->startForm($obj->getId());
$this->view->form = $form;
$this->view->obj = $obj;
$this->view->id = $obj->getId();
if ($isJson) {
return $this->view->render($viewPath);
} else {
$this->view->html = $this->view->render($viewPath);
}
} else {
$this->view->obj = $obj;
$this->view->id = $obj->getId();
$this->view->html = $this->view->render($viewPath);
unset($this->view->obj);
}
} else {
$this->view->html = $this->view->render($viewPath);
}
}
public function contextMenuAction()
{
$id = $this->_getParam('id');
@ -45,21 +161,23 @@ class LibraryController extends Zend_Controller_Action
$isAdminOrPM = $user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER));
$obj_sess = new Zend_Session_Namespace(UI_PLAYLISTCONTROLLER_OBJ_SESSNAME);
if ($type === "audioclip") {
$file = Application_Model_StoredFile::Recall($id);
if (isset($this->obj_sess->id) && $screen == "playlist") {
if (isset($obj_sess->id) && $screen == "playlist") {
// if the user is not admin or pm, check the creator and see if this person owns the playlist or Block
if ($this->obj_sess->type == 'playlist') {
$obj = new Application_Model_Playlist($this->obj_sess->id);
} else {
$obj = new Application_Model_Block($this->obj_sess->id);
if ($obj_sess->type == 'playlist') {
$obj = new Application_Model_Playlist($obj_sess->id);
} else if ($obj_sess->type == 'block') {
$obj = new Application_Model_Block($obj_sess->id);
}
if ($isAdminOrPM || $obj->getCreatorId() == $user->getId()) {
if ($this->obj_sess->type === "playlist") {
if ($obj_sess->type === "playlist") {
$menu["pl_add"] = array("name"=> "Add to Playlist", "icon" => "add-playlist", "icon" => "copy");
} else if ($this->obj_sess->type === "block") {
} else if ($obj_sess->type === "block") {
$menu["pl_add"] = array("name"=> "Add to Smart Block", "icon" => "add-playlist", "icon" => "copy");
}
}
@ -71,22 +189,22 @@ class LibraryController extends Zend_Controller_Action
$url = $file->getRelativeFileUrl($baseUrl).'/download/true';
$menu["download"] = array("name" => "Download", "icon" => "download", "url" => $url);
} elseif ($type === "playlist" || $type === "block") {
} else if ($type === "playlist" || $type === "block") {
if ($type === 'playlist') {
$obj = new Application_Model_Playlist($id);
} else {
} else if ($type === 'block') {
$obj = new Application_Model_Block($id);
if (!$obj->isStatic()) {
unset($menu["play"]);
}
if (($isAdminOrPM || $obj->getCreatorId() == $user->getId()) && $screen == "playlist") {
if ($this->obj_sess->type === "playlist") {
if ($obj_sess->type === "playlist") {
$menu["pl_add"] = array("name"=> "Add to Playlist", "icon" => "add-playlist", "icon" => "copy");
}
}
}
if ($this->obj_sess->id !== $id && $screen == "playlist") {
if ($obj_sess->id !== $id && $screen == "playlist") {
if ($isAdminOrPM || $obj->getCreatorId() == $user->getId()) {
$menu["edit"] = array("name"=> "Edit", "icon" => "edit");
}
@ -98,9 +216,9 @@ class LibraryController extends Zend_Controller_Action
$webstream = CcWebstreamQuery::create()->findPK($id);
$obj = new Application_Model_Webstream($webstream);
if (isset($this->obj_sess->id) && $screen == "playlist") {
if (isset($obj_sess->id) && $screen == "playlist") {
if ($isAdminOrPM || $obj->getCreatorId() == $user->getId()) {
if ($this->obj_sess->type === "playlist") {
if ($obj_sess->type === "playlist") {
$menu["pl_add"] = array("name"=> "Add to Playlist", "icon" => "add-playlist", "icon" => "copy");
}
}
@ -191,7 +309,7 @@ class LibraryController extends Zend_Controller_Action
Application_Model_Webstream::deleteStreams($streams, $user->getId());
} catch (Exception $e) {
//TODO: warn user that not all streams could be deleted.
Logging::log($e);
Logging::info($e);
}
foreach ($files as $id) {
@ -267,10 +385,10 @@ class LibraryController extends Zend_Controller_Action
// set MDATA_KEY_FILEPATH
$data['MDATA_KEY_FILEPATH'] = $file->getFilePath();
Logging::log($data['MDATA_KEY_FILEPATH']);
Logging::info($data['MDATA_KEY_FILEPATH']);
Application_Model_RabbitMq::SendMessageToMediaMonitor("md_update", $data);
$this->_redirect('Playlist');
$this->_redirect('Library');
}
}
@ -344,7 +462,7 @@ class LibraryController extends Zend_Controller_Action
$this->view->type = $type;
}
} catch (Exception $e) {
Logging::log($e->getMessage());
Logging::info($e->getMessage());
}
}

View File

@ -2,9 +2,6 @@
class PlaylistController extends Zend_Controller_Action
{
/*protected $pl_sess = null;
protected $bl_sess = null;*/
protected $obj_sess = null;
public function init()
{
@ -30,19 +27,16 @@ class PlaylistController extends Zend_Controller_Action
->addActionContext('get-block-info', 'json')
->initContext();
/*$this->pl_sess = new Zend_Session_Namespace(UI_PLAYLIST_SESSNAME);
$this->bl_sess = new Zend_Session_Namespace(UI_BLOCK_SESSNAME);*/
$this->obj_sess = new Zend_Session_Namespace(UI_PLAYLISTCONTROLLER_OBJ_SESSNAME);
}
private function getPlaylist($p_type)
{
$obj = null;
$objInfo = $this->getObjInfo($p_type);
$objInfo = Application_Model_Library::getObjInfo($p_type);
if (isset($this->obj_sess->id)) {
$obj = new $objInfo['className']($this->obj_sess->id);
$obj_sess = new Zend_Session_Namespace(UI_PLAYLISTCONTROLLER_OBJ_SESSNAME);
if (isset($obj_sess->id)) {
$obj = new $objInfo['className']($obj_sess->id);
$modified = $this->_getParam('modified', null);
if ($obj->getLastModified("U") !== $modified) {
@ -54,16 +48,6 @@ class PlaylistController extends Zend_Controller_Action
return $obj;
}
private function changePlaylist($p_id, $p_type)
{
if (is_null($p_id) || is_null($p_type)) {
unset($this->obj_sess->id);
unset($this->obj_sess->type);
} else {
$this->obj_sess->id = intval($p_id);
$this->obj_sess->type = $p_type;
}
}
private function createUpdateResponse($obj)
{
@ -106,14 +90,13 @@ class PlaylistController extends Zend_Controller_Action
} else {
$this->view->html = $this->view->render($viewPath);
}
}else{
} else {
$this->view->obj = $obj;
$this->view->id = $obj->getId();
$this->view->html = $this->view->render($viewPath);
unset($this->view->obj);
}
}
else {
} else {
$this->view->html = $this->view->render($viewPath);
}
}
@ -133,100 +116,46 @@ class PlaylistController extends Zend_Controller_Action
{
$this->view->error = "{$p_type} not found";
Logging::log("{$p_type} not found");
$this->changePlaylist(null, $p_type);
Logging::info("{$p_type} not found");
Application_Model_Library::changePlaylist(null, $p_type);
$this->createFullResponse(null);
}
private function playlistNoPermission($p_type){
private function playlistNoPermission($p_type)
{
$this->view->error = "You don't have permission to delete selected {$p_type}(s).";
$this->changePlaylist(null, $p_type);
$this->createFullResponse(null);
}
private function playlistUnknownError($e)
{
$this->view->error = "Something went wrong.";
Logging::log("{$e->getFile()}");
Logging::log("{$e->getLine()}");
Logging::log("{$e->getMessage()}");
Logging::info("{$e->getFile()}");
Logging::info("{$e->getLine()}");
Logging::info("{$e->getMessage()}");
}
private function wrongTypeToBlock($obj) {
private function wrongTypeToBlock($obj)
{
$this->view->error = "You can only add tracks to smart block.";
$this->createFullResponse($obj);
}
private function wrongTypeToPlaylist($obj) {
private function wrongTypeToPlaylist($obj)
{
$this->view->error = "You can only add tracks and smart blocks to playlists.";
$this->createFullResponse($obj);
}
public function indexAction()
{
global $CC_CONFIG;
$request = $this->getRequest();
$baseUrl = $request->getBaseUrl();
$this->view->headScript()->appendFile($baseUrl.'/js/blockui/jquery.blockUI.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/contextmenu/jquery.contextMenu.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/js/jquery.dataTables.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.pluginAPI.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.fnSetFilteringDelay.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.ColVis.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.ColReorder.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.FixedColumns.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.columnFilter.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/buttons/buttons.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/utilities/utilities.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/library/library.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($this->view->baseUrl('/js/airtime/library/events/library_playlistbuilder.js'),'text/javascript');
$this->view->headLink()->appendStylesheet($baseUrl.'/css/media_library.css?'.$CC_CONFIG['airtime_version']);
$this->view->headLink()->appendStylesheet($baseUrl.'/css/jquery.contextMenu.css?'.$CC_CONFIG['airtime_version']);
$this->view->headLink()->appendStylesheet($baseUrl.'/css/datatables/css/ColVis.css?'.$CC_CONFIG['airtime_version']);
$this->view->headLink()->appendStylesheet($baseUrl.'/css/datatables/css/ColReorder.css?'.$CC_CONFIG['airtime_version']);
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/library/spl.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/playlist/smart_blockbuilder.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headLink()->appendStylesheet($baseUrl.'/css/playlist_builder.css?'.$CC_CONFIG['airtime_version']);
try {
if (isset($this->obj_sess->id)) {
$objInfo = $this->getObjInfo($this->obj_sess->type);
$obj = new $objInfo['className']($this->obj_sess->id);
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
$user = new Application_Model_User($userInfo->id);
$isAdminOrPM = $user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER));
if($isAdminOrPM || $obj->getCreatorId() == $userInfo->id){
$this->view->obj = $obj;
if($this->obj_sess->type == "block"){
$form = new Application_Form_SmartBlockCriteria();
$form->startForm($this->obj_sess->id);
$this->view->form = $form;
}
}
$formatter = new LengthFormatter($obj->getLength());
$this->view->length = $formatter->format();
$this->view->type = $this->obj_sess->type;
}
} catch (PlaylistNotFoundException $e) {
$this->playlistNotFound($this->obj_sess->type);
} catch (Exception $e) {
$this->playlistUnknownError($e);
}
}
public function newAction()
{
//$pl_sess = $this->pl_sess;
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
$type = $this->_getParam('type');
$objInfo = $this->getObjInfo($type);
$objInfo = Application_Model_Library::getObjInfo($type);
$name = 'Untitled Playlist';
if ($type == 'block') {
@ -235,9 +164,9 @@ class PlaylistController extends Zend_Controller_Action
$obj = new $objInfo['className']();
$obj->setName($name);
$obj->setMetaData('dc:creator', $userInfo->id);
$obj->setMetadata('dc:creator', $userInfo->id);
$this->changePlaylist($obj->getId(), $type);
Application_Model_Library::changePlaylist($obj->getId(), $type);
$this->createFullResponse($obj);
}
@ -245,11 +174,11 @@ class PlaylistController extends Zend_Controller_Action
{
$id = $this->_getParam('id', null);
$type = $this->_getParam('type');
$objInfo = $this->getObjInfo($type);
Logging::log("editing {$type} {$id}");
$objInfo = Application_Model_Library::getObjInfo($type);
Logging::info("editing {$type} {$id}");
if (!is_null($id)) {
$this->changePlaylist($id, $type);
Application_Model_Library::changePlaylist($id, $type);
}
try {
@ -270,32 +199,35 @@ class PlaylistController extends Zend_Controller_Action
$obj = null;
$objInfo = $this->getObjInfo($type);
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
$objInfo = Application_Model_Library::getObjInfo($type);
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
$user = new Application_Model_User($userInfo->id);
try {
Logging::log("Currently active {$type} {$this->obj_sess->id}");
if (in_array($this->obj_sess->id, $ids)) {
Logging::log("Deleting currently active {$type}");
$this->changePlaylist(null, $type);
$obj_sess = new Zend_Session_Namespace(UI_PLAYLISTCONTROLLER_OBJ_SESSNAME);
try {
Logging::info("Currently active {$type} {$obj_sess->id}");
if (in_array($obj_sess->id, $ids)) {
Logging::info("Deleting currently active {$type}");
Application_Model_Library::changePlaylist(null, $type);
} else {
Logging::log("Not deleting currently active {$type}");
$obj = new $objInfo['className']($this->obj_sess->id);
Logging::info("Not deleting currently active {$type}");
$obj = new $objInfo['className']($obj_sess->id);
}
if (strcmp($objInfo['className'], 'Application_Model_Playlist')==0) {
Application_Model_Playlist::deletePlaylists($ids, $userInfo->id);
} else {
Application_Model_Block::deleteBlocks($ids, $userInfo->id);
}
$this->createFullResponse($obj);
}
catch (PlaylistNoPermissionException $e) {
} catch (PlaylistNoPermissionException $e) {
$this->playlistNoPermission($type);
}
catch (PlaylistNotFoundException $e) {
} catch (BlockNoPermissionException $e) {
$this->playlistNoPermission($type);
} catch (PlaylistNotFoundException $e) {
$this->playlistNotFound($type);
} catch (Exception $e) {
$this->playlistUnknownError($e);
@ -314,7 +246,7 @@ class PlaylistController extends Zend_Controller_Action
try {
$obj = $this->getPlaylist($obj_type);
if ($obj_type == 'playlist') {
foreach($ids as $id) {
foreach ($ids as $id) {
if (is_array($id) && isset($id[1])) {
if ($id[1] == 'playlist') {
throw new WrongTypeToPlaylistException;
@ -325,7 +257,7 @@ class PlaylistController extends Zend_Controller_Action
} else if ($obj->isStatic()) {
// if the dest is a block object
//check if any items are playlists
foreach($ids as $id) {
foreach ($ids as $id) {
if (is_array($id) && isset($id[1])) {
if ($id[1] != 'audioclip') {
throw new WrongTypeToBlockException;
@ -337,11 +269,9 @@ class PlaylistController extends Zend_Controller_Action
throw new BlockDynamicException;
}
$this->createUpdateResponse($obj);
}
catch (PlaylistOutDatedException $e) {
} catch (PlaylistOutDatedException $e) {
$this->playlistOutdated($e);
}
catch (PlaylistNotFoundException $e) {
} catch (PlaylistNotFoundException $e) {
$this->playlistNotFound($obj_type);
}
catch (WrongTypeToBlockException $e) {
@ -525,18 +455,18 @@ class PlaylistController extends Zend_Controller_Action
$this->setPlaylistNameDescAction();
if ($params['type'] == 'block') {
$form = new Application_Form_SmartBlockCriteria();
$form = new Application_Form_SmartBlockCriteria();
$form->startForm($params['obj_id']);
$bl = new Application_Model_Block($params['obj_id']);
$bl = new Application_Model_Block($params['obj_id']);
if ($form->isValid($params)) {
$bl->saveSmartBlockCriteria($params['data']);
$result['html'] = $this->createFullResponse($bl, true);
$result['result'] = 0;
} else {
$this->view->obj = $bl;
$this->view->obj = $bl;
$this->view->id = $bl->getId();
$this->view->form = $form;
$viewPath = 'playlist/smart-block.phtml';
$viewPath = 'playlist/smart-block.phtml';
$result['html'] = $this->view->render($viewPath);
$result['result'] = 1;
}
@ -546,72 +476,54 @@ class PlaylistController extends Zend_Controller_Action
die(json_encode($result));
}
public function smartBlockGenerateAction()
{
$request = $this->getRequest();
public function smartBlockGenerateAction()
{
$request = $this->getRequest();
$params = $request->getPost();
$form = new Application_Form_SmartBlockCriteria();
$form = new Application_Form_SmartBlockCriteria();
$form->startForm($params['obj_id']);
$bl = new Application_Model_Block($params['obj_id']);
if ($form->isValid($params)) {
$result = $bl->generateSmartBlock($params['data']);
try {
die(json_encode(array("result"=>0, "html"=>$this->createFullResponse($bl, true))));
}
catch (PlaylistNotFoundException $e) {
} catch (PlaylistNotFoundException $e) {
$this->playlistNotFound('block');
}
catch (Exception $e) {
} catch (Exception $e) {
$this->playlistUnknownError($e);
}
}else{
$this->view->obj = $bl;
$this->view->id = $bl->getId();
$this->view->form = $form;
$viewPath = 'playlist/smart-block.phtml';
} else {
$this->view->obj = $bl;
$this->view->id = $bl->getId();
$this->view->form = $form;
$viewPath = 'playlist/smart-block.phtml';
$result['html'] = $this->view->render($viewPath);
$result['result'] = 1;
die(json_encode($result));
}
}
}
public function smartBlockShuffleAction()
{
$request = $this->getRequest();
$request = $this->getRequest();
$params = $request->getPost();
$bl = new Application_Model_Block($params['obj_id']);
$result = $bl->shuffleSmartBlock();
if ($result['result'] == 0) {
try {
die(json_encode(array("result"=>0, "html"=>$this->createFullResponse($bl, true))));
}
catch (PlaylistNotFoundException $e) {
$this->playlistNotFound('block');
}
catch (Exception $e) {
$this->playlistUnknownError($e);
}
}else{
die(json_encode($result));
}
}
public function getObjInfo($p_type)
{
$info = array();
if (strcmp($p_type, 'playlist')==0) {
$info['className'] = 'Application_Model_Playlist';
if ($result['result'] == 0) {
try {
die(json_encode(array("result"=>0, "html"=>$this->createFullResponse($bl, true))));
} catch (PlaylistNotFoundException $e) {
$this->playlistNotFound('block');
}
} else {
$info['className'] = 'Application_Model_Block';
die(json_encode($result));
}
return $info;
}
public function getBlockInfoAction(){
$request = $this->getRequest();
public function getBlockInfoAction()
{
$request = $this->getRequest();
$params = $request->getPost();
$bl = new Application_Model_Block($params['id']);
if ($bl->isStatic()) {

View File

@ -69,8 +69,8 @@ class PlayouthistoryController extends Zend_Controller_Action
$startsDT = DateTime::createFromFormat("U", $starts_epoch, new DateTimeZone("UTC"));
$endsDT = DateTime::createFromFormat("U", $ends_epoch, new DateTimeZone("UTC"));
Logging::log("history starts {$startsDT->format("Y-m-d H:i:s")}");
Logging::log("history ends {$endsDT->format("Y-m-d H:i:s")}");
Logging::info("history starts {$startsDT->format("Y-m-d H:i:s")}");
Logging::info("history ends {$endsDT->format("Y-m-d H:i:s")}");
$history = new Application_Model_PlayoutHistory($startsDT, $endsDT, $params);

View File

@ -238,7 +238,7 @@ class ScheduleController extends Zend_Controller_Action
}
$isAdminOrPM = $user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER));
$isDJ = $user->isHost($instance->getShowId());
$isDJ = $user->isHostOfShow($instance->getShowId());
$showStartLocalDT = Application_Common_DateHelper::ConvertToLocalDateTime($instance->getShowInstanceStart());
$showEndLocalDT = Application_Common_DateHelper::ConvertToLocalDateTime($instance->getShowInstanceEnd());
@ -338,7 +338,7 @@ class ScheduleController extends Zend_Controller_Action
return false;
}
if($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER, UTYPE_HOST),$show->getShowId()))
if($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER) && $user->isHostOfShow($show->getShowId())))
$show->clearShow();
}
@ -403,7 +403,7 @@ class ScheduleController extends Zend_Controller_Action
return false;
}
if ($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER, UTYPE_HOST),$show->getShowId())) {
if ($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER) && $user->isHostOfShow($show->getShowId()))) {
$show->removeGroupFromShow($group_id);
}
@ -543,7 +543,7 @@ class ScheduleController extends Zend_Controller_Action
}
$isAdminOrPM = $user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER));
$isDJ = $user->isHost($showInstance->getShowId());
$isDJ = $user->isHostOfShow($showInstance->getShowId());
if (!($isAdminOrPM || $isDJ)) {
return;
@ -864,9 +864,9 @@ class ScheduleController extends Zend_Controller_Action
Application_Model_RabbitMq::SendMessageToPypo("disconnect_source", $data);
} catch (Exception $e) {
$this->view->error = $e->getMessage();
Logging::log($e->getMessage());
Logging::log("{$e->getFile()}");
Logging::log("{$e->getLine()}");
Logging::info($e->getMessage());
Logging::info("{$e->getFile()}");
Logging::info("{$e->getLine()}");
}
}
}

View File

@ -290,14 +290,14 @@ class ShowbuilderController extends Zend_Controller_Action
$scheduler->scheduleAfter($scheduledItems, $mediaItems);
} catch (OutDatedScheduleException $e) {
$this->view->error = $e->getMessage();
Logging::log($e->getMessage());
Logging::log("{$e->getFile()}");
Logging::log("{$e->getLine()}");
Logging::info($e->getMessage());
Logging::info("{$e->getFile()}");
Logging::info("{$e->getLine()}");
} catch (Exception $e) {
$this->view->error = $e->getMessage();
Logging::log($e->getMessage());
Logging::log("{$e->getFile()}");
Logging::log("{$e->getLine()}");
Logging::info($e->getMessage());
Logging::info("{$e->getFile()}");
Logging::info("{$e->getLine()}");
}
}
@ -311,14 +311,14 @@ class ShowbuilderController extends Zend_Controller_Action
$scheduler->removeItems($items);
} catch (OutDatedScheduleException $e) {
$this->view->error = $e->getMessage();
Logging::log($e->getMessage());
Logging::log("{$e->getFile()}");
Logging::log("{$e->getLine()}");
Logging::info($e->getMessage());
Logging::info("{$e->getFile()}");
Logging::info("{$e->getLine()}");
} catch (Exception $e) {
$this->view->error = $e->getMessage();
Logging::log($e->getMessage());
Logging::log("{$e->getFile()}");
Logging::log("{$e->getLine()}");
Logging::info($e->getMessage());
Logging::info("{$e->getFile()}");
Logging::info("{$e->getLine()}");
}
}
@ -333,14 +333,14 @@ class ShowbuilderController extends Zend_Controller_Action
$scheduler->moveItem($selectedItems, $afterItem);
} catch (OutDatedScheduleException $e) {
$this->view->error = $e->getMessage();
Logging::log($e->getMessage());
Logging::log("{$e->getFile()}");
Logging::log("{$e->getLine()}");
Logging::info($e->getMessage());
Logging::info("{$e->getFile()}");
Logging::info("{$e->getLine()}");
} catch (Exception $e) {
$this->view->error = $e->getMessage();
Logging::log($e->getMessage());
Logging::log("{$e->getFile()}");
Logging::log("{$e->getLine()}");
Logging::info($e->getMessage());
Logging::info("{$e->getFile()}");
Logging::info("{$e->getLine()}");
}
}

View File

@ -8,14 +8,19 @@ class WebstreamController extends Zend_Controller_Action
$ajaxContext->addActionContext('new', 'json')
->addActionContext('save', 'json')
->addActionContext('edit', 'json')
->addActionContext('delete', 'json')
->initContext();
//TODO
//$this->pl_sess = new Zend_Session_Namespace(UI_PLAYLIST_SESSNAME);
}
public function newAction()
{
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
if (!$this->isAuthorized(-1)) {
header("Status: 401 Not Authorized");
return;
}
$webstream = new CcWebstream();
//we're not saving this primary key in the DB so it's OK
@ -25,8 +30,26 @@ class WebstreamController extends Zend_Controller_Action
$webstream->setDbUrl("http://");
$webstream->setDbLength("00:00:00");
$webstream->setDbName("Untitled Webstream");
$webstream->setDbCreatorId($userInfo->id);
$webstream->setDbUtime(new DateTime("now", new DateTimeZone('UTC')));
$webstream->setDbMtime(new DateTime("now", new DateTimeZone('UTC')));
//$webstream->save();
$this->view->ws = new Application_Model_Webstream($webstream);
/*
$type = "stream";
$objInfo = Application_Model_Library::getObjInfo($type);
$obj = new $objInfo['className']($webstream);
$obj->setName($webstream->getDbName());
$obj->setMetadata('dc:creator', $userInfo->id);
$type = "stream";
Application_Model_Library::changePlaylist($obj->getId(), $type);
*/
//clear the session in case an old playlist was open: CC-4196
Application_Model_Library::changePlaylist(null, null);
$this->view->obj = new Application_Model_Webstream($webstream);
$this->view->action = "new";
$this->view->html = $this->view->render('webstream/webstream.phtml');
}
@ -40,25 +63,67 @@ class WebstreamController extends Zend_Controller_Action
throw new Exception("Missing parameter 'id'");
}
$webstream = CcWebstreamQuery::create()->findPK($id);
$this->view->ws = new Application_Model_Webstream($webstream);
if ($webstream) {
Application_Model_Library::changePlaylist($id, "stream");
}
$this->view->obj = new Application_Model_Webstream($webstream);
$this->view->action = "edit";
$this->view->html = $this->view->render('webstream/webstream.phtml');
}
public function deleteAction()
{
$request = $this->getRequest();
$id = $request->getParam("ids");
if (!$this->isAuthorized($id)) {
header("Status: 401 Not Authorized");
return;
}
$type = "stream";
Application_Model_Library::changePlaylist(null, $type);
$webstream = CcWebstreamQuery::create()->findPK($id)->delete();
$this->view->obj = null;
$this->view->action = "delete";
$this->view->html = $this->view->render('webstream/webstream.phtml');
}
public function isAuthorized($webstream_id)
{
$hasPermission = false;
$user = Application_Model_User::getCurrentUser();
if ($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER))) {
$hasPermission = true;
}
if ($user->isHost()) {
if ($webstream_id != -1) {
$webstream = CcWebstreamQuery::create()->findPK($webstream_id);
//we are updating a playlist. Ensure that if the user is a host/dj, that he has the correct permission.
$user = Application_Model_User::getCurrentUser();
if ($webstream->getDbCreatorId() == $user->getId()) {
$hasPermission = true;
}
} else {
//we are creating a new stream. Don't need to check whether the DJ/Host owns the stream
$hasPermission = true;
}
}
return $hasPermission;
}
public function saveAction()
{
$request = $this->getRequest();
$user = Application_Model_User::getCurrentUser();
$hasPermission = $user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER, UTYPE_HOST));
if (!$hasPermission) {
header("Status: 401 Not Authorized");
return;
}
$id = $request->getParam("id");
$parameters = array();
@ -68,21 +133,19 @@ class WebstreamController extends Zend_Controller_Action
$parameters['description'] = trim($request->getParam("description"));
$parameters['url'] = trim($request->getParam("url"));
if ($parameters['id'] != -1) {
$webstream = CcWebstreamQuery::create()->findPK($parameters['id']);
//we are updating a playlist. Ensure that if the user is a host/dj, that he has the correct permission.
$user = Application_Model_User::getCurrentUser();
if ($webstream->getDbCreatorId() != $user->getId()) {
header("Status: 401 Not Authorized");
return;
}
}
if (!$this->isAuthorized($id)) {
header("Status: 401 Not Authorized");
return;
}
list($analysis, $mime, $di) = Application_Model_Webstream::analyzeFormData($parameters);
try {
if (Application_Model_Webstream::isValid($analysis)) {
$streamId = Application_Model_Webstream::save($parameters, $mime, $di);
Application_Model_Library::changePlaylist($streamId, "stream");
$this->view->statusMessage = "<div class='success'>Webstream saved.</div>";
$this->view->streamId = $streamId;
} else {

View File

@ -11,5 +11,13 @@ class RabbitMqPlugin extends Zend_Controller_Plugin_Abstract
Application_Model_RabbitMq::SendMessageToShowRecorder("update_recorder_schedule");
}
}
if (memory_get_peak_usage() > 25*pow(2, 20)) {
Logging::debug("Peak memory usage: "
.(memory_get_peak_usage()/1000000)
." MB while accessing URI ".$_SERVER['REQUEST_URI']);
Logging::debug("Should try to keep memory footprint under 25 MB");
}
}
}

View File

@ -4,7 +4,7 @@ class Application_Form_SmartBlockCriteria extends Zend_Form_SubForm
private $criteriaOptions = array(
0 => "Select criteria",
"album_title" => "Album",
"bit_rate" => "Bit Rate",
"bit_rate" => "Bit Rate (Kbps)",
"bpm" => "Bpm",
"comments" => "Comments",
"composer" => "Composer",
@ -23,7 +23,7 @@ class Application_Form_SmartBlockCriteria extends Zend_Form_SubForm
"name" => "Name",
"orchestra" => "Orchestra",
"rating" => "Rating",
"sample_rate" => "Sample Rate",
"sample_rate" => "Sample Rate (kHz)",
"track_title" => "Title",
"track_number" => "Track Number",
"utime" => "Uploaded",
@ -240,7 +240,7 @@ class Application_Form_SmartBlockCriteria extends Zend_Form_SubForm
$generate = new Zend_Form_Element_Button('generate_button');
$generate->setAttrib('class', 'ui-button ui-state-default sp-button');
$generate->setAttrib('title', 'Generate playlist content');
$generate->setAttrib('title', 'Generate playlist content and save criteria');
$generate->setIgnore(true);
$generate->setLabel('Generate');
$generate->setDecorators(array('viewHelper'));

View File

@ -5,7 +5,7 @@ class Logging {
private static $_logger;
private static $_path;
public static function getLogger()
private static function getLogger()
{
if (!isset(self::$_logger)) {
$writer = new Zend_Log_Writer_Stream(self::$_path);
@ -37,7 +37,7 @@ class Logging {
}
}
public static function log($p_msg)
public static function info($p_msg)
{
$bt = debug_backtrace();

View File

@ -8,7 +8,7 @@ require_once 'formatters/LengthFormatter.php';
* @copyright 2010 Sourcefabric O.P.S.
* @license http://www.gnu.org/licenses/gpl.txt
*/
class Application_Model_Block
class Application_Model_Block implements Application_Model_LibraryEditable
{
/**
* propel connection object.
@ -188,11 +188,11 @@ class Application_Model_Block
*/
public function getContents($filterFiles=false)
{
Logging::log("Getting contents for block {$this->id}");
Logging::info("Getting contents for block {$this->id}");
$files = array();
$sql = <<<"EOT"
SELECT pc.id as id, pc.position, pc.cliplength as length, pc.cuein, pc.cueout, pc.fadein, pc.fadeout, bl.type,
SELECT pc.id as id, pc.position, pc.cliplength as length, pc.cuein, pc.cueout, pc.fadein, pc.fadeout, bl.type, f.length as orig_length,
f.id as item_id, f.track_title, f.artist_name as creator, f.file_exists as exists, f.filepath as path FROM cc_blockcontents AS pc
LEFT JOIN cc_files AS f ON pc.file_id=f.id
LEFT JOIN cc_block AS bl ON pc.block_id = bl.id
@ -220,6 +220,10 @@ EOT;
$fades = $this->getFadeInfo($row['position']);
$row['fadein'] = $fades[0];
$row['fadeout'] = $fades[1];
//format original length
$formatter = new LengthFormatter($row['orig_length']);
$row['orig_length'] = $formatter->format();
}
return $rows;
@ -383,11 +387,11 @@ EOT;
try {
if (is_numeric($p_afterItem)) {
Logging::log("Finding block content item {$p_afterItem}");
Logging::info("Finding block content item {$p_afterItem}");
$afterItem = CcBlockcontentsQuery::create()->findPK($p_afterItem);
$index = $afterItem->getDbPosition();
Logging::log("index is {$index}");
Logging::info("index is {$index}");
$pos = ($addType == 'after') ? $index + 1 : $index;
$contentsToUpdate = CcBlockcontentsQuery::create()
@ -396,8 +400,8 @@ EOT;
->orderByDbPosition()
->find($this->con);
Logging::log("Adding to block");
Logging::log("at position {$pos}");
Logging::info("Adding to block");
Logging::info("at position {$pos}");
} else {
//add to the end of the block
@ -420,12 +424,12 @@ EOT;
->orderByDbPosition()
->find($this->con);
Logging::log("Adding to block");
Logging::log("at position {$pos}");
Logging::info("Adding to block");
Logging::info("at position {$pos}");
}
foreach ($p_items as $ac) {
Logging::log("Adding audio file {$ac}");
Logging::info("Adding audio file {$ac}");
if (is_array($ac) && $ac[1] == 'audioclip') {
$res = $this->insertBlockElement($this->buildEntry($ac[0], $pos));
@ -481,32 +485,32 @@ EOT;
$pos = 0;
//moving items to beginning of the block.
if (is_null($p_afterItem)) {
Logging::log("moving items to beginning of block");
Logging::info("moving items to beginning of block");
foreach ($contentsToMove as $item) {
Logging::log("item {$item->getDbId()} to pos {$pos}");
Logging::info("item {$item->getDbId()} to pos {$pos}");
$item->setDbPosition($pos);
$item->save($this->con);
$pos = $pos + 1;
}
foreach ($otherContent as $item) {
Logging::log("item {$item->getDbId()} to pos {$pos}");
Logging::info("item {$item->getDbId()} to pos {$pos}");
$item->setDbPosition($pos);
$item->save($this->con);
$pos = $pos + 1;
}
} else {
Logging::log("moving items after {$p_afterItem}");
Logging::info("moving items after {$p_afterItem}");
foreach ($otherContent as $item) {
Logging::log("item {$item->getDbId()} to pos {$pos}");
Logging::info("item {$item->getDbId()} to pos {$pos}");
$item->setDbPosition($pos);
$item->save($this->con);
$pos = $pos + 1;
if ($item->getDbId() == $p_afterItem) {
foreach ($contentsToMove as $move) {
Logging::log("item {$move->getDbId()} to pos {$pos}");
Logging::info("item {$move->getDbId()} to pos {$pos}");
$move->setDbPosition($pos);
$move->save($this->con);
$pos = $pos + 1;
@ -566,7 +570,7 @@ EOT;
public function getFadeInfo($pos)
{
Logging::log("Getting fade info for pos {$pos}");
Logging::info("Getting fade info for pos {$pos}");
$row = CcBlockcontentsQuery::create()
->joinWith(CcFilesPeer::OM_CLASS)
@ -651,7 +655,7 @@ EOT;
public function setfades($fadein, $fadeout)
{
if (isset($fadein)) {
Logging::log("Setting block fade in {$fadein}");
Logging::info("Setting block fade in {$fadein}");
$row = CcBlockcontentsQuery::create()
->filterByDbBlockId($this->id)
->filterByDbPosition(0)
@ -661,7 +665,7 @@ EOT;
}
if (isset($fadeout)) {
Logging::log("Setting block fade out {$fadeout}");
Logging::info("Setting block fade out {$fadeout}");
$row = CcBlockcontentsQuery::create()
->filterByDbBlockId($this->id)
->filterByDbPosition($this->getSize()-1)
@ -839,7 +843,7 @@ EOT;
return $this->$method();
}
public function setMetaData($category, $value)
public function setMetadata($category, $value)
{
$cat = $this->categories[$category];
@ -871,11 +875,20 @@ EOT;
*/
public static function deleteBlocks($p_ids, $p_userId)
{
$leftOver = self::blocksNotOwnedByUser($p_ids, $p_userId);
if (count($leftOver) == 0) {
CcBlockQuery::create()->findPKs($p_ids)->delete();
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
$user = new Application_Model_User($userInfo->id);
$isAdminOrPM = $user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER));
if (!$isAdminOrPM) {
$leftOver = self::blocksNotOwnedByUser($p_ids, $p_userId);
if (count($leftOver) == 0) {
CcBlockQuery::create()->findPKs($p_ids)->delete();
} else {
throw new BlockNoPermissionException;
}
} else {
throw new BlockNoPermissionException;
CcBlockQuery::create()->findPKs($p_ids)->delete();
}
}
@ -979,7 +992,7 @@ EOT;
public function storeCriteriaIntoDb($p_criteriaData){
// delete criteria under $p_blockId
CcBlockcriteriaQuery::create()->findByDbBlockId($this->id)->delete();
Logging::log($p_criteriaData);
Logging::info($p_criteriaData);
//insert modifier rows
if (isset($p_criteriaData['criteria'])) {
$critKeys = array_keys($p_criteriaData['criteria']);
@ -1141,10 +1154,21 @@ EOT;
// if the column is timestamp, convert it into UTC
if ($column->getType() == PropelColumnTypes::TIMESTAMP) {
$spCriteriaValue = Application_Common_DateHelper::ConvertToUtcDateTimeString($criteria['value']);
} else if($spCriteria == "bit_rate") {
/* Check if only a date was supplied and trim
* the time after it is converted to UTC time
*/
if (strlen($criteria['value']) <= 10) {
//extract date only from timestamp in db
$spCriteria = 'date('.$spCriteria.')';
$spCriteriaValue = substr($spCriteriaValue, 0, 10);
}
} else if($spCriteria == "bit_rate" || $spCriteria == 'sample_rate') {
// multiply 1000 because we store only number value
// e.g 192kps is stored as 192000
$spCriteriaValue = $criteria['value']*1000;
if (isset($criteria['extra'])) {
$criteria['extra'] *= 1000;
}
} else {
$spCriteriaValue = addslashes($criteria['value']);
}
@ -1156,7 +1180,7 @@ EOT;
} else if ($spCriteriaModifier == "contains" || $spCriteriaModifier == "does not contain") {
$spCriteriaValue = "%$spCriteriaValue%";
} else if ($spCriteriaModifier == "is in the range") {
$spCriteriaValue = "$spCriteria > '$spCriteriaValue' AND $spCriteria <= '$criteria[extra]'";
$spCriteriaValue = "$spCriteria >= '$spCriteriaValue' AND $spCriteria <= '$criteria[extra]'";
}
$spCriteriaModifier = self::$modifier2CriteriaMap[$spCriteriaModifier];
@ -1167,7 +1191,7 @@ EOT;
$qry->add($spCriteria, $spCriteriaValue, $spCriteriaModifier);
}
}catch (Exception $e){
Logging::log($e);
Logging::info($e);
}
$i++;
}
@ -1189,7 +1213,7 @@ EOT;
$out = $qry->setFormatter(ModelCriteria::FORMAT_ON_DEMAND)->find();
return array("files"=>$out, "limit"=>$limits, "count"=>$out->count());
}catch(Exception $e){
Logging::log($e);
Logging::info($e);
}
}

View File

@ -152,17 +152,21 @@ class Application_Model_Datatables
// we need to go over all items and fix length for playlist
// in case the playlist contains dynamic block
foreach ($results as &$r) {
if ($r['ftype'] == 'playlist') {
$pl = new Application_Model_Playlist($r['id']);
$r['length'] = $pl->getLength();
} else if ($r['ftype'] == "block") {
$bl = new Application_Model_Block($r['id']);
if ($bl->isStatic()) {
$r['bl_type'] = 'static';
} else {
$r['bl_type'] = 'dynamic';
//this function is also called for Manage Users so in
//this case there will be no 'ftype'
if (isset($r['ftype'])) {
if ($r['ftype'] == 'playlist') {
$pl = new Application_Model_Playlist($r['id']);
$r['length'] = $pl->getLength();
} else if ($r['ftype'] == "block") {
$bl = new Application_Model_Block($r['id']);
if ($bl->isStatic()) {
$r['bl_type'] = 'static';
} else {
$r['bl_type'] = 'dynamic';
}
$r['length'] = $bl->getLength();
}
$r['length'] = $bl->getLength();
}
}
} catch (Exception $e) {

View File

@ -0,0 +1,36 @@
<?php
class Application_Model_Library
{
public static function getObjInfo($p_type)
{
$info = array();
if (strcmp($p_type, 'playlist')==0) {
$info['className'] = 'Application_Model_Playlist';
} else if (strcmp($p_type, 'block')==0) {
$info['className'] = 'Application_Model_Block';
} else if (strcmp($p_type, 'stream')==0) {
$info['className'] = 'Application_Model_Webstream';
} else {
throw new Exception("Unknown object type: '$p_type'");
}
return $info;
}
public static function changePlaylist($p_id, $p_type)
{
$obj_sess = new Zend_Session_Namespace(UI_PLAYLISTCONTROLLER_OBJ_SESSNAME);
if (is_null($p_id) || is_null($p_type)) {
unset($obj_sess->id);
unset($obj_sess->type);
} else {
$obj_sess->id = intval($p_id);
$obj_sess->type = $p_type;
}
}
}

View File

@ -0,0 +1,10 @@
<?php
interface Application_Model_LibraryEditable
{
public function setMetadata($key, $val);
public function setName($name);
public function getLength();
public function getId();
}

View File

@ -96,7 +96,7 @@ class Application_Model_LiveLog
return $minutes;
} catch (Exception $e) {
header('HTTP/1.0 503 Service Unavailable');
Logging::log("GetLiveShowDuration - Could not connect to database.");
Logging::info("GetLiveShowDuration - Could not connect to database.");
exit;
}
}
@ -254,7 +254,7 @@ class Application_Model_LiveLog
return $minutes;
} catch (Exception $e) {
header('HTTP/1.0 503 Service Unavailable');
Logging::log("GetScheduledDuration - Could not connect to database.");
Logging::info("GetScheduledDuration - Could not connect to database.");
exit;
}
}
@ -301,7 +301,7 @@ class Application_Model_LiveLog
} catch (Exception $e) {
header('HTTP/1.0 503 Service Unavailable');
Logging::log("SetNewLogTime - Could not connect to database.");
Logging::info("SetNewLogTime - Could not connect to database.");
exit;
}
}
@ -338,7 +338,7 @@ class Application_Model_LiveLog
} catch (Exception $e) {
header('HTTP/1.0 503 Service Unavailable');
Logging::log("SetEndTime - Could not connect to database.");
Logging::info("SetEndTime - Could not connect to database.");
exit;
}
}

View File

@ -8,7 +8,7 @@ require_once 'formatters/LengthFormatter.php';
* @copyright 2010 Sourcefabric O.P.S.
* @license http://www.gnu.org/licenses/gpl.txt
*/
class Application_Model_Playlist
class Application_Model_Playlist implements Application_Model_LibraryEditable
{
/**
* propel connection object.
@ -135,8 +135,8 @@ class Application_Model_Playlist
public function getLastModified($format = null)
{
//Logging::log($this->pl->getDbMtime($format));
//Logging::log($this->pl);
//Logging::info($this->pl->getDbMtime($format));
//Logging::info($this->pl);
return $this->pl->getDbMtime($format);
}
@ -153,7 +153,7 @@ class Application_Model_Playlist
*/
public function getContents($filterFiles=false)
{
Logging::log("Getting contents for playlist {$this->id}");
Logging::info("Getting contents for playlist {$this->id}");
$files = array();
$sql = <<<SQL
@ -171,7 +171,8 @@ class Application_Model_Playlist
f.track_title,
f.artist_name AS creator,
f.file_exists AS EXISTS,
f.filepath AS path
f.filepath AS path,
f.length AS orig_length
FROM cc_playlistcontents AS pc
JOIN cc_files AS f ON pc.file_id=f.id
WHERE pc.playlist_id = {$this->id}
@ -188,7 +189,8 @@ class Application_Model_Playlist
(ws.name || ': ' || ws.url) AS title,
sub.login AS creator,
't'::boolean AS EXISTS,
ws.url AS path
ws.url AS path,
ws.length AS orig_length
FROM cc_playlistcontents AS pc
JOIN cc_webstream AS ws ON pc.stream_id=ws.id
LEFT JOIN cc_subjs AS sub ON sub.id = ws.creator_id
@ -206,7 +208,8 @@ class Application_Model_Playlist
bl.name AS title,
sbj.login AS creator,
't'::boolean AS EXISTS,
NULL::text AS path
NULL::text AS path,
bl.length AS orig_length
FROM cc_playlistcontents AS pc
JOIN cc_block AS bl ON pc.block_id=bl.id
JOIN cc_subjs AS sbj ON bl.creator_id=sbj.id
@ -240,6 +243,10 @@ SQL;
$fades = $this->getFadeInfo($row['position']);
$row['fadein'] = $fades[0];
$row['fadeout'] = $fades[1];
//format original length
$formatter = new LengthFormatter($row['orig_length']);
$row['orig_length'] = $formatter->format();
}
return $rows;
@ -270,8 +277,8 @@ SQL;
}
// returns true/false and ids of dynamic blocks
public function hasDynamicBlock(){
$ids = $this->getIdsOfDynamicBlocks();
public function hasDynamicBlock(){
$ids = $this->getIdsOfDynamicBlocks();
if (count($ids) > 0) {
return true;
} else {
@ -280,10 +287,10 @@ SQL;
}
public function getIdsOfDynamicBlocks() {
$sql = "SELECT bl.id FROM cc_playlistcontents as pc
JOIN cc_block as bl ON pc.type=2 AND pc.block_id=bl.id AND bl.type='dynamic'
WHERE playlist_id={$this->id} AND pc.type=2";
$r = $this->con->query($sql);
$sql = "SELECT bl.id FROM cc_playlistcontents as pc
JOIN cc_block as bl ON pc.type=2 AND pc.block_id=bl.id AND bl.type='dynamic'
WHERE playlist_id={$this->id} AND pc.type=2";
$r = $this->con->query($sql);
$result = $r->fetchAll(PDO::FETCH_ASSOC);
return $result;
}
@ -384,11 +391,11 @@ SQL;
try {
if (is_numeric($p_afterItem)) {
Logging::log("Finding playlist content item {$p_afterItem}");
Logging::info("Finding playlist content item {$p_afterItem}");
$afterItem = CcPlaylistcontentsQuery::create()->findPK($p_afterItem);
$index = $afterItem->getDbPosition();
Logging::log("index is {$index}");
Logging::info("index is {$index}");
$pos = ($addType == 'after') ? $index + 1 : $index;
$contentsToUpdate = CcPlaylistcontentsQuery::create()
@ -421,13 +428,13 @@ SQL;
}
Logging::log("Adding to playlist");
Logging::log("at position {$pos}");
Logging::info("Adding to playlist");
Logging::info("at position {$pos}");
foreach ($p_items as $ac) {
$res = $this->insertPlaylistElement($this->buildEntry($ac, $pos));
$res = $this->insertPlaylistElement($this->buildEntry($ac, $pos));
$pos = $pos + 1;
Logging::log("Adding $ac[1] $ac[0]");
Logging::info("Adding $ac[1] $ac[0]");
}
@ -476,32 +483,32 @@ SQL;
$pos = 0;
//moving items to beginning of the playlist.
if (is_null($p_afterItem)) {
Logging::log("moving items to beginning of playlist");
Logging::info("moving items to beginning of playlist");
foreach ($contentsToMove as $item) {
Logging::log("item {$item->getDbId()} to pos {$pos}");
Logging::info("item {$item->getDbId()} to pos {$pos}");
$item->setDbPosition($pos);
$item->save($this->con);
$pos = $pos + 1;
}
foreach ($otherContent as $item) {
Logging::log("item {$item->getDbId()} to pos {$pos}");
Logging::info("item {$item->getDbId()} to pos {$pos}");
$item->setDbPosition($pos);
$item->save($this->con);
$pos = $pos + 1;
}
} else {
Logging::log("moving items after {$p_afterItem}");
Logging::info("moving items after {$p_afterItem}");
foreach ($otherContent as $item) {
Logging::log("item {$item->getDbId()} to pos {$pos}");
Logging::info("item {$item->getDbId()} to pos {$pos}");
$item->setDbPosition($pos);
$item->save($this->con);
$pos = $pos + 1;
if ($item->getDbId() == $p_afterItem) {
foreach ($contentsToMove as $move) {
Logging::log("item {$move->getDbId()} to pos {$pos}");
Logging::info("item {$move->getDbId()} to pos {$pos}");
$move->setDbPosition($pos);
$move->save($this->con);
$pos = $pos + 1;
@ -561,7 +568,7 @@ SQL;
public function getFadeInfo($pos)
{
Logging::log("Getting fade info for pos {$pos}");
Logging::info("Getting fade info for pos {$pos}");
$row = CcPlaylistcontentsQuery::create()
->joinWith(CcFilesPeer::OM_CLASS)
@ -647,7 +654,7 @@ SQL;
public function setfades($fadein, $fadeout)
{
if (isset($fadein)) {
Logging::log("Setting playlist fade in {$fadein}");
Logging::info("Setting playlist fade in {$fadein}");
$row = CcPlaylistcontentsQuery::create()
->filterByDbPlaylistId($this->id)
->filterByDbPosition(0)
@ -657,7 +664,7 @@ SQL;
}
if (isset($fadeout)) {
Logging::log("Setting playlist fade out {$fadeout}");
Logging::info("Setting playlist fade out {$fadeout}");
$row = CcPlaylistcontentsQuery::create()
->filterByDbPlaylistId($this->id)
->filterByDbPosition($this->getSize()-1)
@ -835,7 +842,7 @@ SQL;
return $this->$method();
}
public function setMetaData($category, $value)
public function setMetadata($category, $value)
{
$cat = $this->categories[$category];
@ -867,11 +874,19 @@ SQL;
*/
public static function deletePlaylists($p_ids, $p_userId)
{
$leftOver = self::playlistsNotOwnedByUser($p_ids, $p_userId);
if (count($leftOver) == 0) {
CcPlaylistQuery::create()->findPKs($p_ids)->delete();
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
$user = new Application_Model_User($userInfo->id);
$isAdminOrPM = $user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER));
if (!$isAdminOrPM) {
$leftOver = self::playlistsNotOwnedByUser($p_ids, $p_userId);
if (count($leftOver) == 0) {
CcPlaylistQuery::create()->findPKs($p_ids)->delete();
} else {
throw new PlaylistNoPermissionException;
}
} else {
throw new PlaylistNoPermissionException;
CcPlaylistQuery::create()->findPKs($p_ids)->delete();
}
}
@ -890,13 +905,13 @@ SQL;
return $leftOvers;
}
/**
* Delete all files from playlist
* @param int $p_playlistId
*/
public function deleteAllFilesFromPlaylist()
/**
* Delete all files from playlist
* @param int $p_playlistId
*/
public function deleteAllFilesFromPlaylist()
{
CcPlaylistcontentsQuery::create()->findByDbPlaylistId($this->id)->delete();
CcPlaylistcontentsQuery::create()->findByDbPlaylistId($this->id)->delete();
}
} // class Playlist

View File

@ -66,7 +66,7 @@ class Application_Model_Preference
} catch (Exception $e) {
header('HTTP/1.0 503 Service Unavailable');
Logging::log("Could not connect to database: ".$e->getMessage());
Logging::info("Could not connect to database: ".$e->getMessage());
exit;
}
@ -107,7 +107,7 @@ class Application_Model_Preference
}
} catch (Exception $e) {
header('HTTP/1.0 503 Service Unavailable');
Logging::log("Could not connect to database: ".$e->getMessage());
Logging::info("Could not connect to database: ".$e->getMessage());
exit;
}
}

View File

@ -32,7 +32,7 @@ class Application_Model_Schedule
{
if (!is_int($p_prev) || !is_int($p_next)) {
//must enter integers to specify ranges
Logging::log("Invalid range parameters: $p_prev or $p_next");
Logging::info("Invalid range parameters: $p_prev or $p_next");
return array();
}
@ -1065,10 +1065,11 @@ SQL;
if ($update) {
$sql = "SELECT id, starts, ends FROM ".$CC_CONFIG["showInstances"]."
where ends <= '{$show_end->format('Y-m-d H:i:s')}'
and id != ".$instanceId. " order by ends";
and modified_instance = false and id != ".$instanceId. " order by ends";
} else {
$sql = "SELECT id, starts, ends FROM ".$CC_CONFIG["showInstances"]."
where ends <= '{$show_end->format('Y-m-d H:i:s')}' order by ends";
where ends <= '{$show_end->format('Y-m-d H:i:s')}'
and modified_instance = false order by ends";
}
$rows = $con->query($sql);

View File

@ -110,7 +110,7 @@ class Application_Model_Scheduler
$ts = intval($instanceInfo[$id]);
$lastSchedTs = intval($instance->getDbLastScheduled("U")) ? : 0;
if ($ts < $lastSchedTs) {
Logging::log("ts {$ts} last sched {$lastSchedTs}");
Logging::info("ts {$ts} last sched {$lastSchedTs}");
throw new OutDatedScheduleException("The show {$show->getDbName()} has been previously updated!");
}
}
@ -317,7 +317,7 @@ class Application_Model_Scheduler
*/
private function removeGaps($showInstance, $exclude=null)
{
Logging::log("removing gaps from show instance #".$showInstance);
Logging::info("removing gaps from show instance #".$showInstance);
$instance = CcShowInstancesQuery::create()->findPK($showInstance, $this->con);
if (is_null($instance)) {
@ -416,7 +416,7 @@ class Application_Model_Scheduler
} else {
$sched = new CcSchedule();
}
Logging::log($file);
Logging::info($file);
$sched->setDbStarts($nextStartDT)
->setDbEnds($endTimeDT)
->setDbCueIn($file['cuein'])

View File

@ -216,8 +216,8 @@ class Application_Model_Show
$con->commit();
} catch (Exception $e) {
$con->rollback();
Logging::log("Couldn't update schedule status.");
Logging::log($e->getMessage());
Logging::info("Couldn't update schedule status.");
Logging::info($e->getMessage());
}
Application_Model_RabbitMq::PushSchedule();
@ -277,27 +277,27 @@ class Application_Model_Show
->filterByDbShowId($this->getId())
->find();
Logging::log("Unchecked days:");
Logging::info("Unchecked days:");
foreach ($p_uncheckedDays as $day) {
Logging::log($day);
Logging::info($day);
}
foreach ($showDays as $showDay) {
//Logging::log("Local show day is: {$showDay->getDbDay()}");
//Logging::log("First show day is: {$showDay->getDbFirstShow()}");
//Logging::log("Id show days is: {$showDay->getDbId()}");
//Logging::info("Local show day is: {$showDay->getDbDay()}");
//Logging::info("First show day is: {$showDay->getDbFirstShow()}");
//Logging::info("Id show days is: {$showDay->getDbId()}");
if (in_array($showDay->getDbDay(), $p_uncheckedDays)) {
$showDay->reload();
//Logging::log("Local show day is: {$showDay->getDbDay()}");
//Logging::log("First show day is: {$showDay->getDbFirstShow()}");
//Logging::log("Id show days is: {$showDay->getDbId()}");
//Logging::info("Local show day is: {$showDay->getDbDay()}");
//Logging::info("First show day is: {$showDay->getDbFirstShow()}");
//Logging::info("Id show days is: {$showDay->getDbId()}");
$startDay = new DateTime("{$showDay->getDbFirstShow()} {$showDay->getDbStartTime()}", new DateTimeZone($showDay->getDbTimezone()));
//Logging::log("Show start day: {$startDay->format('Y-m-d H:i:s')}");
//Logging::info("Show start day: {$startDay->format('Y-m-d H:i:s')}");
$startDay->setTimezone(new DateTimeZone("UTC"));
//Logging::log("Show start day UTC: {$startDay->format('Y-m-d H:i:s')}");
//Logging::info("Show start day UTC: {$startDay->format('Y-m-d H:i:s')}");
$daysRemovedUTC[] = $startDay->format('w');
//Logging::log("UTC show day is: {$startDay->format('w')}");
//Logging::info("UTC show day is: {$startDay->format('w')}");
}
}
@ -368,7 +368,7 @@ class Application_Model_Show
."WHERE instance_id = (SELECT id FROM cc_show_instances WHERE show_id = $showId ORDER BY starts LIMIT 1) AND rebroadcast = 1 "
."ORDER BY starts";
//Logging::log($sql);
//Logging::info($sql);
$rebroadcasts = $con->query($sql)->fetchAll();
@ -1160,8 +1160,8 @@ class Application_Model_Show
$con->commit();
} catch (Exception $e) {
$con->rollback();
Logging::log("Couldn't update schedule status.");
Logging::log($e->getMessage());
Logging::info("Couldn't update schedule status.");
Logging::info($e->getMessage());
}
}
@ -1549,7 +1549,7 @@ class Application_Model_Show
$sql = $sql." AND ({$exclude})";
}
$result = $con->query($sql);
$result = $con->query($sql)->fetchAll();
return $result;
}
@ -1590,7 +1590,7 @@ class Application_Model_Show
WHERE last_show IS NULL
OR first_show < '{$endTimeString}' AND last_show > '{$startTimeString}'";
//Logging::log($sql);
//Logging::info($sql);
$res = $con->query($sql)->fetchAll();
foreach ($res as $row) {
Application_Model_Show::populateShow($row, $p_endTimestamp);
@ -1723,7 +1723,7 @@ class Application_Model_Show
$showDay->setDbFirstShow($dt)->setDbStartTime($dt)
->save();
//Logging::log("setting show's first show.");
//Logging::info("setting show's first show.");
}
/* Takes in a UTC DateTime object

View File

@ -571,9 +571,9 @@ class Application_Model_ShowInstance
$rebroad = new Application_Model_ShowInstance($rebroadcast->getDbId());
$rebroad->addFileToShow($file_id, false);
} catch (Exception $e) {
Logging::log("{$e->getFile()}");
Logging::log("{$e->getLine()}");
Logging::log("{$e->getMessage()}");
Logging::info("{$e->getFile()}");
Logging::info("{$e->getLine()}");
Logging::info("{$e->getMessage()}");
}
}
}

View File

@ -96,7 +96,7 @@ class Application_Model_StoredFile
*/
public function setMetadata($p_md=null)
{
Logging::log("entered setMetadata");
Logging::info("entered setMetadata");
if (is_null($p_md)) {
$this->setDbColMetadata();
} else {
@ -153,7 +153,7 @@ class Application_Model_StoredFile
if (isset($this->_dbMD[$dbColumn])) {
$propelColumn = $this->_dbMD[$dbColumn];
$method = "set$propelColumn";
Logging::log($method);
Logging::info($method);
$this->_file->$method($mdValue);
}
}
@ -446,7 +446,7 @@ class Application_Model_StoredFile
*/
public function getRelativeFileUrl($baseUrl)
{
Logging::log("getting media!");
Logging::info("getting media!");
return $baseUrl."/api/get-media/file/".$this->getId().".".$this->getFileExtension();
}
@ -760,7 +760,7 @@ class Application_Model_StoredFile
$chunk = isset($_REQUEST["chunk"]) ? $_REQUEST["chunk"] : 0;
$chunks = isset($_REQUEST["chunks"]) ? $_REQUEST["chunks"] : 0;
$fileName = isset($_REQUEST["name"]) ? $_REQUEST["name"] : '';
Logging::log(__FILE__.":uploadFile(): filename=$fileName to $p_targetDir");
Logging::info(__FILE__.":uploadFile(): filename=$fileName to $p_targetDir");
// Clean the fileName for security reasons
//this needs fixing for songs not in ascii.
//$fileName = preg_replace('/[^\w\._]+/', '', $fileName);
@ -852,59 +852,56 @@ class Application_Model_StoredFile
public static function copyFileToStor($p_targetDir, $fileName, $tempname)
{
$audio_file = $p_targetDir . DIRECTORY_SEPARATOR . $tempname;
Logging::log('copyFileToStor: moving file '.$audio_file);
$md5 = md5_file($audio_file);
$duplicate = Application_Model_StoredFile::RecallByMd5($md5, true);
Logging::info('copyFileToStor: moving file '.$audio_file);
$result = null;
if ($duplicate) {
if (file_exists($duplicate->getFilePath())) {
$duplicateName = $duplicate->getMetadataValue('MDATA_KEY_TITLE');
$result = array( "code" => 106, "message" => "An identical audioclip named '$duplicateName' already exists on the server.");
$storDir = Application_Model_MusicDir::getStorDir();
$stor = $storDir->getDirectory();
// check if "organize" dir exists and if not create one
if (!file_exists($stor."/organize")) {
if (!mkdir($stor."/organize", 0777)) {
return array(
"code" => 109,
"message" => "Failed to create 'organize' directory.");
}
}
if (!isset($result)) {//The file has no duplicate, so proceed to copy.
$storDir = Application_Model_MusicDir::getStorDir();
$stor = $storDir->getDirectory();
// check if "organize" dir exists and if not create one
if (!file_exists($stor."/organize")) {
if (!mkdir($stor."/organize", 0777)) {
$result = array("code" => 109, "message" => "Failed to create 'organize' directory.");
return $result;
}
}
if (chmod($audio_file, 0644) === false) {
Logging::log("Warning: couldn't change permissions of $audio_file to 0644");
}
//check to see if there is enough space in $stor to continue.
if (self::isEnoughDiskSpaceToCopy($stor, $audio_file)) {
$audio_stor = Application_Common_OsPath::join($stor, "organize", $fileName);
if (self::liquidsoapFilePlayabilityTest($audio_file)) {
Logging::log("copyFileToStor: moving file $audio_file to $audio_stor");
//Martin K.: changed to rename: Much less load + quicker since this is an atomic operation
if (@rename($audio_file, $audio_stor) === false) {
#something went wrong likely there wasn't enough space in the audio_stor to move the file too.
#warn the user that the file wasn't uploaded and they should check if there is enough disk space.
unlink($audio_file);//remove the file after failed rename
$result = array("code" => 108, "message" => "The file was not uploaded, this error can occur if the computer hard drive does not have enough disk space or the stor directory does not have correct write permissions.");
}
} else {
$result = array("code" => 110, "message" => "This file appears to be corrupted and will not be added to media library.");
}
} else {
$result = array("code" => 107, "message" => "The file was not uploaded, there is ".$freeSpace."MB of disk space left and the file you are uploading has a size of ".$fileSize."MB.");
}
if (chmod($audio_file, 0644) === false) {
Logging::info("Warning: couldn't change permissions of $audio_file to 0644");
}
return $result;
// Check if we have enough space before copying
if(!self::isEnoughDiskSpaceToCopy($stor, $audio_file)) {
$freeSpace = disk_free_space($stor);
return array("code" => 107,
"message" => "The file was not uploaded, there is
".$freeSpace."MB of disk space left and the file you are
uploading has a size of ".$fileSize."MB.");
}
// Check if liquidsoap can play this file
if(!self::liquidsoapFilePlayabilityTest($audio_file)) {
return array(
"code" => 110,
"message" => "This file appears to be corrupted and will not
be added to media library.");
}
// Did all the checks for realz, now trying to copy
$audio_stor = Application_Common_OsPath::join($stor, "organize", $fileName);
Logging::info("copyFileToStor: moving file $audio_file to $audio_stor");
//Martin K.: changed to rename: Much less load + quicker since this is an atomic operation
if (@rename($audio_file, $audio_stor) === false) {
#something went wrong likely there wasn't enough space in the audio_stor to move the file too.
#warn the user that the file wasn't uploaded and they should check if there is enough disk space.
unlink($audio_file);//remove the file after failed rename
return array(
"code" => 108,
"message" => "
The file was not uploaded, this error can occur if the computer
hard drive does not have enough disk space or the stor
directory does not have correct write permissions. ");
}
return null;
}
/*
@ -1004,7 +1001,7 @@ class Application_Model_StoredFile
return count($rows);
} catch (Exception $e) {
header('HTTP/1.0 503 Service Unavailable');
Logging::log("Could not connect to database.");
Logging::info("Could not connect to database.");
exit;
}

View File

@ -66,7 +66,7 @@ class Application_Model_StreamSetting
$ids[] = substr($row["keyname"], 0, strpos($row["keyname"], "_"));
}
//Logging::log(print_r($ids, true));
//Logging::info(print_r($ids, true));
return $ids;
}

View File

@ -224,7 +224,7 @@ class Application_Model_Systemstatus
$partitions[$totalSpace]->totalSpace = $totalSpace;
$partitions[$totalSpace]->totalFreeSpace = $totalSpace - $usedSpace;
Logging::log($partitions[$totalSpace]->totalFreeSpace);
Logging::info($partitions[$totalSpace]->totalFreeSpace);
} else {
/* First lets get all the watched directories. Then we can group them
* into the same partitions by comparing the partition sizes. */

View File

@ -32,9 +32,17 @@ class Application_Model_User
return $this->getType() == UTYPE_GUEST;
}
public function isHostOfShow($showId)
{
$userId = $this->_userInstance->getDbId();
return CcShowHostsQuery::create()
->filterByDbShow($showId)
->filterByDbHost($userId)->count() > 0;
}
public function isHost($showId)
{
return $this->isUserType(UTYPE_HOST, $showId);
return $this->isUserType(UTYPE_HOST);
}
public function isPM()
@ -61,7 +69,7 @@ class Application_Model_User
return $result;
}
public function isUserType($type, $showId='')
public function isUserType($type)
{
if (is_array($type)) {
$result = false;
@ -71,10 +79,7 @@ class Application_Model_User
$result = $this->_userInstance->getDbType() === 'A';
break;
case UTYPE_HOST:
$userId = $this->_userInstance->getDbId();
$result = CcShowHostsQuery::create()
->filterByDbShow($showId)
->filterByDbHost($userId)->count() > 0;
$result = $this->_userInstance->getDbType() === 'H';
break;
case UTYPE_PROGRAM_MANAGER:
$result = $this->_userInstance->getDbType() === 'P';
@ -89,9 +94,7 @@ class Application_Model_User
case UTYPE_ADMIN:
return $this->_userInstance->getDbType() === 'A';
case UTYPE_HOST:
$userId = $this->_userInstance->getDbId();
return CcShowHostsQuery::create()->filterByDbShow($showId)->filterByDbHost($userId)->count() > 0;
return $this->_userInstance->getDbId() === 'H';
case UTYPE_PROGRAM_MANAGER:
return $this->_userInstance->getDbType() === 'P';
}

View File

@ -1,12 +1,20 @@
<?php
class Application_Model_Webstream{
class Application_Model_Webstream implements Application_Model_LibraryEditable
{
private $id;
public function __construct($webstream)
{
//TODO: hacky...
if (is_int($webstream)) {
$this->webstream = CcWebstreamQuery::create()->findPK($webstream);
if (is_null($this->webstream)) {
throw new Exception();
}
} else {
$this->webstream = $webstream;
}
}
public function getOrm()
@ -41,6 +49,11 @@ class Application_Model_Webstream{
return "";
}
public function getLength()
{
return $this->getDefaultLength();
}
public function getDescription()
{
return $this->webstream->getDbDescription();
@ -145,15 +158,6 @@ class Application_Model_Webstream{
$id = $parameters["id"];
if (!is_null($id)) {
// user has performed a create stream action instead of edit
// stream action. Check if user has the rights to edit this stream.
Logging::log("CREATE");
} else {
Logging::log("EDIT");
}
return array($valid, $mime, $di);
}
@ -168,6 +172,18 @@ class Application_Model_Webstream{
return true;
}
public function setMetadata($key, $val)
{
}
public function setName($name)
{
}
private static function discoverStreamMime($url)
{
$headers = get_headers($url);

View File

@ -54,11 +54,11 @@
<?php
$titleMaxStrLen = 35;
if (mb_strlen($row["track_title"], 'UTF-8') > $titleMaxStrLen) {
$row["track_title"] = substr($row["track_title"], 0, 34)."...";
$row["track_title"] = mb_substr($row["track_title"], 0, 34, 'UTF-8')."...";
}
$artistMaxStrLen = 22;
if (strlen($row["creator"]) > $artistMaxStrLen) {
$row["creator"] = substr($row["creator"], 0, 21)."...";
if (mb_strlen($row["creator"], 'UTF-8') > $artistMaxStrLen) {
$row["creator"] = mb_substr($row["creator"], 0, 21, 'UTF-8')."...";
}
?>
<?php if ($row["type"] == 2) {

View File

@ -0,0 +1,19 @@
<div id="library_content" class="lib-content ui-widget ui-widget-content block-shadow alpha-block padded" style="z-index:254">
<?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">
<?php if ($this->type == 'block') {
echo $this->render('playlist/smart-block.phtml');
} else if ($this->type == 'playlist') {
echo $this->render('playlist/playlist.phtml');
} else if ($this->type == 'stream') {
echo $this->render('webstream/webstream.phtml');
} else {
echo $this->render('webstream/webstream.phtml');
//throw new Exception("Unrecognized type: '{$this->type}'");
}
?>
</div>

View File

@ -1,11 +0,0 @@
<div id="library_content" class="lib-content ui-widget ui-widget-content block-shadow alpha-block padded" style="z-index:254">
<?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">
<?php if ($this->type == 'block') {
echo $this->render('playlist/smart-block.phtml');
} else {
echo $this->render('playlist/playlist.phtml');
} ?>
</div>

View File

@ -13,7 +13,7 @@ if (isset($this->obj)) {
<?php endif; ?>
<?php if (isset($this->obj)) : ?>
<button class="ui-button ui-state-default sp-save" type="button" id="save_button">Save</button>
<button class="ui-button ui-state-default sp-save" title='Save playlist' type="button" id="save_button">Save</button>
<input id="obj_id" type="hidden" value="<?php echo $this->obj->getId(); ?>"></input>
<input id="obj_lastMod" type="hidden" value="<?php echo $this->obj->getLastModified('U'); ?>"></input>
<input id='obj_type' type='hidden' value='playlist'></input>

View File

@ -10,7 +10,7 @@ if (isset($this->obj)) {
<a href="#" id="spl_crossfade" class="ui-button ui-button-icon-only ui-widget ui-state-default crossfade-main-button" style="display:<?php echo ($this->obj->isStatic() && $count > 0) ?"block;":"none;"?>">
<span class="ui-icon crossfade-main-icon"></span><span class="ui-button-text">Playlist crossfade</span>
</a>
<button class="ui-button ui-state-default sp-save" type="button" id="save_button">Save</button>
<button class="ui-button ui-state-default sp-save" title='Save smart block&#39s title, description, and criteria' type="button" id="save_button">Save</button>
<?php endif; ?>
<?php if (isset($this->obj)) : ?>

View File

@ -55,7 +55,7 @@ if ($item['type'] == 2) {
'id' => $item["id"],
'cueIn' => $item['cuein'],
'cueOut' => $item['cueout'],
'origLength' => $item['length'])); ?>
'origLength' => $item['orig_length'])); ?>
</div>
<?php }?>

View File

@ -1,18 +1,20 @@
<button id="ws_new" class="ui-button ui-widget ui-state-default" role="button" aria-disabled="false">New</button>
<?php if (isset($this->ws)) : ?>
<?php if (isset($this->obj)) : ?>
<button id="ws_delete" class="ui-button ui-widget ui-state-default" <?php if ($this->action == "new"): ?>style="display:none;"<?php endif; ?> role="button" aria-disabled="false">Delete</button>
<?php endif; ?>
<?php if (isset($this->ws)) : ?>
<input id="ws_id" type="hidden" value="<?php echo $this->ws->getId(); ?>"></input>
<input id="pl_lastMod" type="hidden" value="<?php echo $this->ws->getLastModified('U'); ?>"></input>
<?php if (isset($this->obj)) : ?>
<input id="obj_id" type="hidden" value="<?php echo $this->obj->getId(); ?>"></input>
<input id="obj_lastMod" type="hidden" value="<?php echo "1";//$this->obj->getLastModified('U'); ?>"></input>
<input id="obj_type" type="hidden" value="webstream"></input>
<div class="status" style="display:none;"></div>
<div class="playlist_title">
<div id="name-error" class="errors" style="display:none;"></div>
<h3 id="ws_name">
<a id="playlist_name_display" contenteditable="true"><?php echo $this->ws->getName(); ?></a>
<a id="playlist_name_display" contenteditable="true"><?php echo $this->obj->getName(); ?></a>
</h3>
<h4 id="ws_length"><?php echo $this->ws->getDefaultLength(); ?></h4>
<h4 id="ws_length"><?php echo $this->obj->getDefaultLength(); ?></h4>
</div>
<fieldset class="toggle" id="fieldset-metadate_change">
@ -20,18 +22,18 @@
<dl class="zend_form">
<dt id="description-label"><label for="description">Description</label></dt>
<dd id="description-element">
<textarea cols="80" rows="24" id="description" name="description"><?php echo $this->ws->getDescription(); ?></textarea>
<textarea cols="80" rows="24" id="description" name="description"><?php echo $this->obj->getDescription(); ?></textarea>
</dd>
<dt id="submit-label" style="display: none;">&nbsp;</dt>
<div id="url-error" class="errors" style="display:none;"></div>
<dt id="streamurl-label"><label for="streamurl">Stream URL:</label></dt>
<dd id="streamurl-element">
<input type="text" value="<?php echo $this->ws->getUrl(); ?>" size="40"/>
<input type="text" value="<?php echo $this->obj->getUrl(); ?>" size="40"/>
</dd>
<div id="length-error" class="errors" style="display:none;"></div>
<dt id="streamlength-label"><label for="streamlength">Default Length:</label></dt>
<dd id="streamlength-element">
<input type="text" value="<?php echo $this->ws->getDefaultLength() ?>"/>
<input type="text" value="<?php echo $this->obj->getDefaultLength() ?>"/>
</dd>
<dd id="submit-element" class="buttons">
<input class="ui-button ui-state-default" type="submit" value="Save" id="webstream_save" name="submit">

View File

@ -440,31 +440,37 @@ table.library-get-file-md{
table.library-get-file-md.table-small{
width: 290px !important;
}
}
.file-md-qtip-nowrap{
white-space: nowrap;
overflow: hidden;
}
.file-md-qtip-criteria-width-small{
width:70px;
max-width: 70px;
}
.file-md-qtip-criteria-width{
width:110px;
max-width: 110px;
}
.file-md-qtip-row-width-title{
width:170px;
max-width: 170px;
padding-right:5px !important;
}
.file-md-qtip-row-width-artist{
width:110px;
max-width: 110px;
}
.file-md-qtip-row-width-small{
width:40x;
max-width: 40px;
text-align:right;
}

View File

@ -6,7 +6,7 @@ var AIRTIME = (function(AIRTIME){
if (AIRTIME.playlist === undefined) {
AIRTIME.playlist = {};
}
}
var mod = AIRTIME.playlist,
viewport,
@ -300,7 +300,7 @@ var AIRTIME = (function(AIRTIME){
.empty()
.val(json.description);
$('#spl_sortable').unbind();
$('#spl_sortable').off('focusout keydown');
$('#spl_sortable')
.empty()
.append(json.html);
@ -423,20 +423,20 @@ var AIRTIME = (function(AIRTIME){
//sets events dynamically for the cue editor.
function setCueEvents() {
var temp = $('#spl_sortable');
temp.on("blur", ".spl_cue_in span", changeCueIn);
temp.on("focusout", ".spl_cue_in span", changeCueIn);
temp.on("keydown", ".spl_cue_in span", submitOnEnter);
temp.on("blur", ".spl_cue_out span", changeCueOut);
temp.on("focusout", ".spl_cue_out span", changeCueOut);
temp.on("keydown", ".spl_cue_out span", submitOnEnter);
}
//sets events dynamically for the fade editor.
function setFadeEvents() {
var temp = $('#spl_sortable');
temp.on("blur", ".spl_fade_in span", changeFadeIn);
temp.on("focusout", ".spl_fade_in span", changeFadeIn);
temp.on("keydown", ".spl_fade_in span", submitOnEnter);
temp.on("blur", ".spl_fade_out span", changeFadeOut);
temp.on("focusout", ".spl_fade_out span", changeFadeOut);
temp.on("keydown", ".spl_fade_out span", submitOnEnter);
}
@ -568,7 +568,7 @@ var AIRTIME = (function(AIRTIME){
//stream url
//default_length
//playlist name
var id = $pl.find("#ws_id").attr("value");
var id = $pl.find("#obj_id").attr("value");
var description = $pl.find("#description").val();
var streamurl = $pl.find("#streamurl-element input").val();
var length = $pl.find("#streamlength-element input").val();
@ -596,7 +596,7 @@ var AIRTIME = (function(AIRTIME){
$status.show();
setTimeout(function(){$status.fadeOut("slow", function(){$status.empty()})}, 5000);
var $ws_id = $("#ws_id");
var $ws_id = $("#obj_id");
$ws_id.attr("value", json.streamId);
var $ws_id = $("#ws_delete");
@ -802,6 +802,23 @@ var AIRTIME = (function(AIRTIME){
redrawLib();
});
};
mod.fnWsDelete = function(wsid) {
var url, id, lastMod;
stopAudioPreview();
id = (wsid === undefined) ? getId() : wsid;
lastMod = getModified();
type = $('#obj_type').val();
url = '/Webstream/delete';
$.post(url,
{format: "json", ids: id, modified: lastMod, type: type},
function(json){
openPlaylist(json);
redrawLib();
});
};
mod.disableUI = function() {
@ -903,6 +920,10 @@ var AIRTIME = (function(AIRTIME){
$pl.delegate("#spl_delete", {"click": function(ev){
AIRTIME.playlist.fnDelete();
}});
$pl.delegate("#ws_delete", {"click": function(ev){
AIRTIME.playlist.fnWsDelete();
}});
setPlaylistEntryEvents();
setCueEvents();

View File

@ -458,7 +458,7 @@ function callback(data, type) {
if (type == 'shuffle') {
form.find('.success').text('Smart block shuffled');
} else if (type == 'generate') {
form.find('.success').text('Smart block generated and saved');
form.find('.success').text('Smart block generated and criteria saved');
//redraw library table so the length gets updated
dt.fnStandingRedraw();
}

View File

@ -1,3 +1,3 @@
<?php
define('AIRTIME_VERSION', '2.1.3');
define('AIRTIME_VERSION', '2.2.0');

View File

@ -21,8 +21,8 @@ if (!file_exists('/etc/airtime/airtime.conf')) {
}
require_once(AirtimeInstall::GetAirtimeSrcDir()."/application/configs/db-conf.php");
require_once('propel/runtime/lib/Propel.php');
Propel::init(AirtimeInstall::GetAirtimeSrcDir()."/application/configs/airtime-conf-production.php");
require_once('propel/runtime/lib/Propel.php');
Propel::init(AirtimeInstall::GetAirtimeSrcDir()."/application/configs/airtime-conf-production.php");
$version = AirtimeInstall::GetVersionInstalled();

View File

@ -1,4 +1,4 @@
DELETE FROM cc_pref WHERE keystr = 'system_version';
INSERT INTO cc_pref (keystr, valstr) VALUES ('system_version', '2.1.3');
INSERT INTO cc_pref (keystr, valstr) VALUES ('system_version', '2.2.0');
UPDATE cc_show_instances SET time_filled='00:00:00' WHERE time_filled IS NULL;

View File

@ -3,22 +3,22 @@
* creating connections to a database, backing up config files etc.
*/
class UpgradeCommon{
const CONF_FILE_AIRTIME = "/etc/airtime/airtime.conf";
const CONF_FILE_PYPO = "/etc/airtime/pypo.cfg";
const CONF_FILE_LIQUIDSOAP = "/etc/airtime/liquidsoap.cfg";
const CONF_FILE_AIRTIME = "/etc/airtime/airtime.conf";
const CONF_FILE_PYPO = "/etc/airtime/pypo.cfg";
const CONF_FILE_LIQUIDSOAP = "/etc/airtime/liquidsoap.cfg";
const CONF_FILE_MEDIAMONITOR = "/etc/airtime/media-monitor.cfg";
const CONF_FILE_API_CLIENT = "/etc/airtime/api_client.cfg";
const CONF_FILE_API_CLIENT = "/etc/airtime/api_client.cfg";
const CONF_PYPO_GRP = "pypo";
const CONF_WWW_DATA_GRP = "www-data";
const CONF_BACKUP_SUFFIX = "220";
const VERSION_NUMBER = "2.2.0";
const CONF_PYPO_GRP = "pypo";
const CONF_WWW_DATA_GRP = "www-data";
const CONF_BACKUP_SUFFIX = "220";
const VERSION_NUMBER = "2.2.0";
public static function SetDefaultTimezone()
{
$sql = "SELECT valstr from cc_pref WHERE keystr = 'timezone'";
$result = self::queryDb($sql);
$result = self::queryDb($sql);
$timezone = $result->fetchColumn();
date_default_timezone_set($timezone);
@ -86,14 +86,16 @@ class UpgradeCommon{
$configFiles = array(UpgradeCommon::CONF_FILE_AIRTIME,
UpgradeCommon::CONF_FILE_PYPO,
UpgradeCommon::CONF_FILE_LIQUIDSOAP,
//this is not necessary because liquidsoap configs
//are automatically generated
//UpgradeCommon::CONF_FILE_LIQUIDSOAP,
UpgradeCommon::CONF_FILE_MEDIAMONITOR,
UpgradeCommon::CONF_FILE_API_CLIENT);
// Backup the config files
$suffix = date("Ymdhis")."-".UpgradeCommon::VERSION_NUMBER;
foreach ($configFiles as $conf) {
// do not back up monit cfg
// do not back up monit cfg -- ok?? not being done anyway
if (file_exists($conf)) {
echo "Backing up $conf to $conf$suffix.bak".PHP_EOL;
//copy($conf, $conf.$suffix.".bak");
@ -118,31 +120,27 @@ class UpgradeCommon{
}
}
if (!copy(__DIR__."/../etc/airtime.conf.$suffix", self::CONF_FILE_AIRTIME)){
echo "Could not copy airtime.conf to /etc/airtime/. Exiting.";
exit(1);
}
if (!copy(__DIR__."/../etc/pypo.cfg.$suffix", self::CONF_FILE_PYPO)){
echo "Could not copy pypo.cfg to /etc/airtime/. Exiting.";
exit(1);
}
if (!copy(__DIR__."/../etc/media-monitor.cfg.$suffix", self::CONF_FILE_MEDIAMONITOR)){
echo "Could not copy meadia-monitor.cfg to /etc/airtime/. Exiting.";
exit(1);
}
if (!copy(__DIR__."/../etc/api_client.cfg.$suffix", self::CONF_FILE_API_CLIENT)){
echo "Could not copy api_client.cfg to /etc/monit/conf.d/. Exiting.";
exit(1);
$config_copy = array(
"../etc/airtime.conf" => self::CONF_FILE_AIRTIME,
"../etc/pypo.cfg" => self::CONF_FILE_PYPO,
"../etc/media-monitor.cfg" => self::CONF_FILE_MEDIAMONITOR,
"../etc/api_client.cfg" => self::CONF_FILE_API_CLIENT
);
echo "Copying configs:\n";
foreach ($config_copy as $path_part => $destination) {
$full_path = OsPath::normpath(OsPath::join(__DIR__,
"$path_part.$suffix"));
echo "'$full_path' --> '$destination'\n";
if(!copy($full_path, $destination)) {
echo "Failed on the copying operation above\n";
exit(1);
}
}
}
private static function MergeConfigFiles($configFiles, $suffix) {
private static function MergeConfigFiles(array $configFiles, $suffix) {
foreach ($configFiles as $conf) {
// we want to use new liquidsoap.cfg so don't merge
// also for monit
if( $conf == self::CONF_FILE_LIQUIDSOAP){
continue;
}
if (file_exists("$conf$suffix.bak")) {
if($conf === self::CONF_FILE_AIRTIME) {
@ -212,11 +210,11 @@ class UpgradeCommon{
private static function UpdateIniValue($p_filename, $p_property, $p_value)
{
$lines = file($p_filename);
$n=count($lines);
$n = count($lines);
foreach ($lines as &$line) {
if ($line[0] != "#"){
$key_value = explode("=", $line);
$key = trim($key_value[0]);
$key = trim($key_value[0]);
if ($key == $p_property){
$line = "$p_property = $p_value".PHP_EOL;
@ -244,3 +242,69 @@ class UpgradeCommon{
return $result;
}
}
class OsPath {
// this function is from http://stackoverflow.com/questions/2670299/is-there-a-php-equivalent-function-to-the-python-os-path-normpath
public static function normpath($path)
{
if (empty($path))
return '.';
if (strpos($path, '/') === 0)
$initial_slashes = true;
else
$initial_slashes = false;
if (
($initial_slashes) &&
(strpos($path, '//') === 0) &&
(strpos($path, '///') === false)
)
$initial_slashes = 2;
$initial_slashes = (int) $initial_slashes;
$comps = explode('/', $path);
$new_comps = array();
foreach ($comps as $comp)
{
if (in_array($comp, array('', '.')))
continue;
if (
($comp != '..') ||
(!$initial_slashes && !$new_comps) ||
($new_comps && (end($new_comps) == '..'))
)
array_push($new_comps, $comp);
elseif ($new_comps)
array_pop($new_comps);
}
$comps = $new_comps;
$path = implode('/', $comps);
if ($initial_slashes)
$path = str_repeat('/', $initial_slashes) . $path;
if ($path)
return $path;
else
return '.';
}
/* Similar to the os.path.join python method
* http://stackoverflow.com/a/1782990/276949 */
public static function join() {
$args = func_get_args();
$paths = array();
foreach($args as $arg) {
$paths = array_merge($paths, (array)$arg);
}
foreach($paths as &$path) {
$path = trim($path, DIRECTORY_SEPARATOR);
}
if (substr($args[0], 0, 1) == DIRECTORY_SEPARATOR) {
$paths[0] = DIRECTORY_SEPARATOR . $paths[0];
}
return join(DIRECTORY_SEPARATOR, $paths);
}
}

View File

@ -0,0 +1,2 @@
DELETE FROM cc_pref WHERE keystr = 'system_version';
INSERT INTO cc_pref (keystr, valstr) VALUES ('system_version', '2.2.0');

View File

@ -0,0 +1,31 @@
[database]
host = localhost
dbname = airtime
dbuser = airtime
dbpass = airtime
[rabbitmq]
host = 127.0.0.1
port = 5672
user = guest
password = guest
vhost = /
[general]
api_key = AAA
web_server_user = www-data
airtime_dir = x
base_url = localhost
base_port = 80
;How many hours ahead of time should Airtime playout engine (PYPO)
;cache scheduled media files.
cache_ahead_hours = 1
[monit]
monit_user = guest
monit_password = airtime
[soundcloud]
connection_retries = 3
time_between_retries = 60

View File

@ -0,0 +1,119 @@
bin_dir = "/usr/lib/airtime/api_clients"
#############################
## Common
#############################
# Value needed to access the API
api_key = 'AAA'
# Path to the base of the API
api_base = 'api'
# URL to get the version number of the server API
version_url = 'version/api_key/%%api_key%%'
#URL to register a components IP Address with the central web server
register_component = 'register-component/format/json/api_key/%%api_key%%/component/%%component%%'
# Hostname
base_url = 'localhost'
base_port = 80
#############################
## Config for Media Monitor
#############################
# URL to setup the media monitor
media_setup_url = 'media-monitor-setup/format/json/api_key/%%api_key%%'
# Tell Airtime the file id associated with a show instance.
upload_recorded = 'upload-recorded/format/json/api_key/%%api_key%%/fileid/%%fileid%%/showinstanceid/%%showinstanceid%%'
# URL to tell Airtime to update file's meta data
update_media_url = 'reload-metadata/format/json/api_key/%%api_key%%/mode/%%mode%%'
# URL to tell Airtime we want a listing of all files it knows about
list_all_db_files = 'list-all-files/format/json/api_key/%%api_key%%/dir_id/%%dir_id%%'
# URL to tell Airtime we want a listing of all dirs its watching (including the stor dir)
list_all_watched_dirs = 'list-all-watched-dirs/format/json/api_key/%%api_key%%'
# URL to tell Airtime we want to add watched directory
add_watched_dir = 'add-watched-dir/format/json/api_key/%%api_key%%/path/%%path%%'
# URL to tell Airtime we want to add watched directory
remove_watched_dir = 'remove-watched-dir/format/json/api_key/%%api_key%%/path/%%path%%'
# URL to tell Airtime we want to add watched directory
set_storage_dir = 'set-storage-dir/format/json/api_key/%%api_key%%/path/%%path%%'
# URL to tell Airtime about file system mount change
update_fs_mount = 'update-file-system-mount/format/json/api_key/%%api_key%%'
# URL to commit multiple updates from media monitor at the same time
reload_metadata_group = 'reload-metadata-group/format/json/api_key/%%api_key%%'
# URL to tell Airtime about file system mount change
handle_watched_dir_missing = 'handle-watched-dir-missing/format/json/api_key/%%api_key%%/dir/%%dir%%'
#############################
## Config for Recorder
#############################
# URL to get the schedule of shows set to record
show_schedule_url = 'recorded-shows/format/json/api_key/%%api_key%%'
# URL to upload the recorded show's file to Airtime
upload_file_url = 'upload-file/format/json/api_key/%%api_key%%'
# URL to commit multiple updates from media monitor at the same time
#number of retries to upload file if connection problem
upload_retries = 3
#time to wait between attempts to upload file if connection problem (in seconds)
upload_wait = 60
################################################################################
# Uncomment *one of the sets* of values from the API clients below, and comment
# out all the others.
################################################################################
#############################
## Config for Pypo
#############################
# Schedule export path.
# %%from%% - starting date/time in the form YYYY-MM-DD-hh-mm
# %%to%% - starting date/time in the form YYYY-MM-DD-hh-mm
export_url = 'schedule/api_key/%%api_key%%'
get_media_url = 'get-media/file/%%file%%/api_key/%%api_key%%'
# Update whether a schedule group has begun playing.
update_item_url = 'notify-schedule-group-play/api_key/%%api_key%%/schedule_id/%%schedule_id%%'
# Update whether an audio clip is currently playing.
update_start_playing_url = 'notify-media-item-start-play/api_key/%%api_key%%/media_id/%%media_id%%/schedule_id/%%schedule_id%%'
# URL to tell Airtime we want to get stream setting
get_stream_setting = 'get-stream-setting/format/json/api_key/%%api_key%%/'
#URL to update liquidsoap status
update_liquidsoap_status = 'update-liquidsoap-status/format/json/api_key/%%api_key%%/msg/%%msg%%/stream_id/%%stream_id%%/boot_time/%%boot_time%%'
#URL to check live stream auth
check_live_stream_auth = 'check-live-stream-auth/format/json/api_key/%%api_key%%/username/%%username%%/password/%%password%%/djtype/%%djtype%%'
#URL to update source status
update_source_status = 'update-source-status/format/json/api_key/%%api_key%%/sourcename/%%sourcename%%/status/%%status%%'
get_bootstrap_info = 'get-bootstrap-info/format/json/api_key/%%api_key%%'
get_files_without_replay_gain = 'get-files-without-replay-gain/api_key/%%api_key%%/dir_id/%%dir_id%%'
update_replay_gain_value = 'update-replay-gain-value/api_key/%%api_key%%'
notify_webstream_data = 'notify-webstream-data/api_key/%%api_key%%/media_id/%%media_id%%/format/json'

View File

@ -0,0 +1,31 @@
api_client = "airtime"
# where the binary files live
bin_dir = '/usr/lib/airtime/media-monitor'
# where the logging files live
log_dir = '/var/log/airtime/media-monitor'
############################################
# RabbitMQ settings #
############################################
rabbitmq_host = 'localhost'
rabbitmq_user = 'guest'
rabbitmq_password = 'guest'
rabbitmq_vhost = '/'
############################################
# Media-Monitor preferences #
############################################
check_filesystem_events = 5 #how long to queue up events performed on the files themselves.
check_airtime_events = 30 #how long to queue metadata input from airtime.
# MM2 only:
touch_interval = 5
chunking_number = 450
request_max_wait = 3.0
rmq_event_wait = 0.1
logpath = '/var/log/airtime/media-monitor/media-monitor.log'
index_path = '/var/tmp/airtime/media-monitor/last_index'

View File

@ -0,0 +1,85 @@
############################################
# pypo - configuration #
############################################
# Set the type of client you are using.
# Currently supported types:
# 1) "obp" = Open Broadcast Platform
# 2) "airtime"
#
api_client = "airtime"
############################################
# Cache Directories #
# *include* trailing slash !! #
############################################
cache_dir = '/var/tmp/airtime/pypo/cache/'
file_dir = '/var/tmp/airtime/pypo/files/'
tmp_dir = '/var/tmp/airtime/pypo/tmp/'
############################################
# Setup Directories #
# Do *not* include trailing slash !! #
############################################
cache_base_dir = '/var/tmp/airtime/pypo'
bin_dir = '/usr/lib/airtime/pypo'
log_base_dir = '/var/log/airtime'
pypo_log_dir = '/var/log/airtime/pypo'
liquidsoap_log_dir = '/var/log/airtime/pypo-liquidsoap'
############################################
# Liquidsoap settings #
############################################
ls_host = '127.0.0.1'
ls_port = '1234'
############################################
# RabbitMQ settings #
############################################
rabbitmq_host = 'localhost'
rabbitmq_user = 'guest'
rabbitmq_password = 'guest'
rabbitmq_vhost = '/'
############################################
# pypo preferences #
############################################
# Poll interval in seconds.
#
# This will rarely need to be changed because any schedule changes are
# automatically sent to pypo immediately.
#
# This is how often the poll script downloads new schedules and files from the
# server in the event that no changes are made to the schedule.
#
poll_interval = 3600 # in seconds.
# Push interval in seconds.
#
# This is how often the push script checks whether it has something new to
# push to liquidsoap.
#
# It's hard to imagine a situation where this should be more than 1 second.
#
push_interval = 1 # in seconds
# 'pre' or 'otf'. 'pre' cues while playlist preparation
# while 'otf' (on the fly) cues while loading into ls
# (needs the post_processor patch)
cue_style = 'pre'
############################################
# Recorded Audio settings #
############################################
record_bitrate = 256
record_samplerate = 44100
record_channels = 2
record_sample_size = 16
#can be either ogg|mp3, mp3 recording requires installation of the package "lame"
record_file_type = 'ogg'
# base path to store recordered shows at
base_recorded_files = '/var/tmp/airtime/show-recorder/'

View File

@ -18,7 +18,7 @@ from configobj import ConfigObj
import string
import traceback
AIRTIME_VERSION = "2.1.3"
AIRTIME_VERSION = "2.2.0"
def to_unicode(obj, encoding='utf-8'):
if isinstance(obj, basestring):

View File

@ -57,6 +57,7 @@ class EventContractor(Loggable):
def __unregister(self, evt):
try: del self.store[evt.path]
except Exception as e:
self.unexpected_exception(e)
self.logger.info("Unregistering. Left: '%d'" % len(self.store.keys()))
except KeyError as e:
self.logger.info("Contractor failed to unrecord event: '%s'" \
% evt.path)
except Exception as e: self.unexpected_exception(e)

View File

@ -105,10 +105,38 @@ class Metadata(Loggable):
# little bit messy. Some of the handling is in m.m.pure while the rest is
# here. Also interface is not very consistent
@staticmethod
def airtime_dict(d):
"""
Converts mutagen dictionary 'd' into airtime dictionary
"""
temp_dict = {}
for m_key, m_val in d.iteritems():
# TODO : some files have multiple fields for the same metadata.
# genre is one example. In that case mutagen will return a list
# of values
assign_val = m_val[0] if isinstance(m_val, list) else m_val
temp_dict[ m_key ] = assign_val
airtime_dictionary = {}
for muta_k, muta_v in temp_dict.iteritems():
# We must check if we can actually translate the mutagen key into
# an airtime key before doing the conversion
if muta_k in mutagen2airtime:
airtime_key = mutagen2airtime[muta_k]
# Apply truncation in the case where airtime_key is in our
# truncation table
muta_v = \
truncate_to_length(muta_v, truncate_table[airtime_key])\
if airtime_key in truncate_table else muta_v
airtime_dictionary[ airtime_key ] = muta_v
return airtime_dictionary
@staticmethod
def write_unsafe(path,md):
"""
Writes 'md' metadata into 'path' through mutagen
Writes 'md' metadata into 'path' through mutagen. Converts all
dictionary values to strings because mutagen will not write anything
else
"""
if not os.path.exists(path): raise BadSongFile(path)
song_file = mutagen.File(path, easy=True)
@ -126,39 +154,20 @@ class Metadata(Loggable):
try : full_mutagen = mutagen.File(fpath, easy=True)
except Exception : raise BadSongFile(fpath)
self.path = fpath
if not os.path.exists(self.path):
self.logger.info("Attempting to read metadata of file \
that does not exist. Setting metadata to {}")
self.__metadata = {}
return
# TODO : Simplify the way all of these rules are handled right not it's
# extremely unclear and needs to be refactored.
metadata = {}
# Load only the metadata avilable in mutagen into metdata
for k,v in full_mutagen.iteritems():
# Special handling of attributes here
if isinstance(v, list):
# TODO : some files have multiple fields for the same metadata.
# genre is one example. In that case mutagen will return a list
# of values
metadata[k] = v[0]
#if len(v) == 1: metadata[k] = v[0]
#else: raise Exception("Unknown mutagen %s:%s" % (k,str(v)))
else: metadata[k] = v
self.__metadata = {}
# Start populating a dictionary of airtime metadata in __metadata
for muta_k, muta_v in metadata.iteritems():
# We must check if we can actually translate the mutagen key into
# an airtime key before doing the conversion
if muta_k in mutagen2airtime:
airtime_key = mutagen2airtime[muta_k]
# Apply truncation in the case where airtime_key is in our
# truncation table
muta_v = \
truncate_to_length(muta_v, truncate_table[airtime_key])\
if airtime_key in truncate_table else muta_v
self.__metadata[ airtime_key ] = muta_v
self.__metadata = Metadata.airtime_dict(full_mutagen)
# Now we extra the special values that are calculated from the mutagen
# object itself:
for special_key,f in airtime_special.iteritems():
new_val = f(full_mutagen)
if new_val is not None:
self.__metadata[special_key] = f(full_mutagen)
self.__metadata[special_key] = new_val
# Finally, we "normalize" all the metadata here:
self.__metadata = mmp.normalized_metadata(self.__metadata, fpath)
# Now we must load the md5:

View File

@ -2,6 +2,7 @@
import copy
import os
import shutil
import re
import sys
import hashlib
import locale
@ -82,6 +83,7 @@ def is_file_supported(path):
# TODO : In the future we would like a better way to find out whether a show
# has been recorded
def is_airtime_recorded(md):
if not 'MDATA_KEY_CREATOR' in md: return False
return md['MDATA_KEY_CREATOR'] == u'Airtime Show Recorder'
def clean_empty_dirs(path):
@ -228,34 +230,33 @@ def normalized_metadata(md, original_path):
# Specific rules that are applied in a per attribute basis
format_rules = {
'MDATA_KEY_TRACKNUMBER' : parse_int,
'MDATA_KEY_BITRATE' : lambda x: str(int(x) / 1000) + "kbps",
'MDATA_KEY_FILEPATH' : lambda x: os.path.normpath(x),
'MDATA_KEY_MIME' : lambda x: x.replace('-','/'),
'MDATA_KEY_BPM' : lambda x: x[0:8],
}
new_md = remove_whitespace(new_md)
new_md = remove_whitespace(new_md) # remove whitespace fields
# Format all the fields in format_rules
new_md = apply_rules_dict(new_md, format_rules)
new_md = default_to(dictionary=new_md, keys=['MDATA_KEY_TITLE'],
default=no_extension_basename(original_path))
new_md = default_to(dictionary=new_md, keys=['MDATA_KEY_CREATOR',
'MDATA_KEY_SOURCE'], default=u'')
# set filetype to audioclip by default
new_md = default_to(dictionary=new_md, keys=['MDATA_KEY_FTYPE'],
default=u'audioclip')
# In the case where the creator is 'Airtime Show Recorder' we would like to
# format the MDATA_KEY_TITLE slightly differently
# Note: I don't know why I'm doing a unicode string comparison here
# that part is copied from the original code
# Try to parse bpm but delete the whole key if that fails
if 'MDATA_KEY_BPM' in new_md:
new_md['MDATA_KEY_BPM'] = parse_int(new_md['MDATA_KEY_BPM'])
if new_md['MDATA_KEY_BPM'] is None:
del new_md['MDATA_KEY_BPM']
if is_airtime_recorded(new_md):
hour,minute,second,name = md['MDATA_KEY_TITLE'].split("-",3)
# We assume that MDATA_KEY_YEAR is always given for airtime recorded
# shows
hour,minute,second,name = new_md['MDATA_KEY_TITLE'].split("-",3)
new_md['MDATA_KEY_TITLE'] = u'%s-%s-%s:%s:%s' % \
(name, new_md['MDATA_KEY_YEAR'], hour, minute, second)
# IMPORTANT: in the original code. MDATA_KEY_FILEPATH would also
# be set to the original path of the file for airtime recorded shows
# (before it was "organized"). We will skip this procedure for now
# because it's not clear why it was done
else:
# Read title from filename if it does not exist
new_md = default_to(dictionary=new_md, keys=['MDATA_KEY_TITLE'],
default=no_extension_basename(original_path))
return new_md
def organized_path(old_path, root_path, orig_md):
@ -274,15 +275,26 @@ def organized_path(old_path, root_path, orig_md):
if key in dictionary: return len(dictionary[key]) == 0
else: return True
# We set some metadata elements to a default "unknown" value because we use
# these fields to create a path hence they cannot be empty
# these fields to create a path hence they cannot be empty Here "normal"
# means normalized only for organized path
# MDATA_KEY_BITRATE is in bytes/second i.e. (256000) we want to turn this
# into 254kbps
normal_md = default_to_f(orig_md, path_md, unicode_unknown, default_f)
if normal_md['MDATA_KEY_BITRATE']:
formatted = str(int(normal_md['MDATA_KEY_BITRATE']) / 1000)
normal_md['MDATA_KEY_BITRATE'] = formatted + 'kbps'
else: normal_md['MDATA_KEY_BITRATE'] = unicode_unknown
if is_airtime_recorded(normal_md):
fname = u'%s-%s-%s.%s' % ( normal_md['MDATA_KEY_YEAR'],
normal_md['MDATA_KEY_TITLE'],
normal_md['MDATA_KEY_BITRATE'], ext )
yyyy, mm, _ = normal_md['MDATA_KEY_YEAR'].split('-',3)
path = os.path.join(root_path, yyyy, mm)
filepath = os.path.join(path,fname)
title_re = re.match("(?P<show>\w+)-(?P<date>\d+-\d+-\d+-\d+:\d+:\d+)$",
normal_md['MDATA_KEY_TITLE'])
show_name, = title_re.group('show'),
date = title_re.group('date').replace(':','-')
yyyy, mm, _ = normal_md['MDATA_KEY_YEAR'].split('-',2)
fname_base = '%s-%s-%s.%s' % \
(date, show_name, normal_md['MDATA_KEY_BITRATE'], ext)
filepath = os.path.join(root_path, yyyy, mm, fname_base)
elif len(normal_md['MDATA_KEY_TRACKNUMBER']) == 0:
fname = u'%s-%s.%s' % (normal_md['MDATA_KEY_TITLE'],
normal_md['MDATA_KEY_BITRATE'], ext)

View File

@ -127,6 +127,8 @@ def main(global_config, api_client_config, log_config,
tt = ToucherThread(path=config['index_path'],
interval=int(config['touch_interval']))
apiclient.register_component('media-monitor')
pyi = manager.pyinotify()
pyi.loop()

View File

@ -41,7 +41,6 @@ class TestMMP(unittest.TestCase):
self.assertTrue( isinstance(morphed, DeleteFile) )
delete_ev = e1.safe_pack()[0]
print( ev.store )
self.assertEqual( delete_ev['mode'], u'delete')
self.assertTrue( len(ev.store.keys()) == 0 )
@ -65,6 +64,5 @@ class TestMMP(unittest.TestCase):
actual_events.append(e)
self.assertEqual( len(ev.store.keys()), 1 )
packed = [ x.safe_pack() for x in actual_events ]
print(packed)
if __name__ == '__main__': unittest.main()

View File

@ -2,6 +2,7 @@
import unittest
import os
import media.monitor.pure as mmp
from media.monitor.metadata import Metadata
class TestMMP(unittest.TestCase):
def setUp(self):
@ -34,23 +35,32 @@ class TestMMP(unittest.TestCase):
for k in def_keys: self.assertEqual( sd[k], 'DEF' )
def test_normalized_metadata(self):
normal = mmp.normalized_metadata(self.md1,"")
self.assertTrue(hasattr(normal['MDATA_KEY_CREATOR'],'startswith'))
self.assertTrue('MDATA_KEY_CREATOR' in normal)
self.assertTrue('MDATA_KEY_SOURCE' in normal)
# Recorded show test first
orig = Metadata.airtime_dict({
'date' : [u'2012-08-21'],
'tracknumber' : [u'2'],
'title' : [u'11-29-00-record'],
'artist' : [u'Airtime Show Recorder']
})
orga = Metadata.airtime_dict({
'date' : [u'2012-08-21'],
'tracknumber' : [u'2'],
'artist' : [u'Airtime Show Recorder'],
'title' : [u'record-2012-08-21-11:29:00']
})
orga['MDATA_KEY_FTYPE'] = u'audioclip'
orig['MDATA_KEY_BITRATE'] = u'256000'
orga['MDATA_KEY_BITRATE'] = u'256000'
old_path = "/home/rudi/recorded/2012-08-21-11:29:00.ogg"
normalized = mmp.normalized_metadata(orig, old_path)
normalized['MDATA_KEY_BITRATE'] = u'256000'
def test_organized_path(self):
o_path = '/home/rudi/throwaway/ACDC_-_Back_In_Black-sample-64kbps.ogg'
normal = mmp.normalized_metadata(self.md1,o_path)
og = mmp.organized_path(o_path,
'/home/rudi/throwaway/fucking_around/watch/',
normal)
real_path1 = \
u'/home/rudi/throwaway/fucking_around/watch/unknown/unknown/ACDC_-_Back_In_Black-sample-64kbps-64kbps.ogg'
self.assertTrue( 'unknown' in og, True )
self.assertEqual( og, real_path1 ) # TODO : fix this failure
# for recorded it should be something like this
# ./recorded/2012/07/2012-07-09-17-55-00-Untitled Show-256kbps.ogg
self.assertEqual( orga, normalized )
organized_base_name = "2012-08-21-11-29-00-record-256kbps.ogg"
base = "/srv/airtime/stor/"
organized_path = mmp.organized_path(old_path,base, normalized)
self.assertEqual(os.path.basename(organized_path), organized_base_name)
def test_file_md5(self):
p = os.path.realpath(__file__)

View File

@ -94,7 +94,6 @@ try:
#liq_path DNE, which is OK.
pass
os.symlink(liq_path, symlink_path)
else:
print " * Liquidsoap binary not found!"

View File

@ -27,7 +27,6 @@ stream_metadata_type = ref 0
default_dj_fade = ref 0.
station_name = ref ''
show_name = ref ''
#current_media_id = ref ''
s1_connected = ref ''
s2_connected = ref ''
@ -47,9 +46,6 @@ queue = map_metadata(update=false, append_title, queue)
# the crossfade function controls fade in/out
queue = crossfade(queue)
#make sure we are clearing all buffered data even when the source isn't being actively used
#output.dummy(queue, fallible=true)
#output.dummy(web_stream, fallible=true)
stream_queue = switch(id="stream_queue_switch", track_sensitive=false, transitions=[transition, transition], [({!webstream_enabled},web_stream), ({true}, queue)])

View File

@ -9,6 +9,7 @@ import sys
import pytz
import signal
import math
import traceback
from configobj import ConfigObj
@ -55,16 +56,16 @@ class ShowRecorder(Thread):
def __init__ (self, show_instance, show_name, filelength, start_time):
Thread.__init__(self)
self.logger = logging.getLogger('recorder')
self.api_client = api_client(self.logger)
self.filelength = filelength
self.start_time = start_time
self.logger = logging.getLogger('recorder')
self.api_client = api_client(self.logger)
self.filelength = filelength
self.start_time = start_time
self.show_instance = show_instance
self.show_name = show_name
self.p = None
self.show_name = show_name
self.p = None
def record_show(self):
length = str(self.filelength) + ".0"
length = str(self.filelength) + ".0"
filename = self.start_time
filename = filename.replace(" ", "-")
@ -73,16 +74,18 @@ class ShowRecorder(Thread):
else:
filetype = "ogg";
filepath = "%s%s.%s" % (config["base_recorded_files"], filename, filetype)
joined_path = os.path.join(config["base_recorded_files"], filename)
filepath = "%s.%s" % (joined_path, filetype)
br = config["record_bitrate"]
sr = config["record_samplerate"]
c = config["record_channels"]
c = config["record_channels"]
ss = config["record_sample_size"]
#-f:16,2,44100
#-b:256
command = "ecasound -f:%s,%s,%s -i alsa -o %s,%s000 -t:%s" % (ss, c, sr, filepath, br, length)
command = "ecasound -f:%s,%s,%s -i alsa -o %s,%s000 -t:%s" % \
(ss, c, sr, filepath, br, length)
args = command.split(" ")
self.logger.info("starting record")
@ -144,17 +147,16 @@ class ShowRecorder(Thread):
artist = "Airtime Show Recorder"
#set some metadata for our file daemon
recorded_file = mutagen.File(filepath, easy=True)
recorded_file['title'] = name
recorded_file = mutagen.File(filepath, easy = True)
recorded_file['title'] = name
recorded_file['artist'] = artist
recorded_file['date'] = md[0]
recorded_file['date'] = md[0]
#recorded_file['date'] = md[0].split("-")[0]
#You cannot pass ints into the metadata of a file. Even tracknumber needs to be a string
recorded_file['tracknumber'] = unicode(self.show_instance)
recorded_file.save()
except Exception, e:
import traceback
top = traceback.format_exc()
self.logger.error('Exception: %s', e)
self.logger.error("traceback: %s", top)
@ -180,20 +182,20 @@ class ShowRecorder(Thread):
class Recorder(Thread):
def __init__(self, q):
Thread.__init__(self)
self.logger = logging.getLogger('recorder')
self.api_client = api_client(self.logger)
self.api_client.register_component("show-recorder")
self.sr = None
self.logger = logging.getLogger('recorder')
self.api_client = api_client(self.logger)
self.sr = None
self.shows_to_record = {}
self.server_timezone = ''
self.queue = q
self.queue = q
self.loops = 0
self.api_client.register_component("show-recorder")
self.logger.info("RecorderFetch: init complete")
self.loops = 0
def handle_message(self):
if not self.queue.empty():
message = self.queue.get()
msg = json.loads(message)
msg = json.loads(message)
command = msg["event_type"]
self.logger.info("Received msg from Pypo Message Handler: %s", msg)
if command == 'cancel_recording':
@ -212,8 +214,8 @@ class Recorder(Thread):
shows = m['shows']
for show in shows:
show_starts = getDateTimeObj(show[u'starts'])
show_end = getDateTimeObj(show[u'ends'])
time_delta = show_end - show_starts
show_end = getDateTimeObj(show[u'ends'])
time_delta = show_end - show_starts
temp_shows_to_record[show[u'starts']] = [time_delta, show[u'instance_id'], show[u'name'], m['server_timezone']]
self.shows_to_record = temp_shows_to_record
@ -223,10 +225,10 @@ class Recorder(Thread):
tnow = datetime.datetime.utcnow()
sorted_show_keys = sorted(self.shows_to_record.keys())
start_time = sorted_show_keys[0]
next_show = getDateTimeObj(start_time)
start_time = sorted_show_keys[0]
next_show = getDateTimeObj(start_time)
delta = next_show - tnow
delta = next_show - tnow
s = '%s.%s' % (delta.seconds, delta.microseconds)
out = float(s)
@ -237,36 +239,35 @@ class Recorder(Thread):
return out
def start_record(self):
if len(self.shows_to_record) != 0:
try:
delta = self.get_time_till_next_show()
if delta < 5:
self.logger.debug("sleeping %s seconds until show", delta)
time.sleep(delta)
if len(self.shows_to_record) == 0: return None
try:
delta = self.get_time_till_next_show()
if delta < 5:
self.logger.debug("sleeping %s seconds until show", delta)
time.sleep(delta)
sorted_show_keys = sorted(self.shows_to_record.keys())
start_time = sorted_show_keys[0]
show_length = self.shows_to_record[start_time][0]
show_instance = self.shows_to_record[start_time][1]
show_name = self.shows_to_record[start_time][2]
server_timezone = self.shows_to_record[start_time][3]
sorted_show_keys = sorted(self.shows_to_record.keys())
start_time = sorted_show_keys[0]
show_length = self.shows_to_record[start_time][0]
show_instance = self.shows_to_record[start_time][1]
show_name = self.shows_to_record[start_time][2]
server_timezone = self.shows_to_record[start_time][3]
T = pytz.timezone(server_timezone)
start_time_on_UTC = getDateTimeObj(start_time)
start_time_on_server = start_time_on_UTC.replace(tzinfo=pytz.utc).astimezone(T)
start_time_formatted = '%(year)d-%(month)02d-%(day)02d %(hour)02d:%(min)02d:%(sec)02d' % \
{'year': start_time_on_server.year, 'month': start_time_on_server.month, 'day': start_time_on_server.day, \
'hour': start_time_on_server.hour, 'min': start_time_on_server.minute, 'sec': start_time_on_server.second}
self.sr = ShowRecorder(show_instance, show_name, show_length.seconds, start_time_formatted)
self.sr.start()
#remove show from shows to record.
del self.shows_to_record[start_time]
#self.time_till_next_show = self.get_time_till_next_show()
except Exception, e :
import traceback
top = traceback.format_exc()
self.logger.error('Exception: %s', e)
self.logger.error("traceback: %s", top)
T = pytz.timezone(server_timezone)
start_time_on_UTC = getDateTimeObj(start_time)
start_time_on_server = start_time_on_UTC.replace(tzinfo=pytz.utc).astimezone(T)
start_time_formatted = '%(year)d-%(month)02d-%(day)02d %(hour)02d:%(min)02d:%(sec)02d' % \
{'year': start_time_on_server.year, 'month': start_time_on_server.month, 'day': start_time_on_server.day, \
'hour': start_time_on_server.hour, 'min': start_time_on_server.minute, 'sec': start_time_on_server.second}
self.sr = ShowRecorder(show_instance, show_name, show_length.seconds, start_time_formatted)
self.sr.start()
#remove show from shows to record.
del self.shows_to_record[start_time]
#self.time_till_next_show = self.get_time_till_next_show()
except Exception, e :
top = traceback.format_exc()
self.logger.error('Exception: %s', e)
self.logger.error("traceback: %s", top)
"""
Main loop of the thread:
@ -284,6 +285,7 @@ class Recorder(Thread):
self.process_recorder_schedule(temp)
self.logger.info("Bootstrap recorder schedule received: %s", temp)
except Exception, e:
self.logger.error( traceback.format_exc() )
self.logger.error(e)
self.logger.info("Bootstrap complete: got initial copy of the schedule")
@ -305,14 +307,15 @@ class Recorder(Thread):
self.process_recorder_schedule(temp)
self.logger.info("updated recorder schedule received: %s", temp)
except Exception, e:
self.logger.error( traceback.format_exc() )
self.logger.error(e)
try: self.handle_message()
except Exception, e:
self.logger.error( traceback.format_exc() )
self.logger.error('Pypo Recorder Exception: %s', e)
time.sleep(PUSH_INTERVAL)
self.loops += 1
except Exception, e :
import traceback
top = traceback.format_exc()
self.logger.error('Exception: %s', e)
self.logger.error("traceback: %s", top)