CC-2607: Ability to adjust stream bitrate, type, etc from UI

- removed debug code from NowPlayingController
- New Form for streamsetting
- Action created in PreferenceController
This commit is contained in:
James 2011-08-18 13:53:12 -04:00
parent 4f2b2dba6d
commit cf55e92aa3
17 changed files with 701 additions and 103 deletions

View File

@ -52,7 +52,6 @@ class NowplayingController extends Zend_Controller_Action
// unset session
Zend_Session::namespaceUnset('referrer');
}else{
var_dump($form->getMessages());
$logo = Application_Model_Preference::GetStationLogo();
if($logo){
$this->view->logoImg = $logo;

View File

@ -7,9 +7,7 @@ class PreferenceController extends Zend_Controller_Action
{
/* Initialize action controller here */
$ajaxContext = $this->_helper->getHelper('AjaxContext');
$ajaxContext/*->addActionContext('register', 'json')
->addActionContext('remindme', 'json')*/
->addActionContext('server-browse', 'json')
$ajaxContext->addActionContext('server-browse', 'json')
->addActionContext('change-stor-directory', 'json')
->addActionContext('reload-watch-directory', 'json')
->addActionContext('remove-watch-directory', 'json')
@ -91,7 +89,66 @@ class PreferenceController extends Zend_Controller_Action
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/preferences/streamsetting.js','text/javascript');
$this->view->form = new Application_Form_StreamSetting();
// get current settings
$temp = Application_Model_StreamSetting::getStreamSetting();
$setting = array();
foreach ($temp as $t){
$setting[$t['keyname']] = $t['value'];
}
// get predefined type and bitrate from pref table
$temp_types = Application_Model_Preference::GetStreamType();
$stream_types = array();
foreach ($temp_types as $type){
$stream_types[trim($type)] = strtoupper(trim($type));
}
$temp_bitrate = Application_Model_Preference::GetStreamBitrate();
$stream_bitrates = array();
foreach ($temp_bitrate as $type){
$stream_bitrates[trim($type)] = strtoupper(trim($type))." Kbit/s";
}
$num_of_stream = 3;
$form = new Application_Form_StreamSetting();
$form->setSetting($setting);
$form->startFrom();
for($i=1; $i<=$num_of_stream; $i++){
$subform = new Application_Form_StreamSettingSubForm();
$subform->setPrefix($i);
$subform->setSetting($setting);
$subform->setStreamTypes($stream_types);
$subform->setStreamBitrates($stream_bitrates);
$subform->startForm();
$form->addSubForm($subform, "s".$i."_subform");
}
if ($request->isPost()) {
$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;
}
}
}
if($form->isValid($post_data['output_sound_device'])){
$values['output_sound_device'] = $form->getValue('output_sound_device');
}
if(!$error){
Application_Model_StreamSetting::setStreamSetting($values);
$data = array();
$data['setting'] = Application_Model_StreamSetting::getStreamSetting();
RabbitMq::SendMessageToPypo("update_stream_setting", $data);
$this->view->statusMsg = "<div class='success'>Stream Setting Updated.</div>";
}
}
$this->view->num_stream = $num_of_stream;
$this->view->form = $form;
}
public function serverBrowseAction()
@ -145,16 +202,6 @@ class PreferenceController extends Zend_Controller_Action
$this->view->subform = $watched_dirs_form->render();
}
public function changeStreamSettingAction()
{
$data = array();
$data['setting'] = Application_Model_StreamSetting::getStreamSetting();
RabbitMq::SendMessageToPypo("update_stream_setting", $data);
$form = new Application_Form_StreamSetting();
$this->view->subform = $form->render();
}
public function reloadWatchDirectoryAction()
{

View File

@ -1,13 +1,30 @@
<?php
class Application_Form_StreamSetting extends Zend_Form_SubForm
class Application_Form_StreamSetting extends Zend_Form
{
private $setting;
public function init()
{
$this->setDecorators(array(
array('ViewScript', array('viewScript' => 'form/stream_setting.phtml'))
));
}
public function setSetting($setting){
$this->setting = $setting;
}
public function startFrom(){
$setting = $this->setting;
$output_sound_device = new Zend_Form_Element_Checkbox('output_sound_device');
$output_sound_device->setLabel('Enabled')
->setRequired(false)
->setValue($setting['output_sound_device'])
->setDecorators(array('ViewHelper'));
$this->addElement($output_sound_device);
}
public function isValid($data){
$this->populate(array("output_sound_device"=>$data));
return true;
}
}

View File

@ -0,0 +1,145 @@
<?php
class Application_Form_StreamSettingSubForm extends Zend_Form_SubForm{
private $prefix;
private $setting;
private $stream_types;
private $stream_bitrates;
public function init()
{
}
public function setPrefix($prefix){
$this->prefix = $prefix;
}
public function setSetting($setting){
$this->setting = $setting;
}
public function setStreamTypes($stream_types){
$this->stream_types = $stream_types;
}
public function setStreamBitrates($stream_bitrates){
$this->stream_bitrates = $stream_bitrates;
}
public function startForm(){
$prefix = "s".$this->prefix;
$stream_number = $this->prefix;
$setting = $this->setting;
$stream_types = $this->stream_types;
$stream_bitrates = $this->stream_bitrates;
$this->setIsArray(true);
$this->setElementsBelongTo($prefix."_data");
$enable = new Zend_Form_Element_Checkbox('enable');
$enable->setLabel('Enabled:')
->setValue($setting['output_'.$prefix] != 'disabled'?1:0)
->setDecorators(array('ViewHelper'));
$this->addElement($enable);
$type = new Zend_Form_Element_Select('type');
$type->setLabel("Type:")
->setMultiOptions($stream_types)
->setValue($setting[$prefix.'_type'])
->setDecorators(array('ViewHelper'));
$this->addElement($type);
$bitrate = new Zend_Form_Element_Select('bitrate');
$bitrate->setLabel("Bitrate:")
->setMultiOptions($stream_bitrates)
->setValue($setting[$prefix.'_bitrate'])
->setDecorators(array('ViewHelper'));
$this->addElement($bitrate);
$output = new Zend_Form_Element_Select('output');
$output->setLabel("Output to:")
->setMultiOptions(array("icecast"=>"Icecast", "shoutcast"=>"Shoutcast"))
->setValue($setting['output_'.$prefix])
->setDecorators(array('ViewHelper'));
$this->addElement($output);
$host = new Zend_Form_Element_Text('host');
$host->setLabel("Server")
->setValue($setting[$prefix.'_host'])
->setDecorators(array('ViewHelper'));
$this->addElement($host);
$port = new Zend_Form_Element_Text('port');
$port->setLabel("Port")
->setValue($setting[$prefix.'_port'])
->setDecorators(array('ViewHelper'));
$this->addElement($port);
$pass = new Zend_Form_Element_Text('pass');
$pass->setLabel("Password")
->setValue($setting[$prefix.'_pass'])
->setDecorators(array('ViewHelper'));
$this->addElement($pass);
$genre = new Zend_Form_Element_Text('genre');
$genre->setLabel("Genre:")
->setValue($setting[$prefix.'_genre'])
->setDecorators(array('ViewHelper'));
$this->addElement($genre);
$url = new Zend_Form_Element_Text('url');
$url->setLabel("URL")
->setValue($setting[$prefix.'_url'])
->setDecorators(array('ViewHelper'));
$this->addElement($url);
$description = new Zend_Form_Element_Text('description');
$description->setLabel("Description")
->setValue($setting[$prefix.'_description'])
->setDecorators(array('ViewHelper'));
$this->addElement($description);
$mount_info = explode('.',$setting[$prefix.'_mount']);
$mount = new Zend_Form_Element_Text('mount');
$mount->class = "with-info";
$mount->setLabel("Mount Point")
->setValue($mount_info[0])
->setDecorators(array('ViewHelper'));
$this->addElement($mount);
$stream_url_value = "http://".$setting[$prefix.'_host'].":".$setting[$prefix.'_port']."/".$mount_info[0].".".$setting[$prefix.'_type'];
$this->setDecorators(array(
array('ViewScript', array('viewScript' => 'form/stream-setting-form.phtml', "stream_number"=>$stream_number, "stream_url"=>$stream_url_value))
));
}
public function isValid ($data){
$isValid = parent::isValid($data);
if($data['enable'] == 1){
if($data['host'] == ''){
$element = $this->getElement("host");
$element->addError("Server cannot be empty.");
$isValid = false;
}
if($data['port'] == ''){
$element = $this->getElement("port");
$element->addError("Port cannot be empty.");
$isValid = false;
}
if($data['pass'] == ''){
$element = $this->getElement("pass");
$element->addError("Password cannot be empty.");
$isValid = false;
}
if($data['output'] == 'icecast'){
if($data['mount'] == ''){
$element = $this->getElement("mount");
$element->addError("Mount cannot be empty with Icecast server.");
$isValid = false;
}
}
}
return $isValid;
}
}

View File

@ -377,5 +377,15 @@ class Application_Model_Preference
public static function GetImportTimestamp(){
return Application_Model_Preference::GetValue("import_timestamp");
}
public static function GetStreamType(){
$st = Application_Model_Preference::GetValue("stream_type");
return explode(',', $st);
}
public static function GetStreamBitrate(){
$sb = Application_Model_Preference::GetValue("stream_bitrate");
return explode(',', $sb);
}
}

View File

@ -1,8 +1,9 @@
<?php
class Application_Model_StreamSetting {
public function __construct(){
}
public static function getStreamSetting(){
global $CC_DBC;
$sql = "SELECT *"
@ -11,4 +12,32 @@ class Application_Model_StreamSetting {
$rows = $CC_DBC->getAll($sql);
return $rows;
}
public static function setStreamSetting($data){
global $CC_DBC;
foreach($data as $key=>$d){
if($key == "output_sound_device"){
$v = $d == 1?"true":"false";
$sql = "UPDATE cc_stream_setting SET value='$v' WHERE keyname='$key'";
$CC_DBC->query($sql);
}
else{
$temp = explode('_', $key);
$prefix = $temp[0];
foreach($d as $k=>$v){
$keyname = $prefix."_".$k;
if( $k == 'output'){
$keyname = $k."_".$prefix;
if( $d["enable"] == 0){
$v = 'disabled';
}
}
if( $k == 'mount'){
$v = $d['mount'].".".$d['type'];
}
$sql = "UPDATE cc_stream_setting SET value='$v' WHERE keyname='$keyname'";
$CC_DBC->query($sql);
}
}
}
}
}

View File

@ -0,0 +1,148 @@
<?php
$s_name = "s".$this->stream_number;
?>
<h3 class="collapsible-header"><span class="arrow-icon"></span>Stream <?php echo $this->stream_number?></h3>
<div class="collapsible-content" id="<?=$s_name?>-config" style="display: block;">
<fieldset class="padded">
<dl class="zend_form clearfix">
<dt id="<?=$s_name?>Enabled-label">
<label for="<?=$s_name?>Enabled"><?php echo $this->element->getElement('enable')->getLabel() ?></label>
</dt>
<dd id="<?=$s_name?>Enabled-element">
<?php echo $this->element->getElement('enable')?>
</dd>
<dt id="<?=$s_name?>Type-label">
<label for="<?=$s_name?>Type"><?php echo $this->element->getElement('type')->getLabel()?></label>
</dt>
<dd id="<?=$s_name?>Type-element">
<?php echo $this->element->getElement('type')?>
</dd>
<dt id="<?=$s_name?>Bitrate-label">
<label for="<?=$s_name?>Bitrate"><?php echo $this->element->getElement('bitrate')->getLabel()?></label>
</dt>
<dd id="<?=$s_name?>Bitrate-element">
<?php echo $this->element->getElement('bitrate')?>
</dd>
<dt id="<?=$s_name?>Output-label">
<label for="<?=$s_name?>Output"><?php echo $this->element->getElement('output')->getLabel()?></label>
</dt>
<dd id="<?=$s_name?>Output-element">
<?php echo $this->element->getElement('output')?>
</dd>
</dl>
<fieldset class="padded top-margin left-margin" id="output_setting">
<dl class="zend_form">
<dt id="outputServer-label" class="block-display">
<label for="outputServer"><?php echo $this->element->getElement('host')->getLabel()?><span class="info-text-small">(Required)</span> :</label>
</dt>
<dd id="outputServer-element" class="block-display">
<?php echo $this->element->getElement('host')?>
<?php if($this->element->getElement('host')->hasErrors()) : ?>
<ul class='errors'>
<?php foreach($this->element->getElement('host')->getMessages() as $error): ?>
<li><?php echo $error; ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</dd>
<dt id="outputPort-label" class="block-display">
<label for="outputPort"><?php echo $this->element->getElement('port')->getLabel()?><span class="info-text-small">(Required)</span> :</label>
</dt>
<dd id="outputPort-element" class="block-display">
<?php echo $this->element->getElement('port')?>
<?php if($this->element->getElement('port')->hasErrors()) : ?>
<ul class='errors'>
<?php foreach($this->element->getElement('port')->getMessages() as $error): ?>
<li><?php echo $error; ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</dd>
<dt id="outputPassword-label" class="block-display">
<label class="optional" for="outputPassword"><?php echo $this->element->getElement('pass')->getLabel()?><span class="info-text-small">(Required)</span> :</label>
</dt>
<dd id="outputPassword-element" class="block-display clearfix">
<?php echo $this->element->getElement('pass')?>
<?php if($this->element->getElement('pass')->hasErrors()) : ?>
<ul class='errors'>
<?php foreach($this->element->getElement('pass')->getMessages() as $error): ?>
<li><?php echo $error; ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</dd>
<dt class="block-display info-block">
The following info will be displayed to listeners in their media player:
</dt>
<dt id="outputGenre-label" class="block-display">
<label for="outputGenre"><?php echo $this->element->getElement('genre')->getLabel()?></label>
</dt>
<dd id="outputGenre-element" class="block-display">
<?php echo $this->element->getElement('genre')?>
<?php if($this->element->getElement('genre')->hasErrors()) : ?>
<ul class='errors'>
<?php foreach($this->element->getElement('genre')->getMessages() as $error): ?>
<li><?php echo $error; ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</dd>
<dt id="stationURL-label" class="block-display">
<label for="stationURL"><?php echo $this->element->getElement('url')->getLabel()?><span class="info-text-small">(Your radio station website)</span> :</label>
</dt>
<dd id="stationURL-element" class="block-display clearfix">
<?php echo $this->element->getElement('url')?>
<?php if($this->element->getElement('url')->hasErrors()) : ?>
<ul class='errors'>
<?php foreach($this->element->getElement('url')->getMessages() as $error): ?>
<li><?php echo $error; ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</dd>
<dt id="stationDescription-label" class="block-display">
<label for="stationDescription"><?php echo $this->element->getElement('description')->getLabel()?></label>
</dt>
<dd id="stationDescription-element" class="block-display clearfix">
<?php echo $this->element->getElement('description')?>
<?php if($this->element->getElement('description')->hasErrors()) : ?>
<ul class='errors'>
<?php foreach($this->element->getElement('description')->getMessages() as $error): ?>
<li><?php echo $error; ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</dd>
<dt id="outputMountpoint-label" class="block-display">
<label for="outputMountpoint"><?php echo $this->element->getElement('mount')->getLabel()?><span class="info-text-small">(Your radio station website)</span> :</label>
</dt>
<dd id="outputMountpoint-element" class="block-display">
<?php echo $this->element->getElement('mount')?><span id="mount_ext" class="input-info">.<?php echo $this->element->getElement('type')->getValue()?></span>
<?php if($this->element->getElement('mount')->hasErrors()) : ?>
<ul class='errors'>
<?php foreach($this->element->getElement('mount')->getMessages() as $error): ?>
<li><?php echo $error; ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</dd>
<dt id="outputStreamURL-label" class="block-display">
<label for="outputStreamURL">Stream URL: </label>
</dt>
<dd id="outputStreamURL-element" class="block-display">
<p id="stream_url"><?php echo $this->stream_url?></p>
</dd>
</dl>
</fieldset>
</fieldset>
</div>

View File

@ -1,4 +1,25 @@
<div id="stream-setting-section" class="ui-widget ui-widget-content block-shadow simple-formblock clearfix padded-strong manage-folders">
<h2>Stream Setting</h2>
<?php echo $this->form; ?>
</div>
<div class="ui-widget ui-widget-content block-shadow simple-formblock clearfix padded-strong stream-config">
<h2>Stream configuration</h2>
<?php echo $this->statusMsg;?>
<form method="post" action="/Preference/stream-setting" enctype="application/x-www-form-urlencoded">
<fieldset class="padded">
<legend>Hardware Audio Out</legend>
<dl class="zend_form">
<dt id="hardwareOut-label" class="block-display" style="display:none;"></dt>
<dd id="hardwareOut-element" class="block-display">
<label class="required" for="EnableHardwareOut">
<?php echo $this->form->getElement('output_sound_device')->getLabel() ?></label>
<?php echo $this->form->getElement('output_sound_device') ?>
</dd>
</dl>
</fieldset>
<?php
for($i=1;$i<=$this->num_stream;$i++){
echo $this->form->getSubform("s".$i."_subform");
}
?>
<div class="button-bar bottom" id="submit-element">
<input type="submit" class="ui-button ui-state-default right-floated" value="Save" id="Save" name="Save" />
</div>
</form>
</div>

View File

@ -1,5 +1,8 @@
INSERT INTO cc_subjs ("login", "type", "pass") VALUES ('admin', 'A', md5('admin'));
INSERT INTO cc_pref("keystr", "valstr") VALUES('stream_type', 'mp3, ogg');
INSERT INTO cc_pref("keystr", "valstr") VALUES('stream_bitrate', '24, 32, 48, 64, 96, 128, 160, 192, 224, 256, 320');
INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('output_sound_device', 'false', 'boolean');
INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('output_icecast_vorbis_metadata', 'false', 'boolean');
INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('output_s1', 'icecast', 'string');

View File

@ -1247,7 +1247,7 @@ div.success{
border:1px solid #488214;
}
.collapsible-header {
.collapsible-header, .collapsible-header-disabled {
border: 1px solid #8f8f8f;
background-color: #cccccc;
background: -moz-linear-gradient(top, #cccccc 0, #b9b9b9 100%);
@ -1264,7 +1264,7 @@ div.success{
margin-top:-1px;
display:none;
}
.collapsible-header .arrow-icon {
.collapsible-header .arrow-icon, .collapsible-header-disabled .arrow-icon {
display:block;
background:url(images/arrows_collapse.png) no-repeat 0 0;
height:11px;
@ -1274,7 +1274,7 @@ div.success{
top:8px;
}
.collapsible-header.close .arrow-icon {
.collapsible-header.close .arrow-icon, collapsible-header-disabled.close .arrow-icon {
background-position: 0 -11px;
}
@ -1604,7 +1604,7 @@ div.success{
.medium-icon.finishedplaying {
background:url(images/icon_finishedplaying_m.png) no-repeat 0 0;
}
.preferences, .manage-folders {
.preferences, .manage-folders, .stream-config {
width: 500px;
}
@ -1614,46 +1614,55 @@ dt.block-display, dd.block-display {
margin-left: 0;
padding-left: 0;
}
.preferences dt.block-display, .preferences dd.block-display {
.preferences dt.block-display, .preferences dd.block-display,
.stream-config dt.block-display, .stream-config dd.block-display {
padding: 0 0 5px 0;
}
.preferences dd.block-display {
.preferences dd.block-display, .stream-config dd.block-display {
margin-bottom:4px;
}
.preferences dd.block-display:last-child {
.preferences dd.block-display:last-child, .stream-config dd.block-display:last-child {
margin-bottom:0;
padding-bottom:0;
}
.simple-formblock dd.block-display {
width: 100%;
}
.preferences input[type="radio"] {
.preferences input[type="radio"], .stream-config input[type="radio"] {
margin:0;
}
.preferences label input[type="radio"] {
.preferences label input[type="radio"], .stream-config label input[type="radio"] {
margin:0 1px 0 0;
}
.preferences label input[type="checkbox"] {
.preferences label input[type="checkbox"], .stream-config label input[type="checkbox"] {
margin:0 5px 0 0;
}
dd.radio-inline-list, .preferences dd.radio-inline-list {
dd.radio-inline-list, .preferences dd.radio-inline-list, .stream-config dd.radio-inline-list {
margin-bottom:6px;
}
.radio-inline-list label {
margin-right:12px;
}
.preferences.simple-formblock dd.block-display {
.preferences.simple-formblock dd.block-display, .stream-config.simple-formblock dd.block-display {
width: 100%;
}
.preferences.simple-formblock dd.block-display select {
.preferences.simple-formblock dd.block-display select, .stream-config.simple-formblock dd.block-display select {
width: 100%;
}
.preferences dd.block-display .input_select {
.preferences dd.block-display .input_select, .stream-config dd.block-display .input_select {
width: 100%;
}
.preferences dd.block-display .input_text_area, .preferences dd.block-display .input_text {
.preferences dd.block-display .input_text_area, .preferences dd.block-display .input_text,
.stream-config dd.block-display .input_text_area, .stream-config dd.block-display .input_text,
.stream-config dd.block-display input[type="text"], .stream-config dd.block-display input[type="password"] {
width: 99.5%;
}
.preferences dd#SoundCloudTags-element.block-display .input_text_area {
height: 120px;
}
@ -1872,7 +1881,7 @@ fieldset legend .ui-icon, .ui-widget-content fieldset legend .ui-icon {
input[type="checkbox"][disabled] {
opacity: 0.6;
}
.play_small {
height:11px;
width: 15px;
@ -1909,4 +1918,54 @@ input[type="checkbox"][disabled] {
dd .info-text-small {
padding: 1px 0 2px;
display:inline-block;
}
.stream-config dt {
width:120px;
padding: 4px 0;
}
.stream-config dt.block-display {
width:auto;
}
.stream-config dd {
margin-bottom:0px;
}
.stream-config dd select {
width:160px;
line-height:140%;
}
dt.block-display.info-block {
width: auto;
font-size:12px;
padding:10px 0;
}
.top-margin {
margin-top:10px;
}
.left-margin {
margin-left:20px;
}
.stream-config dd.block-display textarea {
width: 99.5%;
height: 110px;
}
.input-info {
font-size:12px;
padding:0 0 0 5px;
}
.stream-config dd.block-display input[type="text"].with-info, .stream-config dd.block-display input[type="password"].with-info {
width: 85%;
}
.stream-config dd.block-display p {
font-size:13px;
margin:4px 0 4px 2px;
}
.collapsible-header-disabled {
cursor:default;
opacity:0.6;
}

View File

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

View File

@ -1,13 +1,38 @@
$(document).ready(function() {
function showErrorSections() {
$('#change_setting').click(function(){
var url;
url = "/Preference/change-stream-setting";
$.post(url,
{format: "json"}
);
$(".errors").each(function(i){
if($(this).length > 0){
$(this).closest("div").show();
$(window).scrollTop($(this).position().top);
return false;
}
});
}
function buildStreamUrl(){
$("input:[id$=-host], input:[id$=-port], input:[id$=-mount], select:[id$=-type]").change(function(){
div = $(this).closest("div")
host = div.find("input:[id$=-host]").val()
port = div.find("input:[id$=-port]").val()
mount = div.find("input:[id$=-mount]").val()
type = div.find("select:[id$=-type]").val()
div.find("#stream_url").html("http://"+host+":"+port+"/"+mount+"."+type)
if($(this).attr('id').indexOf('type') != -1){
div.find("#mount_ext").html("."+type)
}
})
}
$(document).ready(function() {
$('.collapsible-header').click(function() {
$(this).next().toggle('fast');
$(this).toggleClass("close");
return false;
}).next().hide();
showErrorSections()
buildStreamUrl()
});

View File

@ -19,13 +19,24 @@ PIDFILE0=/var/run/airtime-playout.pid
DAEMON1=/usr/lib/airtime/pypo/bin/airtime-liquidsoap
PIDFILE1=/var/run/airtime-liquidsoap.pid
liquidsoap_start () {
monit monitor airtime-liquidsoap >/dev/null 2>&1
start-stop-daemon --start --background --quiet --chuid $USERID:$GROUPID \
--nicelevel -15 --make-pidfile --pidfile $PIDFILE1 --startas $DAEMON1
}
liquidsoap_stop () {
# Send TERM after 5 seconds, wait at most 30 seconds.
monit unmonitor airtime-liquidsoap >/dev/null 2>&1
start-stop-daemon --stop --oknodo --retry TERM/5/0/30 --quiet --pidfile $PIDFILE1
rm -f $PIDFILE1
}
start () {
monit monitor airtime-playout >/dev/null 2>&1
start-stop-daemon --start --background --quiet --chuid $USERID:$GROUPID --make-pidfile --pidfile $PIDFILE0 --startas $DAEMON0
monit monitor airtime-liquidsoap >/dev/null 2>&1
start-stop-daemon --start --background --quiet --chuid $USERID:$GROUPID \
--nicelevel -15 --make-pidfile --pidfile $PIDFILE1 --startas $DAEMON1
liquidsoap_start
}
stop () {
@ -35,12 +46,9 @@ stop () {
start-stop-daemon --stop --oknodo --retry TERM/5/0/30 --quiet --pidfile $PIDFILE0
rm -f $PIDFILE0
monit unmonitor airtime-liquidsoap >/dev/null 2>&1
start-stop-daemon --stop --oknodo --retry TERM/5/0/30 --quiet --pidfile $PIDFILE1
rm -f $PIDFILE1
liquidsoap_stop
}
case "${1:-''}" in
'start')
# start commands here
@ -65,6 +73,13 @@ case "${1:-''}" in
# status commands here
/usr/bin/airtime-check-system
;;
'restart-liquidsoap')
# restart commands here
echo -n "Restarting Liquidsoap: "
liquidsoap_stop
liquidsoap_start
echo "Done."
;;
*) # no parameter specified
echo "Usage: $SELF start|stop|restart|status"
exit 1

View File

@ -114,26 +114,28 @@ try:
p = Popen("update-rc.d airtime-playout defaults >/dev/null 2>&1", shell=True)
sts = os.waitpid(p.pid, 0)[1]
#we should access the DB and generate liquidsoap.cfg under etc/airtime/
# we should access the DB and generate liquidsoap.cfg under etc/airtime/
api_client = api_client.api_client_factory(config)
ss = api_client.get_stream_setting()
data = ss['msg']
fh = open('/etc/airtime/liquidsoap.cfg', 'w')
for d in data:
buffer = d[u'keyname'] + " = "
if(d[u'type'] == 'string'):
temp = d[u'value']
if(temp == ""):
temp = "dummy_string"
buffer += "\"" + temp + "\""
else:
temp = d[u'value']
if(temp == ""):
temp = "0"
buffer += temp
buffer += "\n"
fh.write(buffer)
fh.close()
# if api_client is somehow not working, just use original cfg file
if(ss is not None):
data = ss['msg']
fh = open('/etc/airtime/liquidsoap.cfg', 'w')
for d in data:
buffer = d[u'keyname'] + " = "
if(d[u'type'] == 'string'):
temp = d[u'value']
if(temp == ""):
temp = ""
buffer += "\"" + temp + "\""
else:
temp = d[u'value']
if(temp == ""):
temp = "0"
buffer += temp
buffer += "\n"
fh.write(buffer)
fh.close()
print "Waiting for processes to start..."
p = Popen("/etc/init.d/airtime-playout start", shell=True)

View File

@ -50,8 +50,12 @@ def output_to(output_type, type, bitrate, host, port, pass, mount_point, url, de
description = description,
genre = genre)
if type == "mp3" then
if bitrate == 32 then
if bitrate == 24 then
ignore(output.icecast(%mp3(bitrate = 24),s))
elsif bitrate == 32 then
ignore(output.icecast(%mp3(bitrate = 32),s))
elsif bitrate == 48 then
ignore(output.icecast(%mp3(bitrate = 48),s))
elsif bitrate == 64 then
ignore(output.icecast(%mp3(bitrate = 64),s))
elsif bitrate == 96 then
@ -60,14 +64,26 @@ def output_to(output_type, type, bitrate, host, port, pass, mount_point, url, de
ignore(output.icecast(%mp3(bitrate = 128),s))
elsif bitrate == 160 then
ignore(output.icecast(%mp3(bitrate = 160),s))
elsif bitrate == 192 then
ignore(output.icecast(%mp3(bitrate = 192),s))
elsif bitrate == 224 then
ignore(output.icecast(%mp3(bitrate = 224),s))
elsif bitrate == 256 then
ignore(output.icecast(%mp3(bitrate = 256),s))
elsif bitrate == 320 then
ignore(output.icecast(%mp3(bitrate = 320),s))
end
else
source = ref s
if not output_icecast_vorbis_metadata then
source := add(normalize=false, [amplify(0.00001, noise()),s])
end
if bitrate == 32 then
if bitrate == 24 then
ignore(output.icecast(%vorbis.cbr(bitrate = 24),!source))
elsif bitrate == 32 then
ignore(output.icecast(%vorbis.cbr(bitrate = 32),!source))
elsif bitrate == 48 then
ignore(output.icecast(%vorbis.cbr(bitrate = 48),!source))
elsif bitrate == 64 then
ignore(output.icecast(%vorbis.cbr(bitrate = 64),!source))
elsif bitrate == 96 then
@ -76,6 +92,14 @@ def output_to(output_type, type, bitrate, host, port, pass, mount_point, url, de
ignore(output.icecast(%vorbis.cbr(bitrate = 128),!source))
elsif bitrate == 160 then
ignore(output.icecast(%vorbis.cbr(bitrate = 160),!source))
elsif bitrate == 192 then
ignore(output.icecast(%vorbis.cbr(bitrate = 192),!source))
elsif bitrate == 224 then
ignore(output.icecast(%vorbis.cbr(bitrate = 224),!source))
elsif bitrate == 256 then
ignore(output.icecast(%vorbis.cbr(bitrate = 256),!source))
elsif bitrate == 320 then
ignore(output.icecast(%vorbis.cbr(bitrate = 320),!source))
end
end
else
@ -87,17 +111,29 @@ def output_to(output_type, type, bitrate, host, port, pass, mount_point, url, de
restart_delay = 5,
url = url,
genre = genre)
if bitrate == 32 then
ignore(output.shoutcast(%mp3(bitrate = 32),s))
elsif bitrate == 64 then
ignore(output.shoutcast(%mp3(bitrate = 64),s))
elsif bitrate == 96 then
ignore(output.shoutcast(%mp3(bitrate = 96),s))
elsif bitrate == 128 then
ignore(output.shoutcast(%mp3(bitrate = 128),s))
elsif bitrate == 160 then
ignore(output.shoutcast(%mp3(bitrate = 160),s))
end
if bitrate == 24 then
ignore(output.shoutcast(%mp3(bitrate = 24),s))
elsif bitrate == 32 then
ignore(output.shoutcast(%mp3(bitrate = 32),s))
elsif bitrate == 48 then
ignore(output.shoutcast(%mp3(bitrate = 48),s))
elsif bitrate == 64 then
ignore(output.shoutcast(%mp3(bitrate = 64),s))
elsif bitrate == 96 then
ignore(output.shoutcast(%mp3(bitrate = 96),s))
elsif bitrate == 128 then
ignore(output.shoutcast(%mp3(bitrate = 128),s))
elsif bitrate == 160 then
ignore(output.shoutcast(%mp3(bitrate = 160),s))
elsif bitrate == 192 then
ignore(output.shoutcast(%mp3(bitrate = 192),s))
elsif bitrate == 224 then
ignore(output.shoutcast(%mp3(bitrate = 224),s))
elsif bitrate == 256 then
ignore(output.shoutcast(%mp3(bitrate = 256),s))
elsif bitrate == 320 then
ignore(output.shoutcast(%mp3(bitrate = 320),s))
end
end
end

View File

@ -109,7 +109,7 @@ class PypoFetch(Thread):
os.environ['TZ'] = m['timezone']
time.tzset()
elif (command == 'update_stream_setting'):
logger.info("Updating stream setting: %s", m['setting'])
logger.info("Updating stream setting...")
self.regenerateLiquidsoapConf(m['setting'])
# ACK the message to take it off the queue
message.ack()
@ -128,20 +128,58 @@ class PypoFetch(Thread):
key = key.strip()
value = value.strip()
value = value.replace('"', '')
if value == "dummy_string" or value == "0":
if value == "" or value == "0":
value = ''
existing[key] = value
fh.close()
# flag for any change in cofig
change = False
# dict flag for any change in cofig
change = {}
# this flag is to detect diable -> disable change
# in that case, we don't want to restart even if there are chnges.
state_change_restart = {}
#restart flag
restart = False
# look for changes
for s in setting:
if not s[u'value'] == existing[s[u'keyname']]:
logger.info("Keyname: %s, Curent value: %s, New Value: %s", s[u'keyname'], s[u'value'], existing[s[u'keyname']])
change = True
if "output_" in s[u'keyname'] and s[u'keyname'] != "output_icecast_vorbis_metadata" and s[u'keyname'] != "output_sound_device":
dump, stream = s[u'keyname'].split('_', 1)
state_change_restart[stream] = False
# This is the case where restart is required no matter what
if (existing[s[u'keyname']] != s[u'value']):
logger.info("'Need-to-restart' state detected for %s...", s[u'keyname'])
restart = True;
# This is the case where we need further checking
if s[u'value'] != 'disabled':
state_change_restart[stream] = True
else:
if s[u'keyname'] == "output_sound_device":
dump, stream = s[u'keyname'].split('_',1)
state_change_restart[stream] = False
if not (s[u'value'] == existing[s[u'keyname']]):
logger.info("'Need-to-restart' state detected for %s...", s[u'keyname'])
state_change_restart[stream] = True
elif s[u'keyname'] != "output_icecast_vorbis_metadata" and s[u'keyname'] != "log_file":
stream, dump = s[u'keyname'].split('_',1)
# setting inital value
if stream not in change:
change[stream] = False
if not (s[u'value'] == existing[s[u'keyname']]):
logger.info("Keyname: %s, Curent value: %s, New Value: %s", s[u'keyname'], existing[s[u'keyname']], s[u'value'])
change[stream] = True
# set flag change for sound_device alway True
logger.info("Change:%s, State_Change:%s...", change, state_change_restart)
for k, v in state_change_restart.items():
if k == "sound_device" and v:
restart = True
elif v and change[k]:
logger.info("'Need-to-restart' state detected for %s...", k)
restart = True
# rewrite
if change:
if restart:
fh = open('/etc/airtime/liquidsoap.cfg', 'w')
logger.info("Rewriting liquidsoap.cfg...")
for d in setting:
@ -149,7 +187,7 @@ class PypoFetch(Thread):
if(d[u'type'] == 'string'):
temp = d[u'value']
if(temp == ""):
temp = "dummy_string"
temp = ""
buffer += "\"" + temp + "\""
else:
temp = d[u'value']
@ -159,10 +197,12 @@ class PypoFetch(Thread):
buffer += "\n"
fh.write(buffer)
fh.close()
# restart playout
logger.info("Restarting airtime-playout...")
# restarting pypo.
# we could just restart liquidsoap but it take more time somehow.
logger.info("Restarting pypo...")
p = Popen("/etc/init.d/airtime-playout restart >/dev/null 2>&1", shell=True)
sts = os.waitpid(p.pid, 0)[1]
self.process_schedule(self.schedule_data, "scheduler", False)
else:
logger.info("No change detected in setting...")
@ -244,6 +284,8 @@ class PypoFetch(Thread):
# TODO: THIS LIQUIDSOAP STUFF NEEDS TO BE MOVED TO PYPO-PUSH!!!
stream_metadata = schedule_data['stream_metadata']
try:
logger.info(LS_HOST)
logger.info(LS_PORT)
tn = telnetlib.Telnet(LS_HOST, LS_PORT)
#encode in latin-1 due to telnet protocol not supporting utf-8
tn.write(('vars.stream_metadata_type %s\n' % stream_metadata['format']).encode('latin-1'))
@ -456,7 +498,7 @@ class PypoFetch(Thread):
# most recent schedule. After that we can just wait for updates.
status, self.schedule_data = self.api_client.get_schedule()
if status == 1:
self.process_schedule(self.schedule_data , "scheduler", True)
self.process_schedule(self.schedule_data , "scheduler", True)
logger.info("Bootstrap complete: got initial copy of the schedule")
loops = 1

View File

@ -141,9 +141,9 @@ class PypoPush(Thread):
tn.read_all()
except Exception, e:
logger.debug(e)
logger.debug('Could not connect to liquidsoap')
self.liquidsoap_state_play = False
logger.debug('Could not connect to liquidsoap')
def push_liquidsoap(self, pkey, schedule, playlists):