Merge branch '2.4.x'

Conflicts:
	python_apps/pypo/pypopush.py
	python_apps/pypo/schedule/pypofetch.py
	python_apps/pypo/schedule/pypofile.py
	python_apps/pypo/schedule/pypoliqqueue.py
This commit is contained in:
denise 2013-05-30 15:21:32 -04:00
commit 586bdf99e9
71 changed files with 5253 additions and 4614 deletions

View file

@ -24,7 +24,7 @@ class ErrorController extends Zend_Controller_Action
} }
// Log exception, if logger available // Log exception, if logger available
if ($log = $this->getLog()) { if (($log = $this->getLog())) {
$log->crit($this->view->message, $errors->exception); $log->crit($this->view->message, $errors->exception);
} }

View file

@ -167,7 +167,7 @@ class LocaleController extends Zend_Controller_Action
"Are you sure you want to remove the watched folder?" => _("Are you sure you want to remove the watched folder?"), "Are you sure you want to remove the watched folder?" => _("Are you sure you want to remove the watched folder?"),
"This path is currently not accessible." => _("This path is currently not accessible."), "This path is currently not accessible." => _("This path is currently not accessible."),
//preferences/streamsetting.js //preferences/streamsetting.js
"Some steam types require extra configuration. Details about enabling %sAAC+ Support%s or %sOpus Support%s are provided." => _("Some steam types require extra configuration. Details about enabling %sAAC+ Support%s or %sOpus Support%s are provided."), "Some stream types require extra configuration. Details about enabling %sAAC+ Support%s or %sOpus Support%s are provided." => _("Some stream types require extra configuration. Details about enabling %sAAC+ Support%s or %sOpus Support%s are provided."),
"Connected to the streaming server" => _("Connected to the streaming server"), "Connected to the streaming server" => _("Connected to the streaming server"),
"The stream is disabled" => _("The stream is disabled"), "The stream is disabled" => _("The stream is disabled"),
"Getting information from the server..." => _("Getting information from the server..."), "Getting information from the server..." => _("Getting information from the server..."),
@ -193,6 +193,7 @@ class LocaleController extends Zend_Controller_Action
"If your live streaming client does not ask for a username, this field should be 'source'." => _("If your live streaming client does not ask for a username, this field should be 'source'."), "If your live streaming client does not ask for a username, this field should be 'source'." => _("If your live streaming client does not ask for a username, this field should be 'source'."),
"The show instance doesn't exist anymore!" => _("The show instance doesn't exist anymore!"), "The show instance doesn't exist anymore!" => _("The show instance doesn't exist anymore!"),
"Warning: Shows cannot be re-linked" => _("Warning: Shows cannot be re-linked"), "Warning: Shows cannot be re-linked" => _("Warning: Shows cannot be re-linked"),
"By linking your repeating shows any media items scheduled in any repeat show will also get scheduled in the other repeat shows" => _("By linking your repeating shows any media items scheduled in any repeat show will also get scheduled in the other repeat shows"),
//schedule/full-calendar-functions //schedule/full-calendar-functions
//already in schedule/add-show.js //already in schedule/add-show.js
//"The show instance doesn't exist anymore!" => _("The show instance doesn't exist anymore!"), //"The show instance doesn't exist anymore!" => _("The show instance doesn't exist anymore!"),

View file

