Merge branch 'devel' of dev.sourcefabric.org:airtime into devel

Conflicts:
	airtime_mvc/public/js/airtime/showbuilder/builder.js
This commit is contained in:
Daniel 2012-03-15 18:12:15 -04:00
commit 5b953443c6
63 changed files with 2816 additions and 781 deletions

View file

@ -28,6 +28,9 @@ class ApiController extends Zend_Controller_Action
->addActionContext('update-file-system-mount', 'json')
->addActionContext('handle-watched-dir-missing', 'json')
->addActionContext('rabbitmq-do-push', 'json')
->addActionContext('check-live-stream-auth', 'json')
->addActionContext('update-source-status', 'json')
->addActionContext('get-switch-status', 'json')
->initContext();
}
@ -804,8 +807,9 @@ class ApiController extends Zend_Controller_Action
print 'You are not allowed to access this resource.';
exit;
}
$this->view->msg = Application_Model_StreamSetting::getStreamSetting();
$info = Application_Model_StreamSetting::getStreamSetting();
$this->view->msg = $info;
}
public function statusAction() {
@ -860,6 +864,22 @@ 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');
// on source disconnection sent msg to pypo to turn off the switch
if($status == "false"){
$data = array("sourcename"=>$sourcename, "status"=>"off");
Application_Model_RabbitMq::SendMessageToPypo("switch_source", $data);
Application_Model_Preference::SetSourceSwitchStatus($sourcename, "off");
}
Application_Model_Preference::SetSourceStatus($sourcename, $status);
}
// handles addition/deletion of mount point which watched dirs reside
public function updateFileSystemMountAction(){
@ -958,7 +978,6 @@ class ApiController extends Zend_Controller_Action
Application_Model_MusicDir::removeWatchedDir($dir, false);
}
/* This action is for use by our dev scripts, that make
* a change to the database and we want rabbitmq to send
* out a message to pypo that a potential change has been made. */
@ -973,10 +992,87 @@ class ApiController extends Zend_Controller_Action
print 'You are not allowed to access this resource.';
exit;
}
Logging::log("Notifying RabbitMQ to send message to pypo");
Application_Model_RabbitMq::PushSchedule();
}
public function getSwitchStatusAction(){
$live_dj = Application_Model_Preference::GetSourceSwitchStatus('live_dj');
$master_dj = Application_Model_Preference::GetSourceSwitchStatus('master_dj');
$scheduled_play = Application_Model_Preference::GetSourceSwitchStatus('scheduled_play');
$res = array("live_dj"=>$live_dj, "master_dj"=>$master_dj, "scheduled_play"=>$scheduled_play);
$this->view->status = $res;
}
/* This is used but Liquidsoap to check authentication of live streams*/
public function checkLiveStreamAuthAction(){
global $CC_CONFIG;
$request = $this->getRequest();
$api_key = $request->getParam('api_key');
$username = $request->getParam('username');
$password = $request->getParam('password');
$djtype = $request->getParam('djtype');
if (!in_array($api_key, $CC_CONFIG["apiKey"]))
{
header('HTTP/1.0 401 Unauthorized');
print 'You are not allowed to access this resource.';
exit;
}
if($djtype == 'master'){
//check against master
if($username == Application_Model_Preference::GetLiveSteamMasterUsername() && $password == Application_Model_Preference::GetLiveSteamMasterPassword()){
$this->view->msg = true;
}else{
$this->view->msg = false;
}
}elseif($djtype == "dj"){
//check against show dj auth
$showInfo = Application_Model_Show::GetCurrentShow();
// there is current playing show
if(isset($showInfo[0]['id'])){
$current_show_id = $showInfo[0]['id'];
$CcShow = CcShowQuery::create()->findPK($current_show_id);
// get custom pass info from the show
$custom_user = $CcShow->getDbLiveStreamUser();
$custom_pass = $CcShow->getDbLiveStreamPass();
// get hosts ids
$show = new Application_Model_Show($current_show_id);
$hosts_ids = $show->getHostsIds();
// check against hosts auth
if($CcShow->getDbLiveStreamUsingAirtimeAuth()){
foreach( $hosts_ids as $host){
$h = new Application_Model_User($host['subjs_id']);
if($username == $h->getLogin() && md5($password) == $h->getPassword()){
$this->view->msg = true;
return;
}
}
}
// check against custom auth
if($CcShow->getDbLiveStreamUsingCustomAuth()){
if($username == $custom_user && $password == $custom_pass){
$this->view->msg = true;
}else{
$this->view->msg = false;
}
}
else{
$this->view->msg = false;
}
}else{
// no show is currently playing
$this->view->msg = false;
}
}
}
}

View file

@ -5,14 +5,86 @@ class DashboardController extends Zend_Controller_Action
public function init()
{
$ajaxContext = $this->_helper->getHelper('AjaxContext');
$ajaxContext->addActionContext('switch-source', 'json')
->addActionContext('disconnect-source', 'json')
->initContext();
}
public function indexAction()
{
// action body
}
public function disconnectSourceAction(){
$request = $this->getRequest();
$sourcename = $request->getParam('sourcename');
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
$user = new Application_Model_User($userInfo->id);
$show = Application_Model_Show::GetCurrentShow();
$show_id = isset($show['id'])?$show['id']:0;
$source_connected = Application_Model_Preference::GetSourceStatus($sourcename);
if($user->canSchedule($show_id) && $source_connected){
$data = array("sourcename"=>$sourcename);
Application_Model_RabbitMq::SendMessageToPypo("disconnect_source", $data);
}else{
if($source_connected){
$this->view->error = "You don't have permission to disconnect source.";
}else{
$this->view->error = "There is no source connected to this input.";
}
}
}
public function switchSourceAction(){
$request = $this->getRequest();
$sourcename = $this->_getParam('sourcename');
$current_status = $this->_getParam('status');
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
$user = new Application_Model_User($userInfo->id);
$show = Application_Model_Show::GetCurrentShow();
$show_id = isset($show['id'])?$show['id']:0;
$source_connected = Application_Model_Preference::GetSourceStatus($sourcename);
if($user->canSchedule($show_id) && ($source_connected || $sourcename == 'scheduled_play')){
$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";
}
}
else{
if($source_connected){
$this->view->error = "You don't have permission to switch source.";
}else{
$this->view->error = "There is no source connected to this input.";
}
}
}
public function switchOffSource(){
}
public function streamPlayerAction()
{
global $CC_CONFIG;

View file

@ -10,7 +10,7 @@ class IndexController extends Zend_Controller_Action
public function indexAction()
{
$this->_forward('index', 'login');
$this->_forward('index', 'showbuilder');
}
public function mainAction()

View file

@ -73,8 +73,6 @@ class LibraryController extends Zend_Controller_Action
public function contextMenuAction()
{
global $CC_CONFIG;
$id = $this->_getParam('id');
$type = $this->_getParam('type');
//playlist||timeline

View file

@ -14,6 +14,7 @@ class PreferenceController extends Zend_Controller_Action
->addActionContext('is-import-in-progress', 'json')
->addActionContext('change-stream-setting', 'json')
->addActionContext('get-liquidsoap-status', 'json')
->addActionContext('set-source-connection-url', 'json')
->initContext();
}
@ -47,7 +48,6 @@ class PreferenceController extends Zend_Controller_Action
Application_Model_Preference::SetSoundCloudTags($values["preferences_soundcloud"]["SoundCloudTags"]);
Application_Model_Preference::SetSoundCloudGenre($values["preferences_soundcloud"]["SoundCloudGenre"]);
Application_Model_Preference::SetSoundCloudTrackType($values["preferences_soundcloud"]["SoundCloudTrackType"]);
Application_Model_Preference::SetSoundCloudLicense($values["preferences_soundcloud"]["SoundCloudLicense"]);
$this->view->statusMsg = "<div class='success'>Preferences updated.</div>";
@ -176,6 +176,9 @@ class PreferenceController extends Zend_Controller_Action
$form->setSetting($setting);
$form->startFrom();
$live_stream_subform = new Application_Form_LiveStreamingPreferences();
$form->addSubForm($live_stream_subform, "live_stream_subform");
for($i=1; $i<=$num_of_stream; $i++){
$subform = new Application_Form_StreamSettingSubForm();
@ -190,17 +193,8 @@ class PreferenceController extends Zend_Controller_Action
$post_data = $request->getPost();
$error = false;
$values = array();
for($i=1; $i<=$num_of_stream; $i++){
if(!$form->getSubForm("s".$i."_subform")->isValid($post_data["s".$i."_data"])){
$error = true;
}else{
// getValues returne array of size 1, so reorganized it
foreach($form->getSubForm("s".$i."_subform")->getValues() as $key => $d){
$values[$key] = $d;
}
}
}
$values = $post_data;
if($form->isValid($post_data)){
if(Application_Model_Preference::GetPlanLevel() == 'disabled'){
$values['output_sound_device'] = $form->getValue('output_sound_device');
@ -211,18 +205,29 @@ class PreferenceController extends Zend_Controller_Action
$values['output_sound_device_type'] = $form->getValue('output_sound_device_type');
$values['streamFormat'] = $form->getValue('streamFormat');
}
if(!$error){
Application_Model_StreamSetting::setStreamSetting($values);
// this goes into cc_pref table
Application_Model_Preference::SetStreamLabelFormat($values['streamFormat']);
Application_Model_Preference::SetLiveSteamMasterUsername($values["master_username"]);
Application_Model_Preference::SetLiveSteamMasterPassword($values["master_password"]);
// extra info that goes into cc_stream_setting
Application_Model_StreamSetting::SetMasterLiveSteamPort($values["master_harbor_input_port"]);
Application_Model_StreamSetting::SetMasterLiveSteamMountPoint($values["master_harbor_input_mount_point"]);
Application_Model_StreamSetting::SetDJLiveSteamPort($values["dj_harbor_input_port"]);
Application_Model_StreamSetting::SetDJLiveSteamMountPoint($values["dj_harbor_input_mount_point"]);
// store stream update timestamp
Application_Model_Preference::SetStreamUpdateTimestamp();
$data = array();
$data['setting'] = Application_Model_StreamSetting::getStreamSetting();
$info = Application_Model_StreamSetting::getStreamSetting();
$data['setting'] = $info;
for($i=1;$i<=$num_of_stream;$i++){
Application_Model_StreamSetting::setLiquidsoapError($i, "waiting");
}
// this goes into cc_pref table
Application_Model_Preference::SetStreamLabelFormat($values['streamFormat']);
// store stream update timestamp
Application_Model_Preference::SetStreamUpdateTimestamp();
Application_Model_RabbitMq::SendMessageToPypo("update_stream_setting", $data);
$this->view->statusMsg = "<div class='success'>Stream Setting Updated.</div>";
}
@ -331,6 +336,19 @@ class PreferenceController extends Zend_Controller_Action
}
die(json_encode($out));
}
public function setSourceConnectionUrlAction(){
$request = $this->getRequest();
$type = $request->getParam("type", null);
$url = urldecode($request->getParam("url", null));
if($type == 'masterdj'){
Application_Model_Preference::SetMasterDJSourceConnectionURL($url);
}elseif($type == 'livedj'){
Application_Model_Preference::SetLiveDJSourceConnectionURL($url);
}
die();
}
}

View file

@ -321,8 +321,28 @@ 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();
$switch_status = array();
$live_dj = Application_Model_Preference::GetSourceStatus("live_dj");
$master_dj = Application_Model_Preference::GetSourceStatus("master_dj");
$scheduled_play_switch = Application_Model_Preference::GetSourceSwitchStatus("scheduled_play");
$live_dj_switch = Application_Model_Preference::GetSourceSwitchStatus("live_dj");
$master_dj_switch = Application_Model_Preference::GetSourceSwitchStatus("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;
$switch_status['live_dj_source'] = $live_dj_switch;
$switch_status['master_dj_source'] = $master_dj_switch;
$switch_status['scheduled_play'] = $scheduled_play_switch;
$this->view->switch_status = $switch_status;
$this->view->entries = $range;
}
public function removeGroupAction()
@ -411,6 +431,7 @@ class ScheduleController extends Zend_Controller_Action
$formWhen = new Application_Form_AddShowWhen();
$formRepeats = new Application_Form_AddShowRepeats();
$formStyle = new Application_Form_AddShowStyle();
$formLive = new Application_Form_AddShowLiveStream();
$formWhat->removeDecorator('DtDdWrapper');
$formWho->removeDecorator('DtDdWrapper');
@ -423,6 +444,7 @@ class ScheduleController extends Zend_Controller_Action
$this->view->repeats = $formRepeats;
$this->view->who = $formWho;
$this->view->style = $formStyle;
$this->view->live = $formLive;
$this->view->addNewShow = false;
$show = new Application_Model_Show($showInstance->getShowId());
@ -476,6 +498,8 @@ class ScheduleController extends Zend_Controller_Action
$formWho->populate(array('add_show_hosts' => $hosts));
$formStyle->populate(array('add_show_background_color' => $show->getBackgroundColor(),
'add_show_color' => $show->getColor()));
$formLive->populate($show->getLiveStreamInfo());
if(!$isSaas){
$formRecord = new Application_Form_AddShowRR();
@ -564,12 +588,14 @@ class ScheduleController extends Zend_Controller_Action
$formWhen = new Application_Form_AddShowWhen();
$formRepeats = new Application_Form_AddShowRepeats();
$formStyle = new Application_Form_AddShowStyle();
$formLive = new Application_Form_AddShowLiveStream();
$formWhat->removeDecorator('DtDdWrapper');
$formWho->removeDecorator('DtDdWrapper');
$formWhen->removeDecorator('DtDdWrapper');
$formRepeats->removeDecorator('DtDdWrapper');
$formStyle->removeDecorator('DtDdWrapper');
$formLive->removeDecorator('DtDdWrapper');
$what = $formWhat->isValid($data);
$when = $formWhen->isValid($data);
@ -686,6 +712,7 @@ class ScheduleController extends Zend_Controller_Action
$this->view->rr = $formRecord;
$this->view->absoluteRebroadcast = $formAbsoluteRebroadcast;
$this->view->rebroadcast = $formRebroadcast;
$this->view->live = $formLive;
$this->view->addNewShow = true;
//the form still needs to be "update" since
@ -719,6 +746,8 @@ class ScheduleController extends Zend_Controller_Action
$this->view->repeats = $formRepeats;
$this->view->who = $formWho;
$this->view->style = $formStyle;
$this->view->live = $formLive;
if(!$isSaas){
$this->view->rr = $formRecord;
$this->view->absoluteRebroadcast = $formAbsoluteRebroadcast;

View file

@ -12,6 +12,7 @@ class ShowbuilderController extends Zend_Controller_Action
->addActionContext('builder-dialog', 'json')
->addActionContext('check-builder-feed', 'json')
->addActionContext('builder-feed', 'json')
->addActionContext('context-menu', 'json')
->initContext();
}
@ -94,6 +95,28 @@ class ShowbuilderController extends Zend_Controller_Action
$this->_helper->actionStack('library', 'library');
$this->_helper->actionStack('builder', 'showbuilder');
}
public function contextMenuAction()
{
$id = $this->_getParam('id');
$now = time();
$request = $this->getRequest();
$baseUrl = $request->getBaseUrl();
$menu = array();
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
$user = new Application_Model_User($userInfo->id);
$item = CcScheduleQuery::create()->findPK($id);
$instance = $item->getCcShowInstances();
if ($now < intval($item->getDbStarts("U")) && $user->canSchedule($instance->getDbShowId())) {
$menu["del"] = array("name"=> "Delete", "icon" => "delete", "url" => "/showbuilder/schedule-remove");
}
$this->view->items = $menu;
}
public function builderAction() {

View file

@ -0,0 +1,54 @@
<?php
require_once 'customvalidators/ConditionalNotEmpty.php';
class Application_Form_AddShowLiveStream extends Zend_Form_SubForm
{
public function init()
{
$description1 = "This follows the same security pattern for the shows: if no users are explicitly set for the show, then anyone with a valid airtime login can connect to the stream, otherwise if there are users assigned to the show, then only those users can connect.";
$cb_airtime_auth = new Zend_Form_Element_Checkbox("cb_airtime_auth");
$cb_airtime_auth->setLabel("Connect using Airtime username & password")
->setDescription($description1)
->setRequired(false)
->setDecorators(array('ViewHelper'));
$this->addElement($cb_airtime_auth);
$description2 = "Specifiy custom athentification which will work for only the show.";
$cb_custom_auth = new Zend_Form_Element_Checkbox("cb_custom_auth");
$cb_custom_auth ->setLabel("Custom")
->setDescription($description2)
->setRequired(false)
->setDecorators(array('ViewHelper'));
$this->addElement($cb_custom_auth);
//custom username
$custom_username = new Zend_Form_Element_Text('custom_username');
$custom_username->setAttrib('class', 'input_text')
->setAttrib('autocomplete', 'off')
->setAllowEmpty(true)
->setLabel('Custom Username')
->setFilters(array('StringTrim'))
->setValidators(array(
new ConditionalNotEmpty(array("cb_custom_auth"=>"1"))))
->setDecorators(array('ViewHelper'));
$this->addElement($custom_username);
//custom password
$custom_password = new Zend_Form_Element_Password('custom_password');
$custom_password->setAttrib('class', 'input_text')
->setAttrib('autocomplete', 'off')
->setAttrib('renderPassword','true')
->setAllowEmpty(true)
->setLabel('Custom Password')
->setFilters(array('StringTrim'))
->setValidators(array(
new ConditionalNotEmpty(array("cb_custom_auth"=>"1"))))
->setDecorators(array('ViewHelper'));
$this->addElement($custom_password);
$this->setDecorators(array(
array('ViewScript', array('viewScript' => 'form/add-show-live-stream.phtml', "connection_url"=>Application_Model_Preference::GetLiveDJSourceConnectionURL()))
));
}
}

View file

@ -0,0 +1,77 @@
<?php
class Application_Form_LiveStreamingPreferences extends Zend_Form_SubForm
{
public function init()
{
//Master username
$master_username = new Zend_Form_Element_Text('master_username');
$master_username->setAttrib('autocomplete', 'off')
->setAllowEmpty(true)
->setLabel('Master Username')
->setFilters(array('StringTrim'))
->setValue(Application_Model_Preference::GetLiveSteamMasterUsername())
->setDecorators(array('ViewHelper'));
$this->addElement($master_username);
//Master password
$master_password = new Zend_Form_Element_Password('master_password');
$master_password->setAttrib('autocomplete', 'off')
->setAttrib('renderPassword','true')
->setAllowEmpty(true)
->setValue(Application_Model_Preference::GetLiveSteamMasterPassword())
->setLabel('Master Password')
->setFilters(array('StringTrim'))
->setDecorators(array('ViewHelper'));
$this->addElement($master_password);
//liquidsoap harbor.input port
$m_port = Application_Model_StreamSetting::GetMasterLiveSteamPort();
$master_dj_port = new Zend_Form_Element_Text('master_harbor_input_port');
$master_dj_port->setLabel("Master DJ Port")
->setValue($m_port)
->setValidators(array(new Zend_Validate_Between(array('min'=>0, 'max'=>99999))))
->addValidator('regex', false, array('pattern'=>'/^[0-9]+$/', 'messages'=>array('regexNotMatch'=>'Only numbers are allowed.')))
->setDecorators(array('ViewHelper'));
$this->addElement($master_dj_port);
$m_mount = Application_Model_StreamSetting::GetMasterLiveSteamMountPoint();
$master_dj_mount = new Zend_Form_Element_Text('master_harbor_input_mount_point');
$master_dj_mount->setLabel("Master DJ Mount Point")
->setValue($m_mount)
->setValidators(array(
array('regex', false, array('/^[^ &<>]+$/', 'messages' => 'Invalid character entered'))))
->setDecorators(array('ViewHelper'));
$this->addElement($master_dj_mount);
//liquidsoap harbor.input port
$l_port = Application_Model_StreamSetting::GetDJLiveSteamPort();
$live_dj_port = new Zend_Form_Element_Text('dj_harbor_input_port');
$live_dj_port->setLabel("DJ Port")
->setValue($l_port)
->setValidators(array(new Zend_Validate_Between(array('min'=>0, 'max'=>99999))))
->addValidator('regex', false, array('pattern'=>'/^[0-9]+$/', 'messages'=>array('regexNotMatch'=>'Only numbers are allowed.')))
->setDecorators(array('ViewHelper'));
$this->addElement($live_dj_port);
$l_mount = Application_Model_StreamSetting::GetDJLiveSteamMountPoint();
$live_dj_mount = new Zend_Form_Element_Text('dj_harbor_input_mount_point');
$live_dj_mount->setLabel("DJ Mount Point")
->setValue($l_mount)
->setValidators(array(
array('regex', false, array('/^[^ &<>]+$/', 'messages' => 'Invalid character entered'))))
->setDecorators(array('ViewHelper'));
$this->addElement($live_dj_mount);
$master_dj_connection_url = Application_Model_Preference::GetMasterDJSourceConnectionURL();
$live_dj_connection_url = Application_Model_Preference::GetLiveDJSourceConnectionURL();
$master_dj_connection_url = ($master_dj_connection_url == "")?("http://".$_SERVER['SERVER_NAME'].":".$m_port."/".$m_mount):$master_dj_connection_url;
$live_dj_connection_url = ($live_dj_connection_url == "")?"http://".$_SERVER['SERVER_NAME'].":".$l_port."/".$l_mount:$live_dj_connection_url;
$this->setDecorators(array(
array('ViewScript', array('viewScript' => 'form/preferences_livestream.phtml', 'master_dj_connection_url'=>$master_dj_connection_url, 'live_dj_connection_url'=>$live_dj_connection_url,))
));
}
}

View file

@ -14,12 +14,12 @@ class Application_Form_Preferences extends Zend_Form
$general_pref = new Application_Form_GeneralPreferences();
$this->addSubForm($general_pref, 'preferences_general');
$livestream_pref = new Application_Form_LiveStreamingPreferences();
$this->addSubForm($livestream_pref, 'preferences_livestream');
$soundcloud_pref = new Application_Form_SoundcloudPreferences();
$this->addSubForm($soundcloud_pref, 'preferences_soundcloud');
/*$support_pref = new Application_Form_SupportPreferences();
$this->addSubForm($support_pref, 'preferences_support');*/
$this->addElement('submit', 'submit', array(
'class' => 'ui-button ui-state-default right-floated',

View file

@ -80,6 +80,7 @@ class Application_Form_StreamSetting extends Zend_Form
$d["streamFormat"] = $data['streamFormat'];
$this->populate($d);
}
return true;
$isValid = parent::isValid($data);
return $isValid;
}
}

View file

@ -177,20 +177,21 @@ class Application_Form_StreamSettingSubForm extends Zend_Form_SubForm{
}
public function isValid ($data){
$isValid = parent::isValid($data);
if($data['enable'] == 1){
if($data['host'] == ''){
$f_data = $data['s'.$this->prefix."_data"];
$isValid = parent::isValid($f_data);
if($f_data['enable'] == 1){
if($f_data['host'] == ''){
$element = $this->getElement("host");
$element->addError("Server cannot be empty.");
$isValid = false;
}
if($data['port'] == ''){
if($f_data['port'] == ''){
$element = $this->getElement("port");
$element->addError("Port cannot be empty.");
$isValid = false;
}
if($data['output'] == 'icecast'){
if($data['mount'] == ''){
if($f_data['output'] == 'icecast'){
if($f_data['mount'] == ''){
$element = $this->getElement("mount");
$element->addError("Mount cannot be empty with Icecast server.");
$isValid = false;

View file

@ -10,9 +10,14 @@
<div id="Panel">
<div class="logo"></div>
<?php echo $this->versionNotify() ?>
<?php echo $this->partial('partialviews/header.phtml', array("user" => $this->loggedInAs(), "is_trial"=>$this->isTrial(), "trial_remain"=> $this->trialRemaining())) ?>
<?php echo $this->versionNotify();
$sss = $this->SourceSwitchStatus();
$scs = $this->SourceConnectionStatus();
?>
<?php echo $this->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'],
"scheduled_play_switch"=>$sss['scheduled_play'])) ?>
<?php $partial = array('menu.phtml', 'default');
$this->navigation()->menu()->setPartial($partial); ?>

View file

@ -11,9 +11,13 @@
<div id="Panel">
<div class="logo"></div>
<?php echo $this->versionNotify() ?>
<?php echo $this->partial('partialviews/header.phtml', array("user" => $this->loggedInAs(), "is_trial"=>$this->isTrial(), "trial_remain"=> $this->trialRemaining())) ?>
<?php echo $this->versionNotify();
$sss = $this->SourceSwitchStatus();
$scs = $this->SourceConnectionStatus();
?>
<?php echo $this->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'],
"scheduled_play_switch"=>$sss['scheduled_play'])) ?>
<?php $partial = array('menu.phtml', 'default');
$this->navigation()->menu()->setPartial($partial); ?>

View file

@ -11,8 +11,14 @@
<div id="Panel">
<div class="logo"></div>
<?php echo $this->versionNotify() ?>
<?php echo $this->partial('partialviews/header.phtml', array("user" => $this->loggedInAs(), "is_trial"=>$this->isTrial(), "trial_remain"=> $this->trialRemaining())) ?>
<?php echo $this->versionNotify();
$sss = $this->SourceSwitchStatus();
$scs = $this->SourceConnectionStatus();
$isPermissionAllowed = $this->IsPermissionAllowed();
?>
<?php echo $this->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'],
"scheduled_play_switch"=>$sss['scheduled_play'], "isPermissionAllowed"=>$isPermissionAllowed)) ?>
<?php $partial = array('menu.phtml', 'default');
$this->navigation()->menu()->setPartial($partial); ?>

View file

@ -11,8 +11,13 @@
<div id="Panel">
<div class="logo"></div>
<?php echo $this->versionNotify() ?>
<?php echo $this->partial('partialviews/header.phtml', array("user" => $this->loggedInAs(), "is_trial"=>$this->isTrial(), "trial_remain"=> $this->trialRemaining())) ?>
<?php echo $this->versionNotify();
$sss = $this->SourceSwitchStatus();
$scs = $this->SourceConnectionStatus();
?>
<?php echo $this->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'],
"scheduled_play_switch"=>$sss['scheduled_play'])) ?>
<?php $partial = array('menu.phtml', 'default');
$this->navigation()->menu()->setPartial($partial); ?>

View file

@ -60,10 +60,10 @@ class Application_Model_Preference
public static function GetValue($key, $isUserValue = false){
global $CC_CONFIG, $CC_DBC;
//Check if key already exists
$sql = "SELECT COUNT(*) FROM cc_pref"
." WHERE keystr = '$key'";
//For user specific preference, check if id matches as well
if($isUserValue) {
$auth = Zend_Auth::getInstance();
@ -72,7 +72,6 @@ class Application_Model_Preference
$sql .= " AND subjid = '$id'";
}
}
$result = $CC_DBC->GetOne($sql);
if ($result == 0)
@ -700,6 +699,63 @@ class Application_Model_Preference
return $val;
}
public static function SetLiveSteamMasterUsername($value){
self::SetValue("live_stream_master_username", $value, false);
}
public static function GetLiveSteamMasterUsername(){
return self::GetValue("live_stream_master_username");
}
public static function SetLiveSteamMasterPassword($value){
self::SetValue("live_stream_master_password", $value, false);
}
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";
}
}
public static function SetMasterDJSourceConnectionURL($value){
self::SetValue("master_dj_source_connection_url", $value, false);
}
public static function GetMasterDJSourceConnectionURL(){
return self::GetValue("master_dj_source_connection_url");
}
public static function SetLiveDJSourceConnectionURL($value){
self::SetValue("live_dj_source_connection_url", $value, false);
}
public static function GetLiveDJSourceConnectionURL(){
return self::GetValue("live_dj_source_connection_url");
}
/* User specific preferences end */
}

View file

