Merge branch '2.3.x' into devel

Conflicts:
	airtime_mvc/application/controllers/LibraryController.php
	airtime_mvc/application/models/StoredFile.php
This commit is contained in:
Martin Konecny 2013-02-02 21:07:34 -05:00
commit 93ec4c001b
39 changed files with 424 additions and 146 deletions

View file

@ -60,8 +60,10 @@ class AudiopreviewController extends Zend_Controller_Action
$this->view->uri = $uri; $this->view->uri = $uri;
$this->view->mime = $mime; $this->view->mime = $mime;
$this->view->audioFileID = $audioFileID; $this->view->audioFileID = $audioFileID;
$this->view->audioFileArtist = $audioFileArtist; // We need to decode artist and title because it gets
$this->view->audioFileTitle = $audioFileTitle; // encoded twice in js
$this->view->audioFileArtist = urldecode($audioFileArtist);
$this->view->audioFileTitle = urldecode($audioFileTitle);
$this->view->type = $type; $this->view->type = $type;
$this->_helper->viewRenderer->setRender('audio-preview'); $this->_helper->viewRenderer->setRender('audio-preview');

View file

@ -412,7 +412,7 @@ class LibraryController extends Zend_Controller_Action
$formValues = $this->_getParam('data', null); $formValues = $this->_getParam('data', null);
$formdata = array(); $formdata = array();
foreach ($formValues as $val) { foreach ($formValues as $val) {
$formdata[$val["name"]] = $val["value"]; $formdata[$val["name"]] = htmlspecialchars($val["value"]);
} }
$file->setDbColMetadata($formdata); $file->setDbColMetadata($formdata);

View file

@ -4,10 +4,6 @@ class LocaleController extends Zend_Controller_Action
{ {
public function init() public function init()
{ {
$ajaxContext = $this->_helper->getHelper("AjaxContext");
$ajaxContext->addActionContext("general-translation-table", "json")
->addActionContext("datatables-translation-table", "json")
->initContext();
} }
public function datatablesTranslationTableAction() public function datatablesTranslationTableAction()

View file

@ -274,6 +274,7 @@ class PreferenceController extends Zend_Controller_Action
Application_Model_Preference::setReplayGainModifier($values["replayGainModifier"]); Application_Model_Preference::setReplayGainModifier($values["replayGainModifier"]);
$md = array('schedule' => Application_Model_Schedule::getSchedule()); $md = array('schedule' => Application_Model_Schedule::getSchedule());
Application_Model_RabbitMq::SendMessageToPypo("update_schedule", $md); Application_Model_RabbitMq::SendMessageToPypo("update_schedule", $md);
//Application_Model_RabbitMq::PushSchedule();
} }
if (!Application_Model_Preference::GetMasterDjConnectionUrlOverride()) { if (!Application_Model_Preference::GetMasterDjConnectionUrlOverride()) {

View file

@ -9,6 +9,7 @@ class ScheduleController extends Zend_Controller_Action
{ {
$ajaxContext = $this->_helper->getHelper('AjaxContext'); $ajaxContext = $this->_helper->getHelper('AjaxContext');
$ajaxContext->addActionContext('event-feed', 'json') $ajaxContext->addActionContext('event-feed', 'json')
->addActionContext('event-feed-preload', 'json')
->addActionContext('make-context-menu', 'json') ->addActionContext('make-context-menu', 'json')
->addActionContext('add-show-dialog', 'json') ->addActionContext('add-show-dialog', 'json')
->addActionContext('add-show', 'json') ->addActionContext('add-show', 'json')
@ -89,15 +90,23 @@ class ScheduleController extends Zend_Controller_Action
$this->view->headLink()->appendStylesheet($baseUrl.'css/showbuilder.css?'.$CC_CONFIG['airtime_version']); $this->view->headLink()->appendStylesheet($baseUrl.'css/showbuilder.css?'.$CC_CONFIG['airtime_version']);
//End Show builder JS/CSS requirements //End Show builder JS/CSS requirements
Application_Model_Schedule::createNewFormSections($this->view); Application_Model_Schedule::createNewFormSections($this->view);
$user = Application_Model_User::getCurrentUser(); $user = Application_Model_User::getCurrentUser();
if ($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER))) { if ($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER))) {
$this->view->preloadShowForm = true; $this->view->preloadShowForm = true;
} }
$this->view->headScript()->appendScript("var weekStart = ".Application_Model_Preference::GetWeekStartDay().";"); $this->view->headScript()->appendScript(
"var calendarPref = {};\n".
"calendarPref.weekStart = ".Application_Model_Preference::GetWeekStartDay().";\n".
"calendarPref.timestamp = ".time().";\n".
"calendarPref.timezoneOffset = ".date("Z").";\n".
"calendarPref.timeScale = '".Application_Model_Preference::GetCalendarTimeScale()."';\n".
"calendarPref.timeInterval = ".Application_Model_Preference::GetCalendarTimeInterval().";\n".
"calendarPref.weekStartDay = ".Application_Model_Preference::GetWeekStartDay().";\n".
"var calendarEvents = null;"
);
} }
public function eventFeedAction() public function eventFeedAction()
@ -109,10 +118,28 @@ class ScheduleController extends Zend_Controller_Action
$userInfo = Zend_Auth::getInstance()->getStorage()->read(); $userInfo = Zend_Auth::getInstance()->getStorage()->read();
$user = new Application_Model_User($userInfo->id); $user = new Application_Model_User($userInfo->id);
if ($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER))) { $editable = $user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER));
$editable = true;
$events = &Application_Model_Show::getFullCalendarEvents($start, $end, $editable);
$this->view->events = $events;
}
public function eventFeedPreloadAction()
{
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
$user = new Application_Model_User($userInfo->id);
$editable = $user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER));
$calendar_interval = Application_Model_Preference::GetCalendarTimeScale();
Logging::info($calendar_interval);
if ($calendar_interval == "agendaDay") {
list($start, $end) = Application_Model_Show::getStartEndCurrentDayView();
} else if ($calendar_interval == "agendaWeek") {
list($start, $end) = Application_Model_Show::getStartEndCurrentWeekView();
} else if ($calendar_interval == "month") {
list($start, $end) = Application_Model_Show::getStartEndCurrentMonthView();
} else { } else {
$editable = false; Logging::error("Invalid Calendar Interval '$calendar_interval'");
} }
$events = &Application_Model_Show::getFullCalendarEvents($start, $end, $editable); $events = &Application_Model_Show::getFullCalendarEvents($start, $end, $editable);

View file

@ -110,7 +110,7 @@ class Zend_Controller_Plugin_Acl extends Zend_Controller_Plugin_Abstract
{ {
$controller = strtolower($request->getControllerName()); $controller = strtolower($request->getControllerName());
if (in_array($controller, array("api", "auth"))) { if (in_array($controller, array("api", "auth", "locale"))) {
$this->setRoleName("G"); $this->setRoleName("G");
} elseif (!Zend_Auth::getInstance()->hasIdentity()) { } elseif (!Zend_Auth::getInstance()->hasIdentity()) {

View file

@ -7,7 +7,7 @@ class Application_Form_RegisterAirtime extends Zend_Form
public function init() public function init()
{ {
$this->setAction(Application_Common_OsPath::getBaseDir().'/Showbuilder'); $this->setAction(Application_Common_OsPath::getBaseDir().'Showbuilder');
$this->setMethod('post'); $this->setMethod('post');
$country_list = Application_Model_Preference::GetCountryList(); $country_list = Application_Model_Preference::GetCountryList();

View file

@ -24,7 +24,7 @@
<div class="personal-block solo"> <div class="personal-block solo">
<ul> <ul>
<li> <li>
<a id="current-user" href=<?php echo $baseUrl . "User/edit-user"?>><span class="name"><?php echo $this->loggedInAs()?></span></a> | <a href=<?php echo $baseUrl . "Login/logout"?>><?php echo _("Logout")?></a> <a id="current-user" href=<?php echo $baseUrl . "User/edit-user"?>><span class="name"><?php echo $this->escape($this->loggedInAs()); ?></span></a> | <a href=<?php echo $baseUrl . "Login/logout"?>><?php echo _("Logout")?></a>
</li> </li>
</ul> </ul>
</div> </div>

View file

@ -32,6 +32,8 @@ class Logging {
{ {
if (is_array($p_msg) || is_object($p_msg)) { if (is_array($p_msg) || is_object($p_msg)) {
return print_r($p_msg, true); return print_r($p_msg, true);
} else if (is_bool($p_msg)) {
return $p_msg ? "true" : "false";
} else { } else {
return $p_msg; return $p_msg;
} }

View file

@ -731,6 +731,10 @@ 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']) {
$schedule_item['cue_in'] = $schedule_item['cue_out'];
}
self::appendScheduleItem($data, $start, $schedule_item); self::appendScheduleItem($data, $start, $schedule_item);
} }
@ -941,7 +945,6 @@ SQL;
self::createScheduledEvents($data, $range_start, $range_end); self::createScheduledEvents($data, $range_start, $range_end);
self::foldData($data["media"]); self::foldData($data["media"]);
return $data; return $data;
} }

View file

@ -136,13 +136,17 @@ class Application_Model_Scheduler
if ($type === "audioclip") { if ($type === "audioclip") {
$file = CcFilesQuery::create()->findPK($id, $this->con); $file = CcFilesQuery::create()->findPK($id, $this->con);
$storedFile = new Application_Model_StoredFile($file->getDbId());
if (is_null($file) || !$file->visible()) { if (is_null($file) || !$file->visible()) {
throw new Exception(_("A selected File does not exist!")); throw new Exception(_("A selected File does not exist!"));
} else { } else {
$data = $this->fileInfo; $data = $this->fileInfo;
$data["id"] = $id; $data["id"] = $id;
$data["cliplength"] = $file->getDbLength(); $data["cliplength"] = $storedFile->getRealClipLength(
$file->getDbCuein(),
$file->getDbCueout());
$data["cuein"] = $file->getDbCuein(); $data["cuein"] = $file->getDbCuein();
$data["cueout"] = $file->getDbCueout(); $data["cueout"] = $file->getDbCueout();
@ -438,7 +442,6 @@ class Application_Model_Scheduler
} }
foreach ($schedFiles as $file) { foreach ($schedFiles as $file) {
$endTimeDT = $this->findEndTime($nextStartDT, $file['cliplength']); $endTimeDT = $this->findEndTime($nextStartDT, $file['cliplength']);
//item existed previously and is being moved. //item existed previously and is being moved.

View file

@ -1750,14 +1750,15 @@ SQL;
$interval = $p_start->diff($p_end); $interval = $p_start->diff($p_end);
$days = $interval->format('%a'); $days = $interval->format('%a');
$shows = Application_Model_Show::getShows($p_start, $p_end); $shows = Application_Model_Show::getShows($p_start, $p_end);
$nowEpoch = time();
$content_count = Application_Model_ShowInstance::getContentCount( $content_count = Application_Model_ShowInstance::getContentCount(
$p_start, $p_end); $p_start, $p_end);
$isFull = Application_Model_ShowInstance::getIsFull($p_start, $p_end); $isFull = Application_Model_ShowInstance::getIsFull($p_start, $p_end);
$timezone = date_default_timezone_get(); $timezone = date_default_timezone_get();
$current_timezone = new DateTimeZone($timezone);
$utc = new DateTimeZone("UTC"); $utc = new DateTimeZone("UTC");
$now = new DateTime("now", $utc);
foreach ($shows as $show) { foreach ($shows as &$show) {
$options = array(); $options = array();
//only bother calculating percent for week or day view. //only bother calculating percent for week or day view.
@ -1767,7 +1768,6 @@ SQL;
if (isset($show["parent_starts"])) { if (isset($show["parent_starts"])) {
$parentStartsDT = new DateTime($show["parent_starts"], $utc); $parentStartsDT = new DateTime($show["parent_starts"], $utc);
$parentStartsEpoch = intval($parentStartsDT->format("U"));
} }
$startsDT = DateTime::createFromFormat("Y-m-d G:i:s", $startsDT = DateTime::createFromFormat("Y-m-d G:i:s",
@ -1775,35 +1775,53 @@ SQL;
$endsDT = DateTime::createFromFormat("Y-m-d G:i:s", $endsDT = DateTime::createFromFormat("Y-m-d G:i:s",
$show["ends"], $utc); $show["ends"], $utc);
$startsEpochStr = $startsDT->format("U");
$endsEpochStr = $endsDT->format("U");
$startsEpoch = intval($startsEpochStr);
$endsEpoch = intval($endsEpochStr);
$startsDT->setTimezone(new DateTimeZone($timezone));
$endsDT->setTimezone(new DateTimeZone($timezone));
if( $p_editable ) { if( $p_editable ) {
if ($show["record"] && $nowEpoch > $startsEpoch) { if ($show["record"] && $now > $startsDT) {
$options["editable"] = false; $options["editable"] = false;
} elseif ($show["rebroadcast"] && } elseif ($show["rebroadcast"] &&
$nowEpoch > $parentStartsEpoch) { $now > $parentStartsDT) {
$options["editable"] = false; $options["editable"] = false;
} elseif ($nowEpoch < $endsEpoch) { } elseif ($now < $endsDT) {
$options["editable"] = true; $options["editable"] = true;
} }
} }
$startsDT->setTimezone($current_timezone);
$endsDT->setTimezone($current_timezone);
$options["show_empty"] = (array_key_exists($show['instance_id'], $options["show_empty"] = (array_key_exists($show['instance_id'],
$content_count)) ? 0 : 1; $content_count)) ? 0 : 1;
$options["show_partial_filled"] = !$isFull[$show['instance_id']]; $options["show_partial_filled"] = !$isFull[$show['instance_id']];
$events[] = &self::makeFullCalendarEvent($show, $options, $event = array();
$startsDT, $endsDT, $startsEpochStr, $endsEpochStr);
$event["id"] = intval($show["instance_id"]);
$event["title"] = $show["name"];
$event["start"] = $startsDT->format("Y-m-d H:i:s");
$event["end"] = $endsDT->format("Y-m-d H:i:s");
$event["allDay"] = false;
$event["showId"] = intval($show["show_id"]);
$event["record"] = intval($show["record"]);
$event["rebroadcast"] = intval($show["rebroadcast"]);
$event["soundcloud_id"] = is_null($show["soundcloud_id"])
? -1 : $show["soundcloud_id"];
//event colouring
if ($show["color"] != "") {
$event["textColor"] = "#".$show["color"];
} }
if ($show["background_color"] != "") {
$event["color"] = "#".$show["background_color"];
}
foreach ($options as $key => $value) {
$event[$key] = $value;
}
$events[] = $event;
}
return $events; return $events;
} }
@ -1820,7 +1838,7 @@ SQL;
return $percent; return $percent;
} }
private static function &makeFullCalendarEvent(&$show, $options=array(), $startDateTime, $endDateTime, $startsEpoch, $endsEpoch) /* private static function &makeFullCalendarEvent(&$show, $options=array(), $startDateTime, $endDateTime, $startsEpoch, $endsEpoch)
{ {
$event = array(); $event = array();
@ -1851,7 +1869,7 @@ SQL;
} }
return $event; return $event;
} }*/
/* Takes in a UTC DateTime object. /* Takes in a UTC DateTime object.
* Converts this to local time, since cc_show days * Converts this to local time, since cc_show days
@ -2158,4 +2176,42 @@ SQL;
} }
return $assocArray; return $assocArray;
} }
public static function getStartEndCurrentMonthView() {
$first_day_of_calendar_month_view = mktime(0, 0, 0, date("n"), 1);
$weekStart = Application_Model_Preference::GetWeekStartDay();
while (date('w', $first_day_of_calendar_month_view) != $weekStart) {
$first_day_of_calendar_month_view -= 60*60*24;
}
$last_day_of_calendar_view = $first_day_of_calendar_month_view + 3600*24*42;
$start = new DateTime("@".$first_day_of_calendar_month_view);
$end = new DateTime("@".$last_day_of_calendar_view);
return array($start, $end);
}
public static function getStartEndCurrentWeekView() {
$first_day_of_calendar_week_view = mktime(0, 0, 0, date("n"), date("j"));
$weekStart = Application_Model_Preference::GetWeekStartDay();
while (date('w', $first_day_of_calendar_week_view) != $weekStart) {
$first_day_of_calendar_week_view -= 60*60*24;
}
$last_day_of_calendar_view = $first_day_of_calendar_week_view + 3600*24*7;
$start = new DateTime("@".$first_day_of_calendar_week_view);
$end = new DateTime("@".$last_day_of_calendar_view);
return array($start, $end);
}
public static function getStartEndCurrentDayView() {
$today = mktime(0, 0, 0, date("n"), date("j"));
$tomorrow = $today + 3600*24;
$start = new DateTime("@".$today);
$end = new DateTime("@".$tomorrow);
return array($start, $end);
}
} }

View file

@ -227,7 +227,7 @@ class Application_Model_ShowBuilder
$row["endDate"] = $showEndDT->format("Y-m-d"); $row["endDate"] = $showEndDT->format("Y-m-d");
$row["endTime"] = $showEndDT->format("H:i"); $row["endTime"] = $showEndDT->format("H:i");
$row["duration"] = floatval($showEndDT->format("U.u")) - floatval($showStartDT->format("U.u")); $row["duration"] = floatval($showEndDT->format("U.u")) - floatval($showStartDT->format("U.u"));
$row["title"] = $p_item["show_name"]; $row["title"] = htmlspecialchars($p_item["show_name"]);
$row["instance"] = intval($p_item["si_id"]); $row["instance"] = intval($p_item["si_id"]);
$row["image"] = ''; $row["image"] = '';

View file

@ -1310,6 +1310,14 @@ SQL;
return $updateIsScheduled; return $updateIsScheduled;
} }
public function getRealClipLength($p_cuein, $p_cueout) {
$sql = "SELECT :cueout::INTERVAL - :cuein::INTERVAL";
return Application_Common_Database::prepareAndExecute($sql, array(
':cueout' => $p_cueout,
':cuein' => $p_cuein), 'column');
}
} }
class DeleteScheduledFileException extends Exception {} class DeleteScheduledFileException extends Exception {}

View file

@ -214,18 +214,6 @@ class Application_Model_Systemstatus
{ {
$partions = array(); $partions = array();
if (isset($_SERVER['AIRTIME_SRV'])) {
//connect to DB and find how much total space user has allocated.
$totalSpace = Application_Model_Preference::GetDiskQuota();
$storPath = Application_Model_MusicDir::getStorDir()->getDirectory();
list($usedSpace,) = preg_split("/[\s]+/", exec("du -bs $storPath"));
$partitions[$totalSpace]->totalSpace = $totalSpace;
$partitions[$totalSpace]->totalFreeSpace = $totalSpace - $usedSpace;
Logging::info($partitions[$totalSpace]->totalFreeSpace);
} else {
/* 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. */
$musicDirs = Application_Model_MusicDir::getWatchedDirs(); $musicDirs = Application_Model_MusicDir::getWatchedDirs();
@ -243,7 +231,6 @@ class Application_Model_Systemstatus
$partitions[$totalSpace]->dirs[] = $md->getDirectory(); $partitions[$totalSpace]->dirs[] = $md->getDirectory();
} }
}
return array_values($partitions); return array_values($partitions);
} }

View file

@ -335,6 +335,8 @@ class Application_Model_User
} else { } else {
$record['delete'] = ""; $record['delete'] = "";
} }
$record = array_map('htmlspecialchars', $record);
} }
return $res; return $res;

View file

@ -1,4 +1,4 @@
<h2><? echo sprintf(_("%s's Settings"), $this->currentUser) ?></h2> <h2><? echo sprintf(_("%s's Settings"), $this->escape($this->currentUser)) ?></h2>
<div id="current-user-container"> <div id="current-user-container">
<form id="current-user-form" class="edit-user-global" method="post" enctype="application/x-www-form-urlencoded"> <form id="current-user-form" class="edit-user-global" method="post" enctype="application/x-www-form-urlencoded">
<dl class="zend_form"> <dl class="zend_form">

View file

@ -11,7 +11,7 @@
<?php if($this->element->getElement('storageFolder')->hasErrors()) : ?> <?php if($this->element->getElement('storageFolder')->hasErrors()) : ?>
<ul class='errors'> <ul class='errors'>
<?php foreach($this->element->getElement('storageFolder')->getMessages() as $error): ?> <?php foreach($this->element->getElement('storageFolder')->getMessages() as $error): ?>
<li><?php echo $error; ?></li> <li><?php echo $this->escape($error); ?></li>
<?php endforeach; ?> <?php endforeach; ?>
</ul> </ul>
<?php endif; ?> <?php endif; ?>
@ -29,7 +29,7 @@
<?php if($this->element->getElement('watchedFolder')->hasErrors()) : ?> <?php if($this->element->getElement('watchedFolder')->hasErrors()) : ?>
<ul class='errors'> <ul class='errors'>
<?php foreach($this->element->getElement('watchedFolder')->getMessages() as $error): ?> <?php foreach($this->element->getElement('watchedFolder')->getMessages() as $error): ?>
<li><?php echo $error; ?></li> <li><?php echo $this->escape($error); ?></li>
<?php endforeach; ?> <?php endforeach; ?>
</ul> </ul>
<?php endif; ?> <?php endif; ?>

View file

@ -42,7 +42,7 @@ if (isset($this->obj)) {
<input id='obj_type' type='hidden' value='playlist'></input> <input id='obj_type' type='hidden' value='playlist'></input>
<div class="playlist_title"> <div class="playlist_title">
<h3 id="obj_name"> <h3 id="obj_name">
<a id="playlist_name_display" contenteditable="true"><?php echo $this->obj->getName(); ?></a> <a id="playlist_name_display" contenteditable="true"><?php echo $this->escape($this->obj->getName()); ?></a>
</h3> </h3>
<h4 id="obj_length"><?php echo $this->length; ?></h4> <h4 id="obj_length"><?php echo $this->length; ?></h4>
</div> </div>

View file

@ -1,6 +1,6 @@
$(window).load(function(){ $(window).load(function(){
$("#username").focus(); $("#username").focus();
$("#locale").val($.cookie("airtime_locale")!== null?$.cookie("airtime_locale"):'en_CA'); $("#locale").val($.cookie("airtime_locale")!== null?$.cookie("airtime_locale"):$.cookie("default_airtime_locale"));
}); });
$(document).ready(function() { $(document).ready(function() {

View file

@ -111,6 +111,7 @@ $(document).ready(function() {
$.post(url, {format: "json", data: data}, function(data){ $.post(url, {format: "json", data: data}, function(data){
var json = $.parseJSON(data); var json = $.parseJSON(data);
$('#content').empty().append(json.html); $('#content').empty().append(json.html);
$.cookie("default_airtime_locale", $('#locale').val(), {path: '/'});
setTimeout(removeSuccessMsg, 5000); setTimeout(removeSuccessMsg, 5000);
showErrorSections(); showErrorSections();
}); });

View file

@ -28,7 +28,7 @@ function rebuildStreamURL(ele){
}else{ }else{
streamurl = "http://"+host+":"+port+"/" streamurl = "http://"+host+":"+port+"/"
} }
div.find("#stream_url").html(streamurl) div.find("#stream_url").text(streamurl)
} }
function restrictOggBitrate(ele, on){ function restrictOggBitrate(ele, on){
var div = ele.closest("div") var div = ele.closest("div")

View file

@ -37,7 +37,7 @@ function createDateInput(el, onSelect) {
dayNamesMin: i18n_days_short, dayNamesMin: i18n_days_short,
closeText: $.i18n._('Close'), closeText: $.i18n._('Close'),
//showButtonPanel: true, //showButtonPanel: true,
firstDay: weekStart firstDay: calendarPref.weekStart
}); });
} }
@ -324,7 +324,7 @@ function setAddShowEvents() {
dayNamesMin: i18n_days_short, dayNamesMin: i18n_days_short,
closeText: 'Close', closeText: 'Close',
showButtonPanel: true, showButtonPanel: true,
firstDay: weekStart firstDay: calendarPref.weekStart
}); });
form.find('input[name^="add_show_rebroadcast_time"]').timepicker({ form.find('input[name^="add_show_rebroadcast_time"]').timepicker({
amPmText: ['', ''], amPmText: ['', ''],

View file

@ -326,19 +326,34 @@ function eventResize( event, dayDelta, minuteDelta, revertFunc, jsEvent, ui, vie
}); });
} }
function preloadEventFeed () {
var url = baseUrl+'Schedule/event-feed-preload';
var d = new Date();
$.post(url, {format: "json", cachep: d.getTime()}, function(json){
calendarEvents = json.events;
createFullCalendar({calendarInit: calendarPref});
});
}
var initialLoad = true;
function getFullCalendarEvents(start, end, callback) { function getFullCalendarEvents(start, end, callback) {
if (initialLoad) {
initialLoad = false;
callback(calendarEvents);
} else {
var url, start_date, end_date; var url, start_date, end_date;
start_date = makeTimeStamp(start); start_date = makeTimeStamp(start);
end_date = makeTimeStamp(end); end_date = makeTimeStamp(end);
url = baseUrl+'Schedule/event-feed'; url = baseUrl+'Schedule/event-feed';
var d = new Date(); var d = new Date();
$.post(url, {format: "json", start: start_date, end: end_date, cachep: d.getTime()}, function(json){ $.post(url, {format: "json", start: start_date, end: end_date, cachep: d.getTime()}, function(json){
callback(json.events); callback(json.events);
}); });
}
} }
function checkSCUploadStatus(){ function checkSCUploadStatus(){
@ -541,6 +556,7 @@ function alertShowErrorAndReload(){
window.location.reload(); window.location.reload();
} }
preloadEventFeed();
$(document).ready(function(){ $(document).ready(function(){
setInterval( "checkSCUploadStatus()", 5000 ); setInterval( "checkSCUploadStatus()", 5000 );
setInterval( "getCurrentShow()", 5000 ); setInterval( "getCurrentShow()", 5000 );

View file

@ -328,9 +328,6 @@ function alertShowErrorAndReload(){
} }
$(document).ready(function() { $(document).ready(function() {
$.ajax({ url: baseUrl+"Api/calendar-init/format/json", dataType:"json", success:createFullCalendar
, error:function(jqXHR, textStatus, errorThrown){}});
setInterval(checkCalendarSCUploadStatus, 5000); setInterval(checkCalendarSCUploadStatus, 5000);
$.contextMenu({ $.contextMenu({

View file

@ -1,6 +1,7 @@
2.3.0 - Jan 21st, 2013 2.3.0 - Jan 21st, 2013
* New features * New features
* Localization (Brazilian, Chinese, Czech, English, French, German, Italian, Korean, Portugese, Russian, Spanish) * Localization (Chinese, Czech, English, French, German, Italian, Korean,
Portuguese, Russian, Spanish)
* User management page for non-admin users * User management page for non-admin users
* Listener statistics (Icecast/Shoutcast) * Listener statistics (Icecast/Shoutcast)
* Airtime no longer requires Apache document root * Airtime no longer requires Apache document root

View file

@ -15,6 +15,8 @@ INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s3_admin_pas
UPDATE cc_music_dirs SET directory = directory || '/' where id in (select id from cc_music_dirs where substr(directory, length(directory)) != '/'); UPDATE cc_music_dirs SET directory = directory || '/' where id in (select id from cc_music_dirs where substr(directory, length(directory)) != '/');
UPDATE cc_files SET filepath = substring(filepath from 2) where id in (select id from cc_files where substring(filepath from 1 for 1) = '/'); UPDATE cc_files SET filepath = substring(filepath from 2) where id in (select id from cc_files where substring(filepath from 1 for 1) = '/');
UPDATE cc_files SET cueout = length where cueout = '00:00:00';
INSERT INTO cc_pref("keystr", "valstr") VALUES('locale', 'en_CA'); INSERT INTO cc_pref("keystr", "valstr") VALUES('locale', 'en_CA');
INSERT INTO cc_pref("subjid", "keystr", "valstr") VALUES(1, 'user_locale', 'en_CA'); INSERT INTO cc_pref("subjid", "keystr", "valstr") VALUES(1, 'user_locale', 'en_CA');

View file

@ -73,17 +73,26 @@ class ApcUrl(object):
else: return self.base_url else: return self.base_url
class ApiRequest(object): class ApiRequest(object):
def __init__(self, name, url): def __init__(self, name, url, logger=None):
self.name = name self.name = name
self.url = url self.url = url
self.__req = None self.__req = None
if logger is None: self.logger = logging
else: self.logger = logger
def __call__(self,_post_data=None, **kwargs): def __call__(self,_post_data=None, **kwargs):
# TODO : get rid of god damn urllib and replace everything with # TODO : get rid of god damn urllib and replace everything with
# grequests or requests at least # grequests or requests at least
final_url = self.url.params(**kwargs).url() final_url = self.url.params(**kwargs).url()
if _post_data is not None: _post_data = urllib.urlencode(_post_data) if _post_data is not None: _post_data = urllib.urlencode(_post_data)
try:
req = urllib2.Request(final_url, _post_data) req = urllib2.Request(final_url, _post_data)
response = urllib2.urlopen(req).read() response = urllib2.urlopen(req).read()
except Exception, e:
self.logger.error('Exception: %s', e)
import traceback
top = traceback.format_exc()
self.logger.error("traceback: %s", top)
response = ""
# Ghetto hack for now because we don't the content type we are getting # Ghetto hack for now because we don't the content type we are getting
# (Pointless to look at mime since it's not being set correctly always) # (Pointless to look at mime since it's not being set correctly always)
try: return json.loads(response) try: return json.loads(response)
@ -168,9 +177,9 @@ class AirtimeApiClient(object):
def get_schedule(self): def get_schedule(self):
# TODO : properly refactor this routine # TODO : properly refactor this routine
# For now thre return type is a little fucked for compatibility reasons # For now the return type is a little fucked for compatibility reasons
try: return (True, self.services.export_url()) try: return (True, self.services.export_url())
except: (False, "") except: return (False, None)
def notify_liquidsoap_started(self): def notify_liquidsoap_started(self):
return self.services.notify_liquidsoap_started() return self.services.notify_liquidsoap_started()

View file

@ -28,10 +28,10 @@ start () {
stop () { stop () {
monit unmonitor airtime-liquidsoap >/dev/null 2>&1 monit unmonitor airtime-liquidsoap >/dev/null 2>&1
/usr/lib/airtime/airtime_virtualenv/bin/python /usr/lib/airtime/pypo/bin/liquidsoap_scripts/liquidsoap_prepare_terminate.py #send term signal after 10 seconds
timeout 10 /usr/lib/airtime/airtime_virtualenv/bin/python /usr/lib/airtime/pypo/bin/liquidsoap_scripts/liquidsoap_prepare_terminate.py
# 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 5 --quiet --pidfile $PIDFILE start-stop-daemon --stop --oknodo --retry=TERM/10/KILL/5 --quiet --pidfile $PIDFILE
rm -f $PIDFILE rm -f $PIDFILE
} }

View file

@ -195,28 +195,81 @@ def check_dj_client(user,password) =
hd == "True" hd == "True"
end end
def append_dj_inputs(master_harbor_input_port, master_harbor_input_mount_point, dj_harbor_input_port, dj_harbor_input_mount_point, s) = def append_dj_inputs(master_harbor_input_port,
if master_harbor_input_port != 0 and master_harbor_input_mount_point != "" and dj_harbor_input_port != 0 and dj_harbor_input_mount_point != "" then master_harbor_input_mount_point,
master_dj = mksafe(audio_to_stereo(input.harbor(id="master_harbor", master_harbor_input_mount_point, port=master_harbor_input_port, auth=check_master_dj_client, dj_harbor_input_port,
max=40., on_connect=master_dj_connect, on_disconnect=master_dj_disconnect))) dj_harbor_input_mount_point,
dj_live = mksafe(audio_to_stereo(input.harbor(id="live_dj_harbor", dj_harbor_input_mount_point, port=dj_harbor_input_port, auth=check_dj_client, s) =
max=40., on_connect=live_dj_connect, on_disconnect=live_dj_disconnect))) if master_harbor_input_port != 0
and master_harbor_input_mount_point != ""
and dj_harbor_input_port != 0
and dj_harbor_input_mount_point != "" then
master_dj = mksafe(
audio_to_stereo(
input.harbor(id="master_harbor",
master_harbor_input_mount_point,
port=master_harbor_input_port,
auth=check_master_dj_client,
max=40.,
on_connect=master_dj_connect,
on_disconnect=master_dj_disconnect)))
dj_live = mksafe(
audio_to_stereo(
input.harbor(id="live_dj_harbor",
dj_harbor_input_mount_point,
port=dj_harbor_input_port,
auth=check_dj_client,
max=40.,
on_connect=live_dj_connect,
on_disconnect=live_dj_disconnect)))
ignore(output.dummy(master_dj, fallible=true)) ignore(output.dummy(master_dj, fallible=true))
ignore(output.dummy(dj_live, fallible=true)) ignore(output.dummy(dj_live, fallible=true))
switch(id="master_dj_switch", track_sensitive=false, transitions=[transition, transition, transition], [({!master_dj_enabled},master_dj), ({!live_dj_enabled},dj_live), ({true}, s)])
switch(id="master_dj_switch",
track_sensitive=false,
transitions=[transition, transition, transition],
[({!master_dj_enabled},master_dj),
({!live_dj_enabled},dj_live),
({true}, s)])
elsif master_harbor_input_port != 0 and master_harbor_input_mount_point != "" then elsif master_harbor_input_port != 0 and master_harbor_input_mount_point != "" then
master_dj = mksafe(audio_to_stereo(input.harbor(id="master_harbor", master_harbor_input_mount_point, port=master_harbor_input_port, auth=check_master_dj_client, master_dj = mksafe(
max=40., on_connect=master_dj_connect, on_disconnect=master_dj_disconnect))) audio_to_stereo(
input.harbor(id="master_harbor",
master_harbor_input_mount_point,
port=master_harbor_input_port,
auth=check_master_dj_client,
max=40.,
on_connect=master_dj_connect,
on_disconnect=master_dj_disconnect)))
ignore(output.dummy(master_dj, fallible=true)) ignore(output.dummy(master_dj, fallible=true))
switch(id="master_dj_switch", track_sensitive=false, transitions=[transition, transition], [({!master_dj_enabled},master_dj), ({true}, s)]) switch(id="master_dj_switch",
track_sensitive=false,
transitions=[transition, transition],
[({!master_dj_enabled},master_dj), ({true}, s)])
elsif dj_harbor_input_port != 0 and dj_harbor_input_mount_point != "" then elsif dj_harbor_input_port != 0 and dj_harbor_input_mount_point != "" then
dj_live = mksafe(audio_to_stereo(input.harbor(id="live_dj_harbor", dj_harbor_input_mount_point, port=dj_harbor_input_port, auth=check_dj_client, dj_live = mksafe(
max=40., on_connect=live_dj_connect, on_disconnect=live_dj_disconnect))) audio_to_stereo(
input.harbor(id="live_dj_harbor",
dj_harbor_input_mount_point,
port=dj_harbor_input_port,
auth=check_dj_client,
max=40.,
on_connect=live_dj_connect,
on_disconnect=live_dj_disconnect)))
ignore(output.dummy(dj_live, fallible=true)) ignore(output.dummy(dj_live, fallible=true))
switch(id="live_dj_switch", track_sensitive=false, transitions=[transition, transition], [({!live_dj_enabled},dj_live), ({true}, s)])
switch(id="live_dj_switch",
track_sensitive=false,
transitions=[transition, transition],
[({!live_dj_enabled},dj_live), ({true}, s)])
else else
s s
end end

View file

@ -5,5 +5,5 @@
check process airtime-playout check process airtime-playout
with pidfile "/var/run/airtime-playout.pid" with pidfile "/var/run/airtime-playout.pid"
start program = "/etc/init.d/airtime-playout monit-restart" with timeout 5 seconds start program = "/etc/init.d/airtime-playout start" with timeout 5 seconds
stop program = "/etc/init.d/airtime-playout stop" stop program = "/etc/init.d/airtime-playout stop"

View file

@ -18,7 +18,8 @@ from std_err_override import LogWriter
from configobj import ConfigObj from configobj import ConfigObj
# configure logging # configure logging
logging.config.fileConfig("logging.cfg") logging_cfg = os.path.join(os.path.dirname(__file__), "logging.cfg")
logging.config.fileConfig(logging_cfg)
logger = logging.getLogger() logger = logging.getLogger()
LogWriter.override_std_err(logger) LogWriter.override_std_err(logger)
@ -132,9 +133,10 @@ class PypoFetch(Thread):
elif(sourcename == "live_dj"): elif(sourcename == "live_dj"):
command += "live_dj_harbor.kick\n" command += "live_dj_harbor.kick\n"
lock.acquire()
try: try:
lock.acquire()
tn = telnetlib.Telnet(LS_HOST, LS_PORT) tn = telnetlib.Telnet(LS_HOST, LS_PORT)
logger.info(command)
tn.write(command) tn.write(command)
tn.write('exit\n') tn.write('exit\n')
tn.read_all() tn.read_all()
@ -143,6 +145,24 @@ class PypoFetch(Thread):
finally: finally:
lock.release() lock.release()
@staticmethod
def telnet_send(logger, lock, commands):
try:
lock.acquire()
tn = telnetlib.Telnet(LS_HOST, LS_PORT)
for i in commands:
logger.info(i)
tn.write(i)
tn.write('exit\n')
tn.read_all()
except Exception, e:
logger.error(str(e))
finally:
lock.release()
@staticmethod @staticmethod
def switch_source(logger, lock, sourcename, status): def switch_source(logger, lock, sourcename, status):
logger.debug('Switching source: %s to "%s" status', sourcename, status) logger.debug('Switching source: %s to "%s" status', sourcename, status)
@ -159,16 +179,26 @@ class PypoFetch(Thread):
else: else:
command += "stop\n" command += "stop\n"
lock.acquire() PypoFetch.telnet_send(logger, lock, [command])
try:
tn = telnetlib.Telnet(LS_HOST, LS_PORT)
tn.write(command) #TODO: Merge this with switch_source
tn.write('exit\n') def switch_source_temp(self, sourcename, status):
tn.read_all() self.logger.debug('Switching source: %s to "%s" status', sourcename, status)
except Exception, e: command = "streams."
logger.error(str(e)) if sourcename == "master_dj":
finally: command += "master_dj_"
lock.release() elif sourcename == "live_dj":
command += "live_dj_"
elif sourcename == "scheduled_play":
command += "scheduled_play_"
if status == "on":
command += "start\n"
else:
command += "stop\n"
return command
""" """
grabs some information that are needed to be set on bootstrap time grabs some information that are needed to be set on bootstrap time
@ -179,19 +209,25 @@ class PypoFetch(Thread):
info = self.api_client.get_bootstrap_info() info = self.api_client.get_bootstrap_info()
if info is None: if info is None:
self.logger.error('Unable to get bootstrap info.. Exiting pypo...') self.logger.error('Unable to get bootstrap info.. Exiting pypo...')
sys.exit(1)
else: else:
self.logger.debug('info:%s', info) self.logger.debug('info:%s', info)
commands = []
for k, v in info['switch_status'].iteritems(): for k, v in info['switch_status'].iteritems():
self.switch_source(self.logger, self.telnet_lock, k, v) commands.append(self.switch_source_temp(k, v))
self.update_liquidsoap_stream_format(info['stream_label'])
self.update_liquidsoap_station_name(info['station_name']) stream_format = info['stream_label']
self.update_liquidsoap_transition_fade(info['transition_fade']) station_name = info['station_name']
fade = info['transition_fade']
commands.append(('vars.stream_metadata_type %s\n' % stream_format).encode('utf-8'))
commands.append(('vars.station_name %s\n' % station_name).encode('utf-8'))
commands.append(('vars.default_dj_fade %s\n' % fade).encode('utf-8'))
PypoFetch.telnet_send(self.logger, self.telnet_lock, commands)
def restart_liquidsoap(self): def restart_liquidsoap(self):
self.telnet_lock.acquire()
try: try:
self.telnet_lock.acquire()
self.logger.info("Restarting Liquidsoap") self.logger.info("Restarting Liquidsoap")
subprocess.call('/etc/init.d/airtime-liquidsoap restart', shell=True) subprocess.call('/etc/init.d/airtime-liquidsoap restart', shell=True)
@ -217,7 +253,7 @@ class PypoFetch(Thread):
self.set_bootstrap_variables() self.set_bootstrap_variables()
#get the most up to date schedule, which will #initiate the process #get the most up to date schedule, which will #initiate the process
#of making sure Liquidsoap is playing the schedule #of making sure Liquidsoap is playing the schedule
self.manual_schedule_fetch() self.persistent_manual_schedule_fetch(max_attempts=5)
except Exception, e: except Exception, e:
self.logger.error(str(e)) self.logger.error(str(e))
@ -322,16 +358,21 @@ class PypoFetch(Thread):
This function updates the bootup time variable in Liquidsoap script This function updates the bootup time variable in Liquidsoap script
""" """
self.telnet_lock.acquire()
try: try:
self.telnet_lock.acquire()
tn = telnetlib.Telnet(LS_HOST, LS_PORT) tn = telnetlib.Telnet(LS_HOST, LS_PORT)
# update the boot up time of Liquidsoap. Since Liquidsoap is not restarting, # update the boot up time of Liquidsoap. Since Liquidsoap is not restarting,
# we are manually adjusting the bootup time variable so the status msg will get # we are manually adjusting the bootup time variable so the status msg will get
# updated. # updated.
current_time = time.time() current_time = time.time()
boot_up_time_command = "vars.bootup_time " + str(current_time) + "\n" boot_up_time_command = "vars.bootup_time " + str(current_time) + "\n"
self.logger.info(boot_up_time_command)
tn.write(boot_up_time_command) tn.write(boot_up_time_command)
tn.write("streams.connection_status\n")
connection_status = "streams.connection_status\n"
self.logger.info(connection_status)
tn.write(connection_status)
tn.write('exit\n') tn.write('exit\n')
output = tn.read_all() output = tn.read_all()
@ -356,6 +397,7 @@ class PypoFetch(Thread):
if(status == "true"): if(status == "true"):
self.api_client.notify_liquidsoap_status("OK", stream_id, str(fake_time)) self.api_client.notify_liquidsoap_status("OK", stream_id, str(fake_time))
def update_liquidsoap_stream_format(self, stream_format): def update_liquidsoap_stream_format(self, stream_format):
# Push stream metadata to liquidsoap # Push stream metadata to liquidsoap
# TODO: THIS LIQUIDSOAP STUFF NEEDS TO BE MOVED TO PYPO-PUSH!!! # TODO: THIS LIQUIDSOAP STUFF NEEDS TO BE MOVED TO PYPO-PUSH!!!
@ -395,8 +437,8 @@ class PypoFetch(Thread):
self.logger.info(LS_HOST) self.logger.info(LS_HOST)
self.logger.info(LS_PORT) self.logger.info(LS_PORT)
self.telnet_lock.acquire()
try: try:
self.telnet_lock.acquire()
tn = telnetlib.Telnet(LS_HOST, LS_PORT) tn = telnetlib.Telnet(LS_HOST, LS_PORT)
command = ('vars.station_name %s\n' % station_name).encode('utf-8') command = ('vars.station_name %s\n' % station_name).encode('utf-8')
self.logger.info(command) self.logger.info(command)
@ -488,10 +530,20 @@ class PypoFetch(Thread):
self.process_schedule(self.schedule_data) self.process_schedule(self.schedule_data)
return success return success
def persistent_manual_schedule_fetch(self, max_attempts=1):
success = False
num_attempts = 0
while not success and num_attempts < max_attempts:
success = self.manual_schedule_fetch()
num_attempts += 1
return success
def main(self): def main(self):
# Bootstrap: since we are just starting up, we need to grab the # Bootstrap: since we are just starting up, we need to grab the
# most recent schedule. After that we can just wait for updates. # most recent schedule. After that we can just wait for updates.
success = self.manual_schedule_fetch() success = self.persistent_manual_schedule_fetch(max_attempts=5)
if success: if success:
self.logger.info("Bootstrap schedule received: %s", self.schedule_data) self.logger.info("Bootstrap schedule received: %s", self.schedule_data)
self.set_bootstrap_variables() self.set_bootstrap_variables()
@ -519,7 +571,7 @@ class PypoFetch(Thread):
self.handle_message(message) self.handle_message(message)
except Empty, e: except Empty, e:
self.logger.info("Queue timeout. Fetching schedule manually") self.logger.info("Queue timeout. Fetching schedule manually")
self.manual_schedule_fetch() self.persistent_manual_schedule_fetch(max_attempts=5)
except Exception, e: except Exception, e:
import traceback import traceback
top = traceback.format_exc() top = traceback.format_exc()

View file

@ -43,7 +43,7 @@ parser.add_option("-t", "--time", help="Liquidsoap boot up time", action="store"
parser.add_option("-x", "--source-name", help="source connection name", metavar="source_name") parser.add_option("-x", "--source-name", help="source connection name", metavar="source_name")
parser.add_option("-y", "--source-status", help="source connection status", metavar="source_status") parser.add_option("-y", "--source-status", help="source connection status", metavar="source_status")
parser.add_option("-w", "--webstream", help="JSON metadata associated with webstream", metavar="json_data") parser.add_option("-w", "--webstream", help="JSON metadata associated with webstream", metavar="json_data")
parser.add_option("-n", "--liquidsoap-started", help="notify liquidsoap started", metavar="json_data", action="store_true", default=True) parser.add_option("-n", "--liquidsoap-started", help="notify liquidsoap started", metavar="json_data", action="store_true", default=False)
# parse options # parse options

View file

@ -9,6 +9,7 @@ import logging.config
import telnetlib import telnetlib
import calendar import calendar
import math import math
import os
from pypofetch import PypoFetch from pypofetch import PypoFetch
from Queue import Empty from Queue import Empty
@ -21,7 +22,8 @@ from configobj import ConfigObj
# configure logging # configure logging
logging.config.fileConfig("logging.cfg") logging_cfg = os.path.join(os.path.dirname(__file__), "logging.cfg")
logging.config.fileConfig(logging_cfg)
logger = logging.getLogger() logger = logging.getLogger()
LogWriter.override_std_err(logger) LogWriter.override_std_err(logger)
@ -249,7 +251,7 @@ class PypoPush(Thread):
self.start_web_stream_buffer(current_item) self.start_web_stream_buffer(current_item)
self.start_web_stream(current_item) self.start_web_stream(current_item)
if is_file(current_item): if is_file(current_item):
self.modify_cue_point(file_chain[0]) file_chain = self.modify_first_link_cue_point(file_chain)
self.push_to_liquidsoap(file_chain) self.push_to_liquidsoap(file_chain)
#we've changed the queue, so let's refetch it #we've changed the queue, so let's refetch it
liquidsoap_queue_approx = self.get_queue_items_from_liquidsoap() liquidsoap_queue_approx = self.get_queue_items_from_liquidsoap()
@ -279,7 +281,7 @@ class PypoPush(Thread):
chain_to_push = file_chain[problem_at_iteration:] chain_to_push = file_chain[problem_at_iteration:]
if len(chain_to_push) > 0: if len(chain_to_push) > 0:
self.modify_cue_point(chain_to_push[0]) chain_to_push = self.modify_first_link_cue_point(chain_to_push)
self.push_to_liquidsoap(chain_to_push) self.push_to_liquidsoap(chain_to_push)
@ -363,6 +365,18 @@ class PypoPush(Thread):
original_cue_in_td = timedelta(seconds=float(link['cue_in'])) original_cue_in_td = timedelta(seconds=float(link['cue_in']))
link['cue_in'] = self.date_interval_to_seconds(original_cue_in_td) + diff_sec link['cue_in'] = self.date_interval_to_seconds(original_cue_in_td) + diff_sec
def modify_first_link_cue_point(self, chain):
if not len(chain):
return []
first_link = chain[0]
self.modify_cue_point(first_link)
if float(first_link['cue_in']) >= float(first_link['cue_out']):
chain = chain [1:]
return chain
""" """
Returns two chains, original chain and current_chain. current_chain is a subset of Returns two chains, original chain and current_chain. current_chain is a subset of
original_chain but can also be equal to original chain. original_chain but can also be equal to original chain.

View file

@ -0,0 +1,18 @@
#!/bin/bash
which py.test
pytest_exist=$?
if [ "$pytest_exist" != "0" ]; then
echo "Need to have py.test installed. Exiting..."
exit 1
fi
SCRIPT=`readlink -f $0`
# Absolute directory this script is in
SCRIPTPATH=`dirname $SCRIPT`
export PYTHONPATH=$PYTHONPATH:$SCRIPTPATH/..:$SCRIPTPATH/../..
py.test

View file

@ -0,0 +1,26 @@
from pypopush import PypoPush
from threading import Lock
from Queue import Queue
import datetime
pypoPush_q = Queue()
telnet_lock = Lock()
pp = PypoPush(pypoPush_q, telnet_lock)
def test_modify_cue_in():
link = pp.modify_first_link_cue_point([])
assert len(link) == 0
min_ago = datetime.datetime.utcnow() - datetime.timedelta(minutes = 1)
link = [{"start":min_ago.strftime("%Y-%m-%d-%H-%M-%S"),
"cue_in":"0", "cue_out":"30"}]
link = pp.modify_first_link_cue_point(link)
assert len(link) == 0
link = [{"start":min_ago.strftime("%Y-%m-%d-%H-%M-%S"),
"cue_in":"0", "cue_out":"70"}]
link = pp.modify_first_link_cue_point(link)
assert len(link) == 1

View file

@ -170,6 +170,8 @@ def WatchAddAction(option, opt, value, parser):
print "%s added to watched folder list successfully" % path print "%s added to watched folder list successfully" % path
else: else:
print "Adding a watched folder failed: %s" % res['msg']['error'] print "Adding a watched folder failed: %s" % res['msg']['error']
print "This error most likely caused by wrong permissions"
print "Try fixing this error by chmodding the parent directory(ies)"
else: else:
print "Given path is not a directory: %s" % path print "Given path is not a directory: %s" % path