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

This commit is contained in:
Daniel 2012-03-05 10:59:43 -05:00
commit 228a9787a8
23 changed files with 399 additions and 169 deletions

View File

@ -37,7 +37,7 @@ Zend_Validate::setDefaultNamespaces("Zend");
$front = Zend_Controller_Front::getInstance();
$front->registerPlugin(new RabbitMqPlugin());
Logging::debug($_SERVER['REQUEST_URI']);
//Logging::debug($_SERVER['REQUEST_URI']);
/* The bootstrap class should only be used to initialize actions that return a view.
Actions that return JSON will not use the bootstrap class! */

View File

@ -54,28 +54,27 @@ $pages = array(
'controller' => 'Preference'
),
array(
'label' => 'Manage Users',
'label' => 'Users',
'module' => 'default',
'controller' => 'user',
'action' => 'add-user',
'resource' => 'user'
),
array(
'label' => 'Manage Media Folders',
'label' => 'Media Folders',
'module' => 'default',
'controller' => 'Preference',
'action' => 'directory-config',
'id' => 'manage_folder'
),
array(
'label' => 'Stream Settings',
'label' => 'Streams',
'module' => 'default',
'controller' => 'Preference',
'action' => 'stream-setting'
),
array(
'label' =>
Application_Model_Preference::GetPlanLevel() == 'disabled'?'Support Settings':'Station Information Settings',
'label' => 'Support Feedback',
'module' => 'default',
'controller' => 'Preference',
'action' => 'support-setting'

View File

@ -277,14 +277,12 @@ class ApiController extends Zend_Controller_Action
$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;
}
* */
PEAR::setErrorHandling(PEAR_ERROR_RETURN);

View File

@ -111,7 +111,7 @@ class PreferenceController extends Zend_Controller_Action
$privacyChecked = true;
}
$this->view->privacyChecked = $privacyChecked;
$this->view->section_title = Application_Model_Preference::GetPlanLevel() == 'disabled'?'Support Settings':'Station Information Settings';
$this->view->section_title = 'Support Feedback';
$this->view->form = $form;
//$form->render($this->view);
}

View File

@ -20,8 +20,7 @@
</div>
<div class="wrapper">
<!--Set to z-index 254 to make it lower than the top-panel and the ZFDebug info bar, but higher than the side-playlist-->
<div id="library_content" class="tabs ui-widget ui-widget-content block-shadow alpha-block padded" style="z-index:254"><?php echo $this->layout()->library ?></div>
<div id="library_content" class="tabs ui-widget ui-widget-content block-shadow alpha-block padded" style="display:none"><?php echo $this->layout()->library ?></div>
<div id="show_builder" class="ui-widget ui-widget-content block-shadow omega-block padded"><?php echo $this->layout()->builder ?></div>
</div>
</body>

View File

