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 "Database.php";
|
||||
require_once "Timezone.php";
|
||||
require_once "Auth.php";
|
||||
require_once __DIR__.'/forms/helpers/ValidationTypes.php';
|
||||
require_once __DIR__.'/controllers/plugins/RabbitMqPlugin.php';
|
||||
require_once __DIR__.'/controllers/plugins/Maintenance.php';
|
||||
|
@ -26,6 +27,8 @@ require_once __DIR__."/configs/navigation.php";
|
|||
|
||||
Zend_Validate::setDefaultNamespaces("Zend");
|
||||
|
||||
Application_Model_Auth::pinSessionToClient(Zend_Auth::getInstance());
|
||||
|
||||
$front = Zend_Controller_Front::getInstance();
|
||||
$front->registerPlugin(new RabbitMqPlugin());
|
||||
|
||||
|
|
|
@ -14,9 +14,10 @@ class LoginController extends Zend_Controller_Action
|
|||
$request = $this->getRequest();
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
|
@ -53,7 +54,6 @@ class LoginController extends Zend_Controller_Action
|
|||
$authAdapter->setIdentity($username)
|
||||
->setCredential($password);
|
||||
|
||||
$auth = Zend_Auth::getInstance();
|
||||
$result = $auth->authenticate($authAdapter);
|
||||
if ($result->isValid()) {
|
||||
//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_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
|
||||
Application_Model_Preference::SetUserLocale($locale);
|
||||
|
||||
$this->_redirect('Showbuilder');
|
||||
} else {
|
||||
|
||||
$message = _("Wrong username or password provided. Please try again.");
|
||||
Application_Model_Subjects::increaseLoginAttempts($username);
|
||||
Application_Model_LoginAttempts::increaseAttempts($_SERVER['REMOTE_ADDR']);
|
||||
|
@ -96,7 +94,8 @@ class LoginController extends Zend_Controller_Action
|
|||
|
||||
public function logoutAction()
|
||||
{
|
||||
Zend_Auth::getInstance()->clearIdentity();
|
||||
$auth = Zend_Auth::getInstance();
|
||||
$auth->clearIdentity();
|
||||
$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)
|
||||
{
|
||||
$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
|
||||
//and/or by OAuth.
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
<?php echo $this->layout()->content ?>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<?php echo sprintf(_("Airtime Copyright ©Sourcefabric o.p.s. All rights reserved.%s"
|
||||
."Maintained and distributed under GNU GPL v.3 by %sSourcefabric o.p.s%s"),
|
||||
<?php echo sprintf(_("Airtime copyright © Sourcefabric z.ú. All rights reserved.%s"
|
||||
."Maintained and distributed under the GNU GPL v.3 by %sSourcefabric z.ú.%s"),
|
||||
"<br>", "<a href='http://www.sourcefabric.org'>" ,"</a>");?>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -110,4 +110,18 @@ class Application_Model_Auth
|
|||
|
||||
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)
|
||||
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)
|
||||
|
@ -1314,6 +1318,11 @@ class Application_Model_Preference
|
|||
|
||||
$ds = unserialize($v);
|
||||
|
||||
|
||||
if (is_null($ds) || !is_array($ds)) {
|
||||
return $id;
|
||||
}
|
||||
|
||||
if (!array_key_exists('ColReorder', $ds)) {
|
||||
return $id;
|
||||
}
|
||||
|
|
|
@ -303,10 +303,10 @@ SQL;
|
|||
$p_start_str = $p_start->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.
|
||||
$p_track_start= $p_start->sub(new DateInterval("PT24H"))->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_start= $p_start->sub(new DateInterval("PT48H"))->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
|
||||
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 += Application_Model_Preference::getReplayGainModifier();
|
||||
|
||||
if ( !Application_Model_Preference::GetEnableReplayGain() ) {
|
||||
if (!Application_Model_Preference::GetEnableReplayGain() ) {
|
||||
$replay_gain = 0;
|
||||
}
|
||||
|
||||
$fileMetadata = CcFiles::sanitizeResponse(CcFilesQuery::create()->findPk($media_id));
|
||||
|
||||
$schedule_item = array(
|
||||
'id' => $media_id,
|
||||
'type' => 'file',
|
||||
'metadata' => $fileMetadata,
|
||||
'row_id' => $item["id"],
|
||||
'uri' => $uri,
|
||||
'fade_in' => Application_Model_Schedule::WallTimeToMillisecs($item["fade_in"]),
|
||||
|
|
|
@ -13,6 +13,14 @@
|
|||
*/
|
||||
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()
|
||||
{
|
||||
$cuein = $this->getDbCuein();
|
||||
|
@ -46,4 +54,20 @@ class CcFiles extends BaseCcFiles {
|
|||
$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
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
class Rest_MediaController extends Zend_Rest_Controller
|
||||
{
|
||||
//fields that are not modifiable via our RESTful API
|
||||
private $blackList = array(
|
||||
private static $blackList = array(
|
||||
'id',
|
||||
'directory',
|
||||
'filepath',
|
||||
|
@ -18,14 +18,6 @@ class Rest_MediaController extends Zend_Rest_Controller
|
|||
'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()
|
||||
{
|
||||
$this->view->layout()->disableLayout();
|
||||
|
@ -44,7 +36,7 @@ class Rest_MediaController extends Zend_Rest_Controller
|
|||
$files_array = array();
|
||||
foreach (CcFilesQuery::create()->find() as $file)
|
||||
{
|
||||
array_push($files_array, $this->sanitizeResponse($file));
|
||||
array_push($files_array, CcFiles::sanitizeResponse($file));
|
||||
}
|
||||
|
||||
$this->getResponse()
|
||||
|
@ -137,7 +129,7 @@ class Rest_MediaController extends Zend_Rest_Controller
|
|||
|
||||
$this->getResponse()
|
||||
->setHttpResponseCode(200)
|
||||
->appendBody(json_encode($this->sanitizeResponse($file)));
|
||||
->appendBody(json_encode(CcFiles::sanitizeResponse($file)));
|
||||
} else {
|
||||
$this->fileNotFoundResponse();
|
||||
}
|
||||
|
@ -204,7 +196,7 @@ class Rest_MediaController extends Zend_Rest_Controller
|
|||
|
||||
$this->getResponse()
|
||||
->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()
|
||||
->setHttpResponseCode(200)
|
||||
->appendBody(json_encode($this->sanitizeResponse($file)));
|
||||
->appendBody(json_encode(CcFiles::sanitizeResponse($file)));
|
||||
} else {
|
||||
$file->setDbImportStatus(2)->save();
|
||||
$this->fileNotFoundResponse();
|
||||
|
@ -428,7 +420,7 @@ class Rest_MediaController extends Zend_Rest_Controller
|
|||
}
|
||||
|
||||
if (!$fileForm->isValidPartial($whiteList)) {
|
||||
throw Exception("Data validation failed");
|
||||
throw new Exception("Data validation failed");
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$errors = $fileForm->getErrors();
|
||||
|
@ -509,30 +501,15 @@ class Rest_MediaController extends Zend_Rest_Controller
|
|||
* from outside of Airtime
|
||||
* @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]);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -85,33 +85,32 @@ class Application_Service_CalendarService
|
|||
$currentShow = Application_Model_Show::getCurrentShow();
|
||||
$currentShowId = count($currentShow) == 1 ? $currentShow[0]["id"] : null;
|
||||
$showIsLinked = $this->ccShow->isLinked();
|
||||
|
||||
//user can add/remove content if the show has not ended
|
||||
if ($now < $end && ($isAdminOrPM || $isHostOfShow) && !$this->ccShowInstance->isRecorded()) {
|
||||
//if the show is not linked the user can add/remove content
|
||||
if (!$showIsLinked) {
|
||||
|
||||
$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()) {
|
||||
//if the show is not linked OR if the show is linked AND not the current playing show
|
||||
//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 ($now < $start && ($isAdminOrPM || $isHostOfShow) &&
|
||||
!$this->ccShowInstance->isRecorded() ) {
|
||||
//user can remove all content if the show has not started
|
||||
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(
|
||||
"name"=> _("Remove All Content"),
|
||||
"icon" => "remove-all-content",
|
||||
"url" => $baseUrl."schedule/clear-show");
|
||||
}
|
||||
}
|
||||
|
||||
//"Show Content" should be a menu item at all times except when
|
||||
//the show is recorded
|
||||
|
|
|
@ -289,7 +289,15 @@ class Application_Service_ShowService
|
|||
if ($this->ccShow->isRepeating()) {
|
||||
$ccShowDays = $this->ccShow->getRepeatingCcShowDays();
|
||||
} 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"));
|
||||
$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());
|
||||
|
|
|
@ -10,7 +10,7 @@ echo sprintf(_("%sAirtime%s %s, the open radio software for scheduling and remot
|
|||
?>
|
||||
<br>© 2013
|
||||
<?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>",
|
||||
"<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">
|
||||
<?php if(isset($this->demo) && $this->demo == 1){?>
|
||||
<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>
|
||||
<?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>
|
||||
|
|
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
|
||||
AirtimeInstall::createDatabaseTables($dbuser, $dbpasswd, $dbname, $dbhost);
|
||||
}
|
||||
AirtimeInstall::SetDefaultTimezone();
|
||||
}
|
||||
|
||||
public static function setupZendBootstrap()
|
||||
|
|
|
@ -178,7 +178,7 @@ class AirtimeInstall
|
|||
|
||||
echo "* Giving Apache permission to access $rp".PHP_EOL;
|
||||
$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)
|
||||
def test_bad_permissions_destination_dir():
|
||||
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())
|
||||
#Move the file back
|
||||
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'])
|
||||
show_name = title_re.group('show')
|
||||
#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' % \
|
||||
(title_re.group('time'), show_name,
|
||||
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:
|
||||
fname = u'%s-%s.%s' % (normal_md['MDATA_KEY_TITLE'],
|
||||
normal_md['MDATA_KEY_BITRATE'], ext)
|
||||
|
|
|
@ -44,5 +44,8 @@ while not successful:
|
|||
logging.error("traceback: %s", traceback.format_exc())
|
||||
sys.exit(1)
|
||||
else:
|
||||
logging.error(str(e))
|
||||
logging.error("traceback: %s", traceback.format_exc())
|
||||
logging.info("Retrying in 3 seconds...")
|
||||
time.sleep(3)
|
||||
attempts += 1
|
||||
|
|
|
@ -3,17 +3,31 @@ from timeout import ls_timeout
|
|||
|
||||
def create_liquidsoap_annotation(media):
|
||||
# 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",' + \
|
||||
'schedule_table_id="%s",replay_gain="%s dB":%s') % \
|
||||
'schedule_table_id="%s",replay_gain="%s dB"') % \
|
||||
(media['id'],
|
||||
float(media['fade_in']) / 1000,
|
||||
float(media['fade_out']) / 1000,
|
||||
float(media['cue_in']),
|
||||
float(media['cue_out']),
|
||||
media['row_id'],
|
||||
media['replay_gain'],
|
||||
media['dst'])
|
||||
media['replay_gain'])
|
||||
|
||||
# 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:
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue