diff --git a/airtime_mvc/application/controllers/ApiController.php b/airtime_mvc/application/controllers/ApiController.php index 128782ec0..d32f2ad30 100644 --- a/airtime_mvc/application/controllers/ApiController.php +++ b/airtime_mvc/application/controllers/ApiController.php @@ -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; + } + } + } } diff --git a/airtime_mvc/application/controllers/DashboardController.php b/airtime_mvc/application/controllers/DashboardController.php index 284e810b6..54aa1bfa9 100644 --- a/airtime_mvc/application/controllers/DashboardController.php +++ b/airtime_mvc/application/controllers/DashboardController.php @@ -5,14 +5,51 @@ 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'); + $data = array("sourcename"=>$sourcename); + Application_Model_RabbitMq::SendMessageToPypo("disconnect_source", $data); + } + + public function switchSourceAction(){ + $request = $this->getRequest(); + + $sourcename = $this->_getParam('sourcename'); + $current_status = $this->_getParam('status'); + $change_status_to = "on"; + + if(strtolower($current_status) == "on"){ + $change_status_to = "off"; + } + + $data = array("sourcename"=>$sourcename, "status"=>$change_status_to); + Application_Model_RabbitMq::SendMessageToPypo("switch_source", $data); + if(strtolower($current_status) == "on"){ + Application_Model_Preference::SetSourceSwitchStatus($sourcename, "off"); + $this->view->status = "OFF"; + }else{ + Application_Model_Preference::SetSourceSwitchStatus($sourcename, "on"); + $this->view->status = "ON"; + } + } + + public function switchOffSource(){ + + } + public function streamPlayerAction() { global $CC_CONFIG; diff --git a/airtime_mvc/application/controllers/PreferenceController.php b/airtime_mvc/application/controllers/PreferenceController.php index 6c59c4eca..d13cd678d 100644 --- a/airtime_mvc/application/controllers/PreferenceController.php +++ b/airtime_mvc/application/controllers/PreferenceController.php @@ -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 = "
Preferences updated.
"; @@ -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 = "
Stream Setting Updated.
"; } @@ -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(); + } } diff --git a/airtime_mvc/application/controllers/ScheduleController.php b/airtime_mvc/application/controllers/ScheduleController.php index a97471759..57c285835 100644 --- a/airtime_mvc/application/controllers/ScheduleController.php +++ b/airtime_mvc/application/controllers/ScheduleController.php @@ -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; diff --git a/airtime_mvc/application/forms/AddShowLiveStream.php b/airtime_mvc/application/forms/AddShowLiveStream.php new file mode 100644 index 000000000..44e6e4087 --- /dev/null +++ b/airtime_mvc/application/forms/AddShowLiveStream.php @@ -0,0 +1,54 @@ +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())) + )); + } +} \ No newline at end of file diff --git a/airtime_mvc/application/forms/LiveStreamingPreferences.php b/airtime_mvc/application/forms/LiveStreamingPreferences.php new file mode 100644 index 000000000..235d75786 --- /dev/null +++ b/airtime_mvc/application/forms/LiveStreamingPreferences.php @@ -0,0 +1,77 @@ +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,)) + )); + } +} \ No newline at end of file diff --git a/airtime_mvc/application/forms/Preferences.php b/airtime_mvc/application/forms/Preferences.php index b4783c591..fbabf0849 100644 --- a/airtime_mvc/application/forms/Preferences.php +++ b/airtime_mvc/application/forms/Preferences.php @@ -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', diff --git a/airtime_mvc/application/forms/StreamSetting.php b/airtime_mvc/application/forms/StreamSetting.php index 127706d48..0168c8c2a 100644 --- a/airtime_mvc/application/forms/StreamSetting.php +++ b/airtime_mvc/application/forms/StreamSetting.php @@ -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; } } diff --git a/airtime_mvc/application/forms/StreamSettingSubForm.php b/airtime_mvc/application/forms/StreamSettingSubForm.php index bbda6576c..a520b8cec 100644 --- a/airtime_mvc/application/forms/StreamSettingSubForm.php +++ b/airtime_mvc/application/forms/StreamSettingSubForm.php @@ -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; diff --git a/airtime_mvc/application/layouts/scripts/builder.phtml b/airtime_mvc/application/layouts/scripts/builder.phtml index d1d37a4f2..5f13b0f67 100644 --- a/airtime_mvc/application/layouts/scripts/builder.phtml +++ b/airtime_mvc/application/layouts/scripts/builder.phtml @@ -10,9 +10,15 @@
- versionNotify() ?> - partial('partialviews/header.phtml', array("user" => $this->loggedInAs(), "is_trial"=>$this->isTrial(), "trial_remain"=> $this->trialRemaining())) ?> - + versionNotify(); + $sss = $this->SourceSwitchStatus(); + $scs = $this->SourceConnectionStatus(); + $isAdmin = $this->isAdmin(); + ?> + 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'], "isAdmin"=>$isAdmin)) ?> + navigation()->menu()->setPartial($partial); ?> diff --git a/airtime_mvc/application/layouts/scripts/layout.phtml b/airtime_mvc/application/layouts/scripts/layout.phtml index 10e6a5ec9..d074b921d 100644 --- a/airtime_mvc/application/layouts/scripts/layout.phtml +++ b/airtime_mvc/application/layouts/scripts/layout.phtml @@ -11,8 +11,14 @@
- versionNotify() ?> - partial('partialviews/header.phtml', array("user" => $this->loggedInAs(), "is_trial"=>$this->isTrial(), "trial_remain"=> $this->trialRemaining())) ?> + versionNotify(); + $sss = $this->SourceSwitchStatus(); + $scs = $this->SourceConnectionStatus(); + $isAdmin = $this->isAdmin(); + ?> + 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'], "isAdmin"=>$isAdmin)) ?> navigation()->menu()->setPartial($partial); ?> diff --git a/airtime_mvc/application/layouts/scripts/library.phtml b/airtime_mvc/application/layouts/scripts/library.phtml index d015fee03..e3a2748e1 100644 --- a/airtime_mvc/application/layouts/scripts/library.phtml +++ b/airtime_mvc/application/layouts/scripts/library.phtml @@ -11,8 +11,14 @@
- versionNotify() ?> - partial('partialviews/header.phtml', array("user" => $this->loggedInAs(), "is_trial"=>$this->isTrial(), "trial_remain"=> $this->trialRemaining())) ?> + versionNotify(); + $sss = $this->SourceSwitchStatus(); + $scs = $this->SourceConnectionStatus(); + $isAdmin = $this->isAdmin(); + ?> + 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'], "isAdmin"=>$isAdmin)) ?> navigation()->menu()->setPartial($partial); ?> diff --git a/airtime_mvc/application/layouts/scripts/playouthistory.phtml b/airtime_mvc/application/layouts/scripts/playouthistory.phtml index 210bbeaa8..0c9fee73f 100644 --- a/airtime_mvc/application/layouts/scripts/playouthistory.phtml +++ b/airtime_mvc/application/layouts/scripts/playouthistory.phtml @@ -11,8 +11,14 @@
- versionNotify() ?> - partial('partialviews/header.phtml', array("user" => $this->loggedInAs(), "is_trial"=>$this->isTrial(), "trial_remain"=> $this->trialRemaining())) ?> + versionNotify(); + $sss = $this->SourceSwitchStatus(); + $scs = $this->SourceConnectionStatus(); + $isAdmin = $this->isAdmin(); + ?> + 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'], "isAdmin"=>$isAdmin)) ?> navigation()->menu()->setPartial($partial); ?> diff --git a/airtime_mvc/application/models/Preference.php b/airtime_mvc/application/models/Preference.php index 061c694c8..ce6a61d13 100644 --- a/airtime_mvc/application/models/Preference.php +++ b/airtime_mvc/application/models/Preference.php @@ -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 */ } diff --git a/airtime_mvc/application/models/Schedule.php b/airtime_mvc/application/models/Schedule.php index 2338fd0e8..b924ee4c0 100644 --- a/airtime_mvc/application/models/Schedule.php +++ b/airtime_mvc/application/models/Schedule.php @@ -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"), diff --git a/airtime_mvc/application/models/Show.php b/airtime_mvc/application/models/Show.php index 1bca7c7a2..afd9255b7 100644 --- a/airtime_mvc/application/models/Show.php +++ b/airtime_mvc/application/models/Show.php @@ -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" diff --git a/airtime_mvc/application/models/StreamSetting.php b/airtime_mvc/application/models/StreamSetting.php index 0ae84a009..bc0fe6f06 100644 --- a/airtime_mvc/application/models/StreamSetting.php +++ b/airtime_mvc/application/models/StreamSetting.php @@ -1,5 +1,48 @@ 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"); + } } diff --git a/airtime_mvc/application/models/airtime/map/CcShowTableMap.php b/airtime_mvc/application/models/airtime/map/CcShowTableMap.php index b558b6e93..f0d7c84c3 100644 --- a/airtime_mvc/application/models/airtime/map/CcShowTableMap.php +++ b/airtime_mvc/application/models/airtime/map/CcShowTableMap.php @@ -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() diff --git a/airtime_mvc/application/models/airtime/om/BaseCcShow.php b/airtime_mvc/application/models/airtime/om/BaseCcShow.php index b2ab6b257..78722b5ba 100644 --- a/airtime_mvc/application/models/airtime/om/BaseCcShow.php +++ b/airtime_mvc/application/models/airtime/om/BaseCcShow.php @@ -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(); diff --git a/airtime_mvc/application/models/airtime/om/BaseCcShowPeer.php b/airtime_mvc/application/models/airtime/om/BaseCcShowPeer.php index 110c08101..e559e0d1a 100644 --- a/airtime_mvc/application/models/airtime/om/BaseCcShowPeer.php +++ b/airtime_mvc/application/models/airtime/om/BaseCcShowPeer.php @@ -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'); } } diff --git a/airtime_mvc/application/models/airtime/om/BaseCcShowQuery.php b/airtime_mvc/application/models/airtime/om/BaseCcShowQuery.php index 10f9dac11..580a7b1ad 100644 --- a/airtime_mvc/application/models/airtime/om/BaseCcShowQuery.php +++ b/airtime_mvc/application/models/airtime/om/BaseCcShowQuery.php @@ -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 * diff --git a/airtime_mvc/application/views/helpers/IsAdmin.php b/airtime_mvc/application/views/helpers/IsAdmin.php new file mode 100644 index 000000000..94c07235a --- /dev/null +++ b/airtime_mvc/application/views/helpers/IsAdmin.php @@ -0,0 +1,11 @@ +getStorage()->read(); + $user = new Application_Model_User($userInfo->id); + return $user->isAdmin(); + } +} \ No newline at end of file diff --git a/airtime_mvc/application/views/helpers/SourceConnectionStatus.php b/airtime_mvc/application/views/helpers/SourceConnectionStatus.php new file mode 100644 index 000000000..1d86b0f57 --- /dev/null +++ b/airtime_mvc/application/views/helpers/SourceConnectionStatus.php @@ -0,0 +1,8 @@ +Application_Model_Preference::GetSourceStatus("live_dj"), "master_dj"=>Application_Model_Preference::GetSourceStatus("master_dj")); + return $status; + } +} \ No newline at end of file diff --git a/airtime_mvc/application/views/helpers/SourceSwitchStatus.php b/airtime_mvc/application/views/helpers/SourceSwitchStatus.php new file mode 100644 index 000000000..86ca01707 --- /dev/null +++ b/airtime_mvc/application/views/helpers/SourceSwitchStatus.php @@ -0,0 +1,10 @@ +Application_Model_Preference::GetSourceSwitchStatus("live_dj"), + "master_dj"=>Application_Model_Preference::GetSourceSwitchStatus("master_dj"), + "scheduled_play"=>Application_Model_Preference::GetSourceSwitchStatus("scheduled_play")); + return $status; + } +} \ No newline at end of file diff --git a/airtime_mvc/application/views/scripts/form/add-show-live-stream.phtml b/airtime_mvc/application/views/scripts/form/add-show-live-stream.phtml new file mode 100644 index 000000000..aed91716d --- /dev/null +++ b/airtime_mvc/application/views/scripts/form/add-show-live-stream.phtml @@ -0,0 +1,67 @@ +
+
+
+ +
+
+ element->getElement('cb_airtime_auth') ?> +
+
+ +
+
+ element->getElement('cb_custom_auth') ?> +
+ + +
+ +
+
+ element->getElement('custom_username') ?> + element->getElement('custom_username')->hasErrors()) : ?> +
    + element->getElement('custom_username')->getMessages() as $error): ?> +
  • + +