@ -742,22 +742,25 @@ class Application_Model_Schedule {
$isSaas = Application_Model_Preference::GetPlanLevel() == 'disabled'?false:true;
$formWhat = new Application_Form_AddShowWhat();
$formWho = new Application_Form_AddShowWho();
$formWhen = new Application_Form_AddShowWhen();
$formRepeats = new Application_Form_AddShowRepeats();
$formStyle = new Application_Form_AddShowStyle();
$formWho = new Application_Form_AddShowWho();
$formWhen = new Application_Form_AddShowWhen();
$formRepeats = new Application_Form_AddShowRepeats();
$formStyle = new Application_Form_AddShowStyle();
$formLive = new Application_Form_AddShowLiveStream();
$formWhat->removeDecorator('DtDdWrapper');
$formWho->removeDecorator('DtDdWrapper');
$formWhen->removeDecorator('DtDdWrapper');
$formRepeats->removeDecorator('DtDdWrapper');
$formStyle->removeDecorator('DtDdWrapper');
$formWhat->removeDecorator('DtDdWrapper');
$formWho->removeDecorator('DtDdWrapper');
$formWhen->removeDecorator('DtDdWrapper');
$formRepeats->removeDecorator('DtDdWrapper');
$formStyle->removeDecorator('DtDdWrapper');
$formLive->removeDecorator('DtDdWrapper');
$p_view->what = $formWhat;
$p_view->when = $formWhen;
$p_view->repeats = $formRepeats;
$p_view->who = $formWho;
$p_view->style = $formStyle;
$p_view->live = $formLive;
$formWhat->populate(array('add_show_id' => '-1'));
$formWhen->populate(array('add_show_start_date' => date("Y-m-d"),

View file

@ -104,6 +104,19 @@ class Application_Model_Show {
return $res;
}
public function getHostsIds()
{
global $CC_DBC;
$sql = "SELECT subjs_id
FROM cc_show_hosts
WHERE show_id = {$this->_showId}";
$hosts = $CC_DBC->GetAll($sql);
return $hosts;
}
//remove everything about this show.
public function delete()
@ -771,6 +784,24 @@ class Application_Model_Show {
return $showInstance;
}
/**
* returns info about live stream override info
*/
public function getLiveStreamInfo(){
$info = array();
if($this->_showId == null){
return $info;
}else{
$ccShow = CcShowQuery::create()->findPK($this->_showId);
$info['custom_username'] = $ccShow->getDbLiveStreamUser();
$info['cb_airtime_auth'] = $ccShow->getDbLiveStreamUsingAirtimeAuth();
$info['cb_custom_auth'] = $ccShow->getDbLiveStreamUsingCustomAuth();
$info['custom_username'] = $ccShow->getDbLiveStreamUser();
$info['custom_password'] = $ccShow->getDbLiveStreamPass();
return $info;
}
}
/* Only used for shows that are repeating. Note that this will return
* true even for dates that only have a "modified" show instance (does not
@ -959,6 +990,10 @@ class Application_Model_Show {
$ccShow->setDbGenre($data['add_show_genre']);
$ccShow->setDbColor($data['add_show_color']);
$ccShow->setDbBackgroundColor($data['add_show_background_color']);
$ccShow->setDbLiveStreamUsingAirtimeAuth($data['cb_airtime_auth'] == 1?true:false);
$ccShow->setDbLiveStreamUsingCustomAuth($data['cb_custom_auth'] == 1?true:false);
$ccShow->setDbLiveStreamUser($data['custom_username']);
$ccShow->setDbLiveStreamPass($data['custom_password']);
$ccShow->save();
$showId = $ccShow->getDbId();
@ -1676,9 +1711,13 @@ class Application_Model_Show {
* @param String $timeNow - current time (in UTC)
* @return array - show being played right now
*/
public static function GetCurrentShow($timeNow)
public static function GetCurrentShow($timeNow=null)
{
global $CC_CONFIG, $CC_DBC;
if($timeNow == null){
$date = new Application_Model_DateHelper;
$timeNow = $date->getUtcTimestamp();
}
//TODO, returning starts + ends twice (once with an alias). Unify this after the 2.0 release. --Martin
$sql = "SELECT si.starts as start_timestamp, si.ends as end_timestamp, s.name, s.id, si.id as instance_id, si.record, s.url, starts, ends"
." FROM $CC_CONFIG[showInstances] si, $CC_CONFIG[showTable] s"

View file

@ -1,5 +1,48 @@
<?php
class Application_Model_StreamSetting {
public static function SetValue($key, $value, $type){
global $CC_CONFIG, $CC_DBC;
$key = pg_escape_string($key);
$value = pg_escape_string($value);
//Check if key already exists
$sql = "SELECT COUNT(*) FROM cc_stream_setting"
." WHERE keyname = '$key'";
$result = $CC_DBC->GetOne($sql);
if($result == 1) {
$sql = "UPDATE cc_stream_setting"
." SET value = '$value', type='$type'"
." WHERE keyname = '$key'";
} else {
$sql = "INSERT INTO cc_stream_setting (keyname, value, type)"
." VALUES ('$key', '$value', '$type')";
}
return $CC_DBC->query($sql);
}
public static function GetValue($key){
global $CC_CONFIG, $CC_DBC;
//Check if key already exists
$sql = "SELECT COUNT(*) FROM cc_stream_setting"
." WHERE keyname = '$key'";
$result = $CC_DBC->GetOne($sql);
if ($result == 0)
return "";
else {
$sql = "SELECT value FROM cc_stream_setting"
." WHERE keyname = '$key'";
$result = $CC_DBC->GetOne($sql);
return $result;
}
}
/* Returns the id's of all streams that are enabled in an array. An
* example of the array returned in JSON notation is ["s1", "s2", "s3"] */
@ -63,6 +106,33 @@ class Application_Model_StreamSetting {
." WHERE keyname not like '%_error'";
$rows = $CC_DBC->getAll($sql);
$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;
}
}
if(!isset($exists["master_live_stream_port"])){
$rows[] = (array("keyname" =>"master_live_stream_port", "value"=>self::GetMasterLiveSteamPort(), "type"=>"integer"));
}
if(!isset($exists["master_live_stream_mp"])){
$rows[] = (array("keyname" =>"master_live_stream_mp", "value"=>self::GetMasterLiveSteamMountPoint(), "type"=>"string"));
}
if(!isset($exists["dj_live_stream_port"])){
$rows[] = (array("keyname" =>"dj_live_stream_port", "value"=>self::GetDJLiveSteamPort(), "type"=>"integer"));
}
if(!isset($exists["dj_live_stream_mp"])){
$rows[] = (array("keyname" =>"dj_live_stream_mp", "value"=>self::GetDJLiveSteamMountPoint(), "type"=>"string"));
}
return $rows;
}
@ -197,4 +267,36 @@ class Application_Model_StreamSetting {
}
return $out;
}
public static function SetMasterLiveSteamPort($value){
self::SetValue("master_live_stream_port", $value, "integer");
}
public static function GetMasterLiveSteamPort(){
return self::GetValue("master_live_stream_port");
}
public static function SetMasterLiveSteamMountPoint($value){
self::SetValue("master_live_stream_mp", $value, "string");
}
public static function GetMasterLiveSteamMountPoint(){
return self::GetValue("master_live_stream_mp");
}
public static function SetDJLiveSteamPort($value){
self::SetValue("dj_live_stream_port", $value, "integer");
}
public static function GetDJLiveSteamPort(){
return self::GetValue("dj_live_stream_port");
}
public static function SetDJLiveSteamMountPoint($value){
self::SetValue("dj_live_stream_mp", $value, "string");
}
public static function GetDJLiveSteamMountPoint(){
return self::GetValue("dj_live_stream_mp");
}
}

View file

@ -30,6 +30,10 @@ class Application_Model_User {
public function isHost($showId) {
return $this->isUserType(UTYPE_HOST, $showId);
}
public function isPM() {
return $this->isUserType(UTYPE_PROGRAM_MANAGER);
}
public function isAdmin() {
return $this->isUserType(UTYPE_ADMIN);

View file

@ -45,6 +45,10 @@ class CcShowTableMap extends TableMap {
$this->addColumn('DESCRIPTION', 'DbDescription', 'VARCHAR', false, 512, null);
$this->addColumn('COLOR', 'DbColor', 'VARCHAR', false, 6, null);
$this->addColumn('BACKGROUND_COLOR', 'DbBackgroundColor', 'VARCHAR', false, 6, null);
$this->addColumn('LIVE_STREAM_USING_AIRTIME_AUTH', 'DbLiveStreamUsingAirtimeAuth', 'BOOLEAN', false, null, null);
$this->addColumn('LIVE_STREAM_USING_CUSTOM_AUTH', 'DbLiveStreamUsingCustomAuth', 'BOOLEAN', false, null, null);
$this->addColumn('LIVE_STREAM_USER', 'DbLiveStreamUser', 'VARCHAR', false, 255, null);
$this->addColumn('LIVE_STREAM_PASS', 'DbLiveStreamPass', 'VARCHAR', false, 255, null);
// validators
} // initialize()

View file

@ -69,6 +69,30 @@ abstract class BaseCcShow extends BaseObject implements Persistent
*/
protected $background_color;
/**
* The value for the live_stream_using_airtime_auth field.
* @var boolean
*/
protected $live_stream_using_airtime_auth;
/**
* The value for the live_stream_using_custom_auth field.
* @var boolean
*/
protected $live_stream_using_custom_auth;
/**
* The value for the live_stream_user field.
* @var string
*/
protected $live_stream_user;
/**
* The value for the live_stream_pass field.
* @var string
*/
protected $live_stream_pass;
/**
* @var array CcShowInstances[] Collection to store aggregation of CcShowInstances objects.
*/
@ -196,6 +220,46 @@ abstract class BaseCcShow extends BaseObject implements Persistent
return $this->background_color;
}
/**
* Get the [live_stream_using_airtime_auth] column value.
*
* @return boolean
*/
public function getDbLiveStreamUsingAirtimeAuth()
{
return $this->live_stream_using_airtime_auth;
}
/**
* Get the [live_stream_using_custom_auth] column value.
*
* @return boolean
*/
public function getDbLiveStreamUsingCustomAuth()
{
return $this->live_stream_using_custom_auth;
}
/**
* Get the [live_stream_user] column value.
*
* @return string
*/
public function getDbLiveStreamUser()
{
return $this->live_stream_user;
}
/**
* Get the [live_stream_pass] column value.
*
* @return string
*/
public function getDbLiveStreamPass()
{
return $this->live_stream_pass;
}
/**
* Set the value of [id] column.
*
@ -336,6 +400,86 @@ abstract class BaseCcShow extends BaseObject implements Persistent
return $this;
} // setDbBackgroundColor()
/**
* Set the value of [live_stream_using_airtime_auth] column.
*
* @param boolean $v new value
* @return CcShow The current object (for fluent API support)
*/
public function setDbLiveStreamUsingAirtimeAuth($v)
{
if ($v !== null) {
$v = (boolean) $v;
}
if ($this->live_stream_using_airtime_auth !== $v) {
$this->live_stream_using_airtime_auth = $v;
$this->modifiedColumns[] = CcShowPeer::LIVE_STREAM_USING_AIRTIME_AUTH;
}
return $this;
} // setDbLiveStreamUsingAirtimeAuth()
/**
* Set the value of [live_stream_using_custom_auth] column.
*
* @param boolean $v new value
* @return CcShow The current object (for fluent API support)
*/
public function setDbLiveStreamUsingCustomAuth($v)
{
if ($v !== null) {
$v = (boolean) $v;
}
if ($this->live_stream_using_custom_auth !== $v) {
$this->live_stream_using_custom_auth = $v;
$this->modifiedColumns[] = CcShowPeer::LIVE_STREAM_USING_CUSTOM_AUTH;
}
return $this;
} // setDbLiveStreamUsingCustomAuth()
/**
* Set the value of [live_stream_user] column.
*
* @param string $v new value
* @return CcShow The current object (for fluent API support)
*/
public function setDbLiveStreamUser($v)
{
if ($v !== null) {
$v = (string) $v;
}
if ($this->live_stream_user !== $v) {
$this->live_stream_user = $v;
$this->modifiedColumns[] = CcShowPeer::LIVE_STREAM_USER;
}
return $this;
} // setDbLiveStreamUser()
/**
* Set the value of [live_stream_pass] column.
*
* @param string $v new value
* @return CcShow The current object (for fluent API support)
*/
public function setDbLiveStreamPass($v)
{
if ($v !== null) {
$v = (string) $v;
}
if ($this->live_stream_pass !== $v) {
$this->live_stream_pass = $v;
$this->modifiedColumns[] = CcShowPeer::LIVE_STREAM_PASS;
}
return $this;
} // setDbLiveStreamPass()
/**
* Indicates whether the columns in this object are only set to default values.
*
@ -387,6 +531,10 @@ abstract class BaseCcShow extends BaseObject implements Persistent
$this->description = ($row[$startcol + 4] !== null) ? (string) $row[$startcol + 4] : null;
$this->color = ($row[$startcol + 5] !== null) ? (string) $row[$startcol + 5] : null;
$this->background_color = ($row[$startcol + 6] !== null) ? (string) $row[$startcol + 6] : null;
$this->live_stream_using_airtime_auth = ($row[$startcol + 7] !== null) ? (boolean) $row[$startcol + 7] : null;
$this->live_stream_using_custom_auth = ($row[$startcol + 8] !== null) ? (boolean) $row[$startcol + 8] : null;
$this->live_stream_user = ($row[$startcol + 9] !== null) ? (string) $row[$startcol + 9] : null;
$this->live_stream_pass = ($row[$startcol + 10] !== null) ? (string) $row[$startcol + 10] : null;
$this->resetModified();
$this->setNew(false);
@ -395,7 +543,7 @@ abstract class BaseCcShow extends BaseObject implements Persistent
$this->ensureConsistency();
}
return $startcol + 7; // 7 = CcShowPeer::NUM_COLUMNS - CcShowPeer::NUM_LAZY_LOAD_COLUMNS).
return $startcol + 11; // 11 = CcShowPeer::NUM_COLUMNS - CcShowPeer::NUM_LAZY_LOAD_COLUMNS).
} catch (Exception $e) {
throw new PropelException("Error populating CcShow object", $e);
@ -787,6 +935,18 @@ abstract class BaseCcShow extends BaseObject implements Persistent
case 6:
return $this->getDbBackgroundColor();
break;
case 7:
return $this->getDbLiveStreamUsingAirtimeAuth();
break;
case 8:
return $this->getDbLiveStreamUsingCustomAuth();
break;
case 9:
return $this->getDbLiveStreamUser();
break;
case 10:
return $this->getDbLiveStreamPass();
break;
default:
return null;
break;
@ -817,6 +977,10 @@ abstract class BaseCcShow extends BaseObject implements Persistent
$keys[4] => $this->getDbDescription(),
$keys[5] => $this->getDbColor(),
$keys[6] => $this->getDbBackgroundColor(),
$keys[7] => $this->getDbLiveStreamUsingAirtimeAuth(),
$keys[8] => $this->getDbLiveStreamUsingCustomAuth(),
$keys[9] => $this->getDbLiveStreamUser(),
$keys[10] => $this->getDbLiveStreamPass(),
);
return $result;
}
@ -869,6 +1033,18 @@ abstract class BaseCcShow extends BaseObject implements Persistent
case 6:
$this->setDbBackgroundColor($value);
break;
case 7:
$this->setDbLiveStreamUsingAirtimeAuth($value);
break;
case 8:
$this->setDbLiveStreamUsingCustomAuth($value);
break;
case 9:
$this->setDbLiveStreamUser($value);
break;
case 10:
$this->setDbLiveStreamPass($value);
break;
} // switch()
}
@ -900,6 +1076,10 @@ abstract class BaseCcShow extends BaseObject implements Persistent
if (array_key_exists($keys[4], $arr)) $this->setDbDescription($arr[$keys[4]]);
if (array_key_exists($keys[5], $arr)) $this->setDbColor($arr[$keys[5]]);
if (array_key_exists($keys[6], $arr)) $this->setDbBackgroundColor($arr[$keys[6]]);
if (array_key_exists($keys[7], $arr)) $this->setDbLiveStreamUsingAirtimeAuth($arr[$keys[7]]);
if (array_key_exists($keys[8], $arr)) $this->setDbLiveStreamUsingCustomAuth($arr[$keys[8]]);
if (array_key_exists($keys[9], $arr)) $this->setDbLiveStreamUser($arr[$keys[9]]);
if (array_key_exists($keys[10], $arr)) $this->setDbLiveStreamPass($arr[$keys[10]]);
}
/**
@ -918,6 +1098,10 @@ abstract class BaseCcShow extends BaseObject implements Persistent
if ($this->isColumnModified(CcShowPeer::DESCRIPTION)) $criteria->add(CcShowPeer::DESCRIPTION, $this->description);
if ($this->isColumnModified(CcShowPeer::COLOR)) $criteria->add(CcShowPeer::COLOR, $this->color);
if ($this->isColumnModified(CcShowPeer::BACKGROUND_COLOR)) $criteria->add(CcShowPeer::BACKGROUND_COLOR, $this->background_color);
if ($this->isColumnModified(CcShowPeer::LIVE_STREAM_USING_AIRTIME_AUTH)) $criteria->add(CcShowPeer::LIVE_STREAM_USING_AIRTIME_AUTH, $this->live_stream_using_airtime_auth);
if ($this->isColumnModified(CcShowPeer::LIVE_STREAM_USING_CUSTOM_AUTH)) $criteria->add(CcShowPeer::LIVE_STREAM_USING_CUSTOM_AUTH, $this->live_stream_using_custom_auth);
if ($this->isColumnModified(CcShowPeer::LIVE_STREAM_USER)) $criteria->add(CcShowPeer::LIVE_STREAM_USER, $this->live_stream_user);
if ($this->isColumnModified(CcShowPeer::LIVE_STREAM_PASS)) $criteria->add(CcShowPeer::LIVE_STREAM_PASS, $this->live_stream_pass);
return $criteria;
}
@ -985,6 +1169,10 @@ abstract class BaseCcShow extends BaseObject implements Persistent
$copyObj->setDbDescription($this->description);
$copyObj->setDbColor($this->color);
$copyObj->setDbBackgroundColor($this->background_color);
$copyObj->setDbLiveStreamUsingAirtimeAuth($this->live_stream_using_airtime_auth);
$copyObj->setDbLiveStreamUsingCustomAuth($this->live_stream_using_custom_auth);
$copyObj->setDbLiveStreamUser($this->live_stream_user);
$copyObj->setDbLiveStreamPass($this->live_stream_pass);
if ($deepCopy) {
// important: temporarily setNew(false) because this affects the behavior of
@ -1583,6 +1771,10 @@ abstract class BaseCcShow extends BaseObject implements Persistent
$this->description = null;
$this->color = null;
$this->background_color = null;
$this->live_stream_using_airtime_auth = null;
$this->live_stream_using_custom_auth = null;
$this->live_stream_user = null;
$this->live_stream_pass = null;
$this->alreadyInSave = false;
$this->alreadyInValidation = false;
$this->clearAllReferences();

View file

@ -26,7 +26,7 @@ abstract class BaseCcShowPeer {
const TM_CLASS = 'CcShowTableMap';
/** The total number of columns. */
const NUM_COLUMNS = 7;
const NUM_COLUMNS = 11;
/** The number of lazy-loaded columns. */
const NUM_LAZY_LOAD_COLUMNS = 0;
@ -52,6 +52,18 @@ abstract class BaseCcShowPeer {
/** the column name for the BACKGROUND_COLOR field */
const BACKGROUND_COLOR = 'cc_show.BACKGROUND_COLOR';
/** the column name for the LIVE_STREAM_USING_AIRTIME_AUTH field */
const LIVE_STREAM_USING_AIRTIME_AUTH = 'cc_show.LIVE_STREAM_USING_AIRTIME_AUTH';
/** the column name for the LIVE_STREAM_USING_CUSTOM_AUTH field */
const LIVE_STREAM_USING_CUSTOM_AUTH = 'cc_show.LIVE_STREAM_USING_CUSTOM_AUTH';
/** the column name for the LIVE_STREAM_USER field */
const LIVE_STREAM_USER = 'cc_show.LIVE_STREAM_USER';
/** the column name for the LIVE_STREAM_PASS field */
const LIVE_STREAM_PASS = 'cc_show.LIVE_STREAM_PASS';
/**
* An identiy map to hold any loaded instances of CcShow objects.
* This must be public so that other peer classes can access this when hydrating from JOIN
@ -68,12 +80,12 @@ abstract class BaseCcShowPeer {
* e.g. self::$fieldNames[self::TYPE_PHPNAME][0] = 'Id'
*/
private static $fieldNames = array (
BasePeer::TYPE_PHPNAME => array ('DbId', 'DbName', 'DbUrl', 'DbGenre', 'DbDescription', 'DbColor', 'DbBackgroundColor', ),
BasePeer::TYPE_STUDLYPHPNAME => array ('dbId', 'dbName', 'dbUrl', 'dbGenre', 'dbDescription', 'dbColor', 'dbBackgroundColor', ),
BasePeer::TYPE_COLNAME => array (self::ID, self::NAME, self::URL, self::GENRE, self::DESCRIPTION, self::COLOR, self::BACKGROUND_COLOR, ),
BasePeer::TYPE_RAW_COLNAME => array ('ID', 'NAME', 'URL', 'GENRE', 'DESCRIPTION', 'COLOR', 'BACKGROUND_COLOR', ),
BasePeer::TYPE_FIELDNAME => array ('id', 'name', 'url', 'genre', 'description', 'color', 'background_color', ),
BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, )
BasePeer::TYPE_PHPNAME => array ('DbId', 'DbName', 'DbUrl', 'DbGenre', 'DbDescription', 'DbColor', 'DbBackgroundColor', 'DbLiveStreamUsingAirtimeAuth', 'DbLiveStreamUsingCustomAuth', 'DbLiveStreamUser', 'DbLiveStreamPass', ),
BasePeer::TYPE_STUDLYPHPNAME => array ('dbId', 'dbName', 'dbUrl', 'dbGenre', 'dbDescription', 'dbColor', 'dbBackgroundColor', 'dbLiveStreamUsingAirtimeAuth', 'dbLiveStreamUsingCustomAuth', 'dbLiveStreamUser', 'dbLiveStreamPass', ),
BasePeer::TYPE_COLNAME => array (self::ID, self::NAME, self::URL, self::GENRE, self::DESCRIPTION, self::COLOR, self::BACKGROUND_COLOR, self::LIVE_STREAM_USING_AIRTIME_AUTH, self::LIVE_STREAM_USING_CUSTOM_AUTH, self::LIVE_STREAM_USER, self::LIVE_STREAM_PASS, ),
BasePeer::TYPE_RAW_COLNAME => array ('ID', 'NAME', 'URL', 'GENRE', 'DESCRIPTION', 'COLOR', 'BACKGROUND_COLOR', 'LIVE_STREAM_USING_AIRTIME_AUTH', 'LIVE_STREAM_USING_CUSTOM_AUTH', 'LIVE_STREAM_USER', 'LIVE_STREAM_PASS', ),
BasePeer::TYPE_FIELDNAME => array ('id', 'name', 'url', 'genre', 'description', 'color', 'background_color', 'live_stream_using_airtime_auth', 'live_stream_using_custom_auth', 'live_stream_user', 'live_stream_pass', ),
BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, )
);
/**
@ -83,12 +95,12 @@ abstract class BaseCcShowPeer {
* e.g. self::$fieldNames[BasePeer::TYPE_PHPNAME]['Id'] = 0
*/
private static $fieldKeys = array (
BasePeer::TYPE_PHPNAME => array ('DbId' => 0, 'DbName' => 1, 'DbUrl' => 2, 'DbGenre' => 3, 'DbDescription' => 4, 'DbColor' => 5, 'DbBackgroundColor' => 6, ),
BasePeer::TYPE_STUDLYPHPNAME => array ('dbId' => 0, 'dbName' => 1, 'dbUrl' => 2, 'dbGenre' => 3, 'dbDescription' => 4, 'dbColor' => 5, 'dbBackgroundColor' => 6, ),
BasePeer::TYPE_COLNAME => array (self::ID => 0, self::NAME => 1, self::URL => 2, self::GENRE => 3, self::DESCRIPTION => 4, self::COLOR => 5, self::BACKGROUND_COLOR => 6, ),
BasePeer::TYPE_RAW_COLNAME => array ('ID' => 0, 'NAME' => 1, 'URL' => 2, 'GENRE' => 3, 'DESCRIPTION' => 4, 'COLOR' => 5, 'BACKGROUND_COLOR' => 6, ),
BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'name' => 1, 'url' => 2, 'genre' => 3, 'description' => 4, 'color' => 5, 'background_color' => 6, ),
BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, )
BasePeer::TYPE_PHPNAME => array ('DbId' => 0, 'DbName' => 1, 'DbUrl' => 2, 'DbGenre' => 3, 'DbDescription' => 4, 'DbColor' => 5, 'DbBackgroundColor' => 6, 'DbLiveStreamUsingAirtimeAuth' => 7, 'DbLiveStreamUsingCustomAuth' => 8, 'DbLiveStreamUser' => 9, 'DbLiveStreamPass' => 10, ),
BasePeer::TYPE_STUDLYPHPNAME => array ('dbId' => 0, 'dbName' => 1, 'dbUrl' => 2, 'dbGenre' => 3, 'dbDescription' => 4, 'dbColor' => 5, 'dbBackgroundColor' => 6, 'dbLiveStreamUsingAirtimeAuth' => 7, 'dbLiveStreamUsingCustomAuth' => 8, 'dbLiveStreamUser' => 9, 'dbLiveStreamPass' => 10, ),
BasePeer::TYPE_COLNAME => array (self::ID => 0, self::NAME => 1, self::URL => 2, self::GENRE => 3, self::DESCRIPTION => 4, self::COLOR => 5, self::BACKGROUND_COLOR => 6, self::LIVE_STREAM_USING_AIRTIME_AUTH => 7, self::LIVE_STREAM_USING_CUSTOM_AUTH => 8, self::LIVE_STREAM_USER => 9, self::LIVE_STREAM_PASS => 10, ),
BasePeer::TYPE_RAW_COLNAME => array ('ID' => 0, 'NAME' => 1, 'URL' => 2, 'GENRE' => 3, 'DESCRIPTION' => 4, 'COLOR' => 5, 'BACKGROUND_COLOR' => 6, 'LIVE_STREAM_USING_AIRTIME_AUTH' => 7, 'LIVE_STREAM_USING_CUSTOM_AUTH' => 8, 'LIVE_STREAM_USER' => 9, 'LIVE_STREAM_PASS' => 10, ),
BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'name' => 1, 'url' => 2, 'genre' => 3, 'description' => 4, 'color' => 5, 'background_color' => 6, 'live_stream_using_airtime_auth' => 7, 'live_stream_using_custom_auth' => 8, 'live_stream_user' => 9, 'live_stream_pass' => 10, ),
BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, )
);
/**
@ -167,6 +179,10 @@ abstract class BaseCcShowPeer {
$criteria->addSelectColumn(CcShowPeer::DESCRIPTION);
$criteria->addSelectColumn(CcShowPeer::COLOR);
$criteria->addSelectColumn(CcShowPeer::BACKGROUND_COLOR);
$criteria->addSelectColumn(CcShowPeer::LIVE_STREAM_USING_AIRTIME_AUTH);
$criteria->addSelectColumn(CcShowPeer::LIVE_STREAM_USING_CUSTOM_AUTH);
$criteria->addSelectColumn(CcShowPeer::LIVE_STREAM_USER);
$criteria->addSelectColumn(CcShowPeer::LIVE_STREAM_PASS);
} else {
$criteria->addSelectColumn($alias . '.ID');
$criteria->addSelectColumn($alias . '.NAME');
@ -175,6 +191,10 @@ abstract class BaseCcShowPeer {
$criteria->addSelectColumn($alias . '.DESCRIPTION');
$criteria->addSelectColumn($alias . '.COLOR');
$criteria->addSelectColumn($alias . '.BACKGROUND_COLOR');
$criteria->addSelectColumn($alias . '.LIVE_STREAM_USING_AIRTIME_AUTH');
$criteria->addSelectColumn($alias . '.LIVE_STREAM_USING_CUSTOM_AUTH');
$criteria->addSelectColumn($alias . '.LIVE_STREAM_USER');
$criteria->addSelectColumn($alias . '.LIVE_STREAM_PASS');
}
}

View file

@ -13,6 +13,10 @@
* @method CcShowQuery orderByDbDescription($order = Criteria::ASC) Order by the description column
* @method CcShowQuery orderByDbColor($order = Criteria::ASC) Order by the color column
* @method CcShowQuery orderByDbBackgroundColor($order = Criteria::ASC) Order by the background_color column
* @method CcShowQuery orderByDbLiveStreamUsingAirtimeAuth($order = Criteria::ASC) Order by the live_stream_using_airtime_auth column
* @method CcShowQuery orderByDbLiveStreamUsingCustomAuth($order = Criteria::ASC) Order by the live_stream_using_custom_auth column
* @method CcShowQuery orderByDbLiveStreamUser($order = Criteria::ASC) Order by the live_stream_user column
* @method CcShowQuery orderByDbLiveStreamPass($order = Criteria::ASC) Order by the live_stream_pass column
*
* @method CcShowQuery groupByDbId() Group by the id column
* @method CcShowQuery groupByDbName() Group by the name column
@ -21,6 +25,10 @@
* @method CcShowQuery groupByDbDescription() Group by the description column
* @method CcShowQuery groupByDbColor() Group by the color column
* @method CcShowQuery groupByDbBackgroundColor() Group by the background_color column
* @method CcShowQuery groupByDbLiveStreamUsingAirtimeAuth() Group by the live_stream_using_airtime_auth column
* @method CcShowQuery groupByDbLiveStreamUsingCustomAuth() Group by the live_stream_using_custom_auth column
* @method CcShowQuery groupByDbLiveStreamUser() Group by the live_stream_user column
* @method CcShowQuery groupByDbLiveStreamPass() Group by the live_stream_pass column
*
* @method CcShowQuery leftJoin($relation) Adds a LEFT JOIN clause to the query
* @method CcShowQuery rightJoin($relation) Adds a RIGHT JOIN clause to the query
@ -52,6 +60,10 @@
* @method CcShow findOneByDbDescription(string $description) Return the first CcShow filtered by the description column
* @method CcShow findOneByDbColor(string $color) Return the first CcShow filtered by the color column
* @method CcShow findOneByDbBackgroundColor(string $background_color) Return the first CcShow filtered by the background_color column
* @method CcShow findOneByDbLiveStreamUsingAirtimeAuth(boolean $live_stream_using_airtime_auth) Return the first CcShow filtered by the live_stream_using_airtime_auth column
* @method CcShow findOneByDbLiveStreamUsingCustomAuth(boolean $live_stream_using_custom_auth) Return the first CcShow filtered by the live_stream_using_custom_auth column
* @method CcShow findOneByDbLiveStreamUser(string $live_stream_user) Return the first CcShow filtered by the live_stream_user column
* @method CcShow findOneByDbLiveStreamPass(string $live_stream_pass) Return the first CcShow filtered by the live_stream_pass column
*
* @method array findByDbId(int $id) Return CcShow objects filtered by the id column
* @method array findByDbName(string $name) Return CcShow objects filtered by the name column
@ -60,6 +72,10 @@
* @method array findByDbDescription(string $description) Return CcShow objects filtered by the description column
* @method array findByDbColor(string $color) Return CcShow objects filtered by the color column
* @method array findByDbBackgroundColor(string $background_color) Return CcShow objects filtered by the background_color column
* @method array findByDbLiveStreamUsingAirtimeAuth(boolean $live_stream_using_airtime_auth) Return CcShow objects filtered by the live_stream_using_airtime_auth column
* @method array findByDbLiveStreamUsingCustomAuth(boolean $live_stream_using_custom_auth) Return CcShow objects filtered by the live_stream_using_custom_auth column
* @method array findByDbLiveStreamUser(string $live_stream_user) Return CcShow objects filtered by the live_stream_user column
* @method array findByDbLiveStreamPass(string $live_stream_pass) Return CcShow objects filtered by the live_stream_pass column
*
* @package propel.generator.airtime.om
*/
@ -318,6 +334,84 @@ abstract class BaseCcShowQuery extends ModelCriteria
return $this->addUsingAlias(CcShowPeer::BACKGROUND_COLOR, $dbBackgroundColor, $comparison);
}
/**
* Filter the query on the live_stream_using_airtime_auth column
*
* @param boolean|string $dbLiveStreamUsingAirtimeAuth The value to use as filter.
* Accepts strings ('false', 'off', '-', 'no', 'n', and '0' are false, the rest is true)
* @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL
*
* @return CcShowQuery The current query, for fluid interface
*/
public function filterByDbLiveStreamUsingAirtimeAuth($dbLiveStreamUsingAirtimeAuth = null, $comparison = null)
{
if (is_string($dbLiveStreamUsingAirtimeAuth)) {
$live_stream_using_airtime_auth = in_array(strtolower($dbLiveStreamUsingAirtimeAuth), array('false', 'off', '-', 'no', 'n', '0')) ? false : true;
}
return $this->addUsingAlias(CcShowPeer::LIVE_STREAM_USING_AIRTIME_AUTH, $dbLiveStreamUsingAirtimeAuth, $comparison);
}
/**
* Filter the query on the live_stream_using_custom_auth column
*
* @param boolean|string $dbLiveStreamUsingCustomAuth The value to use as filter.
* Accepts strings ('false', 'off', '-', 'no', 'n', and '0' are false, the rest is true)
* @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL
*
* @return CcShowQuery The current query, for fluid interface
*/
public function filterByDbLiveStreamUsingCustomAuth($dbLiveStreamUsingCustomAuth = null, $comparison = null)
{
if (is_string($dbLiveStreamUsingCustomAuth)) {
$live_stream_using_custom_auth = in_array(strtolower($dbLiveStreamUsingCustomAuth), array('false', 'off', '-', 'no', 'n', '0')) ? false : true;
}
return $this->addUsingAlias(CcShowPeer::LIVE_STREAM_USING_CUSTOM_AUTH, $dbLiveStreamUsingCustomAuth, $comparison);
}
/**
* Filter the query on the live_stream_user column
*
* @param string $dbLiveStreamUser The value to use as filter.
* Accepts wildcards (* and % trigger a LIKE)
* @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL
*
* @return CcShowQuery The current query, for fluid interface
*/
public function filterByDbLiveStreamUser($dbLiveStreamUser = null, $comparison = null)
{
if (null === $comparison) {
if (is_array($dbLiveStreamUser)) {
$comparison = Criteria::IN;
} elseif (preg_match('/[\%\*]/', $dbLiveStreamUser)) {
$dbLiveStreamUser = str_replace('*', '%', $dbLiveStreamUser);
$comparison = Criteria::LIKE;
}
}
return $this->addUsingAlias(CcShowPeer::LIVE_STREAM_USER, $dbLiveStreamUser, $comparison);
}
/**
* Filter the query on the live_stream_pass column
*
* @param string $dbLiveStreamPass The value to use as filter.
* Accepts wildcards (* and % trigger a LIKE)
* @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL
*
* @return CcShowQuery The current query, for fluid interface
*/
public function filterByDbLiveStreamPass($dbLiveStreamPass = null, $comparison = null)
{
if (null === $comparison) {
if (is_array($dbLiveStreamPass)) {
$comparison = Criteria::IN;
} elseif (preg_match('/[\%\*]/', $dbLiveStreamPass)) {
$dbLiveStreamPass = str_replace('*', '%', $dbLiveStreamPass);
$comparison = Criteria::LIKE;
}
}
return $this->addUsingAlias(CcShowPeer::LIVE_STREAM_PASS, $dbLiveStreamPass, $comparison);
}
/**
* Filter the query by a related CcShowInstances object
*

View file

@ -0,0 +1,8 @@
<?php
class Airtime_View_Helper_SourceConnectionStatus extends Zend_View_Helper_Abstract{
public function SourceConnectionStatus(){
$status = array("live_dj"=>Application_Model_Preference::GetSourceStatus("live_dj"), "master_dj"=>Application_Model_Preference::GetSourceStatus("master_dj"));
return $status;
}
}

View file

@ -0,0 +1,10 @@
<?php
class Airtime_View_Helper_SourceSwitchStatus extends Zend_View_Helper_Abstract{
public function SourceSwitchStatus(){
$status = array("live_dj"=>Application_Model_Preference::GetSourceSwitchStatus("live_dj"),
"master_dj"=>Application_Model_Preference::GetSourceSwitchStatus("master_dj"),
"scheduled_play"=>Application_Model_Preference::GetSourceSwitchStatus("scheduled_play"));
return $status;
}
}

View file

@ -0,0 +1,67 @@
<fieldset>
<dl>
<dt id="cb_airtime_auth_override-label">
<label class="optional" for="cb_airtime_auth">
<?php echo $this->element->getElement('cb_airtime_auth')->getLabel() ?>
<span class='info-tooltip'>
<span>
<?php echo $this->element->getElement('cb_airtime_auth')->getDescription() ?>
</span>
</span>
</label>
</dt>
<dd id="cb_airtime_auth_override-element">
<?php echo $this->element->getElement('cb_airtime_auth') ?>
</dd>
<dt id="cb_custom_auth_override-label">
<label class="optional" for="cb_custom_auth">
<?php echo $this->element->getElement('cb_custom_auth')->getLabel() ?>
<span class='info-tooltip'>
<span>
<?php echo $this->element->getElement('cb_custom_auth')->getDescription() ?>
</span>
</span>
</label>
</dt>
<dd id="cb_custom_auth_override-element">
<?php echo $this->element->getElement('cb_custom_auth') ?>
</dd>
<dt id="custom_username-label" class="block-display">
<label class="optional" for="custom_username"><?php echo $this->element->getElement('custom_username')->getLabel() ?> :
</label>
</dt>
<dd id="custom_username-element" class="block-display">
<?php echo $this->element->getElement('custom_username') ?>
<?php if($this->element->getElement('custom_username')->hasErrors()) : ?>
<ul class='errors'>
<?php foreach($this->element->getElement('custom_username')->getMessages() as $error): ?>
<li><?php echo $error; ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</dd>
<dt id="custom_password-label" class="block-display">
<label class="optional" for="custom_password"><?php echo $this->element->getElement('custom_password')->getLabel() ?> :
</label>
</dt>
<dd id="custom_password-element" class="block-display">
<?php echo $this->element->getElement('custom_password') ?>
<?php if($this->element->getElement('custom_password')->hasErrors()) : ?>
<ul class='errors'>
<?php foreach($this->element->getElement('custom_password')->getMessages() as $error): ?>
<li><?php echo $error; ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</dd>
<dt id="Connection_URL-label">
<label for="outputStreamURL">Connection URL: </label>
</dt>
<dd id="Connection_URL-element">
<span id="stream_url"><?php echo $this->connection_url; ?></span>
</dd>
</dl>
</fieldset>

View file

@ -2,7 +2,6 @@
<?php echo $this->element->getSubform('preferences_general') ?>
<h3 class="collapsible-header" id="soundcloud-heading"><span class="arrow-icon"></span>SoundCloud Settings</h3>
<div class="collapsible-content" id="soundcloud-settings" style="display: none;">

View file

@ -0,0 +1,105 @@
<fieldset class="padded stream-setting-global" style="margin-top: 15px">
<legend>Input Stream Settings</legend>
<dl class="zend_form">
<dt id="master_username-label">
<label class="optional" for="master_username"><?php echo $this->element->getElement('master_username')->getLabel() ?> :
</label>
</dt>
<dd id="master_username-element">
<?php echo $this->element->getElement('master_username') ?>
<?php if($this->element->getElement('master_username')->hasErrors()) : ?>
<ul class='errors'>
<?php foreach($this->element->getElement('master_username')->getMessages() as $error): ?>
<li><?php echo $error; ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</dd>
<dt id="master_password-label">
<label class="optional" for="master_password"><?php echo $this->element->getElement('master_password')->getLabel() ?> :
</label>
</dt>
<dd id="master_password-element">
<?php echo $this->element->getElement('master_password') ?>
<?php if($this->element->getElement('master_password')->hasErrors()) : ?>
<ul class='errors'>
<?php foreach($this->element->getElement('master_password')->getMessages() as $error): ?>
<li><?php echo $error; ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</dd>
<dt id="master_harbor_input_port-label">
<label class="optional" for="master_harbor_input_port"><?php echo $this->element->getElement('master_harbor_input_port')->getLabel() ?> :
</label>
</dt>
<dd id="master_harbor_input_port-element">
<?php echo $this->element->getElement('master_harbor_input_port') ?>
<?php if($this->element->getElement('master_harbor_input_port')->hasErrors()) : ?>
<ul class='errors'>
<?php foreach($this->element->getElement('master_harbor_input_port')->getMessages() as $error): ?>
<li><?php echo $error; ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</dd>
<dt id="master_harbor_input_mount_point-label">
<label class="optional" for="master_harbor_input_mount_point"><?php echo $this->element->getElement('master_harbor_input_mount_point')->getLabel() ?> :
</label>
</dt>
<dd id="master_harbor_input_mount_point-element">
<?php echo $this->element->getElement('master_harbor_input_mount_point') ?>
<?php if($this->element->getElement('master_harbor_input_mount_point')->hasErrors()) : ?>
<ul class='errors'>
<?php foreach($this->element->getElement('master_harbor_input_mount_point')->getMessages() as $error): ?>
<li><?php echo $error; ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</dd>
<dt id="master_dj_connection_url-label">
<label class="optional" for="master_dj_connection_url">Master DJ Connection URL:
</label>
</dt>
<dd id="master_dj_connection_url-element">
<span id="stream_url"><?php echo $this->master_dj_connection_url ?></span> <a href=# id="connection_url_override" style="font-size: 12px;">override</a><br>
<div id="master_dj_connection_url_tb" style="display:none"><input type="text"><a href=# id="ok" style="font-size: 12px;">OK</a> <a href=# id="reset" style="font-size: 12px;">RESET</a></div>
</dd>
<dt id="dj_harbor_input_port-label">
<label class="optional" for="dj_harbor_input_port"><?php echo $this->element->getElement('dj_harbor_input_port')->getLabel() ?> :
</label>
</dt>
<dd id="dj_harbor_input_port-element">
<?php echo $this->element->getElement('dj_harbor_input_port') ?>
<?php if($this->element->getElement('dj_harbor_input_port')->hasErrors()) : ?>
<ul class='errors'>
<?php foreach($this->element->getElement('dj_harbor_input_port')->getMessages() as $error): ?>
<li><?php echo $error; ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</dd>
<dt id="dj_harbor_input_mount_point-label">
<label class="optional" for="dj_harbor_input_mount_point"><?php echo $this->element->getElement('dj_harbor_input_mount_point')->getLabel() ?> :
</label>
</dt>
<dd id="dj_harbor_input_mount_point-element">
<?php echo $this->element->getElement('dj_harbor_input_mount_point') ?>
<?php if($this->element->getElement('dj_harbor_input_mount_point')->hasErrors()) : ?>
<ul class='errors'>
<?php foreach($this->element->getElement('dj_harbor_input_mount_point')->getMessages() as $error): ?>
<li><?php echo $error; ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</dd>
<dt id="live_dj_connection_url-label">
<label class="optional" for="live_dj_connection_url">Live DJ Connection URL:
</label>
</dt>
<dd id="live_dj_connection_url-element">
<span id="stream_url"><?php echo $this->live_dj_connection_url ?></span> <a href=# id="connection_url_override" style="font-size: 12px;">override</a>
<div id="live_dj_connection_url_tb" style="display:none"><input type="text"><a href=# id="ok" style="font-size: 12px;">OK</a> <a href=# id="reset" style="font-size: 12px;">RESET</a></div>
</dd>
</dl>
</fieldset>

View file

@ -1,3 +1,3 @@
<div id="import_status" style="display:none">File import in progress...</div>
<div id="import_status" class="library_import" style="display:none">File import in progress... <img src="/css/images/file_import_loader.gif"></img></div>
<table id="library_display" cellpadding="0" cellspacing="0" class="datatable"></table>

View file

@ -20,6 +20,37 @@
<div class="progress-show" id='progress-show' style="width:0%;"></div>
</div>
</div>
<div class="source-info-block">
<ul>
<li>Source Streams</li>
<li>
<div id="scheduled_play_div">
Scheduled Play
<div class="line-to-on-air off"></div>
<a href="#" id="scheduled_play" class="source-switch-button" onclick="setSwitchListener(this);"><span><?php echo $this->scheduled_play_switch?></span></a>
<div class="line-to-switch off"></div>
</div>
</li>
<li>
<div id="live_dj_div">
<a id="live_dj" class="source-kick-button" onclick="kickSource(this)"></a>
Live DJ
<div class="line-to-on-air off"></div>
<a href="#" id="live_dj" class="source-switch-button" onclick="setSwitchListener(this);"><span><?php echo $this->live_dj_switch?></span></a>
<div class="line-to-switch off"></div>
</div>
</li>
<li>
<div id="master_dj_div">
<a id="master_dj" class="source-kick-button" onclick="kickSource(this)"></a>
Master DJ
<div class="line-to-on-air off"></div>
<a href="#" id="master_dj" class="source-switch-button" onclick="setSwitchListener(this);"><span><?php echo $this->master_dj_switch?></span></a>
<div class="line-to-switch off"></div>
</div>
</li>
</ul>
</div>
<div class="on-air-block">
<div class="on-air-info off" id="on-air-info">ON AIR</div>
<a href="#" class="listen-control-button"><span>Listen</span></a>

View file

@ -4,18 +4,25 @@ if (count($items)) : ?>
<?php $i = 0; ?>
<?php foreach($items as $item) : ?>
<li class="ui-state-default" id="spl_<?php echo $item["id"] ?>" unqid="<?php echo $item["CcFiles"]["gunid"]."_".$item["id"]; ?>">
<div class="list-item-container">
<div class="list-item-container">
<?php if ($item["CcFiles"]['file_exists']):?>
<div class="big_play" audioFile="<?php echo $item["CcFiles"]["gunid"].".".pathinfo($item["CcFiles"]['filepath'], PATHINFO_EXTENSION); ?>">
<span class="ui-icon ui-icon-play"></span>
</div>
<?php else: ?>
<div class="big_play ui-state-hover">
<span class="ui-icon ui-icon-alert"></span>
</div>
<?php endif; ?>
<div class="text-row top">
<span class="spl_playlength"><?php echo $item["cliplength"] ?></span>
<span class="spl_cue ui-state-default"></span>
<span class="spl_title"><?php echo $item["CcFiles"]['track_title'] ?></span>
</div>
<div class="text-row">
<span class="spl_artist"><?php echo $item["CcFiles"]['artist_name'] ?></span>
<span class="spl_artist"><?php echo ($item["CcFiles"]['file_exists'])?"":"<img src='/css/images/warning-icon.png'>" ?></span>
<span class="spl_artist"><?php echo $item["CcFiles"]['artist_name'] ?></span>
<span class="spl_offset"><?php echo $item["offset"]?></span>
</div>
<?php //create the crossfade icon.

View file

@ -8,6 +8,7 @@
<div style="clear:both"></div>
<?php }?>
<?php echo $this->statusMsg;?>
<div style="float: left">
<fieldset class="padded stream-setting-global">
<legend>Global Settings</legend>
<dl class="zend_form">
@ -67,6 +68,9 @@
</dd>
</dl>
</fieldset>
<?php echo $this->form->getSubform('live_stream_subform'); ?>
</div>
<div style="float: left; margin-left: 20px; width: 600px;">
<?php
for($i=1;$i<=$this->num_stream;$i++){
echo $this->form->getSubform("s".$i."_subform");
@ -77,5 +81,6 @@
<input type="submit" class="ui-button ui-state-default right-floated" value="Save" id="Save" name="Save" />
</div>
<?php }?>
</form>
</div>
</form>
</div>

View file

@ -16,6 +16,10 @@
<?php echo $this->when; ?>
<?php echo $this->repeats; ?>
</div>
<h3 class="collapsible-header"><span class="arrow-icon"></span>Live Stream</h3>
<div id="live-stream-override" class="collapsible-content">
<?php echo $this->live; ?>
</div>
<?php if(!$this->isSaas()){?>
<h3 class="collapsible-header"><span class="arrow-icon"></span>Record & Rebroadcast</h3>
<div id="schedule-record-rebroadcast" class="collapsible-content">

View file

@ -146,6 +146,10 @@
<column name="description" phpName="DbDescription" type="VARCHAR" size="512" required="false"/>
<column name="color" phpName="DbColor" type="VARCHAR" size="6" required="false"/>
<column name="background_color" phpName="DbBackgroundColor" type="VARCHAR" size="6" required="false"/>
<column name="live_stream_using_airtime_auth" phpName="DbLiveStreamUsingAirtimeAuth" type="BOOLEAN" required="false"/>
<column name="live_stream_using_custom_auth" phpName="DbLiveStreamUsingCustomAuth" type="BOOLEAN" required="false"/>
<column name="live_stream_user" phpName="DbLiveStreamUser" type="VARCHAR" size="255" required="false"/>
<column name="live_stream_pass" phpName="DbLiveStreamPass" type="VARCHAR" size="255" required="false"/>
</table>
<table name="cc_show_instances" phpName="CcShowInstances">
<column name="id" phpName="DbId" type="INTEGER" primaryKey="true" autoIncrement="true" required="true"/>

View file

@ -178,6 +178,10 @@ CREATE TABLE "cc_show"
"description" VARCHAR(512),
"color" VARCHAR(6),
"background_color" VARCHAR(6),
"live_stream_using_airtime_auth" BOOLEAN,
"live_stream_using_custom_auth" BOOLEAN,
"live_stream_user" VARCHAR(255),
"live_stream_pass" VARCHAR(255),
PRIMARY KEY ("id")
);

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

View file

@ -10,7 +10,10 @@
.ui-timepicker-inline { display: inline; }
#ui-timepicker-div { padding: 0.2em }
#ui-timepicker-div {
padding: 0.2em;
z-index: 1000;
}
.ui-timepicker-table { display: inline-table; width: 0; }
.ui-timepicker-table table { margin:0.15em 0 0 0; border-collapse: collapse; }

View file

@ -80,4 +80,13 @@ td.library_track,
td.library_sr,
td.library_bitrate {
text-align: right;
}
.library_import {
padding-bottom: 5px;
}
.library_import img {
vertical-align: middle;
padding-left: 5px;
}

View file

@ -159,14 +159,10 @@
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));
}
#spl_sortable div.big_play .ui-icon-play {
#spl_sortable div.big_play .ui-icon {
margin: 17px 0 0 1px;
}
#spl_sortable div.big_play .ui-icon-pause {
margin: 17px 0 0 1px;
}
#spl_sortable div.big_play:hover .ui-icon-play, #spl_sortable div.big_play:hover .ui-icon-pause {
background-image:url(redmond/images/ui-icons_ff5d1a_256x240.png);
}
@ -456,4 +452,14 @@ div.helper li {
li.spl_empty {
height: 56px;
}
.pl-overlay {
z-index:100;
opacity: 0.7;
}
.pl-loading {
z-index:101;
background: transparent url(images/loader.gif) no-repeat 0 0;
}

View file

@ -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,24 @@ select {
font-size:17px;
margin-bottom:0;
}
.source-info-block {
padding:0 14px 0 2px;
min-width:180px;
}
.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 +379,97 @@ 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-kick-button {
border:1px solid #242424;
color:#fff;
min-height:14px;
min-width:14px;
background-color:#464646;
margin-right: 2px;
float: left;
}
.source-kick-button:hover{
cursor:pointer;
background-color:#FFFFFF;
}
.line-to-switch {
float: right;
width: 10px;
height:6px;
border:1px solid #242424;
border-width:1px 1px 0 1px;
margin-left: 5px;
}
.line-to-switch.off{
background:#FFFFFF
}
.line-to-switch.on{
background:#D40000
}
.line-to-on-air {
float: right;
height:6px;
border:1px solid #242424;
border-width:1px 1px 0 1px;
width: 10px;
}
.line-to-on-air.off{
background:#FFFFFF
}
.line-to-on-air.on{
background:#D40000
}
/* END Master Panel */
@ -1762,10 +1871,14 @@ div.errors{
.medium-icon.finishedplaying {
background:url(images/icon_finishedplaying_m.png) no-repeat 0 0;
}
.preferences, .manage-folders, .stream-config {
.preferences, .manage-folders {
width: 500px;
}
.stream-config {
width: 1080px;
}
.preferences .padded {
margin-top: 5px; /* Firefox needs this */
}
@ -2096,7 +2209,7 @@ dd .info-text-small {
/*width:98.5%;*/
min-width:152px;
}
.stream-config .display_field dd input[type="text"], .stream-config .display_field dd textarea {
.stream-config .display_field dd input[type="text"], .stream-config .display_field dd input[type="password"], .stream-config .display_field dd textarea {
min-width:99%;
padding: 4px 3px;
}
@ -2106,9 +2219,6 @@ dd .info-text-small {
.simple-formblock .display_field dd {
min-width:68%;
}
.stream-config dd input[id$=port] {
width:152px;
}
dt.block-display.info-block {
width: auto;

View file

@ -13,6 +13,11 @@ var currentElem;
var serverUpdateInterval = 5000;
var uiUpdateInterval = 200;
var master_dj_on_air = false;
var live_dj_on_air = false;
var scheduled_play_on_air = false;
var scheduled_play_source = false;
//var timezoneOffset = 0;
//set to "development" if we are developing :). Useful to disable alerts
@ -31,6 +36,8 @@ function secondsTimer(){
estimatedSchedulePosixTime = date.getTime() - localRemoteTimeOffset;
updateProgressBarValue();
updatePlaybar();
controlOnAirLight();
controlSwitchLight();
}
setTimeout(secondsTimer, uiUpdateInterval);
}
@ -74,14 +81,20 @@ function updateProgressBarValue(){
songPercentDone = 0;
currentSong = null;
} else {
if (currentSong.media_item_played == "t" && currentShow.length > 0)
$('#on-air-info').attr("class", "on-air-info on");
else
$('#on-air-info').attr("class", "on-air-info off");
var scheduled_play_line_to_switch = $("#scheduled_play_div").find(".line-to-switch")
if (currentSong.media_item_played == "t" && currentShow.length > 0){
scheduled_play_line_to_switch.attr("class", "line-to-switch on");
scheduled_play_source = true;
}
else{
scheduled_play_source = false;
scheduled_play_line_to_switch.attr("class", "line-to-switch off");
}
$('#progress-show').attr("class", "progress-show");
}
} else {
$('#on-air-info').attr("class", "on-air-info off");
scheduled_play_source = false;
$("#scheduled_play_div").find(".line-to-switch").attr("class", "line-to-switch off");
$('#progress-show').attr("class", "progress-show-error");
}
$('#progress-bar').attr("style", "width:"+songPercentDone+"%");
@ -218,10 +231,85 @@ function parseItems(obj){
localRemoteTimeOffset = date.getTime() - schedulePosixTime;
}
function parseSourceStatus(obj){
var live_div = $("#live_dj_div").find(".line-to-switch")
var master_div = $("#master_dj_div").find(".line-to-switch")
if(obj.live_dj_source == false){
live_div.attr("class", "line-to-switch off")
}else{
live_div.attr("class", "line-to-switch on")
}
if(obj.master_dj_source == false){
master_div.attr("class", "line-to-switch off")
}else{
master_div.attr("class", "line-to-switch on")
}
}
function parseSwitchStatus(obj){
if(obj.live_dj_source == "on" && obj.master_dj_source == "off"){
live_dj_on_air = true;
}else{
live_dj_on_air = false;
}
if(obj.master_dj_source == "on"){
master_dj_on_air = true;
}else{
master_dj_on_air = false;
}
if(obj.scheduled_play == "on"){
scheduled_play_on_air = true;
}else{
scheduled_play_on_air = false;
}
$("#scheduled_play.source-switch-button").find("span").html(obj.scheduled_play)
$("#live_dj.source-switch-button").find("span").html(obj.live_dj_source)
$("#master_dj.source-switch-button").find("span").html(obj.master_dj_source)
}
function controlOnAirLight(){
if((scheduled_play_on_air && scheduled_play_source)|| live_dj_on_air || master_dj_on_air){
$('#on-air-info').attr("class", "on-air-info on");
}else{
$('#on-air-info').attr("class", "on-air-info off");
}
}
function controlSwitchLight(){
var live_div = $("#live_dj_div")
var master_div = $("#master_dj_div")
var scheduled_play_div = $("#scheduled_play_div")
if((scheduled_play_on_air && scheduled_play_source) && !live_dj_on_air && !master_dj_on_air){
scheduled_play_div.find(".line-to-on-air").attr("class", "line-to-on-air on")
live_div.find(".line-to-on-air").attr("class", "line-to-on-air off")
master_div.find(".line-to-on-air").attr("class", "line-to-on-air off")
}else if(live_dj_on_air && !master_dj_on_air){
scheduled_play_div.find(".line-to-on-air").attr("class", "line-to-on-air off")
live_div.find(".line-to-on-air").attr("class", "line-to-on-air on")
master_div.find(".line-to-on-air").attr("class", "line-to-on-air off")
}else if(master_dj_on_air){
scheduled_play_div.find(".line-to-on-air").attr("class", "line-to-on-air off")
live_div.find(".line-to-on-air").attr("class", "line-to-on-air off")
master_div.find(".line-to-on-air").attr("class", "line-to-on-air on")
}else{
scheduled_play_div.find(".line-to-on-air").attr("class", "line-to-on-air off")
live_div.find(".line-to-on-air").attr("class", "line-to-on-air off")
master_div.find(".line-to-on-air").attr("class", "line-to-on-air off")
}
}
function getScheduleFromServer(){
$.ajax({ url: "/Schedule/get-current-playlist/format/json", dataType:"json", success:function(data){
parseItems(data.entries);
parseSourceStatus(data.source_status);
parseSwitchStatus(data.switch_status);
}, error:function(jqXHR, textStatus, errorThrown){}});
setTimeout(getScheduleFromServer, serverUpdateInterval);
}
@ -251,6 +339,31 @@ function setupQtip(){
}
}
function setSwitchListener(ele){
var sourcename = $(ele).attr('id')
var status_span = $(ele).find("span")
var status = status_span.html()
var source_connection_status = false
$.get("/Dashboard/switch-source/format/json/sourcename/"+sourcename+"/status/"+status, function(data){
if(data.error){
alert(data.error);
}else{
status_span.html(data.status)
}
});
}
function kickSource(ele){
var sourcename = $(ele).attr('id')
$.get("/Dashboard/disconnect-source/format/json/sourcename/"+sourcename, function(data){
if(data.error){
alert(data.error);
}
});
}
var stream_window = null;
function init() {

View file

@ -154,7 +154,7 @@ var AIRTIME = (function(AIRTIME) {
$.ajax( {
"dataType": 'json',
"type": "GET",
"type": "POST",
"url": sSource,
"data": aoData,
"success": fnCallback
@ -329,6 +329,8 @@ var AIRTIME = (function(AIRTIME) {
addQtipToSCIcons();
//begin context menu initialization.
$.contextMenu({
selector: '#library_display td:not(.library_checkbox)',
trigger: "left",

View file

@ -5,6 +5,7 @@
var AIRTIME = (function(AIRTIME){
AIRTIME.playlist = {};
var mod = AIRTIME.playlist;
function isTimeValid(time) {
@ -287,7 +288,7 @@ var AIRTIME = (function(AIRTIME){
}
function setPlaylistContent(json) {
$('#spl_name > a')
.empty()
.append(json.name);
@ -302,7 +303,6 @@ var AIRTIME = (function(AIRTIME){
.append(json.html);
setModified(json.modified);
redrawLib();
}
@ -634,49 +634,84 @@ var AIRTIME = (function(AIRTIME){
});
};
mod.fnAddItems = function(aItems, iAfter, sAddType) {
var lastMod = getModified();
function playlistRequest(sUrl, oData) {
var lastMod = getModified(),
plContent = $("#side_playlist"),
offset = plContent.offset(),
plHeight = plContent.height(),
plWidth = plContent.width(),
overlay,
loading;
$.post("/playlist/add-items",
{format: "json", "ids": aItems, "afterItem": iAfter, "type": sAddType, "modified": lastMod},
function(json){
oData["modified"] = lastMod;
oData["format"] = "json";
overlay = $("<div />", {
"class": "pl-overlay ui-widget-content",
"css": {
"position": "absolute",
"top": offset.top,
"left": offset.left,
"height": plHeight + 16,
"width": plWidth + 16
}
}).click(function(){
return false;
});
loading = $("<div />", {
"class": "pl-loading",
"css": {
"position": "absolute",
"top": offset.top + plHeight/2 - 32 - 8,
"left": offset.left + plWidth/2 - 32 -8,
"height": 64,
"width": 64
}
});
$("body")
.append(overlay)
.append(loading);
$.post(
sUrl,
oData,
function(json){
if (json.error !== undefined) {
playlistError(json);
}
else {
setPlaylistContent(json);
}
});
loading.remove();
overlay.remove();
}
);
}
mod.fnAddItems = function(aItems, iAfter, sAddType) {
var sUrl = "/playlist/add-items";
oData = {"ids": aItems, "afterItem": iAfter, "type": sAddType};
playlistRequest(sUrl, oData);
};
mod.fnMoveItems = function(aIds, iAfter) {
var lastMod = getModified();
var sUrl = "/playlist/move-items",
oData = {"ids": aIds, "afterItem": iAfter};
$.post("/playlist/move-items",
{format: "json", "ids": aIds, "afterItem": iAfter, "modified": lastMod},
function(json){
if (json.error !== undefined) {
playlistError(json);
}
else {
setPlaylistContent(json);
}
});
playlistRequest(sUrl, oData);
};
mod.fnDeleteItems = function(aItems) {
var lastMod = getModified();
var sUrl = "/playlist/delete-items",
oData = {"ids": aItems};
$.post("/playlist/delete-items",
{format: "json", "ids": aItems, "modified": lastMod},
function(json){
if (json.error !== undefined) {
playlistError(json);
}
else {
setPlaylistContent(json);
}
});
playlistRequest(sUrl, oData);
};
mod.init = function() {
@ -717,4 +752,24 @@ $(document).ready(function() {
AIRTIME.library.libraryInit();
AIRTIME.playlist.init();
pl.find(".ui-icon-alert").qtip({
content: {
text: "File does not exist on disk..."
},
position:{
adjust: {
resize: true,
method: "flip flip"
},
at: "right center",
my: "left top",
viewport: $(window)
},
style: {
classes: "ui-tooltip-dark"
},
show: 'mouseover',
hide: 'mouseout'
});
});

View file

@ -2,7 +2,12 @@ function showErrorSections() {
if($("#soundcloud-settings .errors").length > 0) {
$("#soundcloud-settings").show();
$(window).scrollTop($("soundcloud-settings .errors").position().top);
$(window).scrollTop($("#soundcloud-settings .errors").position().top);
}
if($("#livestream-settings .errors").length > 0) {
$("#livestream-settings").show();
$(window).scrollTop($("#livestream-settings .errors").position().top);
}
}

View file

@ -106,6 +106,52 @@ function checkLiquidsoapStatus(){
});
}
function setLiveSourceConnectionOverrideListener(){
$("[id=connection_url_override]").click(function(){
var div_ele = $(this).parent().find("div[id$='_dj_connection_url_tb']")
div_ele.find(":input").val("")
div_ele.show()
})
// set action for "OK" and "X"
var live_dj_input = $("#live_dj_connection_url_tb")
var live_dj_label = live_dj_input.parent().find("span")
var master_dj_input = $("#master_dj_connection_url_tb")
var master_dj_label = master_dj_input.parent().find("span")
live_dj_input.find("#ok").click(function(){
var url = $(this).parent().find(":input").val()
live_dj_label.html(url)
live_dj_input.hide()
$.get("/Preference/set-source-connection-url/", {format: "json", type: "livedj", url:encodeURIComponent(url)});
})
live_dj_input.find("#reset").click(function(){
var port = $("#dj_harbor_input_port").val()
var mount = $("#dj_harbor_input_mount_point").val()
var url = "http://"+location.hostname+":"+port+"/"+mount
live_dj_label.html(url)
live_dj_input.hide()
$.get("/Preference/set-source-connection-url", {format: "json", type: "livedj", url:encodeURIComponent(url)});
})
master_dj_input.find("#ok").click(function(){
var url = $(this).parent().find(":input").val()
master_dj_label.html(url)
master_dj_input.hide()
$.get("/Preference/set-source-connection-url", {format: "json", type: "masterdj", url:encodeURIComponent(url)})
})
master_dj_input.find("#reset").click(function(){
var port = $("#master_harbor_input_port").val()
var mount = $("#master_harbor_input_mount_point").val()
var url = "http://"+location.hostname+":"+port+"/"+mount
master_dj_label.html(url)
master_dj_input.hide()
$.get("/Preference/set-source-connection-url", {format: "json", type: "masterdj", url:encodeURIComponent(url)})
})
}
$(document).ready(function() {
// initial stream url
@ -178,6 +224,8 @@ $(document).ready(function() {
return false;
})
setLiveSourceConnectionOverrideListener()
showErrorSections()
setInterval('checkLiquidsoapStatus()', 1000)
$.mask.rules = {

File diff suppressed because it is too large Load diff

View file

@ -48,6 +48,12 @@ remove_watched_dir = 'remove-watched-dir/format/json/api_key/%%api_key%%/path/%%
# URL to tell Airtime we want to add watched directory
set_storage_dir = 'set-storage-dir/format/json/api_key/%%api_key%%/path/%%path%%'
# URL to tell Airtime about file system mount change
update_fs_mount = 'update-file-system-mount/format/json/api_key/%%api_key%%'
# URL to tell Airtime about file system mount change
handle_watched_dir_missing = 'handle-watched-dir-missing/format/json/api_key/%%api_key%%/dir/%%dir%%'
#############################
## Config for Recorder
#############################
@ -95,3 +101,4 @@ get_stream_setting = 'get-stream-setting/format/json/api_key/%%api_key%%/'
#URL to update liquidsoap status
update_liquidsoap_status = 'update-liquidsoap-status/format/json/api_key/%%api_key%%/msg/%%msg%%/stream_id/%%stream_id%%/boot_time/%%boot_time%%'

View file

@ -95,23 +95,3 @@ get_stream_setting = 'get-stream-setting/format/json/api_key/%%api_key%%/'
#URL to update liquidsoap status
update_liquidsoap_status = 'update-liquidsoap-status/format/json/api_key/%%api_key%%/msg/%%msg%%/stream_id/%%stream_id%%/boot_time/%%boot_time%%'
##############
# OBP config #
##############
# URL to get the version number of the server API
#version_url = 'api/pypo/status/json'
# Schedule export path.
# %%from%% - starting date/time in the form YYYY-MM-DD-hh-mm
# %%to%% - starting date/time in the form YYYY-MM-DD-hh-mm
# Update whether an item has been played.
#update_item_url = 'api/pypo/update_shedueled_item/$$item_id%%?played=%%played%%'
# Update whether an item is currently playing.
#update_start_playing_url = 'api/pypo/mod/medialibrary/?playlist_type=%%playlist_type%%&export_source=%%export_source%%&media_id=%%media_id%%&playlist_id=%%playlist_id%%&transmission_id=%%transmission_id%%'
# ???
#generate_range_url = 'api/pypo/generate_range_dp/'

View file

@ -101,3 +101,11 @@ get_stream_setting = 'get-stream-setting/format/json/api_key/%%api_key%%/'
#URL to update liquidsoap status
update_liquidsoap_status = 'update-liquidsoap-status/format/json/api_key/%%api_key%%/msg/%%msg%%/stream_id/%%stream_id%%/boot_time/%%boot_time%%'
#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%%'
get_switch_status = 'get-switch-status/format/json/api_key/%%api_key%%'

View file

@ -21,6 +21,7 @@ from urlparse import urlparse
import base64
from configobj import ConfigObj
import string
import hashlib
AIRTIME_VERSION = "2.1.0"
@ -363,6 +364,29 @@ class AirTimeApiClient(ApiClientInterface):
time.sleep(retries_wait)
return response
def check_live_stream_auth(self, username, password, dj_type):
#logger = logging.getLogger()
response = ''
try:
url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["check_live_stream_auth"])
url = url.replace("%%api_key%%", self.config["api_key"])
url = url.replace("%%username%%", username)
url = url.replace("%%djtype%%", dj_type)
url = url.replace("%%password%%", password)
req = urllib2.Request(url)
response = urllib2.urlopen(req).read()
response = json.loads(response)
except Exception, e:
import traceback
top = traceback.format_exc()
print "Exception: %s", e
print "traceback: %s", top
response = None
return response
def setup_media_monitor(self):
logger = self.logger
@ -559,12 +583,26 @@ 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
"""
def update_file_system_mount(self, added_dir, removed_dir):
logger = logging.getLogger()
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_fs_mount"])
@ -591,7 +629,7 @@ class AirTimeApiClient(ApiClientInterface):
and will call appropriate function on Airtime.
"""
def handle_watched_dir_missing(self, dir):
logger = logging.getLogger()
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["handle_watched_dir_missing"])
@ -606,4 +644,25 @@ class AirTimeApiClient(ApiClientInterface):
top = traceback.format_exc()
logger.error('Exception: %s', e)
logger.error("traceback: %s", top)
"""
Retrive current switch status of streams sources
"""
def get_switch_status(self):
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["get_switch_status"])
url = url.replace("%%api_key%%", self.config["api_key"])
req = urllib2.Request(url)
response = urllib2.urlopen(req).read()
response = json.loads(response)
logger.info("Switch status retrieved %s", response)
except Exception, e:
import traceback
top = traceback.format_exc()
logger.error('Exception: %s', e)
logger.error("traceback: %s", top)
return response

View file

@ -28,6 +28,7 @@ liquidsoap_start () {
liquidsoap_stop () {
monit unmonitor airtime-liquidsoap >/dev/null 2>&1
python /usr/lib/airtime/pypo/bin/liquidsoap_scripts/liquidsoap_prepare_terminate.py
# Send TERM after 5 seconds, wait at most 30 seconds.
start-stop-daemon --stop --oknodo --retry TERM/5/0/30 --quiet --pidfile $PIDFILE1
@ -64,6 +65,7 @@ monit_restart() {
start-stop-daemon --stop --oknodo --retry TERM/5/0/30 --quiet --pidfile $PIDFILE0
rm -f $PIDFILE0
python /usr/lib/airtime/pypo/bin/liquidsoap_scripts/liquidsoap_prepare_terminate.py
start-stop-daemon --stop --oknodo --retry TERM/5/0/30 --quiet --pidfile $PIDFILE1
rm -f $PIDFILE1

View file

@ -0,0 +1,27 @@
from api_clients import *
from configobj import ConfigObj
import sys
import json
try:
config = ConfigObj('/etc/airtime/pypo.cfg')
except Exception, e:
print 'error: ', e
sys.exit()
api_clients = api_client.api_client_factory(config)
dj_type = sys.argv[1]
username = sys.argv[2]
password = sys.argv[3]
type = ''
if dj_type == '--master':
type = 'master'
elif dj_type == '--dj':
type = 'dj'
response = api_clients.check_live_stream_auth(username, password, type)
print response['msg']

View file

@ -0,0 +1,19 @@
from configobj import ConfigObj
import telnetlib
import sys
try:
config = ConfigObj('/etc/airtime/pypo.cfg')
LS_HOST = config['ls_host']
LS_PORT = config['ls_port']
tn = telnetlib.Telnet(LS_HOST, LS_PORT)
tn.write("master_harbor.stop\n")
tn.write("live_dj_harbor.stop\n")
tn.write('exit\n')
tn.read_all()
except Exception, e:
print('Error loading config file: %s', e)
sys.exit()

View file

@ -15,6 +15,17 @@ 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 crossfade(s)
#duration is automatically overwritten by metadata fields passed in
#with audio

View file

@ -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.equeue(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,13 +39,118 @@ 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))
s = fallback(track_sensitive=false, [queue, default])
master_dj_enabled = ref false;
live_dj_enabled = ref false;
scheduled_play_enabled = ref false;
def make_master_dj_available()
master_dj_enabled := true
end
def make_master_dj_unavailable()
master_dj_enabled := false
end
def make_live_dj_available()
live_dj_enabled := true
end
def make_live_dj_unavailable()
live_dj_enabled := false
end
def make_scheduled_play_available()
scheduled_play_enabled := true
end
def make_scheduled_play_unavailable()
scheduled_play_enabled := false
end
#live stream setup
set("harbor.bind_addr", "0.0.0.0")
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
#auth function for live stream
def check_master_dj_client(user,password) =
#get the output of the php script
ret = get_process_lines("python /usr/lib/airtime/pypo/bin/liquidsoap_scripts/liquidsoap_auth.py --master #{user} #{password}")
#ret has now the value of the live client (dj1,dj2, or djx), or "ERROR"/"unknown" ...
ret = list.hd(ret)
#return true to let the client transmit data, or false to tell harbor to decline
if (ret == "True") then
true
else
false
end
end
def check_dj_client(user,password) =
#get the output of the php script
ret = get_process_lines("python /usr/lib/airtime/pypo/bin/liquidsoap_scripts/liquidsoap_auth.py --dj #{user} #{password}")
#ret has now the value of the live client (dj1,dj2, or djx), or "ERROR"/"unknown" ...
ret = list.hd(ret)
#return true to let the client transmit data, or false to tell harbor to decline
if (ret == "True") then
true
else
false
end
end
def append_dj_inputs(master_harbor_input_port, master_harbor_input_mount_point, dj_harbor_input_port, dj_harbor_input_mount_point, s) =
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))
ignore(output.dummy(dj_live, fallible=true))
switch(id="master_dj_switch", track_sensitive=false, transitions=[transition, transition, transition], [({!master_dj_enabled},master_dj), ({!live_dj_enabled},dj_live), ({true}, s)])
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 = switch(id="default_switch", track_sensitive=false, transitions=[transition, transition], [({!scheduled_play_enabled},queue),({true},default)])
s = append_dj_inputs(master_live_stream_port, master_live_stream_mp, dj_live_stream_port, dj_live_stream_mp, s)
s = on_metadata(notify, s)
s = crossfade(s)
# Attach a skip command to the source s:
#web_stream_source = input.http(id="web_stream", autostart = false, buffer=0.5, max=20., "")
@ -59,7 +168,37 @@ s = crossfade(s)
#)
add_skip_command(s)
s = map_metadata(append_title, s)
server.register(namespace="streams",
description="Stop Master DJ source.",
usage="master_dj_stop",
"master_dj_stop",
fun (s) -> begin make_master_dj_unavailable() "Done." end)
server.register(namespace="streams",
description="Start Master DJ source.",
usage="master_dj_start",
"master_dj_start",
fun (s) -> begin make_master_dj_available() "Done." end)
server.register(namespace="streams",
description="Stop Live DJ source.",
usage="live_dj_stop",
"live_dj_stop",
fun (s) -> begin make_live_dj_unavailable() "Done." end)
server.register(namespace="streams",
description="Start Live DJ source.",
usage="live_dj_start",
"live_dj_start",
fun (s) -> begin make_live_dj_available() "Done." end)
server.register(namespace="streams",
description="Stop Scheduled Play source.",
usage="scheduled_play_stop",
"scheduled_play_stop",
fun (s) -> begin make_scheduled_play_unavailable() "Done." end)
server.register(namespace="streams",
description="Start Scheduled Play source.",
usage="scheduled_play_start",
"scheduled_play_start",
fun (s) -> begin make_scheduled_play_available() "Done." end)
if output_sound_device then

View file

@ -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."

View file

@ -153,11 +153,12 @@ if __name__ == '__main__':
recorder.daemon = True
recorder.start()
pmh.join()
pfile.join()
# all join() are commented out becase we want to exit entire pypo
# if pypofetch is exiting
#pmh.join()
#recorder.join()
#pp.join()
pf.join()
pp.join()
recorder.join()
logger.info("pypo fetch exit")
sys.exit()

View file

@ -92,13 +92,69 @@ 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'])
elif command == 'disconnect_source':
self.logger.info("disconnect_on_source show command received...")
self.disconnect_source(m['sourcename'])
except Exception, e:
import traceback
top = traceback.format_exc()
self.logger.error('Exception: %s', e)
self.logger.error("traceback: %s", top)
self.logger.error("Exception in handling Message Handler message: %s", e)
def disconnect_source(self,sourcename):
self.logger.debug('Disconnecting source: %s', sourcename)
command = ""
if(sourcename == "master_dj"):
command += "master_harbor.kick\n"
elif(sourcename == "live_dj"):
command += "live_dj_harbor.kick\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 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_"
elif(sourcename == "live_dj"):
command += "live_dj_"
elif(sourcename == "scheduled_play"):
command += "scheduled_play_"
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')
"""
This check current switch status from Airtime and update the status
"""
def check_switch_status(self):
self.logger.debug('Checking current switch status with Airtime')
switch_status = self.api_client.get_switch_status()
self.logger.debug('switch_status:%s',switch_status)
for k, v in switch_status['status'].iteritems():
self.switch_source(k, v)
def stop_current_show(self):
self.logger.debug('Notifying Liquidsoap to stop playback.')
@ -111,7 +167,7 @@ class PypoFetch(Thread):
self.logger.debug(e)
self.logger.debug('Could not connect to liquidsoap')
def regenerateLiquidsoapConf(self, setting):
def regenerateLiquidsoapConf(self, setting_p):
existing = {}
# create a temp file
fh = open('/etc/airtime/liquidsoap.cfg', 'r')
@ -146,8 +202,9 @@ class PypoFetch(Thread):
restart = False
self.logger.info("Looking for changes...")
setting = sorted(setting_p.items())
# look for changes
for s in setting:
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
@ -155,6 +212,10 @@ class PypoFetch(Thread):
if (existing[s[u'keyname']] != 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']:
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']:
@ -190,7 +251,7 @@ class PypoFetch(Thread):
fh.write("################################################\n")
fh.write("# THIS FILE IS AUTO GENERATED. DO NOT CHANGE!! #\n")
fh.write("################################################\n")
for d in setting:
for k, d in setting:
buffer = d[u'keyname'] + " = "
if(d[u'type'] == 'string'):
temp = d[u'value']
@ -218,8 +279,7 @@ class PypoFetch(Thread):
"""
updates the status of liquidsoap connection to the streaming server
This fucntion updates the bootup time variable in liquidsoap script
"""
def update_liquidsoap_connection_status(self):
"""
tn = telnetlib.Telnet(LS_HOST, LS_PORT)
# update the boot up time of liquidsoap. Since liquidsoap is not restarting,
# we are manually adjusting the bootup time variable so the status msg will get
@ -348,15 +408,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):
@ -474,6 +541,7 @@ class PypoFetch(Thread):
if success:
self.logger.info("Bootstrap schedule received: %s", self.schedule_data)
self.process_schedule(self.schedule_data, True)
self.check_switch_status()
loops = 1
while True:

View file

@ -74,6 +74,12 @@ 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 == 'disconnect_source':
self.logger.info("disconnect_source command received...")
self.pypo_queue.put(message)
elif command == 'update_recorder_schedule':
self.recorder_queue.put(message)
elif command == 'cancel_recording':

View file

@ -9,10 +9,16 @@ import telnetlib
import calendar
import json
import math
"""
It is possible to use a list as a queue, where the first element added is the first element
retrieved ("first-in, first-out"); however, lists are not efficient for this purpose. Let's use
"deque"
"""
from collections import deque
from threading import Thread
from api_clients import api_client
from configobj import ConfigObj
@ -25,6 +31,7 @@ try:
LS_HOST = config['ls_host']
LS_PORT = config['ls_port']
PUSH_INTERVAL = 2
MAX_LIQUIDSOAP_QUEUE_LENGTH = 2
except Exception, e:
logger = logging.getLogger()
logger.error('Error loading config file %s', e)
@ -42,6 +49,8 @@ class PypoPush(Thread):
self.push_ahead = 10
self.last_end_time = 0
self.pushed_objects = {}
self.logger = logging.getLogger('push')
def push(self):
@ -51,6 +60,9 @@ class PypoPush(Thread):
If yes, the current liquidsoap playlist gets replaced with the corresponding one,
then liquidsoap is asked (via telnet) to reload and immediately play it.
"""
liquidsoap_queue_approx = self.get_queue_items_from_liquidsoap()
self.logger.debug('liquidsoap_queue_approx %s', liquidsoap_queue_approx)
timenow = time.time()
# get a new schedule from pypo-fetch
@ -58,38 +70,42 @@ class PypoPush(Thread):
# make sure we get the latest schedule
while not self.queue.empty():
self.media = self.queue.get()
self.logger.debug("Received data from pypo-fetch")
self.logger.debug('media %s' % json.dumps(self.media))
self.handle_new_media(self.media, liquidsoap_queue_approx)
media = self.media
currently_on_air = False
if media:
tnow = time.gmtime(timenow)
tcoming = time.gmtime(timenow + self.push_ahead)
str_tnow_s = "%04d-%02d-%02d-%02d-%02d-%02d" % (tnow[0], tnow[1], tnow[2], tnow[3], tnow[4], tnow[5])
str_tcoming_s = "%04d-%02d-%02d-%02d-%02d-%02d" % (tcoming[0], tcoming[1], tcoming[2], tcoming[3], tcoming[4], tcoming[5])
for key in media.keys():
media_item = media[key]
item_start = media_item['start'][0:19]
if str_tnow_s <= item_start and item_start < str_tcoming_s:
"""
If the media item starts in the next 30 seconds, push it to the queue.
"""
self.logger.debug('Preparing to push media item scheduled at: %s', key)
if self.push_to_liquidsoap(media_item):
self.logger.debug("Pushed to liquidsoap, updating 'played' status.")
if len(liquidsoap_queue_approx) < MAX_LIQUIDSOAP_QUEUE_LENGTH:
currently_on_air = False
if media:
tnow = time.gmtime(timenow)
tcoming = time.gmtime(timenow + self.push_ahead)
str_tnow_s = "%04d-%02d-%02d-%02d-%02d-%02d" % (tnow[0], tnow[1], tnow[2], tnow[3], tnow[4], tnow[5])
str_tcoming_s = "%04d-%02d-%02d-%02d-%02d-%02d" % (tcoming[0], tcoming[1], tcoming[2], tcoming[3], tcoming[4], tcoming[5])
for key in media.keys():
media_item = media[key]
item_start = media_item['start'][0:19]
if str_tnow_s <= item_start and item_start < str_tcoming_s:
"""
Temporary solution to make sure we don't push the same track multiple times.
If the media item starts in the next 30 seconds, push it to the queue.
"""
del media[key]
currently_on_air = True
self.liquidsoap_state_play = True
self.logger.debug('Preparing to push media item scheduled at: %s', key)
if self.push_to_liquidsoap(media_item):
self.logger.debug("Pushed to liquidsoap, updating 'played' status.")
"""
Temporary solution to make sure we don't push the same track multiple times.
"""
del media[key]
currently_on_air = True
self.liquidsoap_state_play = True
def push_to_liquidsoap(self, media_item):
"""
@ -122,6 +138,129 @@ class PypoPush(Thread):
return False
return True
"""
def update_liquidsoap_queue(self):
# the queue variable liquidsoap_queue is our attempt to mirror
# what liquidsoap actually has in its own queue. Liquidsoap automatically
# updates its own queue when an item finishes playing, we have to do this
# manually.
#
# This function will iterate through the liquidsoap_queue and remove items
# whose end time are in the past.
tnow = time.gmtime(timenow)
str_tnow_s = "%04d-%02d-%02d-%02d-%02d-%02d" % (tnow[0], tnow[1], tnow[2], tnow[3], tnow[4], tnow[5])
while len(self.liquidsoap_queue) > 0:
if self.liquidsoap_queue[0]["end"] < str_tnow_s:
self.liquidsoap_queue.popleft()
"""
def get_queue_items_from_liquidsoap(self):
"""
This function connects to Liquidsoap to find what media items are in its queue.
"""
tn = telnetlib.Telnet(LS_HOST, LS_PORT)
msg = 'queue.queue\n'
tn.write(msg)
response = tn.read_until("\r\n").strip(" \r\n")
tn.write('exit\n')
tn.read_all()
liquidsoap_queue_approx = []
if len(response) > 0:
items_in_queue = response.split(" ")
self.logger.debug("items_in_queue: %s", items_in_queue)
for item in items_in_queue:
if item in self.pushed_objects:
liquidsoap_queue_approx.append(self.pushed_objects[item])
else:
self.logger.error("ID exists in liquidsoap queue that does not exist in our pushed_objects queue: " + item)
return liquidsoap_queue_approx
def handle_new_media(self, media, liquidsoap_queue_approx):
"""
This function's purpose is to gracefully handle situations where
Liquidsoap already has a track in its queue, but the schedule
has changed. If the schedule has changed, this function's job is to
call other functions that will connect to Liquidsoap and alter its
queue.
"""
#TODO: Keys should already be sorted. Verify this.
sorted_keys = sorted(media.keys())
if len(liquidsoap_queue_approx) == 0:
"""
liquidsoap doesn't have anything in its queue, so we have nothing
to worry about. Life is good.
"""
pass
elif len(liquidsoap_queue_approx) == 1:
queue_item_0_start = liquidsoap_queue_approx[0]['start']
try:
if liquidsoap_queue_approx[0]['id'] != media[queue_item_0_start]['id']:
"""
liquidsoap's queue does not match the schedule we just received from the Airtime server.
The queue is only of length 1 which means the item in the queue is playing.
Need to do source.skip.
Since only one item, we don't have to worry about the current item ending and us calling
source.skip unintentionally on the next item (there is no next item).
"""
self.logger.debug("%s from ls does not exist in queue new schedule. Removing" % liquidsoap_queue_approx[0]['id'], media)
self.remove_from_liquidsoap_queue(liquidsoap_queue_approx[0])
except KeyError, k:
self.logger.debug("%s from ls does not exist in queue schedule: %s Removing" % (queue_item_0_start, media))
self.remove_from_liquidsoap_queue(liquidsoap_queue_approx[0])
elif len(liquidsoap_queue_approx) == 2:
queue_item_0_start = liquidsoap_queue_approx[0]['start']
queue_item_1_start = liquidsoap_queue_approx[1]['start']
if queue_item_1_start in media.keys():
if liquidsoap_queue_approx[1]['id'] != media[queue_item_1_start]['id']:
self.remove_from_liquidsoap_queue(liquidsoap_queue_approx[1])
else:
self.remove_from_liquidsoap_queue(liquidsoap_queue_approx[1])
if queue_item_0_start in media.keys():
if liquidsoap_queue_approx[0]['id'] != media[queue_item_0_start]['id']:
self.remove_from_liquidsoap_queue(liquidsoap_queue_approx[0])
else:
self.remove_from_liquidsoap_queue(liquidsoap_queue_approx[0])
def remove_from_liquidsoap_queue(self, media_item, do_only_source_skip=False):
if 'queue_id' in media_item:
queue_id = media_item['queue_id']
tn = telnetlib.Telnet(LS_HOST, LS_PORT)
msg = "queue.remove %s\n" % queue_id
tn.write(msg)
response = tn.read_until("\r\n").strip("\r\n")
if "No such request in my queue" in response:
"""
Cannot remove because Liquidsoap started playing the item. Need
to use source.skip instead
"""
msg = "source.skip"
tn.write("source.skip")
tn.write("exit\n")
tn.read_all()
else:
self.logger.error("'queue_id' key doesn't exist in media_item dict()")
def sleep_until_start(self, media_item):
"""
@ -162,8 +301,16 @@ class PypoPush(Thread):
annotation = media_item['annotation']
msg = 'queue.push %s\n' % annotation.encode('utf-8')
tn.write(msg)
self.logger.debug(msg)
tn.write(msg)
queue_id = tn.read_until("\r\n").strip("\r\n")
#remember the media_item's queue id which we may use
#later if we need to remove it from the queue.
media_item['queue_id'] = queue_id
#add media_item to the end of our queue
self.pushed_objects[queue_id] = media_item
show_name = media_item['show_name']
msg = 'vars.show_name %s\n' % show_name.encode('utf-8')