From f193047a1cc17a5c0f1586d53a9129e5cda37d7d Mon Sep 17 00:00:00 2001 From: James Date: Thu, 8 Mar 2012 17:42:38 -0500 Subject: [PATCH] CC-3367: Display in Now Playing whether Live DJ stream and Live Master stream are connected and give user the ability to block those streams - added stream source switch interface - backend code --- .../application/controllers/ApiController.php | 11 +++ .../controllers/DashboardController.php | 32 +++++++- .../controllers/ScheduleController.php | 12 ++- .../application/layouts/scripts/builder.phtml | 7 +- .../application/layouts/scripts/layout.phtml | 8 +- .../application/layouts/scripts/library.phtml | 7 +- airtime_mvc/application/models/Preference.php | 26 +++++++ .../views/helpers/SourceConnectionStatus.php | 8 ++ .../views/helpers/SourceSwitchStatus.php | 9 +++ .../views/scripts/partialviews/header.phtml | 8 ++ airtime_mvc/public/css/styles.css | 76 ++++++++++++++++++- .../public/js/airtime/dashboard/playlist.js | 49 +++++++++++- python_apps/api_clients/api_client.cfg | 3 + python_apps/api_clients/api_client.py | 14 ++++ .../pypo/liquidsoap_scripts/ls_lib.liq | 25 ++++++ .../pypo/liquidsoap_scripts/ls_script.liq | 69 +++++++++++------ python_apps/pypo/pypo-notify.py | 19 ++++- python_apps/pypo/pypofetch.py | 35 ++++++++- python_apps/pypo/pypomessagehandler.py | 3 + 19 files changed, 383 insertions(+), 38 deletions(-) create mode 100644 airtime_mvc/application/views/helpers/SourceConnectionStatus.php create mode 100644 airtime_mvc/application/views/helpers/SourceSwitchStatus.php diff --git a/airtime_mvc/application/controllers/ApiController.php b/airtime_mvc/application/controllers/ApiController.php index 66309b091..1cbb65ade 100644 --- a/airtime_mvc/application/controllers/ApiController.php +++ b/airtime_mvc/application/controllers/ApiController.php @@ -29,6 +29,7 @@ class ApiController extends Zend_Controller_Action ->addActionContext('handle-watched-dir-missing', 'json') ->addActionContext('rabbitmq-do-push', 'json') ->addActionContext('check-live-stream-auth', 'json') + ->addActionContext('update-source-status', 'json') ->initContext(); } @@ -862,6 +863,16 @@ class ApiController extends Zend_Controller_Action Application_Model_StreamSetting::setLiquidsoapError($stream_id, $msg, $boot_time); } + + public function updateSourceStatusAction(){ + $request = $this->getRequest(); + + $msg = $request->getParam('msg'); + $sourcename = $request->getParam('sourcename'); + $status = $request->getParam('status'); + + Application_Model_Preference::SetSourceStatus($sourcename, $status); + } // handles addition/deletion of mount point which watched dirs reside public function updateFileSystemMountAction(){ diff --git a/airtime_mvc/application/controllers/DashboardController.php b/airtime_mvc/application/controllers/DashboardController.php index 284e810b6..a0ed240f0 100644 --- a/airtime_mvc/application/controllers/DashboardController.php +++ b/airtime_mvc/application/controllers/DashboardController.php @@ -5,14 +5,42 @@ class DashboardController extends Zend_Controller_Action public function init() { - + $ajaxContext = $this->_helper->getHelper('AjaxContext'); + $ajaxContext->addActionContext('switch-source', 'json') + ->initContext(); } public function indexAction() { // action body } - + + public function switchSourceAction(){ + $request = $this->getRequest(); + $baseUrl = $request->getBaseUrl(); + $sourcename = $this->_getParam('sourcename'); + $current_status = $this->_getParam('status'); + $change_status_to = "on"; + + if(strtolower($current_status) == "on"){ + $change_status_to = "off"; + } + + $data = array("sourcename"=>$sourcename, "status"=>$change_status_to); + Application_Model_RabbitMq::SendMessageToPypo("switch_source", $data); + if(strtolower($current_status) == "on"){ + Application_Model_Preference::SetSourceSwitchStatus($sourcename, "off"); + $this->view->status = "OFF"; + }else{ + Application_Model_Preference::SetSourceSwitchStatus($sourcename, "on"); + $this->view->status = "ON"; + } + } + + public function switchOffSource(){ + + } + public function streamPlayerAction() { global $CC_CONFIG; diff --git a/airtime_mvc/application/controllers/ScheduleController.php b/airtime_mvc/application/controllers/ScheduleController.php index 5fb6198fd..0f340ec61 100644 --- a/airtime_mvc/application/controllers/ScheduleController.php +++ b/airtime_mvc/application/controllers/ScheduleController.php @@ -321,8 +321,18 @@ class ScheduleController extends Zend_Controller_Action Application_Model_Show::ConvertToLocalTimeZone($range["currentShow"], array("starts", "ends", "start_timestamp", "end_timestamp")); Application_Model_Show::ConvertToLocalTimeZone($range["nextShow"], array("starts", "ends", "start_timestamp", "end_timestamp")); - + + $source_status = array(); + $live_dj = Application_Model_Preference::GetSourceStatus("live_dj"); + $master_dj = Application_Model_Preference::GetSourceStatus("master_dj"); + + //might not be the correct place to implement this but for now let's just do it here + $source_status['live_dj_source'] = $live_dj; + $source_status['master_dj_source'] = $master_dj; + $this->view->source_status = $source_status; + $this->view->entries = $range; + } public function removeGroupAction() diff --git a/airtime_mvc/application/layouts/scripts/builder.phtml b/airtime_mvc/application/layouts/scripts/builder.phtml index d1d37a4f2..ad1bbe74d 100644 --- a/airtime_mvc/application/layouts/scripts/builder.phtml +++ b/airtime_mvc/application/layouts/scripts/builder.phtml @@ -10,8 +10,11 @@
- versionNotify() ?> - partial('partialviews/header.phtml', array("user" => $this->loggedInAs(), "is_trial"=>$this->isTrial(), "trial_remain"=> $this->trialRemaining())) ?> + versionNotify(); + $sss = $this->SourceSwitchStatus(); + $scs = $this->SourceConnectionStatus();?> + partial('partialviews/header.phtml', array("user" => $this->loggedInAs(), "is_trial"=>$this->isTrial(), "trial_remain"=> $this->trialRemaining(), + "live_dj_switch"=>$sss['live_dj'], "live_dj_connection"=>$scs['live_dj'], "master_dj_switch"=>$sss['master_dj'], "master_dj_connection"=>$scs['master_dj'])) ?> navigation()->menu()->setPartial($partial); ?> diff --git a/airtime_mvc/application/layouts/scripts/layout.phtml b/airtime_mvc/application/layouts/scripts/layout.phtml index 10e6a5ec9..cc6aa9ac1 100644 --- a/airtime_mvc/application/layouts/scripts/layout.phtml +++ b/airtime_mvc/application/layouts/scripts/layout.phtml @@ -11,8 +11,12 @@
- versionNotify() ?> - partial('partialviews/header.phtml', array("user" => $this->loggedInAs(), "is_trial"=>$this->isTrial(), "trial_remain"=> $this->trialRemaining())) ?> + versionNotify(); + $sss = $this->SourceSwitchStatus(); + $scs = $this->SourceConnectionStatus(); + ?> + partial('partialviews/header.phtml', array("user" => $this->loggedInAs(), "is_trial"=>$this->isTrial(), "trial_remain"=> $this->trialRemaining(), + "live_dj_switch"=>$sss['live_dj'], "live_dj_connection"=>$scs['live_dj'], "master_dj_switch"=>$sss['master_dj'], "master_dj_connection"=>$scs['master_dj'])) ?> navigation()->menu()->setPartial($partial); ?> diff --git a/airtime_mvc/application/layouts/scripts/library.phtml b/airtime_mvc/application/layouts/scripts/library.phtml index d015fee03..9a2400624 100644 --- a/airtime_mvc/application/layouts/scripts/library.phtml +++ b/airtime_mvc/application/layouts/scripts/library.phtml @@ -11,8 +11,11 @@
- versionNotify() ?> - partial('partialviews/header.phtml', array("user" => $this->loggedInAs(), "is_trial"=>$this->isTrial(), "trial_remain"=> $this->trialRemaining())) ?> + versionNotify(); + $sss = $this->SourceSwitchStatus(); + $scs = $this->SourceConnectionStatus(); ?> + partial('partialviews/header.phtml', array("user" => $this->loggedInAs(), "is_trial"=>$this->isTrial(), "trial_remain"=> $this->trialRemaining(), + "live_dj_switch"=>$sss['live_dj'], "live_dj_connection"=>$scs['live_dj'], "master_dj_switch"=>$sss['master_dj'], "master_dj_connection"=>$scs['master_dj'])) ?> navigation()->menu()->setPartial($partial); ?> diff --git a/airtime_mvc/application/models/Preference.php b/airtime_mvc/application/models/Preference.php index d5d708418..8f6da6215 100644 --- a/airtime_mvc/application/models/Preference.php +++ b/airtime_mvc/application/models/Preference.php @@ -728,6 +728,32 @@ class Application_Model_Preference public static function GetLiveSteamMasterPassword(){ return self::GetValue("live_stream_master_password"); } + + public static function SetSourceStatus($sourcename, $status){ + self::SetValue($sourcename, $status, false); + } + + public static function GetSourceStatus($sourcename){ + $value = self::GetValue($sourcename); + if($value == null || $value == "false"){ + return false; + }else{ + return true; + } + } + + public static function SetSourceSwitchStatus($sourcename, $status){ + self::SetValue($sourcename."_switch", $status, false); + } + + public static function GetSourceSwitchStatus($sourcename){ + $value = self::GetValue($sourcename."_switch"); + if($value == null || $value == "off"){ + return "off"; + }else{ + return "on"; + } + } /* User specific preferences end */ } diff --git a/airtime_mvc/application/views/helpers/SourceConnectionStatus.php b/airtime_mvc/application/views/helpers/SourceConnectionStatus.php new file mode 100644 index 000000000..1d86b0f57 --- /dev/null +++ b/airtime_mvc/application/views/helpers/SourceConnectionStatus.php @@ -0,0 +1,8 @@ +Application_Model_Preference::GetSourceStatus("live_dj"), "master_dj"=>Application_Model_Preference::GetSourceStatus("master_dj")); + return $status; + } +} \ No newline at end of file diff --git a/airtime_mvc/application/views/helpers/SourceSwitchStatus.php b/airtime_mvc/application/views/helpers/SourceSwitchStatus.php new file mode 100644 index 000000000..12bf8537d --- /dev/null +++ b/airtime_mvc/application/views/helpers/SourceSwitchStatus.php @@ -0,0 +1,9 @@ +Application_Model_Preference::GetSourceSwitchStatus("live_dj"), "master_dj"=>Application_Model_Preference::GetSourceSwitchStatus("master_dj")); + Logging::log(print_r($status,true)); + return $status; + } +} \ No newline at end of file diff --git a/airtime_mvc/application/views/scripts/partialviews/header.phtml b/airtime_mvc/application/views/scripts/partialviews/header.phtml index 82381e4da..eff7016c4 100644 --- a/airtime_mvc/application/views/scripts/partialviews/header.phtml +++ b/airtime_mvc/application/views/scripts/partialviews/header.phtml @@ -31,6 +31,14 @@
  • +
    + +
    • user ?> | Logout
    • diff --git a/airtime_mvc/public/css/styles.css b/airtime_mvc/public/css/styles.css index bbaa69054..0e24da075 100644 --- a/airtime_mvc/public/css/styles.css +++ b/airtime_mvc/public/css/styles.css @@ -152,7 +152,7 @@ select { position:relative; } -.now-playing-block, .show-block, .on-air-block, .time-info-block, .personal-block, .listen-control-block, .trial-info-block { +.now-playing-block, .show-block, .on-air-block, .time-info-block, .personal-block, .listen-control-block, .trial-info-block, .source-info-block { height:100px; float:left; margin-right:10px; @@ -263,7 +263,7 @@ select { padding:0 12px 0 0; background:url(images/masterpanel_spacer.png) no-repeat right 0; } -.time-info-block { +.time-info-block { padding:0 14px 0 2px; background:url(images/masterpanel_spacer.png) no-repeat right 0; min-width:105px; @@ -288,6 +288,25 @@ select { font-size:17px; margin-bottom:0; } + +.source-info-block { + padding:0 14px 0 2px; + background:url(images/masterpanel_spacer.png) no-repeat right 0; + min-width:150px; +} + +.source-info-block li { + list-style-type:none; + font-size:14px; + color:#bdbdbd; + margin:0 0 6px; +} + +.source-info-block ul { + margin:0; + padding:6px 0 0; +} + .on-air-info { height:26px; border:1px solid #242424; @@ -361,6 +380,59 @@ select { color:#fff; } +.source-switch-button { + font-size:11px; + text-transform:uppercase; + padding:0; + border:1px solid #242424; + color:#fff; + text-decoration:none; + font-weight:bold; + display:block; + text-align:center; + width: 40px; + float: right; +} + +.source-switch-button span { + background-color: #6e6e6e; + background: -moz-linear-gradient(top, #868686 0, #6e6e6e 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #868686), color-stop(100%, #6e6e6e)); + border:1px solid #a1a1a1; + border-width:1px 0; + border-bottom-color:#646464; + color:#dcdcdc; + text-shadow: #555555 0px -1px; + display:block; +} + +.source-switch-button:hover { + border:1px solid #000; +} + +.source-switch-button:hover span { + background-color: #292929; + background: -moz-linear-gradient(top, #3b3b3b 0, #292929 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #3b3b3b), color-stop(100%, #292929)); + border:1px solid #555555; + border-width:1px 0; + border-bottom-color:#1e1e1e; + color:#fff; + color:#0C0; + text-shadow: #000 0px -1px; + display:block; +} + +.source-connection { + border:1px solid #242424; + color:#fff; + min-height:14px; + min-width:14px; + background-color:#464646; + margin-right: 2px; + float: left; +} + /* END Master Panel */ diff --git a/airtime_mvc/public/js/airtime/dashboard/playlist.js b/airtime_mvc/public/js/airtime/dashboard/playlist.js index 0c0e2f4c6..676cc3c03 100644 --- a/airtime_mvc/public/js/airtime/dashboard/playlist.js +++ b/airtime_mvc/public/js/airtime/dashboard/playlist.js @@ -74,14 +74,19 @@ function updateProgressBarValue(){ songPercentDone = 0; currentSong = null; } else { - if (currentSong.media_item_played == "t" && currentShow.length > 0) + if (currentSong.media_item_played == "t" && currentShow.length > 0){ $('#on-air-info').attr("class", "on-air-info on"); - else + $("#airtime_connection").attr("class", "source-connection on"); + } + else{ $('#on-air-info').attr("class", "on-air-info off"); + $("#airtime_connection").attr("class", "source-connection off"); + } $('#progress-show').attr("class", "progress-show"); } } else { $('#on-air-info').attr("class", "on-air-info off"); + $("#airtime_connection").attr("class", "source-connection off"); $('#progress-show').attr("class", "progress-show-error"); } $('#progress-bar').attr("style", "width:"+songPercentDone+"%"); @@ -218,10 +223,24 @@ function parseItems(obj){ localRemoteTimeOffset = date.getTime() - schedulePosixTime; } +function parseSourceStatus(obj){ + if(obj.live_dj_source == false){ + $("#live_dj_connection").attr("class", "source-connection off"); + }else{ + $("#live_dj_connection").attr("class", "source-connection on"); + } + + if(obj.master_dj_source == false){ + $("#master_dj_connection").attr("class", "source-connection off"); + }else{ + $("#master_dj_connection").attr("class", "source-connection on"); + } +} function getScheduleFromServer(){ $.ajax({ url: "/Schedule/get-current-playlist/format/json", dataType:"json", success:function(data){ parseItems(data.entries); + parseSourceStatus(data.source_status); }, error:function(jqXHR, textStatus, errorThrown){}}); setTimeout(getScheduleFromServer, serverUpdateInterval); } @@ -251,6 +270,30 @@ function setupQtip(){ } } +function setSwitchListener(){ + $(".source-switch-button").click(function(){ + var sourcename = $(this).attr('id') + var status_span = $(this).find("span") + var status = status_span.html() + var _class = $(this).parent().find("div.source-connection").attr("class") + var source_connection_status = false + + if(_class.indexOf("off") > 0){ + source_connection_status = false + }else{ + source_connection_status = true + } + + if(source_connection_status){ + $.get("/Dashboard/switch-source/format/json/sourcename/"+sourcename+"/status/"+status, function(data){ + status_span.html(data.status) + }); + }else{ + alert("The source is not connected to Airtime!") + } + }) +} + var stream_window = null; function init() { @@ -262,6 +305,8 @@ function init() { setupQtip(); + setSwitchListener(); + $('.listen-control-button').click(function() { if (stream_window == null || stream_window.closed) stream_window=window.open(baseUrl+"Dashboard/stream-player", 'name', 'width=400,height=178'); diff --git a/python_apps/api_clients/api_client.cfg b/python_apps/api_clients/api_client.cfg index e02dc3cac..4aab5816b 100644 --- a/python_apps/api_clients/api_client.cfg +++ b/python_apps/api_clients/api_client.cfg @@ -104,3 +104,6 @@ update_liquidsoap_status = 'update-liquidsoap-status/format/json/api_key/%%api_k #URL to check live stream auth check_live_stream_auth = 'check-live-stream-auth/format/json/api_key/%%api_key%%/username/%%username%%/password/%%password%%/djtype/%%djtype%%' +#URL to update source status +update_source_status = 'update-source-status/format/json/api_key/%%api_key%%/sourcename/%%sourcename%%/status/%%status%%' + diff --git a/python_apps/api_clients/api_client.py b/python_apps/api_clients/api_client.py index 2faeaec97..5dda980b5 100755 --- a/python_apps/api_clients/api_client.py +++ b/python_apps/api_clients/api_client.py @@ -583,6 +583,20 @@ class AirTimeApiClient(ApiClientInterface): response = urllib2.urlopen(req).read() except Exception, e: logger.error("Exception: %s", e) + + def notify_source_status(self, sourcename, status): + logger = self.logger + try: + url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["update_source_status"]) + + url = url.replace("%%api_key%%", self.config["api_key"]) + url = url.replace("%%sourcename%%", sourcename) + url = url.replace("%%status%%", status) + + req = urllib2.Request(url) + response = urllib2.urlopen(req).read() + except Exception, e: + logger.error("Exception: %s", e) """ This function updates status of mounted file system information on airtime diff --git a/python_apps/pypo/liquidsoap_scripts/ls_lib.liq b/python_apps/pypo/liquidsoap_scripts/ls_lib.liq index 74c289f84..ea4455028 100644 --- a/python_apps/pypo/liquidsoap_scripts/ls_lib.liq +++ b/python_apps/pypo/liquidsoap_scripts/ls_lib.liq @@ -15,6 +15,31 @@ def append_title(m) = end end +default_dj_fade_in = ref 5. +default_dj_fade_out = ref 5. + +def transition(a,b) = + log("transition called...") + add(normalize=false, + [ sequence([ blank(duration=2.), + fade.initial(duration=!default_dj_fade_in, b) ]), + fade.final(duration=!default_dj_fade_out, a) ]) +end + +def transition_to_live(a,b) = + log("transition called...") + #add(normalize=false, + # [fade.initial(duration=5.,type="log", b),fade.final(duration=5.,type="log",a)]) + smooth_add(delay=10., normal=a, special=b) +end + +def transition_from_live(a,b) = + log("transition called...") + #add(normalize=false, + # [fade.initial(duration=5.,type="log", b),fade.final(duration=5.,type="log",a)]) + smooth_add(delay=10., normal=b, special=a) +end + def crossfade(s) #duration is automatically overwritten by metadata fields passed in #with audio diff --git a/python_apps/pypo/liquidsoap_scripts/ls_script.liq b/python_apps/pypo/liquidsoap_scripts/ls_script.liq index 3774db0b1..5fd7a4864 100644 --- a/python_apps/pypo/liquidsoap_scripts/ls_script.liq +++ b/python_apps/pypo/liquidsoap_scripts/ls_script.liq @@ -8,7 +8,7 @@ set("server.telnet.port", 1234) time = ref string_of(gettimeofday()) -queue = audio_to_stereo(request.queue(id="queue", length=0.5)) +queue = audio_to_stereo(id="queue_src", request.queue(id="queue", length=0.5)) queue = cue_cut(queue) pypo_data = ref '0' @@ -26,6 +26,10 @@ s3_namespace = ref '' %include "ls_lib.liq" +queue = on_metadata(notify, queue) +queue = map_metadata(append_title, queue) +ignore(output.dummy(queue, fallible=true)) + server.register(namespace="vars", "pypo_data", fun (s) -> begin pypo_data := s "Done" end) server.register(namespace="vars", "web_stream_enabled", fun (s) -> begin web_stream_enabled := (s == "true") string_of(!web_stream_enabled) end) server.register(namespace="vars", "stream_metadata_type", fun (s) -> begin stream_metadata_type := int_of_string(s) s end) @@ -35,8 +39,9 @@ server.register(namespace="vars", "bootup_time", fun (s) -> begin time := s s en server.register(namespace="streams", "connection_status", fun (s) -> begin "1:#{!s1_connected},2:#{!s2_connected},3:#{!s3_connected}" end) -default = amplify(0.00001, noise()) +default = amplify(id="silence_src", 0.00001, noise()) default = rewrite_metadata([("artist","Airtime"), ("title", "offline")],default) +ignore(output.dummy(default, fallible=true)) master_dj_enabled = ref false; live_dj_enabled = ref false; @@ -87,33 +92,53 @@ def check_dj_client(user,password) = end end -def append_master_dj_input(master_harbor_input_port, master_harbor_input_mount_point, s) = - if master_harbor_input_port != 0 and master_harbor_input_mount_point != "" then - master_dj = input.harbor(master_harbor_input_mount_point, port=master_harbor_input_port, auth=check_master_dj_client, buffer=0.5,max=15.) +def update_source_status(sourcename, status) = + system("/usr/lib/airtime/pypo/bin/liquidsoap_scripts/notify.sh --source-name=#{sourcename} --source-status=#{status}") + log("/usr/lib/airtime/pypo/bin/liquidsoap_scripts/notify.sh --source-name=#{sourcename} --source-status=#{status}") +end + +def live_dj_connect(header) = + update_source_status("live_dj", true) +end + +def live_dj_disconnect() = + update_source_status("live_dj", false) +end + +def master_dj_connect(header) = + update_source_status("master_dj", true) +end + +def master_dj_disconnect() = + update_source_status("master_dj", false) +end + +def append_dj_inputs(master_harbor_input_port, master_harbor_input_mount_point, dj_harbor_input_port, dj_harbor_input_mount_point, s) = + if master_harbor_input_port != 0 and master_harbor_input_mount_point != "" and dj_harbor_input_port != 0 and dj_harbor_input_mount_point != "" then + master_dj = input.harbor(id="master_harbor", master_harbor_input_mount_point, port=master_harbor_input_port, auth=check_master_dj_client, + max=40., on_connect=master_dj_connect, on_disconnect=master_dj_disconnect) + dj_live = input.harbor(id="live_dj_harbor", dj_harbor_input_mount_point, port=dj_harbor_input_port, auth=check_dj_client, + max=40., on_connect=live_dj_connect, on_disconnect=live_dj_disconnect) ignore(output.dummy(master_dj, fallible=true)) - stopable_master_dj = switch(track_sensitive=false, [({!master_dj_enabled},master_dj)]) - fallback(track_sensitive=false, [stopable_master_dj, s]) - else - s - end -end - -def append_dj_input(dj_harbor_input_port, dj_harbor_input_mount_point, s) = - if dj_harbor_input_port != 0 and dj_harbor_input_mount_point != "" then - dj_live = input.harbor(dj_harbor_input_mount_point, port=dj_harbor_input_port, auth=check_dj_client, buffer=0.5,max=15.) ignore(output.dummy(dj_live, fallible=true)) - stopable_live_dj = switch(track_sensitive=false, [({!live_dj_enabled},dj_live)]) - fallback(track_sensitive=false, [stopable_live_dj, s]) + switch(id="master_dj_switch", track_sensitive=false, transitions=[transition, transition, transition], [({!master_dj_enabled},master_dj), ({!live_dj_enabled},dj_live), ({true}, s)]) + elsif master_harbor_input_port != 0 and master_harbor_input_mount_point != "" then + master_dj = input.harbor(id="master_harbor", master_harbor_input_mount_point, port=master_harbor_input_port, auth=check_master_dj_client, + max=40., on_connect=master_dj_connect, on_disconnect=master_dj_disconnect) + ignore(output.dummy(master_dj, fallible=true)) + switch(id="master_dj_switch", track_sensitive=false, transitions=[transition, transition], [({!master_dj_enabled},master_dj), ({true}, s)]) + elsif dj_harbor_input_port != 0 and dj_harbor_input_mount_point != "" then + dj_live = input.harbor(id="live_dj_harbor", dj_harbor_input_mount_point, port=dj_harbor_input_port, auth=check_dj_client, + max=40., on_connect=live_dj_connect, on_disconnect=live_dj_disconnect) + ignore(output.dummy(dj_live, fallible=true)) + switch(id="live_dj_switch", track_sensitive=false, transitions=[transition, transition], [({!live_dj_enabled},dj_live), ({true}, s)]) else s end end -s = fallback(track_sensitive=false, [queue, default]) -s = on_metadata(notify, s) -s = map_metadata(append_title, s) -s = append_dj_input(dj_live_stream_port, dj_live_stream_mp, s) -s = append_master_dj_input(master_live_stream_port, master_live_stream_mp, s) +s = fallback(id="default_fallback", track_sensitive=false, [queue, default]) +s = append_dj_inputs(master_live_stream_port, master_live_stream_mp, dj_live_stream_port, dj_live_stream_mp, s) s = crossfade(s) diff --git a/python_apps/pypo/pypo-notify.py b/python_apps/pypo/pypo-notify.py index 5139a4aad..0df1abab5 100644 --- a/python_apps/pypo/pypo-notify.py +++ b/python_apps/pypo/pypo-notify.py @@ -51,6 +51,8 @@ parser.add_option("-e", "--error", action="store", dest="error", type="string", parser.add_option("-s", "--stream-id", help="ID stream", metavar="stream_id") parser.add_option("-c", "--connect", help="liquidsoap connected", action="store_true", metavar="connect") parser.add_option("-t", "--time", help="liquidsoap boot up time", action="store", dest="time", metavar="time", type="string") +parser.add_option("-x", "--source-name", help="source connection name", metavar="source_name") +parser.add_option("-y", "--source-status", help="source connection stauts", metavar="source_status") # parse options (options, args) = parser.parse_args() @@ -91,6 +93,16 @@ class Notify: logger.debug('msg = '+ str(msg)) response = self.api_client.notify_liquidsoap_status(msg, stream_id, time) logger.debug("Response: "+json.dumps(response)) + + def notify_source_status(self, source_name, status): + logger = logging.getLogger() + + logger.debug('#################################################') + logger.debug('# Calling server to update source status #') + logger.debug('#################################################') + logger.debug('msg = '+ str(source_name) + ' : ' + str(status)) + response = self.api_client.notify_source_status(source_name, status) + logger.debug("Response: "+json.dumps(response)) if __name__ == '__main__': print @@ -101,7 +113,6 @@ if __name__ == '__main__': # initialize logger = logging.getLogger("notify") - if options.error and options.stream_id: try: n = Notify() @@ -114,6 +125,12 @@ if __name__ == '__main__': n.notify_liquidsoap_status("OK", options.stream_id, options.time) except Exception, e: print e + elif options.source_name and options.source_status: + try: + n = Notify() + n.notify_source_status(options.source_name, options.source_status) + except Exception, e: + print e else: if not options.data: print "NOTICE: 'data' command-line argument not given." diff --git a/python_apps/pypo/pypofetch.py b/python_apps/pypo/pypofetch.py index d216611b0..7ec43a512 100644 --- a/python_apps/pypo/pypofetch.py +++ b/python_apps/pypo/pypofetch.py @@ -92,6 +92,9 @@ class PypoFetch(Thread): elif command == 'cancel_current_show': self.logger.info("Cancel current show command received...") self.stop_current_show() + elif command == 'switch_source': + self.logger.info("switch_on_source show command received...") + self.switch_source(m['sourcename'], m['status']) except Exception, e: import traceback top = traceback.format_exc() @@ -99,6 +102,27 @@ class PypoFetch(Thread): self.logger.error("traceback: %s", top) self.logger.error("Exception in handling Message Handler message: %s", e) + def switch_source(self, sourcename, status): + self.logger.debug('Switching source: %s to "%s" status', sourcename, status) + command = "streams." + if(sourcename == "master_dj"): + command += "master_dj_" + else: + command += "live_dj_" + + if(status == "on"): + command += "start\n" + else: + command += "stop\n" + + try: + tn = telnetlib.Telnet(LS_HOST, LS_PORT) + tn.write(command) + tn.write('exit\n') + tn.read_all() + except Exception, e: + self.logger.debug(e) + self.logger.debug('Could not connect to liquidsoap') def stop_current_show(self): self.logger.debug('Notifying Liquidsoap to stop playback.') @@ -353,15 +377,22 @@ class PypoFetch(Thread): def create_liquidsoap_annotation(self, media): - entry = \ + """entry = \ 'annotate:media_id="%s",liq_start_next="%s",liq_fade_in="%s",liq_fade_out="%s",liq_cue_in="%s",liq_cue_out="%s",schedule_table_id="%s":%s' \ % (media['id'], 0, \ float(media['fade_in']) / 1000, \ float(media['fade_out']) / 1000, \ float(media['cue_in']), \ float(media['cue_out']), \ + media['row_id'], media['dst'])""" + + entry = \ + 'annotate:media_id="%s",liq_start_next="%s",liq_cue_in="%s",liq_cue_out="%s",schedule_table_id="%s":%s' \ + % (media['id'], 0, \ + float(media['cue_in']), \ + float(media['cue_out']), \ media['row_id'], media['dst']) - + return entry def check_for_previous_crash(self, media_item): diff --git a/python_apps/pypo/pypomessagehandler.py b/python_apps/pypo/pypomessagehandler.py index 75b0407ea..db82f358c 100644 --- a/python_apps/pypo/pypomessagehandler.py +++ b/python_apps/pypo/pypomessagehandler.py @@ -74,6 +74,9 @@ class PypoMessageHandler(Thread): elif command == 'cancel_current_show': self.logger.info("Cancel current show command received...") self.pypo_queue.put(message) + elif command == 'switch_source': + self.logger.info("switch_source command received...") + self.pypo_queue.put(message) elif command == 'update_recorder_schedule': self.recorder_queue.put(message) elif command == 'cancel_recording':