Merge branch 'master' of dev.sourcefabric.org:airtime

This commit is contained in:
Martin Konecny 2013-05-08 16:53:42 -04:00
commit 4dba722272
21 changed files with 283 additions and 84 deletions

View file

@ -2,9 +2,11 @@
class Application_Common_Database class Application_Common_Database
{ {
public static function prepareAndExecute($sql, array $paramValueMap, public static function prepareAndExecute($sql, array $paramValueMap,
$type='all', $fetchType=PDO::FETCH_ASSOC) $type='all', $fetchType=PDO::FETCH_ASSOC, $con=null)
{ {
$con = Propel::getConnection(); if (is_null($con)) {
$con = Propel::getConnection();
}
$stmt = $con->prepare($sql); $stmt = $con->prepare($sql);
foreach ($paramValueMap as $param => $v) { foreach ($paramValueMap as $param => $v) {
$stmt->bindValue($param, $v); $stmt->bindValue($param, $v);

View file

@ -367,13 +367,6 @@ class ScheduleController extends Zend_Controller_Action
$service_showForm = new Application_Service_ShowFormService($showId, $instanceId); $service_showForm = new Application_Service_ShowFormService($showId, $instanceId);
$isAdminOrPM = $currentUser->isAdminOrPM(); $isAdminOrPM = $currentUser->isAdminOrPM();
/*$isHostOfShow = $currentUser->isHostOfShow($showId);
// in case a user was once a dj and had been assigned to a show
// but was then changed to an admin user we need to allow
// the user to edit the show as an admin (CC-4925)
if ($isHostOfShow && !$isAdminOrPM) {
$this->view->action = "dj-edit-show";
}*/
$forms = $this->createShowFormAction(); $forms = $this->createShowFormAction();
@ -397,30 +390,11 @@ class ScheduleController extends Zend_Controller_Action
if ($currentUser->isAdminOrPM()) { if ($currentUser->isAdminOrPM()) {
$this->createShowFormAction(true); $this->createShowFormAction(true);
$this->view->addNewShow = true;
$this->view->form = $this->view->render('schedule/add-show-form.phtml'); $this->view->form = $this->view->render('schedule/add-show-form.phtml');
} }
} }
/*public function djEditShowAction()
{
$js = $this->_getParam('data');
$data = array();
//need to convert from serialized jQuery array.
foreach ($js as $j) {
$data[$j["name"]] = $j["value"];
}
//update cc_show
$show = new Application_Model_Show($data["add_show_id"]);
$show->setAirtimeAuthFlag($data["cb_airtime_auth"]);
$show->setCustomAuthFlag($data["cb_custom_auth"]);
$show->setCustomUsername($data["custom_username"]);
$show->setCustomPassword($data["custom_password"]);
$this->view->edit = true;
}*/
public function editRepeatingShowInstanceAction(){ public function editRepeatingShowInstanceAction(){
$js = $this->_getParam('data'); $js = $this->_getParam('data');
$data = array(); $data = array();

View file

@ -33,6 +33,7 @@ class Application_Model_Block implements Application_Model_LibraryEditable
"cueout" => "00:00:00", "cueout" => "00:00:00",
"fadein" => "0.0", "fadein" => "0.0",
"fadeout" => "0.0", "fadeout" => "0.0",
"crossfadeDuration" => 0
); );
//using propel's phpNames. //using propel's phpNames.
@ -101,6 +102,7 @@ class Application_Model_Block implements Application_Model_LibraryEditable
$this->blockItem["fadein"] = Application_Model_Preference::GetDefaultFadeIn(); $this->blockItem["fadein"] = Application_Model_Preference::GetDefaultFadeIn();
$this->blockItem["fadeout"] = Application_Model_Preference::GetDefaultFadeOut(); $this->blockItem["fadeout"] = Application_Model_Preference::GetDefaultFadeOut();
$this->blockItem["crossfadeDuration"] = Application_Model_Preference::GetDefaultCrossfadeDuration();
$this->con = isset($con) ? $con : Propel::getConnection(CcBlockPeer::DATABASE_NAME); $this->con = isset($con) ? $con : Propel::getConnection(CcBlockPeer::DATABASE_NAME);
$this->id = $this->block->getDbId(); $this->id = $this->block->getDbId();
@ -390,6 +392,7 @@ SQL;
$row->setDbCueout($info["cueout"]); $row->setDbCueout($info["cueout"]);
$row->setDbFadein(Application_Common_DateHelper::secondsToPlaylistTime($info["fadein"])); $row->setDbFadein(Application_Common_DateHelper::secondsToPlaylistTime($info["fadein"]));
$row->setDbFadeout(Application_Common_DateHelper::secondsToPlaylistTime($info["fadeout"])); $row->setDbFadeout(Application_Common_DateHelper::secondsToPlaylistTime($info["fadeout"]));
$row->setDbTrackOffset($info["crossfadeDuration"]);
$row->save($this->con); $row->save($this->con);
// above save result update on cc_block table on length column. // above save result update on cc_block table on length column.
// but $this->block doesn't get updated automatically // but $this->block doesn't get updated automatically
@ -485,7 +488,7 @@ SQL;
} }
foreach ($p_items as $ac) { foreach ($p_items as $ac) {
Logging::info("Adding audio file {$ac[0]}"); //Logging::info("Adding audio file {$ac[0]}");
try { try {
if (is_array($ac) && $ac[1] == 'audioclip') { if (is_array($ac) && $ac[1] == 'audioclip') {
$res = $this->insertBlockElement($this->buildEntry($ac[0], $pos)); $res = $this->insertBlockElement($this->buildEntry($ac[0], $pos));
@ -655,7 +658,7 @@ SQL;
public function getFadeInfo($pos) public function getFadeInfo($pos)
{ {
Logging::info("Getting fade info for pos {$pos}"); //Logging::info("Getting fade info for pos {$pos}");
$row = CcBlockcontentsQuery::create() $row = CcBlockcontentsQuery::create()
->joinWith(CcFilesPeer::OM_CLASS) ->joinWith(CcFilesPeer::OM_CLASS)
@ -1272,8 +1275,10 @@ SQL;
$isBlockFull = false; $isBlockFull = false;
while ($iterator->valid()) { while ($iterator->valid()) {
$id = $iterator->current()->getDbId(); $id = $iterator->current()->getDbId();
$length = Application_Common_DateHelper::calculateLengthInSeconds($iterator->current()->getDbLength()); $fileLength = $iterator->current()->getCueLength();
$length = Application_Common_DateHelper::calculateLengthInSeconds($fileLength);
$insertList[] = array('id'=>$id, 'length'=>$length); $insertList[] = array('id'=>$id, 'length'=>$length);
$totalTime += $length; $totalTime += $length;
$totalItems++; $totalItems++;
@ -1288,8 +1293,11 @@ SQL;
$sizeOfInsert = count($insertList); $sizeOfInsert = count($insertList);
// if block is not full and reapeat_track is check, fill up more // if block is not full and repeat_track is check, fill up more
while (!$isBlockFull && $repeat == 1 && $sizeOfInsert > 0) { while (!$isBlockFull && $repeat == 1 && $sizeOfInsert > 0) {
Logging::debug("adding repeated tracks.");
Logging::debug("total time = " . $totalTime);
$randomEleKey = array_rand(array_slice($insertList, 0, $sizeOfInsert)); $randomEleKey = array_rand(array_slice($insertList, 0, $sizeOfInsert));
$insertList[] = $insertList[$randomEleKey]; $insertList[] = $insertList[$randomEleKey];
$totalTime += $insertList[$randomEleKey]['length']; $totalTime += $insertList[$randomEleKey]['length'];

View file

@ -11,6 +11,9 @@ class Application_Model_Preference
private static function setValue($key, $value, $isUserValue = false, $userId = null) private static function setValue($key, $value, $isUserValue = false, $userId = null)
{ {
try { try {
$con = Propel::getConnection(CcPrefPeer::DATABASE_NAME);
$con->beginTransaction();
//called from a daemon process //called from a daemon process
if (!class_exists("Zend_Auth", false) || !Zend_Auth::getInstance()->hasIdentity()) { if (!class_exists("Zend_Auth", false) || !Zend_Auth::getInstance()->hasIdentity()) {
$id = NULL; $id = NULL;
@ -35,10 +38,18 @@ class Application_Model_Preference
$paramMap[':id'] = $userId; $paramMap[':id'] = $userId;
} }
$result = Application_Common_Database::prepareAndExecute($sql, $paramMap, 'column'); $result = Application_Common_Database::prepareAndExecute($sql,
$paramMap,
'column',
PDO::FETCH_ASSOC,
$con);
$paramMap = array(); $paramMap = array();
if ($result == 1) { if ($result > 1) {
//this case should not happen.
throw new Exception("Invalid number of results returned. Should be ".
"0 or 1, but is '$result' instead");
} elseif ($result == 1) {
// result found // result found
if (is_null($id) || !$isUserValue) { if (is_null($id) || !$isUserValue) {
// system pref // system pref
@ -76,11 +87,17 @@ class Application_Model_Preference
$paramMap[':key'] = $key; $paramMap[':key'] = $key;
$paramMap[':value'] = $value; $paramMap[':value'] = $value;
Application_Common_Database::prepareAndExecute($sql, $paramMap, 'execute'); Application_Common_Database::prepareAndExecute($sql,
$paramMap,
'execute',
PDO::FETCH_ASSOC,
$con);
$con->commit();
} catch (Exception $e) { } catch (Exception $e) {
$con->rollback();
header('HTTP/1.0 503 Service Unavailable'); header('HTTP/1.0 503 Service Unavailable');
Logging::info("Could not connect to database: ".$e->getMessage()); Logging::info("Database error: ".$e->getMessage());
exit; exit;
} }

View file

@ -557,6 +557,7 @@ class Application_Model_Scheduler
*/ */
$instances = $this->getInstances($schedule["instance"]); $instances = $this->getInstances($schedule["instance"]);
foreach($instances as $instance) { foreach($instances as $instance) {
$linked = $instance->getCcShow()->isLinked();
if ($id !== 0) { if ($id !== 0) {
$schedItem = CcScheduleQuery::create()->findPK($id, $this->con); $schedItem = CcScheduleQuery::create()->findPK($id, $this->con);
/* We use the selected cursor's position to find the same /* We use the selected cursor's position to find the same
@ -609,12 +610,31 @@ class Application_Model_Scheduler
$filesToInsert = array_merge($filesToInsert, $this->retrieveMediaFiles($media["id"], $media["type"])); $filesToInsert = array_merge($filesToInsert, $this->retrieveMediaFiles($media["id"], $media["type"]));
} }
} }
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"]); $sched = CcScheduleQuery::create()->findPk($file["sched_id"]);
/* 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
* items in linked instances
*/
if (!isset($originalPosition)) {
$originalPosition = $sched->getDbPosition();
}
/* 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
* relative item is by its position
*/
if ($linked && $moveAction) {
$sched = CcScheduleQuery::create()
->filterByDbInstanceId($instance->getDbId())
->filterByDbPosition($originalPosition)
->findOne();
}
$excludeIds[] = intval($sched->getDbId()); $excludeIds[] = intval($sched->getDbId());
$file["cliplength"] = $sched->getDbClipLength(); $file["cliplength"] = $sched->getDbClipLength();
@ -694,7 +714,6 @@ 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->getDbClipLength()); $endTimeDT = $this->findEndTime($nextStartDT, $item->getDbClipLength());
$item->setDbStarts($nextStartDT); $item->setDbStarts($nextStartDT);
$item->setDbEnds($endTimeDT); $item->setDbEnds($endTimeDT);
$item->setDbPosition($pos); $item->setDbPosition($pos);

View file

@ -12,6 +12,20 @@
* @package propel.generator.campcaster * @package propel.generator.campcaster
*/ */
class CcFiles extends BaseCcFiles { class CcFiles extends BaseCcFiles {
public function getCueLength()
{
$cuein = $this->getDbCuein();
$cueout = $this->getDbCueout();
$cueinSec = Application_Common_DateHelper::calculateLengthInSeconds($cuein);
$cueoutSec = Application_Common_DateHelper::calculateLengthInSeconds($cueout);
$lengthSec = bcsub($cueoutSec, $cueinSec, 6);
$length = Application_Common_DateHelper::secondsToPlaylistTime($lengthSec);
return $length;
}
public function getDbLength($format = "H:i:s.u") public function getDbLength($format = "H:i:s.u")
{ {

View file

@ -67,6 +67,11 @@ class Application_Service_CalendarService
"name"=> $text, "name"=> $text,
"icon" => "soundcloud"); "icon" => "soundcloud");
} }
} else {
$menu["content"] = array(
"name"=> _("Show Content"),
"icon" => "overview",
"url" => $baseUrl."schedule/show-content-dialog");
} }
} else { } else {
//Show content can be modified from the calendar if: //Show content can be modified from the calendar if:

View file

@ -68,8 +68,12 @@ class Application_Service_SchedulerService
$ccSchedules = CcScheduleQuery::create() $ccSchedules = CcScheduleQuery::create()
->filterByDbInstanceId($instanceIds, Criteria::IN) ->filterByDbInstanceId($instanceIds, Criteria::IN)
->find(); ->find();
$interval = new DateInterval("PT".abs($diff)."S");
if ($diff < 0) {
$interval->invert = 1;
}
foreach ($ccSchedules as $ccSchedule) { foreach ($ccSchedules as $ccSchedule) {
$interval = new DateInterval("PT".$diff."S");
$start = new DateTime($ccSchedule->getDbStarts()); $start = new DateTime($ccSchedule->getDbStarts());
$newStart = $start->add($interval); $newStart = $start->add($interval);
$end = new DateTime($ccSchedule->getDbEnds()); $end = new DateTime($ccSchedule->getDbEnds());

View file

@ -216,7 +216,7 @@ class Application_Service_ShowFormService
'add_show_no_end' => (!$service_show->getRepeatingEndDate()), 'add_show_no_end' => (!$service_show->getRepeatingEndDate()),
'add_show_monthly_repeat_type' => $monthlyRepeatType)); 'add_show_monthly_repeat_type' => $monthlyRepeatType));
if (!$this->ccShow->isLinkable()) { 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));
} }
} }

View file

@ -976,7 +976,7 @@ SQL;
$this->createRebroadcastInstances($showDay, $date, $ccShowInstance->getDbId()); $this->createRebroadcastInstances($showDay, $date, $ccShowInstance->getDbId());
} }
} }
$start = $this->getNextMonthlyMonthlyRepeatDate($start, $timezone); $start = $this->getNextMonthlyMonthlyRepeatDate($start, $timezone, $showDay->getDbStartTime());
} }
$this->setNextRepeatingShowDate($start->format("Y-m-d"), $day, $show_id); $this->setNextRepeatingShowDate($start->format("Y-m-d"), $day, $show_id);
} }
@ -1034,7 +1034,7 @@ SQL;
* Enter description here ... * Enter description here ...
* @param $start * @param $start
*/ */
private function getNextMonthlyMonthlyRepeatDate($start, $timezone) private function getNextMonthlyMonthlyRepeatDate($start, $timezone, $startTime)
{ {
$dt = new DateTime($start->format("Y-m"), new DateTimeZone($timezone)); $dt = new DateTime($start->format("Y-m"), new DateTimeZone($timezone));
do { do {
@ -1042,6 +1042,12 @@ SQL;
} while (!checkdate($dt->format("m"), $start->format("d"), $dt->format("Y"))); } while (!checkdate($dt->format("m"), $start->format("d"), $dt->format("Y")));
$dt->setDate($dt->format("Y"), $dt->format("m"), $start->format("d")); $dt->setDate($dt->format("Y"), $dt->format("m"), $start->format("d"));
$startTime = explode(":", $startTime);
$hours = isset($startTime[0]) ? $startTime[0] : "00";
$minutes = isset($startTime[1]) ? $startTime[1] : "00";
$seconds = isset($startTime[2]) ? $startTime[2] : "00";
$dt->setTime($hours, $minutes, $seconds);
return $dt; return $dt;
} }

View file

@ -191,6 +191,12 @@ function setAddShowEvents() {
$(this).blur(); $(this).blur();
form.find("#add_show_rebroadcast").toggle(); form.find("#add_show_rebroadcast").toggle();
if (form.find("#add_show_record").attr("checked")) {
form.find("#add_show_linked").attr("checked", false).attr("disabled", true);
} else {
form.find("#add_show_linked").attr("disabled", false);
}
//uncheck rebroadcast checkbox //uncheck rebroadcast checkbox
form.find("#add_show_rebroadcast").attr('checked', false); form.find("#add_show_rebroadcast").attr('checked', false);

View file

@ -82,7 +82,9 @@ AudioPlayout.prototype.loadData = function (audioData, cb) {
that.buffer = buffer; that.buffer = buffer;
cb(buffer); cb(buffer);
}, },
Error function(err) {
console.log("err(decodeAudioData): "+err);
}
); );
}; };

View file

@ -21,6 +21,24 @@ showhelp () {
exit 0 exit 0
} }
rabbitmq_install () {
RABBITMQ_VHOST="/airtime"
RABBITMQ_USER="airtime"
RABBITMQ_PASSWORD=$(awk -F ' = ' '{if (! ($0 ~ /^;/) && $0 ~ /^password/ ) print $2}' /etc/airtime/airtime.conf)
EXCHANGES="airtime-pypo|pypo-fetch|airtime-media-monitor|media-monitor"
rabbitmqctl delete_vhost $RABBITMQ_VHOST
rabbitmqctl delete_user $RABBITMQ_USER
rabbitmqctl add_vhost $RABBITMQ_VHOST
rabbitmqctl add_user $RABBITMQ_USER $RABBITMQ_PASSWORD
rabbitmqctl set_permissions -p $RABBITMQ_VHOST $RABBITMQ_USER "$EXCHANGES" "$EXCHANGES" "$EXCHANGES"
export RABBITMQ_USER
export RABBITMQ_PASSWORD
export RABBITMQ_VHOST
}
overwrite="f" overwrite="f"
preserve="f" preserve="f"
nodb="f" nodb="f"
@ -198,6 +216,8 @@ if [ "$DO_UPGRADE" -eq "0" ]; then
echo "There was an error during install. Exit code $result" echo "There was an error during install. Exit code $result"
exit 1 exit 1
fi fi
rabbitmq_install
fi fi
set -e set -e

View file

@ -28,6 +28,14 @@ done
#Make 'purge' env variable available to sub bash script #Make 'purge' env variable available to sub bash script
export purge export purge
rabbitmq_uninstall () {
RABBITMQ_VHOST="/airtime"
RABBITMQ_USER="airtime"
rabbitmqctl delete_vhost $RABBITMQ_VHOST
rabbitmqctl delete_user $RABBITMQ_USER
}
echo -e "\n******************************* Uninstall Begin ********************************" echo -e "\n******************************* Uninstall Begin ********************************"
# Absolute path to this script, e.g. /home/user/bin/foo.sh # Absolute path to this script, e.g. /home/user/bin/foo.sh
@ -35,6 +43,8 @@ SCRIPT=`readlink -f $0`
# Absolute path this script is in, thus /home/user/bin # Absolute path this script is in, thus /home/user/bin
SCRIPTPATH=`dirname $SCRIPT` SCRIPTPATH=`dirname $SCRIPT`
rabbitmq_uninstall
virtualenv_bin="/usr/lib/airtime/airtime_virtualenv/bin/" virtualenv_bin="/usr/lib/airtime/airtime_virtualenv/bin/"
. ${virtualenv_bin}activate . ${virtualenv_bin}activate

View file

@ -37,11 +37,11 @@ class AirtimeIni
public static function IniFilesExist() public static function IniFilesExist()
{ {
$configFiles = array(AirtimeIni::CONF_FILE_AIRTIME, $configFiles = array(self::CONF_FILE_AIRTIME,
AirtimeIni::CONF_FILE_PYPO, self::CONF_FILE_PYPO,
AirtimeIni::CONF_FILE_RECORDER, self::CONF_FILE_RECORDER,
AirtimeIni::CONF_FILE_LIQUIDSOAP, self::CONF_FILE_LIQUIDSOAP,
AirtimeIni::CONF_FILE_MEDIAMONITOR); self::CONF_FILE_MEDIAMONITOR);
$exist = false; $exist = false;
foreach ($configFiles as $conf) { foreach ($configFiles as $conf) {
if (file_exists($conf)) { if (file_exists($conf)) {
@ -65,46 +65,46 @@ class AirtimeIni
} }
} }
if (!copy(AirtimeInstall::GetAirtimeSrcDir()."/build/airtime.conf", AirtimeIni::CONF_FILE_AIRTIME)){ if (!copy(AirtimeInstall::GetAirtimeSrcDir()."/build/airtime.conf", self::CONF_FILE_AIRTIME)){
echo "Could not copy airtime.conf to /etc/airtime/. Exiting."; echo "Could not copy airtime.conf to /etc/airtime/. Exiting.";
exit(1); exit(1);
} else if (!self::ChangeFileOwnerGroupMod(AirtimeIni::CONF_FILE_AIRTIME, self::CONF_WWW_DATA_GRP)){ } else if (!self::ChangeFileOwnerGroupMod(self::CONF_FILE_AIRTIME, self::CONF_WWW_DATA_GRP)){
echo "Could not set ownership of api_client.cfg to 'pypo'. Exiting."; echo "Could not set ownership of api_client.cfg to 'pypo'. Exiting.";
exit(1); exit(1);
} }
if (getenv("python_service") == "0"){ if (getenv("python_service") == "0"){
if (!copy(__DIR__."/../../python_apps/api_clients/api_client.cfg", AirtimeIni::CONF_FILE_API_CLIENT)){ if (!copy(__DIR__."/../../python_apps/api_clients/api_client.cfg", self::CONF_FILE_API_CLIENT)){
echo "Could not copy api_client.cfg to /etc/airtime/. Exiting."; echo "Could not copy api_client.cfg to /etc/airtime/. Exiting.";
exit(1); exit(1);
} else if (!self::ChangeFileOwnerGroupMod(AirtimeIni::CONF_FILE_API_CLIENT, self::CONF_PYPO_GRP)){ } else if (!self::ChangeFileOwnerGroupMod(self::CONF_FILE_API_CLIENT, self::CONF_PYPO_GRP)){
echo "Could not set ownership of api_client.cfg to 'pypo'. Exiting."; echo "Could not set ownership of api_client.cfg to 'pypo'. Exiting.";
exit(1); exit(1);
} }
if (!copy(__DIR__."/../../python_apps/pypo/pypo.cfg", AirtimeIni::CONF_FILE_PYPO)){ if (!copy(__DIR__."/../../python_apps/pypo/pypo.cfg", self::CONF_FILE_PYPO)){
echo "Could not copy pypo.cfg to /etc/airtime/. Exiting."; echo "Could not copy pypo.cfg to /etc/airtime/. Exiting.";
exit(1); exit(1);
} else if (!self::ChangeFileOwnerGroupMod(AirtimeIni::CONF_FILE_PYPO, self::CONF_PYPO_GRP)){ } else if (!self::ChangeFileOwnerGroupMod(self::CONF_FILE_PYPO, self::CONF_PYPO_GRP)){
echo "Could not set ownership of pypo.cfg to 'pypo'. Exiting."; echo "Could not set ownership of pypo.cfg to 'pypo'. Exiting.";
exit(1); exit(1);
} }
/* /*
if (!copy(__DIR__."/../../python_apps/pypo/liquidsoap_scripts/liquidsoap.cfg", AirtimeIni::CONF_FILE_LIQUIDSOAP)){ if (!copy(__DIR__."/../../python_apps/pypo/liquidsoap_scripts/liquidsoap.cfg", self::CONF_FILE_LIQUIDSOAP)){
echo "Could not copy liquidsoap.cfg to /etc/airtime/. Exiting."; echo "Could not copy liquidsoap.cfg to /etc/airtime/. Exiting.";
exit(1); exit(1);
} else if (!self::ChangeFileOwnerGroupMod(AirtimeIni::CONF_FILE_LIQUIDSOAP, self::CONF_PYPO_GRP)){ } else if (!self::ChangeFileOwnerGroupMod(self::CONF_FILE_LIQUIDSOAP, self::CONF_PYPO_GRP)){
echo "Could not set ownership of liquidsoap.cfg to 'pypo'. Exiting."; echo "Could not set ownership of liquidsoap.cfg to 'pypo'. Exiting.";
exit(1); exit(1);
} }
* */ * */
if (!copy(__DIR__."/../../python_apps/media-monitor/media-monitor.cfg", AirtimeIni::CONF_FILE_MEDIAMONITOR)){ if (!copy(__DIR__."/../../python_apps/media-monitor/media-monitor.cfg", self::CONF_FILE_MEDIAMONITOR)){
echo "Could not copy media-monitor.cfg to /etc/airtime/. Exiting."; echo "Could not copy media-monitor.cfg to /etc/airtime/. Exiting.";
exit(1); exit(1);
} else if (!self::ChangeFileOwnerGroupMod(AirtimeIni::CONF_FILE_MEDIAMONITOR, self::CONF_PYPO_GRP)){ } else if (!self::ChangeFileOwnerGroupMod(self::CONF_FILE_MEDIAMONITOR, self::CONF_PYPO_GRP)){
echo "Could not set ownership of media-monitor.cfg to 'pypo'. Exiting."; echo "Could not set ownership of media-monitor.cfg to 'pypo'. Exiting.";
exit(1); exit(1);
} }
@ -127,25 +127,25 @@ class AirtimeIni
*/ */
public static function RemoveIniFiles() public static function RemoveIniFiles()
{ {
if (file_exists(AirtimeIni::CONF_FILE_AIRTIME)){ if (file_exists(self::CONF_FILE_AIRTIME)){
unlink(AirtimeIni::CONF_FILE_AIRTIME); unlink(self::CONF_FILE_AIRTIME);
} }
if (file_exists(AirtimeIni::CONF_FILE_PYPO)){ if (file_exists(self::CONF_FILE_PYPO)){
unlink(AirtimeIni::CONF_FILE_PYPO); unlink(self::CONF_FILE_PYPO);
} }
if (file_exists(AirtimeIni::CONF_FILE_RECORDER)){ if (file_exists(self::CONF_FILE_RECORDER)){
unlink(AirtimeIni::CONF_FILE_RECORDER); unlink(self::CONF_FILE_RECORDER);
} }
if (file_exists(AirtimeIni::CONF_FILE_LIQUIDSOAP)){ if (file_exists(self::CONF_FILE_LIQUIDSOAP)){
unlink(AirtimeIni::CONF_FILE_LIQUIDSOAP); unlink(self::CONF_FILE_LIQUIDSOAP);
} }
//wait until Airtime 1.9.0 //wait until Airtime 1.9.0
if (file_exists(AirtimeIni::CONF_FILE_MEDIAMONITOR)){ if (file_exists(self::CONF_FILE_MEDIAMONITOR)){
unlink(AirtimeIni::CONF_FILE_MEDIAMONITOR); unlink(self::CONF_FILE_MEDIAMONITOR);
} }
if (file_exists("etc/airtime")){ if (file_exists("etc/airtime")){
@ -214,6 +214,57 @@ class AirtimeIni
fclose($fp); fclose($fp);
} }
//stupid hack found on http://stackoverflow.com/a/1268642/276949
//with some modifications: 1) Spaces are inserted in between sections and
//2) values are not quoted.
public static function write_ini_file($assoc_arr, $path, $has_sections = false) {
$content = "";
if ($has_sections) {
$first_line = true;
foreach ($assoc_arr as $key=>$elem) {
if ($first_line) {
$content .= "[".$key."]\n";
$first_line = false;
} else {
$content .= "\n[".$key."]\n";
}
foreach ($elem as $key2=>$elem2) {
if(is_array($elem2))
{
for($i=0;$i<count($elem2);$i++)
{
$content .= $key2."[] = \"".$elem2[$i]."\"\n";
}
}
else if($elem2=="") $content .= $key2." = \n";
else $content .= $key2." = ".$elem2."\n";
}
}
} else {
foreach ($assoc_arr as $key=>$elem) {
if(is_array($elem))
{
for($i=0;$i<count($elem);$i++)
{
$content .= $key."[] = \"".$elem[$i]."\"\n";
}
}
else if($elem=="") $content .= $key." = \n";
else $content .= $key." = ".$elem."\n";
}
}
if (!$handle = fopen($path, 'w')) {
return false;
}
if (!fwrite($handle, $content)) {
return false;
}
fclose($handle);
return true;
}
/** /**
* After the configuration files have been copied to /etc/airtime, * After the configuration files have been copied to /etc/airtime,
* this function will update them to values unique to this * this function will update them to values unique to this
@ -221,12 +272,28 @@ class AirtimeIni
*/ */
public static function UpdateIniFiles() public static function UpdateIniFiles()
{ {
$api_key = AirtimeIni::GenerateRandomString(); $api_key = self::GenerateRandomString();
if (getenv("web") == "t"){ if (getenv("web") == "t"){
AirtimeIni::UpdateIniValue(AirtimeIni::CONF_FILE_AIRTIME, 'api_key', $api_key); //self::UpdateIniValue(self::CONF_FILE_AIRTIME, 'api_key', $api_key);
AirtimeIni::UpdateIniValue(AirtimeIni::CONF_FILE_AIRTIME, 'airtime_dir', AirtimeInstall::CONF_DIR_WWW); //self::UpdateIniValue(self::CONF_FILE_AIRTIME, 'airtime_dir', AirtimeInstall::CONF_DIR_WWW);
//self::UpdateIniValue(self::CONF_FILE_AIRTIME, 'password', self::GenerateRandomString());
$ini = parse_ini_file(self::CONF_FILE_AIRTIME, true);
$ini['general']['api_key'] = $api_key;
$ini['general']['airtime_dir'] = AirtimeInstall::CONF_DIR_WWW;
$ini['rabbitmq']['vhost'] = 'airtime';
$ini['rabbitmq']['user'] = 'airtime';
$ini['rabbitmq']['password'] = self::GenerateRandomString();
self::write_ini_file($ini, self::CONF_FILE_AIRTIME, true);
} }
AirtimeIni::UpdateIniValue(AirtimeIni::CONF_FILE_API_CLIENT, 'api_key', "'$api_key'"); //self::UpdateIniValue(self::CONF_FILE_API_CLIENT, 'api_key', "'$api_key'");
$ini = parse_ini_file(self::CONF_FILE_API_CLIENT);
$ini['api_key'] = "'$api_key'";
self::write_ini_file($ini, self::CONF_FILE_API_CLIENT);
} }
public static function ReadPythonConfig($p_filename) public static function ReadPythonConfig($p_filename)
@ -255,8 +322,8 @@ class AirtimeIni
$oldSettings = parse_ini_file("$conf$suffix.bak", true); $oldSettings = parse_ini_file("$conf$suffix.bak", true);
} }
else { else {
$newSettings = AirtimeIni::ReadPythonConfig($conf); $newSettings = self::ReadPythonConfig($conf);
$oldSettings = AirtimeIni::ReadPythonConfig("$conf$suffix.bak"); $oldSettings = self::ReadPythonConfig("$conf$suffix.bak");
} }
$settings = array_keys($newSettings); $settings = array_keys($newSettings);
@ -267,12 +334,12 @@ class AirtimeIni
$sectionKeys = array_keys($newSettings[$section]); $sectionKeys = array_keys($newSettings[$section]);
foreach($sectionKeys as $sectionKey) { foreach($sectionKeys as $sectionKey) {
if(isset($oldSettings[$section][$sectionKey])) { if(isset($oldSettings[$section][$sectionKey])) {
AirtimeIni::UpdateIniValue($conf, $sectionKey, $oldSettings[$section][$sectionKey]); self::UpdateIniValue($conf, $sectionKey, $oldSettings[$section][$sectionKey]);
} }
} }
} }
else { else {
AirtimeIni::UpdateIniValue($conf, $section, $oldSettings[$section]); self::UpdateIniValue($conf, $section, $oldSettings[$section]);
} }
} }
} }

View file

@ -3,3 +3,11 @@ INSERT INTO cc_pref (keystr, valstr) VALUES ('system_version', '2.4.0');
DELETE FROM cc_pref WHERE keystr = 'stream_type'; DELETE FROM cc_pref WHERE keystr = 'stream_type';
INSERT INTO cc_pref (keystr, valstr) VALUES ('stream_type', 'ogg, mp3, opus, aac'); INSERT INTO cc_pref (keystr, valstr) VALUES ('stream_type', 'ogg, mp3, opus, aac');
UPDATE cc_files
SET is_scheduled = true
WHERE id IN (SELECT DISTINCT(file_id) FROM cc_schedule WHERE playout_status != -1);
UPDATE cc_files
SET is_playlist = true
WHERE id IN (SELECT DISTINCT(file_id) FROM cc_playlistcontents);

View file

@ -44,6 +44,10 @@ try:
# load config file # load config file
try: try:
config = ConfigObj(PATH_INI_FILE) config = ConfigObj(PATH_INI_FILE)
config['rabbitmq_user'] = os.environ['RABBITMQ_USER']
config['rabbitmq_password'] = os.environ['RABBITMQ_PASSWORD']
config['rabbitmq_vhost'] = os.environ['RABBITMQ_VHOST']
config.write()
except Exception, e: except Exception, e:
print 'Error loading config file: ', e print 'Error loading config file: ', e
sys.exit(1) sys.exit(1)

View file

@ -10,7 +10,11 @@ ls_param="/usr/lib/airtime/pypo/bin/liquidsoap_scripts/ls_script.liq"
export PYTHONPATH=${api_client_path} export PYTHONPATH=${api_client_path}
cd /usr/lib/airtime/pypo/bin/liquidsoap_scripts SCRIPT=`readlink -f $0`
# Absolute directory this script is in
SCRIPTPATH=`dirname $SCRIPT`
cd $SCRIPTPATH/liquidsoap_scripts
python generate_liquidsoap_cfg.py python generate_liquidsoap_cfg.py
exec ${ls_path} ${ls_param} 2>&1 exec ${ls_path} ${ls_param} 2>&1

View file

@ -81,6 +81,10 @@ try:
# load config file # load config file
try: try:
config = ConfigObj(PATH_INI_FILE) config = ConfigObj(PATH_INI_FILE)
config['rabbitmq_user'] = os.environ['RABBITMQ_USER']
config['rabbitmq_password'] = os.environ['RABBITMQ_PASSWORD']
config['rabbitmq_vhost'] = os.environ['RABBITMQ_VHOST']
config.write()
except Exception, e: except Exception, e:
print 'Error loading config file: ', e print 'Error loading config file: ', e
sys.exit(1) sys.exit(1)