+ +
+
+ +
+
+ element->getElement('custom_password') ?> + element->getElement('custom_password')->hasErrors()) : ?> +
    + element->getElement('custom_password')->getMessages() as $error): ?> +
  • + +
+ +
+
+ +
+
+ connection_url; ?> +
+
+
+ diff --git a/airtime_mvc/application/views/scripts/form/preferences.phtml b/airtime_mvc/application/views/scripts/form/preferences.phtml index d6d20ea00..412d5aa01 100644 --- a/airtime_mvc/application/views/scripts/form/preferences.phtml +++ b/airtime_mvc/application/views/scripts/form/preferences.phtml @@ -2,7 +2,6 @@ element->getSubform('preferences_general') ?> -

SoundCloud Settings

+
+ +
ON AIR
Listen diff --git a/airtime_mvc/application/views/scripts/preference/stream-setting.phtml b/airtime_mvc/application/views/scripts/preference/stream-setting.phtml index d74b57079..58332bde8 100644 --- a/airtime_mvc/application/views/scripts/preference/stream-setting.phtml +++ b/airtime_mvc/application/views/scripts/preference/stream-setting.phtml @@ -8,6 +8,7 @@
statusMsg;?> +
Global Settings
@@ -67,6 +68,9 @@
+ form->getSubform('live_stream_subform'); ?> +
+
num_stream;$i++){ echo $this->form->getSubform("s".$i."_subform"); @@ -77,5 +81,6 @@
- +
+
\ No newline at end of file diff --git a/airtime_mvc/application/views/scripts/schedule/add-show-form.phtml b/airtime_mvc/application/views/scripts/schedule/add-show-form.phtml index b42b408d2..e61593d78 100644 --- a/airtime_mvc/application/views/scripts/schedule/add-show-form.phtml +++ b/airtime_mvc/application/views/scripts/schedule/add-show-form.phtml @@ -16,6 +16,10 @@ when; ?> repeats; ?>
+

Live Stream

+
+ live; ?> +
isSaas()){?>

Record & Rebroadcast

diff --git a/airtime_mvc/build/schema.xml b/airtime_mvc/build/schema.xml index fc0d7284b..261bdcf43 100644 --- a/airtime_mvc/build/schema.xml +++ b/airtime_mvc/build/schema.xml @@ -146,6 +146,10 @@ + + + + diff --git a/airtime_mvc/build/sql/schema.sql b/airtime_mvc/build/sql/schema.sql index e3074c01c..6cc7c2bc1 100644 --- a/airtime_mvc/build/sql/schema.sql +++ b/airtime_mvc/build/sql/schema.sql @@ -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") ); diff --git a/airtime_mvc/public/css/styles.css b/airtime_mvc/public/css/styles.css index a7de7fa82..63d2c631e 100644 --- a/airtime_mvc/public/css/styles.css +++ b/airtime_mvc/public/css/styles.css @@ -152,7 +152,7 @@ select { position:relative; } -.now-playing-block, .show-block, .on-air-block, .time-info-block, .personal-block, .listen-control-block, .trial-info-block { +.now-playing-block, .show-block, .on-air-block, .time-info-block, .personal-block, .listen-control-block, .trial-info-block, .source-info-block { height:100px; float:left; margin-right:10px; @@ -263,7 +263,7 @@ select { padding:0 12px 0 0; background:url(images/masterpanel_spacer.png) no-repeat right 0; } -.time-info-block { +.time-info-block { padding:0 14px 0 2px; background:url(images/masterpanel_spacer.png) no-repeat right 0; min-width:105px; @@ -288,6 +288,24 @@ select { font-size:17px; margin-bottom:0; } + +.source-info-block { + padding:0 14px 0 2px; + min-width:150px; +} + +.source-info-block li { + list-style-type:none; + font-size:14px; + color:#bdbdbd; + margin:0 0 6px; +} + +.source-info-block ul { + margin:0; + padding:6px 0 0; +} + .on-air-info { height:26px; border:1px solid #242424; @@ -361,6 +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:#D$0000 +} + /* 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; diff --git a/airtime_mvc/public/js/airtime/dashboard/playlist.js b/airtime_mvc/public/js/airtime/dashboard/playlist.js index 0c0e2f4c6..aa1461a4c 100644 --- a/airtime_mvc/public/js/airtime/dashboard/playlist.js +++ b/airtime_mvc/public/js/airtime/dashboard/playlist.js @@ -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,40 @@ function setupQtip(){ } } +function setSwitchListener(ele){ + var sourcename = $(ele).attr('id') + var status_span = $(ele).find("span") + var status = status_span.html() + var _class = $(ele).parent().find("div.line-to-switch").attr("class") + var source_connection_status = false + + // user should be able to turn on/off scheduled_play switch anytime. + if(sourcename.indexOf("scheduled_play") > 0 && _class.indexOf("off") > 0){ + source_connection_status = false + }else{ + source_connection_status = true + } + + if(source_connection_status){ + $.get("/Dashboard/switch-source/format/json/sourcename/"+sourcename+"/status/"+status, function(data){ + status_span.html(data.status) + }); + }else{ + alert("The source is not connected to Airtime!") + } +} + +function kickSource(ele){ + var sourcename = $(ele).attr('id') + var source_connection = $(ele).parent().find(".line-to-switch").attr("class") + if(source_connection.indexOf("off") > 0){ + alert("No source is connected to this input.") + return false + }else{ + $.get("/Dashboard/disconnect-source/format/json/sourcename/"+sourcename) + } +} + var stream_window = null; function init() { diff --git a/airtime_mvc/public/js/airtime/preferences/preferences.js b/airtime_mvc/public/js/airtime/preferences/preferences.js index eb6b7a935..6c760d939 100644 --- a/airtime_mvc/public/js/airtime/preferences/preferences.js +++ b/airtime_mvc/public/js/airtime/preferences/preferences.js @@ -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); } } diff --git a/airtime_mvc/public/js/airtime/preferences/streamsetting.js b/airtime_mvc/public/js/airtime/preferences/streamsetting.js index a88d27ace..4dcb8476e 100644 --- a/airtime_mvc/public/js/airtime/preferences/streamsetting.js +++ b/airtime_mvc/public/js/airtime/preferences/streamsetting.js @@ -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 = { diff --git a/install_minimal/upgrades/airtime-2.0.1/api_client.cfg.201 b/install_minimal/upgrades/airtime-2.0.1/api_client.cfg.201 index f7c63bee8..7aa4cc883 100644 --- a/install_minimal/upgrades/airtime-2.0.1/api_client.cfg.201 +++ b/install_minimal/upgrades/airtime-2.0.1/api_client.cfg.201 @@ -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%%' + diff --git a/install_minimal/upgrades/airtime-2.0.2/api_client.cfg.202 b/install_minimal/upgrades/airtime-2.0.2/api_client.cfg.202 index 2d51bb2d2..f7c63bee8 100644 --- a/install_minimal/upgrades/airtime-2.0.2/api_client.cfg.202 +++ b/install_minimal/upgrades/airtime-2.0.2/api_client.cfg.202 @@ -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/' - diff --git a/python_apps/api_clients/api_client.cfg b/python_apps/api_clients/api_client.cfg index 1e7e01edc..cc73bd534 100644 --- a/python_apps/api_clients/api_client.cfg +++ b/python_apps/api_clients/api_client.cfg @@ -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%%' + diff --git a/python_apps/api_clients/api_client.py b/python_apps/api_clients/api_client.py index 1148dcdc1..766908db6 100755 --- a/python_apps/api_clients/api_client.py +++ b/python_apps/api_clients/api_client.py @@ -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 + \ No newline at end of file diff --git a/python_apps/pypo/airtime-playout-init-d b/python_apps/pypo/airtime-playout-init-d index 49573e187..688e4e790 100755 --- a/python_apps/pypo/airtime-playout-init-d +++ b/python_apps/pypo/airtime-playout-init-d @@ -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 diff --git a/python_apps/pypo/liquidsoap_scripts/liquidsoap_auth.py b/python_apps/pypo/liquidsoap_scripts/liquidsoap_auth.py new file mode 100644 index 000000000..a7955add9 --- /dev/null +++ b/python_apps/pypo/liquidsoap_scripts/liquidsoap_auth.py @@ -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'] \ No newline at end of file diff --git a/python_apps/pypo/liquidsoap_scripts/liquidsoap_prepare_terminate.py b/python_apps/pypo/liquidsoap_scripts/liquidsoap_prepare_terminate.py new file mode 100644 index 000000000..e1dac82b6 --- /dev/null +++ b/python_apps/pypo/liquidsoap_scripts/liquidsoap_prepare_terminate.py @@ -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() + \ No newline at end of file diff --git a/python_apps/pypo/liquidsoap_scripts/ls_lib.liq b/python_apps/pypo/liquidsoap_scripts/ls_lib.liq index 74c289f84..cc515875a 100644 --- a/python_apps/pypo/liquidsoap_scripts/ls_lib.liq +++ b/python_apps/pypo/liquidsoap_scripts/ls_lib.liq @@ -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 diff --git a/python_apps/pypo/liquidsoap_scripts/ls_script.liq b/python_apps/pypo/liquidsoap_scripts/ls_script.liq index 42bc1e479..4a7a40d26 100644 --- a/python_apps/pypo/liquidsoap_scripts/ls_script.liq +++ b/python_apps/pypo/liquidsoap_scripts/ls_script.liq @@ -8,7 +8,7 @@ set("server.telnet.port", 1234) time = ref string_of(gettimeofday()) -queue = audio_to_stereo(request.queue(id="queue", length=0.5)) +queue = audio_to_stereo(id="queue_src", request.queue(id="queue", length=0.5)) queue = cue_cut(queue) pypo_data = ref '0' @@ -26,6 +26,10 @@ s3_namespace = ref '' %include "ls_lib.liq" +queue = on_metadata(notify, queue) +queue = map_metadata(append_title, queue) +ignore(output.dummy(queue, fallible=true)) + server.register(namespace="vars", "pypo_data", fun (s) -> begin pypo_data := s "Done" end) server.register(namespace="vars", "web_stream_enabled", fun (s) -> begin web_stream_enabled := (s == "true") string_of(!web_stream_enabled) end) server.register(namespace="vars", "stream_metadata_type", fun (s) -> begin stream_metadata_type := int_of_string(s) s end) @@ -35,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 diff --git a/python_apps/pypo/pypo-notify.py b/python_apps/pypo/pypo-notify.py index 5139a4aad..0df1abab5 100644 --- a/python_apps/pypo/pypo-notify.py +++ b/python_apps/pypo/pypo-notify.py @@ -51,6 +51,8 @@ parser.add_option("-e", "--error", action="store", dest="error", type="string", parser.add_option("-s", "--stream-id", help="ID stream", metavar="stream_id") parser.add_option("-c", "--connect", help="liquidsoap connected", action="store_true", metavar="connect") parser.add_option("-t", "--time", help="liquidsoap boot up time", action="store", dest="time", metavar="time", type="string") +parser.add_option("-x", "--source-name", help="source connection name", metavar="source_name") +parser.add_option("-y", "--source-status", help="source connection stauts", metavar="source_status") # parse options (options, args) = parser.parse_args() @@ -91,6 +93,16 @@ class Notify: logger.debug('msg = '+ str(msg)) response = self.api_client.notify_liquidsoap_status(msg, stream_id, time) logger.debug("Response: "+json.dumps(response)) + + def notify_source_status(self, source_name, status): + logger = logging.getLogger() + + logger.debug('#################################################') + logger.debug('# Calling server to update source status #') + logger.debug('#################################################') + logger.debug('msg = '+ str(source_name) + ' : ' + str(status)) + response = self.api_client.notify_source_status(source_name, status) + logger.debug("Response: "+json.dumps(response)) if __name__ == '__main__': print @@ -101,7 +113,6 @@ if __name__ == '__main__': # initialize logger = logging.getLogger("notify") - if options.error and options.stream_id: try: n = Notify() @@ -114,6 +125,12 @@ if __name__ == '__main__': n.notify_liquidsoap_status("OK", options.stream_id, options.time) except Exception, e: print e + elif options.source_name and options.source_status: + try: + n = Notify() + n.notify_source_status(options.source_name, options.source_status) + except Exception, e: + print e else: if not options.data: print "NOTICE: 'data' command-line argument not given." diff --git a/python_apps/pypo/pypocli.py b/python_apps/pypo/pypocli.py index 265d141d9..9eeb15a6f 100644 --- a/python_apps/pypo/pypocli.py +++ b/python_apps/pypo/pypocli.py @@ -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() diff --git a/python_apps/pypo/pypofetch.py b/python_apps/pypo/pypofetch.py index e01df5619..c7634b878 100644 --- a/python_apps/pypo/pypofetch.py +++ b/python_apps/pypo/pypofetch.py @@ -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: diff --git a/python_apps/pypo/pypomessagehandler.py b/python_apps/pypo/pypomessagehandler.py index 75b0407ea..06aebc0c5 100644 --- a/python_apps/pypo/pypomessagehandler.py +++ b/python_apps/pypo/pypomessagehandler.py @@ -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':