@ -222,7 +222,7 @@ class Application_Model_Schedule {
* @return array $scheduledItems
*
*/
public static function GetScheduleDetailItems($p_startDateTime, $p_endDateTime, $p_shows)
public static function GetScheduleDetailItems($p_start, $p_end, $p_shows)
{
global $CC_CONFIG, $CC_DBC;
@ -237,7 +237,7 @@ class Application_Model_Schedule {
sched.starts AS sched_starts, sched.ends AS sched_ends, sched.id AS sched_id,
sched.cue_in AS cue_in, sched.cue_out AS cue_out,
sched.fade_in AS fade_in, sched.fade_out AS fade_out,
sched.status AS sched_status,
sched.playout_status AS playout_status,
ft.track_title AS file_track_title, ft.artist_name AS file_artist_name,
ft.album_title AS file_album_title, ft.length AS file_length
@ -250,8 +250,11 @@ class Application_Model_Schedule {
WHERE si.modified_instance = false AND
si.starts >= '{$p_startDateTime}' AND si.starts < '{$p_endDateTime}'";
((si.starts >= '{$p_start}' AND si.starts < '{$p_end}')
OR (si.ends > '{$p_start}' AND si.ends <= '{$p_end}')
OR (si.starts <= '{$p_start}' AND si.ends >= '{$p_end}'))";
if (count($p_shows) > 0) {
$sql .= " AND show_id IN (".implode(",", $p_shows).")";
}
@ -421,30 +424,52 @@ class Application_Model_Schedule {
*/
public static function GetItems($p_currentDateTime, $p_toDateTime) {
global $CC_CONFIG, $CC_DBC;
$rows = array();
$baseQuery = "SELECT st.file_id AS file_id,"
." st.id as id,"
." st.starts AS start,"
." st.ends AS end,"
." st.cue_in AS cue_in,"
." st.cue_out AS cue_out,"
." st.fade_in AS fade_in,"
." st.fade_out AS fade_out,"
." si.starts as show_start,"
." si.ends as show_end"
." FROM $CC_CONFIG[scheduleTable] as st"
." LEFT JOIN $CC_CONFIG[showInstances] as si"
." ON st.instance_id = si.id";
$sql = "SELECT st.file_id AS file_id,"
." st.id as id,"
." st.starts AS start,"
." st.ends AS end,"
." st.cue_in AS cue_in,"
." st.cue_out AS cue_out,"
." st.fade_in AS fade_in,"
." st.fade_out AS fade_out,"
." si.starts as show_start,"
." si.ends as show_end"
." FROM $CC_CONFIG[scheduleTable] as st"
." LEFT JOIN $CC_CONFIG[showInstances] as si"
." ON st.instance_id = si.id"
." ORDER BY start";
Logging::log($sql);
$predicates = " WHERE st.ends > '$p_currentDateTime'"
." AND st.starts < '$p_toDateTime'"
." ORDER BY st.starts";
$sql = $baseQuery.$predicates;
$rows = $CC_DBC->GetAll($sql);
if (PEAR::isError($rows)) {
return null;
}
if (count($rows) < 3){
Logging::debug("Get Schedule: Less than 3 results returned. Doing another query since we need a minimum of 3 results.");
$dt = new DateTime("@".time());
$dt->add(new DateInterval("PT30M"));
$range_end = $dt->format("Y-m-d H:i:s");
$predicates = " WHERE st.ends > '$p_currentDateTime'"
." AND st.starts < '$range_end'"
." ORDER BY st.starts"
." LIMIT 3";
$sql = $baseQuery.$predicates;
$rows = $CC_DBC->GetAll($sql);
if (PEAR::isError($rows)) {
return null;
}
}
return $rows;
}
@ -462,7 +487,7 @@ class Application_Model_Schedule {
}
if (is_null($p_fromDateTime)) {
$t2 = new DateTime("@".time());
$t2->add(new DateInterval("PT24H"));
$t2->add(new DateInterval("PT30M"));
$range_end = $t2->format("Y-m-d H:i:s");
} else {
$range_end = Application_Model_Schedule::PypoTimeToAirtimeTime($p_toDateTime);
@ -480,8 +505,8 @@ class Application_Model_Schedule {
foreach ($items as $item){
$storedFile = Application_Model_StoredFile::Recall($item["file_id"]);
$uri = $storedFile->getFileUrlUsingConfigAddress();
$uri = $storedFile->getFilePath();
$showEndDateTime = new DateTime($item["show_end"], $utcTimeZone);
$trackEndDateTime = new DateTime($item["end"], $utcTimeZone);

View File

@ -58,9 +58,14 @@ class Application_Model_ShowBuilder {
}
$showStartDT = new DateTime($p_item["si_starts"], new DateTimeZone("UTC"));
$schedStartDT = new DateTime($p_item["sched_starts"], new DateTimeZone("UTC"));
$showStartEpoch = intval($showStartDT->format('U'));
$schedStartEpoch = intval($schedStartDT->format('U'));
//can only schedule the show if it hasn't started and you are allowed.
if ($this->epoch_now < $showStartDT->format('U') && $this->user->canSchedule($p_item["show_id"]) == true) {
//can only schedule the show if item hasn't started and you are allowed.
if ($this->epoch_now < max($showStartEpoch, $schedStartEpoch)
&& $this->user->canSchedule($p_item["show_id"]) == true) {
$row["allowed"] = true;
}
}
@ -68,7 +73,7 @@ class Application_Model_ShowBuilder {
//information about whether a track is inside|boundary|outside a show.
private function getItemStatus($p_item, &$row) {
$row["status"] = intval($p_item["sched_status"]);
$row["status"] = intval($p_item["playout_status"]);
}
private function getRowTimestamp($p_item, &$row) {
@ -83,14 +88,13 @@ class Application_Model_ShowBuilder {
$row["timestamp"] = $ts;
}
private function isCurrent($p_epochItemStart, $p_epochItemEnd) {
$current = false;
private function isCurrent($p_epochItemStart, $p_epochItemEnd, &$row) {
if ($this->epoch_now >= $p_epochItemStart && $this->epoch_now < $p_epochItemEnd) {
$current = true;
$row["current"] = true;
//how many seconds the view should wait to redraw itself.
$row["refresh"] = $p_epochItemEnd - $this->epoch_now;
}
return $current;
}
private function makeHeaderRow($p_item) {
@ -138,9 +142,7 @@ class Application_Model_ShowBuilder {
$showEndEpoch = intval($showEndDT->format("U"));
//don't want an overbooked item to stay marked as current.
if ($this->isCurrent($startsEpoch, min($endsEpoch, $showEndEpoch))) {
$row["current"] = true;
}
$this->isCurrent($startsEpoch, min($endsEpoch, $showEndEpoch), $row);
$row["id"] = intval($p_item["sched_id"]);
$row["instance"] = intval($p_item["si_id"]);

View File

@ -117,7 +117,7 @@ class CcShowInstances extends BaseCcShowInstances {
CcScheduleQuery::create()
->filterByDbInstanceId($this->id)
->filterByDbEnds($this->ends, Criteria::LESS_EQUAL)
->update(array('DbStatus' => 1), $con);
->update(array('DbPlayoutStatus' => 1), $con);
Logging::log("updating status for in show items.");
@ -126,13 +126,13 @@ class CcShowInstances extends BaseCcShowInstances {
->filterByDbInstanceId($this->id)
->filterByDbStarts($this->ends, Criteria::LESS_THAN)
->filterByDbEnds($this->ends, Criteria::GREATER_THAN)
->update(array('DbStatus' => 2), $con);
->update(array('DbPlayoutStatus' => 2), $con);
//scheduled track is overbooked.
CcScheduleQuery::create()
->filterByDbInstanceId($this->id)
->filterByDbStarts($this->ends, Criteria::GREATER_THAN)
->update(array('DbStatus' => 0), $con);
->update(array('DbPlayoutStatus' => 0), $con);
}

View File

@ -49,7 +49,7 @@ class CcScheduleTableMap extends TableMap {
$this->addColumn('CUE_OUT', 'DbCueOut', 'VARCHAR', false, null, '00:00:00');
$this->addColumn('MEDIA_ITEM_PLAYED', 'DbMediaItemPlayed', 'BOOLEAN', false, null, false);
$this->addForeignKey('INSTANCE_ID', 'DbInstanceId', 'INTEGER', 'cc_show_instances', 'ID', true, null, null);
$this->addColumn('STATUS', 'DbStatus', 'SMALLINT', true, null, 1);
$this->addColumn('PLAYOUT_STATUS', 'DbPlayoutStatus', 'SMALLINT', true, null, 1);
// validators
} // initialize()

View File

@ -97,11 +97,11 @@ abstract class BaseCcSchedule extends BaseObject implements Persistent
protected $instance_id;
/**
* The value for the status field.
* The value for the playout_status field.
* Note: this column has a database default value of: 1
* @var int
*/
protected $status;
protected $playout_status;
/**
* @var CcShowInstances
@ -144,7 +144,7 @@ abstract class BaseCcSchedule extends BaseObject implements Persistent
$this->cue_in = '00:00:00';
$this->cue_out = '00:00:00';
$this->media_item_played = false;
$this->status = 1;
$this->playout_status = 1;
}
/**
@ -360,13 +360,13 @@ abstract class BaseCcSchedule extends BaseObject implements Persistent
}
/**
* Get the [status] column value.
* Get the [playout_status] column value.
*
* @return int
*/
public function getDbStatus()
public function getDbPlayoutStatus()
{
return $this->status;
return $this->playout_status;
}
/**
@ -716,24 +716,24 @@ abstract class BaseCcSchedule extends BaseObject implements Persistent
} // setDbInstanceId()
/**
* Set the value of [status] column.
* Set the value of [playout_status] column.
*
* @param int $v new value
* @return CcSchedule The current object (for fluent API support)
*/
public function setDbStatus($v)
public function setDbPlayoutStatus($v)
{
if ($v !== null) {
$v = (int) $v;
}
if ($this->status !== $v || $this->isNew()) {
$this->status = $v;
$this->modifiedColumns[] = CcSchedulePeer::STATUS;
if ($this->playout_status !== $v || $this->isNew()) {
$this->playout_status = $v;
$this->modifiedColumns[] = CcSchedulePeer::PLAYOUT_STATUS;
}
return $this;
} // setDbStatus()
} // setDbPlayoutStatus()
/**
* Indicates whether the columns in this object are only set to default values.
@ -769,7 +769,7 @@ abstract class BaseCcSchedule extends BaseObject implements Persistent
return false;
}
if ($this->status !== 1) {
if ($this->playout_status !== 1) {
return false;
}
@ -806,7 +806,7 @@ abstract class BaseCcSchedule extends BaseObject implements Persistent
$this->cue_out = ($row[$startcol + 8] !== null) ? (string) $row[$startcol + 8] : null;
$this->media_item_played = ($row[$startcol + 9] !== null) ? (boolean) $row[$startcol + 9] : null;
$this->instance_id = ($row[$startcol + 10] !== null) ? (int) $row[$startcol + 10] : null;
$this->status = ($row[$startcol + 11] !== null) ? (int) $row[$startcol + 11] : null;
$this->playout_status = ($row[$startcol + 11] !== null) ? (int) $row[$startcol + 11] : null;
$this->resetModified();
$this->setNew(false);
@ -1195,7 +1195,7 @@ abstract class BaseCcSchedule extends BaseObject implements Persistent
return $this->getDbInstanceId();
break;
case 11:
return $this->getDbStatus();
return $this->getDbPlayoutStatus();
break;
default:
return null;
@ -1232,7 +1232,7 @@ abstract class BaseCcSchedule extends BaseObject implements Persistent
$keys[8] => $this->getDbCueOut(),
$keys[9] => $this->getDbMediaItemPlayed(),
$keys[10] => $this->getDbInstanceId(),
$keys[11] => $this->getDbStatus(),
$keys[11] => $this->getDbPlayoutStatus(),
);
if ($includeForeignObjects) {
if (null !== $this->aCcShowInstances) {
@ -1306,7 +1306,7 @@ abstract class BaseCcSchedule extends BaseObject implements Persistent
$this->setDbInstanceId($value);
break;
case 11:
$this->setDbStatus($value);
$this->setDbPlayoutStatus($value);
break;
} // switch()
}
@ -1343,7 +1343,7 @@ abstract class BaseCcSchedule extends BaseObject implements Persistent
if (array_key_exists($keys[8], $arr)) $this->setDbCueOut($arr[$keys[8]]);
if (array_key_exists($keys[9], $arr)) $this->setDbMediaItemPlayed($arr[$keys[9]]);
if (array_key_exists($keys[10], $arr)) $this->setDbInstanceId($arr[$keys[10]]);
if (array_key_exists($keys[11], $arr)) $this->setDbStatus($arr[$keys[11]]);
if (array_key_exists($keys[11], $arr)) $this->setDbPlayoutStatus($arr[$keys[11]]);
}
/**
@ -1366,7 +1366,7 @@ abstract class BaseCcSchedule extends BaseObject implements Persistent
if ($this->isColumnModified(CcSchedulePeer::CUE_OUT)) $criteria->add(CcSchedulePeer::CUE_OUT, $this->cue_out);
if ($this->isColumnModified(CcSchedulePeer::MEDIA_ITEM_PLAYED)) $criteria->add(CcSchedulePeer::MEDIA_ITEM_PLAYED, $this->media_item_played);
if ($this->isColumnModified(CcSchedulePeer::INSTANCE_ID)) $criteria->add(CcSchedulePeer::INSTANCE_ID, $this->instance_id);
if ($this->isColumnModified(CcSchedulePeer::STATUS)) $criteria->add(CcSchedulePeer::STATUS, $this->status);
if ($this->isColumnModified(CcSchedulePeer::PLAYOUT_STATUS)) $criteria->add(CcSchedulePeer::PLAYOUT_STATUS, $this->playout_status);
return $criteria;
}
@ -1438,7 +1438,7 @@ abstract class BaseCcSchedule extends BaseObject implements Persistent
$copyObj->setDbCueOut($this->cue_out);
$copyObj->setDbMediaItemPlayed($this->media_item_played);
$copyObj->setDbInstanceId($this->instance_id);
$copyObj->setDbStatus($this->status);
$copyObj->setDbPlayoutStatus($this->playout_status);
$copyObj->setNew(true);
$copyObj->setDbId(NULL); // this is a auto-increment column, so set to default value
@ -1600,7 +1600,7 @@ abstract class BaseCcSchedule extends BaseObject implements Persistent
$this->cue_out = null;
$this->media_item_played = null;
$this->instance_id = null;
$this->status = null;
$this->playout_status = null;
$this->alreadyInSave = false;
$this->alreadyInValidation = false;
$this->clearAllReferences();

View File

@ -64,8 +64,8 @@ abstract class BaseCcSchedulePeer {
/** the column name for the INSTANCE_ID field */
const INSTANCE_ID = 'cc_schedule.INSTANCE_ID';
/** the column name for the STATUS field */
const STATUS = 'cc_schedule.STATUS';
/** the column name for the PLAYOUT_STATUS field */
const PLAYOUT_STATUS = 'cc_schedule.PLAYOUT_STATUS';
/**
* An identiy map to hold any loaded instances of CcSchedule objects.
@ -83,11 +83,11 @@ abstract class BaseCcSchedulePeer {
* e.g. self::$fieldNames[self::TYPE_PHPNAME][0] = 'Id'
*/
private static $fieldNames = array (
BasePeer::TYPE_PHPNAME => array ('DbId', 'DbStarts', 'DbEnds', 'DbFileId', 'DbClipLength', 'DbFadeIn', 'DbFadeOut', 'DbCueIn', 'DbCueOut', 'DbMediaItemPlayed', 'DbInstanceId', 'DbStatus', ),
BasePeer::TYPE_STUDLYPHPNAME => array ('dbId', 'dbStarts', 'dbEnds', 'dbFileId', 'dbClipLength', 'dbFadeIn', 'dbFadeOut', 'dbCueIn', 'dbCueOut', 'dbMediaItemPlayed', 'dbInstanceId', 'dbStatus', ),
BasePeer::TYPE_COLNAME => array (self::ID, self::STARTS, self::ENDS, self::FILE_ID, self::CLIP_LENGTH, self::FADE_IN, self::FADE_OUT, self::CUE_IN, self::CUE_OUT, self::MEDIA_ITEM_PLAYED, self::INSTANCE_ID, self::STATUS, ),
BasePeer::TYPE_RAW_COLNAME => array ('ID', 'STARTS', 'ENDS', 'FILE_ID', 'CLIP_LENGTH', 'FADE_IN', 'FADE_OUT', 'CUE_IN', 'CUE_OUT', 'MEDIA_ITEM_PLAYED', 'INSTANCE_ID', 'STATUS', ),
BasePeer::TYPE_FIELDNAME => array ('id', 'starts', 'ends', 'file_id', 'clip_length', 'fade_in', 'fade_out', 'cue_in', 'cue_out', 'media_item_played', 'instance_id', 'status', ),
BasePeer::TYPE_PHPNAME => array ('DbId', 'DbStarts', 'DbEnds', 'DbFileId', 'DbClipLength', 'DbFadeIn', 'DbFadeOut', 'DbCueIn', 'DbCueOut', 'DbMediaItemPlayed', 'DbInstanceId', 'DbPlayoutStatus', ),
BasePeer::TYPE_STUDLYPHPNAME => array ('dbId', 'dbStarts', 'dbEnds', 'dbFileId', 'dbClipLength', 'dbFadeIn', 'dbFadeOut', 'dbCueIn', 'dbCueOut', 'dbMediaItemPlayed', 'dbInstanceId', 'dbPlayoutStatus', ),
BasePeer::TYPE_COLNAME => array (self::ID, self::STARTS, self::ENDS, self::FILE_ID, self::CLIP_LENGTH, self::FADE_IN, self::FADE_OUT, self::CUE_IN, self::CUE_OUT, self::MEDIA_ITEM_PLAYED, self::INSTANCE_ID, self::PLAYOUT_STATUS, ),
BasePeer::TYPE_RAW_COLNAME => array ('ID', 'STARTS', 'ENDS', 'FILE_ID', 'CLIP_LENGTH', 'FADE_IN', 'FADE_OUT', 'CUE_IN', 'CUE_OUT', 'MEDIA_ITEM_PLAYED', 'INSTANCE_ID', 'PLAYOUT_STATUS', ),
BasePeer::TYPE_FIELDNAME => array ('id', 'starts', 'ends', 'file_id', 'clip_length', 'fade_in', 'fade_out', 'cue_in', 'cue_out', 'media_item_played', 'instance_id', 'playout_status', ),
BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, )
);
@ -98,11 +98,11 @@ abstract class BaseCcSchedulePeer {
* e.g. self::$fieldNames[BasePeer::TYPE_PHPNAME]['Id'] = 0
*/
private static $fieldKeys = array (
BasePeer::TYPE_PHPNAME => array ('DbId' => 0, 'DbStarts' => 1, 'DbEnds' => 2, 'DbFileId' => 3, 'DbClipLength' => 4, 'DbFadeIn' => 5, 'DbFadeOut' => 6, 'DbCueIn' => 7, 'DbCueOut' => 8, 'DbMediaItemPlayed' => 9, 'DbInstanceId' => 10, 'DbStatus' => 11, ),
BasePeer::TYPE_STUDLYPHPNAME => array ('dbId' => 0, 'dbStarts' => 1, 'dbEnds' => 2, 'dbFileId' => 3, 'dbClipLength' => 4, 'dbFadeIn' => 5, 'dbFadeOut' => 6, 'dbCueIn' => 7, 'dbCueOut' => 8, 'dbMediaItemPlayed' => 9, 'dbInstanceId' => 10, 'dbStatus' => 11, ),
BasePeer::TYPE_COLNAME => array (self::ID => 0, self::STARTS => 1, self::ENDS => 2, self::FILE_ID => 3, self::CLIP_LENGTH => 4, self::FADE_IN => 5, self::FADE_OUT => 6, self::CUE_IN => 7, self::CUE_OUT => 8, self::MEDIA_ITEM_PLAYED => 9, self::INSTANCE_ID => 10, self::STATUS => 11, ),
BasePeer::TYPE_RAW_COLNAME => array ('ID' => 0, 'STARTS' => 1, 'ENDS' => 2, 'FILE_ID' => 3, 'CLIP_LENGTH' => 4, 'FADE_IN' => 5, 'FADE_OUT' => 6, 'CUE_IN' => 7, 'CUE_OUT' => 8, 'MEDIA_ITEM_PLAYED' => 9, 'INSTANCE_ID' => 10, 'STATUS' => 11, ),
BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'starts' => 1, 'ends' => 2, 'file_id' => 3, 'clip_length' => 4, 'fade_in' => 5, 'fade_out' => 6, 'cue_in' => 7, 'cue_out' => 8, 'media_item_played' => 9, 'instance_id' => 10, 'status' => 11, ),
BasePeer::TYPE_PHPNAME => array ('DbId' => 0, 'DbStarts' => 1, 'DbEnds' => 2, 'DbFileId' => 3, 'DbClipLength' => 4, 'DbFadeIn' => 5, 'DbFadeOut' => 6, 'DbCueIn' => 7, 'DbCueOut' => 8, 'DbMediaItemPlayed' => 9, 'DbInstanceId' => 10, 'DbPlayoutStatus' => 11, ),
BasePeer::TYPE_STUDLYPHPNAME => array ('dbId' => 0, 'dbStarts' => 1, 'dbEnds' => 2, 'dbFileId' => 3, 'dbClipLength' => 4, 'dbFadeIn' => 5, 'dbFadeOut' => 6, 'dbCueIn' => 7, 'dbCueOut' => 8, 'dbMediaItemPlayed' => 9, 'dbInstanceId' => 10, 'dbPlayoutStatus' => 11, ),
BasePeer::TYPE_COLNAME => array (self::ID => 0, self::STARTS => 1, self::ENDS => 2, self::FILE_ID => 3, self::CLIP_LENGTH => 4, self::FADE_IN => 5, self::FADE_OUT => 6, self::CUE_IN => 7, self::CUE_OUT => 8, self::MEDIA_ITEM_PLAYED => 9, self::INSTANCE_ID => 10, self::PLAYOUT_STATUS => 11, ),
BasePeer::TYPE_RAW_COLNAME => array ('ID' => 0, 'STARTS' => 1, 'ENDS' => 2, 'FILE_ID' => 3, 'CLIP_LENGTH' => 4, 'FADE_IN' => 5, 'FADE_OUT' => 6, 'CUE_IN' => 7, 'CUE_OUT' => 8, 'MEDIA_ITEM_PLAYED' => 9, 'INSTANCE_ID' => 10, 'PLAYOUT_STATUS' => 11, ),
BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'starts' => 1, 'ends' => 2, 'file_id' => 3, 'clip_length' => 4, 'fade_in' => 5, 'fade_out' => 6, 'cue_in' => 7, 'cue_out' => 8, 'media_item_played' => 9, 'instance_id' => 10, 'playout_status' => 11, ),
BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, )
);
@ -186,7 +186,7 @@ abstract class BaseCcSchedulePeer {
$criteria->addSelectColumn(CcSchedulePeer::CUE_OUT);
$criteria->addSelectColumn(CcSchedulePeer::MEDIA_ITEM_PLAYED);
$criteria->addSelectColumn(CcSchedulePeer::INSTANCE_ID);
$criteria->addSelectColumn(CcSchedulePeer::STATUS);
$criteria->addSelectColumn(CcSchedulePeer::PLAYOUT_STATUS);
} else {
$criteria->addSelectColumn($alias . '.ID');
$criteria->addSelectColumn($alias . '.STARTS');
@ -199,7 +199,7 @@ abstract class BaseCcSchedulePeer {
$criteria->addSelectColumn($alias . '.CUE_OUT');
$criteria->addSelectColumn($alias . '.MEDIA_ITEM_PLAYED');
$criteria->addSelectColumn($alias . '.INSTANCE_ID');
$criteria->addSelectColumn($alias . '.STATUS');
$criteria->addSelectColumn($alias . '.PLAYOUT_STATUS');
}
}

View File

@ -17,7 +17,7 @@
* @method CcScheduleQuery orderByDbCueOut($order = Criteria::ASC) Order by the cue_out column
* @method CcScheduleQuery orderByDbMediaItemPlayed($order = Criteria::ASC) Order by the media_item_played column
* @method CcScheduleQuery orderByDbInstanceId($order = Criteria::ASC) Order by the instance_id column
* @method CcScheduleQuery orderByDbStatus($order = Criteria::ASC) Order by the status column
* @method CcScheduleQuery orderByDbPlayoutStatus($order = Criteria::ASC) Order by the playout_status column
*
* @method CcScheduleQuery groupByDbId() Group by the id column
* @method CcScheduleQuery groupByDbStarts() Group by the starts column
@ -30,7 +30,7 @@
* @method CcScheduleQuery groupByDbCueOut() Group by the cue_out column
* @method CcScheduleQuery groupByDbMediaItemPlayed() Group by the media_item_played column
* @method CcScheduleQuery groupByDbInstanceId() Group by the instance_id column
* @method CcScheduleQuery groupByDbStatus() Group by the status column
* @method CcScheduleQuery groupByDbPlayoutStatus() Group by the playout_status column
*
* @method CcScheduleQuery leftJoin($relation) Adds a LEFT JOIN clause to the query
* @method CcScheduleQuery rightJoin($relation) Adds a RIGHT JOIN clause to the query
@ -58,7 +58,7 @@
* @method CcSchedule findOneByDbCueOut(string $cue_out) Return the first CcSchedule filtered by the cue_out column
* @method CcSchedule findOneByDbMediaItemPlayed(boolean $media_item_played) Return the first CcSchedule filtered by the media_item_played column
* @method CcSchedule findOneByDbInstanceId(int $instance_id) Return the first CcSchedule filtered by the instance_id column
* @method CcSchedule findOneByDbStatus(int $status) Return the first CcSchedule filtered by the status column
* @method CcSchedule findOneByDbPlayoutStatus(int $playout_status) Return the first CcSchedule filtered by the playout_status column
*
* @method array findByDbId(int $id) Return CcSchedule objects filtered by the id column
* @method array findByDbStarts(string $starts) Return CcSchedule objects filtered by the starts column
@ -71,7 +71,7 @@
* @method array findByDbCueOut(string $cue_out) Return CcSchedule objects filtered by the cue_out column
* @method array findByDbMediaItemPlayed(boolean $media_item_played) Return CcSchedule objects filtered by the media_item_played column
* @method array findByDbInstanceId(int $instance_id) Return CcSchedule objects filtered by the instance_id column
* @method array findByDbStatus(int $status) Return CcSchedule objects filtered by the status column
* @method array findByDbPlayoutStatus(int $playout_status) Return CcSchedule objects filtered by the playout_status column
*
* @package propel.generator.airtime.om
*/
@ -468,24 +468,24 @@ abstract class BaseCcScheduleQuery extends ModelCriteria
}
/**
* Filter the query on the status column
* Filter the query on the playout_status column
*
* @param int|array $dbStatus The value to use as filter.
* @param int|array $dbPlayoutStatus The value to use as filter.
* Accepts an associative array('min' => $minValue, 'max' => $maxValue)
* @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL
*
* @return CcScheduleQuery The current query, for fluid interface
*/
public function filterByDbStatus($dbStatus = null, $comparison = null)
public function filterByDbPlayoutStatus($dbPlayoutStatus = null, $comparison = null)
{
if (is_array($dbStatus)) {
if (is_array($dbPlayoutStatus)) {
$useMinMax = false;
if (isset($dbStatus['min'])) {
$this->addUsingAlias(CcSchedulePeer::STATUS, $dbStatus['min'], Criteria::GREATER_EQUAL);
if (isset($dbPlayoutStatus['min'])) {
$this->addUsingAlias(CcSchedulePeer::PLAYOUT_STATUS, $dbPlayoutStatus['min'], Criteria::GREATER_EQUAL);
$useMinMax = true;
}
if (isset($dbStatus['max'])) {
$this->addUsingAlias(CcSchedulePeer::STATUS, $dbStatus['max'], Criteria::LESS_EQUAL);
if (isset($dbPlayoutStatus['max'])) {
$this->addUsingAlias(CcSchedulePeer::PLAYOUT_STATUS, $dbPlayoutStatus['max'], Criteria::LESS_EQUAL);
$useMinMax = true;
}
if ($useMinMax) {
@ -495,7 +495,7 @@ abstract class BaseCcScheduleQuery extends ModelCriteria
$comparison = Criteria::IN;
}
}
return $this->addUsingAlias(CcSchedulePeer::STATUS, $dbStatus, $comparison);
return $this->addUsingAlias(CcSchedulePeer::PLAYOUT_STATUS, $dbPlayoutStatus, $comparison);
}
/**

View File

@ -4,6 +4,7 @@
<?php echo $this->element->getElement('sb_date_end') ?>
<?php echo $this->element->getElement('sb_time_end') ?>
<input type="button" id="sb_submit" class="ui-button ui-state-default" value="GO"></input>
<input type="button" id="sb_edit" class="ui-button ui-state-default sb-edit" value="Add Files"></input>
</div>
<div class="sb-advanced-options">
<label><?php echo $this->element->getElement('sb_show_filter')->getLabel() ?></label>

View File

@ -280,7 +280,7 @@
<column name="cue_out" phpName="DbCueOut" type="VARCHAR" sqlType="interval" required="false" defaultValue="00:00:00"/>
<column name="media_item_played" phpName="DbMediaItemPlayed" type="BOOLEAN" required="false" defaultValue="0"/>
<column name="instance_id" phpName="DbInstanceId" type="INTEGER" required="true"/>
<column name="status" phpName="DbStatus" type="SMALLINT" required="true" defaultValue="1"/>
<column name="playout_status" phpName="DbPlayoutStatus" type="SMALLINT" required="true" defaultValue="1"/>
<!-- This foreign key is still useful even though it may seem we don't ever delete cc_show_instances anymore.
We will do delete them in some cases (when editing a show and changing the repeating days of the week
for example. \

View File

@ -371,7 +371,7 @@ CREATE TABLE "cc_schedule"
"cue_out" interval default '00:00:00',
"media_item_played" BOOLEAN default 'f',
"instance_id" INTEGER NOT NULL,
"status" INT2 default 1 NOT NULL,
"playout_status" INT2 default 1 NOT NULL,
PRIMARY KEY ("id")
);

View File

@ -1,7 +1,11 @@
@CHARSET "UTF-8";
#show_builder {
width:45%;
width:95%;
}
#show_builder_table th {
text-align: left;
}
#show_builder input.input_text {
@ -45,6 +49,10 @@ tr.cursor-selected-row .marker {
padding: 10px 0 0 0;
}
.ui-dialog #show_builder {
width:45%;
}
.ui-dialog .ui-buttonset {
margin-right: 0 !important;
}

View File

@ -267,27 +267,44 @@ var AIRTIME = (function(AIRTIME){
"fnDrawCallback": function(oSettings, json) {
var wrapperDiv,
markerDiv,
td;
td,
$lib = $("#library_content"),
tr;
//create cursor arrows.
tableDiv.find("tr:not(:first, .sb-footer, .sb-empty, .sb-not-allowed)").each(function(i, el) {
td = $(el).find("td:first");
if (td.hasClass("dataTables_empty")) {
return false;
}
wrapperDiv = $("<div />", {
"class": "innerWrapper",
"css": {
"height": td.height()
}
});
markerDiv = $("<div />", {
"class": "marker"
});
td.append(markerDiv).wrapInner(wrapperDiv);
});
//only create the cursor arrows if the library is on the page.
if ($lib.length > 0 && $lib.filter(":visible").length > 0) {
//create cursor arrows.
tableDiv.find("tr.sb-now-playing, tr:not(:first, .sb-footer, .sb-empty, .sb-not-allowed)").each(function(i, el) {
td = $(el).find("td:first");
if (td.hasClass("dataTables_empty")) {
return false;
}
wrapperDiv = $("<div />", {
"class": "innerWrapper",
"css": {
"height": td.height()
}
});
markerDiv = $("<div />", {
"class": "marker"
});
td.append(markerDiv).wrapInner(wrapperDiv);
});
}
//if the now playing song is visible set a timeout to redraw the table at the start of the next song.
tr = tableDiv.find("tr.sb-now-playing");
if (tr.length > 0) {
var oTable = $('#show_builder_table').dataTable(),
aData = tr.data("aData");
setTimeout(function(){
oTable.fnDraw();
}, aData.refresh * 1000); //need refresh in milliseconds
}
},
"fnHeaderCallback": function(nHead) {
$(nHead).find("input[type=checkbox]").attr("checked", false);
@ -429,7 +446,9 @@ var AIRTIME = (function(AIRTIME){
var prev = ui.item.prev();
//can't add items outside of shows.
if (!prev.hasClass("sb-allowed")) {
if (prev.hasClass("sb-footer")
|| prev.find("td:first").hasClass("dataTables_empty")
|| prev.length === 0) {
alert("Cannot schedule outside a show.");
ui.item.remove();
return;

View File

@ -6,12 +6,8 @@ $(document).ready(function(){
oBaseDatePickerSettings = {
dateFormat: 'yy-mm-dd',
onSelect: function(sDate, oDatePicker) {
var oDate,
dInput;
dInput = $(this);
oDate = dInput.datepicker( "setDate", sDate );
onSelect: function(sDate, oDatePicker) {
$(this).datepicker( "setDate", sDate );
}
};
@ -120,9 +116,44 @@ $(document).ready(function(){
oTable.fnDraw();
});
$("#sb_edit").click(function(ev){
var $button = $(this),
$lib = $("#library_content"),
$builder = $("#show_builder"),
oTable = $("#show_builder_table").dataTable();
if ($button.hasClass("sb-edit")) {
$lib.show();
$lib.width("45%");
$builder.width("50%");
$button.removeClass("sb-edit");
$button.addClass("sb-finish-edit");
$button.val("Close Library");
}
else if($button.hasClass("sb-finish-edit")) {
$lib.hide();
$builder.width("95%");
$button.removeClass("sb-finish-edit");
$button.addClass("sb-edit");
$button.val("Add Files");
}
oTable.fnDraw();
});
oRange = fnGetScheduleRange();
AIRTIME.showbuilder.fnServerData.start = oRange.start;
AIRTIME.showbuilder.fnServerData.end = oRange.end;
AIRTIME.showbuilder.builderDataTable();
setInterval(function(){
var oTable = $('#show_builder_table').dataTable();
oTable.fnDraw();
}, 20 * 1000); //need refresh in milliseconds
});

View File

@ -17,8 +17,8 @@ if [ "$1" = "--enable" ]; then
user=$2
echo "Changing ownership to user $1"
chown -Rv $user:$user /var/log/airtime/pypo
chown -v $user:$user /etc/airtime/pypo.cfg
chmod -R a+rw /var/log/airtime/pypo
chmod a+r /etc/airtime/pypo.cfg
chown -Rv $user:$user /var/tmp/airtime/pypo/
chmod -v a+r /etc/airtime/api_client.cfg
elif [ "$1" = "--disable" ]; then
@ -26,8 +26,7 @@ elif [ "$1" = "--disable" ]; then
user="pypo"
echo "Changing ownership to user $1"
chown -Rv $user:$user /var/log/airtime/pypo
chown -v $user:$user /etc/airtime/pypo.cfg
chmod 644 /etc/airtime/pypo.cfg
chown -Rv $user:$user /var/tmp/airtime/pypo/
chmod -v a+r /etc/airtime/api_client.cfg

View File

@ -8,7 +8,7 @@ pypo_user="pypo"
# Location of pypo_cli.py Python script
pypo_path="/usr/lib/airtime/pypo/bin/"
api_client_path="/usr/lib/airtime/"
pypo_script="pypo-cli.py"
pypo_script="pypocli.py"
cd ${pypo_path}
exec 2>&1

View File

@ -1,8 +1,7 @@
# -*- coding: utf-8 -*-
"""
Python part of radio playout (pypo)
"""
import time
from optparse import *
import sys
@ -15,6 +14,7 @@ from Queue import Queue
from pypopush import PypoPush
from pypofetch import PypoFetch
from pypofile import PypoFile
from recorder import Recorder
from pypomessagehandler import PypoMessageHandler
@ -125,11 +125,23 @@ if __name__ == '__main__':
recorder_q = Queue()
pypoPush_q = Queue()
"""
This queue is shared between pypo-fetch and pypo-file, where pypo-file
is the receiver. Pypo-fetch will send every schedule it gets to pypo-file
and pypo will parse this schedule to determine which file has the highest
priority, and will retrieve it.
"""
media_q = Queue()
pmh = PypoMessageHandler(pypoFetch_q, recorder_q)
pmh.daemon = True
pmh.start()
pf = PypoFetch(pypoFetch_q, pypoPush_q)
pfile = PypoFile(media_q)
pfile.daemon = True
pfile.start()
pf = PypoFetch(pypoFetch_q, pypoPush_q, media_q)
pf.daemon = True
pf.start()
@ -142,8 +154,9 @@ if __name__ == '__main__':
recorder.start()
pmh.join()
pp.join()
pfile.join()
pf.join()
pp.join()
recorder.join()
logger.info("pypo fetch exit")

View File

@ -10,6 +10,7 @@ import string
import json
import telnetlib
import math
import copy
from threading import Thread
from subprocess import Popen, PIPE
from datetime import datetime
@ -36,11 +37,12 @@ except Exception, e:
sys.exit()
class PypoFetch(Thread):
def __init__(self, pypoFetch_q, pypoPush_q):
def __init__(self, pypoFetch_q, pypoPush_q, media_q):
Thread.__init__(self)
self.api_client = api_client.api_client_factory(config)
self.fetch_queue = pypoFetch_q
self.push_queue = pypoPush_q
self.media_prepare_queue = media_q
self.logger = logging.getLogger();
@ -288,11 +290,29 @@ class PypoFetch(Thread):
# Download all the media and put playlists in liquidsoap "annotate" format
try:
media = self.prepare_media(media, bootstrapping)
"""
Make sure cache_dir exists
"""
download_dir = self.cache_dir
try:
os.makedirs(download_dir)
except Exception, e:
pass
for key in media:
media_item = media[key]
fileExt = os.path.splitext(media_item['uri'])[1]
dst = os.path.join(download_dir, media_item['id']+fileExt)
media_item['dst'] = dst
self.media_prepare_queue.put(copy.copy(media))
self.prepare_media(media, bootstrapping)
except Exception, e: self.logger.error("%s", e)
# Send the data to pypo-push
self.logger.debug("Pushing to pypo-push: "+ str(media))
self.logger.debug("Pushing to pypo-push")
self.push_queue.put(media)
"""
@ -317,27 +337,10 @@ class PypoFetch(Thread):
if bootstrapping:
self.check_for_previous_crash(media_item)
# create playlist directory
try:
"""
Extract year, month, date from mkey
"""
y_m_d = mkey[0:10]
download_dir = os.path.join(self.cache_dir, y_m_d)
try:
os.makedirs(os.path.join(self.cache_dir, y_m_d))
except Exception, e:
pass
fileExt = os.path.splitext(media_item['uri'])[1]
dst = os.path.join(download_dir, media_item['id']+fileExt)
except Exception, e:
self.logger.warning(e)
if self.handle_media_file(media_item, dst):
entry = self.create_liquidsoap_annotation(media_item, dst)
media_item['show_name'] = "TODO"
media_item["annotation"] = entry
entry = self.create_liquidsoap_annotation(media_item)
media_item['show_name'] = "TODO"
media_item["annotation"] = entry
except Exception, e:
self.logger.error("%s", e)
@ -345,7 +348,7 @@ class PypoFetch(Thread):
return media
def create_liquidsoap_annotation(self, media, dst):
def create_liquidsoap_annotation(self, media):
entry = \
'annotate:media_id="%s",liq_start_next="%s",liq_fade_in="%s",liq_fade_out="%s",liq_cue_in="%s",liq_cue_out="%s",schedule_table_id="%s":%s' \
% (media['id'], 0, \
@ -353,7 +356,7 @@ class PypoFetch(Thread):
float(media['fade_out']) / 1000, \
float(media['cue_in']), \
float(media['cue_out']), \
media['row_id'], dst)
media['row_id'], media['dst'])
return entry
@ -397,7 +400,8 @@ class PypoFetch(Thread):
try:
#blocking function to download the media item
self.download_file(media_item, dst)
#self.download_file(media_item, dst)
self.copy_file(media_item, dst)
if os.access(dst, os.R_OK):
# check filesize (avoid zero-byte files)
@ -417,10 +421,25 @@ class PypoFetch(Thread):
return False
"""
Download a file from a remote server and store it in the cache.
"""
def copy_file(self, media_item, dst):
"""
Copy the file from local library directory.
"""
if not os.path.isfile(dst):
self.logger.debug("copying from %s to local cache %s" % (media_item['uri'], dst))
try:
shutil.copy(media_item['uri'], dst)
except:
self.logger.error("Could not copy from %s to %s" % (media_item['uri'], dst))
else:
#file already exists
pass
def download_file(self, media_item, dst):
"""
Download a file from a remote server and store it in the cache.
"""
if os.path.isfile(dst):
pass
#self.logger.debug("file already in cache: %s", dst)

View File

@ -0,0 +1,117 @@
from threading import Thread
from Queue import Empty
from configobj import ConfigObj
import logging
import logging.config
import shutil
import os
import time
# configure logging
logging.config.fileConfig("logging.cfg")
# loading config file
try:
config = ConfigObj('/etc/airtime/pypo.cfg')
LS_HOST = config['ls_host']
LS_PORT = config['ls_port']
POLL_INTERVAL = int(config['poll_interval'])
except Exception, e:
logger = logging.getLogger()
logger.error('Error loading config file: %s', e)
sys.exit()
class PypoFile(Thread):
def __init__(self, schedule_queue):
Thread.__init__(self)
self.logger = logging.getLogger()
self.media_queue = schedule_queue
self.media = None
self.cache_dir = os.path.join(config["cache_dir"], "scheduler")
def copy_file(self, media_item):
"""
Copy media_item from local library directory to local cache directory.
"""
if media_item is None:
return
dst = media_item['dst']
if not os.path.isfile(dst):
self.logger.debug("copying from %s to local cache %s" % (media_item['uri'], dst))
try:
shutil.copy(media_item['uri'], dst)
except:
self.logger.error("Could not copy from %s to %s" % (media_item['uri'], dst))
else:
self.logger.debug("Destination %s already exists. Not copying", dst)
def get_highest_priority_media_item(self, schedule):
"""
Get highest priority media_item in the queue. Currently the highest
priority is decided by how close the start time is to "now".
"""
if schedule is None:
return None
sorted_keys = sorted(schedule.keys())
if len(sorted_keys) == 0:
return None
highest_priority = sorted_keys[0]
media_item = schedule[highest_priority]
self.logger.debug("Highest priority item: %s" % highest_priority)
"""
Remove this media_item from the dictionary. On the next iteration
(from the main function) we won't consider it for prioritization
anymore. If on the next iteration we have received a new schedule,
it is very possible we will have to deal with the same media_items
again. In this situation, the worst possible case is that we try to
copy the file again and realize we already have it (thus aborting the copy).
"""
del schedule[highest_priority]
return media_item
def main(self):
while True:
try:
if self.media is None or len(self.media) == 0:
"""
We have no schedule, so we have nothing else to do. Let's
do a blocked wait on the queue
"""
self.media = self.media_queue.get(block=True)
else:
"""
We have a schedule we need to process, but we also want
to check if a newer schedule is available. In this case
do a non-blocking queue.get and in either case (we get something
or we don't), get back to work on preparing getting files.
"""
try:
self.media = self.media_queue.get_nowait()
except Empty, e:
pass
media_item = self.get_highest_priority_media_item(self.media)
self.copy_file(media_item)
except Exception, e:
self.logger.error(str(e))
raise
def run(self):
"""
Entry point of the thread
"""
self.main()