Merge branch 'cc-5709-airtime-analyzer' into cc-5709-airtime-analyzer-cloud-storage
This commit is contained in:
commit
c09457ce7c
30 changed files with 11878 additions and 105 deletions
22
INSTALL
22
INSTALL
|
@ -1,22 +0,0 @@
|
||||||
Airtime is the open radio software for scheduling and remote station management.
|
|
||||||
Home page: http://airtime.sourcefabric.org/
|
|
||||||
|
|
||||||
Installation instructions are here:
|
|
||||||
http://wiki.sourcefabric.org/x/BQBF
|
|
||||||
|
|
||||||
Here is the manual:
|
|
||||||
http://en.flossmanuals.net/airtime/
|
|
||||||
|
|
||||||
To report bugs, visit our bug tracker at:
|
|
||||||
http://dev.sourcefabric.org/browse/CC
|
|
||||||
|
|
||||||
Visit our community support forum here:
|
|
||||||
http://forum.sourcefabric.org/index.php/f/14/
|
|
||||||
|
|
||||||
For commercial support, see:
|
|
||||||
http://sourcefabric.org/en/services/about/347/Support.htm
|
|
||||||
or send an e-mail to contact@sourcefabric.org
|
|
||||||
|
|
||||||
If you are a developer and want to hack on Airtime, go here:
|
|
||||||
http://wiki.sourcefabric.org/display/CC
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ require_once "DateHelper.php";
|
||||||
require_once "OsPath.php";
|
require_once "OsPath.php";
|
||||||
require_once "Database.php";
|
require_once "Database.php";
|
||||||
require_once "Timezone.php";
|
require_once "Timezone.php";
|
||||||
|
require_once "Auth.php";
|
||||||
require_once __DIR__.'/forms/helpers/ValidationTypes.php';
|
require_once __DIR__.'/forms/helpers/ValidationTypes.php';
|
||||||
require_once __DIR__.'/controllers/plugins/RabbitMqPlugin.php';
|
require_once __DIR__.'/controllers/plugins/RabbitMqPlugin.php';
|
||||||
require_once __DIR__.'/controllers/plugins/Maintenance.php';
|
require_once __DIR__.'/controllers/plugins/Maintenance.php';
|
||||||
|
@ -26,6 +27,8 @@ require_once __DIR__."/configs/navigation.php";
|
||||||
|
|
||||||
Zend_Validate::setDefaultNamespaces("Zend");
|
Zend_Validate::setDefaultNamespaces("Zend");
|
||||||
|
|
||||||
|
Application_Model_Auth::pinSessionToClient(Zend_Auth::getInstance());
|
||||||
|
|
||||||
$front = Zend_Controller_Front::getInstance();
|
$front = Zend_Controller_Front::getInstance();
|
||||||
$front->registerPlugin(new RabbitMqPlugin());
|
$front->registerPlugin(new RabbitMqPlugin());
|
||||||
|
|
||||||
|
|
|
@ -14,9 +14,10 @@ class LoginController extends Zend_Controller_Action
|
||||||
$request = $this->getRequest();
|
$request = $this->getRequest();
|
||||||
|
|
||||||
Application_Model_Locale::configureLocalization($request->getcookie('airtime_locale', 'en_CA'));
|
Application_Model_Locale::configureLocalization($request->getcookie('airtime_locale', 'en_CA'));
|
||||||
if (Zend_Auth::getInstance()->hasIdentity())
|
$auth = Zend_Auth::getInstance();
|
||||||
{
|
|
||||||
|
|
||||||
|
if ($auth->hasIdentity())
|
||||||
|
{
|
||||||
$this->_redirect('Showbuilder');
|
$this->_redirect('Showbuilder');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +54,6 @@ class LoginController extends Zend_Controller_Action
|
||||||
$authAdapter->setIdentity($username)
|
$authAdapter->setIdentity($username)
|
||||||
->setCredential($password);
|
->setCredential($password);
|
||||||
|
|
||||||
$auth = Zend_Auth::getInstance();
|
|
||||||
$result = $auth->authenticate($authAdapter);
|
$result = $auth->authenticate($authAdapter);
|
||||||
if ($result->isValid()) {
|
if ($result->isValid()) {
|
||||||
//all info about this user from the login table omit only the password
|
//all info about this user from the login table omit only the password
|
||||||
|
@ -66,14 +66,12 @@ class LoginController extends Zend_Controller_Action
|
||||||
Application_Model_LoginAttempts::resetAttempts($_SERVER['REMOTE_ADDR']);
|
Application_Model_LoginAttempts::resetAttempts($_SERVER['REMOTE_ADDR']);
|
||||||
Application_Model_Subjects::resetLoginAttempts($username);
|
Application_Model_Subjects::resetLoginAttempts($username);
|
||||||
|
|
||||||
$tempSess = new Zend_Session_Namespace("referrer");
|
|
||||||
$tempSess->referrer = 'login';
|
|
||||||
|
|
||||||
//set the user locale in case user changed it in when logging in
|
//set the user locale in case user changed it in when logging in
|
||||||
Application_Model_Preference::SetUserLocale($locale);
|
Application_Model_Preference::SetUserLocale($locale);
|
||||||
|
|
||||||
$this->_redirect('Showbuilder');
|
$this->_redirect('Showbuilder');
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
$message = _("Wrong username or password provided. Please try again.");
|
$message = _("Wrong username or password provided. Please try again.");
|
||||||
Application_Model_Subjects::increaseLoginAttempts($username);
|
Application_Model_Subjects::increaseLoginAttempts($username);
|
||||||
Application_Model_LoginAttempts::increaseAttempts($_SERVER['REMOTE_ADDR']);
|
Application_Model_LoginAttempts::increaseAttempts($_SERVER['REMOTE_ADDR']);
|
||||||
|
@ -96,7 +94,8 @@ class LoginController extends Zend_Controller_Action
|
||||||
|
|
||||||
public function logoutAction()
|
public function logoutAction()
|
||||||
{
|
{
|
||||||
Zend_Auth::getInstance()->clearIdentity();
|
$auth = Zend_Auth::getInstance();
|
||||||
|
$auth->clearIdentity();
|
||||||
$this->_redirect('showbuilder/index');
|
$this->_redirect('showbuilder/index');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -109,6 +109,7 @@ class Zend_Controller_Plugin_Acl extends Zend_Controller_Plugin_Abstract
|
||||||
public function preDispatch(Zend_Controller_Request_Abstract $request)
|
public function preDispatch(Zend_Controller_Request_Abstract $request)
|
||||||
{
|
{
|
||||||
$controller = strtolower($request->getControllerName());
|
$controller = strtolower($request->getControllerName());
|
||||||
|
Application_Model_Auth::pinSessionToClient(Zend_Auth::getInstance());
|
||||||
|
|
||||||
//Ignore authentication for all access to the rest API. We do auth via API keys for this
|
//Ignore authentication for all access to the rest API. We do auth via API keys for this
|
||||||
//and/or by OAuth.
|
//and/or by OAuth.
|
||||||
|
|
|
@ -13,8 +13,8 @@
|
||||||
<?php echo $this->layout()->content ?>
|
<?php echo $this->layout()->content ?>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<?php echo sprintf(_("Airtime Copyright ©Sourcefabric o.p.s. All rights reserved.%s"
|
<?php echo sprintf(_("Airtime copyright © Sourcefabric z.ú. All rights reserved.%s"
|
||||||
."Maintained and distributed under GNU GPL v.3 by %sSourcefabric o.p.s%s"),
|
."Maintained and distributed under the GNU GPL v.3 by %sSourcefabric z.ú.%s"),
|
||||||
"<br>", "<a href='http://www.sourcefabric.org'>" ,"</a>");?>
|
"<br>", "<a href='http://www.sourcefabric.org'>" ,"</a>");?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -110,4 +110,18 @@ class Application_Model_Auth
|
||||||
|
|
||||||
return $string;
|
return $string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** It is essential to do this before interacting with Zend_Auth otherwise sessions could be shared between
|
||||||
|
* different copies of Airtime on the same webserver. This essentially pins this session to:
|
||||||
|
* - The server hostname - including subdomain so we segment multiple Airtime installs on different subdomains
|
||||||
|
* - The remote IP of the browser - to help prevent session hijacking
|
||||||
|
* - The client ID - same reason as server hostname
|
||||||
|
* @param Zend_Auth $auth Get this with Zend_Auth::getInstance().
|
||||||
|
*/
|
||||||
|
public static function pinSessionToClient($auth)
|
||||||
|
{
|
||||||
|
$serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : "";
|
||||||
|
$remoteAddr = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : "";
|
||||||
|
$auth->setStorage(new Zend_Auth_Storage_Session('Airtime' . $serverName . $remoteAddr . Application_Model_Preference::GetClientId()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -545,7 +545,11 @@ class Application_Model_Preference
|
||||||
// Returns station default timezone (from preferences)
|
// Returns station default timezone (from preferences)
|
||||||
public static function GetDefaultTimezone()
|
public static function GetDefaultTimezone()
|
||||||
{
|
{
|
||||||
return self::getValue("timezone");
|
$stationTimezone = self::getValue("timezone");
|
||||||
|
if (is_null($stationTimezone) || $stationTimezone == "") {
|
||||||
|
$stationTimezone = "UTC";
|
||||||
|
}
|
||||||
|
return $stationTimezone;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function SetUserTimezone($timezone = null)
|
public static function SetUserTimezone($timezone = null)
|
||||||
|
@ -1314,6 +1318,11 @@ class Application_Model_Preference
|
||||||
|
|
||||||
$ds = unserialize($v);
|
$ds = unserialize($v);
|
||||||
|
|
||||||
|
|
||||||
|
if (is_null($ds) || !is_array($ds)) {
|
||||||
|
return $id;
|
||||||
|
}
|
||||||
|
|
||||||
if (!array_key_exists('ColReorder', $ds)) {
|
if (!array_key_exists('ColReorder', $ds)) {
|
||||||
return $id;
|
return $id;
|
||||||
}
|
}
|
||||||
|
|
|
@ -303,10 +303,10 @@ SQL;
|
||||||
$p_start_str = $p_start->format("Y-m-d H:i:s");
|
$p_start_str = $p_start->format("Y-m-d H:i:s");
|
||||||
$p_end_str = $p_end->format("Y-m-d H:i:s");
|
$p_end_str = $p_end->format("Y-m-d H:i:s");
|
||||||
|
|
||||||
//We need to search 24 hours before and after the show times so that that we
|
//We need to search 48 hours before and after the show times so that that we
|
||||||
//capture all of the show's contents.
|
//capture all of the show's contents.
|
||||||
$p_track_start= $p_start->sub(new DateInterval("PT24H"))->format("Y-m-d H:i:s");
|
$p_track_start= $p_start->sub(new DateInterval("PT48H"))->format("Y-m-d H:i:s");
|
||||||
$p_track_end = $p_end->add(new DateInterval("PT24H"))->format("Y-m-d H:i:s");
|
$p_track_end = $p_end->add(new DateInterval("PT48H"))->format("Y-m-d H:i:s");
|
||||||
|
|
||||||
$templateSql = <<<SQL
|
$templateSql = <<<SQL
|
||||||
SELECT DISTINCT sched.starts AS sched_starts,
|
SELECT DISTINCT sched.starts AS sched_starts,
|
||||||
|
@ -738,13 +738,16 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$fileMetadata = CcFiles::sanitizeResponse(CcFilesQuery::create()->findPk($media_id));
|
||||||
|
|
||||||
$schedule_item = array(
|
$schedule_item = array(
|
||||||
'id' => $media_id,
|
'id' => $media_id,
|
||||||
'type' => 'file',
|
'type' => 'file',
|
||||||
|
'metadata' => $fileMetadata,
|
||||||
'row_id' => $item["id"],
|
'row_id' => $item["id"],
|
||||||
'uri' => $uri,
|
'uri' => $uri,
|
||||||
'fade_in' => Application_Model_Schedule::WallTimeToMillisecs($item["fade_in"]),
|
'fade_in' => Application_Model_Schedule::WallTimeToMillisecs($item["fade_in"]),
|
||||||
|
|
|
@ -13,6 +13,14 @@
|
||||||
*/
|
*/
|
||||||
class CcFiles extends BaseCcFiles {
|
class CcFiles extends BaseCcFiles {
|
||||||
|
|
||||||
|
//fields we should never expose through our RESTful API
|
||||||
|
private static $privateFields = array(
|
||||||
|
'file_exists',
|
||||||
|
'silan_check',
|
||||||
|
'is_scheduled',
|
||||||
|
'is_playlist'
|
||||||
|
);
|
||||||
|
|
||||||
public function getCueLength()
|
public function getCueLength()
|
||||||
{
|
{
|
||||||
$cuein = $this->getDbCuein();
|
$cuein = $this->getDbCuein();
|
||||||
|
@ -46,4 +54,20 @@ class CcFiles extends BaseCcFiles {
|
||||||
$this->save();
|
$this->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Strips out the private fields we do not want to send back in API responses
|
||||||
|
* @param $file a CcFiles object
|
||||||
|
*/
|
||||||
|
//TODO: rename this function?
|
||||||
|
public static function sanitizeResponse($file)
|
||||||
|
{
|
||||||
|
$response = $file->toArray(BasePeer::TYPE_FIELDNAME);
|
||||||
|
|
||||||
|
foreach (self::$privateFields as $key) {
|
||||||
|
unset($response[$key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
} // CcFiles
|
} // CcFiles
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
class Rest_MediaController extends Zend_Rest_Controller
|
class Rest_MediaController extends Zend_Rest_Controller
|
||||||
{
|
{
|
||||||
//fields that are not modifiable via our RESTful API
|
//fields that are not modifiable via our RESTful API
|
||||||
private $blackList = array(
|
private static $blackList = array(
|
||||||
'id',
|
'id',
|
||||||
'directory',
|
'directory',
|
||||||
'filepath',
|
'filepath',
|
||||||
|
@ -18,14 +18,6 @@ class Rest_MediaController extends Zend_Rest_Controller
|
||||||
'is_playlist'
|
'is_playlist'
|
||||||
);
|
);
|
||||||
|
|
||||||
//fields we should never expose through our RESTful API
|
|
||||||
private $privateFields = array(
|
|
||||||
'file_exists',
|
|
||||||
'silan_check',
|
|
||||||
'is_scheduled',
|
|
||||||
'is_playlist'
|
|
||||||
);
|
|
||||||
|
|
||||||
public function init()
|
public function init()
|
||||||
{
|
{
|
||||||
$this->view->layout()->disableLayout();
|
$this->view->layout()->disableLayout();
|
||||||
|
@ -44,7 +36,7 @@ class Rest_MediaController extends Zend_Rest_Controller
|
||||||
$files_array = array();
|
$files_array = array();
|
||||||
foreach (CcFilesQuery::create()->find() as $file)
|
foreach (CcFilesQuery::create()->find() as $file)
|
||||||
{
|
{
|
||||||
array_push($files_array, $this->sanitizeResponse($file));
|
array_push($files_array, CcFiles::sanitizeResponse($file));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->getResponse()
|
$this->getResponse()
|
||||||
|
@ -137,7 +129,7 @@ class Rest_MediaController extends Zend_Rest_Controller
|
||||||
|
|
||||||
$this->getResponse()
|
$this->getResponse()
|
||||||
->setHttpResponseCode(200)
|
->setHttpResponseCode(200)
|
||||||
->appendBody(json_encode($this->sanitizeResponse($file)));
|
->appendBody(json_encode(CcFiles::sanitizeResponse($file)));
|
||||||
} else {
|
} else {
|
||||||
$this->fileNotFoundResponse();
|
$this->fileNotFoundResponse();
|
||||||
}
|
}
|
||||||
|
@ -204,7 +196,7 @@ class Rest_MediaController extends Zend_Rest_Controller
|
||||||
|
|
||||||
$this->getResponse()
|
$this->getResponse()
|
||||||
->setHttpResponseCode(201)
|
->setHttpResponseCode(201)
|
||||||
->appendBody(json_encode($this->sanitizeResponse($file)));
|
->appendBody(json_encode(CcFiles::sanitizeResponse($file)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,7 +246,7 @@ class Rest_MediaController extends Zend_Rest_Controller
|
||||||
|
|
||||||
$this->getResponse()
|
$this->getResponse()
|
||||||
->setHttpResponseCode(200)
|
->setHttpResponseCode(200)
|
||||||
->appendBody(json_encode($this->sanitizeResponse($file)));
|
->appendBody(json_encode(CcFiles::sanitizeResponse($file)));
|
||||||
} else {
|
} else {
|
||||||
$file->setDbImportStatus(2)->save();
|
$file->setDbImportStatus(2)->save();
|
||||||
$this->fileNotFoundResponse();
|
$this->fileNotFoundResponse();
|
||||||
|
@ -428,7 +420,7 @@ class Rest_MediaController extends Zend_Rest_Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$fileForm->isValidPartial($whiteList)) {
|
if (!$fileForm->isValidPartial($whiteList)) {
|
||||||
throw Exception("Data validation failed");
|
throw new Exception("Data validation failed");
|
||||||
}
|
}
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$errors = $fileForm->getErrors();
|
$errors = $fileForm->getErrors();
|
||||||
|
@ -509,30 +501,15 @@ class Rest_MediaController extends Zend_Rest_Controller
|
||||||
* from outside of Airtime
|
* from outside of Airtime
|
||||||
* @param array $data
|
* @param array $data
|
||||||
*/
|
*/
|
||||||
private function removeBlacklistedFieldsFromRequestData($data)
|
private static function removeBlacklistedFieldsFromRequestData($data)
|
||||||
{
|
{
|
||||||
foreach ($this->blackList as $key) {
|
foreach (self::$blackList as $key) {
|
||||||
unset($data[$key]);
|
unset($data[$key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Strips out the private fields we do not want to send back in API responses
|
|
||||||
*/
|
|
||||||
//TODO: rename this function?
|
|
||||||
public function sanitizeResponse($file)
|
|
||||||
{
|
|
||||||
$response = $file->toArray(BasePeer::TYPE_FIELDNAME);
|
|
||||||
|
|
||||||
foreach ($this->privateFields as $key) {
|
|
||||||
unset($response[$key]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function removeEmptySubFolders($path)
|
private function removeEmptySubFolders($path)
|
||||||
{
|
{
|
||||||
|
|
|
@ -85,33 +85,32 @@ class Application_Service_CalendarService
|
||||||
$currentShow = Application_Model_Show::getCurrentShow();
|
$currentShow = Application_Model_Show::getCurrentShow();
|
||||||
$currentShowId = count($currentShow) == 1 ? $currentShow[0]["id"] : null;
|
$currentShowId = count($currentShow) == 1 ? $currentShow[0]["id"] : null;
|
||||||
$showIsLinked = $this->ccShow->isLinked();
|
$showIsLinked = $this->ccShow->isLinked();
|
||||||
|
|
||||||
|
//user can add/remove content if the show has not ended
|
||||||
if ($now < $end && ($isAdminOrPM || $isHostOfShow) && !$this->ccShowInstance->isRecorded()) {
|
if ($now < $end && ($isAdminOrPM || $isHostOfShow) && !$this->ccShowInstance->isRecorded()) {
|
||||||
//if the show is not linked the user can add/remove content
|
//if the show is not linked OR if the show is linked AND not the current playing show
|
||||||
if (!$showIsLinked) {
|
//the user can add/remove content
|
||||||
|
if (!$showIsLinked || ($showIsLinked && $currentShowId != $this->ccShow->getDbId())) {
|
||||||
$menu["schedule"] = array(
|
|
||||||
"name"=> _("Add / Remove Content"),
|
|
||||||
"icon" => "add-remove-content",
|
|
||||||
"url" => $baseUrl."showbuilder/builder-dialog/");
|
|
||||||
//if the show is linked and it's not currently playing the user can add/remove content
|
|
||||||
} elseif ($showIsLinked && $currentShowId != $this->ccShow->getDbId()) {
|
|
||||||
|
|
||||||
$menu["schedule"] = array(
|
$menu["schedule"] = array(
|
||||||
"name"=> _("Add / Remove Content"),
|
"name"=> _("Add / Remove Content"),
|
||||||
"icon" => "add-remove-content",
|
"icon" => "add-remove-content",
|
||||||
"url" => $baseUrl."showbuilder/builder-dialog/");
|
"url" => $baseUrl."showbuilder/builder-dialog/");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($now < $start && ($isAdminOrPM || $isHostOfShow) &&
|
//user can remove all content if the show has not started
|
||||||
!$this->ccShowInstance->isRecorded() ) {
|
if ($now < $start && ($isAdminOrPM || $isHostOfShow) && !$this->ccShowInstance->isRecorded() ) {
|
||||||
|
//if the show is not linked OR if the show is linked AND not the current playing show
|
||||||
|
//the user can remove all content
|
||||||
|
if (!$showIsLinked || ($showIsLinked && $currentShowId != $this->ccShow->getDbId())) {
|
||||||
|
|
||||||
$menu["clear"] = array(
|
$menu["clear"] = array(
|
||||||
"name"=> _("Remove All Content"),
|
"name"=> _("Remove All Content"),
|
||||||
"icon" => "remove-all-content",
|
"icon" => "remove-all-content",
|
||||||
"url" => $baseUrl."schedule/clear-show");
|
"url" => $baseUrl."schedule/clear-show");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//"Show Content" should be a menu item at all times except when
|
//"Show Content" should be a menu item at all times except when
|
||||||
//the show is recorded
|
//the show is recorded
|
||||||
|
|
|
@ -289,7 +289,15 @@ class Application_Service_ShowService
|
||||||
if ($this->ccShow->isRepeating()) {
|
if ($this->ccShow->isRepeating()) {
|
||||||
$ccShowDays = $this->ccShow->getRepeatingCcShowDays();
|
$ccShowDays = $this->ccShow->getRepeatingCcShowDays();
|
||||||
} else {
|
} else {
|
||||||
$ccShowDays = $this->ccShow->getCcShowDayss();
|
//$ccShowDays = $this->ccShow->getCcShowDayss();
|
||||||
|
|
||||||
|
/* Cannot use the above statement to get the cc_show_days
|
||||||
|
* object because it's getting the old object before the
|
||||||
|
* show was edited. clearInstancePool() didn't work.
|
||||||
|
*/
|
||||||
|
$ccShowDays = CcShowDaysQuery::create()
|
||||||
|
->filterByDbShowId($this->ccShow->getDbId())
|
||||||
|
->find();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1039,6 +1047,9 @@ SQL;
|
||||||
);
|
);
|
||||||
$origStartDateTime->setTimezone(new DateTimeZone("UTC"));
|
$origStartDateTime->setTimezone(new DateTimeZone("UTC"));
|
||||||
$ccShowInstance = $this->getInstance($origStartDateTime);
|
$ccShowInstance = $this->getInstance($origStartDateTime);
|
||||||
|
if (!$ccShowInstance) {
|
||||||
|
throw new Exception("Could not find show instance with start time: ".$origStartDateTime->format("Y-m-d H:i:s"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$ccShowInstance->setDbShowId($this->ccShow->getDbId());
|
$ccShowInstance->setDbShowId($this->ccShow->getDbId());
|
||||||
|
|
|
@ -10,7 +10,7 @@ echo sprintf(_("%sAirtime%s %s, the open radio software for scheduling and remot
|
||||||
?>
|
?>
|
||||||
<br>© 2013
|
<br>© 2013
|
||||||
<?php
|
<?php
|
||||||
echo sprintf(_("%sSourcefabric%s o.p.s. Airtime is distributed under the %sGNU GPL v.3%s"),
|
echo sprintf(_("%sSourcefabric%s z.ú Airtime is distributed under the %sGNU GPL v.3%s"),
|
||||||
"<a href='http://www.sourcefabric.org' target='_blank'>",
|
"<a href='http://www.sourcefabric.org' target='_blank'>",
|
||||||
"</a>",
|
"</a>",
|
||||||
"<a href='http://www.gnu.org/licenses/gpl-3.0-standalone.html' target='_blank'>",
|
"<a href='http://www.gnu.org/licenses/gpl-3.0-standalone.html' target='_blank'>",
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<div id="login" class="login-content clearfix">
|
<div id="login" class="login-content clearfix">
|
||||||
<?php if(isset($this->demo) && $this->demo == 1){?>
|
<?php if(isset($this->demo) && $this->demo == 1){?>
|
||||||
<p style="font-weight:bold">
|
<p style="font-weight:bold">
|
||||||
<?php echo _("Welcome to the online Airtime demo! You can log in using the username 'admin' and the password 'admin'.")?>
|
<?php echo _("Welcome to the Airtime demo! You can log in using the username 'admin' and the password 'admin'.")?>
|
||||||
</p>
|
</p>
|
||||||
<?php }?>
|
<?php }?>
|
||||||
<p class="light" style='<?php echo $this->error?"color:#902d2d;font-size:11px;padding:2px 4px;background:#c6b4b4;margin-bottom:2px;border:1px solid #c83f3f;":""?>'><?php echo $this->message; ?></p>
|
<p class="light" style='<?php echo $this->error?"color:#902d2d;font-size:11px;padding:2px 4px;background:#c6b4b4;margin-bottom:2px;border:1px solid #c83f3f;":""?>'><?php echo $this->message; ?></p>
|
||||||
|
|
BIN
airtime_mvc/locale/az/LC_MESSAGES/airtime.mo
Normal file
BIN
airtime_mvc/locale/az/LC_MESSAGES/airtime.mo
Normal file
Binary file not shown.
3913
airtime_mvc/locale/az/LC_MESSAGES/airtime.po
Normal file
3913
airtime_mvc/locale/az/LC_MESSAGES/airtime.po
Normal file
File diff suppressed because it is too large
Load diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
airtime_mvc/locale/hy/LC_MESSAGES/airtime.mo
Normal file
BIN
airtime_mvc/locale/hy/LC_MESSAGES/airtime.mo
Normal file
Binary file not shown.
3913
airtime_mvc/locale/hy/LC_MESSAGES/airtime.po
Normal file
3913
airtime_mvc/locale/hy/LC_MESSAGES/airtime.po
Normal file
File diff suppressed because it is too large
Load diff
BIN
airtime_mvc/locale/ka/LC_MESSAGES/airtime.mo
Normal file
BIN
airtime_mvc/locale/ka/LC_MESSAGES/airtime.mo
Normal file
Binary file not shown.
3913
airtime_mvc/locale/ka/LC_MESSAGES/airtime.po
Normal file
3913
airtime_mvc/locale/ka/LC_MESSAGES/airtime.po
Normal file
File diff suppressed because it is too large
Load diff
Binary file not shown.
|
@ -109,7 +109,6 @@ class TestHelper
|
||||||
//Create all the database tables
|
//Create all the database tables
|
||||||
AirtimeInstall::createDatabaseTables($dbuser, $dbpasswd, $dbname, $dbhost);
|
AirtimeInstall::createDatabaseTables($dbuser, $dbpasswd, $dbname, $dbhost);
|
||||||
}
|
}
|
||||||
AirtimeInstall::SetDefaultTimezone();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function setupZendBootstrap()
|
public static function setupZendBootstrap()
|
||||||
|
|
|
@ -178,7 +178,7 @@ class AirtimeInstall
|
||||||
|
|
||||||
echo "* Giving Apache permission to access $rp".PHP_EOL;
|
echo "* Giving Apache permission to access $rp".PHP_EOL;
|
||||||
$success = chgrp($rp, $CC_CONFIG["webServerUser"]);
|
$success = chgrp($rp, $CC_CONFIG["webServerUser"]);
|
||||||
$success = chmod($rp, 02775);
|
$success = chmod($rp, 0775);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -104,7 +104,7 @@ def test_double_duplicate_files():
|
||||||
@raises(OSError)
|
@raises(OSError)
|
||||||
def test_bad_permissions_destination_dir():
|
def test_bad_permissions_destination_dir():
|
||||||
filename = os.path.basename(DEFAULT_AUDIO_FILE)
|
filename = os.path.basename(DEFAULT_AUDIO_FILE)
|
||||||
dest_dir = u'/var/foobar'
|
dest_dir = u'/sys/foobar' # /sys is using sysfs on Linux, which is unwritable
|
||||||
FileMoverAnalyzer.move(DEFAULT_AUDIO_FILE, dest_dir, filename, dict())
|
FileMoverAnalyzer.move(DEFAULT_AUDIO_FILE, dest_dir, filename, dict())
|
||||||
#Move the file back
|
#Move the file back
|
||||||
shutil.move(os.path.join(dest_dir, filename), DEFAULT_AUDIO_FILE)
|
shutil.move(os.path.join(dest_dir, filename), DEFAULT_AUDIO_FILE)
|
||||||
|
|
|
@ -283,11 +283,11 @@ def organized_path(old_path, root_path, orig_md):
|
||||||
title_re = re.match(r, normal_md['MDATA_KEY_TITLE'])
|
title_re = re.match(r, normal_md['MDATA_KEY_TITLE'])
|
||||||
show_name = title_re.group('show')
|
show_name = title_re.group('show')
|
||||||
#date = title_re.group('date')
|
#date = title_re.group('date')
|
||||||
yyyy, mm, _ = normal_md['MDATA_KEY_YEAR'].split('-',2)
|
yyyy, mm, dd = normal_md['MDATA_KEY_YEAR'].split('-',2)
|
||||||
fname_base = '%s-%s-%s.%s' % \
|
fname_base = '%s-%s-%s.%s' % \
|
||||||
(title_re.group('time'), show_name,
|
(title_re.group('time'), show_name,
|
||||||
normal_md['MDATA_KEY_BITRATE'], ext)
|
normal_md['MDATA_KEY_BITRATE'], ext)
|
||||||
filepath = os.path.join(root_path, yyyy, mm, fname_base)
|
filepath = os.path.join(root_path, yyyy, mm, dd, fname_base)
|
||||||
elif len(normal_md['MDATA_KEY_TRACKNUMBER']) == 0:
|
elif len(normal_md['MDATA_KEY_TRACKNUMBER']) == 0:
|
||||||
fname = u'%s-%s.%s' % (normal_md['MDATA_KEY_TITLE'],
|
fname = u'%s-%s.%s' % (normal_md['MDATA_KEY_TITLE'],
|
||||||
normal_md['MDATA_KEY_BITRATE'], ext)
|
normal_md['MDATA_KEY_BITRATE'], ext)
|
||||||
|
|
|
@ -44,5 +44,8 @@ while not successful:
|
||||||
logging.error("traceback: %s", traceback.format_exc())
|
logging.error("traceback: %s", traceback.format_exc())
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
else:
|
else:
|
||||||
|
logging.error(str(e))
|
||||||
|
logging.error("traceback: %s", traceback.format_exc())
|
||||||
|
logging.info("Retrying in 3 seconds...")
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
attempts += 1
|
attempts += 1
|
||||||
|
|
|
@ -3,17 +3,31 @@ from timeout import ls_timeout
|
||||||
|
|
||||||
def create_liquidsoap_annotation(media):
|
def create_liquidsoap_annotation(media):
|
||||||
# We need liq_start_next value in the annotate. That is the value that controls overlap duration of crossfade.
|
# We need liq_start_next value in the annotate. That is the value that controls overlap duration of crossfade.
|
||||||
return ('annotate:media_id="%s",liq_start_next="0",liq_fade_in="%s",' + \
|
|
||||||
|
filename = media['dst']
|
||||||
|
annotation = ('annotate:media_id="%s",liq_start_next="0",liq_fade_in="%s",' + \
|
||||||
'liq_fade_out="%s",liq_cue_in="%s",liq_cue_out="%s",' + \
|
'liq_fade_out="%s",liq_cue_in="%s",liq_cue_out="%s",' + \
|
||||||
'schedule_table_id="%s",replay_gain="%s dB":%s') % \
|
'schedule_table_id="%s",replay_gain="%s dB"') % \
|
||||||
(media['id'],
|
(media['id'],
|
||||||
float(media['fade_in']) / 1000,
|
float(media['fade_in']) / 1000,
|
||||||
float(media['fade_out']) / 1000,
|
float(media['fade_out']) / 1000,
|
||||||
float(media['cue_in']),
|
float(media['cue_in']),
|
||||||
float(media['cue_out']),
|
float(media['cue_out']),
|
||||||
media['row_id'],
|
media['row_id'],
|
||||||
media['replay_gain'],
|
media['replay_gain'])
|
||||||
media['dst'])
|
|
||||||
|
# Override the the artist/title that Liquidsoap extracts from a file's metadata
|
||||||
|
# with the metadata we get from Airtime. (You can modify metadata in Airtime's library,
|
||||||
|
# which doesn't get saved back to the file.)
|
||||||
|
if 'metadata' in media:
|
||||||
|
if 'artist_name' in media['metadata']:
|
||||||
|
annotation += ',artist="%s"' % (media['metadata']['artist_name'])
|
||||||
|
if 'track_title' in media['metadata']:
|
||||||
|
annotation += ',title="%s"' % (media['metadata']['track_title'])
|
||||||
|
|
||||||
|
annotation += ":" + filename
|
||||||
|
|
||||||
|
return annotation
|
||||||
|
|
||||||
class TelnetLiquidsoap:
|
class TelnetLiquidsoap:
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue