Merge branch '2.4.x'

This commit is contained in:
Martin Konecny 2013-05-23 13:47:19 -04:00
commit 46ecd69b03
9 changed files with 362 additions and 194 deletions

View file

@ -26,6 +26,7 @@ class Config {
$CC_CONFIG['webServerUser'] = $values['general']['web_server_user']; $CC_CONFIG['webServerUser'] = $values['general']['web_server_user'];
$CC_CONFIG['rabbitmq'] = $values['rabbitmq']; $CC_CONFIG['rabbitmq'] = $values['rabbitmq'];
$CC_CONFIG['baseDir'] = $values['general']['base_dir'];
$CC_CONFIG['baseUrl'] = $values['general']['base_url']; $CC_CONFIG['baseUrl'] = $values['general']['base_url'];
$CC_CONFIG['basePort'] = $values['general']['base_port']; $CC_CONFIG['basePort'] = $values['general']['base_port'];
$CC_CONFIG['phpDir'] = $values['general']['airtime_dir']; $CC_CONFIG['phpDir'] = $values['general']['airtime_dir'];

View file

@ -383,6 +383,7 @@ class PlaylistController extends Zend_Controller_Action
$this->createUpdateResponse($obj); $this->createUpdateResponse($obj);
} else { } else {
$this->view->cue_error = $response["error"]; $this->view->cue_error = $response["error"];
$this->view->code = $response["type"];
} }
} catch (PlaylistOutDatedException $e) { } catch (PlaylistOutDatedException $e) {
$this->playlistOutdated($e); $this->playlistOutdated($e);

View file

@ -10,6 +10,10 @@ require_once 'formatters/LengthFormatter.php';
*/ */
class Application_Model_Playlist implements Application_Model_LibraryEditable class Application_Model_Playlist implements Application_Model_LibraryEditable
{ {
const CUE_ALL_ERROR = 0;
const CUE_IN_ERROR = 1;
const CUE_OUT_ERROR = 2;
/** /**
* propel connection object. * propel connection object.
*/ */
@ -792,6 +796,7 @@ SQL;
try { try {
if (is_null($cueIn) && is_null($cueOut)) { if (is_null($cueIn) && is_null($cueOut)) {
$errArray["error"] = _("Cue in and cue out are null."); $errArray["error"] = _("Cue in and cue out are null.");
$errArray["type"] = self::CUE_ALL_ERROR;
return $errArray; return $errArray;
} }
@ -822,6 +827,7 @@ SQL;
$sql = "SELECT :cueIn::INTERVAL > :cueOut::INTERVAL"; $sql = "SELECT :cueIn::INTERVAL > :cueOut::INTERVAL";
if (Application_Common_Database::prepareAndExecute($sql, array(':cueIn'=>$cueIn, ':cueOut'=>$cueOut), 'column')) { if (Application_Common_Database::prepareAndExecute($sql, array(':cueIn'=>$cueIn, ':cueOut'=>$cueOut), 'column')) {
$errArray["error"] = _("Can't set cue in to be larger than cue out."); $errArray["error"] = _("Can't set cue in to be larger than cue out.");
$errArray["type"] = self::CUE_IN_ERROR;
return $errArray; return $errArray;
} }
@ -829,6 +835,7 @@ SQL;
$sql = "SELECT :cueOut::INTERVAL > :origLength::INTERVAL"; $sql = "SELECT :cueOut::INTERVAL > :origLength::INTERVAL";
if (Application_Common_Database::prepareAndExecute($sql, array(':cueOut'=>$cueOut, ':origLength'=>$origLength), 'column')) { if (Application_Common_Database::prepareAndExecute($sql, array(':cueOut'=>$cueOut, ':origLength'=>$origLength), 'column')) {
$errArray["error"] = _("Can't set cue out to be greater than file length."); $errArray["error"] = _("Can't set cue out to be greater than file length.");
$errArray["type"] = self::CUE_OUT_ERROR;
return $errArray; return $errArray;
} }
@ -845,6 +852,7 @@ SQL;
$sql = "SELECT :cueIn::INTERVAL > :oldCueOut::INTERVAL"; $sql = "SELECT :cueIn::INTERVAL > :oldCueOut::INTERVAL";
if (Application_Common_Database::prepareAndExecute($sql, array(':cueIn'=>$cueIn, ':oldCueOut'=>$oldCueOut), 'column')) { if (Application_Common_Database::prepareAndExecute($sql, array(':cueIn'=>$cueIn, ':oldCueOut'=>$oldCueOut), 'column')) {
$errArray["error"] = _("Can't set cue in to be larger than cue out."); $errArray["error"] = _("Can't set cue in to be larger than cue out.");
$errArray["type"] = self::CUE_IN_ERROR;
return $errArray; return $errArray;
} }
@ -863,6 +871,7 @@ SQL;
$sql = "SELECT :cueOut::INTERVAL < :oldCueIn::INTERVAL"; $sql = "SELECT :cueOut::INTERVAL < :oldCueIn::INTERVAL";
if (Application_Common_Database::prepareAndExecute($sql, array(':cueOut'=>$cueOut, ':oldCueIn'=>$oldCueIn), 'column')) { if (Application_Common_Database::prepareAndExecute($sql, array(':cueOut'=>$cueOut, ':oldCueIn'=>$oldCueIn), 'column')) {
$errArray["error"] = _("Can't set cue out to be smaller than cue in."); $errArray["error"] = _("Can't set cue out to be smaller than cue in.");
$errArray["type"] = self::CUE_OUT_ERROR;
return $errArray; return $errArray;
} }
@ -870,6 +879,7 @@ SQL;
$sql = "SELECT :cueOut::INTERVAL > :origLength::INTERVAL"; $sql = "SELECT :cueOut::INTERVAL > :origLength::INTERVAL";
if (Application_Common_Database::prepareAndExecute($sql, array(':cueOut'=>$cueOut, ':origLength'=>$origLength), 'column')) { if (Application_Common_Database::prepareAndExecute($sql, array(':cueOut'=>$cueOut, ':origLength'=>$origLength), 'column')) {
$errArray["error"] = _("Can't set cue out to be greater than file length."); $errArray["error"] = _("Can't set cue out to be greater than file length.");
$errArray["type"] = self::CUE_OUT_ERROR;
return $errArray; return $errArray;
} }

View file

@ -388,7 +388,7 @@ class Application_Model_Scheduler
return $dt; return $dt;
} }
private function findNextStartTime($DT, $instance) private function findNextStartTime($DT, $instanceId)
{ {
$sEpoch = $DT->format("U.u"); $sEpoch = $DT->format("U.u");
$nEpoch = $this->epochNow; $nEpoch = $this->epochNow;
@ -410,7 +410,7 @@ class Application_Model_Scheduler
->setDbCueIn('00:00:00') ->setDbCueIn('00:00:00')
->setDbCueOut('00:00:00') ->setDbCueOut('00:00:00')
->setDbPlayoutStatus(-1) ->setDbPlayoutStatus(-1)
->setDbInstanceId($instance->getDbId()) ->setDbInstanceId($instanceId)
->save($this->con); ->save($this->con);
} else { } else {
$nextDT = $DT; $nextDT = $DT;
@ -521,7 +521,12 @@ class Application_Model_Scheduler
$linked = false; $linked = false;
$dropIndex_sql = "DROP INDEX cc_schedule_instance_id_idx";
Application_Common_Database::prepareAndExecute(
$dropIndex_sql, array(), Application_Common_Database::EXECUTE);
foreach ($scheduleItems as $schedule) { foreach ($scheduleItems as $schedule) {
Logging::info($schedule);
$id = intval($schedule["id"]); $id = intval($schedule["id"]);
/* Find out if the show where the cursor position (where an item will /* Find out if the show where the cursor position (where an item will
@ -531,12 +536,18 @@ class Application_Model_Scheduler
* of inserted items * of inserted items
*/ */
if ($id != 0) { if ($id != 0) {
$ccSchedule = CcScheduleQuery::create()->findPk($id); $schedule_sql = "SELECT * FROM cc_schedule WHERE id = ".$id;
$ccShowInstance = CcShowInstancesQuery::create()->findPk($ccSchedule->getDbInstanceId()); $ccSchedule = Application_Common_Database::prepareAndExecute(
$ccShow = $ccShowInstance->getCcShow(); $schedule_sql, array(), Application_Common_Database::SINGLE);
$linked = $ccShow->isLinked();
$show_sql = "SELECT * FROM cc_show WHERE id IN (".
"SELECT show_id FROM cc_show_instances WHERE id = ".$ccSchedule["instance_id"].")";
$ccShow = Application_Common_Database::prepareAndExecute(
$show_sql, array(), Application_Common_Database::SINGLE);
$linked = $ccShow["linked"];
if ($linked) { if ($linked) {
$unique = $ccShow->getDbId() . $ccSchedule->getDbPosition(); $unique = $ccShow["id"] . $ccSchedule["position"];
if (!in_array($unique, $temp)) { if (!in_array($unique, $temp)) {
$temp[] = $unique; $temp[] = $unique;
} else { } else {
@ -544,11 +555,14 @@ class Application_Model_Scheduler
} }
} }
} else { } else {
$ccShowInstance = CcShowInstancesQuery::create()->findPk($schedule["instance"]); $show_sql = "SELECT * FROM cc_show WHERE id IN (".
$ccShow = $ccShowInstance->getccShow(); "SELECT show_id FROM cc_show_instances WHERE id = ".$schedule["instance"].")";
$linked = $ccShow->isLinked(); $ccShow = Application_Common_Database::prepareAndExecute(
$show_sql, array(), Application_Common_Database::SINGLE);
$linked = $ccShow["linked"];
if ($linked) { if ($linked) {
$unique = $ccShow->getDbId() . "a"; $unique = $ccShow["id"] . "a";
if (!in_array($unique, $temp)) { if (!in_array($unique, $temp)) {
$temp[] = $unique; $temp[] = $unique;
} else { } else {
@ -562,38 +576,47 @@ class Application_Model_Scheduler
* to that show * to that show
*/ */
if ($linked) { if ($linked) {
$instances = $ccShow->getCcShowInstancess(); $instance_sql = "SELECT * FROM cc_show_instances ".
"WHERE show_id = ".$ccShow["id"];
$instances = Application_Common_Database::prepareAndExecute(
$instance_sql);
} else { } else {
$instances = array($ccShowInstance); $instance_sql = "SELECT * FROM cc_show_instances ".
"WHERE id = ".$schedule["instance"];
$instances = Application_Common_Database::prepareAndExecute(
$instance_sql);
} }
foreach($instances as &$instance) { foreach($instances as &$instance) {
$instanceId = $instance->getDbId(); $instanceId = $instance["id"];
if ($id !== 0) { if ($id !== 0) {
/* We use the selected cursor's position to find the same /* We use the selected cursor's position to find the same
* positions in every other linked instance * positions in every other linked instance
*/ */
$pos = $ccSchedule->getDbPosition(); $pos = $ccSchedule["position"];
$linkCcSchedule = CcScheduleQuery::create() $linkedItem_sql = "SELECT ends FROM cc_schedule ".
->filterByDbInstanceId($instanceId) "WHERE instance_id = {$instanceId} ".
->filterByDbPosition($pos) "AND position = {$pos} ".
->findOne(); "AND playout_status IS NOT -1";
$linkedItemEnds = Application_Common_Database::prepareAndExecute(
$linkedItem_sql, array(), Application_Common_Database::COLUMN);
$schedItemEndDT = $linkCcSchedule->getDbEnds(null); $nextStartDT = $this->findNextStartTime(
$nextStartDT = $this->findNextStartTime($schedItemEndDT, $instance); new DateTime($linkedItemEnds, new DateTimeZone("UTC")),
$instanceId);
$pos++; $pos++;
} }
//selected empty row to add after //selected empty row to add after
else { else {
$showStartDT = $instance->getDbStarts(null); $showStartDT = new DateTime($instance["starts"], new DateTimeZone("UTC"));
$nextStartDT = $this->findNextStartTime($showStartDT, $instance); $nextStartDT = $this->findNextStartTime($showStartDT, $instanceId);
//show is empty so start position counter at 0 //show is empty so start position counter at 0
$pos = 0; $pos = 0;
} }
if (!in_array($instance->getDbId(), $affectedShowInstances)) { if (!in_array($instanceId, $affectedShowInstances)) {
$affectedShowInstances[] = $instanceId; $affectedShowInstances[] = $instanceId;
} }
@ -620,39 +643,50 @@ class Application_Model_Scheduler
} }
} }
$doInsert = false;
$doUpdate = false;
$values = array();
foreach ($filesToInsert as &$file) { foreach ($filesToInsert as &$file) {
//item existed previously and is being moved. //item existed previously and is being moved.
//need to keep same id for resources if we want REST. //need to keep same id for resources if we want REST.
if (isset($file['sched_id'])) { if (isset($file['sched_id'])) {
$sched = CcScheduleQuery::create()->findPk($file["sched_id"]); $doUpdate = true;
$movedItem_sql = "SELECT * FROM cc_schedule ".
"WHERE id = ".$file["sched_id"];
$sched = Application_Common_Database::prepareAndExecute(
$movedItem_sql, array(), Application_Common_Database::SINGLE);
/* We need to keep a record of the original positon a track /* We need to keep a record of the original positon a track
* is being moved from so we can use it to retrieve the correct * is being moved from so we can use it to retrieve the correct
* items in linked instances * items in linked instances
*/ */
if (!isset($originalPosition)) { if (!isset($originalPosition)) {
$originalPosition = $sched->getDbPosition(); $originalPosition = $sched["position"];
} }
/* If we are moving an item in a linked show we need to get /* If we are moving an item in a linked show we need to get
* the relative item to move in each instance. We know what the * the relative item to move in each instance. We know what the
* relative item is by its position * relative item is by its position
*/ */
if ($linked && $moveAction) { if ($linked) {
$sched = CcScheduleQuery::create() $movedItem_sql = "SELECT * FROM cc_schedule ".
->filterByDbInstanceId($instanceId) "WHERE position = {$originalPosition} ".
->filterByDbPosition($originalPosition) "AND instance_id = {$instanceId}";
->findOne();
}
$excludeIds[] = intval($sched->getDbId());
$file["cliplength"] = $sched->getDbClipLength(); $sched = Application_Common_Database::prepareAndExecute(
$file["cuein"] = $sched->getDbCueIn(); $movedItem_sql, array(), Application_Common_Database::SINGLE);
$file["cueout"] = $sched->getDbCueOut(); }
$file["fadein"] = $sched->getDbFadeIn(); $excludeIds[] = intval($sched["id"]);
$file["fadeout"] = $sched->getDbFadeOut();
$file["cliplength"] = $sched["clip_length"];
$file["cuein"] = $sched["cue_in"];
$file["cueout"] = $sched["cue_out"];
$file["fadein"] = $sched["fade_in"];
$file["fadeout"] = $sched["fade_out"];
} else { } else {
$sched = new CcSchedule(); //$sched = new CcSchedule();
$doInsert = true;
} }
$endTimeDT = $this->findEndTime($nextStartDT, $file['cliplength']); $endTimeDT = $this->findEndTime($nextStartDT, $file['cliplength']);
@ -661,30 +695,47 @@ class Application_Model_Scheduler
$file['fadein'] = Application_Common_DateHelper::secondsToPlaylistTime($file['fadein']); $file['fadein'] = Application_Common_DateHelper::secondsToPlaylistTime($file['fadein']);
$file['fadeout'] = Application_Common_DateHelper::secondsToPlaylistTime($file['fadeout']); $file['fadeout'] = Application_Common_DateHelper::secondsToPlaylistTime($file['fadeout']);
$sched->setDbStarts($nextStartDT)
->setDbEnds($endTimeDT)
->setDbCueIn($file['cuein'])
->setDbCueOut($file['cueout'])
->setDbFadeIn($file['fadein'])
->setDbFadeOut($file['fadeout'])
->setDbClipLength($file['cliplength'])
->setDbPosition($pos);
if (!$moveAction) {
$sched->setDbInstanceId($instanceId);
}
switch ($file["type"]) { switch ($file["type"]) {
case 0: case 0:
$sched->setDbFileId($file['id']); $fileId = $file["id"];
$streamId = "null";
break; break;
case 1: case 1:
$sched->setDbStreamId($file['id']); $streamId = $file["id"];
$fileId = "null";
break; break;
default: break; default: break;
} }
$sched->save($this->con); if ($doInsert) {
$values[] = "(".
"'{$nextStartDT->format("Y-m-d H:i:s")}', ".
"'{$endTimeDT->format("Y-m-d H:i:s")}', ".
"'{$file["cuein"]}', ".
"'{$file["cueout"]}', ".
"'{$file["fadein"]}', ".
"'{$file["fadeout"]}', ".
"'{$file["cliplength"]}', ".
"{$pos}, ".
"{$instanceId}, ".
"{$fileId}, ".
"{$streamId})";
} elseif ($doUpdate) {
$update_sql = "UPDATE cc_schedule SET ".
"starts = '{$nextStartDT->format("Y-m-d H:i:s")}', ".
"ends = '{$endTimeDT->format("Y-m-d H:i:s")}', ".
"cue_in = '{$file["cuein"]}', ".
"cue_out = '{$file["cueout"]}', ".
"fade_in = '{$file["fadein"]}', ".
"fade_out = '{$file["fadeout"]}', ".
"clip_length = '{$file["cliplength"]}', ".
"position = {$pos} ".
"WHERE id = {$sched["id"]}";
Application_Common_Database::prepareAndExecute(
$update_sql, array(), Application_Common_Database::EXECUTE);
}
$nextStartDT = $endTimeDT; $nextStartDT = $endTimeDT;
$pos++; $pos++;
@ -693,9 +744,18 @@ class Application_Model_Scheduler
* after the insert location, we need to exclude the * after the insert location, we need to exclude the
* schedule item we just inserted because it has correct * schedule item we just inserted because it has correct
* start and end times*/ * start and end times*/
$excludeIds[] = $sched->getDbId(); //$excludeIds[] = $lastInsertId;
}//all files have been inserted/moved }//all files have been inserted/moved
if ($doInsert) {
$insert_sql = "INSERT INTO cc_schedule ".
"(starts, ends, cue_in, cue_out, fade_in, fade_out, ".
"clip_length, position, instance_id, file_id, stream_id) VALUES ".
implode($values, ",");
Application_Common_Database::prepareAndExecute(
$insert_sql, array(), Application_Common_Database::EXECUTE);
}
// update is_scheduled flag for each cc_file // update is_scheduled flag for each cc_file
$fileIds = array(); $fileIds = array();
@ -717,22 +777,30 @@ class Application_Model_Scheduler
} }
if ($adjustSched === true) { if ($adjustSched === true) {
$followingSchedItems = CcScheduleQuery::create() $followingItems_sql = "SELECT * FROM cc_schedule ".
->filterByDBStarts($initalStartDT->format("Y-m-d H:i:s.u"), Criteria::GREATER_EQUAL) "WHERE starts >= '{$initalStartDT->format("Y-m-d H:i:s.u")}' ".
->filterByDbInstanceId($instance->getDbId()) "AND instance_id = {$instanceId} ";
->filterByDbId($excludeIds, Criteria::NOT_IN) if (count($excludeIds) > 0) {
->orderByDbStarts() $followingItems_sql .= "AND id NOT IN (". implode($excludeIds, ",").") ";
->find($this->con); }
$followingItems_sql .= "ORDER BY starts";
$followingSchedItems = Application_Common_Database::prepareAndExecute(
$followingItems_sql);
$pstart = microtime(true); $pstart = microtime(true);
//recalculate the start/end times after the inserted items. //recalculate the start/end times after the inserted items.
foreach ($followingSchedItems as $item) { foreach ($followingSchedItems as $item) {
$endTimeDT = $this->findEndTime($nextStartDT, $item->getDbClipLength()); $endTimeDT = $this->findEndTime($nextStartDT, $item["clip_length"]);
$item->setDbStarts($nextStartDT); $update_sql = "UPDATE cc_schedule SET ".
$item->setDbEnds($endTimeDT); "starts = '{$nextStartDT->format("Y-m-d H:i:s")}', ".
$item->setDbPosition($pos); "ends = '{$endTimeDT->format("Y-m-d H:i:s")}', ".
$item->save($this->con); "position = {$pos} ".
"WHERE id = {$item["id"]}";
Application_Common_Database::prepareAndExecute(
$update_sql, array(), Application_Common_Database::EXECUTE);
$nextStartDT = $endTimeDT; $nextStartDT = $endTimeDT;
$pos++; $pos++;
} }
@ -741,12 +809,16 @@ class Application_Model_Scheduler
Logging::debug("adjusting all following items."); Logging::debug("adjusting all following items.");
Logging::debug(floatval($pend) - floatval($pstart)); Logging::debug(floatval($pend) - floatval($pstart));
$this->calculateCrossfades($instance->getDbId()); $this->calculateCrossfades($instanceId);
} }
}//for each instance }//for each instance
}//for each schedule location }//for each schedule location
$createIndex_sql = "CREATE INDEX cc_schedule_instance_id_idx ".
"ON cc_schedule USING btree(instance_id)";
Application_Common_Database::prepareAndExecute(
$createIndex_sql, array(), Application_Common_Database::EXECUTE);
$endProfile = microtime(true); $endProfile = microtime(true);
Logging::debug("finished adding scheduled items."); Logging::debug("finished adding scheduled items.");
Logging::debug(floatval($endProfile) - floatval($startProfile)); Logging::debug(floatval($endProfile) - floatval($startProfile));
@ -782,6 +854,11 @@ class Application_Model_Scheduler
} }
} }
private function updateMovedItem()
{
}
private function getInstances($instanceId) private function getInstances($instanceId)
{ {
$ccShowInstance = CcShowInstancesQuery::create()->findPk($instanceId); $ccShowInstance = CcShowInstancesQuery::create()->findPk($instanceId);

View file

@ -501,44 +501,25 @@ SQL;
} }
/** /**
* Get the URL to access this file using the server name/address that * Get the URL to access this file
* this PHP script was invoked through.
*/ */
public function getFileUrl() public function getFileUrl()
{ {
$serverName = $_SERVER['SERVER_NAME']; $CC_CONFIG = Config::getConfig();
$serverPort = $_SERVER['SERVER_PORT'];
$protocol = empty($_SERVER['HTTPS']) ? "http" : "https";
return $this->constructGetFileUrl($serverName, $serverPort);
} $serverName = $_SERVER['SERVER_NAME'];
$serverPort = $_SERVER['SERVER_PORT'];
/** $subDir = $CC_CONFIG['baseDir'];
* Get the URL to access this file using the server name/address that
* is specified in the airtime.conf config file. If either of these is if ($subDir[0] === "/") {
* not specified, then use values provided by the $_SERVER global variable. $subDir = substr($subDir, 1, strlen($subDir) - 1);
*/ }
public function getFileUrlUsingConfigAddress()
{ $baseUrl = "{$protocol}://{$serverName}:{$serverPort}/{$subDir}";
$CC_CONFIG = Config::getConfig();
return $this->getRelativeFileUrl($baseUrl);
if (isset($CC_CONFIG['baseUrl'])) {
$serverName = $CC_CONFIG['baseUrl'];
} else {
$serverName = $_SERVER['SERVER_NAME'];
}
if (isset($CC_CONFIG['basePort'])) {
$serverPort = $CC_CONFIG['basePort'];
} else {
$serverPort = $_SERVER['SERVER_PORT'];
}
return $this->constructGetFileUrl($serverName, $serverPort);
}
private function constructGetFileUrl($p_serverName, $p_serverPort)
{
return "http://$p_serverName:$p_serverPort/api/get-media/file/".$this->getId().".".$this->getFileExtension();
} }
/** /**
@ -547,6 +528,8 @@ SQL;
*/ */
public function getRelativeFileUrl($baseUrl) public function getRelativeFileUrl($baseUrl)
{ {
Logging::debug("Zend base url: $baseUrl");
return $baseUrl."api/get-media/file/".$this->getId().".".$this->getFileExtension(); return $baseUrl."api/get-media/file/".$this->getId().".".$this->getFileExtension();
} }

View file

@ -155,64 +155,105 @@ class Application_Service_SchedulerService
* any other instances with content * any other instances with content
*/ */
$instanceIds = $ccShow->getInstanceIds(); $instanceIds = $ccShow->getInstanceIds();
$ccSchedules = CcScheduleQuery::create() $schedule_sql = "SELECT * FROM cc_schedule ".
->filterByDbInstanceId($instanceIds, Criteria::IN) "WHERE instance_id IN (".implode($instanceIds, ",").")";
->find(); $ccSchedules = Application_Common_Database::prepareAndExecute(
if (!$ccSchedules->isEmpty()) { $schedule_sql);
if (count($ccSchedules) > 0) {
/* Find the show contents of just one of the instances. It doesn't /* Find the show contents of just one of the instances. It doesn't
* matter which instance we use since all the content is the same * matter which instance we use since all the content is the same
*/ */
$ccSchedule = $ccSchedules->getFirst(); $ccSchedule = $ccSchedules[0];
$showStamp = CcScheduleQuery::create() $showStamp_sql = "SELECT * FROM cc_schedule ".
->filterByDbInstanceId($ccSchedule->getDbInstanceId()) "WHERE instance_id = {$ccSchedule["instance_id"]} ".
->orderByDbStarts() "ORDER BY starts";
->find(); $showStamp = Application_Common_Database::prepareAndExecute(
$showStamp_sql);
//get time_filled so we can update cc_show_instances //get time_filled so we can update cc_show_instances
$timeFilled = $ccSchedule->getCcShowInstances()->getDbTimeFilled(); $timeFilled_sql = "SELECT time_filled FROM cc_show_instances ".
"WHERE id = {$ccSchedule["instance_id"]}";
$timeFilled = Application_Common_Database::prepareAndExecute(
$timeFilled_sql, array(), Application_Common_Database::COLUMN);
$dropIndex_sql = "DROP INDEX cc_schedule_instance_id_idx";
Application_Common_Database::prepareAndExecute(
$dropIndex_sql, array(), Application_Common_Database::EXECUTE);
//need to find out which linked instances are empty //need to find out which linked instances are empty
foreach ($ccShow->getCcShowInstancess() as $ccShowInstance) { $values = array();
$ccSchedules = CcScheduleQuery::create() foreach ($instanceIds as $id) {
->filterByDbInstanceId($ccShowInstance->getDbId()) $instanceSched_sql = "SELECT * FROM cc_schedule ".
->find(); "WHERE instance_id = {$id} ".
"ORDER by starts";
$ccSchedules = Application_Common_Database::prepareAndExecute(
$instanceSched_sql);
/* If the show instance is empty OR it has different content than /* If the show instance is empty OR it has different content than
* the first instance, we cant to fill/replace with the show stamp * the first instance, we need to fill/replace with the show stamp
* (The show stamp is taken from the first show instance's content) * (The show stamp is taken from the first show instance's content)
*/ */
if ($ccSchedules->isEmpty() || if (count($ccSchedules) < 1 ||
self::replaceInstanceContentCheck($ccShowInstance, $showStamp)) { self::replaceInstanceContentCheck($ccSchedules, $showStamp)) {
$nextStartDT = $ccShowInstance->getDbStarts(null); //$nextStartDT = $ccShowInstance->getDbStarts(null);
$instanceStart_sql = "SELECT starts FROM cc_show_instances ".
"WHERE id = {$id}";
$nextStartDT = new DateTime(
Application_Common_Database::prepareAndExecute(
$instanceStart_sql, array(), Application_Common_Database::EXECUTE),
new DateTimeZone("UTC"));
foreach ($showStamp as $item) { foreach ($showStamp as $item) {
$endTimeDT = self::findEndTime($nextStartDT, $item->getDbClipLength()); $endTimeDT = self::findEndTime($nextStartDT, $item["clip_length"]);
$ccSchedule = new CcSchedule(); if (is_null($item["file_id"])) {
$ccSchedule $item["file_id"] = "null";
->setDbStarts($nextStartDT) } elseif (is_null($item["stream_id"])) {
->setDbEnds($endTimeDT) $item["stream_id"] = "null";
->setDbFileId($item->getDbFileId()) }
->setDbStreamId($item->getDbStreamId())
->setDbClipLength($item->getDbClipLength()) $values[] = "(".
->setDbFadeIn($item->getDbFadeIn()) "'{$nextStartDT->format("Y-m-d H:i:s")}', ".
->setDbFadeOut($item->getDbFadeOut()) "'{$endTimeDT->format("Y-m-d H:i:s")}', ".
->setDbCuein($item->getDbCueIn()) "'{$item["clip_length"]}', ".
->setDbCueOut($item->getDbCueOut()) "'{$item["fade_in"]}', ".
->setDbInstanceId($ccShowInstance->getDbId()) "'{$item["fade_out"]}', ".
->setDbPosition($item->getDbPosition()) "'{$item["cue_in"]}', ".
->save(); "'{$item["cue_out"]}', ".
"{$item["file_id"]}, ".
"{$item["stream_id"]}, ".
"{$id}, ".
"{$item["position"]})";
$nextStartDT = $endTimeDT; $nextStartDT = $endTimeDT;
} //foreach show item } //foreach show item
//update time_filled in cc_show_instances
$ccShowInstance
->setDbTimeFilled($timeFilled)
->setDbLastScheduled(gmdate("Y-m-d H:i:s"))
->save();
} }
} //foreach linked instance } //foreach linked instance
$insert_sql = "INSERT INTO cc_schedule (starts, ends, ".
"clip_length, fade_in, fade_out, cue_in, cue_out, ".
"file_id, stream_id, instance_id, position) VALUES ".
implode($values, ",");
Application_Common_Database::prepareAndExecute(
$insert_sql, array(), Application_Common_Database::EXECUTE);
$createIndex_sql = "CREATE INDEX cc_schedule_instance_id_idx ".
"ON cc_schedule USING btree(instance_id)";
Application_Common_Database::prepareAndExecute(
$createIndex_sql, array(), Application_Common_Database::EXECUTE);
//update time_filled in cc_show_instances
$now = gmdate("Y-m-d H:i:s");
$update_sql = "UPDATE cc_show_instances SET ".
"time_filled = '{$timeFilled}', ".
"last_scheduled = '{$now}' ".
"WHERE show_id = {$ccShow->getDbId()}";
Application_Common_Database::prepareAndExecute(
$update_sql, array(), Application_Common_Database::EXECUTE);
} //if at least one linked instance has content } //if at least one linked instance has content
} }
@ -259,20 +300,24 @@ class Application_Service_SchedulerService
} }
} }
private static function replaceInstanceContentCheck($ccShowInstance, $showStamp) private static function replaceInstanceContentCheck($currentShowStamp, $showStamp)
{ {
$currentShowStamp = CcScheduleQuery::create() /*$currentShowStamp = CcScheduleQuery::create()
->filterByDbInstanceId($ccShowInstance->getDbId()) ->filterByDbInstanceId($ccShowInstance->getDbId())
->orderByDbStarts() ->orderByDbStarts()
->find(); ->find();*/
$counter = 0; $counter = 0;
foreach ($showStamp as $item) { foreach ($showStamp as $item) {
if ($item->getDbFileId() != $currentShowStamp[$counter]->getDbFileId() || if ($item["file_id"] != $currentShowStamp[$counter]["file_id"] ||
$item->getDbStreamId() != $currentShowStamp[$counter]->getDbStreamId()) { $item["stream_id"] != $currentShowStamp[$counter]["stream_id"]) {
CcScheduleQuery::create() /*CcScheduleQuery::create()
->filterByDbInstanceId($ccShowInstance->getDbId()) ->filterByDbInstanceId($ccShowInstance->getDbId())
->delete(); ->delete();*/
$delete_sql = "DELETE FROM cc_schedule ".
"WHERE instance_id = {$currentShowStamp[$counter]["instance_id"]}";
Application_Common_Database::prepareAndExecute(
$delete_sql, array(), Application_Common_Database::EXECUTE);
return true; return true;
} }
} }

View file

@ -22,6 +22,13 @@ var live_dj_on_air = false;
var scheduled_play_on_air = false; var scheduled_play_on_air = false;
var scheduled_play_source = false; var scheduled_play_source = false;
//a reference returned by setTimeout. Useful for when we want clearTimeout()
var newSongTimeoutId = null;
//a reference returned by setTimeout. Useful for when we want clearTimeout()
var newShowTimeoutId = null;
//keep track of how many UI refreshes the ON-AIR light has been off for. //keep track of how many UI refreshes the ON-AIR light has been off for.
//For example, the uiUpdateInterval is every 200ms, so if onAirOffIterations //For example, the uiUpdateInterval is every 200ms, so if onAirOffIterations
//is 25, then that means 5 seconds have gone by. //is 25, then that means 5 seconds have gone by.
@ -34,6 +41,8 @@ var nextSongPrepare = true;
var nextShowPrepare = true; var nextShowPrepare = true;
function secondsTimer(){ function secondsTimer(){
/* This function constantly calls itself every 'uiUpdateInterval'
* micro-seconds and is responsible for updating the UI. */
if (localRemoteTimeOffset !== null){ if (localRemoteTimeOffset !== null){
var date = new Date(); var date = new Date();
approximateServerTime = date.getTime() - localRemoteTimeOffset; approximateServerTime = date.getTime() - localRemoteTimeOffset;
@ -79,9 +88,11 @@ function updateProgressBarValue(){
var songElapsedTime = 0; var songElapsedTime = 0;
songPercentDone = (approximateServerTime - currentSong.songStartPosixTime)/currentSong.songLengthMs*100; songPercentDone = (approximateServerTime - currentSong.songStartPosixTime)/currentSong.songLengthMs*100;
songElapsedTime = approximateServerTime - currentSong.songStartPosixTime; songElapsedTime = approximateServerTime - currentSong.songStartPosixTime;
if (songPercentDone < 0 || songPercentDone > 100){ if (songPercentDone < 0) {
songPercentDone = 0; songPercentDone = 0;
//currentSong = null; //currentSong = null;
} else if (songPercentDone > 100) {
songPercentDone = 100;
} else { } else {
if ((currentSong.media_item_played == true && currentShow.length > 0) || (songElapsedTime < 5000 && currentShow[0].record != 1)) { if ((currentSong.media_item_played == true && currentShow.length > 0) || (songElapsedTime < 5000 && currentShow[0].record != 1)) {
scheduled_play_line_to_switch.attr("class", "line-to-switch on"); scheduled_play_line_to_switch.attr("class", "line-to-switch on");
@ -95,40 +106,13 @@ function updateProgressBarValue(){
} }
$('#progress-show').attr("class", "progress-show"); $('#progress-show').attr("class", "progress-show");
} }
} else if (nextSong == null) { } else {
scheduled_play_source = false; scheduled_play_source = false;
scheduled_play_line_to_switch.attr("class", "line-to-switch off"); scheduled_play_line_to_switch.attr("class", "line-to-switch off");
scheduled_play_div.removeClass("ready"); scheduled_play_div.removeClass("ready");
$('#progress-show').attr("class", "progress-show-error"); $('#progress-show').attr("class", "progress-show-error");
} }
$('#progress-bar').attr("style", "width:"+songPercentDone+"%"); $('#progress-bar').attr("style", "width:"+songPercentDone+"%");
//calculate how much time left to next song if there is any
if (nextSong !== null && nextSongPrepare){
var diff = nextSong.songStartPosixTime - approximateServerTime;
if (diff < serverUpdateInterval){
//sometimes the diff is negative (-100ms for example). Still looking
//into why this could sometimes happen.
if (diff < 0)
diff=0;
nextSongPrepare = false;
setTimeout(newSongStart, diff);
}
}
//calculate how much time left to next show if there is any
if (nextShow.length > 0 && nextShowPrepare){
var diff = nextShow[0].showStartPosixTime - approximateServerTime;
if (diff < serverUpdateInterval){
if (diff < 0)
diff=0;
nextShowPrepare = false;
setTimeout(nextShowStart, diff);
}
}
} }
function updatePlaybar(){ function updatePlaybar(){
@ -159,7 +143,7 @@ function updatePlaybar(){
} else { } else {
$('#current').html($.i18n._("Current")+": <span style='color:red; font-weight:bold'>"+$.i18n._("Live Stream")+"</span>"); $('#current').html($.i18n._("Current")+": <span style='color:red; font-weight:bold'>"+$.i18n._("Live Stream")+"</span>");
} }
} else if (nextSong == null) { } else {
$('#current').html($.i18n._("Current")+": <span style='color:red; font-weight:bold'>"+$.i18n._("Nothing Scheduled")+"</span>"); $('#current').html($.i18n._("Current")+": <span style='color:red; font-weight:bold'>"+$.i18n._("Nothing Scheduled")+"</span>");
} }
} }
@ -223,22 +207,66 @@ function calcAdditionalShowData(show){
} }
} }
function parseItems(obj){ function calculateTimeToNextSong() {
if (approximateServerTime === null) {
return;
}
if (newSongTimeoutId !== null) {
/* We have a previous timeout set, let's unset it */
clearTimeout(newSongTimeoutId);
newSongTimeoutId = null;
}
var diff = nextSong.songStartPosixTime - approximateServerTime;
if (diff < 0) diff=0;
nextSongPrepare = false;
newSongTimeoutId= setTimeout(newSongStart, diff);
}
function calculateTimeToNextShow() {
if (approximateServerTime === null) {
return;
}
if (newShowTimeoutId !== null) {
/* We have a previous timeout set, let's unset it */
clearTimeout(newShowTimeoutId);
newShowTimeoutId = null;
}
var diff = nextShow[0].showStartPosixTime - approximateServerTime;
if (diff < 0) diff=0;
nextShowPrepare = false;
newShowTimeoutId= setTimeout(nextShowStart, diff);
}
function parseItems(obj){
$('#time-zone').text(obj.timezone); $('#time-zone').text(obj.timezone);
previousSong = obj.previous; previousSong = obj.previous;
currentSong = obj.current; currentSong = obj.current;
nextSong = obj.next; nextSong = obj.next;
if (previousSong !== null) if (previousSong !== null) {
calcAdditionalData(previousSong); calcAdditionalData(previousSong);
if (currentSong !== null) }
if (currentSong !== null) {
calcAdditionalData(currentSong); calcAdditionalData(currentSong);
if (nextSong !== null) }
if (nextSong !== null) {
calcAdditionalData(nextSong); calcAdditionalData(nextSong);
calculateTimeToNextSong();
}
calcAdditionalShowData(obj.currentShow); if (obj.currentShow.length > 0) {
calcAdditionalShowData(obj.nextShow); calcAdditionalShowData(obj.currentShow);
}
if (obj.nextShow.length > 0) {
calcAdditionalShowData(obj.nextShow);
calculateTimeToNextShow();
}
currentShow = obj.currentShow; currentShow = obj.currentShow;
nextShow = obj.nextShow; nextShow = obj.nextShow;

View file

@ -144,7 +144,8 @@ var AIRTIME = (function(AIRTIME){
var url = baseUrl+"Playlist/set-cue", var url = baseUrl+"Playlist/set-cue",
lastMod = getModified(), lastMod = getModified(),
type = $('#obj_type').val(), type = $('#obj_type').val(),
li; li,
span;
if (!isTimeValid(cueIn)){ if (!isTimeValid(cueIn)){
$el.find('.cue-in-error').val($.i18n._("please put in a time '00:00:00 (.0)'")).show(); $el.find('.cue-in-error').val($.i18n._("please put in a time '00:00:00 (.0)'")).show();
@ -174,7 +175,27 @@ var AIRTIME = (function(AIRTIME){
return; return;
} }
if (json.cue_error !== undefined) { if (json.cue_error !== undefined) {
showError(span, json.cue_error);
li = $('#side_playlist li[unqid='+id+']');
if (json.code === 0) {
span = $('#spl_cue_in_'+id).find('span');
showError(span, json.cue_error);
span = $('#spl_cue_out_'+id).find('span');
showError(span, json.cue_error);
}
else if (json.code === 1) {
span = $('#spl_cue_in_'+id).find('span');
showError(span, json.cue_error);
}
else if (json.code === 2) {
span = $('#spl_cue_out_'+id).find('span');
showError(span, json.cue_error);
}
return; return;
} }

View file

@ -40,6 +40,14 @@ source_id = ref 0
def create_source() def create_source()
l = request.equeue(id="s#{!source_id}", length=0.5) l = request.equeue(id="s#{!source_id}", length=0.5)
l = cue_cut(l) l = cue_cut(l)
l = audio_to_stereo(id="queue_src", l)
l = amplify(1., override="replay_gain", l)
# the crossfade function controls fade in/out
l = crossfade_airtime(l)
l = on_metadata(notify, l)
sources := list.append([l], !sources) sources := list.append([l], !sources)
server.register(namespace="queues", server.register(namespace="queues",
"s#{!source_id}_skip", "s#{!source_id}_skip",
@ -62,12 +70,6 @@ create_source()
queue = add(!sources, normalize=false) queue = add(!sources, normalize=false)
queue = audio_to_stereo(id="queue_src", queue)
queue = amplify(1., override="replay_gain", queue)
# the crossfade function controls fade in/out
queue = crossfade_airtime(queue)
queue = on_metadata(notify, queue)
output.dummy(fallible=true, queue) output.dummy(fallible=true, queue)
http = input.http_restart(id="http") http = input.http_restart(id="http")