View file

@ -1,5 +1,6 @@
import logging import logging
import sys import sys
import time
from api_clients.api_client import AirtimeApiClient from api_clients.api_client import AirtimeApiClient
def generate_liquidsoap_config(ss): def generate_liquidsoap_config(ss):
@ -26,10 +27,19 @@ def generate_liquidsoap_config(ss):
logging.basicConfig(format='%(message)s') logging.basicConfig(format='%(message)s')
ac = AirtimeApiClient(logging.getLogger()) ac = AirtimeApiClient(logging.getLogger())
try: attempts = 0
ss = ac.get_stream_setting() max_attempts = 5
generate_liquidsoap_config(ss)
except Exception, e: while True:
logging.error(str(e)) try:
print "Unable to connect to the Airtime server." ss = ac.get_stream_setting()
sys.exit(1) generate_liquidsoap_config(ss)
break
except Exception, e:
if attempts == max_attempts:
print "Unable to connect to the Airtime server."
logging.error(str(e))
sys.exit(1)
else:
time.sleep(3)
attempts += 1

View file

@ -432,6 +432,7 @@ class PypoFetch(Thread):
for key in media: for key in media:
media_item = media[key] media_item = media[key]
if (media_item['type'] == 'file'): if (media_item['type'] == 'file'):
self.sanity_check_media_item(media_item)
fileExt = os.path.splitext(media_item['uri'])[1] fileExt = os.path.splitext(media_item['uri'])[1]
dst = os.path.join(download_dir, unicode(media_item['id']) + fileExt) dst = os.path.join(download_dir, unicode(media_item['id']) + fileExt)
media_item['dst'] = dst media_item['dst'] = dst
@ -455,6 +456,20 @@ class PypoFetch(Thread):
try: self.cache_cleanup(media) try: self.cache_cleanup(media)
except Exception, e: self.logger.error("%s", e) except Exception, e: self.logger.error("%s", e)
#do basic validation of file parameters. Useful for debugging
#purposes
def sanity_check_media_item(self, media_item):
start = datetime.strptime(media_item['start'], "%Y-%m-%d-%H-%M-%S")
end = datetime.strptime(media_item['end'], "%Y-%m-%d-%H-%M-%S")
length1 = (end - start).total_seconds()
length2 = media_item['cue_out'] - media_item['cue_in']
if abs(length2 - length1) > 1:
self.logger.error("end - start length: %s", length1)
self.logger.error("cue_out - cue_in length: %s", length2)
self.logger.error("Two lengths are not equal!!!")
def is_file_opened(self, path): def is_file_opened(self, path):
#Capture stderr to avoid polluting py-interpreter.log #Capture stderr to avoid polluting py-interpreter.log
proc = Popen(["lsof", path], stdout=PIPE, stderr=PIPE) proc = Popen(["lsof", path], stdout=PIPE, stderr=PIPE)