@ -32,6 +32,7 @@ class PreferenceController extends Zend_Controller_Action
$this->view->statusMsg = ""; $this->view->statusMsg = "";
$form = new Application_Form_Preferences(); $form = new Application_Form_Preferences();
$values = array();
if ($request->isPost()) { if ($request->isPost()) {
$params = $request->getPost(); $params = $request->getPost();
@ -223,6 +224,7 @@ class PreferenceController extends Zend_Controller_Action
$s1_data = array(); $s1_data = array();
$s2_data = array(); $s2_data = array();
$s3_data = array(); $s3_data = array();
$values = array();
foreach($postData as $k=>$v) { foreach($postData as $k=>$v) {
$v = explode('=', urldecode($v)); $v = explode('=', urldecode($v));
if (strpos($v[0], "s1_data") !== false) { if (strpos($v[0], "s1_data") !== false) {

View file

@ -600,6 +600,7 @@ class ScheduleController extends Zend_Controller_Action
$baseUrl = $this->getRequest()->getBaseUrl(); $baseUrl = $this->getRequest()->getBaseUrl();
$url = $file->getRelativeFileUrl($baseUrl).'download/true'; $url = $file->getRelativeFileUrl($baseUrl).'download/true';
$menu = array();
$menu[] = array('action' => array('type' => 'gourl', 'url' => $url), $menu[] = array('action' => array('type' => 'gourl', 'url' => $url),
'title' => _('Download')); 'title' => _('Download'));

View file

@ -41,6 +41,7 @@ class UserController extends Zend_Controller_Action
if ($request->isPost()) { if ($request->isPost()) {
$params = $request->getPost(); $params = $request->getPost();
$postData = explode('&', $params['data']); $postData = explode('&', $params['data']);
$formData = array();
foreach($postData as $k=>$v) { foreach($postData as $k=>$v) {
$v = explode('=', $v); $v = explode('=', $v);
$formData[$v[0]] = urldecode($v[1]); $formData[$v[0]] = urldecode($v[1]);

View file

@ -330,7 +330,7 @@ SQL;
{ {
list($value, $modifier) = $this->getLimitValueAndModifier(); list($value, $modifier) = $this->getLimitValueAndModifier();
if ($modifier == "items") { if ($modifier == "items") {
$length = $value." ".$modifier; $length = $value." "._("items");
} else { } else {
$hour = "00"; $hour = "00";
$mins = "00"; $mins = "00";
@ -1354,6 +1354,16 @@ SQL;
"year" => _("Year") "year" => _("Year")
); );
$modifierOptions = array(
"0" => _("Select modifier"),
"contains" => _("contains"),
"does not contain" => _("does not contain"),
"is" => _("is"),
"is not" => _("is not"),
"starts with" => _("starts with"),
"ends with" => _("ends with")
);
// Load criteria from db // Load criteria from db
$out = CcBlockcriteriaQuery::create()->orderByDbCriteria()->findByDbBlockId($this->id); $out = CcBlockcriteriaQuery::create()->orderByDbCriteria()->findByDbBlockId($this->id);
$storedCrit = array(); $storedCrit = array();
@ -1365,11 +1375,17 @@ SQL;
$extra = $crit->getDbExtra(); $extra = $crit->getDbExtra();
if ($criteria == "limit") { if ($criteria == "limit") {
$storedCrit["limit"] = array("value"=>$value, "modifier"=>$modifier); $storedCrit["limit"] = array("value"=>$value, "modifier"=>_($modifier));
} else if($criteria == "repeat_tracks") { } else if($criteria == "repeat_tracks") {
$storedCrit["repeat_tracks"] = array("value"=>$value); $storedCrit["repeat_tracks"] = array("value"=>$value);
} else { } else {
$storedCrit["crit"][$criteria][] = array("criteria"=>$criteria, "value"=>$value, "modifier"=>$modifier, "extra"=>$extra, "display_name"=>$criteriaOptions[$criteria]); $storedCrit["crit"][$criteria][] = array(
"criteria"=>$criteria,
"value"=>$value,
"modifier"=>$modifier,
"extra"=>$extra,
"display_name"=>$criteriaOptions[$criteria],
"display_modifier"=>$modifierOptions[$modifier]);
} }
} }

View file

@ -4,6 +4,7 @@ class Application_Model_Datatables
{ {
private static function buildWhereClauseForAdvancedSearch($dbname2searchTerm) private static function buildWhereClauseForAdvancedSearch($dbname2searchTerm)
{ {
$where = array();
$where['clause'] = array(); $where['clause'] = array();
$where['params'] = array(); $where['params'] = array();
foreach ($dbname2searchTerm as $dbname=>$term) { foreach ($dbname2searchTerm as $dbname=>$term) {

View file

@ -1075,8 +1075,7 @@ SQL;
$sql .= "END WHERE position IN ($currentPos) and playlist_id=:p1"; $sql .= "END WHERE position IN ($currentPos) and playlist_id=:p1";
Application_Common_Database::prepareAndExecute($sql, array("p1"=>$this->id)); Application_Common_Database::prepareAndExecute($sql, array("p1"=>$this->id));
$result['result'] = 0; return array('result' => 0);
return $result;
} }
public static function getAllPlaylistFiles() public static function getAllPlaylistFiles()

View file

@ -38,6 +38,8 @@ class Application_Model_Preference
$paramMap[':id'] = $userId; $paramMap[':id'] = $userId;
} }
Application_Common_Database::prepareAndExecute("LOCK TABLE cc_pref");
$result = Application_Common_Database::prepareAndExecute($sql, $result = Application_Common_Database::prepareAndExecute($sql,
$paramMap, $paramMap,
Application_Common_Database::COLUMN, Application_Common_Database::COLUMN,

View file

@ -30,7 +30,7 @@ AND file_id is not null
SQL; SQL;
$files = Application_Common_Database::prepareAndExecute( $sql, array()); $files = Application_Common_Database::prepareAndExecute( $sql, array());
$real_files = array(); $real_files = array();
foreach ($files as $f) { foreach ($files as $f) {
$real_files[] = $f['file_id']; $real_files[] = $f['file_id'];
@ -48,7 +48,7 @@ WHERE ends > now() AT TIME ZONE 'UTC'
AND stream_id is not null AND stream_id is not null
SQL; SQL;
$streams = Application_Common_Database::prepareAndExecute( $sql, array()); $streams = Application_Common_Database::prepareAndExecute( $sql, array());
$real_streams = array(); $real_streams = array();
foreach ($streams as $s) { foreach ($streams as $s) {
$real_streams[] = $s['stream_id']; $real_streams[] = $s['stream_id'];
@ -322,7 +322,8 @@ SQL;
ft.album_title AS file_album_title, ft.album_title AS file_album_title,
ft.length AS file_length, ft.length AS file_length,
ft.file_exists AS file_exists, ft.file_exists AS file_exists,
ft.mime AS file_mime ft.mime AS file_mime,
ft.soundcloud_id AS soundcloud_id
SQL; SQL;
$filesJoin = <<<SQL $filesJoin = <<<SQL
cc_schedule AS sched cc_schedule AS sched
@ -357,7 +358,8 @@ SQL;
ws.description AS file_album_title, ws.description AS file_album_title,
ws.length AS file_length, ws.length AS file_length,
't'::BOOL AS file_exists, 't'::BOOL AS file_exists,
ws.mime as file_mime ws.mime AS file_mime,
(SELECT NULL::integer AS soundcloud_id)
SQL; SQL;
$streamJoin = <<<SQL $streamJoin = <<<SQL
cc_schedule AS sched cc_schedule AS sched
@ -391,17 +393,17 @@ SQL;
$showPredicate = ""; $showPredicate = "";
if (count($p_shows) > 0) { if (count($p_shows) > 0) {
$params = array(); $params = array();
$map = array(); $map = array();
for ($i = 0, $len = count($p_shows); $i < $len; $i++) { for ($i = 0, $len = count($p_shows); $i < $len; $i++) {
$holder = "show_".$i; $holder = ":show_".$i;
$params[] = $holder; $params[] = $holder;
$map[$holder] = $p_shows[$i]; $map[$holder] = $p_shows[$i];
} }
$showPredicate = " AND show_id IN (".implode(",", $params).")"; $showPredicate = " AND show_id IN (".implode(",", $params).")";
$paramMap = $paramMap + $map; $paramMap = $paramMap + $map;
} else if (count($p_show_instances) > 0) { } else if (count($p_show_instances) > 0) {
@ -448,13 +450,13 @@ SQL;
":ts_6" => $p_end_str, ":ts_6" => $p_end_str,
); );
$paramMap = $paramMap + $map; $paramMap = $paramMap + $map;
$rows = Application_Common_Database::prepareAndExecute( $rows = Application_Common_Database::prepareAndExecute(
$sql, $sql,
$paramMap, $paramMap,
Application_Common_Database::ALL Application_Common_Database::ALL
); );
return $rows; return $rows;
} }
@ -475,7 +477,7 @@ SQL;
$sql .= " WHERE id=:pid"; $sql .= " WHERE id=:pid";
$map = array(":pid" => $p_id); $map = array(":pid" => $p_id);
Application_Common_Database::prepareAndExecute($sql, $map, Application_Common_Database::prepareAndExecute($sql, $map,
Application_Common_Database::EXECUTE); Application_Common_Database::EXECUTE);
} }
@ -501,9 +503,9 @@ SQL;
{ {
$sql = "SELECT count(*) as cnt FROM cc_schedule"; $sql = "SELECT count(*) as cnt FROM cc_schedule";
$res = Application_Common_Database::prepareAndExecute($sql, array(), $res = Application_Common_Database::prepareAndExecute($sql, array(),
Application_Common_Database::COLUMN); Application_Common_Database::COLUMN);
return $res; return $res;
} }
@ -706,7 +708,7 @@ SQL;
$key = "{$time}_{$i}"; $key = "{$time}_{$i}";
$i++; $i++;
} }
$data["media"][$key] = $item; $data["media"][$key] = $item;
} }
@ -755,7 +757,7 @@ SQL;
$replay_gain = is_null($item["replay_gain"]) ? "0": $item["replay_gain"]; $replay_gain = is_null($item["replay_gain"]) ? "0": $item["replay_gain"];
$replay_gain += Application_Model_Preference::getReplayGainModifier(); $replay_gain += Application_Model_Preference::getReplayGainModifier();
if ( !Application_Model_Preference::GetEnableReplayGain() ) { if ( !Application_Model_Preference::GetEnableReplayGain() ) {
$replay_gain = 0; $replay_gain = 0;
} }
@ -775,7 +777,7 @@ SQL;
'replay_gain' => $replay_gain, 'replay_gain' => $replay_gain,
'independent_event' => $independent_event, 'independent_event' => $independent_event,
); );
if ($schedule_item['cue_in'] > $schedule_item['cue_out']) { if ($schedule_item['cue_in'] > $schedule_item['cue_out']) {
$schedule_item['cue_in'] = $schedule_item['cue_out']; $schedule_item['cue_in'] = $schedule_item['cue_out'];
} }
@ -915,10 +917,10 @@ SQL;
} else { } else {
throw new Exception("Unknown schedule type: ".print_r($item, true)); throw new Exception("Unknown schedule type: ".print_r($item, true));
} }
} }
} }
/* Check if two events are less than or equal to 1 second apart /* Check if two events are less than or equal to 1 second apart
*/ */
public static function areEventsLinked($event1, $event2) { public static function areEventsLinked($event1, $event2) {
@ -996,7 +998,7 @@ SQL;
public static function deleteAll() public static function deleteAll()
{ {
$sql = "TRUNCATE TABLE cc_schedule"; $sql = "TRUNCATE TABLE cc_schedule";
Application_Common_Database::prepareAndExecute($sql, array(), Application_Common_Database::prepareAndExecute($sql, array(),
Application_Common_Database::EXECUTE); Application_Common_Database::EXECUTE);
} }
@ -1279,14 +1281,14 @@ SQL;
$update=false, $instanceId=null, $showId=null) $update=false, $instanceId=null, $showId=null)
{ {
$overlapping = false; $overlapping = false;
$params = array( $params = array(
':show_end1' => $show_end->format('Y-m-d H:i:s'), ':show_end1' => $show_end->format('Y-m-d H:i:s'),
':show_end2' => $show_end->format('Y-m-d H:i:s'), ':show_end2' => $show_end->format('Y-m-d H:i:s'),
':show_end3' => $show_end->format('Y-m-d H:i:s') ':show_end3' => $show_end->format('Y-m-d H:i:s')
); );
/* If a show is being edited, exclude it from the query /* If a show is being edited, exclude it from the query
* In both cases (new and edit) we only grab shows that * In both cases (new and edit) we only grab shows that
* are scheduled 2 days prior * are scheduled 2 days prior
@ -1357,18 +1359,18 @@ SQL;
return 'file'; return 'file';
} }
} }
public static function GetFileId($p_scheduleId) public static function GetFileId($p_scheduleId)
{ {
$scheduledItem = CcScheduleQuery::create()->findPK($p_scheduleId); $scheduledItem = CcScheduleQuery::create()->findPK($p_scheduleId);
return $scheduledItem->getDbFileId(); return $scheduledItem->getDbFileId();
} }
public static function GetStreamId($p_scheduleId) public static function GetStreamId($p_scheduleId)
{ {
$scheduledItem = CcScheduleQuery::create()->findPK($p_scheduleId); $scheduledItem = CcScheduleQuery::create()->findPK($p_scheduleId);
return $scheduledItem->getDbStreamId(); return $scheduledItem->getDbStreamId();
} }
} }

View file

@ -85,6 +85,9 @@ class Application_Model_Scheduler
$nowEpoch = floatval($this->nowDT->format("U.u")); $nowEpoch = floatval($this->nowDT->format("U.u"));
$schedInfo = array();
$instanceInfo = array();
for ($i = 0; $i < count($items); $i++) { for ($i = 0; $i < count($items); $i++) {
$id = $items[$i]["id"]; $id = $items[$i]["id"];
@ -103,7 +106,7 @@ class Application_Model_Scheduler
} }
$schedIds = array(); $schedIds = array();
if (isset($schedInfo)) { if (count($schedInfo) > 0) {
$schedIds = array_keys($schedInfo); $schedIds = array_keys($schedInfo);
} }
$schedItems = CcScheduleQuery::create()->findPKs($schedIds, $this->con); $schedItems = CcScheduleQuery::create()->findPKs($schedIds, $this->con);
@ -527,10 +530,6 @@ 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) {
$id = intval($schedule["id"]); $id = intval($schedule["id"]);
@ -592,6 +591,7 @@ class Application_Model_Scheduler
$instance_sql); $instance_sql);
} }
$excludePositions = array();
foreach($instances as &$instance) { foreach($instances as &$instance) {
$instanceId = $instance["id"]; $instanceId = $instance["id"];
if ($id !== 0) { if ($id !== 0) {
@ -612,15 +612,24 @@ class Application_Model_Scheduler
$instanceId); $instanceId);
$pos++; $pos++;
/* Show is not empty so we need to apply crossfades
* for the first inserted item
*/
$applyCrossfades = true;
} }
//selected empty row to add after //selected empty row to add after
else { else {
$showStartDT = new DateTime($instance["starts"], new DateTimeZone("UTC")); $showStartDT = new DateTime($instance["starts"], new DateTimeZone("UTC"));
$nextStartDT = $this->findNextStartTime($showStartDT, $instanceId); $nextStartDT = $this->findNextStartTime($showStartDT, $instanceId);
//show is empty so start position counter at 0 //first item in show so start position counter at 0
$pos = 0; $pos = 0;
$adjustSched = false;
/* Show is empty so we don't need to calculate crossfades
* for the first inserted item
*/
$applyCrossfades = false;
} }
if (!in_array($instanceId, $affectedShowInstances)) { if (!in_array($instanceId, $affectedShowInstances)) {
@ -635,7 +644,12 @@ class Application_Model_Scheduler
$pstart = microtime(true); $pstart = microtime(true);
$initalStartDT = clone $nextStartDT; if ($applyCrossfades) {
$initalStartDT = clone $this->findTimeDifference(
$nextStartDT, $this->crossfadeDuration);
} else {
$initalStartDT = clone $nextStartDT;
}
$pend = microtime(true); $pend = microtime(true);
Logging::debug("finding all following items."); Logging::debug("finding all following items.");
@ -658,6 +672,7 @@ class Application_Model_Scheduler
//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'])) {
$adjustFromDT = clone $nextStartDT;
$doUpdate = true; $doUpdate = true;
$movedItem_sql = "SELECT * FROM cc_schedule ". $movedItem_sql = "SELECT * FROM cc_schedule ".
@ -693,11 +708,9 @@ class Application_Model_Scheduler
$file["fadein"] = $sched["fade_in"]; $file["fadein"] = $sched["fade_in"];
$file["fadeout"] = $sched["fade_out"]; $file["fadeout"] = $sched["fade_out"];
} else { } else {
//$sched = new CcSchedule();
$doInsert = true; $doInsert = true;
} }
$endTimeDT = $this->findEndTime($nextStartDT, $file['cliplength']);
// default fades are in seconds // default fades are in seconds
// we need to convert to '00:00:00' format // we need to convert to '00:00:00' format
$file['fadein'] = Application_Common_DateHelper::secondsToPlaylistTime($file['fadein']); $file['fadein'] = Application_Common_DateHelper::secondsToPlaylistTime($file['fadein']);
@ -715,6 +728,18 @@ class Application_Model_Scheduler
default: break; default: break;
} }
if ($applyCrossfades) {
$nextStartDT = $this->findTimeDifference($nextStartDT,
$this->crossfadeDuration);
$endTimeDT = $this->findEndTime($nextStartDT, $file['cliplength']);
$endTimeDT = $this->findTimeDifference($endTimeDT, $this->crossfadeDuration);
/* Set it to false because the rest of the crossfades
* will be applied after we insert each item
*/
$applyCrossfades = false;
}
$endTimeDT = $this->findEndTime($nextStartDT, $file['cliplength']);
if ($doInsert) { if ($doInsert) {
$values[] = "(". $values[] = "(".
"'{$nextStartDT->format("Y-m-d H:i:s")}', ". "'{$nextStartDT->format("Y-m-d H:i:s")}', ".
@ -753,12 +778,15 @@ class Application_Model_Scheduler
$insert_sql = "INSERT INTO cc_schedule ". $insert_sql = "INSERT INTO cc_schedule ".
"(starts, ends, cue_in, cue_out, fade_in, fade_out, ". "(starts, ends, cue_in, cue_out, fade_in, fade_out, ".
"clip_length, position, instance_id, file_id, stream_id) VALUES ". "clip_length, position, instance_id, file_id, stream_id) VALUES ".
implode($values, ","); implode($values, ",")." RETURNING id";
Application_Common_Database::prepareAndExecute(
$insert_sql, array(), Application_Common_Database::EXECUTE);
}
$stmt = $this->con->prepare($insert_sql);
if ($stmt->execute()) {
foreach ($stmt->fetchAll() as $row) {
$excludeIds[] = $row["id"];
}
};
}
// update is_scheduled flag for each cc_file // update is_scheduled flag for each cc_file
$fileIds = array(); $fileIds = array();
foreach ($filesToInsert as &$file) { foreach ($filesToInsert as &$file) {
@ -779,6 +807,7 @@ class Application_Model_Scheduler
} }
if ($adjustSched === true) { if ($adjustSched === true) {
$followingItems_sql = "SELECT * FROM cc_schedule ". $followingItems_sql = "SELECT * FROM cc_schedule ".
"WHERE starts >= '{$initalStartDT->format("Y-m-d H:i:s.u")}' ". "WHERE starts >= '{$initalStartDT->format("Y-m-d H:i:s.u")}' ".
"AND instance_id = {$instanceId} "; "AND instance_id = {$instanceId} ";
@ -786,7 +815,6 @@ class Application_Model_Scheduler
$followingItems_sql .= "AND id NOT IN (". implode($excludeIds, ",").") "; $followingItems_sql .= "AND id NOT IN (". implode($excludeIds, ",").") ";
} }
$followingItems_sql .= "ORDER BY starts"; $followingItems_sql .= "ORDER BY starts";
$followingSchedItems = Application_Common_Database::prepareAndExecute( $followingSchedItems = Application_Common_Database::prepareAndExecute(
$followingItems_sql); $followingItems_sql);
@ -795,6 +823,7 @@ class Application_Model_Scheduler
//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["clip_length"]); $endTimeDT = $this->findEndTime($nextStartDT, $item["clip_length"]);
$endTimeDT = $this->findTimeDifference($endTimeDT, $this->crossfadeDuration);
$update_sql = "UPDATE cc_schedule SET ". $update_sql = "UPDATE cc_schedule SET ".
"starts = '{$nextStartDT->format("Y-m-d H:i:s")}', ". "starts = '{$nextStartDT->format("Y-m-d H:i:s")}', ".
"ends = '{$endTimeDT->format("Y-m-d H:i:s")}', ". "ends = '{$endTimeDT->format("Y-m-d H:i:s")}', ".
@ -814,11 +843,6 @@ class Application_Model_Scheduler
}//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));

View file

@ -388,6 +388,7 @@ class Application_Model_ShowBuilder
$outdated = false; $outdated = false;
$shows = Application_Model_Show::getShows($this->startDT, $this->endDT); $shows = Application_Model_Show::getShows($this->startDT, $this->endDT);
$include = array();
if ($this->opts["showFilter"] !== 0) { if ($this->opts["showFilter"] !== 0) {
$include[] = $this->opts["showFilter"]; $include[] = $this->opts["showFilter"];
} elseif ($this->opts["myShows"] === 1) { } elseif ($this->opts["myShows"] === 1) {

View file

@ -352,10 +352,10 @@ SQL;
); );
//only need to check overlap if show increased in size. //only need to check overlap if show increased in size.
if (strtotime($new_ends) > strtotime($ends)) { if (strtotime($now_ends) > strtotime($ends)) {
$utcStartDateTime = new DateTime($ends, new DateTimeZone("UTC")); $utcStartDateTime = new DateTime($ends, new DateTimeZone("UTC"));
$utcEndDateTime = new DateTime($new_ends, new DateTimeZone("UTC")); $utcEndDateTime = new DateTime($now_ends, new DateTimeZone("UTC"));
$overlap = Application_Model_Show::getShows($utcStartDateTime, $utcEndDateTime); $overlap = Application_Model_Show::getShows($utcStartDateTime, $utcEndDateTime);
@ -381,7 +381,7 @@ SQL;
} }
$this->setShowEnd($new_ends); $this->setShowEnd($now_ends);
Application_Model_RabbitMq::PushSchedule(); Application_Model_RabbitMq::PushSchedule();
} }

View file

@ -150,7 +150,7 @@ class Application_Model_StoredFile
} }
} }
$dbMd[constant($mdConst)] = $mdValue; $dbMd[constant($mdConst)] = $mdValue;
} }
} }
$this->setDbColMetadata($dbMd); $this->setDbColMetadata($dbMd);
@ -214,7 +214,7 @@ class Application_Model_StoredFile
if (isset($this->_dbMD[$dbColumn])) { if (isset($this->_dbMD[$dbColumn])) {
$propelColumn = $this->_dbMD[$dbColumn]; $propelColumn = $this->_dbMD[$dbColumn];
$method = "set$propelColumn"; $method = "set$propelColumn";
/* We need to set track_number to null if it is an empty string /* We need to set track_number to null if it is an empty string
* because propel defaults empty strings to zeros */ * because propel defaults empty strings to zeros */
if ($dbColumn == "track_number" && empty($mdValue)) $mdValue = null; if ($dbColumn == "track_number" && empty($mdValue)) $mdValue = null;
@ -330,7 +330,7 @@ SQL;
$stmt = $con->prepare($sql); $stmt = $con->prepare($sql);
$stmt->bindParam(':file_id', $this->id, PDO::PARAM_INT); $stmt->bindParam(':file_id', $this->id, PDO::PARAM_INT);
if ($stmt->execute()) { if ($stmt->execute()) {
$ids = $stmt->fetchAll(); $ids = $stmt->fetchAll();
} else { } else {
@ -386,7 +386,7 @@ SQL;
// set hidden flag to true // set hidden flag to true
$this->_file->setDbHidden(true); $this->_file->setDbHidden(true);
$this->_file->save(); $this->_file->save();
// need to explicitly update any playlist's and block's length // need to explicitly update any playlist's and block's length
// that contains the file getting deleted // that contains the file getting deleted
$fileId = $this->_file->getDbId(); $fileId = $this->_file->getDbId();
@ -396,7 +396,7 @@ SQL;
$pl->setDbLength($pl->computeDbLength(Propel::getConnection(CcPlaylistPeer::DATABASE_NAME))); $pl->setDbLength($pl->computeDbLength(Propel::getConnection(CcPlaylistPeer::DATABASE_NAME)));
$pl->save(); $pl->save();
} }
$blRows = CcBlockcontentsQuery::create()->filterByDbFileId($fileId)->find(); $blRows = CcBlockcontentsQuery::create()->filterByDbFileId($fileId)->find();
foreach ($blRows as $row) { foreach ($blRows as $row) {
$bl = CcBlockQuery::create()->filterByDbId($row->getDbBlockId())->findOne(); $bl = CcBlockQuery::create()->filterByDbId($row->getDbBlockId())->findOne();
@ -506,19 +506,19 @@ SQL;
public function getFileUrl() public function getFileUrl()
{ {
$CC_CONFIG = Config::getConfig(); $CC_CONFIG = Config::getConfig();
$protocol = empty($_SERVER['HTTPS']) ? "http" : "https"; $protocol = empty($_SERVER['HTTPS']) ? "http" : "https";
$serverName = $_SERVER['SERVER_NAME']; $serverName = $_SERVER['SERVER_NAME'];
$serverPort = $_SERVER['SERVER_PORT']; $serverPort = $_SERVER['SERVER_PORT'];
$subDir = $CC_CONFIG['baseDir']; $subDir = $CC_CONFIG['baseDir'];
if ($subDir[0] === "/") { if ($subDir[0] === "/") {
$subDir = substr($subDir, 1, strlen($subDir) - 1); $subDir = substr($subDir, 1, strlen($subDir) - 1);
} }
$baseUrl = "{$protocol}://{$serverName}:{$serverPort}/{$subDir}"; $baseUrl = "{$protocol}://{$serverName}:{$serverPort}/{$subDir}";
return $this->getRelativeFileUrl($baseUrl); return $this->getRelativeFileUrl($baseUrl);
} }
@ -641,7 +641,7 @@ SQL;
public static function searchLibraryFiles($datatables) public static function searchLibraryFiles($datatables)
{ {
$baseUrl = Application_Common_OsPath::getBaseDir(); $baseUrl = Application_Common_OsPath::getBaseDir();
$con = Propel::getConnection(CcFilesPeer::DATABASE_NAME); $con = Propel::getConnection(CcFilesPeer::DATABASE_NAME);
$displayColumns = self::getLibraryColumns(); $displayColumns = self::getLibraryColumns();
@ -796,7 +796,7 @@ SQL;
//soundcloud status //soundcloud status
$file = Application_Model_StoredFile::RecallById($row['id']); $file = Application_Model_StoredFile::RecallById($row['id']);
$row['soundcloud_status'] = $file->getSoundCloudId(); $row['soundcloud_id'] = $file->getSoundCloudId();
// for audio preview // for audio preview
$row['audioFile'] = $row['id'].".".pathinfo($row['filepath'], PATHINFO_EXTENSION); $row['audioFile'] = $row['id'].".".pathinfo($row['filepath'], PATHINFO_EXTENSION);
@ -893,7 +893,7 @@ SQL;
$in = fopen($_FILES['file']['tmp_name'], "rb"); $in = fopen($_FILES['file']['tmp_name'], "rb");
if ($in) { if ($in) {
while ($buff = fread($in, 4096)) while (($buff = fread($in, 4096)))
fwrite($out, $buff); fwrite($out, $buff);
} else } else
die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": _("Failed to open input stream.")}, "id" : "id"}'); die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": _("Failed to open input stream.")}, "id" : "id"}');
@ -912,7 +912,7 @@ SQL;
$in = fopen("php://input", "rb"); $in = fopen("php://input", "rb");
if ($in) { if ($in) {
while ($buff = fread($in, 4096)) while (($buff = fread($in, 4096)))
fwrite($out, $buff); fwrite($out, $buff);
} else } else
die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": _("Failed to open input stream.")}, "id" : "id"}'); die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": _("Failed to open input stream.")}, "id" : "id"}');
@ -961,6 +961,7 @@ SQL;
// Check if we have enough space before copying // Check if we have enough space before copying
if (!self::isEnoughDiskSpaceToCopy($stor, $audio_file)) { if (!self::isEnoughDiskSpaceToCopy($stor, $audio_file)) {
$freeSpace = disk_free_space($stor); $freeSpace = disk_free_space($stor);
$fileSize = filesize($audio_file);
return array("code" => 107, return array("code" => 107,
"message" => sprintf(_("The file was not uploaded, there is " "message" => sprintf(_("The file was not uploaded, there is "
@ -1028,7 +1029,7 @@ SQL;
$LIQUIDSOAP_ERRORS = array('TagLib: MPEG::Properties::read() -- Could not find a valid last MPEG frame in the stream.'); $LIQUIDSOAP_ERRORS = array('TagLib: MPEG::Properties::read() -- Could not find a valid last MPEG frame in the stream.');
// Ask Liquidsoap if file is playable // Ask Liquidsoap if file is playable
$ls_command = sprintf('/usr/bin/airtime-liquidsoap -v -c "output.dummy(audio_to_stereo(single(%s)))" 2>&1', $ls_command = sprintf('/usr/bin/airtime-liquidsoap -v -c "output.dummy(audio_to_stereo(single(%s)))" 2>&1',
escapeshellarg($audio_file)); escapeshellarg($audio_file));
$command = "export PATH=/usr/local/bin:/usr/bin:/bin/usr/bin/ && $ls_command"; $command = "export PATH=/usr/local/bin:/usr/bin:/bin/usr/bin/ && $ls_command";
@ -1068,14 +1069,14 @@ SQL;
$stmt = $con->prepare($sql); $stmt = $con->prepare($sql);
$stmt->bindParam(':dir_id', $dir_id); $stmt->bindParam(':dir_id', $dir_id);
if ($stmt->execute()) { if ($stmt->execute()) {
$rows = $stmt->fetchAll(); $rows = $stmt->fetchAll();
} else { } else {
$msg = implode(',', $stmt->errorInfo()); $msg = implode(',', $stmt->errorInfo());
throw new Exception("Error: $msg"); throw new Exception("Error: $msg");
} }
$results = array(); $results = array();
foreach ($rows as $row) { foreach ($rows as $row) {
$results[] = $row["fp"]; $results[] = $row["fp"];
@ -1111,10 +1112,10 @@ SQL;
return $rows; return $rows;
} }
public static function getAllFilesWithoutSilan() { public static function getAllFilesWithoutSilan() {
$con = Propel::getConnection(); $con = Propel::getConnection();
$sql = <<<SQL $sql = <<<SQL
SELECT f.id, SELECT f.id,
m.directory || f.filepath AS fp m.directory || f.filepath AS fp
@ -1124,14 +1125,14 @@ WHERE file_exists = 'TRUE'
AND silan_check IS FALSE Limit 100 AND silan_check IS FALSE Limit 100
SQL; SQL;
$stmt = $con->prepare($sql); $stmt = $con->prepare($sql);
if ($stmt->execute()) { if ($stmt->execute()) {
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
} else { } else {
$msg = implode(',', $stmt->errorInfo()); $msg = implode(',', $stmt->errorInfo());
throw new Exception("Error: $msg"); throw new Exception("Error: $msg");
} }
return $rows; return $rows;
} }
@ -1227,7 +1228,7 @@ SQL;
->save(); ->save();
} }
// This method seems to be unsued everywhere so I've commented it out // This method seems to be unsued everywhere so I've commented it out
// If it's absence does not have any effect then it will be completely // If it's absence does not have any effect then it will be completely
// removed soon // removed soon
@ -1255,7 +1256,7 @@ SQL;
$description = $file->getDbTrackTitle(); $description = $file->getDbTrackTitle();
$tag = array(); $tag = array();
$genre = $file->getDbGenre(); $genre = $file->getDbGenre();
$release = $file->getDbYear(); $release = $file->getDbUtime();
try { try {
$soundcloud = new Application_Model_Soundcloud(); $soundcloud = new Application_Model_Soundcloud();
$soundcloud_res = $soundcloud->uploadTrack( $soundcloud_res = $soundcloud->uploadTrack(
@ -1284,7 +1285,7 @@ SQL;
} }
} }
} }
public static function setIsPlaylist($p_playlistItems, $p_type, $p_status) { public static function setIsPlaylist($p_playlistItems, $p_type, $p_status) {
foreach ($p_playlistItems as $item) { foreach ($p_playlistItems as $item) {
$file = self::RecallById($item->getDbFileId()); $file = self::RecallById($item->getDbFileId());
@ -1302,7 +1303,7 @@ SQL;
} }
} }
} }
public static function setIsScheduled($p_scheduleItem, $p_status, public static function setIsScheduled($p_scheduleItem, $p_status,
$p_fileId=null) { $p_fileId=null) {

View file

@ -125,6 +125,7 @@ class Application_Model_Systemstatus
public static function GetPlatformInfo() public static function GetPlatformInfo()
{ {
$keys = array("release", "machine", "memory", "swap"); $keys = array("release", "machine", "memory", "swap");
$data = array();
foreach ($keys as $key) { foreach ($keys as $key) {
$data[$key] = "UNKNOWN"; $data[$key] = "UNKNOWN";
} }
@ -212,7 +213,7 @@ class Application_Model_Systemstatus
public static function GetDiskInfo() public static function GetDiskInfo()
{ {
$partions = array(); $partitions = array();
/* First lets get all the watched directories. Then we can group them /* First lets get all the watched directories. Then we can group them
* into the same partitions by comparing the partition sizes. */ * into the same partitions by comparing the partition sizes. */

View file

@ -226,7 +226,7 @@ class Application_Model_User
public function deleteAllFiles() public function deleteAllFiles()
{ {
$my_files = $this->getOwnedFiles(); $my_files = $this->getOwnedFiles();
foreach ($files as $file) { foreach ($my_files as $file) {
$file->delete(); $file->delete();
} }
} }

View file

@ -57,6 +57,14 @@ class CcFiles extends BaseCcFiles {
return $this; return $this;
} }
public function setDbTrackNumber($v)
{
$max = pow(2, 31)-1;
$v = ($v > $max) ? $max : $v;
return parent::setDbTrackNumber($v);
}
// returns true if the file exists and is not hidden // returns true if the file exists and is not hidden
public function visible() { public function visible() {
return $this->getDbFileExists() && !$this->getDbHidden(); return $this->getDbFileExists() && !$this->getDbHidden();

View file

@ -177,10 +177,6 @@ class Application_Service_SchedulerService
$timeFilled = Application_Common_Database::prepareAndExecute( $timeFilled = Application_Common_Database::prepareAndExecute(
$timeFilled_sql, array(), Application_Common_Database::COLUMN); $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
$values = array(); $values = array();
foreach ($instanceIds as $id) { foreach ($instanceIds as $id) {
@ -210,7 +206,8 @@ class Application_Service_SchedulerService
if (is_null($item["file_id"])) { if (is_null($item["file_id"])) {
$item["file_id"] = "null"; $item["file_id"] = "null";
} elseif (is_null($item["stream_id"])) { }
if (is_null($item["stream_id"])) {
$item["stream_id"] = "null"; $item["stream_id"] = "null";
} }
@ -240,11 +237,6 @@ class Application_Service_SchedulerService
Application_Common_Database::prepareAndExecute( Application_Common_Database::prepareAndExecute(
$insert_sql, array(), Application_Common_Database::EXECUTE); $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 //update time_filled in cc_show_instances
$now = gmdate("Y-m-d H:i:s"); $now = gmdate("Y-m-d H:i:s");
$update_sql = "UPDATE cc_show_instances SET ". $update_sql = "UPDATE cc_show_instances SET ".

View file

@ -99,8 +99,9 @@ class Application_Service_ShowFormService
public function delegateShowFormPopulation($forms) public function delegateShowFormPopulation($forms)
{ {
$this->populateFormWhat($forms["what"]); $this->populateFormWhat($forms["what"]);
$this->populateFormWhen($forms["when"]); //local show start DT
$this->populateFormRepeats($forms["repeats"]); $showStart = $this->populateFormWhen($forms["when"]);
$this->populateFormRepeats($forms["repeats"], $showStart);
$this->populateFormWho($forms["who"]); $this->populateFormWho($forms["who"]);
$this->populateFormStyle($forms["style"]); $this->populateFormStyle($forms["style"]);
$this->populateFormLive($forms["live"]); $this->populateFormLive($forms["live"]);
@ -136,6 +137,9 @@ class Application_Service_ShowFormService
$form->disableStartDateAndTime(); $form->disableStartDateAndTime();
} else { } else {
list($showStart, $showEnd) = $this->getNextFutureRepeatShowTime(); list($showStart, $showEnd) = $this->getNextFutureRepeatShowTime();
if ($this->hasShowStarted($showStart)) {
$form->disableStartDateAndTime();
}
} }
} }
@ -147,6 +151,8 @@ class Application_Service_ShowFormService
'add_show_end_time' => $showEnd->format("H:i"), 'add_show_end_time' => $showEnd->format("H:i"),
'add_show_duration' => $ccShowDay->formatDuration(true), 'add_show_duration' => $ccShowDay->formatDuration(true),
'add_show_repeats' => $ccShowDay->isRepeating() ? 1 : 0)); 'add_show_repeats' => $ccShowDay->isRepeating() ? 1 : 0));
return $showStart;
} }
private function populateInstanceFormWhen($form) private function populateInstanceFormWhen($form)
@ -179,7 +185,13 @@ class Application_Service_ShowFormService
$form->getElement('add_show_repeats')->setOptions(array("disabled" => true)); $form->getElement('add_show_repeats')->setOptions(array("disabled" => true));
} }
private function populateFormRepeats($form) /**
*
* Enter description here ...
* @param $form
* @param DateTime $nextFutureShowStart user's local timezone
*/
private function populateFormRepeats($form, $nextFutureShowStart)
{ {
$ccShowDays = $this->ccShow->getCcShowDays(); $ccShowDays = $this->ccShow->getCcShowDays();
@ -219,6 +231,14 @@ class Application_Service_ShowFormService
if (!$this->ccShow->isLinkable() || $this->ccShow->isRecorded()) { if (!$this->ccShow->isLinkable() || $this->ccShow->isRecorded()) {
$form->getElement('add_show_linked')->setOptions(array('disabled' => true)); $form->getElement('add_show_linked')->setOptions(array('disabled' => true));
} }
/* Because live editing of a linked show is disabled, we will disable
* the linking option if the current show is being edited. We don't
* want the user to suddenly not be able to edit the current show
*/
if ($this->hasShowStarted($nextFutureShowStart)) {
$form->getElement('add_show_linked')->setOptions(array('disabled' => true));
}
} }
private function populateFormWho($form) private function populateFormWho($form)
@ -295,6 +315,22 @@ class Application_Service_ShowFormService
$form->populate($formValues); $form->populate($formValues);
} }
/**
*
* Enter description here ...
* @param DateTime $showStart user's local time
*/
private function hasShowStarted($p_showStart) {
$showStart = clone $p_showStart;
$showStart->setTimeZone(new DateTimeZone("UTC"));
if ($showStart->format("Y-m-d H:i:s") < gmdate("Y-m-d H:i:s")) {
return true;
} else {
return false;
}
}
/** /**
* *
* Before we send the form data in for validation, there * Before we send the form data in for validation, there

View file

@ -999,7 +999,7 @@ SQL;
} }
if ($this->isRebroadcast) { if ($this->isRebroadcast) {
$this->createRebroadcastInstances($showDay, $date, $ccShowInstance->getDbId()); $this->createRebroadcastInstances($showDay, $start, $ccShowInstance->getDbId());
} }
} }
$start = $this->getNextMonthlyMonthlyRepeatDate($start, $timezone, $showDay->getDbStartTime()); $start = $this->getNextMonthlyMonthlyRepeatDate($start, $timezone, $showDay->getDbStartTime());

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 801 B

After

Width:  |  Height:  |  Size: 481 B

Before After
Before After

View file

@ -125,7 +125,7 @@ select {
.airtime_auth_help_icon, .custom_auth_help_icon, .stream_username_help_icon, .airtime_auth_help_icon, .custom_auth_help_icon, .stream_username_help_icon,
.playlist_type_help_icon, .master_username_help_icon, .repeat_tracks_help_icon, .playlist_type_help_icon, .master_username_help_icon, .repeat_tracks_help_icon,
.admin_username_help_icon, .stream_type_help_icon { .admin_username_help_icon, .stream_type_help_icon, .show_linking_help_icon {
cursor: help; cursor: help;
position: relative; position: relative;
display:inline-block; zoom:1; display:inline-block; zoom:1;

View file

@ -262,14 +262,14 @@ function parseItems(obj){
if (obj.currentShow.length > 0) { if (obj.currentShow.length > 0) {
calcAdditionalShowData(obj.currentShow); calcAdditionalShowData(obj.currentShow);
currentShow = obj.currentShow;
} }
if (obj.nextShow.length > 0) { if (obj.nextShow.length > 0) {
calcAdditionalShowData(obj.nextShow); calcAdditionalShowData(obj.nextShow);
nextShow = obj.nextShow;
calculateTimeToNextShow(); calculateTimeToNextShow();
} }
currentShow = obj.currentShow;
nextShow = obj.nextShow;
var schedulePosixTime = convertDateToPosixTime(obj.schedulerTime); var schedulePosixTime = convertDateToPosixTime(obj.schedulerTime);
var date = new Date(); var date = new Date();

View file

@ -593,12 +593,12 @@ var AIRTIME = (function(AIRTIME) {
"fnRowCallback": AIRTIME.library.fnRowCallback, "fnRowCallback": AIRTIME.library.fnRowCallback,
"fnCreatedRow": function( nRow, aData, iDataIndex ) { "fnCreatedRow": function( nRow, aData, iDataIndex ) {
//add soundcloud icon //add soundcloud icon
if (aData.soundcloud_status !== undefined) { if (aData.soundcloud_id !== undefined) {
if (aData.soundcloud_status === "-2") { if (aData.soundcloud_id === "-2") {
$(nRow).find("td.library_title").append('<span class="small-icon progress"/>'); $(nRow).find("td.library_title").append('<span class="small-icon progress"/>');
} else if (aData.soundcloud_status === "-3") { } else if (aData.soundcloud_id === "-3") {
$(nRow).find("td.library_title").append('<span class="small-icon sc-error"/>'); $(nRow).find("td.library_title").append('<span class="small-icon sc-error"/>');
} else if (aData.soundcloud_status !== null) { } else if (aData.soundcloud_id !== null) {
$(nRow).find("td.library_title").append('<span class="small-icon soundcloud"/>'); $(nRow).find("td.library_title").append('<span class="small-icon soundcloud"/>');
} }
} }
@ -1126,7 +1126,6 @@ function checkLibrarySCUploadStatus(){
else if (json.sc_id == "-3") { else if (json.sc_id == "-3") {
span.removeClass("progress").addClass("sc-error"); span.removeClass("progress").addClass("sc-error");
} }
setTimeout(checkLibrarySCUploadStatus, 5000);
} }
function checkSCUploadStatusRequest() { function checkSCUploadStatusRequest() {
@ -1138,12 +1137,16 @@ function checkLibrarySCUploadStatus(){
} }
$("#library_display span.progress").each(checkSCUploadStatusRequest); $("#library_display span.progress").each(checkSCUploadStatusRequest);
setTimeout(checkLibrarySCUploadStatus, 5000);
} }
function addQtipToSCIcons(){ function addQtipToSCIcons() {
$(".progress, .soundcloud, .sc-error").live('mouseover', function(){ $("#content")
.on('mouseover', ".progress, .soundcloud, .sc-error", function() {
var id = $(this).parent().parent().data("aData").id; var aData = $(this).parents("tr").data("aData"),
id = aData.id,
sc_id = aData.soundcloud_id;
if ($(this).hasClass("progress")){ if ($(this).hasClass("progress")){
$(this).qtip({ $(this).qtip({
@ -1163,24 +1166,15 @@ function addQtipToSCIcons(){
classes: "ui-tooltip-dark file-md-long" classes: "ui-tooltip-dark file-md-long"
}, },
show: { show: {
ready: true // Needed to make it show on first mouseover ready: true // Needed to make it show on first mouseover event
// event
} }
}); });
} }
else if($(this).hasClass("soundcloud")){ else if ($(this).hasClass("soundcloud")){
var sc_id = $(this).parent().parent().data("aData").soundcloud_id;
$(this).qtip({ $(this).qtip({
content: { content: {
text: $.i18n._("Retrieving data from the server..."), text: $.i18n._("The soundcloud id for this file is: ") + sc_id
ajax: {
url: baseUrl+"Library/get-upload-to-soundcloud-status",
type: "post",
data: ({format: "json", id : id, type: "file"}),
success: function(json, status){
this.set('content.text', $.i18n._("The soundcloud id for this file is: ")+json.sc_id);
}
}
}, },
position:{ position:{
adjust: { adjust: {
@ -1195,11 +1189,11 @@ function addQtipToSCIcons(){
classes: "ui-tooltip-dark file-md-long" classes: "ui-tooltip-dark file-md-long"
}, },
show: { show: {
ready: true // Needed to make it show on first mouseover ready: true // Needed to make it show on first mouseover event
// event
} }
}); });
}else if($(this).hasClass("sc-error")){ }
else if ($(this).hasClass("sc-error")) {
$(this).qtip({ $(this).qtip({
content: { content: {
text: $.i18n._("Retreiving data from the server..."), text: $.i18n._("Retreiving data from the server..."),
@ -1227,8 +1221,7 @@ function addQtipToSCIcons(){
classes: "ui-tooltip-dark file-md-long" classes: "ui-tooltip-dark file-md-long"
}, },
show: { show: {
ready: true // Needed to make it show on first mouseover ready: true // Needed to make it show on first mouseover event
// event
} }
}); });
} }

View file

@ -587,7 +587,7 @@ var AIRTIME = (function(AIRTIME){
var extra = (ele['extra']==null)?"":"- "+ele['extra']; var extra = (ele['extra']==null)?"":"- "+ele['extra'];
$html += "<li>" + $html += "<li>" +
"<span class='block-item-title'>"+ele['display_name']+"</span>" + "<span class='block-item-title'>"+ele['display_name']+"</span>" +
"<span class='block-item-criteria'>"+ele['modifier']+"</span>" + "<span class='block-item-criteria'>"+ele['display_modifier']+"</span>" +
"<span class='block-item-criteria'>"+ele['value']+"</span>" + "<span class='block-item-criteria'>"+ele['value']+"</span>" +
"<span class='block-item-criteria'>"+extra+"</span>" + "<span class='block-item-criteria'>"+extra+"</span>" +
"</li>"; "</li>";

View file

@ -192,7 +192,8 @@ function setAddShowEvents() {
$(this).parent().after("<ul id='show-link-warning' class='errors'><li>"+$.i18n._("Warning: Shows cannot be re-linked")+"</li></ul>"); $(this).parent().after("<ul id='show-link-warning' class='errors'><li>"+$.i18n._("Warning: Shows cannot be re-linked")+"</li></ul>");
} }
}); });
form.find("#add_show_linked-label").before("<span class='show_linking_help_icon'></span>");
form.find("#add_show_record").click(function(){ form.find("#add_show_record").click(function(){
$(this).blur(); $(this).blur();
@ -315,7 +316,26 @@ function setAddShowEvents() {
at: "right center" at: "right center"
} }
}); });
form.find(".show_linking_help_icon").qtip({
content: {
text: $.i18n._("By linking your repeating shows any media items scheduled in any repeat show will also get scheduled in the other repeat shows")
},
hide: {
delay: 500,
fixed: true
},
style: {
border: {
width: 0,
radius: 4
},
classes: "ui-tooltip-dark ui-tooltip-rounded"
},
position: {
my: "left bottom",
at: "right center"
}
});
function endDateVisibility(){ function endDateVisibility(){
if(form.find("#add_show_no_end").is(':checked')){ if(form.find("#add_show_no_end").is(':checked')){
form.find("#add_show_end_date").hide(); form.find("#add_show_end_date").hide();

View file

@ -211,6 +211,7 @@ function viewDisplay( view ) {
function eventRender(event, element, view) { function eventRender(event, element, view) {
$(element).attr("id", "fc-show-instance-"+event.id);
$(element).data("event", event); $(element).data("event", event);
//only put progress bar on shows that aren't being recorded. //only put progress bar on shows that aren't being recorded.
@ -228,35 +229,28 @@ function eventRender(event, element, view) {
$(element).find(".fc-event-content").append(div); $(element).find(".fc-event-content").append(div);
} }
//need to add id for every event to find the current show
if (view.name === 'agendaDay' || view.name === 'agendaWeek') {
$(element).find(".fc-event-time").attr("id", event.id);
} else if (view.name === 'month') {
$(element).find(".fc-event-title").attr("id", event.id);
}
//add the record/rebroadcast/soundcloud icons if needed //add the record/rebroadcast/soundcloud icons if needed
if (event.record === 1) { if (event.record === 1) {
if (view.name === 'agendaDay' || view.name === 'agendaWeek') { if (view.name === 'agendaDay' || view.name === 'agendaWeek') {
if (event.soundcloud_id === -1) { if (event.soundcloud_id === -1) {
$(element).find(".fc-event-time").before('<span id="'+event.id+'" class="small-icon recording"></span>'); $(element).find(".fc-event-time").before('<span class="small-icon recording"></span>');
} else if ( event.soundcloud_id > 0) { } else if ( event.soundcloud_id > 0) {
$(element).find(".fc-event-time").before('<span id="'+event.id+'" class="small-icon recording"></span><span id="'+event.id+'" class="small-icon soundcloud"></span>'); $(element).find(".fc-event-time").before('<span class="small-icon recording"></span><span class="small-icon soundcloud"></span>');
} else if (event.soundcloud_id === -2) { } else if (event.soundcloud_id === -2) {
$(element).find(".fc-event-time").before('<span id="'+event.id+'" class="small-icon recording"></span><span id="'+event.id+'" class="small-icon progress"></span>'); $(element).find(".fc-event-time").before('<span class="small-icon recording"></span><span class="small-icon progress"></span>');
} else if (event.soundcloud_id === -3) { } else if (event.soundcloud_id === -3) {
$(element).find(".fc-event-time").before('<span id="'+event.id+'" class="small-icon recording"></span><span id="'+event.id+'" class="small-icon sc-error"></span>'); $(element).find(".fc-event-time").before('<span class="small-icon recording"></span><span class="small-icon sc-error"></span>');
} }
} else if (view.name === 'month') { } else if (view.name === 'month') {
if(event.soundcloud_id === -1) { if(event.soundcloud_id === -1) {
$(element).find(".fc-event-title").after('<span id="'+event.id+'" class="small-icon recording"></span>'); $(element).find(".fc-event-title").after('<span class="small-icon recording"></span>');
} else if (event.soundcloud_id > 0) { } else if (event.soundcloud_id > 0) {
$(element).find(".fc-event-title").after('<span id="'+event.id+'" class="small-icon recording"></span><span id="'+event.id+'" class="small-icon soundcloud"></span>'); $(element).find(".fc-event-title").after('<span class="small-icon recording"></span><span class="small-icon soundcloud"></span>');
} else if (event.soundcloud_id === -2) { } else if (event.soundcloud_id === -2) {
$(element).find(".fc-event-title").after('<span id="'+event.id+'" class="small-icon recording"></span><span id="'+event.id+'" class="small-icon progress"></span>'); $(element).find(".fc-event-title").after('<span class="small-icon recording"></span><span class="small-icon progress"></span>');
} else if (event.soundcloud_id === -3) { } else if (event.soundcloud_id === -3) {
$(element).find(".fc-event-title").after('<span id="'+event.id+'" class="small-icon recording"></span><span id="'+event.id+'" class="small-icon sc-error"></span>'); $(element).find(".fc-event-title").after('<span class="small-icon recording"></span><span class="small-icon sc-error"></span>');
} }
} }
} }
@ -267,27 +261,27 @@ function eventRender(event, element, view) {
if (event.linked) { if (event.linked) {
$(element) $(element)
.find(".fc-event-time") .find(".fc-event-time")
.before('<span id="'+event.id+'" class="small-icon linked"></span><span id="'+event.id+'" class="small-icon show-empty"></span>'); .before('<span class="small-icon linked"></span><span class="small-icon show-empty"></span>');
} else { } else {
$(element) $(element)
.find(".fc-event-time") .find(".fc-event-time")
.before('<span id="'+event.id+'" class="small-icon show-empty"></span>'); .before('<span class="small-icon show-empty"></span>');
} }
} else if (event.show_partial_filled === true) { } else if (event.show_partial_filled === true) {
if (event.linked) { if (event.linked) {
$(element) $(element)
.find(".fc-event-time") .find(".fc-event-time")
.before('<span id="'+event.id+'" class="small-icon linked"></span><span id="'+event.id+'" class="small-icon show-partial-filled"></span>'); .before('<span class="small-icon linked"></span><span class="small-icon show-partial-filled"></span>');
} else { } else {
$(element) $(element)
.find(".fc-event-time") .find(".fc-event-time")
.before('<span id="'+event.id+'" class="small-icon show-partial-filled"></span>'); .before('<span class="small-icon show-partial-filled"></span>');
} }
} else { } else {
if (event.linked) { if (event.linked) {
$(element) $(element)
.find(".fc-event-time") .find(".fc-event-time")
.before('<span id="'+event.id+'" class="small-icon linked"></span>'); .before('<span class="small-icon linked"></span>');
} }
} }
} else if (view.name === 'month') { } else if (view.name === 'month') {
@ -295,27 +289,27 @@ function eventRender(event, element, view) {
if (event.linked) { if (event.linked) {
$(element) $(element)
.find(".fc-event-title") .find(".fc-event-title")
.after('<span id="'+event.id+'" class="small-icon linked"></span><span id="'+event.id+'" title="'+$.i18n._("Show is empty")+'" class="small-icon show-empty"></span>'); .after('<span class="small-icon linked"></span><span title="'+$.i18n._("Show is empty")+'" class="small-icon show-empty"></span>');
} else { } else {
$(element) $(element)
.find(".fc-event-title") .find(".fc-event-title")
.after('<span id="'+event.id+'" title="'+$.i18n._("Show is empty")+'" class="small-icon show-empty"></span>'); .after('<span title="'+$.i18n._("Show is empty")+'" class="small-icon show-empty"></span>');
} }
} else if (event.show_partial_filled === true) { } else if (event.show_partial_filled === true) {
if (event.linked) { if (event.linked) {
$(element) $(element)
.find(".fc-event-title") .find(".fc-event-title")
.after('<span id="'+event.id+'" class="small-icon linked"></span><span id="'+event.id+'" title="'+$.i18n._("Show is partially filled")+'" class="small-icon show-partial-filled"></span>'); .after('<span class="small-icon linked"></span><span title="'+$.i18n._("Show is partially filled")+'" class="small-icon show-partial-filled"></span>');
} else { } else {
$(element) $(element)
.find(".fc-event-title") .find(".fc-event-title")
.after('<span id="'+event.id+'" title="'+$.i18n._("Show is partially filled")+'" class="small-icon show-partial-filled"></span>'); .after('<span title="'+$.i18n._("Show is partially filled")+'" class="small-icon show-partial-filled"></span>');
} }
} else { } else {
if (event.linked) { if (event.linked) {
$(element) $(element)
.find(".fc-event-title") .find(".fc-event-title")
.after('<span id="'+event.id+'" class="small-icon linked"></span>'); .after('<span class="small-icon linked"></span>');
} }
} }
} }
@ -324,9 +318,9 @@ function eventRender(event, element, view) {
//rebroadcast icon //rebroadcast icon
if (event.rebroadcast === 1) { if (event.rebroadcast === 1) {
if (view.name === 'agendaDay' || view.name === 'agendaWeek') { if (view.name === 'agendaDay' || view.name === 'agendaWeek') {
$(element).find(".fc-event-time").before('<span id="'+event.id+'" class="small-icon rebroadcast"></span>'); $(element).find(".fc-event-time").before('<span class="small-icon rebroadcast"></span>');
} else if (view.name === 'month') { } else if (view.name === 'month') {
$(element).find(".fc-event-title").after('<span id="'+event.id+'" class="small-icon rebroadcast"></span>'); $(element).find(".fc-event-title").after('<span class="small-icon rebroadcast"></span>');
} }
} }
} }
@ -334,7 +328,7 @@ function eventRender(event, element, view) {
function eventAfterRender( event, element, view ) { function eventAfterRender( event, element, view ) {
$(element).find(".small-icon").live('mouseover',function(){ $(element).find(".small-icon").live('mouseover',function(){
addQtipsToIcons($(this)); addQtipsToIcons($(this), event.id);
}); });
} }
@ -403,15 +397,25 @@ function getFullCalendarEvents(start, end, callback) {
} }
function checkSCUploadStatus(){ function checkSCUploadStatus(){
var url = baseUrl+'Library/get-upload-to-soundcloud-status/format/json'; var url = baseUrl+'Library/get-upload-to-soundcloud-status/format/json',
id;
$("span[class*=progress]").each(function(){ $("span[class*=progress]").each(function(){
var id = $(this).attr("id"); id = $(this).parents("div.fc-event").data("event").id;
$.post(url, {format: "json", id: id, type:"show"}, function(json){ $.post(url, {format: "json", id: id, type:"show"}, function(json){
if(json.sc_id > 0){ if (json.sc_id > 0){
$("span[id="+id+"]:not(.recording)").removeClass("progress").addClass("soundcloud"); $("#fc-show-instance-"+id)
}else if(json.sc_id == "-3"){ .find(".progress")
$("span[id="+id+"]:not(.recording)").removeClass("progress").addClass("sc-error"); .removeClass("progress")
.addClass("soundcloud");
} }
else if (json.sc_id == "-3"){
$("#fc-show-instance-"+id)
.find(".progress")
.removeClass("progress")
.addClass("sc-error");
}
setTimeout(checkSCUploadStatus, 5000); setTimeout(checkSCUploadStatus, 5000);
}); });
}); });
@ -425,7 +429,7 @@ function getCurrentShow(){
$el; $el;
$.post(url, {format: "json"}, function(json) { $.post(url, {format: "json"}, function(json) {
if (json.current_show === true) { if (json.current_show === true) {
$el = $("div[class*=fc-event-time][id="+json.si_id+"]"); $el = $("div[class*=fc-event-time]");
if (view_name === 'agendaDay' || view_name === 'agendaWeek') { if (view_name === 'agendaDay' || view_name === 'agendaWeek') {
/* Need to remove now-playing class because if user /* Need to remove now-playing class because if user
@ -440,40 +444,40 @@ function getCurrentShow(){
* icon will overwrite it. * icon will overwrite it.
*/ */
$el.siblings().remove("span[class=small-icon recording]"); $el.siblings().remove("span[class=small-icon recording]");
$el.before('<span id="'+json.si_id+'" class="small-icon now-playing"></span><span id="'+json.si_id+'" class="small-icon recording"></span>'); $el.before('<span class="small-icon now-playing"></span><span class="small-icon recording"></span>');
} else if ($el.siblings().hasClass("small-icon rebroadcast")) { } else if ($el.siblings().hasClass("small-icon rebroadcast")) {
/* Without removing rebroadcast icon, the now playing /* Without removing rebroadcast icon, the now playing
* icon will overwrite it. * icon will overwrite it.
*/ */
$el.siblings().remove("span[class=small-icon rebroadcast]"); $el.siblings().remove("span[class=small-icon rebroadcast]");
$el.before('<span id="'+json.si_id+'" class="small-icon now-playing"></span><span id="'+json.si_id+'" class="small-icon rebroadcast"></span>'); $el.before('<span class="small-icon now-playing"></span><span class="small-icon rebroadcast"></span>');
} else { } else {
$el.before('<span id="'+json.si_id+'" class="small-icon now-playing"></span>'); $el.before('<span class="small-icon now-playing"></span>');
} }
} }
} else if (view_name === 'month') { } else if (view_name === 'month') {
if (!$("span[class*=fc-event-title][id="+json.si_id+"]").siblings().hasClass("small-icon now-playing")) { if (!$("span[class*=fc-event-title]").siblings().hasClass("small-icon now-playing")) {
$("span[class*=fc-event-title][id="+json.si_id+"]").after('<span id="'+json.si_id+'" class="small-icon now-playing"></span>'); $("span[class*=fc-event-title]").after('<span class="small-icon now-playing"></span>');
} }
} }
} }
//remove icon from shows that have ended //remove icon from shows that have ended
$(".now-playing").each(function(){ $(".now-playing").each(function(){
id = $(this).attr("id"); id = $(this).parents("div.fc-event").data("event").id;
if (id != json.si_id) {
$(this).remove("span[small-icon now-playing]"); if (id != json.si_id) {
} $(this).remove("span[small-icon now-playing]");
}); }
});
setTimeout(getCurrentShow, 5000); setTimeout(getCurrentShow, 5000);
}); });
} }
function addQtipsToIcons(ele, id){
function addQtipsToIcons(ele){
var id = $(ele).attr("id"); if ($(ele).hasClass("progress")){
if($(ele).hasClass("progress")){
$(ele).qtip({ $(ele).qtip({
content: { content: {
text: $.i18n._("Uploading in progress...") text: $.i18n._("Uploading in progress...")

View file

@ -58,24 +58,22 @@ function confirmCancelRecordedShow(show_instance_id){
} }
} }
function uploadToSoundCloud(show_instance_id){ function uploadToSoundCloud(show_instance_id, el){
var url = baseUrl+"Schedule/upload-to-sound-cloud"; var url = baseUrl+"Schedule/upload-to-sound-cloud",
var span = $(window.triggerElement).find(".recording"); $el = $(el),
$span = $el.find(".soundcloud");
$.post(url, $.post(url, {id: show_instance_id, format: "json"});
{id: show_instance_id, format: "json"},
function(json){
scheduleRefetchEvents(json);
});
if(span.length == 0){ //first upload to soundcloud.
span = $(window.triggerElement).find(".soundcloud"); if ($span.length === 0){
span.removeClass("soundcloud") $span = $("<span/>", {"class": "progress"});
.addClass("progress");
}else{ $el.find(".fc-event-title").after($span);
span.removeClass("recording") }
.addClass("progress"); else {
$span.removeClass("soundcloud").addClass("progress");
} }
} }
@ -93,8 +91,6 @@ function checkCalendarSCUploadStatus(){
else if (json.sc_id == "-3") { else if (json.sc_id == "-3") {
span.removeClass("progress").addClass("sc-error"); span.removeClass("progress").addClass("sc-error");
} }
setTimeout(checkCalendarSCUploadStatus, 5000);
} }
function checkSCUploadStatusRequest() { function checkSCUploadStatusRequest() {
@ -106,6 +102,7 @@ function checkCalendarSCUploadStatus(){
} }
$("#schedule_calendar span.progress").each(checkSCUploadStatusRequest); $("#schedule_calendar span.progress").each(checkSCUploadStatusRequest);
setTimeout(checkCalendarSCUploadStatus, 5000);
} }
function findViewportDimensions() { function findViewportDimensions() {
@ -421,7 +418,7 @@ $(document).ready(function() {
if (oItems.soundcloud_upload !== undefined) { if (oItems.soundcloud_upload !== undefined) {
callback = function() { callback = function() {
uploadToSoundCloud(data.id); uploadToSoundCloud(data.id, this.context);
}; };
oItems.soundcloud_upload.callback = callback; oItems.soundcloud_upload.callback = callback;
} }

View file

@ -546,7 +546,7 @@ var AIRTIME = (function(AIRTIME){
cl = 'sb-footer'; cl = 'sb-footer';
//check the show's content status. //check the show's content status.
if (aData.runtime > 0) { if (aData.runtime >= 0) {
$node.html('<span class="ui-icon ui-icon-check"></span>'); $node.html('<span class="ui-icon ui-icon-check"></span>');
cl = cl + ' ui-state-highlight'; cl = cl + ' ui-state-highlight';
} }

View file

@ -6,7 +6,7 @@ VERSION=2.4.0~$(date "+%Y%m%d")
BUILDDEST=/tmp/airtime-${VERSION}/ BUILDDEST=/tmp/airtime-${VERSION}/
DEBDIR=`pwd`/debian DEBDIR=`pwd`/debian
git checkout master git checkout 2.4.x
git pull git pull
echo "cleaning up previous build..." echo "cleaning up previous build..."

View file

@ -18,7 +18,6 @@ PIDFILE=/var/run/airtime-liquidsoap.pid
EXEC='/usr/bin/airtime-liquidsoap' EXEC='/usr/bin/airtime-liquidsoap'
start () { start () {
mkdir -p /var/log/airtime/pypo-liquidsoap mkdir -p /var/log/airtime/pypo-liquidsoap
chown $USERID:$GROUPID /var/log/airtime/pypo-liquidsoap chown $USERID:$GROUPID /var/log/airtime/pypo-liquidsoap
@ -36,9 +35,19 @@ start () {
} }
stop () { stop () {
timeout --version >/dev/null 2>&1
RESULT="$?"
#send term signal after 10 seconds #send term signal after 10 seconds
timeout -s9 10s /usr/lib/airtime/airtime_virtualenv/bin/python \ if [ "$RESULT" = "0" ]; then
/usr/lib/airtime/pypo/bin/liquidsoap_scripts/liquidsoap_prepare_terminate.py timeout -s9 10s /usr/lib/airtime/airtime_virtualenv/bin/python \
/usr/lib/airtime/pypo/bin/liquidsoap_scripts/liquidsoap_prepare_terminate.py
else
#some earlier versions of Ubuntu (Lucid) had a different timeout
#command that takes different input parameters.
timeout 10 /usr/lib/airtime/airtime_virtualenv/bin/python \
/usr/lib/airtime/pypo/bin/liquidsoap_scripts/liquidsoap_prepare_terminate.py
fi
# Send TERM after 5 seconds, wait at most 30 seconds. # Send TERM after 5 seconds, wait at most 30 seconds.
#start-stop-daemon --stop --oknodo --retry=TERM/10/KILL/5 --quiet --pidfile $PIDFILE #start-stop-daemon --stop --oknodo --retry=TERM/10/KILL/5 --quiet --pidfile $PIDFILE
start-stop-daemon --stop --oknodo --retry=TERM/10/KILL/5 --quiet --exec $EXEC start-stop-daemon --stop --oknodo --retry=TERM/10/KILL/5 --quiet --exec $EXEC

View file

@ -4,6 +4,8 @@
set httpd port 2812 set httpd port 2812
check process airtime-liquidsoap matching "airtime-liquidsoap.*airtime.*ls_script" check process airtime-liquidsoap matching "airtime-liquidsoap.*airtime.*ls_script"
if does not exist for 3 cycles then restart
start program = "/etc/init.d/airtime-liquidsoap start" with timeout 30 seconds start program = "/etc/init.d/airtime-liquidsoap start" with timeout 30 seconds
stop program = "/etc/init.d/airtime-liquidsoap stop" stop program = "/etc/init.d/airtime-liquidsoap stop"

View file

@ -3,7 +3,7 @@
set httpd port 2812 set httpd port 2812
check process airtime-liquidsoap check process airtime-liquidsoap with pidfile "/var/run/airtime-liquidsoap.pid"
with pidfile "/var/run/airtime-liquidsoap.pid" if does not exist for 3 cycles then restart
start program = "/etc/init.d/airtime-liquidsoap start" with timeout 5 seconds start program = "/etc/init.d/airtime-liquidsoap start" with timeout 5 seconds
stop program = "/etc/init.d/airtime-liquidsoap stop" stop program = "/etc/init.d/airtime-liquidsoap stop"

View file

@ -0,0 +1,196 @@
# -*- coding: utf-8 -*-
from datetime import datetime
from datetime import timedelta
import sys
import time
import logging.config
import telnetlib
import calendar
import math
import traceback
import os
from pypofetch import PypoFetch
from pypoliqqueue import PypoLiqQueue
from Queue import Empty, Queue
from threading import Thread
from api_clients import api_client
from std_err_override import LogWriter
from configobj import ConfigObj
# configure logging
logging_cfg = os.path.join(os.path.dirname(__file__), "logging.cfg")
logging.config.fileConfig(logging_cfg)
logger = logging.getLogger()
LogWriter.override_std_err(logger)
#need to wait for Python 2.7 for this..
#logging.captureWarnings(True)
PUSH_INTERVAL = 2
def is_stream(media_item):
return media_item['type'] == 'stream_output_start'
def is_file(media_item):
return media_item['type'] == 'file'
class PypoPush(Thread):
def __init__(self, q, telnet_lock, pypo_liquidsoap, config):
Thread.__init__(self)
self.api_client = api_client.AirtimeApiClient()
self.queue = q
self.telnet_lock = telnet_lock
self.config = config
self.pushed_objects = {}
self.logger = logging.getLogger('push')
self.current_prebuffering_stream_id = None
self.queue_id = 0
self.future_scheduled_queue = Queue()
self.pypo_liquidsoap = pypo_liquidsoap
self.plq = PypoLiqQueue(self.future_scheduled_queue, \
self.pypo_liquidsoap, \
self.logger)
self.plq.daemon = True
self.plq.start()
def main(self):
loops = 0
heartbeat_period = math.floor(30 / PUSH_INTERVAL)
media_schedule = None
while True:
try:
media_schedule = self.queue.get(block=True)
except Exception, e:
self.logger.error(str(e))
raise
else:
self.logger.debug(media_schedule)
#separate media_schedule list into currently_playing and
#scheduled_for_future lists
currently_playing, scheduled_for_future = \
self.separate_present_future(media_schedule)
self.pypo_liquidsoap.verify_correct_present_media(currently_playing)
self.future_scheduled_queue.put(scheduled_for_future)
if loops % heartbeat_period == 0:
self.logger.info("heartbeat")
loops = 0
loops += 1
def separate_present_future(self, media_schedule):
tnow = datetime.utcnow()
present = []
future = {}
sorted_keys = sorted(media_schedule.keys())
for mkey in sorted_keys:
media_item = media_schedule[mkey]
diff_td = tnow - media_item['start']
diff_sec = self.date_interval_to_seconds(diff_td)
if diff_sec >= 0:
present.append(media_item)
else:
future[mkey] = media_item
return present, future
def get_current_stream_id_from_liquidsoap(self):
response = "-1"
try:
self.telnet_lock.acquire()
tn = telnetlib.Telnet(self.config['ls_host'], self.config['ls_port'])
msg = 'dynamic_source.get_id\n'
tn.write(msg)
response = tn.read_until("\r\n").strip(" \r\n")
tn.write('exit\n')
tn.read_all()
except Exception, e:
self.logger.error("Error connecting to Liquidsoap: %s", e)
response = []
finally:
self.telnet_lock.release()
return response
#def is_correct_current_item(self, media_item, liquidsoap_queue_approx, liquidsoap_stream_id):
#correct = False
#if media_item is None:
#correct = (len(liquidsoap_queue_approx) == 0 and liquidsoap_stream_id == "-1")
#else:
#if is_file(media_item):
#if len(liquidsoap_queue_approx) == 0:
#correct = False
#else:
#correct = liquidsoap_queue_approx[0]['start'] == media_item['start'] and \
#liquidsoap_queue_approx[0]['row_id'] == media_item['row_id'] and \
#liquidsoap_queue_approx[0]['end'] == media_item['end'] and \
#liquidsoap_queue_approx[0]['replay_gain'] == media_item['replay_gain']
#elif is_stream(media_item):
#correct = liquidsoap_stream_id == str(media_item['row_id'])
#self.logger.debug("Is current item correct?: %s", str(correct))
#return correct
def date_interval_to_seconds(self, interval):
"""
Convert timedelta object into int representing the number of seconds. If
number of seconds is less than 0, then return 0.
"""
seconds = (interval.microseconds + \
(interval.seconds + interval.days * 24 * 3600) * 10 ** 6) / float(10 ** 6)
return seconds
def stop_web_stream_all(self):
try:
self.telnet_lock.acquire()
tn = telnetlib.Telnet(self.config['LS_HOST'], self.config['LS_PORT'])
#msg = 'dynamic_source.read_stop_all xxx\n'
msg = 'http.stop\n'
self.logger.debug(msg)
tn.write(msg)
msg = 'dynamic_source.output_stop\n'
self.logger.debug(msg)
tn.write(msg)
msg = 'dynamic_source.id -1\n'
self.logger.debug(msg)
tn.write(msg)
tn.write("exit\n")
self.logger.debug(tn.read_all())
except Exception, e:
self.logger.error(str(e))
finally:
self.telnet_lock.release()
def run(self):
try: self.main()
except Exception, e:
top = traceback.format_exc()
self.logger.error('Pypo Push Exception: %s', top)

View file

@ -378,11 +378,11 @@ class PypoFetch(Thread):
media_item['file_ready'] = False media_item['file_ready'] = False
media_filtered[key] = media_item media_filtered[key] = media_item
media_item['start'] = datetime.strptime(media_item['start'], media_item['start'] = datetime.strptime(media_item['start'],
"%Y-%m-%d-%H-%M-%S") "%Y-%m-%d-%H-%M-%S")
media_item['end'] = datetime.strptime(media_item['end'], media_item['end'] = datetime.strptime(media_item['end'],
"%Y-%m-%d-%H-%M-%S") "%Y-%m-%d-%H-%M-%S")
media_copy[media_item['start']] = media_item media_copy[key] = media_item
self.media_prepare_queue.put(copy.copy(media_filtered)) self.media_prepare_queue.put(copy.copy(media_filtered))
except Exception, e: self.logger.error("%s", e) except Exception, e: self.logger.error("%s", e)

View file

@ -76,14 +76,6 @@ class PypoFile(Thread):
self.logger.debug("copying from %s to local cache %s" % (src, dst)) self.logger.debug("copying from %s to local cache %s" % (src, dst))
try: try:
"""
List file as "ready" before it starts copying because by the
time Liquidsoap is ready to play this file, it should have at
least started copying (and can continue copying while
Liquidsoap reads from the beginning of the file)
"""
media_item['file_ready'] = True
""" """
copy will overwrite dst if it already exists copy will overwrite dst if it already exists
""" """
@ -91,6 +83,8 @@ class PypoFile(Thread):
#make file world readable #make file world readable
os.chmod(dst, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH) os.chmod(dst, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH)
media_item['file_ready'] = True
except Exception, e: except Exception, e:
self.logger.error("Could not copy from %s to %s" % (src, dst)) self.logger.error("Could not copy from %s to %s" % (src, dst))
self.logger.error(e) self.logger.error(e)

View file

@ -74,8 +74,9 @@ class PypoLiqQueue(Thread):
schedule_deque.append(media_schedule[i]) schedule_deque.append(media_schedule[i])
if len(keys): if len(keys):
time_until_next_play = pure.date_interval_to_seconds(\ time_until_next_play = self.date_interval_to_seconds(
keys[0] - datetime.utcnow()) media_schedule[keys[0]]['start'] -
datetime.utcnow())
else: else:
time_until_next_play = None time_until_next_play = None

View file

@ -32,6 +32,7 @@ set_include_path(implode(PATH_SEPARATOR, array(
realpath($CC_CONFIG['phpDir'] . '/library') realpath($CC_CONFIG['phpDir'] . '/library')
))); )));
require_once($CC_CONFIG['phpDir'].'/application/common/Database.php');
require_once($CC_CONFIG['phpDir'].'/application/models/StoredFile.php'); require_once($CC_CONFIG['phpDir'].'/application/models/StoredFile.php');
require_once($CC_CONFIG['phpDir'].'/application/models/Preference.php'); require_once($CC_CONFIG['phpDir'].'/application/models/Preference.php');
require_once($CC_CONFIG['phpDir'].'/application/models/MusicDir.php'); require_once($CC_CONFIG['phpDir'].'/application/models/MusicDir.php');
@ -52,7 +53,8 @@ if(count($argv) != 2){
} }
$id = $argv[1]; $id = $argv[1];
$file = Application_Model_StoredFile::Recall($id);
$file = Application_Model_StoredFile::RecallById($id);
// set id with -2 which is indicator for processing // set id with -2 which is indicator for processing
$file->setSoundCloudFileId(SOUNDCLOUD_PROGRESS); $file->setSoundCloudFileId(SOUNDCLOUD_PROGRESS);
$file->uploadToSoundCloud(); $file->uploadToSoundCloud();