Merge branch 'master' of dev.sourcefabric.org:airtime
Conflicts: install/airtime-install.php
This commit is contained in:
commit
c17ee178d1
|
@ -1,5 +1,5 @@
|
|||
.*
|
||||
*.pyc
|
||||
files/
|
||||
pypo/liquidsoap/liquidsoap
|
||||
/files
|
||||
python_apps/pypo/liquidsoap/liquidsoap
|
||||
build/build.properties
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
require_once (__DIR__."/configs/navigation.php");
|
||||
require_once (__DIR__."/configs/ACL.php");
|
||||
require_once __DIR__."/configs/navigation.php";
|
||||
require_once __DIR__."/configs/ACL.php";
|
||||
|
||||
require_once 'propel/runtime/lib/Propel.php';
|
||||
Propel::init(__DIR__."/configs/airtime-conf.php");
|
||||
|
@ -10,17 +10,20 @@ Propel::init(__DIR__."/configs/airtime-conf.php");
|
|||
$tz = ini_get('date.timezone') ? ini_get('date.timezone') : 'UTC';
|
||||
date_default_timezone_set($tz);
|
||||
|
||||
require_once (__DIR__."/configs/constants.php");
|
||||
require_once (__DIR__."/configs/conf.php");
|
||||
require_once __DIR__."/configs/constants.php";
|
||||
require_once __DIR__."/configs/conf.php";
|
||||
require_once 'DB.php';
|
||||
|
||||
require_once 'Soundcloud.php';
|
||||
require_once 'Playlist.php';
|
||||
require_once 'StoredFile.php';
|
||||
require_once 'Schedule.php';
|
||||
require_once 'Shows.php';
|
||||
require_once 'Users.php';
|
||||
require_once 'RabbitMq.php';
|
||||
require_once __DIR__.'/controllers/plugins/RabbitMqPlugin.php';
|
||||
|
||||
global $CC_CONFIG, $CC_DBC;
|
||||
global $CC_CONFIG, $CC_DBC;
|
||||
$dsn = $CC_CONFIG['dsn'];
|
||||
|
||||
$CC_DBC = DB::connect($dsn, FALSE);
|
||||
|
@ -33,6 +36,9 @@ $CC_DBC->setFetchMode(DB_FETCHMODE_ASSOC);
|
|||
//Zend_Session::start();
|
||||
Zend_Validate::setDefaultNamespaces("Zend");
|
||||
|
||||
$front = Zend_Controller_Front::getInstance();
|
||||
$front->registerPlugin(new RabbitMqPlugin());
|
||||
|
||||
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
|
||||
{
|
||||
protected function _initDoctype()
|
||||
|
@ -45,9 +51,7 @@ class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
|
|||
protected function _initHeadLink()
|
||||
{
|
||||
$view = $this->getResource('view');
|
||||
|
||||
$view->headLink()->appendStylesheet('/css/redmond/jquery-ui-1.8.8.custom.css');
|
||||
|
||||
$this->view->headLink()->appendStylesheet('/css/pro_dropdown_3.css');
|
||||
$this->view->headLink()->appendStylesheet('/css/styles.css');
|
||||
}
|
||||
|
@ -64,17 +68,20 @@ class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
|
|||
$this->view->headScript()->appendFile('/js/playlist/helperfunctions.js','text/javascript');
|
||||
$this->view->headScript()->appendFile('/js/playlist/playlist.js','text/javascript');
|
||||
|
||||
$view->headScript()->appendFile('/js/airtime/common/common.js','text/javascript');
|
||||
$view->headScript()->appendFile('/js/airtime/common/common.js','text/javascript');
|
||||
}
|
||||
|
||||
protected function _initViewHelpers(){
|
||||
|
||||
protected function _initViewHelpers()
|
||||
{
|
||||
$view = $this->getResource('view');
|
||||
$view->addHelperPath('../application/views/helpers', 'Airtime_View_Helper');
|
||||
}
|
||||
|
||||
protected function _initTitle(){
|
||||
|
||||
protected function _initTitle()
|
||||
{
|
||||
$view = $this->getResource('view');
|
||||
$view->headTitle(Application_Model_Preference::GetHeadTitle());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
<?php
|
||||
define('AIRTIME_VERSION', '1.7.0 alpha');
|
||||
define('AIRTIME_VERSION', '1.7.0-alpha');
|
||||
define('AIRTIME_COPYRIGHT_DATE', '2010-2011');
|
||||
define('AIRTIME_REST_VERSION', '1.1');
|
||||
|
||||
// These are the default values for the config.
|
||||
global $CC_CONFIG;
|
||||
$values = load_airtime_config();
|
||||
|
||||
// **********************************
|
||||
// **********************************
|
||||
// ***** START CUSTOMIZING HERE *****
|
||||
// **********************************
|
||||
// **********************************
|
||||
|
||||
// Set the location where you want to store all of your audio files.
|
||||
//
|
||||
|
@ -25,10 +26,16 @@ $CC_CONFIG = array(
|
|||
// Name of the web server user
|
||||
'webServerUser' => 'www-data',
|
||||
|
||||
// ***********************************************************************
|
||||
'rabbitmq' => array("host" => "127.0.0.1",
|
||||
"port" => "5672",
|
||||
"user" => "guest",
|
||||
"password" => "guest",
|
||||
"vhost" => "/"),
|
||||
|
||||
// ***********************************************************************
|
||||
// STOP CUSTOMIZING HERE
|
||||
//
|
||||
// You don't need to touch anything below this point.
|
||||
// You don't need to touch anything below this point.
|
||||
// ***********************************************************************
|
||||
|
||||
'baseFilesDir' => $baseFilesDir,
|
||||
|
@ -46,6 +53,9 @@ $CC_CONFIG = array(
|
|||
'apiKey' => $values['api_key'],
|
||||
'apiPath' => '/api/',
|
||||
|
||||
'soundcloud-client-id' => '2CLCxcSXYzx7QhhPVHN4A',
|
||||
'soundcloud-client-secret' => 'pZ7beWmF06epXLHVUP1ufOg2oEnIt9XhE8l8xt0bBs',
|
||||
|
||||
"rootDir" => __DIR__."/../..",
|
||||
'pearPath' => dirname(__FILE__).'/../../library/pear',
|
||||
'zendPath' => dirname(__FILE__).'/../../library/Zend',
|
||||
|
@ -55,26 +65,26 @@ $CC_CONFIG = array(
|
|||
//'AdminsGr' => 'Admins',
|
||||
|
||||
// name of station preferences group
|
||||
'StationPrefsGr'=> 'StationPrefs',
|
||||
// 'StationPrefsGr'=> 'StationPrefs',
|
||||
|
||||
// name of 'all users' group
|
||||
//'AllGr' => 'All',
|
||||
|
||||
/* ==================================== application-specific configuration */
|
||||
'objtypes' => array(
|
||||
'Storage' => array(/*'Folder',*/ 'File' /*, 'Replica'*/),
|
||||
'File' => array(),
|
||||
'audioclip' => array(),
|
||||
'playlist' => array(),
|
||||
),
|
||||
'allowedActions'=> array(
|
||||
'File' => array('editPrivs', 'write', 'read'),
|
||||
'audioclip' => array('editPrivs', 'write', 'read'),
|
||||
'playlist' => array('editPrivs', 'write', 'read'),
|
||||
),
|
||||
'allActions' => array(
|
||||
'editPrivs', 'write', 'read', 'subjects'
|
||||
),
|
||||
// 'objtypes' => array(
|
||||
// 'Storage' => array(/*'Folder',*/ 'File' /*, 'Replica'*/),
|
||||
// 'File' => array(),
|
||||
// 'audioclip' => array(),
|
||||
// 'playlist' => array(),
|
||||
// ),
|
||||
// 'allowedActions'=> array(
|
||||
// 'File' => array('editPrivs', 'write', 'read'),
|
||||
// 'audioclip' => array('editPrivs', 'write', 'read'),
|
||||
// 'playlist' => array('editPrivs', 'write', 'read'),
|
||||
// ),
|
||||
// 'allActions' => array(
|
||||
// 'editPrivs', 'write', 'read', 'subjects'
|
||||
// ),
|
||||
|
||||
/* =================================================== cron configuration */
|
||||
'cronUserName' => 'www-data',
|
||||
|
@ -82,7 +92,7 @@ $CC_CONFIG = array(
|
|||
'lockfile' => dirname(__FILE__).'/stor/buffer/cron.lock',
|
||||
'cronfile' => dirname(__FILE__).'/cron/croncall.php',
|
||||
'paramdir' => dirname(__FILE__).'/cron/params',
|
||||
'systemPrefId' => "0", // ID for system prefs in prefs table
|
||||
// 'systemPrefId' => "0", // ID for system prefs in prefs table
|
||||
);
|
||||
|
||||
// Add database table names
|
||||
|
@ -94,10 +104,8 @@ $CC_CONFIG['permTable'] = $CC_CONFIG['tblNamePrefix'].'perms';
|
|||
$CC_CONFIG['sessTable'] = $CC_CONFIG['tblNamePrefix'].'sess';
|
||||
$CC_CONFIG['subjTable'] = $CC_CONFIG['tblNamePrefix'].'subjs';
|
||||
$CC_CONFIG['smembTable'] = $CC_CONFIG['tblNamePrefix'].'smemb';
|
||||
$CC_CONFIG['transTable'] = $CC_CONFIG['tblNamePrefix'].'trans';
|
||||
$CC_CONFIG['prefTable'] = $CC_CONFIG['tblNamePrefix'].'pref';
|
||||
$CC_CONFIG['scheduleTable'] = $CC_CONFIG['tblNamePrefix'].'schedule';
|
||||
$CC_CONFIG['backupTable'] = $CC_CONFIG['tblNamePrefix'].'backup';
|
||||
$CC_CONFIG['playListTimeView'] = $CC_CONFIG['tblNamePrefix'].'playlisttimes';
|
||||
$CC_CONFIG['showSchedule'] = $CC_CONFIG['tblNamePrefix'].'show_schedule';
|
||||
$CC_CONFIG['showDays'] = $CC_CONFIG['tblNamePrefix'].'show_days';
|
||||
|
@ -106,16 +114,15 @@ $CC_CONFIG['showInstances'] = $CC_CONFIG['tblNamePrefix'].'show_instances';
|
|||
|
||||
$CC_CONFIG['playListSequence'] = $CC_CONFIG['playListTable'].'_id';
|
||||
$CC_CONFIG['filesSequence'] = $CC_CONFIG['filesTable'].'_id';
|
||||
$CC_CONFIG['transSequence'] = $CC_CONFIG['transTable'].'_id';
|
||||
$CC_CONFIG['prefSequence'] = $CC_CONFIG['prefTable'].'_id';
|
||||
$CC_CONFIG['permSequence'] = $CC_CONFIG['permTable'].'_id';
|
||||
$CC_CONFIG['subjSequence'] = $CC_CONFIG['subjTable'].'_id';
|
||||
$CC_CONFIG['smembSequence'] = $CC_CONFIG['smembTable'].'_id';
|
||||
|
||||
// System users/groups - they cannot be deleted
|
||||
$CC_CONFIG['sysSubjs'] = array(
|
||||
'root', /*$CC_CONFIG['AdminsGr'],*/ /*$CC_CONFIG['AllGr'],*/ $CC_CONFIG['StationPrefsGr']
|
||||
);
|
||||
//$CC_CONFIG['sysSubjs'] = array(
|
||||
// 'root', /*$CC_CONFIG['AdminsGr'],*/ /*$CC_CONFIG['AllGr'],*/ $CC_CONFIG['StationPrefsGr']
|
||||
//);
|
||||
|
||||
// Add libs to the PHP path
|
||||
$old_include_path = get_include_path();
|
||||
|
@ -125,9 +132,9 @@ set_include_path('.'.PATH_SEPARATOR.$CC_CONFIG['pearPath']
|
|||
|
||||
function load_airtime_config(){
|
||||
$ini_array = parse_ini_file(dirname(__FILE__).'/../../build/airtime.conf', true);
|
||||
|
||||
|
||||
return array(
|
||||
'database' => array(
|
||||
'database' => array(
|
||||
'username' => $ini_array['database']['dbuser'],
|
||||
'password' => $ini_array['database']['dbpass'],
|
||||
'hostspec' => $ini_array['database']['host'],
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
/*
|
||||
* Navigation container (config/array)
|
||||
|
||||
|
||||
* Each element in the array will be passed to
|
||||
* Zend_Navigation_Page::factory() when constructing
|
||||
* the navigation container below.
|
||||
|
@ -16,7 +16,7 @@ $pages = array(
|
|||
'resource' => 'nowplaying'
|
||||
),
|
||||
array(
|
||||
'label' => 'Add Audio',
|
||||
'label' => 'Add Media',
|
||||
'module' => 'default',
|
||||
'controller' => 'Plupload',
|
||||
'action' => 'plupload',
|
||||
|
@ -51,7 +51,7 @@ $pages = array(
|
|||
'module' => 'default',
|
||||
'controller' => 'user',
|
||||
'action' => 'add-user',
|
||||
'resource' => 'user'
|
||||
'resource' => 'user'
|
||||
)
|
||||
)
|
||||
),
|
||||
|
@ -64,10 +64,10 @@ $pages = array(
|
|||
)
|
||||
);
|
||||
|
||||
|
||||
|
||||
// Create container from array
|
||||
$container = new Zend_Navigation($pages);
|
||||
$container->id = "nav";
|
||||
|
||||
|
||||
//store it in the registry:
|
||||
Zend_Registry::set('Zend_Navigation', $container);
|
||||
|
|
|
@ -6,8 +6,10 @@ class ApiController extends Zend_Controller_Action
|
|||
public function init()
|
||||
{
|
||||
/* Initialize action controller here */
|
||||
$ajaxContext = $this->_helper->getHelper('AjaxContext');
|
||||
$ajaxContext->addActionContext('version', 'json')
|
||||
$context = $this->_helper->getHelper('contextSwitch');
|
||||
$context->addActionContext('version', 'json')
|
||||
->addActionContext('recorded-shows', 'json')
|
||||
->addActionContext('upload-recorded', 'json')
|
||||
->initContext();
|
||||
}
|
||||
|
||||
|
@ -24,7 +26,7 @@ class ApiController extends Zend_Controller_Action
|
|||
* in application/conf.php
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
*
|
||||
*/
|
||||
public function versionAction()
|
||||
{
|
||||
|
@ -101,6 +103,29 @@ class ApiController extends Zend_Controller_Action
|
|||
exit;
|
||||
}
|
||||
|
||||
public function liveInfoAction(){
|
||||
global $CC_CONFIG;
|
||||
|
||||
// disable the view and the layout
|
||||
$this->view->layout()->disableLayout();
|
||||
$this->_helper->viewRenderer->setNoRender(true);
|
||||
|
||||
$result = Schedule::GetPlayOrderRange(0, 1);
|
||||
|
||||
$date = new Application_Model_DateHelper;
|
||||
$timeNow = $date->getDate();
|
||||
$result = array("env"=>APPLICATION_ENV,
|
||||
"schedulerTime"=>gmdate("Y-m-d H:i:s"),
|
||||
"currentShow"=>Show_DAL::GetCurrentShow($timeNow),
|
||||
"nextShow"=>Show_DAL::GetNextShows($timeNow, 5),
|
||||
"timezone"=> date("T"),
|
||||
"timezoneOffset"=> date("Z"));
|
||||
|
||||
//echo json_encode($result);
|
||||
header("Content-type: text/javascript");
|
||||
echo $_GET['callback'].'('.json_encode($result).')';
|
||||
}
|
||||
|
||||
public function scheduleAction()
|
||||
{
|
||||
global $CC_CONFIG;
|
||||
|
@ -110,6 +135,7 @@ class ApiController extends Zend_Controller_Action
|
|||
$this->_helper->viewRenderer->setNoRender(true);
|
||||
|
||||
$api_key = $this->_getParam('api_key');
|
||||
|
||||
if(!in_array($api_key, $CC_CONFIG["apiKey"]))
|
||||
{
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
|
@ -119,18 +145,10 @@ class ApiController extends Zend_Controller_Action
|
|||
|
||||
PEAR::setErrorHandling(PEAR_ERROR_RETURN);
|
||||
|
||||
$from = $this->_getParam("from");
|
||||
$to = $this->_getParam("to");
|
||||
if (Schedule::ValidPypoTimeFormat($from) && Schedule::ValidPypoTimeFormat($to)) {
|
||||
$result = Schedule::ExportRangeAsJson($from, $to);
|
||||
$result['stream_metadata'] = array();
|
||||
$result['stream_metadata']['format'] = Application_Model_Preference::GetStreamLabelFormat();
|
||||
$result['stream_metadata']['station_name'] = Application_Model_Preference::GetStationName();
|
||||
echo json_encode($result);
|
||||
}
|
||||
$result = Schedule::GetScheduledPlaylists();
|
||||
echo json_encode($result);
|
||||
}
|
||||
|
||||
|
||||
public function notifyMediaItemStartPlayAction()
|
||||
{
|
||||
global $CC_CONFIG;
|
||||
|
@ -197,5 +215,53 @@ class ApiController extends Zend_Controller_Action
|
|||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
public function recordedShowsAction()
|
||||
{
|
||||
global $CC_CONFIG;
|
||||
|
||||
$api_key = $this->_getParam('api_key');
|
||||
if (!in_array($api_key, $CC_CONFIG["apiKey"]))
|
||||
{
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
print 'You are not allowed to access this resource.';
|
||||
exit;
|
||||
}
|
||||
|
||||
$today_timestamp = date("Y-m-d H:i:s");
|
||||
$this->view->shows = Show::getShows($today_timestamp, null, $excludeInstance=NULL, $onlyRecord=TRUE);
|
||||
}
|
||||
|
||||
public function uploadRecordedAction()
|
||||
{
|
||||
global $CC_CONFIG;
|
||||
|
||||
$api_key = $this->_getParam('api_key');
|
||||
if (!in_array($api_key, $CC_CONFIG["apiKey"]))
|
||||
{
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
print 'You are not allowed to access this resource.';
|
||||
exit;
|
||||
}
|
||||
|
||||
$upload_dir = ini_get("upload_tmp_dir");
|
||||
$file = StoredFile::uploadFile($upload_dir);
|
||||
|
||||
$show_instance = $this->_getParam('show_instance');
|
||||
|
||||
$show_inst = new ShowInstance($show_instance);
|
||||
$show_inst->setRecordedFile($file->getId());
|
||||
|
||||
if(Application_Model_Preference::GetDoSoundCloudUpload())
|
||||
{
|
||||
$show = new Show($show_inst->getShowId());
|
||||
$description = $show->getDescription();
|
||||
|
||||
$soundcloud = new ATSoundcloud();
|
||||
$soundcloud->uploadTrack($file->getRealFilePath(), $file->getName(), $description);
|
||||
}
|
||||
|
||||
$this->view->id = $file->getId();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,144 +11,6 @@ class PluploadController extends Zend_Controller_Action
|
|||
->initContext();
|
||||
}
|
||||
|
||||
public function upload($targetDir)
|
||||
{
|
||||
// HTTP headers for no cache etc
|
||||
header('Content-type: text/plain; charset=UTF-8');
|
||||
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
|
||||
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
|
||||
header("Cache-Control: no-store, no-cache, must-revalidate");
|
||||
header("Cache-Control: post-check=0, pre-check=0", false);
|
||||
header("Pragma: no-cache");
|
||||
|
||||
// Settings
|
||||
//$targetDir = ini_get("upload_tmp_dir"); //. DIRECTORY_SEPARATOR . "plupload";
|
||||
$cleanupTargetDir = false; // Remove old files
|
||||
$maxFileAge = 60 * 60; // Temp file age in seconds
|
||||
|
||||
// 5 minutes execution time
|
||||
@set_time_limit(5 * 60);
|
||||
// usleep(5000);
|
||||
|
||||
// Get parameters
|
||||
$chunk = isset($_REQUEST["chunk"]) ? $_REQUEST["chunk"] : 0;
|
||||
$chunks = isset($_REQUEST["chunks"]) ? $_REQUEST["chunks"] : 0;
|
||||
$fileName = isset($_REQUEST["name"]) ? $_REQUEST["name"] : '';
|
||||
|
||||
// Clean the fileName for security reasons
|
||||
//$fileName = preg_replace('/[^\w\._]+/', '', $fileName);
|
||||
|
||||
// Create target dir
|
||||
if (!file_exists($targetDir))
|
||||
@mkdir($targetDir);
|
||||
|
||||
// Remove old temp files
|
||||
if (is_dir($targetDir) && ($dir = opendir($targetDir))) {
|
||||
while (($file = readdir($dir)) !== false) {
|
||||
$filePath = $targetDir . DIRECTORY_SEPARATOR . $file;
|
||||
|
||||
// Remove temp files if they are older than the max age
|
||||
if (preg_match('/\.tmp$/', $file) && (filemtime($filePath) < time() - $maxFileAge))
|
||||
@unlink($filePath);
|
||||
}
|
||||
|
||||
closedir($dir);
|
||||
} else
|
||||
die('{"jsonrpc" : "2.0", "error" : {"code": 100, "message": "Failed to open temp directory."}, "id" : "id"}');
|
||||
|
||||
// Look for the content type header
|
||||
if (isset($_SERVER["HTTP_CONTENT_TYPE"]))
|
||||
$contentType = $_SERVER["HTTP_CONTENT_TYPE"];
|
||||
|
||||
if (isset($_SERVER["CONTENT_TYPE"]))
|
||||
$contentType = $_SERVER["CONTENT_TYPE"];
|
||||
|
||||
if (strpos($contentType, "multipart") !== false) {
|
||||
if (isset($_FILES['file']['tmp_name']) && is_uploaded_file($_FILES['file']['tmp_name'])) {
|
||||
// Open temp file
|
||||
$out = fopen($targetDir . DIRECTORY_SEPARATOR . $fileName, $chunk == 0 ? "wb" : "ab");
|
||||
if ($out) {
|
||||
// Read binary input stream and append it to temp file
|
||||
$in = fopen($_FILES['file']['tmp_name'], "rb");
|
||||
|
||||
if ($in) {
|
||||
while ($buff = fread($in, 4096))
|
||||
fwrite($out, $buff);
|
||||
} else
|
||||
die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');
|
||||
|
||||
fclose($out);
|
||||
unlink($_FILES['file']['tmp_name']);
|
||||
} else
|
||||
die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}');
|
||||
} else
|
||||
die('{"jsonrpc" : "2.0", "error" : {"code": 103, "message": "Failed to move uploaded file."}, "id" : "id"}');
|
||||
} else {
|
||||
// Open temp file
|
||||
$out = fopen($targetDir . DIRECTORY_SEPARATOR . $fileName, $chunk == 0 ? "wb" : "ab");
|
||||
if ($out) {
|
||||
// Read binary input stream and append it to temp file
|
||||
$in = fopen("php://input", "rb");
|
||||
|
||||
if ($in) {
|
||||
while ($buff = fread($in, 4096))
|
||||
fwrite($out, $buff);
|
||||
} else
|
||||
die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');
|
||||
|
||||
fclose($out);
|
||||
} else
|
||||
die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}');
|
||||
}
|
||||
|
||||
$audio_file = $targetDir . DIRECTORY_SEPARATOR . $fileName;
|
||||
|
||||
$md5 = md5_file($audio_file);
|
||||
$duplicate = StoredFile::RecallByMd5($md5);
|
||||
if ($duplicate) {
|
||||
if (PEAR::isError($duplicate)) {
|
||||
die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": ' . $duplicate->getMessage() .'}}');
|
||||
}
|
||||
else {
|
||||
$duplicateName = $duplicate->getMetadataValue(UI_MDATA_KEY_TITLE);
|
||||
die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "An identical audioclip named ' . $duplicateName . ' already exists in the storage server."}}');
|
||||
}
|
||||
}
|
||||
|
||||
$metadata = Metadata::LoadFromFile($audio_file);
|
||||
|
||||
if (PEAR::isError($metadata)) {
|
||||
die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": ' + $metadata->getMessage() + '}}');
|
||||
}
|
||||
|
||||
// #2196 no id tag -> use the original filename
|
||||
if (basename($audio_file) == $metadata[UI_MDATA_KEY_TITLE]) {
|
||||
$metadata[UI_MDATA_KEY_TITLE] = basename($audio_file);
|
||||
$metadata[UI_MDATA_KEY_FILENAME] = basename($audio_file);
|
||||
}
|
||||
|
||||
// setMetadataBatch doesnt like these values
|
||||
unset($metadata['audio']);
|
||||
unset($metadata['playtime_seconds']);
|
||||
|
||||
$values = array(
|
||||
"filename" => basename($audio_file),
|
||||
"filepath" => $audio_file,
|
||||
"filetype" => "audioclip",
|
||||
"mime" => $metadata[UI_MDATA_KEY_FORMAT],
|
||||
"md5" => $md5
|
||||
);
|
||||
$storedFile = StoredFile::Insert($values);
|
||||
|
||||
if (PEAR::isError($storedFile)) {
|
||||
die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": ' + $storedFile->getMessage() + '}}');
|
||||
}
|
||||
|
||||
$storedFile->setMetadataBatch($metadata);
|
||||
|
||||
// Return JSON-RPC response
|
||||
die('{"jsonrpc" : "2.0", "id" : '.$storedFile->getId().' }');
|
||||
}
|
||||
|
||||
public function indexAction()
|
||||
{
|
||||
|
@ -158,13 +20,9 @@ class PluploadController extends Zend_Controller_Action
|
|||
public function uploadAction()
|
||||
{
|
||||
$upload_dir = ini_get("upload_tmp_dir") . DIRECTORY_SEPARATOR . "plupload";
|
||||
$this->upload($upload_dir);
|
||||
}
|
||||
$file = StoredFile::uploadFile($upload_dir);
|
||||
|
||||
public function uploadRecordedAction()
|
||||
{
|
||||
$upload_dir = ini_get("upload_tmp_dir");
|
||||
$this->upload($upload_dir);
|
||||
die('{"jsonrpc" : "2.0", "id" : '.$file->getId().' }');
|
||||
}
|
||||
|
||||
public function pluploadAction()
|
||||
|
|
|
@ -29,7 +29,11 @@ class PreferenceController extends Zend_Controller_Action
|
|||
$values = $form->getValues();
|
||||
Application_Model_Preference::SetHeadTitle($values["stationName"], $this->view);
|
||||
Application_Model_Preference::SetDefaultFade($values["stationDefaultFade"]);
|
||||
Application_Model_Preference::SetStreamLabelFormat($values["streamFormat"]);
|
||||
Application_Model_Preference::SetStreamLabelFormat($values["streamFormat"]);
|
||||
Application_Model_Preference::SetDoSoundCloudUpload($values["UseSoundCloud"]);
|
||||
Application_Model_Preference::SetSoundCloudUser($values["SoundCloudUser"]);
|
||||
Application_Model_Preference::SetSoundCloudPassword($values["SoundCloudPassword"]);
|
||||
Application_Model_Preference::SetSoundCloudTags($values["SoundCloudTags"]);
|
||||
|
||||
$this->view->statusMsg = "Preferences Updated.";
|
||||
}
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
<?php
|
||||
|
||||
class RecorderController extends Zend_Controller_Action
|
||||
{
|
||||
|
||||
public function init()
|
||||
{
|
||||
$ajaxContext = $this->_helper->getHelper('contextSwitch');
|
||||
$ajaxContext->addActionContext('get-show-schedule', 'json')
|
||||
->addActionContext('get-uploaded-file', 'json')
|
||||
->initContext();
|
||||
}
|
||||
|
||||
public function indexAction()
|
||||
{
|
||||
// action body
|
||||
}
|
||||
|
||||
public function getShowScheduleAction()
|
||||
{
|
||||
$today_timestamp = date("Y-m-d H:i:s");
|
||||
$this->view->shows = Show::getShows($today_timestamp, null, $excludeInstance=NULL, $onlyRecord=TRUE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -19,9 +19,9 @@ class ScheduleController extends Zend_Controller_Action
|
|||
->addActionContext('schedule-show-dialog', 'json')
|
||||
->addActionContext('show-content-dialog', 'json')
|
||||
->addActionContext('clear-show', 'json')
|
||||
->addActionContext('get-current-playlist', 'json')
|
||||
->addActionContext('get-current-playlist', 'json')
|
||||
->addActionContext('find-playlists', 'json')
|
||||
->addActionContext('remove-group', 'json')
|
||||
->addActionContext('remove-group', 'json')
|
||||
->addActionContext('edit-show', 'json')
|
||||
->addActionContext('add-show', 'json')
|
||||
->addActionContext('cancel-show', 'json')
|
||||
|
@ -64,7 +64,7 @@ class ScheduleController extends Zend_Controller_Action
|
|||
$formRepeats->removeDecorator('DtDdWrapper');
|
||||
$formStyle->removeDecorator('DtDdWrapper');
|
||||
$formRecord->removeDecorator('DtDdWrapper');
|
||||
|
||||
|
||||
|
||||
$this->view->what = $formWhat;
|
||||
$this->view->when = $formWhen;
|
||||
|
@ -84,7 +84,7 @@ class ScheduleController extends Zend_Controller_Action
|
|||
{
|
||||
$start = $this->_getParam('start', null);
|
||||
$end = $this->_getParam('end', null);
|
||||
|
||||
|
||||
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
|
||||
$user = new User($userInfo->id);
|
||||
if($user->isAdmin())
|
||||
|
@ -111,6 +111,7 @@ class ScheduleController extends Zend_Controller_Action
|
|||
|
||||
if(isset($error))
|
||||
$this->view->error = $error;
|
||||
|
||||
}
|
||||
|
||||
public function resizeShowAction()
|
||||
|
@ -134,7 +135,7 @@ class ScheduleController extends Zend_Controller_Action
|
|||
public function deleteShowAction()
|
||||
{
|
||||
$showInstanceId = $this->_getParam('id');
|
||||
|
||||
|
||||
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
|
||||
$user = new User($userInfo->id);
|
||||
|
||||
|
@ -158,41 +159,41 @@ class ScheduleController extends Zend_Controller_Action
|
|||
if (strtotime($today_timestamp) < strtotime($show->getShowStart())) {
|
||||
|
||||
if (($user->isHost($show->getShowId()) || $user->isAdmin()) && !$show->isRecorded() && !$show->isRebroadcast()) {
|
||||
|
||||
$menu[] = array('action' => array('type' => 'ajax', 'url' => '/Schedule/schedule-show-dialog'.$params,
|
||||
'callback' => 'window["buildScheduleDialog"]'), 'title' => 'Add Content');
|
||||
|
||||
$menu[] = array('action' => array('type' => 'ajax', 'url' => '/Schedule/clear-show'.$params,
|
||||
$menu[] = array('action' => array('type' => 'ajax', 'url' => '/Schedule/schedule-show-dialog'.$params,
|
||||
'callback' => 'window["buildScheduleDialog"]'), 'title' => 'Add / Remove Content');
|
||||
|
||||
$menu[] = array('action' => array('type' => 'ajax', 'url' => '/Schedule/clear-show'.$params,
|
||||
'callback' => 'window["scheduleRefetchEvents"]'), 'title' => 'Remove All Content');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(!$show->isRecorded()) {
|
||||
$menu[] = array('action' => array('type' => 'ajax', 'url' => '/Schedule/show-content-dialog'.$params,
|
||||
$menu[] = array('action' => array('type' => 'ajax', 'url' => '/Schedule/show-content-dialog'.$params,
|
||||
'callback' => 'window["buildContentDialog"]'), 'title' => 'Show Content');
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (strtotime($show->getShowStart()) <= strtotime($today_timestamp) &&
|
||||
strtotime($today_timestamp) < strtotime($show->getShowEnd())) {
|
||||
$menu[] = array('action' => array('type' => 'fn',
|
||||
//'url' => '/Schedule/cancel-current-show'.$params,
|
||||
'callback' => "window['confirmCancelShow']($id)"),
|
||||
'title' => 'Cancel Current Show');
|
||||
'callback' => "window['confirmCancelShow']($id)"),
|
||||
'title' => 'Cancel Current Show');
|
||||
}
|
||||
|
||||
|
||||
if (strtotime($today_timestamp) < strtotime($show->getShowStart())) {
|
||||
|
||||
if ($user->isAdmin()) {
|
||||
|
||||
$menu[] = array('action' => array('type' => 'ajax', 'url' => '/Schedule/delete-show'.$params,
|
||||
$menu[] = array('action' => array('type' => 'ajax', 'url' => '/Schedule/delete-show'.$params,
|
||||
'callback' => 'window["scheduleRefetchEvents"]'), 'title' => 'Delete This Instance');
|
||||
$menu[] = array('action' => array('type' => 'ajax', 'url' => '/Schedule/cancel-show'.$params,
|
||||
$menu[] = array('action' => array('type' => 'ajax', 'url' => '/Schedule/cancel-show'.$params,
|
||||
'callback' => 'window["scheduleRefetchEvents"]'), 'title' => 'Delete This Instance and All Following');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//returns format jjmenu is looking for.
|
||||
die(json_encode($menu));
|
||||
}
|
||||
|
@ -219,7 +220,7 @@ class ScheduleController extends Zend_Controller_Action
|
|||
$this->view->timeFilled = $show->getTimeScheduled();
|
||||
$this->view->percentFilled = $show->getPercentScheduled();
|
||||
|
||||
$this->view->chosen = $this->view->render('schedule/scheduled-content.phtml');
|
||||
$this->view->chosen = $this->view->render('schedule/scheduled-content.phtml');
|
||||
unset($this->view->showContent);
|
||||
}
|
||||
|
||||
|
@ -242,7 +243,7 @@ class ScheduleController extends Zend_Controller_Action
|
|||
public function findPlaylistsAction()
|
||||
{
|
||||
$post = $this->getRequest()->getPost();
|
||||
|
||||
|
||||
$show = new ShowInstance($this->sched_sess->showInstanceId);
|
||||
$playlists = $show->searchPlaylistsForShow($post);
|
||||
|
||||
|
@ -267,7 +268,7 @@ class ScheduleController extends Zend_Controller_Action
|
|||
$this->view->showContent = $show->getShowContent();
|
||||
$this->view->timeFilled = $show->getTimeScheduled();
|
||||
$this->view->percentFilled = $show->getPercentScheduled();
|
||||
$this->view->chosen = $this->view->render('schedule/scheduled-content.phtml');
|
||||
$this->view->chosen = $this->view->render('schedule/scheduled-content.phtml');
|
||||
unset($this->view->showContent);
|
||||
}
|
||||
|
||||
|
@ -275,7 +276,7 @@ class ScheduleController extends Zend_Controller_Action
|
|||
{
|
||||
$showInstanceId = $this->_getParam('id');
|
||||
$this->sched_sess->showInstanceId = $showInstanceId;
|
||||
|
||||
|
||||
$show = new ShowInstance($showInstanceId);
|
||||
$start_timestamp = $show->getShowStart();
|
||||
$end_timestamp = $show->getShowEnd();
|
||||
|
@ -285,14 +286,14 @@ class ScheduleController extends Zend_Controller_Action
|
|||
$this->view->error = "cannot schedule an overlapping show.";
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$start = explode(" ", $start_timestamp);
|
||||
$end = explode(" ", $end_timestamp);
|
||||
$startTime = explode(":", $start[1]);
|
||||
$endTime = explode(":", $end[1]);
|
||||
$dateInfo_s = getDate(strtotime($start_timestamp));
|
||||
$dateInfo_e = getDate(strtotime($end_timestamp));
|
||||
|
||||
|
||||
$this->view->showContent = $show->getShowContent();
|
||||
$this->view->timeFilled = $show->getTimeScheduled();
|
||||
$this->view->showName = $show->getName();
|
||||
|
@ -308,7 +309,7 @@ class ScheduleController extends Zend_Controller_Action
|
|||
$this->view->startTime = sprintf("%d:%02d", $startTime[0], $startTime[1]);
|
||||
$this->view->endTime = sprintf("%d:%02d", $endTime[0], $endTime[1]);
|
||||
|
||||
$this->view->chosen = $this->view->render('schedule/scheduled-content.phtml');
|
||||
$this->view->chosen = $this->view->render('schedule/scheduled-content.phtml');
|
||||
$this->view->dialog = $this->view->render('schedule/schedule-show-dialog.phtml');
|
||||
unset($this->view->showContent);
|
||||
}
|
||||
|
@ -335,7 +336,7 @@ class ScheduleController extends Zend_Controller_Action
|
|||
{
|
||||
$js = $this->_getParam('data');
|
||||
$data = array();
|
||||
|
||||
|
||||
//need to convert from serialized jQuery array.
|
||||
foreach($js as $j){
|
||||
$data[$j["name"]] = $j["value"];
|
||||
|
@ -392,8 +393,8 @@ class ScheduleController extends Zend_Controller_Action
|
|||
$rebroadAb = $formAbsoluteRebroadcast->isValid($data);
|
||||
$rebroad = $formRebroadcast->isValid($data);
|
||||
|
||||
if ($what && $when && $repeats && $who && $style && $record && $rebroadAb && $rebroad) {
|
||||
|
||||
if ($what && $when && $repeats && $who && $style && $record && $rebroadAb && $rebroad) {
|
||||
|
||||
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
|
||||
$user = new User($userInfo->id);
|
||||
if($user->isAdmin()) {
|
||||
|
@ -413,7 +414,7 @@ class ScheduleController extends Zend_Controller_Action
|
|||
$formRecord->reset();
|
||||
$formAbsoluteRebroadcast->reset();
|
||||
$formRebroadcast->reset();
|
||||
|
||||
|
||||
$this->view->newForm = $this->view->render('schedule/add-show-form.phtml');
|
||||
}
|
||||
else {
|
||||
|
@ -426,7 +427,7 @@ class ScheduleController extends Zend_Controller_Action
|
|||
{
|
||||
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
|
||||
$user = new User($userInfo->id);
|
||||
|
||||
|
||||
if($user->isAdmin()) {
|
||||
$showInstanceId = $this->_getParam('id');
|
||||
|
||||
|
@ -434,14 +435,14 @@ class ScheduleController extends Zend_Controller_Action
|
|||
$show = new Show($showInstance->getShowId());
|
||||
|
||||
$show->cancelShow($showInstance->getShowStart());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function cancelCurrentShowAction()
|
||||
{
|
||||
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
|
||||
$user = new User($userInfo->id);
|
||||
|
||||
|
||||
if($user->isAdmin()) {
|
||||
$showInstanceId = $this->_getParam('id');
|
||||
$show = new ShowInstance($showInstanceId);
|
||||
|
|
|
@ -23,6 +23,8 @@ class UserController extends Zend_Controller_Action
|
|||
$this->view->headScript()->appendFile('/js/airtime/user/user.js','text/javascript');
|
||||
$request = $this->getRequest();
|
||||
$form = new Application_Form_AddUser();
|
||||
|
||||
$this->view->successMessage = "";
|
||||
|
||||
if ($request->isPost()) {
|
||||
if ($form->isValid($request->getPost())) {
|
||||
|
@ -42,6 +44,12 @@ class UserController extends Zend_Controller_Action
|
|||
$user->save();
|
||||
|
||||
$form->reset();
|
||||
|
||||
if (strlen($formdata['user_id']) == 0){
|
||||
$this->view->successMessage = "<div class='success'>User added successfully!</div>";
|
||||
} else {
|
||||
$this->view->successMessage = "<div class='success'>User updated successfully!</div>";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,7 +110,7 @@ class Zend_Controller_Plugin_Acl extends Zend_Controller_Plugin_Abstract
|
|||
{
|
||||
$controller = strtolower($request->getControllerName());
|
||||
|
||||
if ($controller == 'api' || $controller == 'recorder' || $controller == 'plupload' && $request->getActionName() == 'upload-recorded'){
|
||||
if ($controller == 'api'){
|
||||
|
||||
$this->setRoleName("G");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
class RabbitMqPlugin extends Zend_Controller_Plugin_Abstract
|
||||
{
|
||||
public function dispatchLoopShutdown()
|
||||
{
|
||||
RabbitMq::PushScheduleFinal();
|
||||
}
|
||||
}
|
|
@ -9,17 +9,18 @@ class Application_Form_AddShowRebroadcastDates extends Zend_Form_SubForm
|
|||
array('ViewScript', array('viewScript' => 'form/add-show-rebroadcast.phtml'))
|
||||
));
|
||||
|
||||
|
||||
$relativeDates = array();
|
||||
$relativeDates[""] = "";
|
||||
for($i=0; $i <=30; $i++) {
|
||||
$relativeDates["$i days"] = "+$i days";
|
||||
}
|
||||
|
||||
//Add date select
|
||||
$this->addElement('select', 'add_show_rebroadcast_date_1', array(
|
||||
'required' => false,
|
||||
'class' => ' input_select',
|
||||
'multiOptions' => array(
|
||||
"" => "",
|
||||
"0 days" => "+0 days",
|
||||
"1 day" => "+1 day",
|
||||
"2 days" => "+2 days",
|
||||
"3 days" => "+3 days"
|
||||
),
|
||||
'multiOptions' => $relativeDates,
|
||||
'decorators' => array(
|
||||
'ViewHelper'
|
||||
)
|
||||
|
@ -44,13 +45,7 @@ class Application_Form_AddShowRebroadcastDates extends Zend_Form_SubForm
|
|||
$this->addElement('select', 'add_show_rebroadcast_date_2', array(
|
||||
'required' => false,
|
||||
'class' => ' input_select',
|
||||
'multiOptions' => array(
|
||||
"" => "",
|
||||
"0 days" => "+0 days",
|
||||
"1 day" => "+1 day",
|
||||
"2 days" => "+2 days",
|
||||
"3 days" => "+3 days"
|
||||
),
|
||||
'multiOptions' => $relativeDates,
|
||||
'decorators' => array(
|
||||
'ViewHelper'
|
||||
)
|
||||
|
@ -75,13 +70,7 @@ class Application_Form_AddShowRebroadcastDates extends Zend_Form_SubForm
|
|||
$this->addElement('select', 'add_show_rebroadcast_date_3', array(
|
||||
'required' => false,
|
||||
'class' => ' input_select',
|
||||
'multiOptions' => array(
|
||||
"" => "",
|
||||
"0 days" => "+0 days",
|
||||
"1 day" => "+1 day",
|
||||
"2 days" => "+2 days",
|
||||
"3 days" => "+3 days"
|
||||
),
|
||||
'multiOptions' => $relativeDates,
|
||||
'decorators' => array(
|
||||
'ViewHelper'
|
||||
)
|
||||
|
@ -106,13 +95,7 @@ class Application_Form_AddShowRebroadcastDates extends Zend_Form_SubForm
|
|||
$this->addElement('select', 'add_show_rebroadcast_date_4', array(
|
||||
'required' => false,
|
||||
'class' => ' input_select',
|
||||
'multiOptions' => array(
|
||||
"" => "",
|
||||
"0 days" => "+0 days",
|
||||
"1 day" => "+1 day",
|
||||
"2 days" => "+2 days",
|
||||
"3 days" => "+3 days"
|
||||
),
|
||||
'multiOptions' => $relativeDates,
|
||||
'decorators' => array(
|
||||
'ViewHelper'
|
||||
)
|
||||
|
@ -137,13 +120,7 @@ class Application_Form_AddShowRebroadcastDates extends Zend_Form_SubForm
|
|||
$this->addElement('select', 'add_show_rebroadcast_date_5', array(
|
||||
'required' => false,
|
||||
'class' => ' input_select',
|
||||
'multiOptions' => array(
|
||||
"" => "",
|
||||
"0 days" => "+0 days",
|
||||
"1 day" => "+1 day",
|
||||
"2 days" => "+2 days",
|
||||
"3 days" => "+3 days"
|
||||
),
|
||||
'multiOptions' => $relativeDates,
|
||||
'decorators' => array(
|
||||
'ViewHelper'
|
||||
)
|
||||
|
|
|
@ -16,7 +16,7 @@ class Application_Form_AddShowWhat extends Zend_Form_SubForm
|
|||
|
||||
// Add URL element
|
||||
$this->addElement('text', 'add_show_url', array(
|
||||
'label' => 'Show URL:',
|
||||
'label' => 'Website:',
|
||||
'class' => 'input_text',
|
||||
'required' => false,
|
||||
'filters' => array('StringTrim'),
|
||||
|
|
|
@ -68,12 +68,13 @@ class Application_Form_AddUser extends Zend_Form
|
|||
$this->addElement($jabber);
|
||||
|
||||
$select = new Zend_Form_Element_Select('type');
|
||||
$select->setLabel('User Type:');
|
||||
$select->setAttrib('class', 'input_select');
|
||||
$select->setAttrib('style', 'width: 40%');
|
||||
$select->setMultiOptions(array(
|
||||
"A" => "admin",
|
||||
"H" => "host",
|
||||
"G" => "guest",
|
||||
"G" => "Guest",
|
||||
"H" => "Host",
|
||||
"A" => "Admin"
|
||||
));
|
||||
$select->setRequired(true);
|
||||
$this->addElement($select);
|
||||
|
|
|
@ -7,7 +7,7 @@ class Application_Form_Preferences extends Zend_Form
|
|||
{
|
||||
$this->setAction('/Preference/update')->setMethod('post');
|
||||
|
||||
// Add login element
|
||||
//Station name
|
||||
$this->addElement('text', 'stationName', array(
|
||||
'class' => 'input_text',
|
||||
'label' => 'Station Name:',
|
||||
|
@ -17,12 +17,12 @@ class Application_Form_Preferences extends Zend_Form
|
|||
'value' => Application_Model_Preference::GetValue("station_name")
|
||||
));
|
||||
|
||||
$defaultFade = Application_Model_Preference::GetValue("default_fade");
|
||||
$defaultFade = Application_Model_Preference::GetDefaultFade();
|
||||
if($defaultFade == ""){
|
||||
$defaultFade = '00:00:00.000000';
|
||||
}
|
||||
|
||||
// Add login element
|
||||
//Default station fade
|
||||
$this->addElement('text', 'stationDefaultFade', array(
|
||||
'class' => 'input_text',
|
||||
'label' => 'Default Fade:',
|
||||
|
@ -42,11 +42,46 @@ class Application_Form_Preferences extends Zend_Form
|
|||
$stream_format->setValue(Application_Model_Preference::GetStreamLabelFormat());
|
||||
$this->addElement($stream_format);
|
||||
|
||||
|
||||
$this->addElement('checkbox', 'UseSoundCloud', array(
|
||||
'label' => 'Automatically Upload Recorded Shows To SoundCloud',
|
||||
'required' => false,
|
||||
'value' => Application_Model_Preference::GetDoSoundCloudUpload()
|
||||
));
|
||||
|
||||
//SoundCloud Username
|
||||
$this->addElement('text', 'SoundCloudUser', array(
|
||||
'class' => 'input_text',
|
||||
'label' => 'SoundCloud Email:',
|
||||
'required' => false,
|
||||
'filters' => array('StringTrim'),
|
||||
'value' => Application_Model_Preference::GetSoundCloudUser()
|
||||
));
|
||||
|
||||
//SoundCloud Password
|
||||
$this->addElement('text', 'SoundCloudPassword', array(
|
||||
'class' => 'input_text',
|
||||
'label' => 'SoundCloud Password:',
|
||||
'required' => false,
|
||||
'filters' => array('StringTrim'),
|
||||
'value' => Application_Model_Preference::GetSoundCloudPassword()
|
||||
));
|
||||
|
||||
// Add the description element
|
||||
$this->addElement('textarea', 'SoundCloudTags', array(
|
||||
'label' => 'space separated SoundCloud Tags',
|
||||
'required' => false,
|
||||
'class' => 'input_text_area',
|
||||
'value' => Application_Model_Preference::GetSoundCloudTags()
|
||||
));
|
||||
|
||||
$this->addElement('submit', 'submit', array(
|
||||
'class' => 'ui-button ui-state-default',
|
||||
'ignore' => true,
|
||||
'label' => 'Submit',
|
||||
));
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,61 +2,85 @@
|
|||
|
||||
class Application_Model_DateHelper
|
||||
{
|
||||
private $_timestamp;
|
||||
|
||||
function __construct() {
|
||||
private $_timestamp;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
$this->_timestamp = date("U");
|
||||
}
|
||||
|
||||
function getDate(){
|
||||
return date("Y-m-d H:i:s", $this->_timestamp);
|
||||
}
|
||||
|
||||
function getTime(){
|
||||
return date("H:i:s", $this->_timestamp);
|
||||
}
|
||||
|
||||
function setDate($dateString){
|
||||
}
|
||||
|
||||
/**
|
||||
* Get time of object construction in the format
|
||||
* YYYY-MM-DD HH:mm:ss
|
||||
*/
|
||||
function getDate()
|
||||
{
|
||||
return date("Y-m-d H:i:s", $this->_timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get time of object construction in the format
|
||||
* HH:mm:ss
|
||||
*/
|
||||
function getTime()
|
||||
{
|
||||
return date("H:i:s", $this->_timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the internal timestamp of the object.
|
||||
*/
|
||||
function setDate($dateString)
|
||||
{
|
||||
$this->_timestamp = strtotime($dateString);
|
||||
}
|
||||
|
||||
function getNowDayStartDiff(){
|
||||
$dayStartTS = strtotime(date("Y-m-d", $this->_timestamp));
|
||||
return $this->_timestamp - $dayStartTS;
|
||||
}
|
||||
}
|
||||
|
||||
function getNowDayEndDiff(){
|
||||
$dayEndTS = strtotime(date("Y-m-d", $this->_timestamp+(86400)));
|
||||
return $dayEndTS - $this->_timestamp;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* Enter description here ...
|
||||
*/
|
||||
function getNowDayStartDiff()
|
||||
{
|
||||
$dayStartTS = strtotime(date("Y-m-d", $this->_timestamp));
|
||||
return $this->_timestamp - $dayStartTS;
|
||||
}
|
||||
|
||||
function getEpochTime(){
|
||||
function getNowDayEndDiff()
|
||||
{
|
||||
$dayEndTS = strtotime(date("Y-m-d", $this->_timestamp+(86400)));
|
||||
return $dayEndTS - $this->_timestamp;
|
||||
}
|
||||
|
||||
function getEpochTime()
|
||||
{
|
||||
return $this->_timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
public static function TimeDiff($time1, $time2){
|
||||
public static function TimeDiff($time1, $time2)
|
||||
{
|
||||
return strtotime($time2) - strtotime($time1);
|
||||
}
|
||||
|
||||
public static function ConvertMSToHHMMSSmm($time){
|
||||
}
|
||||
|
||||
public static function ConvertMSToHHMMSSmm($time)
|
||||
{
|
||||
$hours = floor($time / 3600000);
|
||||
$time -= 3600000*$hours;
|
||||
|
||||
|
||||
$minutes = floor($time / 60000);
|
||||
$time -= 60000*$minutes;
|
||||
|
||||
|
||||
$seconds = floor($time / 1000);
|
||||
$time -= 1000*$seconds;
|
||||
|
||||
|
||||
$ms = $time;
|
||||
|
||||
|
||||
if (strlen($hours) == 1)
|
||||
$hours = "0".$hours;
|
||||
$hours = "0".$hours;
|
||||
if (strlen($minutes) == 1)
|
||||
$minutes = "0".$minutes;
|
||||
$minutes = "0".$minutes;
|
||||
if (strlen($seconds) == 1)
|
||||
$seconds = "0".$seconds;
|
||||
|
||||
$seconds = "0".$seconds;
|
||||
|
||||
return $hours.":".$minutes.":".$seconds.".".$ms;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,30 +8,30 @@ class Application_Model_Preference
|
|||
|
||||
$auth = Zend_Auth::getInstance();
|
||||
$id = $auth->getIdentity()->id;
|
||||
|
||||
|
||||
//Check if key already exists
|
||||
$sql = "SELECT COUNT(*) FROM cc_pref"
|
||||
." WHERE keystr = '$key'";
|
||||
$result = $CC_DBC->GetOne($sql);
|
||||
|
||||
|
||||
if ($result == 1){
|
||||
$sql = "UPDATE cc_pref"
|
||||
." SET subjid = $id, valstr = '$value'"
|
||||
." WHERE keystr = '$key'";
|
||||
." WHERE keystr = '$key'";
|
||||
} else {
|
||||
$sql = "INSERT INTO cc_pref (subjid, keystr, valstr)"
|
||||
." VALUES ($id, '$key', '$value')";
|
||||
}
|
||||
return $CC_DBC->query($sql);
|
||||
}
|
||||
|
||||
|
||||
public static function GetValue($key){
|
||||
global $CC_CONFIG, $CC_DBC;
|
||||
//Check if key already exists
|
||||
$sql = "SELECT COUNT(*) FROM cc_pref"
|
||||
." WHERE keystr = '$key'";
|
||||
$result = $CC_DBC->GetOne($sql);
|
||||
|
||||
|
||||
if ($result == 0)
|
||||
return "";
|
||||
else {
|
||||
|
@ -40,9 +40,9 @@ class Application_Model_Preference
|
|||
$result = $CC_DBC->GetOne($sql);
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static function GetHeadTitle(){
|
||||
/* Caches the title name as a session variable so we dont access
|
||||
* the database on every page load. */
|
||||
|
@ -55,31 +55,32 @@ class Application_Model_Preference
|
|||
}
|
||||
if (strlen($title) > 0)
|
||||
$title .= " - ";
|
||||
|
||||
|
||||
return $title."Airtime";
|
||||
}
|
||||
|
||||
|
||||
public static function SetHeadTitle($title, $view){
|
||||
Application_Model_Preference::SetValue("station_name", $title);
|
||||
$defaultNamespace = new Zend_Session_Namespace('title_name');
|
||||
Application_Model_Preference::SetValue("station_name", $title);
|
||||
$defaultNamespace = new Zend_Session_Namespace('title_name');
|
||||
$defaultNamespace->title = $title;
|
||||
|
||||
RabbitMq::PushSchedule();
|
||||
|
||||
//set session variable to new station name so that html title is updated.
|
||||
//should probably do this in a view helper to keep this controller as minimal as possible.
|
||||
$view->headTitle()->exchangeArray(array()); //clear headTitle ArrayObject
|
||||
$view->headTitle(Application_Model_Preference::GetHeadTitle());
|
||||
}
|
||||
|
||||
public static function SetShowsPopulatedUntil($timestamp) {
|
||||
Application_Model_Preference::SetValue("shows_populated_until", $timestamp);
|
||||
public static function SetShowsPopulatedUntil($timestamp) {
|
||||
Application_Model_Preference::SetValue("shows_populated_until", $timestamp);
|
||||
}
|
||||
|
||||
public static function GetShowsPopulatedUntil() {
|
||||
return Application_Model_Preference::GetValue("shows_populated_until");
|
||||
}
|
||||
|
||||
public static function SetDefaultFade($fade) {
|
||||
Application_Model_Preference::SetValue("default_fade", $fade);
|
||||
public static function SetDefaultFade($fade) {
|
||||
Application_Model_Preference::SetValue("default_fade", $fade);
|
||||
}
|
||||
|
||||
public static function GetDefaultFade() {
|
||||
|
@ -88,6 +89,7 @@ class Application_Model_Preference
|
|||
|
||||
public static function SetStreamLabelFormat($type){
|
||||
Application_Model_Preference::SetValue("stream_label_format", $type);
|
||||
RabbitMq::PushSchedule();
|
||||
}
|
||||
|
||||
public static function GetStreamLabelFormat(){
|
||||
|
@ -97,5 +99,38 @@ class Application_Model_Preference
|
|||
public static function GetStationName(){
|
||||
return Application_Model_Preference::getValue("station_name");
|
||||
}
|
||||
|
||||
public static function SetDoSoundCloudUpload($upload) {
|
||||
Application_Model_Preference::SetValue("soundcloud_upload", $upload);
|
||||
}
|
||||
|
||||
public static function GetDoSoundCloudUpload() {
|
||||
return Application_Model_Preference::GetValue("soundcloud_upload");
|
||||
}
|
||||
|
||||
public static function SetSoundCloudUser($user) {
|
||||
Application_Model_Preference::SetValue("soundcloud_user", $user);
|
||||
}
|
||||
|
||||
public static function GetSoundCloudUser() {
|
||||
return Application_Model_Preference::GetValue("soundcloud_user");
|
||||
}
|
||||
|
||||
public static function SetSoundCloudPassword($password) {
|
||||
Application_Model_Preference::SetValue("soundcloud_password", $password);
|
||||
}
|
||||
|
||||
public static function GetSoundCloudPassword() {
|
||||
return Application_Model_Preference::GetValue("soundcloud_password");
|
||||
}
|
||||
|
||||
public static function SetSoundCloudTags($tags) {
|
||||
Application_Model_Preference::SetValue("soundcloud_tags", $tags);
|
||||
}
|
||||
|
||||
public static function GetSoundCloudTags() {
|
||||
return Application_Model_Preference::GetValue("soundcloud_tags");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
require_once 'php-amqplib/amqp.inc';
|
||||
|
||||
class RabbitMq
|
||||
{
|
||||
static private $doPush = FALSE;
|
||||
|
||||
/**
|
||||
* Sets a flag to push the schedule at the end of the request.
|
||||
*/
|
||||
public static function PushSchedule() {
|
||||
RabbitMq::$doPush = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push the current schedule to RabbitMQ, to be picked up by Pypo.
|
||||
* Will push the schedule in the range from 24 hours ago to 24 hours
|
||||
* in the future.
|
||||
*/
|
||||
public static function PushScheduleFinal()
|
||||
{
|
||||
global $CC_CONFIG;
|
||||
if (RabbitMq::$doPush) {
|
||||
$conn = new AMQPConnection($CC_CONFIG["rabbitmq"]["host"],
|
||||
$CC_CONFIG["rabbitmq"]["port"],
|
||||
$CC_CONFIG["rabbitmq"]["user"],
|
||||
$CC_CONFIG["rabbitmq"]["password"]);
|
||||
$channel = $conn->channel();
|
||||
$channel->access_request($CC_CONFIG["rabbitmq"]["vhost"], false, false, true, true);
|
||||
|
||||
$EXCHANGE = 'airtime-schedule';
|
||||
$channel->exchange_declare($EXCHANGE, 'direct', false, true);
|
||||
|
||||
$data = json_encode(Schedule::GetScheduledPlaylists());
|
||||
$msg = new AMQPMessage($data, array('content_type' => 'text/plain'));
|
||||
|
||||
$channel->basic_publish($msg, $EXCHANGE);
|
||||
$channel->close();
|
||||
$conn->close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -24,41 +24,6 @@ class ScheduleGroup {
|
|||
return $result != "0";
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a date to an ID by stripping out all characters
|
||||
* and padding with zeros.
|
||||
*
|
||||
* @param string $p_dateStr
|
||||
*/
|
||||
public static function dateToId($p_dateStr) {
|
||||
$p_dateStr = str_replace(":", "", $p_dateStr);
|
||||
$p_dateStr = str_replace(" ", "", $p_dateStr);
|
||||
$p_dateStr = str_replace(".", "", $p_dateStr);
|
||||
$p_dateStr = str_replace("-", "", $p_dateStr);
|
||||
$p_dateStr = substr($p_dateStr, 0, 17);
|
||||
$p_dateStr = str_pad($p_dateStr, 17, "0");
|
||||
return $p_dateStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the two times together, return the result.
|
||||
*
|
||||
* @param string $p_baseTime
|
||||
* Specified as YYYY-MM-DD HH:MM:SS
|
||||
*
|
||||
* @param string $p_addTime
|
||||
* Specified as HH:MM:SS.nnnnnn
|
||||
*
|
||||
* @return string
|
||||
* The end time, to the nearest second.
|
||||
*/
|
||||
// protected function calculateEndTime($p_startTime, $p_trackTime) {
|
||||
// $p_trackTime = substr($p_startTime, 0, );
|
||||
// $start = new DateTime();
|
||||
// $interval = new DateInterval()
|
||||
//
|
||||
// }
|
||||
|
||||
/**
|
||||
* Add a music clip or playlist to the schedule.
|
||||
*
|
||||
|
@ -77,6 +42,7 @@ class ScheduleGroup {
|
|||
*/
|
||||
public function add($show_instance, $p_datetime, $p_audioFileId = null, $p_playlistId = null, $p_options = null) {
|
||||
global $CC_CONFIG, $CC_DBC;
|
||||
|
||||
if (!is_null($p_audioFileId)) {
|
||||
// Schedule a single audio track
|
||||
|
||||
|
@ -92,27 +58,24 @@ class ScheduleGroup {
|
|||
if (empty($length)) {
|
||||
return new PEAR_Error("Length is empty.");
|
||||
}
|
||||
if (!Schedule::isScheduleEmptyInRange($p_datetime, $length)) {
|
||||
return new PEAR_Error("Schedule conflict.", 555);
|
||||
}
|
||||
|
||||
|
||||
// Insert into the table
|
||||
$this->groupId = $CC_DBC->GetOne("SELECT nextval('schedule_group_id_seq')");
|
||||
$id = $this->dateToId($p_datetime);
|
||||
|
||||
$sql = "INSERT INTO ".$CC_CONFIG["scheduleTable"]
|
||||
." (playlist_id, starts, ends, clip_length, group_id, file_id)"
|
||||
." VALUES (0, TIMESTAMP '$p_datetime', "
|
||||
." (instance_id, starts, ends, clip_length, group_id, file_id, cue_out)"
|
||||
." VALUES ($show_instance, TIMESTAMP '$p_datetime', "
|
||||
." (TIMESTAMP '$p_datetime' + INTERVAL '$length'),"
|
||||
." '$length',"
|
||||
." {$this->groupId}, $p_audioFileId)";
|
||||
." {$this->groupId}, $p_audioFileId, '$length')";
|
||||
$result = $CC_DBC->query($sql);
|
||||
if (PEAR::isError($result)) {
|
||||
//var_dump($sql);
|
||||
return $result;
|
||||
}
|
||||
return $this->groupId;
|
||||
|
||||
} elseif (!is_null($p_playlistId)){
|
||||
}
|
||||
elseif (!is_null($p_playlistId)){
|
||||
// Schedule a whole playlist
|
||||
|
||||
// Load existing playlist
|
||||
|
@ -130,7 +93,6 @@ class ScheduleGroup {
|
|||
|
||||
// Insert all items into the schedule
|
||||
$this->groupId = $CC_DBC->GetOne("SELECT nextval('schedule_group_id_seq')");
|
||||
$id = $this->dateToId($p_datetime);
|
||||
$itemStartTime = $p_datetime;
|
||||
|
||||
$plItems = $playlist->getContents();
|
||||
|
@ -151,13 +113,13 @@ class ScheduleGroup {
|
|||
return $result;
|
||||
}
|
||||
$itemStartTime = $CC_DBC->getOne("SELECT TIMESTAMP '$itemStartTime' + INTERVAL '$trackLength'");
|
||||
$id = $this->dateToId($itemStartTime);
|
||||
}
|
||||
return $this->groupId;
|
||||
}
|
||||
RabbitMq::PushSchedule();
|
||||
return $this->groupId;
|
||||
}
|
||||
|
||||
public function addAfter($show_instance, $p_groupId, $p_audioFileId) {
|
||||
public function addFileAfter($show_instance, $p_groupId, $p_audioFileId) {
|
||||
global $CC_CONFIG, $CC_DBC;
|
||||
// Get the end time for the given entry
|
||||
$sql = "SELECT MAX(ends) FROM ".$CC_CONFIG["scheduleTable"]
|
||||
|
@ -176,10 +138,6 @@ class ScheduleGroup {
|
|||
return $this->add($show_instance, $startTime, null, $p_playlistId);
|
||||
}
|
||||
|
||||
public function update() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the group from the schedule.
|
||||
* Note: does not check if it is in the past, you can remove anything.
|
||||
|
@ -195,7 +153,9 @@ class ScheduleGroup {
|
|||
$sql = "DELETE FROM ".$CC_CONFIG["scheduleTable"]
|
||||
." WHERE group_id = ".$this->groupId;
|
||||
//echo $sql;
|
||||
return $CC_DBC->query($sql);
|
||||
$retVal = $CC_DBC->query($sql);
|
||||
RabbitMq::PushSchedule();
|
||||
return $retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -231,17 +191,13 @@ class ScheduleGroup {
|
|||
return $CC_DBC->GetAll($sql);
|
||||
}
|
||||
|
||||
public function reschedule($toDateTime) {
|
||||
global $CC_CONFIG, $CC_DBC;
|
||||
// $sql = "UPDATE ".$CC_CONFIG["scheduleTable"]. " SET id=, starts=,ends="
|
||||
}
|
||||
|
||||
public function notifyGroupStartPlay() {
|
||||
global $CC_CONFIG, $CC_DBC;
|
||||
$sql = "UPDATE ".$CC_CONFIG['scheduleTable']
|
||||
." SET schedule_group_played=TRUE"
|
||||
." WHERE group_id=".$this->groupId;
|
||||
return $CC_DBC->query($sql);
|
||||
$retVal = $CC_DBC->query($sql);
|
||||
return $retVal;
|
||||
}
|
||||
|
||||
public function notifyMediaItemStartPlay($p_fileId) {
|
||||
|
@ -250,7 +206,8 @@ class ScheduleGroup {
|
|||
." SET media_item_played=TRUE"
|
||||
." WHERE group_id=".$this->groupId
|
||||
." AND file_id=".pg_escape_string($p_fileId);
|
||||
return $CC_DBC->query($sql);
|
||||
$retVal = $CC_DBC->query($sql);
|
||||
return $retVal;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -334,9 +291,10 @@ class Schedule {
|
|||
return $res;
|
||||
}
|
||||
|
||||
public static function GetPercentScheduled($instance_id, $s_datetime, $e_datetime){
|
||||
public static function GetPercentScheduled($instance_id, $s_datetime, $e_datetime)
|
||||
{
|
||||
$time = Schedule::GetTotalShowTime($instance_id);
|
||||
|
||||
|
||||
$s_epoch = strtotime($s_datetime);
|
||||
$e_epoch = strtotime($e_datetime);
|
||||
|
||||
|
@ -396,12 +354,14 @@ class Schedule {
|
|||
* @return array
|
||||
* Returns empty array if nothing found
|
||||
*/
|
||||
public static function GetItems($p_fromDateTime, $p_toDateTime, $p_playlistsOnly = true) {
|
||||
|
||||
public static function GetItems($p_currentDateTime, $p_toDateTime, $p_playlistsOnly = true)
|
||||
{
|
||||
global $CC_CONFIG, $CC_DBC;
|
||||
$rows = array();
|
||||
if (!$p_playlistsOnly) {
|
||||
$sql = "SELECT * FROM ".$CC_CONFIG["scheduleTable"]
|
||||
." WHERE (starts >= TIMESTAMP '$p_fromDateTime') "
|
||||
." WHERE (starts >= TIMESTAMP '$p_currentDateTime') "
|
||||
." AND (ends <= TIMESTAMP '$p_toDateTime')";
|
||||
$rows = $CC_DBC->GetAll($sql);
|
||||
foreach ($rows as &$row) {
|
||||
|
@ -429,11 +389,11 @@ class Schedule {
|
|||
." ON st.instance_id = si.id"
|
||||
." LEFT JOIN $CC_CONFIG[showTable] as sh"
|
||||
." ON si.show_id = sh.id"
|
||||
." WHERE (st.starts >= TIMESTAMP '$p_fromDateTime')"
|
||||
." WHERE (st.ends >= TIMESTAMP '$p_currentDateTime')"
|
||||
." AND (st.ends <= TIMESTAMP '$p_toDateTime')"
|
||||
//next line makes sure that we aren't returning items that
|
||||
//are past the show's scheduled timeslot.
|
||||
." AND (st.starts < si.ends)"
|
||||
." AND (st.starts < si.ends)"
|
||||
." GROUP BY st.group_id"
|
||||
." ORDER BY starts";
|
||||
|
||||
|
@ -457,7 +417,8 @@ class Schedule {
|
|||
* @param int $next
|
||||
* @return date
|
||||
*/
|
||||
public static function GetPlayOrderRange($prev = 1, $next = 1) {
|
||||
public static function GetPlayOrderRange($prev = 1, $next = 1)
|
||||
{
|
||||
if (!is_int($prev) || !is_int($next)){
|
||||
//must enter integers to specify ranges
|
||||
return array();
|
||||
|
@ -469,11 +430,11 @@ class Schedule {
|
|||
$timeNow = $date->getDate();
|
||||
return array("env"=>APPLICATION_ENV,
|
||||
"schedulerTime"=>gmdate("Y-m-d H:i:s"),
|
||||
"previous"=>Schedule::Get_Scheduled_Item_Data($timeNow, -1, $prev, "24 hours"),
|
||||
"current"=>Schedule::Get_Scheduled_Item_Data($timeNow, 0),
|
||||
"next"=>Schedule::Get_Scheduled_Item_Data($timeNow, 1, $next, "48 hours"),
|
||||
"previous"=>Schedule::GetScheduledItemData($timeNow, -1, $prev, "24 hours"),
|
||||
"current"=>Schedule::GetScheduledItemData($timeNow, 0),
|
||||
"next"=>Schedule::GetScheduledItemData($timeNow, 1, $next, "48 hours"),
|
||||
"currentShow"=>Show_DAL::GetCurrentShow($timeNow),
|
||||
"nextShow"=>Show_DAL::GetNextShow($timeNow),
|
||||
"nextShow"=>Show_DAL::GetNextShows($timeNow, 1),
|
||||
"timezone"=> date("T"),
|
||||
"timezoneOffset"=> date("Z"),
|
||||
"apiKey"=>$CC_CONFIG['apiKey'][0]);
|
||||
|
@ -501,7 +462,8 @@ class Schedule {
|
|||
* want to search the database. For example "5 days", "18 hours", "60 minutes",
|
||||
* "30 seconds" etc.
|
||||
*/
|
||||
public static function Get_Scheduled_Item_Data($timeStamp, $timePeriod=0, $count = 0, $interval="0 hours"){
|
||||
public static function GetScheduledItemData($timeStamp, $timePeriod=0, $count = 0, $interval="0 hours")
|
||||
{
|
||||
global $CC_CONFIG, $CC_DBC;
|
||||
|
||||
$sql = "SELECT DISTINCT pt.name, ft.track_title, ft.artist_name, ft.album_title, st.starts, st.ends, st.clip_length, st.media_item_played, st.group_id, show.name as show_name, st.instance_id"
|
||||
|
@ -531,7 +493,8 @@ class Schedule {
|
|||
return $rows;
|
||||
}
|
||||
|
||||
public static function GetShowInstanceItems($instance_id){
|
||||
public static function GetShowInstanceItems($instance_id)
|
||||
{
|
||||
global $CC_CONFIG, $CC_DBC;
|
||||
|
||||
$sql = "SELECT DISTINCT pt.name, ft.track_title, ft.artist_name, ft.album_title, st.starts, st.ends, st.clip_length, st.media_item_played, st.group_id, show.name as show_name, st.instance_id"
|
||||
|
@ -547,12 +510,14 @@ class Schedule {
|
|||
return $rows;
|
||||
}
|
||||
|
||||
public static function UpdateMediaPlayedStatus($id){
|
||||
public static function UpdateMediaPlayedStatus($p_id)
|
||||
{
|
||||
global $CC_CONFIG, $CC_DBC;
|
||||
$sql = "UPDATE ".$CC_CONFIG['scheduleTable']
|
||||
." SET media_item_played=TRUE"
|
||||
." WHERE id=$id";
|
||||
return $CC_DBC->query($sql);
|
||||
." WHERE id=$p_id";
|
||||
$retVal = $CC_DBC->query($sql);
|
||||
return $retVal;
|
||||
}
|
||||
|
||||
|
||||
|
@ -563,7 +528,7 @@ class Schedule {
|
|||
* @param string $p_time
|
||||
* @return string
|
||||
*/
|
||||
private static function CcTimeToPypoTime($p_time)
|
||||
private static function AirtimeTimeToPypoTime($p_time)
|
||||
{
|
||||
$p_time = substr($p_time, 0, 19);
|
||||
$p_time = str_replace(" ", "-", $p_time);
|
||||
|
@ -578,7 +543,7 @@ class Schedule {
|
|||
* @param string $p_time
|
||||
* @return string
|
||||
*/
|
||||
private static function PypoTimeToCcTime($p_time)
|
||||
private static function PypoTimeToAirtimeTime($p_time)
|
||||
{
|
||||
$t = explode("-", $p_time);
|
||||
return $t[0]."-".$t[1]."-".$t[2]." ".$t[3].":".$t[4].":00";
|
||||
|
@ -658,17 +623,21 @@ class Schedule {
|
|||
/**
|
||||
* Export the schedule in json formatted for pypo (the liquidsoap scheduler)
|
||||
*
|
||||
* @param string $range
|
||||
* In the format "YYYY-MM-DD HH:mm:ss"
|
||||
* @param string $source
|
||||
* In the format "YYYY-MM-DD HH:mm:ss"
|
||||
* @param string $p_fromDateTime
|
||||
* In the format "YYYY-MM-DD-HH-mm-SS"
|
||||
* @param string $p_toDateTime
|
||||
* In the format "YYYY-MM-DD-HH-mm-SS"
|
||||
*/
|
||||
public static function ExportRangeAsJson($p_fromDateTime, $p_toDateTime)
|
||||
public static function GetScheduledPlaylists()
|
||||
{
|
||||
global $CC_CONFIG, $CC_DBC;
|
||||
|
||||
$range_start = Schedule::PypoTimeToCcTime($p_fromDateTime);
|
||||
$range_end = Schedule::PypoTimeToCcTime($p_toDateTime);
|
||||
$t1 = new DateTime();
|
||||
$range_start = $t1->format("Y-m-d H:i:s");
|
||||
|
||||
$t2 = new DateTime();
|
||||
$t2->add(new DateInterval("PT24H"));
|
||||
$range_end = $t2->format("Y-m-d H:i:s");
|
||||
|
||||
// Scheduler wants everything in a playlist
|
||||
$data = Schedule::GetItems($range_start, $range_end, true);
|
||||
|
@ -684,10 +653,10 @@ class Schedule {
|
|||
$start = substr($start, 0, 19);
|
||||
|
||||
//Start time is the array key, needs to be in the format "YYYY-MM-DD-HH-mm-ss"
|
||||
$pkey = Schedule::CcTimeToPypoTime($start);
|
||||
$pkey = Schedule::AirtimeTimeToPypoTime($start);
|
||||
$timestamp = strtotime($start);
|
||||
$playlists[$pkey]['source'] = "PLAYLIST";
|
||||
$playlists[$pkey]['x_ident'] = $dx["playlist_id"];
|
||||
$playlists[$pkey]['x_ident'] = $dx['group_id'];
|
||||
$playlists[$pkey]['subtype'] = '1'; // Just needs to be between 1 and 4 inclusive
|
||||
$playlists[$pkey]['timestamp'] = $timestamp;
|
||||
$playlists[$pkey]['duration'] = $dx['clip_length'];
|
||||
|
@ -695,9 +664,9 @@ class Schedule {
|
|||
$playlists[$pkey]['schedule_id'] = $dx['group_id'];
|
||||
$playlists[$pkey]['show_name'] = $dx['show_name'];
|
||||
$playlists[$pkey]['user_id'] = 0;
|
||||
$playlists[$pkey]['id'] = $dx["playlist_id"];
|
||||
$playlists[$pkey]['start'] = Schedule::CcTimeToPypoTime($dx["start"]);
|
||||
$playlists[$pkey]['end'] = Schedule::CcTimeToPypoTime($dx["end"]);
|
||||
$playlists[$pkey]['id'] = $dx['group_id'];
|
||||
$playlists[$pkey]['start'] = Schedule::AirtimeTimeToPypoTime($dx["start"]);
|
||||
$playlists[$pkey]['end'] = Schedule::AirtimeTimeToPypoTime($dx["end"]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -734,30 +703,15 @@ class Schedule {
|
|||
|
||||
$result = array();
|
||||
$result['status'] = array('range' => array('start' => $range_start, 'end' => $range_end),
|
||||
'version' => "1.1");
|
||||
'version' => AIRTIME_REST_VERSION);
|
||||
$result['playlists'] = $playlists;
|
||||
$result['check'] = 1;
|
||||
$result['stream_metadata'] = array();
|
||||
$result['stream_metadata']['format'] = Application_Model_Preference::GetStreamLabelFormat();
|
||||
$result['stream_metadata']['station_name'] = Application_Model_Preference::GetStationName();
|
||||
$result['server_timezone'] = date('O');
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove all items from the schedule in the given range.
|
||||
*
|
||||
* @param string $p_start
|
||||
* In the format YYYY-MM-DD HH:MM:SS.nnnnnn
|
||||
* @param string $p_end
|
||||
* In the format YYYY-MM-DD HH:MM:SS.nnnnnn
|
||||
*/
|
||||
public static function RemoveItemsInRange($p_start, $p_end)
|
||||
{
|
||||
$items = Schedule::GetItems($p_start, $p_end);
|
||||
foreach ($items as $item) {
|
||||
$scheduleGroup = new ScheduleGroup($item["group_id"]);
|
||||
$scheduleGroup->remove();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -6,50 +6,60 @@ class Show {
|
|||
|
||||
public function __construct($showId=NULL)
|
||||
{
|
||||
$this->_showId = $showId;
|
||||
$this->_showId = $showId;
|
||||
}
|
||||
|
||||
public function getName() {
|
||||
public function getName()
|
||||
{
|
||||
$show = CcShowQuery::create()->findPK($this->_showId);
|
||||
return $show->getDbName();
|
||||
}
|
||||
|
||||
public function setName($name) {
|
||||
|
||||
public function setName($name)
|
||||
{
|
||||
$show = CcShowQuery::create()->findPK($this->_showId);
|
||||
$show->setDbName($name);
|
||||
RabbitMq::PushSchedule();
|
||||
}
|
||||
|
||||
public function getDescription() {
|
||||
public function getDescription()
|
||||
{
|
||||
$show = CcShowQuery::create()->findPK($this->_showId);
|
||||
return $show->getDbDescription();
|
||||
}
|
||||
|
||||
public function setDescription($description) {
|
||||
|
||||
public function setDescription($description)
|
||||
{
|
||||
$show = CcShowQuery::create()->findPK($this->_showId);
|
||||
$show->setDbDescription($description);
|
||||
}
|
||||
|
||||
public function getColor() {
|
||||
public function getColor()
|
||||
{
|
||||
$show = CcShowQuery::create()->findPK($this->_showId);
|
||||
return $show->getDbColor();
|
||||
}
|
||||
|
||||
public function setColor($color) {
|
||||
|
||||
public function setColor($color)
|
||||
{
|
||||
$show = CcShowQuery::create()->findPK($this->_showId);
|
||||
$show->setDbColor($color);
|
||||
}
|
||||
|
||||
public function getBackgroundColor() {
|
||||
public function getBackgroundColor()
|
||||
{
|
||||
$show = CcShowQuery::create()->findPK($this->_showId);
|
||||
return $show->getDbBackgroundColor();
|
||||
}
|
||||
|
||||
public function setBackgroundColor($backgroundColor) {
|
||||
|
||||
public function setBackgroundColor($backgroundColor)
|
||||
{
|
||||
$show = CcShowQuery::create()->findPK($this->_showId);
|
||||
$show->setDbBackgroundColor($backgroundColor);
|
||||
}
|
||||
|
||||
public function cancelShow($day_timestamp) {
|
||||
public function cancelShow($day_timestamp)
|
||||
{
|
||||
global $CC_DBC;
|
||||
|
||||
$timeinfo = explode(" ", $day_timestamp);
|
||||
|
@ -62,20 +72,21 @@ class Show {
|
|||
WHERE starts >= '{$day_timestamp}' AND show_id = {$this->_showId}";
|
||||
|
||||
$CC_DBC->query($sql);
|
||||
RabbitMq::PushSchedule();
|
||||
}
|
||||
|
||||
//end dates are non inclusive.
|
||||
public static function addShow($data) {
|
||||
|
||||
public static function addShow($data)
|
||||
{
|
||||
$con = Propel::getConnection(CcShowPeer::DATABASE_NAME);
|
||||
|
||||
$sql = "SELECT time '{$data['add_show_start_time']}' + INTERVAL '{$data['add_show_duration']} hour' ";
|
||||
$r = $con->query($sql);
|
||||
$endTime = $r->fetchColumn(0);
|
||||
$endTime = $r->fetchColumn(0);
|
||||
|
||||
$sql = "SELECT EXTRACT(DOW FROM TIMESTAMP '{$data['add_show_start_date']} {$data['add_show_start_time']}')";
|
||||
$r = $con->query($sql);
|
||||
$startDow = $r->fetchColumn(0);
|
||||
$startDow = $r->fetchColumn(0);
|
||||
|
||||
if($data['add_show_no_end']) {
|
||||
$endDate = NULL;
|
||||
|
@ -84,13 +95,13 @@ class Show {
|
|||
else if($data['add_show_repeats']) {
|
||||
$sql = "SELECT date '{$data['add_show_end_date']}' + INTERVAL '1 day' ";
|
||||
$r = $con->query($sql);
|
||||
$endDate = $r->fetchColumn(0);
|
||||
$endDate = $r->fetchColumn(0);
|
||||
}
|
||||
else {
|
||||
$sql = "SELECT date '{$data['add_show_start_date']}' + INTERVAL '1 day' ";
|
||||
$r = $con->query($sql);
|
||||
$endDate = $r->fetchColumn(0);
|
||||
}
|
||||
}
|
||||
|
||||
//only want the day of the week from the start date.
|
||||
if(!$data['add_show_repeats']) {
|
||||
|
@ -98,7 +109,7 @@ class Show {
|
|||
}
|
||||
else if($data['add_show_repeats'] && $data['add_show_day_check'] == "") {
|
||||
$data['add_show_day_check'] = array($startDow);
|
||||
}
|
||||
}
|
||||
|
||||
//find repeat type or set to a non repeating show.
|
||||
if($data['add_show_repeats']) {
|
||||
|
@ -114,7 +125,7 @@ class Show {
|
|||
$show->setDbUrl($data['add_show_url']);
|
||||
$show->setDbColor($data['add_show_color']);
|
||||
$show->setDbBackgroundColor($data['add_show_background_color']);
|
||||
$show->save();
|
||||
$show->save();
|
||||
|
||||
$showId = $show->getDbId();
|
||||
|
||||
|
@ -127,7 +138,6 @@ class Show {
|
|||
|
||||
//don't set day for monthly repeat type, it's invalid.
|
||||
if($data['add_show_repeats'] && $data["add_show_repeat_type"] == 2) {
|
||||
|
||||
$showDay = new CcShowDays();
|
||||
$showDay->setDbFirstShow($data['add_show_start_date']);
|
||||
$showDay->setDbLastShow($endDate);
|
||||
|
@ -137,29 +147,25 @@ class Show {
|
|||
$showDay->setDbShowId($showId);
|
||||
$showDay->setDbRecord($isRecorded);
|
||||
$showDay->save();
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
foreach ($data['add_show_day_check'] as $day) {
|
||||
|
||||
if($startDow !== $day){
|
||||
|
||||
if($startDow > $day)
|
||||
|
||||
if ($startDow > $day)
|
||||
$daysAdd = 6 - $startDow + 1 + $day;
|
||||
else
|
||||
$daysAdd = $day - $startDow;
|
||||
$daysAdd = $day - $startDow;
|
||||
|
||||
$sql = "SELECT date '{$data['add_show_start_date']}' + INTERVAL '{$daysAdd} day' ";
|
||||
$r = $con->query($sql);
|
||||
$start = $r->fetchColumn(0);
|
||||
$start = $r->fetchColumn(0);
|
||||
}
|
||||
else {
|
||||
$start = $data['add_show_start_date'];
|
||||
}
|
||||
|
||||
if(strtotime($start) < strtotime($endDate) || is_null($endDate)) {
|
||||
|
||||
$showDay = new CcShowDays();
|
||||
$showDay->setDbFirstShow($start);
|
||||
$showDay->setDbLastShow($endDate);
|
||||
|
@ -180,7 +186,6 @@ class Show {
|
|||
for($i=1; $i<=5; $i++) {
|
||||
|
||||
if($data['add_show_rebroadcast_date_'.$i]) {
|
||||
|
||||
$showRebroad = new CcShowRebroadcast();
|
||||
$showRebroad->setDbDayOffset($data['add_show_rebroadcast_date_'.$i]);
|
||||
$showRebroad->setDbStartTime($data['add_show_rebroadcast_time_'.$i]);
|
||||
|
@ -190,14 +195,13 @@ class Show {
|
|||
}
|
||||
}
|
||||
else if($data['add_show_record'] && $data['add_show_rebroadcast'] && $repeat_type == -1){
|
||||
|
||||
|
||||
for($i=1; $i<=5; $i++) {
|
||||
|
||||
if($data['add_show_rebroadcast_absolute_date_'.$i]) {
|
||||
|
||||
$sql = "SELECT date '{$data['add_show_rebroadcast_absolute_date_'.$i]}' - date '{$data['add_show_start_date']}' ";
|
||||
$r = $con->query($sql);
|
||||
$offset_days = $r->fetchColumn(0);
|
||||
$offset_days = $r->fetchColumn(0);
|
||||
|
||||
$showRebroad = new CcShowRebroadcast();
|
||||
$showRebroad->setDbDayOffset($offset_days." days");
|
||||
|
@ -207,7 +211,7 @@ class Show {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(is_array($data['add_show_hosts'])) {
|
||||
//add selected hosts to cc_show_hosts table.
|
||||
foreach ($data['add_show_hosts'] as $host) {
|
||||
|
@ -219,18 +223,20 @@ class Show {
|
|||
}
|
||||
|
||||
Show::populateShowUntilLastGeneratedDate($showId);
|
||||
RabbitMq::PushSchedule();
|
||||
}
|
||||
|
||||
public static function getShows($start_timestamp, $end_timestamp, $excludeInstance=NULL, $onlyRecord=FALSE) {
|
||||
public static function getShows($start_timestamp, $end_timestamp, $excludeInstance=NULL, $onlyRecord=FALSE)
|
||||
{
|
||||
global $CC_DBC;
|
||||
|
||||
$sql = "SELECT starts, ends, record, rebroadcast, instance_id, show_id, name, description,
|
||||
color, background_color, cc_show_instances.id AS instance_id
|
||||
FROM cc_show_instances
|
||||
$sql = "SELECT starts, ends, record, rebroadcast, instance_id, show_id, name, description,
|
||||
color, background_color, cc_show_instances.id AS instance_id
|
||||
FROM cc_show_instances
|
||||
LEFT JOIN cc_show ON cc_show.id = cc_show_instances.show_id";
|
||||
|
||||
//only want shows that are starting at the time or later.
|
||||
if($onlyRecord) {
|
||||
if ($onlyRecord) {
|
||||
|
||||
$sql = $sql." WHERE (starts >= '{$start_timestamp}' AND starts < timestamp '{$start_timestamp}' + interval '2 hours')";
|
||||
$sql = $sql." AND (record = 1)";
|
||||
|
@ -240,10 +246,10 @@ class Show {
|
|||
$sql = $sql." WHERE ((starts >= '{$start_timestamp}' AND starts < '{$end_timestamp}')
|
||||
OR (ends > '{$start_timestamp}' AND ends <= '{$end_timestamp}')
|
||||
OR (starts <= '{$start_timestamp}' AND ends >= '{$end_timestamp}'))";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(isset($excludeInstance)) {
|
||||
|
||||
if (isset($excludeInstance)) {
|
||||
foreach($excludeInstance as $instance) {
|
||||
$sql_exclude[] = "cc_show_instances.id != {$instance}";
|
||||
}
|
||||
|
@ -257,8 +263,8 @@ class Show {
|
|||
return $CC_DBC->GetAll($sql);
|
||||
}
|
||||
|
||||
private static function setNextPop($next_date, $show_id, $day) {
|
||||
|
||||
private static function setNextPop($next_date, $show_id, $day)
|
||||
{
|
||||
$nextInfo = explode(" ", $next_date);
|
||||
|
||||
$repeatInfo = CcShowDaysQuery::create()
|
||||
|
@ -271,15 +277,16 @@ class Show {
|
|||
}
|
||||
|
||||
//for a show with repeat_type == -1
|
||||
private static function populateNonRepeatingShow($show_id, $first_show, $start_time, $duration, $day, $record, $end_timestamp) {
|
||||
private static function populateNonRepeatingShow($show_id, $first_show, $start_time, $duration, $day, $record, $end_timestamp)
|
||||
{
|
||||
global $CC_DBC;
|
||||
|
||||
|
||||
$next_date = $first_show." ".$start_time;
|
||||
|
||||
|
||||
if(strtotime($next_date) < strtotime($end_timestamp)) {
|
||||
|
||||
|
||||
$start = $next_date;
|
||||
|
||||
|
||||
$sql = "SELECT timestamp '{$start}' + interval '{$duration}'";
|
||||
$end = $CC_DBC->GetOne($sql);
|
||||
|
||||
|
@ -298,10 +305,10 @@ class Show {
|
|||
foreach($rebroadcasts as $rebroadcast) {
|
||||
|
||||
$timeinfo = explode(" ", $start);
|
||||
|
||||
|
||||
$sql = "SELECT timestamp '{$timeinfo[0]}' + interval '{$rebroadcast["day_offset"]}' + interval '{$rebroadcast["start_time"]}'";
|
||||
$rebroadcast_start_time = $CC_DBC->GetOne($sql);
|
||||
|
||||
|
||||
$sql = "SELECT timestamp '{$rebroadcast_start_time}' + interval '{$duration}'";
|
||||
$rebroadcast_end_time = $CC_DBC->GetOne($sql);
|
||||
|
||||
|
@ -315,12 +322,13 @@ class Show {
|
|||
$newRebroadcastInstance->save();
|
||||
}
|
||||
}
|
||||
RabbitMq::PushSchedule();
|
||||
}
|
||||
|
||||
//for a show with repeat_type == 0,1,2
|
||||
private static function populateRepeatingShow($show_id, $next_pop_date, $first_show, $last_show,
|
||||
private static function populateRepeatingShow($show_id, $next_pop_date, $first_show, $last_show,
|
||||
$start_time, $duration, $day, $record, $end_timestamp, $interval) {
|
||||
global $CC_DBC;
|
||||
global $CC_DBC;
|
||||
|
||||
if(isset($next_pop_date)) {
|
||||
$next_date = $next_pop_date." ".$start_time;
|
||||
|
@ -333,9 +341,9 @@ class Show {
|
|||
$rebroadcasts = $CC_DBC->GetAll($sql);
|
||||
|
||||
while(strtotime($next_date) < strtotime($end_timestamp) && (strtotime($last_show) > strtotime($next_date) || is_null($last_show))) {
|
||||
|
||||
|
||||
$start = $next_date;
|
||||
|
||||
|
||||
$sql = "SELECT timestamp '{$start}' + interval '{$duration}'";
|
||||
$end = $CC_DBC->GetOne($sql);
|
||||
|
||||
|
@ -351,10 +359,10 @@ class Show {
|
|||
foreach($rebroadcasts as $rebroadcast) {
|
||||
|
||||
$timeinfo = explode(" ", $next_date);
|
||||
|
||||
|
||||
$sql = "SELECT timestamp '{$timeinfo[0]}' + interval '{$rebroadcast["day_offset"]}' + interval '{$rebroadcast["start_time"]}'";
|
||||
$rebroadcast_start_time = $CC_DBC->GetOne($sql);
|
||||
|
||||
|
||||
$sql = "SELECT timestamp '{$rebroadcast_start_time}' + interval '{$duration}'";
|
||||
$rebroadcast_end_time = $CC_DBC->GetOne($sql);
|
||||
|
||||
|
@ -373,64 +381,65 @@ class Show {
|
|||
}
|
||||
|
||||
Show::setNextPop($next_date, $show_id, $day);
|
||||
RabbitMq::PushSchedule();
|
||||
}
|
||||
|
||||
private static function populateShow($repeat_type, $show_id, $next_pop_date,
|
||||
private static function populateShow($repeat_type, $show_id, $next_pop_date,
|
||||
$first_show, $last_show, $start_time, $duration, $day, $record, $end_timestamp) {
|
||||
|
||||
if($repeat_type == -1) {
|
||||
Show::populateNonRepeatingShow($show_id, $first_show, $start_time, $duration, $day, $record, $end_timestamp);
|
||||
}
|
||||
else if($repeat_type == 0) {
|
||||
Show::populateRepeatingShow($show_id, $next_pop_date, $first_show, $last_show,
|
||||
Show::populateRepeatingShow($show_id, $next_pop_date, $first_show, $last_show,
|
||||
$start_time, $duration, $day, $record, $end_timestamp, '7 days');
|
||||
}
|
||||
else if($repeat_type == 1) {
|
||||
Show::populateRepeatingShow($show_id, $next_pop_date, $first_show, $last_show,
|
||||
Show::populateRepeatingShow($show_id, $next_pop_date, $first_show, $last_show,
|
||||
$start_time, $duration, $day, $record, $end_timestamp, '14 days');
|
||||
}
|
||||
else if($repeat_type == 2) {
|
||||
Show::populateRepeatingShow($show_id, $next_pop_date, $first_show, $last_show,
|
||||
Show::populateRepeatingShow($show_id, $next_pop_date, $first_show, $last_show,
|
||||
$start_time, $duration, $day, $record, $end_timestamp, '1 month');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//used to catch up a newly added show
|
||||
private static function populateShowUntilLastGeneratedDate($show_id) {
|
||||
global $CC_DBC;
|
||||
$showsPopUntil = Application_Model_Preference::GetShowsPopulatedUntil();
|
||||
|
||||
|
||||
$sql = "SELECT * FROM cc_show_days WHERE show_id = {$show_id}";
|
||||
$res = $CC_DBC->GetAll($sql);
|
||||
$res = $CC_DBC->GetAll($sql);
|
||||
|
||||
foreach($res as $row) {
|
||||
Show::populateShow($row["repeat_type"], $row["show_id"], $row["next_pop_date"], $row["first_show"],
|
||||
$row["last_show"], $row["start_time"], $row["duration"], $row["day"], $row["record"], $showsPopUntil);
|
||||
}
|
||||
Show::populateShow($row["repeat_type"], $row["show_id"], $row["next_pop_date"], $row["first_show"],
|
||||
$row["last_show"], $row["start_time"], $row["duration"], $row["day"], $row["record"], $showsPopUntil);
|
||||
}
|
||||
}
|
||||
|
||||
public static function populateShowsUntil($pop_timestamp, $end_timestamp) {
|
||||
global $CC_DBC;
|
||||
|
||||
if($pop_timestamp != "") {
|
||||
$sql = "SELECT * FROM cc_show_days
|
||||
WHERE last_show IS NULL
|
||||
$sql = "SELECT * FROM cc_show_days
|
||||
WHERE last_show IS NULL
|
||||
OR first_show < '{$end_timestamp}' AND last_show > '{$pop_timestamp}'";
|
||||
}
|
||||
else {
|
||||
$today_timestamp = date("Y-m-d");
|
||||
|
||||
$sql = "SELECT * FROM cc_show_days
|
||||
WHERE last_show IS NULL
|
||||
$sql = "SELECT * FROM cc_show_days
|
||||
WHERE last_show IS NULL
|
||||
OR first_show < '{$end_timestamp}' AND last_show > '{$today_timestamp}'";
|
||||
}
|
||||
|
||||
$res = $CC_DBC->GetAll($sql);
|
||||
$res = $CC_DBC->GetAll($sql);
|
||||
|
||||
foreach($res as $row) {
|
||||
Show::populateShow($row["repeat_type"], $row["show_id"], $row["next_pop_date"], $row["first_show"],
|
||||
$row["last_show"], $row["start_time"], $row["duration"], $row["day"], $row["record"], $end_timestamp);
|
||||
}
|
||||
Show::populateShow($row["repeat_type"], $row["show_id"], $row["next_pop_date"], $row["first_show"],
|
||||
$row["last_show"], $row["start_time"], $row["duration"], $row["day"], $row["record"], $end_timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
public static function getFullCalendarEvents($start, $end, $editable=false) {
|
||||
|
@ -460,19 +469,15 @@ class Show {
|
|||
|
||||
private static function makeFullCalendarEvent($show, $options=array()) {
|
||||
global $CC_DBC;
|
||||
|
||||
|
||||
$event = array();
|
||||
|
||||
if($show["rebroadcast"]) {
|
||||
$title = "REBROADCAST ".$show["name"];
|
||||
$event["disableResizing"] = true;
|
||||
}
|
||||
else {
|
||||
$title = $show["name"];
|
||||
}
|
||||
|
||||
$event["id"] = $show["instance_id"];
|
||||
$event["title"] = $title;
|
||||
$event["title"] = $show["name"];
|
||||
$event["start"] = $show["starts"];
|
||||
$event["end"] = $show["ends"];
|
||||
$event["allDay"] = false;
|
||||
|
@ -500,56 +505,68 @@ class ShowInstance {
|
|||
|
||||
public function __construct($instanceId)
|
||||
{
|
||||
$this->_instanceId = $instanceId;
|
||||
$this->_instanceId = $instanceId;
|
||||
}
|
||||
|
||||
public function getShowId() {
|
||||
public function getShowId()
|
||||
{
|
||||
$showInstance = CcShowInstancesQuery::create()->findPK($this->_instanceId);
|
||||
return $showInstance->getDbShowId();
|
||||
}
|
||||
|
||||
public function getShowInstanceId() {
|
||||
public function getShowInstanceId()
|
||||
{
|
||||
return $this->_instanceId;
|
||||
}
|
||||
|
||||
public function isRebroadcast() {
|
||||
public function isRebroadcast()
|
||||
{
|
||||
$showInstance = CcShowInstancesQuery::create()->findPK($this->_instanceId);
|
||||
return $showInstance->getDbOriginalShow();
|
||||
}
|
||||
|
||||
public function isRecorded() {
|
||||
public function isRecorded()
|
||||
{
|
||||
$showInstance = CcShowInstancesQuery::create()->findPK($this->_instanceId);
|
||||
return $showInstance->getDbRecord();
|
||||
}
|
||||
|
||||
public function getName() {
|
||||
public function getName()
|
||||
{
|
||||
$show = CcShowQuery::create()->findPK($this->getShowId());
|
||||
return $show->getDbName();
|
||||
}
|
||||
|
||||
public function getShowStart() {
|
||||
public function getShowStart()
|
||||
{
|
||||
$showInstance = CcShowInstancesQuery::create()->findPK($this->_instanceId);
|
||||
return $showInstance->getDbStarts();
|
||||
}
|
||||
|
||||
public function getShowEnd() {
|
||||
public function getShowEnd()
|
||||
{
|
||||
$showInstance = CcShowInstancesQuery::create()->findPK($this->_instanceId);
|
||||
return $showInstance->getDbEnds();
|
||||
}
|
||||
|
||||
public function setShowStart($start) {
|
||||
public function setShowStart($start)
|
||||
{
|
||||
$showInstance = CcShowInstancesQuery::create()->findPK($this->_instanceId);
|
||||
$showInstance->setDbStarts($start)
|
||||
->save();
|
||||
RabbitMq::PushSchedule();
|
||||
}
|
||||
|
||||
public function setShowEnd($end) {
|
||||
public function setShowEnd($end)
|
||||
{
|
||||
$showInstance = CcShowInstancesQuery::create()->findPK($this->_instanceId);
|
||||
$showInstance->setDbEnds($end)
|
||||
->save();
|
||||
->save();
|
||||
RabbitMq::PushSchedule();
|
||||
}
|
||||
|
||||
public function moveScheduledShowContent($deltaDay, $deltaHours, $deltaMin) {
|
||||
public function moveScheduledShowContent($deltaDay, $deltaHours, $deltaMin)
|
||||
{
|
||||
global $CC_DBC;
|
||||
|
||||
$sql = "UPDATE cc_schedule
|
||||
|
@ -558,9 +575,11 @@ class ShowInstance {
|
|||
WHERE instance_id = '{$this->_instanceId}'";
|
||||
|
||||
$CC_DBC->query($sql);
|
||||
RabbitMq::PushSchedule();
|
||||
}
|
||||
|
||||
public function moveShow($deltaDay, $deltaMin){
|
||||
public function moveShow($deltaDay, $deltaMin)
|
||||
{
|
||||
global $CC_DBC;
|
||||
|
||||
$hours = $deltaMin/60;
|
||||
|
@ -572,7 +591,7 @@ class ShowInstance {
|
|||
$mins = abs($deltaMin%60);
|
||||
|
||||
$starts = $this->getShowStart();
|
||||
$ends = $this->getShowEnd();
|
||||
$ends = $this->getShowEnd();
|
||||
|
||||
$sql = "SELECT timestamp '{$starts}' + interval '{$deltaDay} days' + interval '{$hours}:{$mins}'";
|
||||
$new_starts = $CC_DBC->GetOne($sql);
|
||||
|
@ -595,18 +614,20 @@ class ShowInstance {
|
|||
if($rebroadcast) {
|
||||
$sql = "SELECT timestamp '{$new_starts}' < (SELECT starts FROM cc_show_instances WHERE id = {$rebroadcast})";
|
||||
$isBeforeRecordedOriginal = $CC_DBC->GetOne($sql);
|
||||
|
||||
|
||||
if($isBeforeRecordedOriginal === 't'){
|
||||
return "Cannot move a rebroadcast show before its original";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$this->moveScheduledShowContent($deltaDay, $hours, $mins);
|
||||
$this->setShowStart($new_starts);
|
||||
$this->setShowEnd($new_ends);
|
||||
$this->setShowEnd($new_ends);
|
||||
RabbitMq::PushSchedule();
|
||||
}
|
||||
|
||||
public function resizeShow($deltaDay, $deltaMin){
|
||||
public function resizeShow($deltaDay, $deltaMin)
|
||||
{
|
||||
global $CC_DBC;
|
||||
|
||||
$hours = $deltaMin/60;
|
||||
|
@ -618,7 +639,7 @@ class ShowInstance {
|
|||
$mins = abs($deltaMin%60);
|
||||
|
||||
$starts = $this->getShowStart();
|
||||
$ends = $this->getShowEnd();
|
||||
$ends = $this->getShowEnd();
|
||||
|
||||
$sql = "SELECT timestamp '{$ends}' + interval '{$deltaDay} days' + interval '{$hours}:{$mins}'";
|
||||
$new_ends = $CC_DBC->GetOne($sql);
|
||||
|
@ -639,106 +660,142 @@ class ShowInstance {
|
|||
WHERE rebroadcast = 1 AND instance_id = {$this->_instanceId}";
|
||||
$CC_DBC->query($sql);
|
||||
}
|
||||
|
||||
|
||||
$this->setShowEnd($new_ends);
|
||||
RabbitMq::PushSchedule();
|
||||
}
|
||||
|
||||
private function getLastGroupId() {
|
||||
private function getLastGroupId()
|
||||
{
|
||||
global $CC_DBC;
|
||||
|
||||
$sql = "SELECT group_id FROM cc_schedule WHERE instance_id = '{$this->_instanceId}' ORDER BY ends DESC LIMIT 1";
|
||||
$res = $CC_DBC->GetOne($sql);
|
||||
|
||||
$res = $CC_DBC->GetOne($sql);
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function addPlaylistToShow($plId) {
|
||||
|
||||
public function addPlaylistToShow($plId)
|
||||
{
|
||||
$sched = new ScheduleGroup();
|
||||
$lastGroupId = $this->getLastGroupId();
|
||||
|
||||
|
||||
if(is_null($lastGroupId)) {
|
||||
|
||||
$groupId = $sched->add($this->_instanceId, $this->getShowStart(), null, $plId);
|
||||
$groupId = $sched->add($this->_instanceId, $this->getShowStart(), null, $plId);
|
||||
}
|
||||
else {
|
||||
$groupId = $sched->addPlaylistAfter($this->_instanceId, $lastGroupId, $plId);
|
||||
}
|
||||
RabbitMq::PushSchedule();
|
||||
}
|
||||
|
||||
public function addFileToShow($file_id)
|
||||
{
|
||||
$sched = new ScheduleGroup();
|
||||
$lastGroupId = $this->getLastGroupId();
|
||||
|
||||
if(is_null($lastGroupId)) {
|
||||
|
||||
$groupId = $sched->add($this->_instanceId, $this->getShowStart(), $file_id);
|
||||
}
|
||||
else {
|
||||
$groupId = $sched->addFileAfter($this->_instanceId, $lastGroupId, $file_id);
|
||||
}
|
||||
RabbitMq::PushSchedule();
|
||||
}
|
||||
|
||||
public function scheduleShow($plIds) {
|
||||
|
||||
|
||||
foreach($plIds as $plId) {
|
||||
$this->addPlaylistToShow($plId);
|
||||
}
|
||||
}
|
||||
|
||||
public function removeGroupFromShow($group_id){
|
||||
public function removeGroupFromShow($group_id)
|
||||
{
|
||||
global $CC_DBC;
|
||||
|
||||
$sql = "SELECT MAX(ends) as end_timestamp, (MAX(ends) - MIN(starts)) as length
|
||||
FROM cc_schedule
|
||||
FROM cc_schedule
|
||||
WHERE group_id = '{$group_id}'";
|
||||
|
||||
|
||||
$groupBoundry = $CC_DBC->GetRow($sql);
|
||||
|
||||
$group = CcScheduleQuery::create()
|
||||
->filterByDbGroupId($group_id)
|
||||
->delete();
|
||||
|
||||
$sql = "UPDATE cc_schedule
|
||||
SET starts = (starts - INTERVAL '{$groupBoundry["length"]}'), ends = (ends - INTERVAL '{$groupBoundry["length"]}')
|
||||
$sql = "UPDATE cc_schedule
|
||||
SET starts = (starts - INTERVAL '{$groupBoundry["length"]}'), ends = (ends - INTERVAL '{$groupBoundry["length"]}')
|
||||
WHERE starts >= '{$groupBoundry["end_timestamp"]}' AND instance_id = {$this->_instanceId}";
|
||||
|
||||
$CC_DBC->query($sql);
|
||||
RabbitMq::PushSchedule();
|
||||
}
|
||||
|
||||
public function clearShow() {
|
||||
|
||||
public function clearShow()
|
||||
{
|
||||
CcScheduleQuery::create()
|
||||
->filterByDbInstanceId($this->_instanceId)
|
||||
->delete();
|
||||
RabbitMq::PushSchedule();
|
||||
}
|
||||
|
||||
public function deleteShow() {
|
||||
|
||||
public function deleteShow()
|
||||
{
|
||||
CcShowInstancesQuery::create()
|
||||
->findPK($this->_instanceId)
|
||||
->delete();
|
||||
RabbitMq::PushSchedule();
|
||||
}
|
||||
|
||||
public function getTimeScheduled() {
|
||||
public function setRecordedFile($file_id)
|
||||
{
|
||||
$showInstance = CcShowInstancesQuery::create()
|
||||
->findPK($this->_instanceId);
|
||||
$showInstance->setDbRecordedFile($file_id)
|
||||
->save();
|
||||
|
||||
$rebroadcasts = CcShowInstancesQuery::create()
|
||||
->filterByDbOriginalShow($this->_instanceId)
|
||||
->find();
|
||||
|
||||
foreach ($rebroadcasts as $rebroadcast) {
|
||||
|
||||
$rebroad = new ShowInstance($rebroadcast->getDbId());
|
||||
$rebroad->addFileToShow($file_id);
|
||||
RabbitMq::PushSchedule();
|
||||
}
|
||||
}
|
||||
|
||||
public function getTimeScheduled()
|
||||
{
|
||||
$instance_id = $this->getShowInstanceId();
|
||||
$time = Schedule::GetTotalShowTime($instance_id);
|
||||
|
||||
return $time;
|
||||
}
|
||||
|
||||
public function getTimeUnScheduled() {
|
||||
|
||||
$start_timestamp = $this->getShowStart();
|
||||
public function getTimeUnScheduled()
|
||||
{
|
||||
$start_timestamp = $this->getShowStart();
|
||||
$end_timestamp = $this->getShowEnd();
|
||||
$instance_id = $this->getShowInstanceId();
|
||||
|
||||
$time = Schedule::getTimeUnScheduledInRange($instance_id, $start_timestamp, $end_timestamp);
|
||||
|
||||
return $time;
|
||||
}
|
||||
|
||||
public function getPercentScheduled() {
|
||||
|
||||
$start_timestamp = $this->getShowStart();
|
||||
public function getPercentScheduled()
|
||||
{
|
||||
$start_timestamp = $this->getShowStart();
|
||||
$end_timestamp = $this->getShowEnd();
|
||||
$instance_id = $this->getShowInstanceId();
|
||||
|
||||
return Schedule::GetPercentScheduled($instance_id, $start_timestamp, $end_timestamp);
|
||||
}
|
||||
|
||||
public function getShowLength() {
|
||||
public function getShowLength()
|
||||
{
|
||||
global $CC_DBC;
|
||||
|
||||
$start_timestamp = $this->getShowStart();
|
||||
$start_timestamp = $this->getShowStart();
|
||||
$end_timestamp = $this->getShowEnd();
|
||||
|
||||
$sql = "SELECT TIMESTAMP '{$end_timestamp}' - TIMESTAMP '{$start_timestamp}' ";
|
||||
|
@ -747,26 +804,27 @@ class ShowInstance {
|
|||
return $length;
|
||||
}
|
||||
|
||||
public function searchPlaylistsForShow($datatables){
|
||||
|
||||
public function searchPlaylistsForShow($datatables)
|
||||
{
|
||||
$time_remaining = $this->getTimeUnScheduled();
|
||||
|
||||
return StoredFile::searchPlaylistsForSchedule($time_remaining, $datatables);
|
||||
}
|
||||
|
||||
public function getShowListContent() {
|
||||
public function getShowListContent()
|
||||
{
|
||||
global $CC_DBC;
|
||||
|
||||
$sql = "SELECT *
|
||||
$sql = "SELECT *
|
||||
FROM (cc_schedule AS s LEFT JOIN cc_files AS f ON f.id = s.file_id
|
||||
LEFT JOIN cc_playlist AS p ON p.id = s.playlist_id )
|
||||
|
||||
WHERE s.instance_id = '{$this->_instanceId}' ORDER BY starts";
|
||||
|
||||
return $CC_DBC->GetAll($sql);
|
||||
return $CC_DBC->GetAll($sql);
|
||||
}
|
||||
|
||||
public function getShowContent() {
|
||||
public function getShowContent()
|
||||
{
|
||||
global $CC_DBC;
|
||||
|
||||
$res = $this->getShowListContent();
|
||||
|
@ -788,7 +846,7 @@ class ShowInstance {
|
|||
$items[$pl_counter]["pl_name"] = $row["name"];
|
||||
$items[$pl_counter]["pl_creator"] = $row["creator"];
|
||||
$items[$pl_counter]["pl_description"] = $row["description"];
|
||||
$items[$pl_counter]["pl_group"] = $row["group_id"];
|
||||
$items[$pl_counter]["pl_group"] = $row["group_id"];
|
||||
|
||||
$sql = "SELECT SUM(clip_length) FROM cc_schedule WHERE group_id = '{$currGroupId}'";
|
||||
$length = $CC_DBC->GetOne($sql);
|
||||
|
@ -802,46 +860,49 @@ class ShowInstance {
|
|||
$items[$pl_counter]["pl_content"][$f_counter]["f_length"] = $row["length"];
|
||||
}
|
||||
|
||||
return $items;
|
||||
return $items;
|
||||
}
|
||||
}
|
||||
|
||||
/* Show Data Access Layer */
|
||||
class Show_DAL{
|
||||
|
||||
public static function GetCurrentShow($timeNow) {
|
||||
class Show_DAL {
|
||||
|
||||
public static function GetCurrentShow($timeNow)
|
||||
{
|
||||
global $CC_CONFIG, $CC_DBC;
|
||||
|
||||
|
||||
$timestamp = explode(" ", $timeNow);
|
||||
$date = $timestamp[0];
|
||||
$time = $timestamp[1];
|
||||
|
||||
|
||||
$sql = "SELECT si.starts as start_timestamp, si.ends as end_timestamp, s.name, s.id, si.id as instance_id, si.record"
|
||||
." FROM $CC_CONFIG[showInstances] si, $CC_CONFIG[showTable] s"
|
||||
." WHERE si.show_id = s.id"
|
||||
." AND si.starts <= TIMESTAMP '$timeNow'"
|
||||
." AND si.ends > TIMESTAMP '$timeNow'";
|
||||
|
||||
|
||||
$rows = $CC_DBC->GetAll($sql);
|
||||
return $rows;
|
||||
}
|
||||
|
||||
public static function GetNextShow($timeNow) {
|
||||
|
||||
public static function GetNextShows($timeNow, $limit)
|
||||
{
|
||||
global $CC_CONFIG, $CC_DBC;
|
||||
|
||||
|
||||
$sql = "SELECT *, si.starts as start_timestamp, si.ends as end_timestamp FROM "
|
||||
." $CC_CONFIG[showInstances] si, $CC_CONFIG[showTable] s"
|
||||
." WHERE si.show_id = s.id"
|
||||
." AND si.starts >= TIMESTAMP '$timeNow'"
|
||||
." AND si.starts < TIMESTAMP '$timeNow' + INTERVAL '48 hours'"
|
||||
." ORDER BY si.starts"
|
||||
." LIMIT 1";
|
||||
|
||||
." LIMIT $limit";
|
||||
|
||||
$rows = $CC_DBC->GetAll($sql);
|
||||
return $rows;
|
||||
}
|
||||
|
||||
public static function GetShowsInRange($timeNow, $start, $end){
|
||||
public static function GetShowsInRange($timeNow, $start, $end)
|
||||
{
|
||||
global $CC_CONFIG, $CC_DBC;
|
||||
$sql = "SELECT"
|
||||
." si.starts as show_starts,"
|
||||
|
@ -873,5 +934,5 @@ class Show_DAL{
|
|||
|
||||
return $CC_DBC->GetAll($sql);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
require_once 'soundcloud-api/Services/Soundcloud.php';
|
||||
|
||||
class ATSoundcloud {
|
||||
|
||||
private $_soundcloud;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
global $CC_CONFIG;
|
||||
|
||||
$this->_soundcloud = new Services_Soundcloud($CC_CONFIG['soundcloud-client-id'], $CC_CONFIG['soundcloud-client-secret']);
|
||||
}
|
||||
|
||||
private function getToken()
|
||||
{
|
||||
$username = Application_Model_Preference::GetSoundCloudUser();
|
||||
$password = Application_Model_Preference::GetSoundCloudPassword();
|
||||
|
||||
if($username === "" || $password === "")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$token = $this->_soundcloud->accessTokenResourceOwner($username, $password);
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
public function uploadTrack($filepath, $filename, $description, $tags=array())
|
||||
{
|
||||
if($this->getToken())
|
||||
{
|
||||
if(count($tags)) {
|
||||
$tags = join(" ", $tags);
|
||||
$tags = $tags." ".Application_Model_Preference::GetSoundCloudTags();
|
||||
}
|
||||
else {
|
||||
$tags = Application_Model_Preference::GetSoundCloudTags();
|
||||
}
|
||||
|
||||
$track_data = array(
|
||||
'track[sharing]' => 'private',
|
||||
'track[title]' => $filename,
|
||||
'track[asset_data]' => '@' . $filepath,
|
||||
'track[tag_list]' => $tags,
|
||||
'track[description]' => $description
|
||||
);
|
||||
|
||||
try {
|
||||
$response = json_decode(
|
||||
$this->_soundcloud->post('tracks', $track_data),
|
||||
true
|
||||
);
|
||||
|
||||
echo var_dump($response);
|
||||
}
|
||||
catch (Services_Soundcloud_Invalid_Http_Response_Code_Exception $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "could not get soundcloud token";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1647,5 +1647,143 @@ class StoredFile {
|
|||
return array("sEcho" => intval($data["sEcho"]), "iTotalDisplayRecords" => $totalDisplayRows, "iTotalRecords" => $totalRows, "aaData" => $results);
|
||||
}
|
||||
|
||||
public static function uploadFile($targetDir) {
|
||||
|
||||
// HTTP headers for no cache etc
|
||||
header('Content-type: text/plain; charset=UTF-8');
|
||||
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
|
||||
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
|
||||
header("Cache-Control: no-store, no-cache, must-revalidate");
|
||||
header("Cache-Control: post-check=0, pre-check=0", false);
|
||||
header("Pragma: no-cache");
|
||||
|
||||
// Settings
|
||||
//$targetDir = ini_get("upload_tmp_dir"); //. DIRECTORY_SEPARATOR . "plupload";
|
||||
$cleanupTargetDir = false; // Remove old files
|
||||
$maxFileAge = 60 * 60; // Temp file age in seconds
|
||||
|
||||
// 5 minutes execution time
|
||||
@set_time_limit(5 * 60);
|
||||
// usleep(5000);
|
||||
|
||||
// Get parameters
|
||||
$chunk = isset($_REQUEST["chunk"]) ? $_REQUEST["chunk"] : 0;
|
||||
$chunks = isset($_REQUEST["chunks"]) ? $_REQUEST["chunks"] : 0;
|
||||
$fileName = isset($_REQUEST["name"]) ? $_REQUEST["name"] : '';
|
||||
|
||||
// Clean the fileName for security reasons
|
||||
//$fileName = preg_replace('/[^\w\._]+/', '', $fileName);
|
||||
|
||||
// Create target dir
|
||||
if (!file_exists($targetDir))
|
||||
@mkdir($targetDir);
|
||||
|
||||
// Remove old temp files
|
||||
if (is_dir($targetDir) && ($dir = opendir($targetDir))) {
|
||||
while (($file = readdir($dir)) !== false) {
|
||||
$filePath = $targetDir . DIRECTORY_SEPARATOR . $file;
|
||||
|
||||
// Remove temp files if they are older than the max age
|
||||
if (preg_match('/\.tmp$/', $file) && (filemtime($filePath) < time() - $maxFileAge))
|
||||
@unlink($filePath);
|
||||
}
|
||||
|
||||
closedir($dir);
|
||||
} else
|
||||
die('{"jsonrpc" : "2.0", "error" : {"code": 100, "message": "Failed to open temp directory."}, "id" : "id"}');
|
||||
|
||||
// Look for the content type header
|
||||
if (isset($_SERVER["HTTP_CONTENT_TYPE"]))
|
||||
$contentType = $_SERVER["HTTP_CONTENT_TYPE"];
|
||||
|
||||
if (isset($_SERVER["CONTENT_TYPE"]))
|
||||
$contentType = $_SERVER["CONTENT_TYPE"];
|
||||
|
||||
if (strpos($contentType, "multipart") !== false) {
|
||||
if (isset($_FILES['file']['tmp_name']) && is_uploaded_file($_FILES['file']['tmp_name'])) {
|
||||
// Open temp file
|
||||
$out = fopen($targetDir . DIRECTORY_SEPARATOR . $fileName, $chunk == 0 ? "wb" : "ab");
|
||||
if ($out) {
|
||||
// Read binary input stream and append it to temp file
|
||||
$in = fopen($_FILES['file']['tmp_name'], "rb");
|
||||
|
||||
if ($in) {
|
||||
while ($buff = fread($in, 4096))
|
||||
fwrite($out, $buff);
|
||||
} else
|
||||
die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');
|
||||
|
||||
fclose($out);
|
||||
unlink($_FILES['file']['tmp_name']);
|
||||
} else
|
||||
die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}');
|
||||
} else
|
||||
die('{"jsonrpc" : "2.0", "error" : {"code": 103, "message": "Failed to move uploaded file."}, "id" : "id"}');
|
||||
} else {
|
||||
// Open temp file
|
||||
$out = fopen($targetDir . DIRECTORY_SEPARATOR . $fileName, $chunk == 0 ? "wb" : "ab");
|
||||
if ($out) {
|
||||
// Read binary input stream and append it to temp file
|
||||
$in = fopen("php://input", "rb");
|
||||
|
||||
if ($in) {
|
||||
while ($buff = fread($in, 4096))
|
||||
fwrite($out, $buff);
|
||||
} else
|
||||
die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');
|
||||
|
||||
fclose($out);
|
||||
} else
|
||||
die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}');
|
||||
}
|
||||
|
||||
$audio_file = $targetDir . DIRECTORY_SEPARATOR . $fileName;
|
||||
|
||||
$md5 = md5_file($audio_file);
|
||||
$duplicate = StoredFile::RecallByMd5($md5);
|
||||
if ($duplicate) {
|
||||
if (PEAR::isError($duplicate)) {
|
||||
die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": ' . $duplicate->getMessage() .'}}');
|
||||
}
|
||||
else {
|
||||
$duplicateName = $duplicate->getMetadataValue(UI_MDATA_KEY_TITLE);
|
||||
die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "An identical audioclip named ' . $duplicateName . ' already exists in the storage server."}}');
|
||||
}
|
||||
}
|
||||
|
||||
$metadata = Metadata::LoadFromFile($audio_file);
|
||||
|
||||
if (PEAR::isError($metadata)) {
|
||||
die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": ' + $metadata->getMessage() + '}}');
|
||||
}
|
||||
|
||||
// #2196 no id tag -> use the original filename
|
||||
if (basename($audio_file) == $metadata[UI_MDATA_KEY_TITLE]) {
|
||||
$metadata[UI_MDATA_KEY_TITLE] = basename($audio_file);
|
||||
$metadata[UI_MDATA_KEY_FILENAME] = basename($audio_file);
|
||||
}
|
||||
|
||||
// setMetadataBatch doesnt like these values
|
||||
unset($metadata['audio']);
|
||||
unset($metadata['playtime_seconds']);
|
||||
|
||||
$values = array(
|
||||
"filename" => basename($audio_file),
|
||||
"filepath" => $audio_file,
|
||||
"filetype" => "audioclip",
|
||||
"mime" => $metadata[UI_MDATA_KEY_FORMAT],
|
||||
"md5" => $md5
|
||||
);
|
||||
$storedFile = StoredFile::Insert($values);
|
||||
|
||||
if (PEAR::isError($storedFile)) {
|
||||
die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": ' + $storedFile->getMessage() + '}}');
|
||||
}
|
||||
|
||||
$storedFile->setMetadataBatch($metadata);
|
||||
|
||||
return $storedFile;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ class CcScheduleTableMap extends TableMap {
|
|||
$this->setPrimaryKeyMethodInfo('cc_schedule_id_seq');
|
||||
// columns
|
||||
$this->addPrimaryKey('ID', 'DbId', 'INTEGER', true, null, null);
|
||||
$this->addColumn('PLAYLIST_ID', 'DbPlaylistId', 'INTEGER', true, null, null);
|
||||
$this->addColumn('PLAYLIST_ID', 'DbPlaylistId', 'INTEGER', false, null, null);
|
||||
$this->addColumn('STARTS', 'DbStarts', 'TIMESTAMP', true, null, null);
|
||||
$this->addColumn('ENDS', 'DbEnds', 'TIMESTAMP', true, null, null);
|
||||
$this->addColumn('GROUP_ID', 'DbGroupId', 'INTEGER', false, null, null);
|
||||
|
|
|
@ -110,6 +110,7 @@ class SchedulerTests extends PHPUnit_TestCase {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
function testGetItems() {
|
||||
$i1 = new ScheduleGroup();
|
||||
$groupId1 = $i1->add('2008-01-01 12:00:00.000', $this->storedFile->getId());
|
||||
|
@ -123,5 +124,6 @@ class SchedulerTests extends PHPUnit_TestCase {
|
|||
$i1->remove();
|
||||
$i2->remove();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
<?php
|
||||
|
||||
require_once 'soundcloud-api/Services/Soundcloud.php';
|
||||
|
||||
class Airtime_View_Helper_SoundCloudLink extends Zend_View_Helper_Abstract
|
||||
{
|
||||
public function soundCloudLink()
|
||||
{
|
||||
$request = Zend_Controller_Front::getInstance()->getRequest();
|
||||
$host = $request->getHttpHost();
|
||||
$controller = $request->getControllerName();
|
||||
$action = $request->getActionName();
|
||||
|
||||
$redirectUrl = "http://{$host}/{$controller}/{$action}";
|
||||
|
||||
$soundcloud = new Services_Soundcloud('2CLCxcSXYzx7QhhPVHN4A', 'pZ7beWmF06epXLHVUP1ufOg2oEnIt9XhE8l8xt0bBs', $redirectUrl);
|
||||
$authorizeUrl = $soundcloud->getAuthorizeUrl();
|
||||
|
||||
return $authorizeUrl;
|
||||
}
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
<div class="now-playing-info show">
|
||||
<div class="recording-show" style="display: none;"></div>
|
||||
<span id="playlist"></span>
|
||||
<span class="lenght">00:00</span>
|
||||
<span id="show-length" class="show-length"></span>
|
||||
</div>
|
||||
<div class="progressbar">
|
||||
<div class="progress-show" id='progress-show' style="width:0%;"></div>
|
||||
|
@ -43,6 +43,6 @@
|
|||
<div id="jquery_jplayer_1" class="jp-jplayer" style="width:0px; height:0px;"></div>
|
||||
|
||||
<div id="about-txt" style="display: none;">
|
||||
<a href="http://airtime.sourcefabric.org">Airtime</a>, the open radio software for scheduling and remote station management.<br>
|
||||
<a href="http://airtime.sourcefabric.org">Airtime</a> <?php echo AIRTIME_VERSION ?>, the open radio software for scheduling and remote station management.<br>
|
||||
© 2011 <a href="http://www.sourcefabric.org">Sourcefabric</a> o.p.s 2011. Airtime is distributed under the <a href="http://www.gnu.org/licenses/gpl-3.0-standalone.html">GNU GPL v.3</a>
|
||||
</div>
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
<div class="text-row top">
|
||||
<span class="spl_playlength"><?php echo $item["cliplength"] ?></span>
|
||||
<span class="spl_cue ui-state-default"></span>
|
||||
<span class="spl_title"><?php echo $item["CcFiles"]['track_title'] ?></span>
|
||||
</div>
|
||||
<div class="text-row">
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
<div id="schedule-add-show" class="tabs ui-widget ui-widget-content block-shadow alpha-block padded">
|
||||
<div class="button-bar">
|
||||
<a href="#" id="add-show-close" class="icon-link"><span class="ui-icon ui-icon-circle-close"></span>Close</a>
|
||||
<button id="add-show-submit" class="right-floated">Add this show</button>
|
||||
<button aria-disabled="false" role="button" id="add-show-submit" class="right-floated ui-button ui-widget ui-state-default ui-button-text-icon-primary">
|
||||
<span class="ui-icon ui-icon-plusthick"></span>
|
||||
<span class="ui-button-text">Add this show</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="clear"></div>
|
||||
<h3 class="collapsible-header"><span class="arrow-icon"></span>What</h3>
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
<div id="users_wrapper" class="dataTables_wrapper">
|
||||
|
||||
<div class="button-holder">
|
||||
<button type="button" id="add_user_button" name="search_add_group" class="ui-button ui-widget ui-state-default ui-button-text-icon-primary"><span class="ui-button-text">New User</span></button>
|
||||
<button type="button" id="add_user_button" name="search_add_group" class="ui-button ui-widget ui-state-default ui-button-text-icon-primary">
|
||||
<span class="ui-icon ui-icon-plusthick"></span>
|
||||
<span class="ui-button-text">New User</span></button>
|
||||
</div>
|
||||
|
||||
<table cellspacing="0" cellpadding="0" style="" id="users_datatable" class="datatable">
|
||||
|
@ -26,6 +28,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="user-data simple-formblock" id="user_details">
|
||||
<?php echo $this->successMessage ?>
|
||||
<fieldset class="padded">
|
||||
<?php echo $this->form ?>
|
||||
</fieldset>
|
||||
|
|
|
@ -234,7 +234,7 @@
|
|||
</table>
|
||||
<table name="cc_schedule" phpName="CcSchedule">
|
||||
<column name="id" phpName="DbId" type="INTEGER" primaryKey="true" autoIncrement="true" required="true"/>
|
||||
<column name="playlist_id" phpName="DbPlaylistId" type="INTEGER" required="true"/>
|
||||
<column name="playlist_id" phpName="DbPlaylistId" type="INTEGER" required="false"/>
|
||||
<column name="starts" phpName="DbStarts" type="TIMESTAMP" required="true"/>
|
||||
<column name="ends" phpName="DbEnds" type="TIMESTAMP" required="true"/>
|
||||
<column name="group_id" phpName="DbGroupId" type="INTEGER" required="false"/>
|
||||
|
|
|
@ -345,7 +345,7 @@ DROP TABLE "cc_schedule" CASCADE;
|
|||
CREATE TABLE "cc_schedule"
|
||||
(
|
||||
"id" serial NOT NULL,
|
||||
"playlist_id" INTEGER NOT NULL,
|
||||
"playlist_id" INTEGER,
|
||||
"starts" TIMESTAMP NOT NULL,
|
||||
"ends" TIMESTAMP NOT NULL,
|
||||
"group_id" INTEGER,
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
su -l pypo -c "tail -F /etc/service/pypo-fetch/log/main/current"
|
|
@ -1,3 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
su -l pypo -c "tail -F /etc/service/pypo-push/log/main/current"
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
|
||||
su -l pypo -c "tail -F /etc/service/recorder/log/main/current"
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
|
||||
su -l pypo -c "less /etc/service/pypo/log/main/current"
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
|
||||
su -l pypo -c "tail -F /etc/service/pypo/log/main/current"
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Migrations\AbstractMigration,
|
||||
Doctrine\DBAL\Schema\Schema;
|
||||
|
||||
class Version20110312121200 extends AbstractMigration
|
||||
{
|
||||
public function up(Schema $schema)
|
||||
{
|
||||
$schema->dropTable("cc_backup");
|
||||
$schema->dropTable("cc_trans");
|
||||
}
|
||||
|
||||
public function down(Schema $schema)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -39,7 +39,6 @@ AirtimeInstall::InstallPostgresScriptingLanguage();
|
|||
|
||||
echo "* Creating database tables".PHP_EOL;
|
||||
AirtimeInstall::CreateDatabaseTables();
|
||||
AirtimeInstall::MigrateTables(__DIR__);
|
||||
|
||||
echo "* Storage directory setup".PHP_EOL;
|
||||
AirtimeInstall::SetupStorageDirectory($CC_CONFIG);
|
||||
|
@ -47,11 +46,20 @@ AirtimeInstall::SetupStorageDirectory($CC_CONFIG);
|
|||
echo "* Giving Apache permission to access the storage directory".PHP_EOL;
|
||||
AirtimeInstall::ChangeDirOwnerToWebserver($CC_CONFIG["storageDir"]);
|
||||
|
||||
echo "* Creating /usr/bin symlinks".PHP_EOL;
|
||||
AirtimeInstall::CreateSymlinks($CC_CONFIG["storageDir"]);
|
||||
|
||||
echo "* Importing sample audio clips".PHP_EOL;
|
||||
system(__DIR__."/../utils/airtime-import --copy ../audio_samples/ > /dev/null");
|
||||
|
||||
echo "* Python eggs Setup".PHP_EOL;
|
||||
AirtimeInstall::SetUpPythonEggs();
|
||||
|
||||
echo PHP_EOL."*** Pypo Installation ***".PHP_EOL;
|
||||
system("python ".__DIR__."/../pypo/install/pypo-install.py");
|
||||
system("python ".__DIR__."/../python_apps/pypo/install/pypo-install.py");
|
||||
|
||||
echo PHP_EOL."*** Recorder Installation ***".PHP_EOL;
|
||||
system("python ".__DIR__."/../python_apps/show-recorder/install/recorder-install.py");
|
||||
|
||||
|
||||
echo "******************************* Install Complete *******************************".PHP_EOL;
|
||||
|
|
|
@ -20,6 +20,7 @@ require_once(dirname(__FILE__).'/installInit.php');
|
|||
// Need to check that we are superuser before running this.
|
||||
AirtimeInstall::ExitIfNotRoot();
|
||||
|
||||
AirtimeInstall::RemoveSymlinks();
|
||||
|
||||
echo "******************************* Uninstall Begin ********************************".PHP_EOL;
|
||||
//------------------------------------------------------------------------
|
||||
|
@ -38,7 +39,7 @@ $command = "sudo -u postgres dropdb {$CC_CONFIG['dsn']['database']} 2> /dev/null
|
|||
//------------------------------------------------------------------------
|
||||
if ($dbDeleteFailed) {
|
||||
echo " * Couldn't delete the database, so deleting all the DB tables...".PHP_EOL;
|
||||
AirtimeInstall::DbConnect(true);
|
||||
AirtimeInstall::DbConnect(false);
|
||||
|
||||
if (!PEAR::isError($CC_DBC)) {
|
||||
$sql = "select * from pg_tables where tableowner = 'airtime'";
|
||||
|
@ -81,7 +82,10 @@ if ($results == 0) {
|
|||
AirtimeInstall::DeleteFilesRecursive($CC_CONFIG['storageDir']);
|
||||
|
||||
|
||||
$command = "python ".__DIR__."/../pypo/install/pypo-uninstall.py";
|
||||
$command = "python ".__DIR__."/../python_apps/pypo/install/pypo-uninstall.py";
|
||||
system($command);
|
||||
|
||||
$command = "python ".__DIR__."/../python_apps/show-recorder/install/recorder-uninstall.py";
|
||||
system($command);
|
||||
echo "****************************** Uninstall Complete ******************************".PHP_EOL;
|
||||
|
||||
|
|
|
@ -79,7 +79,8 @@ class AirtimeInstall {
|
|||
{
|
||||
$api_key = AirtimeInstall::GenerateRandomString();
|
||||
AirtimeInstall::UpdateIniValue(__DIR__.'/../build/airtime.conf', 'api_key', $api_key);
|
||||
AirtimeInstall::UpdateIniValue(__DIR__.'/../pypo/config.cfg', 'api_key', "'$api_key'");
|
||||
AirtimeInstall::UpdateIniValue(__DIR__.'/../python_apps/pypo/config.cfg', 'api_key', "'$api_key'");
|
||||
AirtimeInstall::UpdateIniValue(__DIR__.'/../python_apps/show-recorder/config.cfg', 'api_key', "'$api_key'");
|
||||
}
|
||||
|
||||
public static function ExitIfNotRoot()
|
||||
|
@ -112,7 +113,7 @@ class AirtimeInstall {
|
|||
public static function SetupStorageDirectory($CC_CONFIG)
|
||||
{
|
||||
global $CC_CONFIG, $CC_DBC;
|
||||
|
||||
|
||||
echo PHP_EOL."*** Directory Setup ***".PHP_EOL;
|
||||
foreach (array('baseFilesDir', 'storageDir') as $d) {
|
||||
if ( !file_exists($CC_CONFIG[$d]) ) {
|
||||
|
@ -141,7 +142,7 @@ class AirtimeInstall {
|
|||
// Create the database user
|
||||
$command = "sudo -u postgres psql postgres --command \"CREATE USER {$CC_CONFIG['dsn']['username']} "
|
||||
." ENCRYPTED PASSWORD '{$CC_CONFIG['dsn']['password']}' LOGIN CREATEDB NOCREATEUSER;\" 2>/dev/null";
|
||||
|
||||
|
||||
@exec($command, $output, $results);
|
||||
if ($results == 0) {
|
||||
echo "* Database user '{$CC_CONFIG['dsn']['username']}' created.".PHP_EOL;
|
||||
|
@ -159,7 +160,7 @@ class AirtimeInstall {
|
|||
public static function CreateDatabase()
|
||||
{
|
||||
global $CC_CONFIG;
|
||||
|
||||
|
||||
$command = "sudo -u postgres createdb {$CC_CONFIG['dsn']['database']} --owner {$CC_CONFIG['dsn']['username']} 2> /dev/null";
|
||||
@exec($command, $output, $results);
|
||||
if ($results == 0) {
|
||||
|
@ -202,10 +203,33 @@ class AirtimeInstall {
|
|||
system($command);
|
||||
}
|
||||
|
||||
public static function SetUpPythonEggs()
|
||||
{
|
||||
//install poster streaming upload
|
||||
$command = "sudo easy_install poster";
|
||||
@exec($command);
|
||||
}
|
||||
|
||||
public static function DeleteFilesRecursive($p_path)
|
||||
{
|
||||
$command = "rm -rf $p_path";
|
||||
exec($command);
|
||||
}
|
||||
|
||||
}
|
||||
public static function CreateSymlinks(){
|
||||
AirtimeInstall::RemoveSymlinks();
|
||||
|
||||
$dir = realpath(__DIR__."/../utils/airtime-import");
|
||||
exec("ln -s $dir /usr/bin/airtime-import");
|
||||
|
||||
$dir = realpath(__DIR__."/../utils/airtime-clean-storage");
|
||||
exec("ln -s $dir /usr/bin/airtime-clean-storage");
|
||||
}
|
||||
|
||||
public static function RemoveSymlinks(){
|
||||
exec("rm -f /usr/bin/airtime-import");
|
||||
exec("rm -f /usr/bin/airtime-clean-storage");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
#!/usr/bin/php
|
||||
<?php
|
||||
/**
|
||||
* Repeatedly receive messages from queue until it receives a message with
|
||||
* 'quit' as the body.
|
||||
*
|
||||
* @author Sean Murphy<sean@iamseanmurphy.com>
|
||||
*/
|
||||
|
||||
require_once('../amqp.inc');
|
||||
|
||||
$HOST = 'localhost';
|
||||
$PORT = 5672;
|
||||
$USER = 'guest';
|
||||
$PASS = 'guest';
|
||||
$VHOST = '/';
|
||||
$EXCHANGE = 'airtime-schedule';
|
||||
$QUEUE = 'airtime-schedule-msgs';
|
||||
$CONSUMER_TAG = 'airtime-consumer';
|
||||
|
||||
$conn = new AMQPConnection($HOST, $PORT, $USER, $PASS);
|
||||
$ch = $conn->channel();
|
||||
$ch->access_request($VHOST, false, false, true, true);
|
||||
|
||||
$ch->queue_declare($QUEUE);
|
||||
$ch->exchange_declare($EXCHANGE, 'direct', false, false, false);
|
||||
$ch->queue_bind($QUEUE, $EXCHANGE);
|
||||
|
||||
function process_message($msg) {
|
||||
global $ch, $CONSUMER_TAG;
|
||||
|
||||
echo "\n--------\n";
|
||||
echo $msg->body;
|
||||
echo "\n--------\n";
|
||||
|
||||
$ch->basic_ack($msg->delivery_info['delivery_tag']);
|
||||
|
||||
// Cancel callback
|
||||
if ($msg->body === 'quit') {
|
||||
$ch->basic_cancel($CONSUMER_TAG);
|
||||
}
|
||||
}
|
||||
|
||||
$ch->basic_consume($QUEUE, $CONSUMER_TAG, false, false, false, false, 'process_message');
|
||||
|
||||
// Loop as long as the channel has callbacks registered
|
||||
echo "Waiting for messages...\n";
|
||||
while(count($ch->callbacks)) {
|
||||
$ch->wait();
|
||||
}
|
||||
|
||||
$ch->close();
|
||||
$conn->close();
|
||||
?>
|
|
@ -0,0 +1,267 @@
|
|||
(function($){
|
||||
$.fn.airtimeShowSchedule = function(options) {
|
||||
|
||||
var defaults = {
|
||||
updatePeriod: 20, //seconds
|
||||
sourceDomain: "http://localhost/", //where to get show status from
|
||||
};
|
||||
var options = $.extend(defaults, options);
|
||||
|
||||
return this.each(function() {
|
||||
var obj = $(this);
|
||||
var sd;
|
||||
|
||||
getServerData();
|
||||
|
||||
function updateWidget(){
|
||||
var currentShow = sd.getCurrentShow();
|
||||
var nextShows = sd.getNextShows();
|
||||
|
||||
var currentShowName = "";
|
||||
var nextShowName = ""
|
||||
|
||||
if (currentShow.length > 0){
|
||||
currentShowName = currentShow[0].getName();
|
||||
}
|
||||
|
||||
if (nextShows.length > 0){
|
||||
nextShowName = nextShows[0].getName();
|
||||
}
|
||||
|
||||
tableString = "";
|
||||
tableString += "<h3>On air today</h3>";
|
||||
tableString += "<table width='100%' border='0' cellspacing='0' cellpadding='0' class='widget widget no-playing-list small'>"+
|
||||
"<tbody>";
|
||||
|
||||
var shows=currentShow.concat(nextShows);
|
||||
|
||||
obj.empty();
|
||||
for (var i=0; i<shows.length; i++){
|
||||
tableString +=
|
||||
"<tr>" +
|
||||
"<td class='time'>"+shows[i].getRange()+"</td>" +
|
||||
"<td><a href='#'>"+shows[i].getName()+"</a> <a href='#' class='listen'>Listen</a></td>" +
|
||||
"</tr>";
|
||||
}
|
||||
|
||||
tableString += "</tbody></table>";
|
||||
|
||||
obj.append(tableString);
|
||||
}
|
||||
|
||||
function processData(data){
|
||||
sd = new ScheduleData(data);
|
||||
updateWidget();
|
||||
}
|
||||
|
||||
function getServerData(){
|
||||
$.ajax({ url: options.sourceDomain + "api/live-info/", dataType:"jsonp", success:function(data){
|
||||
processData(data);
|
||||
}, error:function(jqXHR, textStatus, errorThrown){}});
|
||||
setTimeout(getServerData, defaults.updatePeriod*1000);
|
||||
}
|
||||
});
|
||||
};
|
||||
})(jQuery);
|
||||
|
||||
|
||||
(function($){
|
||||
$.fn.airtimeLiveInfo = function(options) {
|
||||
|
||||
var defaults = {
|
||||
updatePeriod: 5, //seconds
|
||||
sourceDomain: "http://localhost/", //where to get show status from
|
||||
audioStreamSource: "" //where to get audio stream from
|
||||
};
|
||||
var options = $.extend(defaults, options);
|
||||
|
||||
return this.each(function() {
|
||||
var obj = $(this);
|
||||
var sd;
|
||||
getServerData();
|
||||
|
||||
function updateWidget(){
|
||||
var currentShow = sd.getCurrentShow();
|
||||
var nextShows = sd.getNextShows();
|
||||
|
||||
var showStatus = "Offline";
|
||||
var currentShowName = "";
|
||||
var timeElapsed = "";
|
||||
var timeRemaining = "";
|
||||
|
||||
var nextShowName = "";
|
||||
var nextShowRange = "";
|
||||
|
||||
if (currentShow.length > 0){
|
||||
showStatus = "On Air Now";
|
||||
currentShowName = currentShow[0].getName();
|
||||
|
||||
timeElapsed = sd.getShowTimeElapsed(currentShow[0]);
|
||||
timeRemaining = sd.getShowTimeRemaining(currentShow[0]);
|
||||
}
|
||||
|
||||
if (nextShows.length > 0){
|
||||
nextShowName = nextShows[0].getName();
|
||||
nextShowRange = nextShows[0].getRange();
|
||||
}
|
||||
|
||||
obj.empty();
|
||||
obj.append("<a id='listenWadrLive'><span>Listen WADR Live</span></a>");
|
||||
obj.append("<h4>"+showStatus+" >></h4>");
|
||||
obj.append("<ul class='widget no-playing-bar'>" +
|
||||
"<li class='current'>Current: "+currentShowName+
|
||||
"<span id='time-elapsed' class='time-elapsed'>"+timeElapsed+"</span>" +
|
||||
"<span id='time-remaining' class='time-remaining'>"+timeRemaining+"</span>"+
|
||||
"</li>" +
|
||||
"<li class='next'>Next: "+nextShowName+"<span>"+nextShowRange+"</span></li>" +
|
||||
"</ul>");
|
||||
|
||||
//refresh the UI to update the elapsed/remaining time
|
||||
setTimeout(updateWidget, 1000);
|
||||
}
|
||||
|
||||
function processData(data){
|
||||
sd = new ScheduleData(data);
|
||||
updateWidget();
|
||||
}
|
||||
|
||||
function getServerData(){
|
||||
$.ajax({ url: options.sourceDomain + "api/live-info/", dataType:"jsonp", success:function(data){
|
||||
processData(data);
|
||||
}, error:function(jqXHR, textStatus, errorThrown){}});
|
||||
setTimeout(getServerData, defaults.updatePeriod*1000);
|
||||
}
|
||||
});
|
||||
};
|
||||
})(jQuery);
|
||||
|
||||
/* ScheduleData class BEGIN */
|
||||
function ScheduleData(data){
|
||||
this.data = data;
|
||||
this.estimatedSchedulePosixTime;
|
||||
|
||||
this.currentShow = new Array();
|
||||
for (var i=0; i< data.currentShow.length; i++){
|
||||
this.currentShow[i] = new Show(data.currentShow[i]);
|
||||
}
|
||||
|
||||
this.nextShows = new Array();
|
||||
for (var i=0; i< data.nextShow.length; i++){
|
||||
this.nextShows[i] = new Show(data.nextShow[i]);
|
||||
}
|
||||
|
||||
|
||||
this.schedulePosixTime = convertDateToPosixTime(data.schedulerTime);
|
||||
this.schedulePosixTime += parseInt(data.timezoneOffset)*1000;
|
||||
var date = new Date();
|
||||
this.localRemoteTimeOffset = date.getTime() - this.schedulePosixTime;
|
||||
}
|
||||
|
||||
|
||||
ScheduleData.prototype.secondsTimer = function(){
|
||||
var date = new Date();
|
||||
this.estimatedSchedulePosixTime = date.getTime() - this.localRemoteTimeOffset;
|
||||
}
|
||||
|
||||
ScheduleData.prototype.getCurrentShow = function(){
|
||||
return this.currentShow;
|
||||
}
|
||||
|
||||
ScheduleData.prototype.getNextShows = function() {
|
||||
return this.nextShows;
|
||||
}
|
||||
|
||||
ScheduleData.prototype.getShowTimeElapsed = function(show) {
|
||||
this.secondsTimer();
|
||||
|
||||
var showStart = convertDateToPosixTime(show.getStartTimestamp());
|
||||
return convertToHHMMSS(this.estimatedSchedulePosixTime - showStart);
|
||||
};
|
||||
|
||||
ScheduleData.prototype.getShowTimeRemaining = function(show) {
|
||||
this.secondsTimer();
|
||||
|
||||
var showEnd = convertDateToPosixTime(show.getEndTimestamp());
|
||||
return convertToHHMMSS(showEnd - this.estimatedSchedulePosixTime);
|
||||
};
|
||||
/* ScheduleData class END */
|
||||
|
||||
/* Show class BEGIN */
|
||||
function Show(showData){
|
||||
this.showData = showData;
|
||||
}
|
||||
|
||||
Show.prototype.getName = function(){
|
||||
return this.showData.name;
|
||||
}
|
||||
Show.prototype.getRange = function(){
|
||||
return getTime(this.showData.start_timestamp) + " - " + getTime(this.showData.end_timestamp);
|
||||
}
|
||||
Show.prototype.getStartTimestamp = function(){
|
||||
return this.showData.start_timestamp;
|
||||
}
|
||||
Show.prototype.getEndTimestamp = function(){
|
||||
return this.showData.end_timestamp;
|
||||
}
|
||||
/* Show class END */
|
||||
|
||||
|
||||
function getTime(timestamp) {
|
||||
var time = timestamp.split(" ")[1].split(":");
|
||||
return time[0] + ":" + time[1];
|
||||
};
|
||||
|
||||
/* Takes an input parameter of milliseconds and converts these into
|
||||
* the format HH:MM:SS */
|
||||
function convertToHHMMSS(timeInMS){
|
||||
var time = parseInt(timeInMS);
|
||||
|
||||
var hours = parseInt(time / 3600000);
|
||||
time -= 3600000*hours;
|
||||
|
||||
var minutes = parseInt(time / 60000);
|
||||
time -= 60000*minutes;
|
||||
|
||||
var seconds = parseInt(time / 1000);
|
||||
|
||||
hours = hours.toString();
|
||||
minutes = minutes.toString();
|
||||
seconds = seconds.toString();
|
||||
|
||||
if (hours.length == 1)
|
||||
hours = "0" + hours;
|
||||
if (minutes.length == 1)
|
||||
minutes = "0" + minutes;
|
||||
if (seconds.length == 1)
|
||||
seconds = "0" + seconds;
|
||||
if (hours == "00")
|
||||
return minutes + ":" + seconds;
|
||||
else
|
||||
return hours + ":" + minutes + ":" + seconds;
|
||||
}
|
||||
|
||||
/* Takes in a string of format similar to 2011-02-07 02:59:57,
|
||||
* and converts this to epoch/posix time. */
|
||||
function convertDateToPosixTime(s){
|
||||
var datetime = s.split(" ");
|
||||
|
||||
var date = datetime[0].split("-");
|
||||
var time = datetime[1].split(":");
|
||||
|
||||
var year = date[0];
|
||||
var month = date[1];
|
||||
var day = date[2];
|
||||
var hour = time[0];
|
||||
var minute = time[1];
|
||||
var sec = 0;
|
||||
var msec = 0;
|
||||
|
||||
if (time[2].indexOf(".") != -1){
|
||||
var temp = time[2].split(".");
|
||||
sec = temp[0];
|
||||
msec = temp[1];
|
||||
} else
|
||||
sec = time[2];
|
||||
|
||||
return Date.UTC(year, month, day, hour, minute, sec, msec);
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 990 B |
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
|
@ -15,7 +15,11 @@
|
|||
#spl_sortable > li,
|
||||
#side_playlist > div,
|
||||
#spl_editor,
|
||||
.spl_artist {
|
||||
.spl_artist,
|
||||
.spl_cue_in,
|
||||
.spl_fade_in,
|
||||
.spl_cue_out,
|
||||
.spl_fade_out {
|
||||
clear: left;
|
||||
}
|
||||
|
||||
|
@ -35,8 +39,8 @@
|
|||
#spl_sortable {
|
||||
list-style: none;
|
||||
padding:0;
|
||||
height: 400px;
|
||||
overflow-y: scroll;
|
||||
height: 300px;
|
||||
overflow: auto;
|
||||
width:100%;
|
||||
margin-top:0;
|
||||
}
|
||||
|
@ -52,6 +56,10 @@
|
|||
border: none;
|
||||
}
|
||||
|
||||
#spl_name {
|
||||
|
||||
}
|
||||
|
||||
.ui-icon-closethick {
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
@ -72,10 +80,18 @@
|
|||
font-size:12px;
|
||||
}
|
||||
|
||||
/*#spl_editor {
|
||||
height: 50px;
|
||||
}*/
|
||||
|
||||
#spl_editor > div > span {
|
||||
/* display: inline-block;
|
||||
width: 150px;*/
|
||||
}
|
||||
|
||||
.ui-icon-closethick,
|
||||
.ui-icon-play,
|
||||
.spl_fade_control,
|
||||
.spl_playlength,
|
||||
.spl_text_input {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
@ -239,13 +255,12 @@
|
|||
margin: 0;
|
||||
|
||||
}
|
||||
dd.edit-error {
|
||||
.edit-error {
|
||||
color:#b80000;
|
||||
margin:0;
|
||||
padding-bottom:0;
|
||||
font-size:12px;
|
||||
display:none;
|
||||
clear: left;
|
||||
}
|
||||
|
||||
/*.edit-error:last-child {
|
||||
|
@ -276,3 +291,26 @@ dd.edit-error {
|
|||
top: 3px;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
#spl_sortable li .spl_cue {
|
||||
background-color: transparent;
|
||||
float:right;
|
||||
font-size: 9px;
|
||||
height: 15px;
|
||||
right: 35px;
|
||||
width: 33px;
|
||||
margin-top:2px;
|
||||
cursor:pointer;
|
||||
}
|
||||
#spl_sortable li .spl_cue.ui-state-default {
|
||||
background: transparent url(images/cue_playlist.png) no-repeat 0 0;
|
||||
border:none;
|
||||
}
|
||||
#spl_sortable li .spl_cue.ui-state-default:hover {
|
||||
background: transparent url(images/cue_playlist.png) no-repeat 0 -15px;
|
||||
border:none;
|
||||
}
|
||||
#spl_sortable li .spl_cue.ui-state-active, #spl_sortable li .spl_cue.ui-state-active:hover {
|
||||
background: transparent url(images/cue_playlist.png) no-repeat 0 -30px;
|
||||
border:none;
|
||||
}
|
|
@ -184,7 +184,7 @@ select {
|
|||
.progressbar .progress-show-error {
|
||||
background:#d40000 url(images/progressbar_show_error.png) repeat-x 0 0;
|
||||
}
|
||||
.now-playing-info .lenght {
|
||||
.now-playing-info .show-length {
|
||||
color:#c4c4c4;
|
||||
padding-left:6px;
|
||||
}
|
||||
|
@ -196,6 +196,7 @@ select {
|
|||
.time-info-block {
|
||||
padding:0 14px 0 2px;
|
||||
background:url(images/masterpanel_spacer.png) no-repeat right 0;
|
||||
min-width:105px;
|
||||
}
|
||||
.time-info-block ul {
|
||||
margin:0;
|
||||
|
@ -825,7 +826,6 @@ div.ui-datepicker {
|
|||
#schedule_playlist_chosen li > h3 > span.ui-icon.ui-icon-triangle-1-e,
|
||||
#schedule_playlist_chosen li > h3 > span.ui-icon.ui-icon-triangle-1-s {
|
||||
float:left;
|
||||
|
||||
margin-right: 8px;
|
||||
}
|
||||
#schedule_playlist_chosen li > h3 > span.ui-icon.ui-icon-close {
|
||||
|
@ -1219,6 +1219,16 @@ ul.errors li {
|
|||
margin-bottom:2px;
|
||||
border:1px solid #c83f3f;
|
||||
}
|
||||
|
||||
div.success{
|
||||
color:#3B5323;
|
||||
font-size:11px;
|
||||
padding:2px 4px;
|
||||
background:#93DB70;
|
||||
margin-bottom:2px;
|
||||
border:1px solid #488214;
|
||||
}
|
||||
|
||||
.collapsible-header {
|
||||
border: 1px solid #8f8f8f;
|
||||
background-color: #cccccc;
|
||||
|
@ -1474,9 +1484,35 @@ ul.errors li {
|
|||
margin:-4px 3px -3px 0;
|
||||
float:right;
|
||||
}
|
||||
|
||||
.time-flow {
|
||||
float:right;
|
||||
margin-right:4px;
|
||||
float:right;
|
||||
margin-right:4px;
|
||||
}
|
||||
.small-icon {
|
||||
display:block;
|
||||
width:20px;
|
||||
height:10px;
|
||||
float:right;
|
||||
margin-left:3px;
|
||||
}
|
||||
.small-icon.recording {
|
||||
background:url(images/icon_record.png) no-repeat 0 0;
|
||||
}
|
||||
.small-icon.rebroadcast {
|
||||
background:url(images/icon_rebroadcast.png) no-repeat 0 0;
|
||||
}
|
||||
|
||||
.medium-icon {
|
||||
display:block;
|
||||
width:25px;
|
||||
height:12px;
|
||||
float:right;
|
||||
margin-left:4px;
|
||||
}
|
||||
.medium-icon.recording {
|
||||
background:url(images/icon_record_m.png) no-repeat 0 0;
|
||||
}
|
||||
.medium-icon.rebroadcast {
|
||||
background:url(images/icon_rebroadcast_m.png) no-repeat 0 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -205,13 +205,15 @@ function openFadeEditor(event) {
|
|||
function openCueEditor(event) {
|
||||
event.stopPropagation();
|
||||
|
||||
var pos, url, li;
|
||||
var pos, url, li, icon;
|
||||
|
||||
li = $(this).parent().parent().parent();
|
||||
icon = $(this);
|
||||
pos = li.attr("id").split("_").pop();
|
||||
|
||||
if(li.hasClass("ui-state-active")) {
|
||||
li.removeClass("ui-state-active");
|
||||
icon.attr("class", "spl_cue ui-state-default");
|
||||
|
||||
$("#cues_"+pos)
|
||||
.empty()
|
||||
|
@ -220,6 +222,7 @@ function openCueEditor(event) {
|
|||
return;
|
||||
}
|
||||
|
||||
icon.attr("class", "spl_cue ui-state-default ui-state-active");
|
||||
url = '/Playlist/set-cue';
|
||||
|
||||
highlightActive(li);
|
||||
|
@ -253,7 +256,8 @@ function setSPLContent(json) {
|
|||
|
||||
$("#spl_sortable .ui-icon-closethick").click(deleteSPLItem);
|
||||
$(".spl_fade_control").click(openFadeEditor);
|
||||
$(".spl_playlength").click(openCueEditor);
|
||||
//$(".spl_playlength").click(openCueEditor);
|
||||
$(".spl_cue").click(openCueEditor);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -487,7 +491,8 @@ function setUpSPL() {
|
|||
|
||||
$("#spl_sortable .ui-icon-closethick").click(deleteSPLItem);
|
||||
$(".spl_fade_control").click(openFadeEditor);
|
||||
$(".spl_playlength").click(openCueEditor);
|
||||
//$(".spl_playlength").click(openCueEditor);
|
||||
$(".spl_cue").click(openCueEditor);
|
||||
|
||||
$("#spl_sortable").droppable();
|
||||
$("#spl_sortable" ).bind( "drop", addSPLItem);
|
||||
|
|
|
@ -182,7 +182,6 @@ function setAddShowEvents() {
|
|||
});
|
||||
|
||||
form.find("#add-show-submit")
|
||||
.button()
|
||||
.click(function(event){
|
||||
event.preventDefault();
|
||||
|
||||
|
|
|
@ -165,6 +165,25 @@ function eventRender(event, element, view) {
|
|||
}
|
||||
|
||||
$(element).find(".fc-event-title").after(div);
|
||||
}
|
||||
|
||||
//add the record/rebroadcast icons if needed.
|
||||
if((view.name === 'agendaDay' || view.name === 'agendaWeek') && event.record === 1) {
|
||||
|
||||
$(element).find(".fc-event-time").after('<span class="small-icon recording"></span>');
|
||||
}
|
||||
if(view.name === 'month' && event.record === 1) {
|
||||
|
||||
$(element).find(".fc-event-title").after('<span class="small-icon recording"></span>');
|
||||
}
|
||||
|
||||
if((view.name === 'agendaDay' || view.name === 'agendaWeek') && event.rebroadcast === 1) {
|
||||
|
||||
$(element).find(".fc-event-time").after('<span class="small-icon rebroadcast"></span>');
|
||||
}
|
||||
if(view.name === 'month' && event.rebroadcast === 1) {
|
||||
|
||||
$(element).find(".fc-event-title").after('<span class="small-icon rebroadcast"></span>');
|
||||
}
|
||||
|
||||
if(event.backgroundColor !== "") {
|
||||
|
|
|
@ -2,6 +2,7 @@ function populateForm(entries){
|
|||
//$('#user_details').show();
|
||||
|
||||
$('.errors').remove();
|
||||
$('.success').remove();
|
||||
|
||||
$('#user_id').val(entries.id);
|
||||
$('#login').val(entries.login);
|
||||
|
|
|
@ -165,11 +165,12 @@ function updatePlaybar(){
|
|||
|
||||
/* Column 1 update */
|
||||
$('#playlist').text("Current Show:");
|
||||
var recElem = $('.recording-show');
|
||||
if (currentShow.length > 0){
|
||||
$('#playlist').text(currentShow[0].name);
|
||||
|
||||
var recElem = $('.recording-show');
|
||||
currentShow[0].record ? recElem.show(): recElem.hide();
|
||||
(currentShow[0].record == "1") ? recElem.show(): recElem.hide();
|
||||
} else {
|
||||
recElem.hide();
|
||||
}
|
||||
|
||||
$('#show-length').empty();
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
import airtime_api_client
|
||||
import obp_api_client
|
||||
|
||||
def create_api_client(config):
|
||||
if config["api_client"] == "airtime":
|
||||
return campcaster_api_client.AirtimeApiClient(config)
|
||||
elif config["api_client"] == "obp":
|
||||
return obp_api_client.ObpApiClient(config)
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
#!/bin/sh
|
||||
pypo_user="pypo"
|
||||
export HOME="/home/pypo/"
|
||||
# Location of pypo_cli.py Python script
|
||||
pypo_path="/opt/pypo/bin/"
|
||||
pypo_script="pypo-cli.py"
|
||||
echo "*** Daemontools: starting daemon"
|
||||
cd ${pypo_path}
|
||||
exec 2>&1
|
||||
# Note the -u when calling python! we need it to get unbuffered binary stdout and stderr
|
||||
exec setuidgid ${pypo_user} \
|
||||
python -u ${pypo_path}${pypo_script} \
|
||||
-f
|
||||
# EOF
|
|
@ -1,23 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
if os.geteuid() != 0:
|
||||
print "Please run this as root."
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
print "Stopping daemontool script pypo-fetch"
|
||||
os.system("svc -dx /etc/service/pypo-fetch 2>/dev/null")
|
||||
|
||||
print "Stopping daemontool script pypo-push"
|
||||
os.system("svc -dx /etc/service/pypo-push 2>/dev/null")
|
||||
|
||||
print "Stopping daemontool script pypo-liquidsoap"
|
||||
os.system("svc -dx /etc/service/pypo-liquidsoap 2>/dev/null")
|
||||
os.system("killall liquidsoap")
|
||||
|
||||
except Exception, e:
|
||||
print "exception:" + str(e)
|
|
@ -1,60 +0,0 @@
|
|||
[loggers]
|
||||
keys=root
|
||||
|
||||
[handlers]
|
||||
keys=consoleHandler,fileHandlerERROR,fileHandlerDEBUG,nullHandler
|
||||
|
||||
[formatters]
|
||||
keys=simpleFormatter
|
||||
|
||||
[logger_root]
|
||||
level=DEBUG
|
||||
handlers=consoleHandler,fileHandlerERROR,fileHandlerDEBUG
|
||||
|
||||
[logger_libs]
|
||||
handlers=nullHandler
|
||||
level=DEBUG
|
||||
qualname="process"
|
||||
propagate=0
|
||||
|
||||
|
||||
[handler_consoleHandler]
|
||||
class=StreamHandler
|
||||
level=DEBUG
|
||||
formatter=simpleFormatter
|
||||
args=(sys.stdout,)
|
||||
|
||||
[handler_fileHandlerERROR]
|
||||
class=FileHandler
|
||||
level=WARNING
|
||||
formatter=simpleFormatter
|
||||
args=("./error.log",)
|
||||
|
||||
[handler_fileHandlerDEBUG]
|
||||
class=FileHandler
|
||||
level=DEBUG
|
||||
formatter=simpleFormatter
|
||||
args=("./debug.log",)
|
||||
|
||||
[handler_nullHandler]
|
||||
class=FileHandler
|
||||
level=DEBUG
|
||||
formatter=simpleFormatter
|
||||
args=("/dev/null",)
|
||||
|
||||
|
||||
[formatter_simpleFormatter]
|
||||
format=%(asctime)s %(levelname)s - [%(filename)s : %(funcName)s() : line %(lineno)d] - %(message)s
|
||||
datefmt=
|
||||
|
||||
|
||||
## multitail color sheme
|
||||
## pyml / python
|
||||
# colorscheme:pyml:www.obp.net
|
||||
# cs_re:blue:\[[^ ]*\]
|
||||
# cs_re:red:CRITICAL:*
|
||||
# cs_re:red,black,blink:ERROR:*
|
||||
# cs_re:blue:NOTICE:*
|
||||
# cs_re:cyan:INFO:*
|
||||
# cs_re:green:DEBUG:*
|
||||
|
Binary file not shown.
|
@ -13,6 +13,7 @@
|
|||
import sys
|
||||
import time
|
||||
import urllib
|
||||
import urllib2
|
||||
import logging
|
||||
import json
|
||||
import os
|
||||
|
@ -90,6 +91,12 @@ class ApiClientInterface:
|
|||
# You will be able to use this data in update_start_playing
|
||||
def get_liquidsoap_data(self, pkey, schedule):
|
||||
pass
|
||||
|
||||
def get_shows_to_record(self):
|
||||
pass
|
||||
|
||||
def upload_recorded_show(self):
|
||||
pass
|
||||
|
||||
# Put here whatever tests you want to run to make sure your API is working
|
||||
def test(self):
|
||||
|
@ -189,30 +196,10 @@ class AirTimeApiClient(ApiClientInterface):
|
|||
|
||||
def get_schedule(self, start=None, end=None):
|
||||
logger = logging.getLogger()
|
||||
|
||||
"""
|
||||
calculate start/end time range (format: YYYY-DD-MM-hh-mm-ss,YYYY-DD-MM-hh-mm-ss)
|
||||
(seconds are ignored, just here for consistency)
|
||||
"""
|
||||
tnow = time.localtime(time.time())
|
||||
if (not start):
|
||||
tstart = time.localtime(time.time() - 3600 * int(self.config["cache_for"]))
|
||||
start = "%04d-%02d-%02d-%02d-%02d" % (tstart[0], tstart[1], tstart[2], tstart[3], tstart[4])
|
||||
|
||||
if (not end):
|
||||
tend = time.localtime(time.time() + 3600 * int(self.config["prepare_ahead"]))
|
||||
end = "%04d-%02d-%02d-%02d-%02d" % (tend[0], tend[1], tend[2], tend[3], tend[4])
|
||||
|
||||
range = {}
|
||||
range['start'] = start
|
||||
range['end'] = end
|
||||
|
||||
|
||||
# Construct the URL
|
||||
export_url = self.config["base_url"] + self.config["api_base"] + self.config["export_url"]
|
||||
|
||||
# Insert the start and end times into the URL
|
||||
export_url = export_url.replace('%%from%%', range['start'])
|
||||
export_url = export_url.replace('%%to%%', range['end'])
|
||||
logger.info("Fetching schedule from %s", export_url)
|
||||
export_url = export_url.replace('%%api_key%%', self.config["api_key"])
|
||||
|
||||
|
@ -225,24 +212,6 @@ class AirTimeApiClient(ApiClientInterface):
|
|||
except Exception, e:
|
||||
print e
|
||||
|
||||
#schedule = response["playlists"]
|
||||
#scheduleKeys = sorted(schedule.iterkeys())
|
||||
#
|
||||
## Remove all playlists that have passed current time
|
||||
#try:
|
||||
# tnow = time.localtime(time.time())
|
||||
# str_tnow_s = "%04d-%02d-%02d-%02d-%02d-%02d" % (tnow[0], tnow[1], tnow[2], tnow[3], tnow[4], tnow[5])
|
||||
# toRemove = []
|
||||
# for pkey in scheduleKeys:
|
||||
# if (str_tnow_s > schedule[pkey]['end']):
|
||||
# toRemove.append(pkey)
|
||||
# else:
|
||||
# break
|
||||
# for index in toRemove:
|
||||
# del schedule[index]
|
||||
#except Exception, e:
|
||||
#response["playlists"] = schedule
|
||||
|
||||
return status, response
|
||||
|
||||
|
||||
|
@ -316,6 +285,41 @@ class AirTimeApiClient(ApiClientInterface):
|
|||
except Exception, e:
|
||||
data["schedule_id"] = 0
|
||||
return data
|
||||
|
||||
def get_shows_to_record(self):
|
||||
logger = logging.getLogger()
|
||||
response = ''
|
||||
try:
|
||||
url = self.config["base_url"] + self.config["api_base"] + self.config["show_schedule_url"]
|
||||
logger.debug(url)
|
||||
url = url.replace("%%api_key%%", self.config["api_key"])
|
||||
|
||||
response = urllib.urlopen(url)
|
||||
response = json.loads(response.read())
|
||||
logger.info("shows %s", response)
|
||||
|
||||
except Exception, e:
|
||||
logger.error("Exception: %s", e)
|
||||
|
||||
return response[u'shows']
|
||||
|
||||
def upload_recorded_show(self, data, headers):
|
||||
logger = logging.getLogger()
|
||||
response = ''
|
||||
try:
|
||||
url = self.config["base_url"] + self.config["api_base"] + self.config["upload_file_url"]
|
||||
logger.debug(url)
|
||||
url = url.replace("%%api_key%%", self.config["api_key"])
|
||||
|
||||
request = urllib2.Request(url, data, headers)
|
||||
response = urllib2.urlopen(request).read().strip()
|
||||
|
||||
logger.info("uploaded show result %s", response)
|
||||
|
||||
except Exception, e:
|
||||
logger.error("Exception: %s", e)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
|
Binary file not shown.
|
@ -26,6 +26,13 @@ base_url = 'http://localhost/'
|
|||
ls_host = '127.0.0.1'
|
||||
ls_port = '1234'
|
||||
|
||||
############################################
|
||||
# RabbitMQ settings #
|
||||
############################################
|
||||
rabbitmq_host = 'localhost'
|
||||
rabbitmq_user = 'guest'
|
||||
rabbitmq_password = 'guest'
|
||||
|
||||
############################################
|
||||
# pypo preferences #
|
||||
############################################
|
||||
|
@ -34,15 +41,13 @@ cache_for = 24 #how long to hold the cache, in hours
|
|||
|
||||
# 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.
|
||||
# server in the event that no changes are made to the schedule.
|
||||
#
|
||||
# For production use, this number depends on whether you plan on making any
|
||||
# last-minute changes to your schedule. This number should be set to half of
|
||||
# the time you expect to "lock-in" your schedule. So if your schedule is set
|
||||
# 24 hours in advance, this can be set to poll every 12 hours.
|
||||
#
|
||||
poll_interval = 5 # in seconds.
|
||||
poll_interval = 3600 # in seconds.
|
||||
|
||||
|
||||
# Push interval in seconds.
|
||||
|
@ -52,7 +57,7 @@ poll_interval = 5 # in seconds.
|
|||
#
|
||||
# It's hard to imagine a situation where this should be more than 1 second.
|
||||
#
|
||||
push_interval = 2 # in seconds
|
||||
push_interval = 1 # in seconds
|
||||
|
||||
# 'pre' or 'otf'. 'pre' cues while playlist preparation
|
||||
# while 'otf' (on the fly) cues while loading into ls
|
||||
|
@ -80,7 +85,7 @@ version_url = 'version/api_key/%%api_key%%'
|
|||
# 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%%/from/%%from%%/to/%%to%%'
|
||||
export_url = 'schedule/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%%'
|
|
@ -1,10 +1,12 @@
|
|||
#!/bin/sh
|
||||
ls_user="pypo"
|
||||
export HOME="/home/pypo/"
|
||||
api_client_path="/opt/pypo/"
|
||||
ls_path="/opt/pypo/bin/liquidsoap/liquidsoap"
|
||||
ls_param="/opt/pypo/bin/scripts/ls_script.liq"
|
||||
echo "*** Daemontools: starting liquidsoap"
|
||||
exec 2>&1
|
||||
echo "exec sudo -u ${ls_user} ${ls_path} ${ls_param} "
|
||||
cd /opt/pypo/bin/scripts && sudo -u ${ls_user} ${ls_path} ${ls_param}
|
||||
|
||||
cd /opt/pypo/bin/scripts
|
||||
sudo PYTHONPATH=${api_client_path} -u ${ls_user} ${ls_path} ${ls_param}
|
||||
# EOF
|
|
@ -3,12 +3,16 @@ pypo_user="pypo"
|
|||
export HOME="/home/pypo/"
|
||||
# Location of pypo_cli.py Python script
|
||||
pypo_path="/opt/pypo/bin/"
|
||||
api_client_path="/opt/pypo/"
|
||||
pypo_script="pypo-cli.py"
|
||||
echo "*** Daemontools: starting daemon"
|
||||
cd ${pypo_path}
|
||||
exec 2>&1
|
||||
|
||||
PYTHONPATH=${api_client_path}:$PYTHONPATH
|
||||
export PYTHONPATH
|
||||
|
||||
# Note the -u when calling python! we need it to get unbuffered binary stdout and stderr
|
||||
exec setuidgid ${pypo_user} \
|
||||
python -u ${pypo_path}${pypo_script} \
|
||||
-p
|
||||
python -u ${pypo_path}${pypo_script}
|
||||
# EOF
|
|
@ -36,14 +36,16 @@ def create_user(username):
|
|||
os.system("adduser --system --quiet --group --shell /bin/bash "+username)
|
||||
|
||||
#set pypo password
|
||||
p = os.popen('/usr/bin/passwd pypo', 'w')
|
||||
p = os.popen('/usr/bin/passwd pypo 1>/dev/null 2>&1', 'w')
|
||||
p.write('pypo\n')
|
||||
p.write('pypo\n')
|
||||
p.close()
|
||||
else:
|
||||
print "User already exists."
|
||||
#add pypo to audio group
|
||||
os.system("adduser " + username + " audio 2>&1 1>/dev/null")
|
||||
os.system("adduser " + username + " audio 1>/dev/null 2>&1")
|
||||
#add pypo to pulse-access group
|
||||
#os.system("adduser " + username + " pulse-access 1>/dev/null 2>&1")
|
||||
|
||||
def copy_dir(src_dir, dest_dir):
|
||||
if (os.path.exists(dest_dir)) and (dest_dir != "/"):
|
||||
|
@ -63,7 +65,7 @@ def get_current_script_dir():
|
|||
try:
|
||||
current_script_dir = get_current_script_dir()
|
||||
print "Checking and removing any existing pypo processes"
|
||||
os.system("python %s/pypo-uninstall.py 2>&1 1>/dev/null"% current_script_dir)
|
||||
os.system("python %s/pypo-uninstall.py 1>/dev/null 2>&1"% current_script_dir)
|
||||
time.sleep(5)
|
||||
|
||||
# Create users
|
||||
|
@ -79,14 +81,8 @@ try:
|
|||
create_path(BASE_PATH+"cache")
|
||||
create_path(BASE_PATH+"files")
|
||||
create_path(BASE_PATH+"tmp")
|
||||
create_path(BASE_PATH+"files/basic")
|
||||
create_path(BASE_PATH+"files/fallback")
|
||||
create_path(BASE_PATH+"files/jingles")
|
||||
create_path(BASE_PATH+"archive")
|
||||
|
||||
print "Copying pypo files"
|
||||
shutil.copy("%s/../scripts/silence.mp3"%current_script_dir, BASE_PATH+"files/basic")
|
||||
|
||||
|
||||
if platform.architecture()[0] == '64bit':
|
||||
print "Installing 64-bit liquidsoap binary"
|
||||
shutil.copy("%s/../liquidsoap/liquidsoap64"%current_script_dir, "%s/../liquidsoap/liquidsoap"%current_script_dir)
|
||||
|
@ -98,28 +94,21 @@ try:
|
|||
sys.exit(1)
|
||||
|
||||
copy_dir("%s/.."%current_script_dir, BASE_PATH+"bin/")
|
||||
copy_dir("%s/../../api_clients"%current_script_dir, BASE_PATH+"api_clients/")
|
||||
|
||||
print "Setting permissions"
|
||||
os.system("chmod -R 755 "+BASE_PATH)
|
||||
os.system("chown -R pypo:pypo "+BASE_PATH)
|
||||
|
||||
print "Installing daemontool script pypo-fetch"
|
||||
create_path("/etc/service/pypo-fetch")
|
||||
create_path("/etc/service/pypo-fetch/log")
|
||||
shutil.copy("%s/pypo-daemontools-fetch.sh"%current_script_dir, "/etc/service/pypo-fetch/run")
|
||||
shutil.copy("%s/pypo-daemontools-logger.sh"%current_script_dir, "/etc/service/pypo-fetch/log/run")
|
||||
os.system("chmod -R 755 /etc/service/pypo-fetch")
|
||||
os.system("chown -R pypo:pypo /etc/service/pypo-fetch")
|
||||
print "Installing pypo daemon"
|
||||
create_path("/etc/service/pypo")
|
||||
create_path("/etc/service/pypo/log")
|
||||
shutil.copy("%s/pypo-daemontools.sh"%current_script_dir, "/etc/service/pypo/run")
|
||||
shutil.copy("%s/pypo-daemontools-logger.sh"%current_script_dir, "/etc/service/pypo/log/run")
|
||||
os.system("chmod -R 755 /etc/service/pypo")
|
||||
os.system("chown -R pypo:pypo /etc/service/pypo")
|
||||
|
||||
print "Installing daemontool script pypo-push"
|
||||
create_path("/etc/service/pypo-push")
|
||||
create_path("/etc/service/pypo-push/log")
|
||||
shutil.copy("%s/pypo-daemontools-push.sh"%current_script_dir, "/etc/service/pypo-push/run")
|
||||
shutil.copy("%s/pypo-daemontools-logger.sh"%current_script_dir, "/etc/service/pypo-push/log/run")
|
||||
os.system("chmod -R 755 /etc/service/pypo-push")
|
||||
os.system("chown -R pypo:pypo /etc/service/pypo-push")
|
||||
|
||||
print "Installing daemontool script pypo-liquidsoap"
|
||||
print "Installing liquidsoap daemon"
|
||||
create_path("/etc/service/pypo-liquidsoap")
|
||||
create_path("/etc/service/pypo-liquidsoap/log")
|
||||
shutil.copy("%s/pypo-daemontools-liquidsoap.sh"%current_script_dir, "/etc/service/pypo-liquidsoap/run")
|
||||
|
@ -134,16 +123,12 @@ try:
|
|||
|
||||
found = True
|
||||
|
||||
p = Popen('svstat /etc/service/pypo-fetch', shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
|
||||
p = Popen('svstat /etc/service/pypo', shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
|
||||
output = p.stdout.read()
|
||||
if (output.find("unable to open supervise/ok: file does not exist") >= 0):
|
||||
found = False
|
||||
print output
|
||||
|
||||
p = Popen('svstat /etc/service/pypo-push', shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
|
||||
output = p.stdout.read()
|
||||
print output
|
||||
|
||||
|
||||
p = Popen('svstat /etc/service/pypo-liquidsoap', shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
|
||||
output = p.stdout.read()
|
||||
print output
|
||||
|
@ -152,6 +137,7 @@ try:
|
|||
print "Pypo install has completed, but daemontools is not running, please make sure you have it installed and then reboot."
|
||||
except Exception, e:
|
||||
print "exception:" + str(e)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
|
|
@ -9,12 +9,9 @@ if os.geteuid() != 0:
|
|||
sys.exit(1)
|
||||
|
||||
try:
|
||||
print "Starting daemontool script pypo-fetch"
|
||||
os.system("svc -u /etc/service/pypo-fetch")
|
||||
|
||||
print "Starting daemontool script pypo-push"
|
||||
os.system("svc -u /etc/service/pypo-push")
|
||||
|
||||
print "Starting daemontool script pypo"
|
||||
os.system("svc -u /etc/service/pypo")
|
||||
|
||||
print "Starting daemontool script pypo-liquidsoap"
|
||||
os.system("svc -u /etc/service/pypo-liquidsoap")
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
if os.geteuid() != 0:
|
||||
print "Please run this as root."
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
print "Stopping daemontool script pypo"
|
||||
os.system("svc -dx /etc/service/pypo 1>/dev/null 2>&1")
|
||||
|
||||
if os.path.exists("/etc/service/pypo-fetch"):
|
||||
os.system("svc -dx /etc/service/pypo-fetch 1>/dev/null 2>&1")
|
||||
if os.path.exists("/etc/service/pypo-push"):
|
||||
os.system("svc -dx /etc/service/pypo-push 1>/dev/null 2>&1")
|
||||
|
||||
print "Stopping daemontool script pypo-liquidsoap"
|
||||
os.system("svc -dx /etc/service/pypo-liquidsoap 1>/dev/null 2>&1")
|
||||
os.system("killall liquidsoap")
|
||||
|
||||
except Exception, e:
|
||||
print "exception:" + str(e)
|
|
@ -15,13 +15,13 @@ def remove_path(path):
|
|||
os.system("rm -rf " + path)
|
||||
|
||||
def remove_user(username):
|
||||
os.system("killall -u %s 2>&1 1>/dev/null" % username)
|
||||
os.system("killall -u %s 1>/dev/null 2>&1" % username)
|
||||
|
||||
#allow all process to be completely closed before we attempt to delete user
|
||||
print "Waiting for processes to close..."
|
||||
time.sleep(5)
|
||||
|
||||
os.system("deluser --remove-home " + username + " 1>/dev/null")
|
||||
os.system("deluser --remove-home " + username + " 1>/dev/null 2>&1")
|
||||
|
||||
def get_current_script_dir():
|
||||
current_script_dir = os.path.realpath(__file__)
|
||||
|
@ -37,16 +37,19 @@ try:
|
|||
print "Removing pypo files"
|
||||
remove_path(BASE_PATH)
|
||||
|
||||
print "Removing daemontool script pypo-fetch"
|
||||
remove_path("rm -rf /etc/service/pypo-fetch")
|
||||
|
||||
print "Removing daemontool script pypo-push"
|
||||
remove_path("rm -rf /etc/service/pypo-push")
|
||||
|
||||
print "Removing daemontool script pypo"
|
||||
remove_path("/etc/service/pypo")
|
||||
|
||||
if os.path.exists("/etc/service/pypo-fetch"):
|
||||
remove_path("/etc/service/pypo-fetch")
|
||||
|
||||
if os.path.exists("/etc/service/pypo-push"):
|
||||
remove_path("/etc/service/pypo-push")
|
||||
|
||||
print "Removing daemontool script pypo-liquidsoap"
|
||||
remove_path("rm -rf /etc/service/pypo-liquidsoap")
|
||||
remove_path("/etc/service/pypo-liquidsoap")
|
||||
|
||||
remove_user("pypo")
|
||||
print "Uninstall complete."
|
||||
print "Pypo uninstall complete."
|
||||
except Exception, e:
|
||||
print "exception:" + str(e)
|
|
@ -0,0 +1,34 @@
|
|||
[loggers]
|
||||
keys=root,fetch,push
|
||||
|
||||
[handlers]
|
||||
keys=consoleHandler
|
||||
|
||||
[formatters]
|
||||
keys=simpleFormatter
|
||||
|
||||
[logger_root]
|
||||
level=DEBUG
|
||||
handlers=consoleHandler
|
||||
|
||||
[logger_fetch]
|
||||
level=DEBUG
|
||||
handlers=consoleHandler
|
||||
qualname=fetch
|
||||
propagate=0
|
||||
|
||||
[logger_push]
|
||||
level=DEBUG
|
||||
handlers=consoleHandler
|
||||
qualname=push
|
||||
propagate=0
|
||||
|
||||
[handler_consoleHandler]
|
||||
class=StreamHandler
|
||||
level=DEBUG
|
||||
formatter=simpleFormatter
|
||||
args=(sys.stdout,)
|
||||
|
||||
[formatter_simpleFormatter]
|
||||
format=%(asctime)s %(levelname)s - [%(filename)s : %(funcName)s() : line %(lineno)d] - %(message)s
|
||||
datefmt=
|
|
@ -7,14 +7,13 @@ Python part of radio playout (pypo)
|
|||
The main functions are "fetch" (./pypo_cli.py -f) and "push" (./pypo_cli.py -p)
|
||||
"""
|
||||
|
||||
# python defaults (debian default)
|
||||
import time
|
||||
#import calendar
|
||||
|
||||
|
||||
#import traceback
|
||||
from optparse import *
|
||||
import sys
|
||||
import os
|
||||
import signal
|
||||
#import datetime
|
||||
import logging
|
||||
import logging.config
|
||||
|
@ -27,11 +26,11 @@ import logging.config
|
|||
#import string
|
||||
#import operator
|
||||
#import inspect
|
||||
from Queue import Queue
|
||||
|
||||
from pypopush import PypoPush
|
||||
from pypofetch import PypoFetch
|
||||
|
||||
# additional modules (should be checked)
|
||||
from configobj import ConfigObj
|
||||
|
||||
# custom imports
|
||||
|
@ -53,7 +52,6 @@ parser.add_option("-v", "--compat", help="Check compatibility with server API ve
|
|||
parser.add_option("-t", "--test", help="Do a test to make sure everything is working properly.", default=False, action="store_true", dest="test")
|
||||
parser.add_option("-f", "--fetch-scheduler", help="Fetch the schedule from server. This is a polling process that runs forever.", default=False, action="store_true", dest="fetch_scheduler")
|
||||
parser.add_option("-p", "--push-scheduler", help="Push the schedule to Liquidsoap. This is a polling process that runs forever.", default=False, action="store_true", dest="push_scheduler")
|
||||
|
||||
parser.add_option("-b", "--cleanup", help="Cleanup", default=False, action="store_true", dest="cleanup")
|
||||
parser.add_option("-c", "--check", help="Check the cached schedule and exit", default=False, action="store_true", dest="check")
|
||||
|
||||
|
@ -66,10 +64,6 @@ logging.config.fileConfig("logging.cfg")
|
|||
# loading config file
|
||||
try:
|
||||
config = ConfigObj('config.cfg')
|
||||
POLL_INTERVAL = float(config['poll_interval'])
|
||||
PUSH_INTERVAL = float(config['push_interval'])
|
||||
LS_HOST = config['ls_host']
|
||||
LS_PORT = config['ls_port']
|
||||
except Exception, e:
|
||||
print 'Error loading config file: ', e
|
||||
sys.exit()
|
||||
|
@ -121,55 +115,44 @@ class Global:
|
|||
for media in playlist['medias']:
|
||||
print media
|
||||
|
||||
def keyboardInterruptHandler(signum, frame):
|
||||
print "\nKeyboard Interrupt\n"
|
||||
sys.exit();
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print '###########################################'
|
||||
print '# *** pypo *** #'
|
||||
print '# Liquidsoap + External Scheduler #'
|
||||
print '# Playout System #'
|
||||
print '# Liquidsoap Scheduled Playout System #'
|
||||
print '###########################################'
|
||||
|
||||
signal.signal(signal.SIGINT, keyboardInterruptHandler)
|
||||
|
||||
# initialize
|
||||
g = Global()
|
||||
g.selfcheck()
|
||||
|
||||
logger = logging.getLogger()
|
||||
loops = 0
|
||||
|
||||
if options.test:
|
||||
g.test_api()
|
||||
sys.exit()
|
||||
|
||||
|
||||
if options.fetch_scheduler:
|
||||
pf = PypoFetch()
|
||||
while True:
|
||||
try: pf.fetch('scheduler')
|
||||
except Exception, e:
|
||||
print e
|
||||
sys.exit()
|
||||
q = Queue()
|
||||
|
||||
if (loops%2 == 0):
|
||||
logger.info("heartbeat")
|
||||
loops += 1
|
||||
time.sleep(POLL_INTERVAL)
|
||||
pp = PypoPush(q)
|
||||
pp.daemon = True
|
||||
pp.start()
|
||||
|
||||
if options.push_scheduler:
|
||||
pp = PypoPush()
|
||||
while True:
|
||||
try: pp.push('scheduler')
|
||||
except Exception, e:
|
||||
print 'PUSH ERROR!! WILL EXIT NOW:('
|
||||
print e
|
||||
sys.exit()
|
||||
pf = PypoFetch(q)
|
||||
pf.daemon = True
|
||||
pf.start()
|
||||
|
||||
if (loops%60 == 0):
|
||||
logger.info("heartbeat")
|
||||
|
||||
loops += 1
|
||||
time.sleep(PUSH_INTERVAL)
|
||||
while True: time.sleep(3600)
|
||||
|
||||
#pp.join()
|
||||
#pf.join()
|
||||
"""
|
||||
if options.check:
|
||||
try: g.check_schedule()
|
||||
except Exception, e:
|
||||
|
@ -179,4 +162,4 @@ if __name__ == '__main__':
|
|||
try: pf.cleanup('scheduler')
|
||||
except Exception, e:
|
||||
print e
|
||||
sys.exit()
|
||||
"""
|
|
@ -9,146 +9,151 @@ import random
|
|||
import string
|
||||
import json
|
||||
import telnetlib
|
||||
import math
|
||||
from threading import Thread
|
||||
from subprocess import Popen, PIPE
|
||||
|
||||
# For RabbitMQ
|
||||
from kombu.connection import BrokerConnection
|
||||
from kombu.messaging import Exchange, Queue, Consumer, Producer
|
||||
|
||||
from api_clients import api_client
|
||||
from util import CueFile
|
||||
|
||||
from configobj import ConfigObj
|
||||
|
||||
# configure logging
|
||||
logging.config.fileConfig("logging.cfg")
|
||||
|
||||
# loading config file
|
||||
try:
|
||||
config = ConfigObj('config.cfg')
|
||||
POLL_INTERVAL = float(config['poll_interval'])
|
||||
PUSH_INTERVAL = 0.5
|
||||
#PUSH_INTERVAL = float(config['push_interval'])
|
||||
LS_HOST = config['ls_host']
|
||||
LS_PORT = config['ls_port']
|
||||
POLL_INTERVAL = int(config['poll_interval'])
|
||||
|
||||
except Exception, e:
|
||||
print 'Error loading config file: ', e
|
||||
sys.exit()
|
||||
|
||||
class PypoFetch:
|
||||
def __init__(self):
|
||||
# Yuk - using a global, i know!
|
||||
SCHEDULE_PUSH_MSG = []
|
||||
|
||||
"""
|
||||
Handle a message from RabbitMQ, put it into our yucky global var.
|
||||
Hopefully there is a better way to do this.
|
||||
"""
|
||||
def handle_message(body, message):
|
||||
logger = logging.getLogger('fetch')
|
||||
global SCHEDULE_PUSH_MSG
|
||||
logger.info("Received schedule from RabbitMQ: " + message.body)
|
||||
SCHEDULE_PUSH_MSG = json.loads(message.body)
|
||||
# ACK the message to take it off the queue
|
||||
message.ack()
|
||||
|
||||
|
||||
class PypoFetch(Thread):
|
||||
def __init__(self, q):
|
||||
Thread.__init__(self)
|
||||
logger = logging.getLogger('fetch')
|
||||
self.api_client = api_client.api_client_factory(config)
|
||||
self.cue_file = CueFile()
|
||||
self.set_export_source('scheduler')
|
||||
self.queue = q
|
||||
|
||||
logger.info("Initializing RabbitMQ stuff")
|
||||
schedule_exchange = Exchange("airtime-schedule", "direct", durable=True, auto_delete=True)
|
||||
schedule_queue = Queue("pypo-fetch", exchange=schedule_exchange, key="foo")
|
||||
self.connection = BrokerConnection(config["rabbitmq_host"], config["rabbitmq_user"], config["rabbitmq_password"], "/")
|
||||
channel = self.connection.channel()
|
||||
consumer = Consumer(channel, schedule_queue)
|
||||
consumer.register_callback(handle_message)
|
||||
consumer.consume()
|
||||
|
||||
logger.info("PypoFetch: init complete")
|
||||
|
||||
|
||||
def set_export_source(self, export_source):
|
||||
self.export_source = export_source
|
||||
self.cache_dir = config["cache_dir"] + self.export_source + '/'
|
||||
self.schedule_file = self.cache_dir + 'schedule.pickle'
|
||||
self.schedule_tracker_file = self.cache_dir + "schedule_tracker.pickle"
|
||||
|
||||
def check_matching_timezones(self, server_timezone):
|
||||
logger = logging.getLogger('fetch')
|
||||
|
||||
process = Popen(["date", "+%z"], stdout=PIPE)
|
||||
pypo_timezone = (process.communicate()[0]).strip(' \r\n\t')
|
||||
|
||||
if server_timezone != pypo_timezone:
|
||||
logger.error("Server and pypo timezone offsets do not match. Audio playback may not start when expected!")
|
||||
logger.error("Server timezone offset: %s", server_timezone)
|
||||
logger.error("Pypo timezone offset: %s", pypo_timezone)
|
||||
|
||||
"""
|
||||
Fetching part of pypo
|
||||
- Reads the scheduled entries of a given range (actual time +/- "prepare_ahead" / "cache_for")
|
||||
- Saves a serialized file of the schedule
|
||||
- playlists are prepared. (brought to liquidsoap format) and, if not mounted via nsf, files are copied
|
||||
to the cache dir (Folder-structure: cache/YYYY-MM-DD-hh-mm-ss)
|
||||
- runs the cleanup routine, to get rid of unused cashed files
|
||||
Process the schedule
|
||||
- Reads the scheduled entries of a given range (actual time +/- "prepare_ahead" / "cache_for")
|
||||
- Saves a serialized file of the schedule
|
||||
- playlists are prepared. (brought to liquidsoap format) and, if not mounted via nsf, files are copied
|
||||
to the cache dir (Folder-structure: cache/YYYY-MM-DD-hh-mm-ss)
|
||||
- runs the cleanup routine, to get rid of unused cashed files
|
||||
"""
|
||||
def fetch(self, export_source):
|
||||
"""
|
||||
wrapper script for fetching the whole schedule (in json)
|
||||
"""
|
||||
logger = logging.getLogger()
|
||||
def process_schedule(self, schedule_data, export_source):
|
||||
logger = logging.getLogger('fetch')
|
||||
self.schedule = schedule_data["playlists"]
|
||||
|
||||
try: os.mkdir(self.cache_dir)
|
||||
except Exception, e: pass
|
||||
|
||||
# get schedule
|
||||
self.check_matching_timezones(schedule_data["server_timezone"])
|
||||
|
||||
# Push stream metadata to liquidsoap
|
||||
# TODO: THIS LIQUIDSOAP STUFF NEEDS TO BE MOVED TO PYPO-PUSH!!!
|
||||
stream_metadata = schedule_data['stream_metadata']
|
||||
try:
|
||||
while self.get_schedule() != 1:
|
||||
logger.warning("failed to read from export url")
|
||||
time.sleep(1)
|
||||
tn = telnetlib.Telnet(LS_HOST, LS_PORT)
|
||||
#encode in latin-1 due to telnet protocol not supporting utf-8
|
||||
tn.write(('vars.stream_metadata_type %s\n' % stream_metadata['format']).encode('latin-1'))
|
||||
tn.write(('vars.station_name %s\n' % stream_metadata['station_name']).encode('latin-1'))
|
||||
tn.write('exit\n')
|
||||
tn.read_all()
|
||||
except Exception, e:
|
||||
logger.error("Exception %s", e)
|
||||
status = 0
|
||||
|
||||
# Download all the media and put playlists in liquidsoap format
|
||||
try:
|
||||
playlists = self.prepare_playlists()
|
||||
except Exception, e: logger.error("%s", e)
|
||||
|
||||
# prepare the playlists
|
||||
if config["cue_style"] == 'pre':
|
||||
try: self.prepare_playlists_cue()
|
||||
except Exception, e: logger.error("%s", e)
|
||||
elif config["cue_style"] == 'otf':
|
||||
try: self.prepare_playlists(self.export_source)
|
||||
except Exception, e: logger.error("%s", e)
|
||||
# Send the data to pypo-push
|
||||
scheduled_data = dict()
|
||||
scheduled_data['playlists'] = playlists
|
||||
scheduled_data['schedule'] = self.schedule
|
||||
scheduled_data['stream_metadata'] = schedule_data["stream_metadata"]
|
||||
self.queue.put(scheduled_data)
|
||||
|
||||
# cleanup
|
||||
try: self.cleanup(self.export_source)
|
||||
except Exception, e: logger.error("%s", e)
|
||||
|
||||
def get_schedule(self):
|
||||
logger = logging.getLogger()
|
||||
status, response = self.api_client.get_schedule()
|
||||
|
||||
if status == 1:
|
||||
logger.info("dump serialized schedule to %s", self.schedule_file)
|
||||
schedule = response['playlists']
|
||||
stream_metadata = response['stream_metadata']
|
||||
try:
|
||||
schedule_file = open(self.schedule_file, "w")
|
||||
pickle.dump(schedule, schedule_file)
|
||||
schedule_file.close()
|
||||
|
||||
tn = telnetlib.Telnet(LS_HOST, LS_PORT)
|
||||
|
||||
#encode in latin-1 due to telnet protocol not supporting utf-8
|
||||
tn.write(('vars.stream_metadata_type %s\n' % stream_metadata['format']).encode('latin-1'))
|
||||
tn.write(('vars.station_name %s\n' % stream_metadata['station_name']).encode('latin-1'))
|
||||
|
||||
tn.write('exit\n')
|
||||
logger.debug(tn.read_all())
|
||||
|
||||
except Exception, e:
|
||||
logger.error("Exception %s", e)
|
||||
status = 0
|
||||
|
||||
return status
|
||||
|
||||
#TODO this is a duplicate function!!!
|
||||
def load_schedule(self):
|
||||
logger = logging.getLogger()
|
||||
schedule = None
|
||||
|
||||
# create the file if it doesnt exist
|
||||
if (not os.path.exists(self.schedule_file)):
|
||||
logger.debug('creating file ' + self.schedule_file)
|
||||
open(self.schedule_file, 'w').close()
|
||||
else:
|
||||
# load the schedule from cache
|
||||
#logger.debug('loading schedule file '+self.schedule_file)
|
||||
try:
|
||||
schedule_file = open(self.schedule_file, "r")
|
||||
schedule = pickle.load(schedule_file)
|
||||
schedule_file.close()
|
||||
|
||||
except Exception, e:
|
||||
logger.error('%s', e)
|
||||
|
||||
return schedule
|
||||
|
||||
|
||||
"""
|
||||
Alternative version of playout preparation. Every playlist entry is
|
||||
pre-cued if neccessary (cue_in/cue_out != 0) and stored in the
|
||||
playlist folder.
|
||||
file is eg 2010-06-23-15-00-00/17_cue_10.132-123.321.mp3
|
||||
In this function every audio file is cut as necessary (cue_in/cue_out != 0)
|
||||
and stored in a playlist folder.
|
||||
file is e.g. 2010-06-23-15-00-00/17_cue_10.132-123.321.mp3
|
||||
"""
|
||||
def prepare_playlists_cue(self):
|
||||
logger = logging.getLogger()
|
||||
def prepare_playlists(self):
|
||||
logger = logging.getLogger('fetch')
|
||||
|
||||
# Load schedule from disk
|
||||
schedule = self.load_schedule()
|
||||
schedule = self.schedule
|
||||
playlists = dict()
|
||||
|
||||
# Dont do anything if schedule is empty
|
||||
if (not schedule):
|
||||
if not schedule:
|
||||
logger.debug("Schedule is empty.")
|
||||
return
|
||||
return playlists
|
||||
|
||||
scheduleKeys = sorted(schedule.iterkeys())
|
||||
|
||||
try:
|
||||
for pkey in scheduleKeys:
|
||||
logger.info("found playlist at %s", pkey)
|
||||
logger.info("Playlist starting at %s", pkey)
|
||||
playlist = schedule[pkey]
|
||||
|
||||
# create playlist directory
|
||||
|
@ -157,15 +162,15 @@ class PypoFetch:
|
|||
except Exception, e:
|
||||
pass
|
||||
|
||||
logger.debug('*****************************************')
|
||||
logger.debug('pkey: ' + str(pkey))
|
||||
logger.debug('cached at : ' + self.cache_dir + str(pkey))
|
||||
logger.debug('subtype: ' + str(playlist['subtype']))
|
||||
logger.debug('played: ' + str(playlist['played']))
|
||||
logger.debug('schedule id: ' + str(playlist['schedule_id']))
|
||||
logger.debug('duration: ' + str(playlist['duration']))
|
||||
logger.debug('source id: ' + str(playlist['x_ident']))
|
||||
logger.debug('*****************************************')
|
||||
#logger.debug('*****************************************')
|
||||
#logger.debug('pkey: ' + str(pkey))
|
||||
#logger.debug('cached at : ' + self.cache_dir + str(pkey))
|
||||
#logger.debug('subtype: ' + str(playlist['subtype']))
|
||||
#logger.debug('played: ' + str(playlist['played']))
|
||||
#logger.debug('schedule id: ' + str(playlist['schedule_id']))
|
||||
#logger.debug('duration: ' + str(playlist['duration']))
|
||||
#logger.debug('source id: ' + str(playlist['x_ident']))
|
||||
#logger.debug('*****************************************')
|
||||
|
||||
if int(playlist['played']) == 1:
|
||||
logger.info("playlist %s already played / sent to liquidsoap, so will ignore it", pkey)
|
||||
|
@ -173,34 +178,32 @@ class PypoFetch:
|
|||
elif int(playlist['subtype']) > 0 and int(playlist['subtype']) < 5:
|
||||
ls_playlist = self.handle_media_file(playlist, pkey)
|
||||
|
||||
# write playlist file
|
||||
plfile = open(self.cache_dir + str(pkey) + '/list.lsp', "w")
|
||||
plfile.write(json.dumps(ls_playlist))
|
||||
plfile.close()
|
||||
logger.info('ls playlist file written to %s', self.cache_dir + str(pkey) + '/list.lsp')
|
||||
|
||||
playlists[pkey] = ls_playlist
|
||||
except Exception, e:
|
||||
logger.info("%s", e)
|
||||
return playlists
|
||||
|
||||
|
||||
"""
|
||||
Download and cache the media files.
|
||||
This handles both remote and local files.
|
||||
Returns an updated ls_playlist string.
|
||||
"""
|
||||
def handle_media_file(self, playlist, pkey):
|
||||
"""
|
||||
This handles both remote and local files.
|
||||
Returns an updated ls_playlist string.
|
||||
"""
|
||||
ls_playlist = []
|
||||
|
||||
logger = logging.getLogger()
|
||||
logger = logging.getLogger('fetch')
|
||||
for media in playlist['medias']:
|
||||
logger.debug("Processing track %s", media['uri'])
|
||||
|
||||
fileExt = os.path.splitext(media['uri'])[1]
|
||||
try:
|
||||
if str(media['cue_in']) == '0' and str(media['cue_out']) == '0':
|
||||
logger.debug('No cue in/out detected for this file')
|
||||
#logger.debug('No cue in/out detected for this file')
|
||||
dst = "%s%s/%s%s" % (self.cache_dir, str(pkey), str(media['id']), str(fileExt))
|
||||
do_cue = False
|
||||
else:
|
||||
logger.debug('Cue in/out detected')
|
||||
#logger.debug('Cue in/out detected')
|
||||
dst = "%s%s/%s_cue_%s-%s%s" % \
|
||||
(self.cache_dir, str(pkey), str(media['id']), str(float(media['cue_in']) / 1000), str(float(media['cue_out']) / 1000), str(fileExt))
|
||||
do_cue = True
|
||||
|
@ -225,7 +228,7 @@ class PypoFetch:
|
|||
% (str(media['export_source']), media['id'], 0, str(float(media['fade_in']) / 1000), \
|
||||
str(float(media['fade_out']) / 1000), media['row_id'],dst)
|
||||
|
||||
logger.debug(pl_entry)
|
||||
#logger.debug(pl_entry)
|
||||
|
||||
"""
|
||||
Tracks are only added to the playlist if they are accessible
|
||||
|
@ -239,7 +242,7 @@ class PypoFetch:
|
|||
entry['show_name'] = playlist['show_name']
|
||||
ls_playlist.append(entry)
|
||||
|
||||
logger.debug("everything ok, adding %s to playlist", pl_entry)
|
||||
#logger.debug("everything ok, adding %s to playlist", pl_entry)
|
||||
else:
|
||||
print 'zero-file: ' + dst + ' from ' + media['uri']
|
||||
logger.warning("zero-size file - skipping %s. will not add it to playlist", dst)
|
||||
|
@ -251,11 +254,15 @@ class PypoFetch:
|
|||
return ls_playlist
|
||||
|
||||
|
||||
"""
|
||||
Download a file from a remote server and store it in the cache.
|
||||
"""
|
||||
def handle_remote_file(self, media, dst, do_cue):
|
||||
logger = logging.getLogger()
|
||||
logger = logging.getLogger('fetch')
|
||||
if do_cue == False:
|
||||
if os.path.isfile(dst):
|
||||
logger.debug("file already in cache: %s", dst)
|
||||
pass
|
||||
#logger.debug("file already in cache: %s", dst)
|
||||
else:
|
||||
logger.debug("try to download %s", media['uri'])
|
||||
self.api_client.get_media(media['uri'], dst)
|
||||
|
@ -296,12 +303,12 @@ class PypoFetch:
|
|||
logger.error("%s", e)
|
||||
|
||||
|
||||
"""
|
||||
Cleans up folders in cache_dir. Look for modification date older than "now - CACHE_FOR"
|
||||
and deletes them.
|
||||
"""
|
||||
def cleanup(self, export_source):
|
||||
"""
|
||||
Cleans up folders in cache_dir. Look for modification date older than "now - CACHE_FOR"
|
||||
and deletes them.
|
||||
"""
|
||||
logger = logging.getLogger()
|
||||
logger = logging.getLogger('fetch')
|
||||
|
||||
offset = 3600 * int(config["cache_for"])
|
||||
now = time.time()
|
||||
|
@ -323,3 +330,41 @@ class PypoFetch:
|
|||
print e
|
||||
logger.error("%s", e)
|
||||
|
||||
|
||||
"""
|
||||
Main loop of the thread:
|
||||
Wait for schedule updates from RabbitMQ, but in case there arent any,
|
||||
poll the server to get the upcoming schedule.
|
||||
"""
|
||||
def run(self):
|
||||
logger = logging.getLogger('fetch')
|
||||
|
||||
try: os.mkdir(self.cache_dir)
|
||||
except Exception, e: pass
|
||||
|
||||
# Bootstrap: since we are just starting up, we need to grab the
|
||||
# most recent schedule. After that we can just wait for updates.
|
||||
status, schedule_data = self.api_client.get_schedule()
|
||||
if status == 1:
|
||||
self.process_schedule(schedule_data, "scheduler")
|
||||
logger.info("Bootstrap complete: got initial copy of the schedule")
|
||||
|
||||
loops = 1
|
||||
while True:
|
||||
logger.info("Loop #"+str(loops))
|
||||
try:
|
||||
# Wait for messages from RabbitMQ. Timeout if we
|
||||
# dont get any after POLL_INTERVAL.
|
||||
self.connection.drain_events(timeout=POLL_INTERVAL)
|
||||
# Hooray for globals!
|
||||
schedule_data = SCHEDULE_PUSH_MSG
|
||||
status = 1
|
||||
except:
|
||||
# We didnt get a message for a while, so poll the server
|
||||
# to get an updated schedule.
|
||||
status, schedule_data = self.api_client.get_schedule()
|
||||
|
||||
if status == 1:
|
||||
self.process_schedule(schedule_data, "scheduler")
|
||||
loops += 1
|
||||
|
|
@ -7,29 +7,38 @@ import pickle
|
|||
import telnetlib
|
||||
import calendar
|
||||
import json
|
||||
import math
|
||||
from threading import Thread
|
||||
|
||||
from api_clients import api_client
|
||||
from util import CueFile
|
||||
|
||||
from configobj import ConfigObj
|
||||
|
||||
# configure logging
|
||||
logging.config.fileConfig("logging.cfg")
|
||||
|
||||
# loading config file
|
||||
try:
|
||||
config = ConfigObj('config.cfg')
|
||||
POLL_INTERVAL = float(config['poll_interval'])
|
||||
PUSH_INTERVAL = 0.5
|
||||
#PUSH_INTERVAL = float(config['push_interval'])
|
||||
LS_HOST = config['ls_host']
|
||||
LS_PORT = config['ls_port']
|
||||
PUSH_INTERVAL = 2
|
||||
except Exception, e:
|
||||
print 'Error loading config file: ', e
|
||||
logger.error('Error loading config file %s', e)
|
||||
sys.exit()
|
||||
|
||||
class PypoPush:
|
||||
def __init__(self):
|
||||
class PypoPush(Thread):
|
||||
def __init__(self, q):
|
||||
Thread.__init__(self)
|
||||
self.api_client = api_client.api_client_factory(config)
|
||||
self.cue_file = CueFile()
|
||||
self.set_export_source('scheduler')
|
||||
self.queue = q
|
||||
|
||||
self.schedule = dict()
|
||||
self.playlists = dict()
|
||||
self.stream_metadata = dict()
|
||||
|
||||
"""
|
||||
push_ahead2 MUST be < push_ahead. The difference in these two values
|
||||
|
@ -42,51 +51,58 @@ class PypoPush:
|
|||
def set_export_source(self, export_source):
|
||||
self.export_source = export_source
|
||||
self.cache_dir = config["cache_dir"] + self.export_source + '/'
|
||||
self.schedule_file = self.cache_dir + 'schedule.pickle'
|
||||
self.schedule_tracker_file = self.cache_dir + "schedule_tracker.pickle"
|
||||
|
||||
"""
|
||||
The Push Loop - the push loop periodically (minimal 1/2 of the playlist-grid)
|
||||
checks if there is a playlist that should be scheduled at the current time.
|
||||
If yes, the temporary liquidsoap playlist gets replaced with the corresponding one,
|
||||
The Push Loop - the push loop periodically checks if there is a playlist
|
||||
that should be scheduled at the current time.
|
||||
If yes, the current liquidsoap playlist gets replaced with the corresponding one,
|
||||
then liquidsoap is asked (via telnet) to reload and immediately play it.
|
||||
"""
|
||||
def push(self, export_source):
|
||||
logger = logging.getLogger()
|
||||
logger = logging.getLogger('push')
|
||||
|
||||
self.schedule = self.load_schedule()
|
||||
playedItems = self.load_schedule_tracker()
|
||||
# get a new schedule from pypo-fetch
|
||||
if not self.queue.empty():
|
||||
scheduled_data = self.queue.get()
|
||||
logger.debug("Received data from pypo-fetch")
|
||||
self.schedule = scheduled_data['schedule']
|
||||
self.playlists = scheduled_data['playlists']
|
||||
self.stream_metadata = scheduled_data['stream_metadata']
|
||||
|
||||
tcoming = time.localtime(time.time() + self.push_ahead)
|
||||
tcoming2 = time.localtime(time.time() + self.push_ahead2)
|
||||
schedule = self.schedule
|
||||
playlists = self.playlists
|
||||
|
||||
|
||||
str_tcoming_s = "%04d-%02d-%02d-%02d-%02d-%02d" % (tcoming[0], tcoming[1], tcoming[2], tcoming[3], tcoming[4], tcoming[5])
|
||||
str_tcoming2_s = "%04d-%02d-%02d-%02d-%02d-%02d" % (tcoming2[0], tcoming2[1], tcoming2[2], tcoming2[3], tcoming2[4], tcoming2[5])
|
||||
|
||||
currently_on_air = False
|
||||
if self.schedule == None:
|
||||
logger.warn('Unable to loop schedule - maybe write in progress?')
|
||||
logger.warn('Will try again in next loop.')
|
||||
if schedule:
|
||||
playedItems = self.load_schedule_tracker()
|
||||
|
||||
else:
|
||||
for pkey in self.schedule:
|
||||
timenow = time.time()
|
||||
tcoming = time.localtime(timenow + self.push_ahead)
|
||||
str_tcoming_s = "%04d-%02d-%02d-%02d-%02d-%02d" % (tcoming[0], tcoming[1], tcoming[2], tcoming[3], tcoming[4], tcoming[5])
|
||||
|
||||
tcoming2 = time.localtime(timenow + self.push_ahead2)
|
||||
str_tcoming2_s = "%04d-%02d-%02d-%02d-%02d-%02d" % (tcoming2[0], tcoming2[1], tcoming2[2], tcoming2[3], tcoming2[4], tcoming2[5])
|
||||
|
||||
tnow = time.localtime(timenow)
|
||||
str_tnow_s = "%04d-%02d-%02d-%02d-%02d-%02d" % (tnow[0], tnow[1], tnow[2], tnow[3], tnow[4], tnow[5])
|
||||
|
||||
for pkey in schedule:
|
||||
plstart = pkey[0:19]
|
||||
start = self.schedule[pkey]['start']
|
||||
end = self.schedule[pkey]['end']
|
||||
start = schedule[pkey]['start']
|
||||
end = schedule[pkey]['end']
|
||||
|
||||
playedFlag = (pkey in playedItems) and playedItems[pkey].get("played", 0)
|
||||
|
||||
if plstart == str_tcoming_s or (plstart < str_tcoming_s and plstart > str_tcoming2_s and not playedFlag):
|
||||
logger.debug('Preparing to push playlist scheduled at: %s', pkey)
|
||||
playlist = self.schedule[pkey]
|
||||
playlist = schedule[pkey]
|
||||
|
||||
ptype = playlist['subtype']
|
||||
currently_on_air = True
|
||||
|
||||
# We have a match, replace the current playlist and
|
||||
# force liquidsoap to refresh.
|
||||
if (self.push_liquidsoap(pkey, self.schedule, ptype) == 1):
|
||||
if (self.push_liquidsoap(pkey, schedule, playlists) == 1):
|
||||
logger.debug("Pushed to liquidsoap, updating 'played' status.")
|
||||
# Marked the current playlist as 'played' in the schedule tracker
|
||||
# so it is not called again in the next push loop.
|
||||
|
@ -100,39 +116,28 @@ class PypoPush:
|
|||
|
||||
# Call API to update schedule states
|
||||
logger.debug("Doing callback to server to update 'played' status.")
|
||||
self.api_client.notify_scheduled_item_start_playing(pkey, self.schedule)
|
||||
|
||||
if self.schedule != None:
|
||||
tnow = time.localtime(time.time())
|
||||
str_tnow_s = "%04d-%02d-%02d-%02d-%02d-%02d" % (tnow[0], tnow[1], tnow[2], tnow[3], tnow[4], tnow[5])
|
||||
for pkey in self.schedule:
|
||||
start = self.schedule[pkey]['start']
|
||||
end = self.schedule[pkey]['end']
|
||||
self.api_client.notify_scheduled_item_start_playing(pkey, schedule)
|
||||
|
||||
start = schedule[pkey]['start']
|
||||
end = schedule[pkey]['end']
|
||||
|
||||
if start <= str_tnow_s and str_tnow_s < end:
|
||||
currently_on_air = True
|
||||
|
||||
else:
|
||||
pass
|
||||
#logger.debug('Empty schedule')
|
||||
|
||||
if not currently_on_air:
|
||||
tn = telnetlib.Telnet(LS_HOST, LS_PORT)
|
||||
tn.write('source.skip\n'.encode('latin-1'))
|
||||
tn.write('source.skip\n')
|
||||
tn.write('exit\n')
|
||||
tn.read_all()
|
||||
#logger.info('source.skip')
|
||||
#logger.debug(tn.read_all())
|
||||
|
||||
def push_liquidsoap(self, pkey, schedule, ptype):
|
||||
logger = logging.getLogger()
|
||||
src = self.cache_dir + str(pkey) + '/list.lsp'
|
||||
def push_liquidsoap(self, pkey, schedule, playlists):
|
||||
logger = logging.getLogger('push')
|
||||
|
||||
try:
|
||||
if True == os.access(src, os.R_OK):
|
||||
logger.debug('OK - Can read playlist file')
|
||||
|
||||
pl_file = open(src, "r")
|
||||
file_content = pl_file.read()
|
||||
pl_file.close()
|
||||
logger.debug('file content: %s' % (file_content))
|
||||
playlist = json.loads(file_content)
|
||||
playlist = playlists[pkey]
|
||||
|
||||
#strptime returns struct_time in local time
|
||||
#mktime takes a time_struct and returns a floating point
|
||||
|
@ -180,43 +185,24 @@ class PypoPush:
|
|||
except Exception, e:
|
||||
logger.error('%s', e)
|
||||
status = 0
|
||||
|
||||
return status
|
||||
|
||||
|
||||
def load_schedule(self):
|
||||
logger = logging.getLogger()
|
||||
schedule = None
|
||||
|
||||
# create the file if it doesnt exist
|
||||
if (not os.path.exists(self.schedule_file)):
|
||||
logger.debug('creating file ' + self.schedule_file)
|
||||
open(self.schedule_file, 'w').close()
|
||||
else:
|
||||
# load the schedule from cache
|
||||
#logger.debug('loading schedule file '+self.schedule_file)
|
||||
try:
|
||||
schedule_file = open(self.schedule_file, "r")
|
||||
schedule = pickle.load(schedule_file)
|
||||
schedule_file.close()
|
||||
|
||||
except Exception, e:
|
||||
logger.error('%s', e)
|
||||
|
||||
return schedule
|
||||
|
||||
|
||||
def load_schedule_tracker(self):
|
||||
logger = logging.getLogger()
|
||||
logger = logging.getLogger('push')
|
||||
#logger.debug('load_schedule_tracker')
|
||||
playedItems = dict()
|
||||
|
||||
# create the file if it doesnt exist
|
||||
if (not os.path.exists(self.schedule_tracker_file)):
|
||||
logger.debug('creating file ' + self.schedule_tracker_file)
|
||||
schedule_tracker = open(self.schedule_tracker_file, 'w')
|
||||
pickle.dump(playedItems, schedule_tracker)
|
||||
schedule_tracker.close()
|
||||
try:
|
||||
logger.debug('creating file ' + self.schedule_tracker_file)
|
||||
schedule_tracker = open(self.schedule_tracker_file, 'w')
|
||||
pickle.dump(playedItems, schedule_tracker)
|
||||
schedule_tracker.close()
|
||||
except Exception, e:
|
||||
logger.error('Error creating schedule tracker file: %s', e)
|
||||
else:
|
||||
#logger.debug('schedule tracker file exists, opening: ' + self.schedule_tracker_file)
|
||||
try:
|
||||
schedule_tracker = open(self.schedule_tracker_file, "r")
|
||||
playedItems = pickle.load(schedule_tracker)
|
||||
|
@ -226,3 +212,18 @@ class PypoPush:
|
|||
|
||||
return playedItems
|
||||
|
||||
def run(self):
|
||||
loops = 0
|
||||
heartbeat_period = math.floor(30/PUSH_INTERVAL)
|
||||
logger = logging.getLogger('push')
|
||||
|
||||
while True:
|
||||
if loops % heartbeat_period == 0:
|
||||
logger.info("heartbeat")
|
||||
loops = 0
|
||||
try: self.push('scheduler')
|
||||
except Exception, e:
|
||||
logger.error('Pypo Push Error, exiting: %s', e)
|
||||
sys.exit()
|
||||
time.sleep(PUSH_INTERVAL)
|
||||
loops += 1
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue