Merge branch 'saas' of github.com:sourcefabric/Airtime into saas
This commit is contained in:
commit
a48ae75907
|
@ -37,7 +37,8 @@ $ccAcl->add(new Zend_Acl_Resource('library'))
|
|||
->add(new Zend_Acl_Resource('rest:show-image'))
|
||||
->add(new Zend_Acl_Resource('billing'))
|
||||
->add(new Zend_Acl_Resource('thank-you'))
|
||||
->add(new Zend_Acl_Resource('provisioning'));
|
||||
->add(new Zend_Acl_Resource('provisioning'))
|
||||
->add(new Zend_Acl_Resource('player'));
|
||||
|
||||
/** Creating permissions */
|
||||
$ccAcl->allow('G', 'index')
|
||||
|
@ -70,6 +71,7 @@ $ccAcl->allow('G', 'index')
|
|||
->allow('A', 'user')
|
||||
->allow('A', 'systemstatus')
|
||||
->allow('A', 'preference')
|
||||
->allow('A', 'player')
|
||||
->allow('S', 'thank-you')
|
||||
->allow('S', 'billing');
|
||||
|
||||
|
|
|
@ -85,6 +85,12 @@ $pages = array(
|
|||
'controller' => 'listenerstat',
|
||||
'action' => 'index',
|
||||
'resource' => 'listenerstat'
|
||||
),
|
||||
array(
|
||||
'label' => _('Player'),
|
||||
'module' => 'default',
|
||||
'controller' => 'player',
|
||||
'action' => 'customize'
|
||||
)
|
||||
)
|
||||
),
|
||||
|
|
|
@ -523,6 +523,7 @@ class ApiController extends Zend_Controller_Action
|
|||
$result["description"] = Application_Model_Preference::GetStationDescription();
|
||||
$result["timezone"] = Application_Model_Preference::GetDefaultTimezone();
|
||||
$result["locale"] = Application_Model_Preference::GetDefaultLocale();
|
||||
$result["stream_data"] = Application_Model_StreamSetting::getEnabledStreamData();
|
||||
|
||||
// used by caller to determine if the airtime they are running or widgets in use is out of date.
|
||||
$result['AIRTIME_API_VERSION'] = AIRTIME_API_VERSION;
|
||||
|
@ -1310,7 +1311,7 @@ class ApiController extends Zend_Controller_Action
|
|||
}
|
||||
|
||||
public function getStreamParametersAction() {
|
||||
$streams = array("s1", "s2", "s3");
|
||||
$streams = array("s1", "s2", "s3", "s4");
|
||||
$stream_params = array();
|
||||
foreach ($streams as $s) {
|
||||
$stream_params[$s] =
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
class EmbedController extends Zend_Controller_Action
|
||||
{
|
||||
public function init()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the action that is called to insert the player onto a web page.
|
||||
* It passes all the js and css files to the view, as well as all the
|
||||
* stream customization information.
|
||||
*
|
||||
* The view for this action contains all the inline javascript needed to
|
||||
* create the player.
|
||||
*/
|
||||
public function playerAction()
|
||||
{
|
||||
$this->view->layout()->disableLayout();
|
||||
|
||||
$CC_CONFIG = Config::getConfig();
|
||||
|
||||
$request = $this->getRequest();
|
||||
|
||||
$this->view->css = Application_Common_HTTPHelper::getStationUrl() . "css/player.css?".$CC_CONFIG['airtime_version'];
|
||||
$this->view->mrp_js = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/player/mrp.js?".$CC_CONFIG['airtime_version'];
|
||||
$this->view->jquery = Application_Common_HTTPHelper::getStationUrl() . "js/libs/jquery-1.10.2.js";
|
||||
$this->view->muses_swf = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/player/muses.swf";
|
||||
$this->view->metadata_api_url = Application_Common_HTTPHelper::getStationUrl() . "api/live-info";
|
||||
$this->view->player_title = json_encode($request->getParam('title'));
|
||||
|
||||
$stream = $request->getParam('stream');
|
||||
$streamData = Application_Model_StreamSetting::getEnabledStreamData();
|
||||
$availableMobileStreams = array();
|
||||
$availableDesktopStreams = array();
|
||||
|
||||
if ($stream == "auto") {
|
||||
$this->view->playerMode = "auto";
|
||||
$this->view->streamURL = json_encode("");
|
||||
foreach ($streamData as $s) {
|
||||
if ($s["mobile"]) {
|
||||
array_push($availableMobileStreams, $s);
|
||||
} else if (!$s["mobile"]) {
|
||||
array_push($availableDesktopStreams, $s);
|
||||
}
|
||||
}
|
||||
} elseif (!empty($stream)) {
|
||||
$this->view->playerMode = "manual";
|
||||
$selectedStreamData = $streamData[$stream];
|
||||
$this->view->streamURL = json_encode($selectedStreamData["url"]);
|
||||
$this->view->codec = $selectedStreamData["codec"];
|
||||
}
|
||||
$this->view->availableMobileStreams = json_encode($availableMobileStreams);
|
||||
$this->view->availableDesktopStreams = json_encode($availableDesktopStreams);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
class PlayerController extends Zend_Controller_Action
|
||||
{
|
||||
public function init()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function customizeAction()
|
||||
{
|
||||
$CC_CONFIG = Config::getConfig();
|
||||
$baseUrl = Application_Common_OsPath::getBaseDir();
|
||||
$this->view->headLink()->appendStylesheet($baseUrl.'css/player-form.css?'.$CC_CONFIG['airtime_version']);
|
||||
$this->view->headScript()->appendFile($baseUrl.'js/airtime/player/player.js?'.$CC_CONFIG['airtime_version']);
|
||||
|
||||
$form = new Application_Form_Player();
|
||||
|
||||
$apiEnabled = Application_Model_Preference::GetAllow3rdPartyApi();
|
||||
$numEnabledStreams = $form->getElement('player_stream_url')->getAttrib('numberOfEnabledStreams');
|
||||
|
||||
if ($numEnabledStreams > 0 && $apiEnabled) {
|
||||
$this->view->form = $form;
|
||||
} else {
|
||||
$this->view->errorMsg = "To configure and use the embeddable player you must:<br><br>
|
||||
1. Enable at least one MP3, AAC, or OGG stream under System -> Streams<br>
|
||||
2. Enable the Public Airtime API under System -> Preferences";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -141,11 +141,7 @@ class PreferenceController extends Zend_Controller_Action
|
|||
$this->view->headScript()->appendFile($baseUrl.'js/airtime/preferences/streamsetting.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
|
||||
|
||||
// get current settings
|
||||
$temp = Application_Model_StreamSetting::getStreamSetting();
|
||||
$setting = array();
|
||||
foreach ($temp as $t) {
|
||||
$setting[$t['keyname']] = $t['value'];
|
||||
}
|
||||
$setting = Application_Model_StreamSetting::getStreamSetting();
|
||||
|
||||
$name_map = array(
|
||||
'ogg' => 'Ogg Vorbis',
|
||||
|
@ -208,6 +204,7 @@ class PreferenceController extends Zend_Controller_Action
|
|||
$s1_data = array();
|
||||
$s2_data = array();
|
||||
$s3_data = array();
|
||||
$s4_data = array();
|
||||
$values = array();
|
||||
foreach($postData as $k=>$v) {
|
||||
$v = explode('=', urldecode($v));
|
||||
|
@ -223,6 +220,9 @@ class PreferenceController extends Zend_Controller_Action
|
|||
} elseif (strpos($v[0], "s3_data") !== false) {
|
||||
preg_match('/\[(.*)\]/', $v[0], $matches);
|
||||
$s3_data[$matches[1]] = $v[1];
|
||||
} elseif (strpos($v[0], "s4_data") !== false) {
|
||||
preg_match('/\[(.*)\]/', $v[0], $matches);
|
||||
$s4_data[$matches[1]] = $v[1];
|
||||
} else {
|
||||
$values[$v[0]] = $v[1];
|
||||
}
|
||||
|
@ -230,6 +230,7 @@ class PreferenceController extends Zend_Controller_Action
|
|||
$values["s1_data"] = $s1_data;
|
||||
$values["s2_data"] = $s2_data;
|
||||
$values["s3_data"] = $s3_data;
|
||||
$values["s4_data"] = $s4_data;
|
||||
|
||||
$error = false;
|
||||
if ($form->isValid($values)) {
|
||||
|
@ -245,6 +246,7 @@ class PreferenceController extends Zend_Controller_Action
|
|||
$s1_set_admin_pass = !empty($values["s1_data"]["admin_pass"]);
|
||||
$s2_set_admin_pass = !empty($values["s2_data"]["admin_pass"]);
|
||||
$s3_set_admin_pass = !empty($values["s3_data"]["admin_pass"]);
|
||||
$s4_set_admin_pass = !empty($values["s4_data"]["admin_pass"]);
|
||||
|
||||
// this goes into cc_pref table
|
||||
Application_Model_Preference::SetStreamLabelFormat($values['streamFormat']);
|
||||
|
@ -290,6 +292,7 @@ class PreferenceController extends Zend_Controller_Action
|
|||
"s1_set_admin_pass"=>$s1_set_admin_pass,
|
||||
"s2_set_admin_pass"=>$s2_set_admin_pass,
|
||||
"s3_set_admin_pass"=>$s3_set_admin_pass,
|
||||
"s4_set_admin_pass"=>$s4_set_admin_pass,
|
||||
));
|
||||
} else {
|
||||
$live_stream_subform->updateVariables();
|
||||
|
@ -441,7 +444,8 @@ class PreferenceController extends Zend_Controller_Action
|
|||
public function getAdminPasswordStatusAction()
|
||||
{
|
||||
$out = array();
|
||||
for ($i=1; $i<=3; $i++) {
|
||||
$num_of_stream = intval(Application_Model_Preference::GetNumOfStreams());
|
||||
for ($i=1; $i<=$num_of_stream; $i++) {
|
||||
if (Application_Model_StreamSetting::getAdminPass('s'.$i)=='') {
|
||||
$out["s".$i] = false;
|
||||
} else {
|
||||
|
|
|
@ -118,7 +118,8 @@ class Zend_Controller_Plugin_Acl extends Zend_Controller_Plugin_Abstract
|
|||
"locale",
|
||||
"upgrade",
|
||||
'whmcs-login',
|
||||
"provisioning"
|
||||
"provisioning",
|
||||
"embed"
|
||||
)))
|
||||
{
|
||||
$this->setRoleName("G");
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
define("OPUS", "opus");
|
||||
|
||||
class Application_Form_Player extends Zend_Form_SubForm
|
||||
{
|
||||
public function init()
|
||||
{
|
||||
$this->setDecorators(array(
|
||||
array('ViewScript', array('viewScript' => 'form/player.phtml'))
|
||||
));
|
||||
|
||||
$title = new Zend_Form_Element_Text('player_title');
|
||||
$title->setValue(_('Now Playing'));
|
||||
$title->setLabel(_('Title:'));
|
||||
$title->setDecorators(array(
|
||||
'ViewHelper',
|
||||
'Errors',
|
||||
'Label'
|
||||
));
|
||||
$title->addDecorator('Label', array('class' => 'player-title'));
|
||||
$this->addElement($title);
|
||||
|
||||
$streamMode = new Zend_Form_Element_Radio('player_stream_mode');
|
||||
$streamMode->setLabel(_('Select Stream:'));
|
||||
$streamMode->setMultiOptions(
|
||||
array(
|
||||
"auto" => _("Auto detect the most appropriate stream to use."),
|
||||
"manual" => _("Select a stream:")
|
||||
)
|
||||
);
|
||||
$streamMode->setValue("auto");
|
||||
$this->addElement($streamMode);
|
||||
|
||||
$streamURL = new Zend_Form_Element_Radio('player_stream_url');
|
||||
$opusStreamCount = 0;
|
||||
$urlOptions = Array();
|
||||
foreach(Application_Model_StreamSetting::getEnabledStreamData() as $stream => $data) {
|
||||
$urlOptions[$stream] = strtoupper($data["codec"])." - ".$data["bitrate"]."kbps";
|
||||
if ($data["mobile"]) {
|
||||
$urlOptions[$stream] .= _(" - Mobile friendly");
|
||||
}
|
||||
if ($data["codec"] == OPUS) {
|
||||
$opusStreamCount += 1;
|
||||
$urlOptions[$stream] .= _(" - The player does not support Opus streams.");
|
||||
}
|
||||
}
|
||||
$streamURL->setMultiOptions(
|
||||
$urlOptions
|
||||
);
|
||||
|
||||
// Set default value to the first non-opus stream we find
|
||||
foreach ($urlOptions as $o => $v) {
|
||||
if (strpos(strtolower($v), OPUS) !== false) {
|
||||
continue;
|
||||
} else {
|
||||
$streamURL->setValue($o);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$streamURL->setAttrib('numberOfEnabledStreams', sizeof($urlOptions)-$opusStreamCount);
|
||||
$streamURL->removeDecorator('label');
|
||||
$this->addElement($streamURL);
|
||||
|
||||
$embedSrc = new Zend_Form_Element_Textarea('player_embed_src');
|
||||
$embedSrc->setAttrib("readonly", "readonly");
|
||||
$embedSrc->setAttrib("class", "embed-player-text-box");
|
||||
$embedSrc->setAttrib('cols', '40')
|
||||
->setAttrib('rows', '4');
|
||||
$embedSrc->setLabel(_("Embeddable code:"));
|
||||
$embedSrc->setDescription(_("Copy this code and paste it into your website's HTML to embed the player in your site."));
|
||||
$embedSrc->setValue('<iframe frameborder="0" width="280" height="216" src="'.Application_Common_HTTPHelper::getStationUrl().'embed/player?stream=auto&title=Now Playing"></iframe>');
|
||||
$this->addElement($embedSrc);
|
||||
|
||||
$previewLabel = new Zend_Form_Element_Text('player_preview_label');
|
||||
$previewLabel->setLabel(_("Preview:"));
|
||||
$this->addElement($previewLabel);
|
||||
|
||||
}
|
||||
}
|
|
@ -53,6 +53,12 @@ class Application_Form_StreamSettingSubForm extends Zend_Form_SubForm
|
|||
}
|
||||
$this->addElement($enable);
|
||||
|
||||
$mobile = new Zend_Form_Element_Checkbox('mobile');
|
||||
$mobile->setLabel(_('Mobile:'));
|
||||
$mobile->setValue($setting[$prefix.'_mobile']);
|
||||
$mobile->setDecorators(array('ViewHelper'));
|
||||
$this->addElement($mobile);
|
||||
|
||||
$type = new Zend_Form_Element_Select('type');
|
||||
$type->setLabel(_("Stream Type:"))
|
||||
->setMultiOptions($stream_types)
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
<?php
|
||||
|
||||
define("MAX_NUM_STREAMS", 4);
|
||||
|
||||
class Application_Model_StreamSetting
|
||||
{
|
||||
public static function setValue($key, $value, $type)
|
||||
|
@ -41,7 +44,7 @@ class Application_Model_StreamSetting
|
|||
}
|
||||
}
|
||||
|
||||
public static function getValue($key)
|
||||
public static function getValue($key, $default="")
|
||||
{
|
||||
$con = Propel::getConnection();
|
||||
|
||||
|
@ -59,7 +62,27 @@ class Application_Model_StreamSetting
|
|||
throw new Exception("Error: $msg");
|
||||
}
|
||||
|
||||
return $result ? $result : "";
|
||||
return $result ? $result : $default;
|
||||
}
|
||||
|
||||
public static function getEnabledStreamData()
|
||||
{
|
||||
$streams = Array();
|
||||
$streamIds = self::getEnabledStreamIds();
|
||||
foreach ($streamIds as $id) {
|
||||
$streamData = self::getStreamData($id);
|
||||
$prefix = $id."_";
|
||||
$host = $streamData[$prefix."host"];
|
||||
$port = $streamData[$prefix."port"];
|
||||
$mount = $streamData[$prefix."mount"];
|
||||
$streams[$id] = Array(
|
||||
"url" => "http://$host:$port/$mount",
|
||||
"codec" => $streamData[$prefix."type"],
|
||||
"bitrate" => $streamData[$prefix."bitrate"],
|
||||
"mobile" => $streamData[$prefix."mobile"]
|
||||
);
|
||||
}
|
||||
return $streams;
|
||||
}
|
||||
|
||||
/* Returns the id's of all streams that are enabled in an array. An
|
||||
|
@ -83,50 +106,63 @@ class Application_Model_StreamSetting
|
|||
return $ids;
|
||||
}
|
||||
|
||||
/* Returns only global data as array*/
|
||||
public static function getGlobalData()
|
||||
{
|
||||
$con = Propel::getConnection();
|
||||
$sql = "SELECT * "
|
||||
."FROM cc_stream_setting "
|
||||
."WHERE keyname IN ('output_sound_device', 'icecast_vorbis_metadata')";
|
||||
|
||||
$rows = Application_Common_Database::prepareAndExecute($sql, array(), 'all');
|
||||
|
||||
$data = array();
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$data[$row["keyname"]] = $row["value"];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/* Returns all information related to a specific stream. An example
|
||||
* of a stream id is 's1' or 's2'. */
|
||||
public static function getStreamData($p_streamId)
|
||||
{
|
||||
$con = Propel::getConnection();
|
||||
$streamId = pg_escape_string($p_streamId);
|
||||
$sql = "SELECT * "
|
||||
."FROM cc_stream_setting "
|
||||
."WHERE keyname LIKE '{$streamId}_%'";
|
||||
|
||||
$stmt = $con->prepare($sql);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
$rows = $stmt->fetchAll();
|
||||
} else {
|
||||
$msg = implode(',', $stmt->errorInfo());
|
||||
throw new Exception("Error: $msg");
|
||||
}
|
||||
$rows = CcStreamSettingQuery::create()
|
||||
->filterByDbKeyName("${p_streamId}_%")
|
||||
->find();
|
||||
|
||||
//This is way too much code because someone made only stupid decisions about how
|
||||
//the layout of this table worked. The git history doesn't lie.
|
||||
$data = array();
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$data[$row["keyname"]] = $row["value"];
|
||||
$key = $row->getDbKeyName();
|
||||
$value = $row->getDbValue();
|
||||
$type = $row->getDbType();
|
||||
//Fix stupid defaults so we end up with proper typing in our JSON
|
||||
if ($row->getDbType() == "boolean") {
|
||||
if (empty($value)) {
|
||||
//In Python, there is no way to tell the difference between ints and booleans,
|
||||
//which we need to differentiate between for when we're generating the Liquidsoap
|
||||
//config file. Returning booleans as a string is a workaround that lets us do that.
|
||||
$value = "false";
|
||||
}
|
||||
$data[$key] = $value;
|
||||
}
|
||||
elseif ($row->getDbType() == "integer") {
|
||||
if (empty($value)) {
|
||||
$value = 0;
|
||||
}
|
||||
$data[$key] = intval($value);
|
||||
}
|
||||
else {
|
||||
$data[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
//Add in defaults in case they don't exist in the database.
|
||||
$keyPrefix = $p_streamId . '_';
|
||||
self::ensureKeyExists($keyPrefix . 'admin_pass', $data);
|
||||
self::ensureKeyExists($keyPrefix . 'admin_user', $data);
|
||||
self::ensureKeyExists($keyPrefix . 'bitrate', $data, 128);
|
||||
self::ensureKeyExists($keyPrefix . 'channels', $data, "stereo");
|
||||
self::ensureKeyExists($keyPrefix . 'description', $data);
|
||||
self::ensureKeyExists($keyPrefix . 'enable', $data, "false");
|
||||
self::ensureKeyExists($keyPrefix . 'genre', $data);
|
||||
self::ensureKeyExists($keyPrefix . 'host', $data);
|
||||
self::ensureKeyExists($keyPrefix . 'liquidsoap_error', $data, "waiting");
|
||||
self::ensureKeyExists($keyPrefix . 'mount', $data);
|
||||
self::ensureKeyExists($keyPrefix . 'name', $data);
|
||||
self::ensureKeyExists($keyPrefix . 'output', $data);
|
||||
self::ensureKeyExists($keyPrefix . 'pass', $data);
|
||||
self::ensureKeyExists($keyPrefix . 'port', $data, 8000);
|
||||
self::ensureKeyExists($keyPrefix . 'type', $data);
|
||||
self::ensureKeyExists($keyPrefix . 'url', $data);
|
||||
self::ensureKeyExists($keyPrefix . 'user', $data);
|
||||
self::ensureKeyExists($keyPrefix . 'mobile', $data);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
@ -134,76 +170,41 @@ class Application_Model_StreamSetting
|
|||
* make data easier to iterate over */
|
||||
public static function getStreamDataNormalized($p_streamId)
|
||||
{
|
||||
$con = Propel::getConnection();
|
||||
$streamId = pg_escape_string($p_streamId);
|
||||
$sql = "SELECT * "
|
||||
."FROM cc_stream_setting "
|
||||
."WHERE keyname LIKE '{$streamId}_%'";
|
||||
|
||||
$stmt = $con->prepare($sql);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
$rows = $stmt->fetchAll();
|
||||
} else {
|
||||
$msg = implode(',', $stmt->errorInfo());
|
||||
throw new Exception("Error: $msg");
|
||||
$settings = self::getStreamData($p_streamId);
|
||||
foreach ($settings as $key => $value)
|
||||
{
|
||||
unset($settings[$key]);
|
||||
$newKey = substr($key, strlen($p_streamId)+1); //$p_streamId is assumed to be the key prefix.
|
||||
$settings[$newKey] = $value;
|
||||
}
|
||||
return $settings;
|
||||
}
|
||||
|
||||
$data = array();
|
||||
|
||||
foreach ($rows as $row) {
|
||||
list($id, $key) = explode("_", $row["keyname"], 2);
|
||||
$data[$key] = $row["value"];
|
||||
private static function ensureKeyExists($key, &$array, $default='')
|
||||
{
|
||||
if (!array_key_exists($key, $array)) {
|
||||
$array[$key] = $default;
|
||||
}
|
||||
|
||||
return $data;
|
||||
return $array;
|
||||
}
|
||||
|
||||
public static function getStreamSetting()
|
||||
{
|
||||
$con = Propel::getConnection();
|
||||
$sql = "SELECT *"
|
||||
." FROM cc_stream_setting"
|
||||
." WHERE keyname not like '%_error' AND keyname not like '%_admin_%'";
|
||||
|
||||
$rows = Application_Common_Database::prepareAndExecute($sql, array(), 'all');
|
||||
|
||||
$exists = array();
|
||||
|
||||
foreach ($rows as $r) {
|
||||
if ($r['keyname'] == 'master_live_stream_port') {
|
||||
$exists['master_live_stream_port'] = true;
|
||||
} elseif ($r['keyname'] == 'master_live_stream_mp') {
|
||||
$exists['master_live_stream_mp'] = true;
|
||||
} elseif ($r['keyname'] == 'dj_live_stream_port') {
|
||||
$exists['dj_live_stream_port'] = true;
|
||||
} elseif ($r['keyname'] == 'dj_live_stream_mp') {
|
||||
$exists['dj_live_stream_mp'] = true;
|
||||
}
|
||||
$settings = array();
|
||||
$numStreams = MAX_NUM_STREAMS;
|
||||
for ($streamIdx = 1; $streamIdx <= $numStreams; $streamIdx++)
|
||||
{
|
||||
$settings = array_merge($settings, self::getStreamData("s" . $streamIdx));
|
||||
}
|
||||
|
||||
if (!isset($exists["master_live_stream_port"])) {
|
||||
$rows[] = array("keyname" =>"master_live_stream_port",
|
||||
"value"=>self::getMasterLiveStreamPort(),
|
||||
"type"=>"integer");
|
||||
}
|
||||
if (!isset($exists["master_live_stream_mp"])) {
|
||||
$rows[] = array("keyname" =>"master_live_stream_mp",
|
||||
"value"=>self::getMasterLiveStreamMountPoint(),
|
||||
"type"=>"string");
|
||||
}
|
||||
if (!isset($exists["dj_live_stream_port"])) {
|
||||
$rows[] = array("keyname" =>"dj_live_stream_port",
|
||||
"value"=>self::getDjLiveStreamPort(),
|
||||
"type"=>"integer");
|
||||
}
|
||||
if (!isset($exists["dj_live_stream_mp"])) {
|
||||
$rows[] = array("keyname" =>"dj_live_stream_mp",
|
||||
"value"=>self::getDjLiveStreamMountPoint(),
|
||||
"type"=>"string");
|
||||
}
|
||||
|
||||
return $rows;
|
||||
$settings["master_live_stream_port"] = self::getMasterLiveStreamPort();
|
||||
$settings["master_live_stream_mp"] = self::getMasterLiveStreamMountPoint();
|
||||
$settings["dj_live_stream_port"] = self::getDjLiveStreamPort();
|
||||
$settings["dj_live_stream_mp"] = self::getDjLiveStreamMountPoint();
|
||||
$settings["off_air_meta"] = self::getOffAirMeta();
|
||||
$settings["icecast_vorbis_metadata"] = self::getIcecastVorbisMetadata();
|
||||
$settings["output_sound_device"] = self::getOutputSoundDevice();
|
||||
$settings["output_sound_device_type"] = self::getOutputSoundDeviceType();
|
||||
return $settings;
|
||||
}
|
||||
|
||||
|
||||
|
@ -211,7 +212,10 @@ class Application_Model_StreamSetting
|
|||
{
|
||||
$stream_setting = CcStreamSettingQuery::create()->filterByDbKeyName($key)->findOne();
|
||||
if (is_null($stream_setting)) {
|
||||
throw new Exception("Keyname $key does not exist!");
|
||||
//throw new Exception("Keyname $key does not exist!");
|
||||
$stream_setting = new CcStreamSetting();
|
||||
$stream_setting->setDbKeyName($key);
|
||||
$stream_setting->setDbType("");
|
||||
}
|
||||
|
||||
$stream_setting->setDbValue($value);
|
||||
|
@ -411,7 +415,7 @@ class Application_Model_StreamSetting
|
|||
|
||||
public static function getMasterLiveStreamPort()
|
||||
{
|
||||
return self::getValue("master_live_stream_port");
|
||||
return self::getValue("master_live_stream_port", 8001);
|
||||
}
|
||||
|
||||
public static function setMasterLiveStreamMountPoint($value)
|
||||
|
@ -421,7 +425,7 @@ class Application_Model_StreamSetting
|
|||
|
||||
public static function getMasterLiveStreamMountPoint()
|
||||
{
|
||||
return self::getValue("master_live_stream_mp");
|
||||
return self::getValue("master_live_stream_mp", "/master");
|
||||
}
|
||||
|
||||
public static function setDjLiveStreamPort($value)
|
||||
|
@ -431,7 +435,7 @@ class Application_Model_StreamSetting
|
|||
|
||||
public static function getDjLiveStreamPort()
|
||||
{
|
||||
return self::getValue("dj_live_stream_port");
|
||||
return self::getValue("dj_live_stream_port", 8001);
|
||||
}
|
||||
|
||||
public static function setDjLiveStreamMountPoint($value)
|
||||
|
@ -441,7 +445,7 @@ class Application_Model_StreamSetting
|
|||
|
||||
public static function getDjLiveStreamMountPoint()
|
||||
{
|
||||
return self::getValue("dj_live_stream_mp");
|
||||
return self::getValue("dj_live_stream_mp", "/show");
|
||||
}
|
||||
|
||||
public static function getAdminUser($stream){
|
||||
|
@ -488,4 +492,16 @@ class Application_Model_StreamSetting
|
|||
public static function SetListenerStatError($key, $v) {
|
||||
self::setValue($key, $v, 'string');
|
||||
}
|
||||
|
||||
public static function getIcecastVorbisMetadata() {
|
||||
return self::getValue("icecast_vorbis_metadata", "");
|
||||
}
|
||||
|
||||
public static function getOutputSoundDevice() {
|
||||
return self::getValue("output_sound_device", "false");
|
||||
}
|
||||
|
||||
public static function getOutputSoundDeviceType() {
|
||||
return self::getValue("output_sound_device_type", "");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,310 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
|
||||
<head>
|
||||
<link rel="stylesheet" href="<?php echo $this->css?>" type="text/css">
|
||||
<script src="<?php echo $this->mrp_js?>" type="text/javascript"></script>
|
||||
<script src="<?php echo $this->jquery?>" type="text/javascript"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
var MAX_MOBILE_SCREEN_WIDTH = 760;
|
||||
|
||||
// We are creating a custom player object that acts as a wrapper
|
||||
// around the player object we get from Muses. We are doing this
|
||||
// for a couple reasons:
|
||||
//
|
||||
// 1. It will be easier to swap out Muses for a different player engine
|
||||
// in the future - if we ever decide to do that.
|
||||
// 2. We had to add in some custom behaviour depending on the player
|
||||
// customizations and whether or not the player is in Flash or HTML5
|
||||
// mode.
|
||||
var MusesPlayer = function() {
|
||||
this.mobileDetect = this.mobileDetect();
|
||||
this.playerMode = "<?php echo $this->playerMode ?>";
|
||||
this.flashDetect = FlashDetect.versionAtLeast(10, 1) ? true : false;
|
||||
this.settings = {
|
||||
'volume': 100,
|
||||
'jsevents': true,
|
||||
'autoplay': false,
|
||||
'buffering': 0,
|
||||
'title': 'test',
|
||||
'bgcolor': '#FFFFFF',
|
||||
'skin': 'mcclean',
|
||||
'width': 180,
|
||||
'height': 60
|
||||
};
|
||||
|
||||
if (this.playerMode == "manual") {
|
||||
this.settings.url = <?php echo $this->streamURL ?>;
|
||||
this.settings.codec = "<?php echo $this->codec ?>";
|
||||
} else if (this.playerMode == "auto") {
|
||||
this.availableMobileStreamQueue = <?php echo $this->availableMobileStreams?>;
|
||||
this.availableDesktopStreamQueue = <?php echo $this->availableDesktopStreams?>;
|
||||
var stream = this.getNextAvailableStream();
|
||||
this.settings.url = stream["url"];
|
||||
this.settings.codec = stream["codec"];
|
||||
}
|
||||
|
||||
// Create the Muses player object
|
||||
MRP.insert(this.settings);
|
||||
|
||||
// Configure player title
|
||||
var player_title = <?php echo $this->player_title?>;
|
||||
if (player_title === null) {
|
||||
$(".airtime_header").hide();
|
||||
$(".airtime_player").css('height', '150px');
|
||||
} else {
|
||||
$("p.station_name").html(player_title);
|
||||
}
|
||||
|
||||
attachStreamMetadataToPlayer();
|
||||
|
||||
// detects events in HTML5 mode
|
||||
if (!this.flashDetect) {
|
||||
|
||||
MRP.html.audio.addEventListener('error', function failed(e) {
|
||||
switch (e.target.error.code) {
|
||||
case e.target.error.MEDIA_ERR_NETWORK:
|
||||
// If there is a network error keep retrying to connect
|
||||
// to a stream.
|
||||
var stream;
|
||||
if (musesPlayer.playerMode == "auto") {
|
||||
var nextAvailableStream = musesPlayer.getNextAvailableStream();
|
||||
stream = nextAvailableStream["url"];
|
||||
} else {
|
||||
stream = musesPlayer.settings.url;
|
||||
}
|
||||
var audio = $(MRP.html.audio);
|
||||
audio[0].src = stream;
|
||||
audio[0].load();
|
||||
audio[0].play();
|
||||
break;
|
||||
case e.target.error.MEDIA_ERR_DECODE:
|
||||
// If there was a corruption error or a problem with the browser
|
||||
// display an error and stop playback.
|
||||
togglePlayStopButton();
|
||||
clearTimeout(metadataTimer);
|
||||
$("p.now_playing").html("Error - Try again later");
|
||||
break;
|
||||
case e.target.error.MEDIA_ERR_SRC_NOT_SUPPORTED:
|
||||
// If in auto mode and the current stream format is not supported
|
||||
// or the max number of listeners has been reached
|
||||
// retry connection with the next available stream.
|
||||
if (musesPlayer.playerMode == "auto") {
|
||||
var nextAvailableStream = musesPlayer.getNextAvailableStream();
|
||||
var audio = $(MRP.html.audio);
|
||||
audio[0].src = nextAvailableStream["url"];;
|
||||
audio[0].load();
|
||||
audio[0].play();
|
||||
} else {
|
||||
// If in manual mode and the current stream format is not supported
|
||||
// or the max number of listeners has been reached
|
||||
// display an error and stop play back.
|
||||
togglePlayStopButton();
|
||||
clearTimeout(metadataTimer);
|
||||
$("p.now_playing").html("Error - Try again later");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
togglePlayStopButton();
|
||||
clearTimeout(metadataTimer);
|
||||
$("p.now_playing").html("Error - Try again later");
|
||||
break;
|
||||
}
|
||||
|
||||
}, true);
|
||||
}
|
||||
};
|
||||
|
||||
MusesPlayer.prototype.mobileDetect = function() {
|
||||
return (screen.width <= MAX_MOBILE_SCREEN_WIDTH);
|
||||
}
|
||||
|
||||
// This function is called if an error occurs while a client is
|
||||
// attempting to connect to a stream (An error would occur if
|
||||
// the streams listener count has been maxed out or if the stream is down).
|
||||
// It checks if the client is a mobile device or not and returns the next
|
||||
// best available stream.
|
||||
MusesPlayer.prototype.getNextAvailableStream = function() {
|
||||
if (this.mobileDetect && this.availableMobileStreamQueue.length > 0) {
|
||||
return this.getNextAvailableMobileStream();
|
||||
}
|
||||
|
||||
if (!this.mobileDetect && this.availableDesktopStreamQueue.length > 0) {
|
||||
return this.getNextAvailableDesktopStream();
|
||||
}
|
||||
|
||||
// If we get to this point there are no available streams for the
|
||||
// type of device the client has connected with so just return
|
||||
// the next available stream - first we'll try the desktop streams
|
||||
var desktopStream = this.getNextAvailableDesktopStream();
|
||||
if (desktopStream) {
|
||||
return desktopStream;
|
||||
} else {
|
||||
return this.getNextAvailableMobileStream();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Gets and returns the next available mobile stream from the queue,
|
||||
// but adds it back to the end of the queue to be recycled.
|
||||
MusesPlayer.prototype.getNextAvailableMobileStream = function() {
|
||||
var stream = this.availableMobileStreamQueue.shift();
|
||||
//add to end of queue
|
||||
this.availableMobileStreamQueue.push(stream);
|
||||
return stream;
|
||||
}
|
||||
|
||||
// Gets and returns the next available desktop stream from the queue,
|
||||
// but adds it back to the end of the queue to be recycled.
|
||||
MusesPlayer.prototype.getNextAvailableDesktopStream = function() {
|
||||
var stream = this.availableDesktopStreamQueue.shift();
|
||||
//add to end of queue
|
||||
this.availableDesktopStreamQueue.push(stream);
|
||||
return stream;
|
||||
}
|
||||
|
||||
MusesPlayer.prototype.play = function() {
|
||||
this.flashDetect ? MRP.play() : musesHTMLPlayClick();;
|
||||
togglePlayStopButton();
|
||||
};
|
||||
|
||||
MusesPlayer.prototype.stop = function() {
|
||||
this.flashDetect ? MRP.stop() : musesHTMLStopClick();
|
||||
togglePlayStopButton();
|
||||
};
|
||||
|
||||
MusesPlayer.prototype.setURL = function(url) {
|
||||
MRP.setUrl(url);
|
||||
};
|
||||
|
||||
// detects errors in FLASH mode
|
||||
function musesCallback(event,value) {
|
||||
switch (event) {
|
||||
case "ioError":
|
||||
// connection limit reached or problem connecting to stream
|
||||
if (value === "0") {
|
||||
var stream = musesPlayer.getNextAvailableStream();
|
||||
musesPlayer.setURL(stream["url"]);
|
||||
musesPlayer.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Triggers the play function on the Muses player object in HTML5 mode
|
||||
function musesHTMLPlayClick() {
|
||||
/*if (MRP.html === undefined) {
|
||||
console.log("inserting player");
|
||||
MRP.insert(musesPlayer.settings);
|
||||
}*/
|
||||
MRP.html.audio.src = MRP.html.src;
|
||||
|
||||
MRP.html.audio.play();
|
||||
}
|
||||
|
||||
// Triggers the stop function on the Muses player object in HTML5 mode
|
||||
// NOTE: The HTML5 audio element doesn't have stop functionality. It
|
||||
// can only be paused.
|
||||
function musesHTMLStopClick() {
|
||||
MRP.html.audio.pause();
|
||||
//delete MRP.html;
|
||||
}
|
||||
|
||||
function togglePlayStopButton() {
|
||||
document.getElementById("play_button").classList.toggle("hide_button");
|
||||
document.getElementById("stop_button").classList.toggle("hide_button");
|
||||
}
|
||||
|
||||
// variables for updating the player's metadata
|
||||
var time_to_next_track_starts;
|
||||
var metadataTimer;
|
||||
|
||||
// Fetches the streams metadata from the Airtime live-info API
|
||||
// and attaches it to the player UI.
|
||||
//
|
||||
// The metadata is fetched when the current track is about to end.
|
||||
function attachStreamMetadataToPlayer(){
|
||||
$.ajax({url: "<?php echo $this->metadata_api_url?>",
|
||||
data: {type:"interval",limit:"5"},
|
||||
dataType: "jsonp",
|
||||
success: function(data) {
|
||||
|
||||
if (data.current === null) {
|
||||
$("p.now_playing").html("Offline");
|
||||
time_to_next_track_starts = 20000;
|
||||
} else {
|
||||
var artist = data.current.name.split(" - ")[0];
|
||||
var track = data.current.name.split(" - ")[1];
|
||||
$("p.now_playing").html(artist + "<span>" + track + "</span>");
|
||||
|
||||
var current_track_end_time = new Date(data.current.ends);
|
||||
var current_time = new Date();
|
||||
//convert current_time to UTC to match the timezone of time_to_next_track_starts
|
||||
current_time = new Date(current_time.getTime() + current_time.getTimezoneOffset() * 60 * 1000);
|
||||
time_to_next_track_starts = current_track_end_time - current_time;
|
||||
}
|
||||
|
||||
if (data.next === null) {
|
||||
$("ul.schedule_list").find("li").html("Nothing scheduled");
|
||||
} else {
|
||||
$("ul.schedule_list").find("li").html(data.next.name);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
// Add 3 seconds to the timeout so Airtime has time to update the metadata before we fetch it
|
||||
metadataTimer = setTimeout(attachStreamMetadataToPlayer, time_to_next_track_starts+3000);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style type="text/css">
|
||||
/*
|
||||
We have to have the default Muses skin displayed on the page or else
|
||||
the player will not work. Setting the display to none and hidden does
|
||||
not work. It has to be "visible" on the page. As a hacky work around we
|
||||
set the height and width to 1px so users will not see it.
|
||||
*/
|
||||
#muses_skin{width:1px; height:1px; overflow-x: hidden; overflow-y: hidden;}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="airtime_player">
|
||||
|
||||
<div class="airtime_header">
|
||||
<p class="station_name">fff</p>
|
||||
</div>
|
||||
|
||||
<div class="airtime_box">
|
||||
|
||||
<div class="airtime_button">
|
||||
<span id="play_button" class="play_button" onclick="musesPlayer.play()"></span>
|
||||
<span id="stop_button" class="stop_button hide_button" onclick="musesPlayer.stop()"></span>
|
||||
</div>
|
||||
<p class="now_playing"></p>
|
||||
|
||||
</div>
|
||||
|
||||
<div style="clear:both"></div>
|
||||
|
||||
<div class="airtime_schedule">
|
||||
<p class="airtime_next">Next</p>
|
||||
<ul class="schedule_list">
|
||||
<li></li>
|
||||
</ul>
|
||||
</div>
|
||||
<a class="airtime_pro" target="_blank" href="https://www.airtime.pro/">Powered by <span class="airtime-pro-orange">Airtime Pro</span></a>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="muses_skin">
|
||||
<script type="text/javascript">
|
||||
var musesPlayer = new MusesPlayer();
|
||||
</script>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,29 @@
|
|||
<fieldset class="padded">
|
||||
<dl class="zend_form">
|
||||
|
||||
<?php echo $this->element->getElement('player_preview_label')->renderLabel(); ?>
|
||||
|
||||
<div style="clear:both"></div>
|
||||
<div class="player-preview">
|
||||
<?php echo $this->element->getElement('player_embed_src')->getValue(); ?>
|
||||
</div>
|
||||
|
||||
<div id="player_instructions">
|
||||
Customize the player by configuring the options below. When you are done,
|
||||
copy the embeddable code below and paste it into your website's HTML.
|
||||
</div>
|
||||
|
||||
<?php echo $this->element->getElement('player_title')->render(); ?>
|
||||
|
||||
<?php echo $this->element->getElement('player_stream_mode')->render(); ?>
|
||||
|
||||
<?php echo $this->element->getElement('player_stream_url'); ?>
|
||||
|
||||
<?php echo $this->element->getElement('player_embed_src')->render(); ?>
|
||||
|
||||
<?php //echo $this->element->getElement('player_display_track_metadata'); ?>
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
</fieldset>
|
|
@ -14,6 +14,13 @@
|
|||
<dd id="<?php echo $s_name?>Enabled-element">
|
||||
<?php echo $this->element->getElement('enable')?>
|
||||
</dd>
|
||||
|
||||
<dt id="<?php echo $s_name?>Mobile-label">
|
||||
<label for="<?php echo $s_name?>Mobile"><?php echo $this->element->getElement('mobile')->getLabel() ?></label>
|
||||
</dt>
|
||||
<dd id="<?php echo $s_name?>Mobile-element">
|
||||
<?php echo $this->element->getElement('mobile')?>
|
||||
</dd>
|
||||
|
||||
<dt id="<?php echo $s_name?>Type-label">
|
||||
<label for="<?php echo $s_name?>Type"><?php echo $this->element->getElement('type')->getLabel()?></label>
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<div class="ui-widget ui-widget-content block-shadow simple-formblock embed-player-form clearfix padded-strong ">
|
||||
|
||||
<?php $baseUrl = Application_Common_OsPath::getBaseDir(); ?>
|
||||
|
||||
<form method="post" id="player_form" enctype="multipart/form-data">
|
||||
<h2 style="float:left"><?php echo _("Embeddable Player") ?></h2>
|
||||
<div style="clear:both"></div>
|
||||
<?php echo $this->errorMsg; ?>
|
||||
<?php echo $this->form; ?>
|
||||
|
||||
</form>
|
||||
</div>
|
|
@ -358,3 +358,21 @@ INSERT INTO cc_pref (subjid, keystr, valstr) VALUES (1, 'user_timezone', 'UTC');
|
|||
INSERT INTO cc_pref (keystr, valstr) VALUES ('import_timestamp', '0');
|
||||
|
||||
--end added in 2.5.2
|
||||
|
||||
INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_enable', 'false', 'boolean');
|
||||
INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_output', 'icecast', 'string');
|
||||
INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_name', '', 'string');
|
||||
INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_type', '', 'string');
|
||||
INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_bitrate', '', 'integer');
|
||||
INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_host', '', 'string');
|
||||
INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_port', '', 'integer');
|
||||
INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_user', '', 'string');
|
||||
INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_pass', '', 'string');
|
||||
INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_admin_user', '', 'string');
|
||||
INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_admin_pass', '', 'string');
|
||||
INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_mount', '', 'string');
|
||||
INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_url', '', 'string');
|
||||
INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_description', '', 'string');
|
||||
INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_genre', '', 'string');
|
||||
INSERT INTO cc_stream_setting (keyname, value, type) VALUES ('s4_channels', 'stereo', 'string');
|
||||
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
|
@ -0,0 +1,62 @@
|
|||
.embed-player-text-box {
|
||||
padding-right: 0px !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
.embed-player-form {
|
||||
width: 40%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.embed-player-form dd {
|
||||
width: 100% !important;
|
||||
float: left;
|
||||
margin: 0;
|
||||
padding: 4px 0px 4px 0px;
|
||||
}
|
||||
.player-preview {
|
||||
width: 100%;
|
||||
}
|
||||
.player-preview iframe {
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
}
|
||||
#player_form {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
#player_form dd {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
#player_instructions {
|
||||
border-bottom: 1px solid;
|
||||
padding-bottom: 10px;
|
||||
font-size: 14px;
|
||||
/*font-weight: bold;*/
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.player-title {
|
||||
clear: left;
|
||||
color: #5b5b5b;
|
||||
float: left;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
width: 40px;
|
||||
padding: 4px 0;
|
||||
text-align: left;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 17px;
|
||||
}
|
||||
#player_title {
|
||||
clear: left;
|
||||
}
|
||||
#player_stream_url-element {
|
||||
margin-left:30px;
|
||||
}
|
||||
#player_embed_src-element p {
|
||||
margin: 0px;
|
||||
font-size: 13px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,215 @@
|
|||
.airtime_player {
|
||||
width: 270px;
|
||||
height: 191px;
|
||||
position: relative;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
color: #fff;
|
||||
background: rgba(53, 53, 53, 0.9);
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: 0 3px 5px rgba(0,0,0,0.1) inset,0 1px 0 rgba(255,255,255,0.1),0 0 1px #000 inset;
|
||||
-moz-box-shadow: 0 3px 5px rgba(0,0,0,0.1) inset,0 1px 0 rgba(255,255,255,0.1),0 0 1px #000 inset;
|
||||
box-shadow: 0 3px 5px rgba(0,0,0,0.1) inset,0 1px 0 rgba(255,255,255,0.1),0 0 1px #000 inset;
|
||||
}
|
||||
|
||||
.airtime_header {
|
||||
background: rgba(53, 53, 53, 0.9);
|
||||
-webkit-box-shadow: 0 3px 5px rgba(0,0,0,0.1) inset,0 1px 0 rgba(255,255,255,0.1),0 0 1px #000 inset;
|
||||
-moz-box-shadow: 0 3px 5px rgba(0,0,0,0.1) inset,0 1px 0 rgba(255,255,255,0.1),0 0 1px #000 inset;
|
||||
box-shadow: 0 3px 5px rgba(0,0,0,0.1) inset,0 1px 0 rgba(255,255,255,0.1),0 0 1px #000 inset;
|
||||
height: 37px;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.airtime_box {
|
||||
margin-top: 15px;
|
||||
float: left;
|
||||
width: 100%;
|
||||
height: 52px;
|
||||
}
|
||||
.station_name {
|
||||
font-size: 14px;
|
||||
padding-top: 10px;
|
||||
padding-left: 20px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
padding-right: 30px;
|
||||
}
|
||||
.airtime_pro {
|
||||
margin: 6px 20px;
|
||||
color: #fff;
|
||||
font-size: 11px;
|
||||
text-decoration: none;
|
||||
display:inline-block;
|
||||
float:right;
|
||||
}
|
||||
.airtime_pro_logo {
|
||||
background: url("embed-player-images/airtime_logo.png") center no-repeat;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
display:inline-block;
|
||||
}
|
||||
|
||||
/*.airtime_pro span {
|
||||
display: inline-block;
|
||||
vertical-align: 2px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.airtime_pro:hover span {
|
||||
display: inline-block;
|
||||
vertical-align: 2px;
|
||||
margin-right: 5px;
|
||||
}*/
|
||||
.airtime_box .airtime_button {
|
||||
text-indent: -9999px;
|
||||
-webkit-border-radius: 2px;
|
||||
-moz-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
background: rgb(100,100,100);
|
||||
background: -moz-linear-gradient(top, rgba(107, 107, 107, 1) 0%, rgba(88,88,88,1) 100%);
|
||||
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(100,100,100,1)), color-stop(100%,rgba(88,88,88,1)));
|
||||
background: -webkit-linear-gradient(top, rgba(107, 107, 107, 1) 0%,rgba(88,88,88,1) 100%);
|
||||
background: -o-linear-gradient(top, rgba(107, 107, 107, 1) 0%,rgba(88,88,88,1) 100%);
|
||||
background: -ms-linear-gradient(top, rgba(107, 107, 107, 1) 0%,rgba(88,88,88,1) 100%);
|
||||
background: linear-gradient(to bottom, rgba(107, 107, 107, 1) 0%,rgba(88,88,88,1) 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#646464', endColorstr='#585858',GradientType=0 );
|
||||
-webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.2) inset;
|
||||
-moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.2) inset;
|
||||
box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.2) inset;
|
||||
width: 47px;
|
||||
height: 47px;
|
||||
display: inline-block;
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
margin-left: 20px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.airtime_box .airtime_button:hover {
|
||||
background: rgb(147,147,147);
|
||||
background: -moz-linear-gradient(top, rgba(147,147,147,1) 0%, rgba(117,117,117,1) 100%);
|
||||
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(147,147,147,1)), color-stop(100%,rgba(117,117,117,1)));
|
||||
background: -webkit-linear-gradient(top, rgba(147,147,147,1) 0%,rgba(117,117,117,1) 100%);
|
||||
background: -o-linear-gradient(top, rgba(147,147,147,1) 0%,rgba(117,117,117,1) 100%);
|
||||
background: -ms-linear-gradient(top, rgba(147,147,147,1) 0%,rgba(117,117,117,1) 100%);
|
||||
background: linear-gradient(to bottom, rgba(147,147,147,1) 0%,rgba(117,117,117,1) 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#939393', endColorstr='#757575',GradientType=0 );
|
||||
}
|
||||
|
||||
.airtime_box .airtime_button .play_button {
|
||||
display: block;
|
||||
background: url("embed-player-images/play_button.png") center no-repeat;
|
||||
width: 47px;
|
||||
height: 47px;
|
||||
}
|
||||
|
||||
.airtime_box .airtime_button .stop_button {
|
||||
display: block;
|
||||
background: url("embed-player-images/pause_button.png") center no-repeat;
|
||||
width: 47px;
|
||||
height: 47px;
|
||||
}
|
||||
|
||||
.hide_button {
|
||||
display:none !important;
|
||||
}
|
||||
|
||||
.now_playing {
|
||||
margin-top: 8px;
|
||||
margin-left: 15px;
|
||||
margin-right: 15px;
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
width: 170px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.now_playing span {
|
||||
display: block;
|
||||
color: #aaaaaa;
|
||||
width: 170px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.airtime_volume {
|
||||
padding: 10px 0px 15px 0px;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.airtime_volume .volume_control {
|
||||
margin-left: 55px;
|
||||
float: left;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.airtime_volume .mute {
|
||||
background: url("embed-player-images/mute.png") center no-repeat;
|
||||
display: block;
|
||||
margin-top: -4px;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.airtime_volume_bar {
|
||||
border-color: #262526 #262526 #5E5E5E;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
background-color: #393939;
|
||||
width: auto;
|
||||
height: 5px;
|
||||
cursor: pointer;
|
||||
margin-left: 80px;
|
||||
margin-right: 40px;
|
||||
}
|
||||
|
||||
.airtime_volume_bar_value {
|
||||
background-color: #ff9122;
|
||||
width: 0px;
|
||||
height: 5px;
|
||||
}
|
||||
|
||||
.airtime_schedule {
|
||||
margin: 10px 20px 5px 20px;
|
||||
padding-top: 10px;
|
||||
font-size: 14px;
|
||||
color: #aaaaaa;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
|
||||
.airtime_next {
|
||||
float: left;
|
||||
margin: 0px;
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.schedule_list {
|
||||
list-style: none;
|
||||
padding-left: 0px;
|
||||
padding-bottom: 10px;
|
||||
margin-top: 0px;
|
||||
margin-left: 60px;
|
||||
margin-bottom: 0px;
|
||||
line-height: 130%;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.schedule_list li {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.airtime-pro-orange {
|
||||
color: #ff5d1a;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
@ -0,0 +1,94 @@
|
|||
function updateEmbedSrcParams()
|
||||
{
|
||||
var $embedCodeParams = "?";
|
||||
var $streamMode = getStreamMode();
|
||||
if ($streamMode == "manual") {
|
||||
var $stream = $("input[name=player_stream_url]:radio:checked").val();
|
||||
$embedCodeParams += "stream="+$stream;
|
||||
} else if ($streamMode == "auto") {
|
||||
$embedCodeParams += "stream=auto";
|
||||
}
|
||||
|
||||
$embedCodeParams += "&title="+getPlayerTitle();
|
||||
|
||||
$embedCodeParams += "\"";
|
||||
|
||||
$("textarea[name=player_embed_src]").val(function(index, value) {
|
||||
return value.replace(/\?.*?"/, $embedCodeParams);
|
||||
});
|
||||
|
||||
updatePlayerIframeSrc($("textarea[name=player_embed_src]").val());
|
||||
}
|
||||
|
||||
function updatePlayerIframeSrc(iframe_text) {
|
||||
var $player_iframe = $("#player_form iframe");
|
||||
var player_iframe_src = iframe_text.match(/http.*?"/)[0].slice(0, -1);
|
||||
$player_iframe.attr('src', player_iframe_src);
|
||||
}
|
||||
|
||||
function getStreamMode() {
|
||||
return $("input[name=player_stream_mode]:radio:checked").val();
|
||||
}
|
||||
|
||||
function getPlayerTitle() {
|
||||
return $("input[name=player_title]").val();
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
$("#player_stream_url-element").hide();
|
||||
|
||||
// stream mode change event
|
||||
$("#player_stream_mode-element").change(function() {
|
||||
var $streamMode = getStreamMode();
|
||||
|
||||
if ($streamMode == "auto") {
|
||||
$("#player_stream_url-element").hide();
|
||||
|
||||
} else if ($streamMode == "manual") {
|
||||
$("#player_stream_url-element").show();
|
||||
|
||||
$("input[name=player_stream_url]").each(function(i, obj) {
|
||||
if ($(this).parent().text().toLowerCase().indexOf("opus") >= 0) {
|
||||
$(this).attr("disabled", "disabled");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
updateEmbedSrcParams();
|
||||
});
|
||||
|
||||
// stream url change event
|
||||
$("#player_stream_url-element").change(function() {
|
||||
updateEmbedSrcParams();
|
||||
});
|
||||
|
||||
// display title checkbox change event
|
||||
$("#player_display_title").change(function() {
|
||||
if ($(this).prop("checked")) {
|
||||
$("#player_title-label").show();
|
||||
$("#player_title-element").show();
|
||||
} else {
|
||||
$("#player_title-label").hide();
|
||||
$("#player_title-element").hide();
|
||||
}
|
||||
updateEmbedSrcParams();
|
||||
});
|
||||
|
||||
// title textbox change event
|
||||
// setup before functions
|
||||
var typingTimer;
|
||||
var doneTypingInterval = 3000;
|
||||
|
||||
// on keyup, start the countdown
|
||||
$("input[name=player_title]").keyup(function(){
|
||||
clearTimeout(typingTimer);
|
||||
typingTimer = setTimeout(updateEmbedSrcParams, doneTypingInterval);
|
||||
});
|
||||
|
||||
// on keydown, clear the countdown
|
||||
$("input[name=player_title]").keydown(function(){
|
||||
clearTimeout(typingTimer);
|
||||
});
|
||||
});
|
||||
|
|
@ -443,7 +443,7 @@ function setSliderForReplayGain(){
|
|||
$( "#replayGainModifier" ).val( $( "#slider-range-max" ).slider( "value" ) );
|
||||
}
|
||||
|
||||
function setPseudoAdminPassword(s1, s2, s3) {
|
||||
function setPseudoAdminPassword(s1, s2, s3, s4) {
|
||||
if (s1) {
|
||||
$('#s1_data-admin_pass').val('xxxxxx');
|
||||
}
|
||||
|
@ -453,11 +453,14 @@ function setPseudoAdminPassword(s1, s2, s3) {
|
|||
if (s3) {
|
||||
$('#s3_data-admin_pass').val('xxxxxx');
|
||||
}
|
||||
if (s4) {
|
||||
$('#s4_data-admin_pass').val('xxxxxx');
|
||||
}
|
||||
}
|
||||
|
||||
function getAdminPasswordStatus() {
|
||||
$.ajax({ url: baseUrl+'Preference/get-admin-password-status/format/json', dataType:"json", success:function(data){
|
||||
setPseudoAdminPassword(data.s1, data.s2, data.s3);
|
||||
setPseudoAdminPassword(data.s1, data.s2, data.s3, data.s4);
|
||||
}});
|
||||
}
|
||||
|
||||
|
@ -476,7 +479,7 @@ $(document).ready(function() {
|
|||
$('#content').empty().append(json.html);
|
||||
setupEventListeners();
|
||||
setSliderForReplayGain();
|
||||
setPseudoAdminPassword(json.s1_set_admin_pass, json.s2_set_admin_pass, json.s3_set_admin_pass);
|
||||
setPseudoAdminPassword(json.s1_set_admin_pass, json.s2_set_admin_pass, json.s3_set_admin_pass, json.s4_set_admin_pass);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -10,18 +10,23 @@ def generate_liquidsoap_config(ss):
|
|||
fh.write("################################################\n")
|
||||
fh.write("# THIS FILE IS AUTO GENERATED. DO NOT CHANGE!! #\n")
|
||||
fh.write("################################################\n")
|
||||
fh.write("# The ignore() lines are to squash unused variable warnings\n")
|
||||
|
||||
for d in data:
|
||||
key = d['keyname']
|
||||
for key, value in data.iteritems():
|
||||
try:
|
||||
str_buffer = "%s = %s\n" % (key, int(value))
|
||||
except ValueError:
|
||||
try: # Is it a boolean?
|
||||
if "true" in value or "false" in value:
|
||||
str_buffer = "%s = %s\n" % (key, value.lower())
|
||||
else:
|
||||
raise ValueError() # Just drop into the except below
|
||||
except: #Everything else is a string
|
||||
str_buffer = "%s = \"%s\"\n" % (key, value)
|
||||
|
||||
str_buffer = d[u'keyname'] + " = "
|
||||
if d[u'type'] == 'string':
|
||||
val = '"%s"' % d['value']
|
||||
else:
|
||||
val = d[u'value']
|
||||
val = val if len(val) > 0 else "0"
|
||||
str_buffer = "%s = %s\n" % (key, val)
|
||||
fh.write(str_buffer.encode('utf-8'))
|
||||
# ignore squashes unused variable errors from Liquidsoap
|
||||
fh.write(("ignore(%s)\n" % key).encode('utf-8'))
|
||||
|
||||
fh.write('log_file = "/var/log/airtime/pypo-liquidsoap/<script>.log"\n')
|
||||
fh.close()
|
||||
|
|
|
@ -10,18 +10,22 @@ output_sound_device_type = "ALSA"
|
|||
s1_output = "icecast"
|
||||
s2_output = "icecast"
|
||||
s3_output = "icecast"
|
||||
s4_output = "icecast"
|
||||
|
||||
s1_enable = true
|
||||
s2_enable = false
|
||||
s3_enable = false
|
||||
s4_enable = false
|
||||
|
||||
s1_type = "ogg"
|
||||
s2_type = "ogg"
|
||||
s3_type = "mp3"
|
||||
s4_type = "mp3"
|
||||
|
||||
s1_bitrate = 128
|
||||
s2_bitrate = 128
|
||||
s3_bitrate = 160
|
||||
s4_bitrate = 160
|
||||
|
||||
###########################################
|
||||
# Logging settings #
|
||||
|
@ -35,31 +39,39 @@ log_file = "/var/log/airtime/pypo-liquidsoap/<script>.log"
|
|||
s1_host = "127.0.0.1"
|
||||
s2_host = "127.0.0.1"
|
||||
s3_host = "127.0.0.1"
|
||||
s4_host = "127.0.0.1"
|
||||
s1_port = 8000
|
||||
s2_port = 8000
|
||||
s3_port = 8000
|
||||
s4_port = 8000
|
||||
s1_user = ""
|
||||
s2_user = ""
|
||||
s3_user = ""
|
||||
s4_user = ""
|
||||
s1_pass = "hackme"
|
||||
s2_pass = "hackme"
|
||||
s3_pass = "hackme"
|
||||
s4_pass = "hackme"
|
||||
|
||||
# Icecast mountpoint names
|
||||
s1_mount = "airtime_128.ogg"
|
||||
s2_mount = "airtime_128.ogg"
|
||||
s3_mount = "airtime_160.mp3"
|
||||
s4_mount = "airtime_160.mp3"
|
||||
|
||||
# Webstream metadata settings
|
||||
s1_url = "http://airtime.sourcefabric.org"
|
||||
s2_url = "http://airtime.sourcefabric.org"
|
||||
s3_url = "http://airtime.sourcefabric.org"
|
||||
s1_description = "Airtime Radio! stream1"
|
||||
s2_description = "Airtime Radio! stream2"
|
||||
s3_description = "Airtime Radio! stream3"
|
||||
s4_url = "http://airtime.sourcefabric.org"
|
||||
s1_description = "Airtime Radio! Stream 1"
|
||||
s2_description = "Airtime Radio! Stream 2"
|
||||
s3_description = "Airtime Radio! Stream 3"
|
||||
s4_description = "Airtime Radio! Stream 4"
|
||||
s1_genre = "genre"
|
||||
s2_genre = "genre"
|
||||
s3_genre = "genre"
|
||||
s4_genre = "genre"
|
||||
|
||||
# Audio stream metadata for vorbis/ogg is disabled by default
|
||||
# due to a number of client media players that disconnect
|
||||
|
|
|
@ -29,6 +29,7 @@ dynamic_metadata_callback = ref fun (s) -> begin () end
|
|||
s1_connected = ref ''
|
||||
s2_connected = ref ''
|
||||
s3_connected = ref ''
|
||||
s4_connected = ref ''
|
||||
s1_namespace = ref ''
|
||||
s2_namespace = ref ''
|
||||
s3_namespace = ref ''
|
||||
|
@ -103,7 +104,7 @@ server.register(namespace="vars",
|
|||
fun (s) -> begin log("vars.bootup_time") time := s s end)
|
||||
server.register(namespace="streams",
|
||||
"connection_status",
|
||||
fun (s) -> begin log("streams.connection_status") "1:#{!s1_connected},2:#{!s2_connected},3:#{!s3_connected}" end)
|
||||
fun (s) -> begin log("streams.connection_status") "1:#{!s1_connected},2:#{!s2_connected},3:#{!s3_connected},4:#{!s4_connected}" end)
|
||||
server.register(namespace="vars",
|
||||
"default_dj_fade",
|
||||
fun (s) -> begin log("vars.default_dj_fade") default_dj_fade := float_of_string(s) s end)
|
||||
|
@ -399,6 +400,21 @@ if s3_enable == true then
|
|||
s3_connected, s3_description, s3_channels)
|
||||
end
|
||||
|
||||
s4_namespace = ref ''
|
||||
if s4_enable == true then
|
||||
log("Stream 4 Enabled")
|
||||
if s4_output == 'shoutcast' then
|
||||
s4_namespace := "shoutcast_stream_4"
|
||||
else
|
||||
s4_namespace := s4_mount
|
||||
end
|
||||
server.register(namespace=!s4_namespace, "connected", fun (s) -> begin log("#{!s4_namespace}.connected") !s4_connected end)
|
||||
output_to(s4_output, s4_type, s4_bitrate, s4_host, s4_port, s4_pass,
|
||||
s4_mount, s4_url, s4_name, s4_genre, s4_user, s, "4",
|
||||
s4_connected, s4_description, s4_channels)
|
||||
end
|
||||
|
||||
|
||||
command = "/usr/lib/airtime/pypo/bin/liquidsoap_scripts/notify.sh --liquidsoap-started &"
|
||||
log(command)
|
||||
system(command)
|
||||
|
|
|
@ -118,10 +118,10 @@ class ListenerStat(Thread):
|
|||
else:
|
||||
stats.append(self.get_shoutcast_stats(v))
|
||||
self.update_listener_stat_error(v["mount"], 'OK')
|
||||
except Exception, e:
|
||||
except Exception as e:
|
||||
try:
|
||||
self.update_listener_stat_error(v["mount"], str(e))
|
||||
except Exception, e:
|
||||
except Exception as e:
|
||||
self.logger.error('Exception: %s', e)
|
||||
|
||||
return stats
|
||||
|
|
|
@ -216,98 +216,9 @@ class PypoFetch(Thread):
|
|||
TODO: This function needs to be way shorter, and refactored :/ - MK
|
||||
"""
|
||||
def regenerate_liquidsoap_conf(self, setting):
|
||||
existing = {}
|
||||
self.restart_liquidsoap()
|
||||
self.update_liquidsoap_connection_status()
|
||||
|
||||
setting = sorted(setting.items())
|
||||
try:
|
||||
fh = open('/etc/airtime/liquidsoap.cfg', 'r')
|
||||
except IOError, e:
|
||||
#file does not exist
|
||||
self.restart_liquidsoap()
|
||||
return
|
||||
|
||||
self.logger.info("Reading existing config...")
|
||||
# read existing conf file and build dict
|
||||
while True:
|
||||
line = fh.readline()
|
||||
|
||||
# empty line means EOF
|
||||
if not line:
|
||||
break
|
||||
|
||||
line = line.strip()
|
||||
|
||||
if not len(line) or line[0] == "#":
|
||||
continue
|
||||
|
||||
try:
|
||||
key, value = line.split('=', 1)
|
||||
except ValueError:
|
||||
continue
|
||||
key = key.strip()
|
||||
value = value.strip()
|
||||
value = value.replace('"', '')
|
||||
if value == '' or value == "0":
|
||||
value = ''
|
||||
existing[key] = value
|
||||
fh.close()
|
||||
|
||||
# dict flag for any change in config
|
||||
change = {}
|
||||
# this flag is to detect disable -> disable change
|
||||
# in that case, we don't want to restart even if there are changes.
|
||||
state_change_restart = {}
|
||||
#restart flag
|
||||
restart = False
|
||||
|
||||
self.logger.info("Looking for changes...")
|
||||
# look for changes
|
||||
for k, s in setting:
|
||||
if "output_sound_device" in s[u'keyname'] or "icecast_vorbis_metadata" in s[u'keyname']:
|
||||
dump, stream = s[u'keyname'].split('_', 1)
|
||||
state_change_restart[stream] = False
|
||||
# This is the case where restart is required no matter what
|
||||
if (existing[s[u'keyname']] != str(s[u'value'])):
|
||||
self.logger.info("'Need-to-restart' state detected for %s...", s[u'keyname'])
|
||||
restart = True;
|
||||
elif "master_live_stream_port" in s[u'keyname'] or "master_live_stream_mp" in s[u'keyname'] or "dj_live_stream_port" in s[u'keyname'] or "dj_live_stream_mp" in s[u'keyname'] or "off_air_meta" in s[u'keyname']:
|
||||
if (existing[s[u'keyname']] != s[u'value']):
|
||||
self.logger.info("'Need-to-restart' state detected for %s...", s[u'keyname'])
|
||||
restart = True;
|
||||
else:
|
||||
stream, dump = s[u'keyname'].split('_', 1)
|
||||
if "_output" in s[u'keyname']:
|
||||
if (existing[s[u'keyname']] != s[u'value']):
|
||||
self.logger.info("'Need-to-restart' state detected for %s...", s[u'keyname'])
|
||||
restart = True;
|
||||
state_change_restart[stream] = True
|
||||
elif (s[u'value'] != 'disabled'):
|
||||
state_change_restart[stream] = True
|
||||
else:
|
||||
state_change_restart[stream] = False
|
||||
else:
|
||||
# setting inital value
|
||||
if stream not in change:
|
||||
change[stream] = False
|
||||
if not (s[u'value'] == existing[s[u'keyname']]):
|
||||
self.logger.info("Keyname: %s, Current value: %s, New Value: %s", s[u'keyname'], existing[s[u'keyname']], s[u'value'])
|
||||
change[stream] = True
|
||||
|
||||
# set flag change for sound_device alway True
|
||||
self.logger.info("Change:%s, State_Change:%s...", change, state_change_restart)
|
||||
|
||||
for k, v in state_change_restart.items():
|
||||
if k == "sound_device" and v:
|
||||
restart = True
|
||||
elif v and change[k]:
|
||||
self.logger.info("'Need-to-restart' state detected for %s...", k)
|
||||
restart = True
|
||||
# rewrite
|
||||
if restart:
|
||||
self.restart_liquidsoap()
|
||||
else:
|
||||
self.logger.info("No change detected in setting...")
|
||||
self.update_liquidsoap_connection_status()
|
||||
|
||||
@ls_timeout
|
||||
def update_liquidsoap_connection_status(self):
|
||||
|
|
|
@ -15,6 +15,7 @@ class PypoLiquidsoap():
|
|||
"s1": None,
|
||||
"s2": None,
|
||||
"s3": None,
|
||||
"s4": None,
|
||||
}
|
||||
|
||||
self.telnet_liquidsoap = TelnetLiquidsoap(telnet_lock, \
|
||||
|
|
|
@ -83,12 +83,12 @@ class Notify:
|
|||
|
||||
# @pram time: time that LS started
|
||||
def notify_liquidsoap_status(self, msg, stream_id, time):
|
||||
logger.debug('#################################################')
|
||||
logger.debug('# Calling server to update liquidsoap status #')
|
||||
logger.debug('#################################################')
|
||||
logger.debug('msg = ' + str(msg))
|
||||
logger.info('#################################################')
|
||||
logger.info('# Calling server to update liquidsoap status #')
|
||||
logger.info('#################################################')
|
||||
logger.info('msg = ' + str(msg))
|
||||
response = self.api_client.notify_liquidsoap_status(msg, stream_id, time)
|
||||
logger.debug("Response: " + json.dumps(response))
|
||||
logger.info("Response: " + json.dumps(response))
|
||||
|
||||
def notify_source_status(self, source_name, status):
|
||||
logger.debug('#################################################')
|
||||
|
|
Loading…
Reference in New Issue