diff --git a/airtime_mvc/application/controllers/ApiController.php b/airtime_mvc/application/controllers/ApiController.php index 0bc07cdd1..80429db08 100644 --- a/airtime_mvc/application/controllers/ApiController.php +++ b/airtime_mvc/application/controllers/ApiController.php @@ -1309,7 +1309,7 @@ class ApiController extends Zend_Controller_Action } public function getStreamParametersAction() { - $streams = array("s1", "s2", "s3"); + $streams = array("s1", "s2", "s3", "s4"); $stream_params = array(); foreach ($streams as $s) { $stream_params[$s] = diff --git a/airtime_mvc/application/controllers/PreferenceController.php b/airtime_mvc/application/controllers/PreferenceController.php index 219e35e01..b06a9e1ed 100644 --- a/airtime_mvc/application/controllers/PreferenceController.php +++ b/airtime_mvc/application/controllers/PreferenceController.php @@ -141,11 +141,7 @@ class PreferenceController extends Zend_Controller_Action $this->view->headScript()->appendFile($baseUrl.'js/airtime/preferences/streamsetting.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); // get current settings - $temp = Application_Model_StreamSetting::getStreamSetting(); - $setting = array(); - foreach ($temp as $t) { - $setting[$t['keyname']] = $t['value']; - } + $setting = Application_Model_StreamSetting::getStreamSetting(); $name_map = array( 'ogg' => 'Ogg Vorbis', @@ -208,6 +204,7 @@ class PreferenceController extends Zend_Controller_Action $s1_data = array(); $s2_data = array(); $s3_data = array(); + $s4_data = array(); $values = array(); foreach($postData as $k=>$v) { $v = explode('=', urldecode($v)); @@ -223,6 +220,9 @@ class PreferenceController extends Zend_Controller_Action } elseif (strpos($v[0], "s3_data") !== false) { preg_match('/\[(.*)\]/', $v[0], $matches); $s3_data[$matches[1]] = $v[1]; + } elseif (strpos($v[0], "s4_data") !== false) { + preg_match('/\[(.*)\]/', $v[0], $matches); + $s4_data[$matches[1]] = $v[1]; } else { $values[$v[0]] = $v[1]; } @@ -230,6 +230,7 @@ class PreferenceController extends Zend_Controller_Action $values["s1_data"] = $s1_data; $values["s2_data"] = $s2_data; $values["s3_data"] = $s3_data; + $values["s4_data"] = $s4_data; $error = false; if ($form->isValid($values)) { @@ -245,6 +246,7 @@ class PreferenceController extends Zend_Controller_Action $s1_set_admin_pass = !empty($values["s1_data"]["admin_pass"]); $s2_set_admin_pass = !empty($values["s2_data"]["admin_pass"]); $s3_set_admin_pass = !empty($values["s3_data"]["admin_pass"]); + $s4_set_admin_pass = !empty($values["s4_data"]["admin_pass"]); // this goes into cc_pref table Application_Model_Preference::SetStreamLabelFormat($values['streamFormat']); @@ -290,6 +292,7 @@ class PreferenceController extends Zend_Controller_Action "s1_set_admin_pass"=>$s1_set_admin_pass, "s2_set_admin_pass"=>$s2_set_admin_pass, "s3_set_admin_pass"=>$s3_set_admin_pass, + "s4_set_admin_pass"=>$s4_set_admin_pass, )); } else { $live_stream_subform->updateVariables(); @@ -441,7 +444,8 @@ class PreferenceController extends Zend_Controller_Action public function getAdminPasswordStatusAction() { $out = array(); - for ($i=1; $i<=3; $i++) { + $num_of_stream = intval(Application_Model_Preference::GetNumOfStreams()); + for ($i=1; $i<=$num_of_stream; $i++) { if (Application_Model_StreamSetting::getAdminPass('s'.$i)=='') { $out["s".$i] = false; } else { diff --git a/airtime_mvc/application/models/StreamSetting.php b/airtime_mvc/application/models/StreamSetting.php index 49ec7a072..a85fad988 100644 --- a/airtime_mvc/application/models/StreamSetting.php +++ b/airtime_mvc/application/models/StreamSetting.php @@ -1,4 +1,7 @@ prepare($sql); - - if ($stmt->execute()) { - $rows = $stmt->fetchAll(); - } else { - $msg = implode(',', $stmt->errorInfo()); - throw new Exception("Error: $msg"); - } + $rows = CcStreamSettingQuery::create() + ->filterByDbKeyName("${p_streamId}_%") + ->find(); + //This is way too much code because someone made only stupid decisions about how + //the layout of this table worked. The git history doesn't lie. $data = array(); - foreach ($rows as $row) { - $data[$row["keyname"]] = $row["value"]; + $key = $row->getDbKeyName(); + $value = $row->getDbValue(); + $type = $row->getDbType(); + //Fix stupid defaults so we end up with proper typing in our JSON + if ($row->getDbType() == "boolean") { + if (empty($value)) { + //In Python, there is no way to tell the difference between ints and booleans, + //which we need to differentiate between for when we're generating the Liquidsoap + //config file. Returning booleans as a string is a workaround that lets us do that. + $value = "false"; + } + $data[$key] = $value; + } + elseif ($row->getDbType() == "integer") { + if (empty($value)) { + $value = 0; + } + $data[$key] = intval($value); + } + else { + $data[$key] = $value; + } } + //Add in defaults in case they don't exist in the database. + $keyPrefix = $p_streamId . '_'; + self::ensureKeyExists($keyPrefix . 'admin_pass', $data); + self::ensureKeyExists($keyPrefix . 'admin_user', $data); + self::ensureKeyExists($keyPrefix . 'bitrate', $data, 128); + self::ensureKeyExists($keyPrefix . 'channels', $data, "stereo"); + self::ensureKeyExists($keyPrefix . 'description', $data); + self::ensureKeyExists($keyPrefix . 'enable', $data, "false"); + self::ensureKeyExists($keyPrefix . 'genre', $data); + self::ensureKeyExists($keyPrefix . 'host', $data); + self::ensureKeyExists($keyPrefix . 'liquidsoap_error', $data, "waiting"); + self::ensureKeyExists($keyPrefix . 'mount', $data); + self::ensureKeyExists($keyPrefix . 'name', $data); + self::ensureKeyExists($keyPrefix . 'output', $data); + self::ensureKeyExists($keyPrefix . 'pass', $data); + self::ensureKeyExists($keyPrefix . 'port', $data, 8000); + self::ensureKeyExists($keyPrefix . 'type', $data); + self::ensureKeyExists($keyPrefix . 'url', $data); + self::ensureKeyExists($keyPrefix . 'user', $data); + return $data; } @@ -169,76 +184,41 @@ class Application_Model_StreamSetting * make data easier to iterate over */ public static function getStreamDataNormalized($p_streamId) { - $con = Propel::getConnection(); - $streamId = pg_escape_string($p_streamId); - $sql = "SELECT * " - ."FROM cc_stream_setting " - ."WHERE keyname LIKE '{$streamId}_%'"; - - $stmt = $con->prepare($sql); - - if ($stmt->execute()) { - $rows = $stmt->fetchAll(); - } else { - $msg = implode(',', $stmt->errorInfo()); - throw new Exception("Error: $msg"); + $settings = self::getStreamData($p_streamId); + foreach ($settings as $key => $value) + { + unset($settings[$key]); + $newKey = substr($key, strlen($p_streamId)+1); //$p_streamId is assumed to be the key prefix. + $settings[$newKey] = $value; } + return $settings; + } - $data = array(); - - foreach ($rows as $row) { - list($id, $key) = explode("_", $row["keyname"], 2); - $data[$key] = $row["value"]; + private static function ensureKeyExists($key, &$array, $default='') + { + if (!array_key_exists($key, $array)) { + $array[$key] = $default; } - - return $data; + return $array; } public static function getStreamSetting() { - $con = Propel::getConnection(); - $sql = "SELECT *" - ." FROM cc_stream_setting" - ." WHERE keyname not like '%_error' AND keyname not like '%_admin_%'"; - - $rows = Application_Common_Database::prepareAndExecute($sql, array(), 'all'); - - $exists = array(); - - foreach ($rows as $r) { - if ($r['keyname'] == 'master_live_stream_port') { - $exists['master_live_stream_port'] = true; - } elseif ($r['keyname'] == 'master_live_stream_mp') { - $exists['master_live_stream_mp'] = true; - } elseif ($r['keyname'] == 'dj_live_stream_port') { - $exists['dj_live_stream_port'] = true; - } elseif ($r['keyname'] == 'dj_live_stream_mp') { - $exists['dj_live_stream_mp'] = true; - } + $settings = array(); + $numStreams = MAX_NUM_STREAMS; + for ($streamIdx = 1; $streamIdx <= $numStreams; $streamIdx++) + { + $settings = array_merge($settings, self::getStreamData("s" . $streamIdx)); } - - if (!isset($exists["master_live_stream_port"])) { - $rows[] = array("keyname" =>"master_live_stream_port", - "value"=>self::getMasterLiveStreamPort(), - "type"=>"integer"); - } - if (!isset($exists["master_live_stream_mp"])) { - $rows[] = array("keyname" =>"master_live_stream_mp", - "value"=>self::getMasterLiveStreamMountPoint(), - "type"=>"string"); - } - if (!isset($exists["dj_live_stream_port"])) { - $rows[] = array("keyname" =>"dj_live_stream_port", - "value"=>self::getDjLiveStreamPort(), - "type"=>"integer"); - } - if (!isset($exists["dj_live_stream_mp"])) { - $rows[] = array("keyname" =>"dj_live_stream_mp", - "value"=>self::getDjLiveStreamMountPoint(), - "type"=>"string"); - } - - return $rows; + $settings["master_live_stream_port"] = self::getMasterLiveStreamPort(); + $settings["master_live_stream_mp"] = self::getMasterLiveStreamMountPoint(); + $settings["dj_live_stream_port"] = self::getDjLiveStreamPort(); + $settings["dj_live_stream_mp"] = self::getDjLiveStreamMountPoint(); + $settings["off_air_meta"] = self::getOffAirMeta(); + $settings["icecast_vorbis_metadata"] = self::getIcecastVorbisMetadata(); + $settings["output_sound_device"] = self::getOutputSoundDevice(); + $settings["output_sound_device_type"] = self::getOutputSoundDeviceType(); + return $settings; } @@ -246,7 +226,10 @@ class Application_Model_StreamSetting { $stream_setting = CcStreamSettingQuery::create()->filterByDbKeyName($key)->findOne(); if (is_null($stream_setting)) { - throw new Exception("Keyname $key does not exist!"); + //throw new Exception("Keyname $key does not exist!"); + $stream_setting = new CcStreamSetting(); + $stream_setting->setDbKeyName($key); + $stream_setting->setDbType(""); } $stream_setting->setDbValue($value); @@ -446,7 +429,7 @@ class Application_Model_StreamSetting public static function getMasterLiveStreamPort() { - return self::getValue("master_live_stream_port"); + return self::getValue("master_live_stream_port", 8001); } public static function setMasterLiveStreamMountPoint($value) @@ -456,7 +439,7 @@ class Application_Model_StreamSetting public static function getMasterLiveStreamMountPoint() { - return self::getValue("master_live_stream_mp"); + return self::getValue("master_live_stream_mp", "/master"); } public static function setDjLiveStreamPort($value) @@ -466,7 +449,7 @@ class Application_Model_StreamSetting public static function getDjLiveStreamPort() { - return self::getValue("dj_live_stream_port"); + return self::getValue("dj_live_stream_port", 8001); } public static function setDjLiveStreamMountPoint($value) @@ -476,7 +459,7 @@ class Application_Model_StreamSetting public static function getDjLiveStreamMountPoint() { - return self::getValue("dj_live_stream_mp"); + return self::getValue("dj_live_stream_mp", "/show"); } public static function getAdminUser($stream){ @@ -523,4 +506,16 @@ class Application_Model_StreamSetting public static function SetListenerStatError($key, $v) { self::setValue($key, $v, 'string'); } + + public static function getIcecastVorbisMetadata() { + return self::getValue("icecast_vorbis_metadata", ""); + } + + public static function getOutputSoundDevice() { + return self::getValue("output_sound_device", "false"); + } + + public static function getOutputSoundDeviceType() { + return self::getValue("output_sound_device_type", ""); + } } diff --git a/airtime_mvc/build/sql/defaultdata.sql b/airtime_mvc/build/sql/defaultdata.sql index 3c1a60752..438dfc979 100644 --- a/airtime_mvc/build/sql/defaultdata.sql +++ b/airtime_mvc/build/sql/defaultdata.sql @@ -358,3 +358,21 @@ INSERT INTO cc_pref (subjid, keystr, valstr) VALUES (1, 'user_timezone', 'UTC'); INSERT INTO cc_pref (keystr, valstr) VALUES ('import_timestamp', '0'); --end added in 2.5.2 + +INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_enable', 'false', 'boolean'); +INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_output', 'icecast', 'string'); +INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_name', '', 'string'); +INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_type', '', 'string'); +INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_bitrate', '', 'integer'); +INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_host', '', 'string'); +INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_port', '', 'integer'); +INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_user', '', 'string'); +INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_pass', '', 'string'); +INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_admin_user', '', 'string'); +INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_admin_pass', '', 'string'); +INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_mount', '', 'string'); +INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_url', '', 'string'); +INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_description', '', 'string'); +INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_genre', '', 'string'); +INSERT INTO cc_stream_setting (keyname, value, type) VALUES ('s4_channels', 'stereo', 'string'); + diff --git a/airtime_mvc/public/js/airtime/preferences/streamsetting.js b/airtime_mvc/public/js/airtime/preferences/streamsetting.js index 7529783a0..0fd0cd90a 100644 --- a/airtime_mvc/public/js/airtime/preferences/streamsetting.js +++ b/airtime_mvc/public/js/airtime/preferences/streamsetting.js @@ -443,7 +443,7 @@ function setSliderForReplayGain(){ $( "#replayGainModifier" ).val( $( "#slider-range-max" ).slider( "value" ) ); } -function setPseudoAdminPassword(s1, s2, s3) { +function setPseudoAdminPassword(s1, s2, s3, s4) { if (s1) { $('#s1_data-admin_pass').val('xxxxxx'); } @@ -453,11 +453,14 @@ function setPseudoAdminPassword(s1, s2, s3) { if (s3) { $('#s3_data-admin_pass').val('xxxxxx'); } + if (s4) { + $('#s4_data-admin_pass').val('xxxxxx'); + } } function getAdminPasswordStatus() { $.ajax({ url: baseUrl+'Preference/get-admin-password-status/format/json', dataType:"json", success:function(data){ - setPseudoAdminPassword(data.s1, data.s2, data.s3); + setPseudoAdminPassword(data.s1, data.s2, data.s3, data.s4); }}); } @@ -476,7 +479,7 @@ $(document).ready(function() { $('#content').empty().append(json.html); setupEventListeners(); setSliderForReplayGain(); - setPseudoAdminPassword(json.s1_set_admin_pass, json.s2_set_admin_pass, json.s3_set_admin_pass); + setPseudoAdminPassword(json.s1_set_admin_pass, json.s2_set_admin_pass, json.s3_set_admin_pass, json.s4_set_admin_pass); }); } }); diff --git a/python_apps/pypo/liquidsoap_scripts/generate_liquidsoap_cfg.py b/python_apps/pypo/liquidsoap_scripts/generate_liquidsoap_cfg.py index 45bdb46f4..ec5d10cc3 100644 --- a/python_apps/pypo/liquidsoap_scripts/generate_liquidsoap_cfg.py +++ b/python_apps/pypo/liquidsoap_scripts/generate_liquidsoap_cfg.py @@ -10,18 +10,23 @@ def generate_liquidsoap_config(ss): fh.write("################################################\n") fh.write("# THIS FILE IS AUTO GENERATED. DO NOT CHANGE!! #\n") fh.write("################################################\n") + fh.write("# The ignore() lines are to squash unused variable warnings\n") - for d in data: - key = d['keyname'] + for key, value in data.iteritems(): + try: + str_buffer = "%s = %s\n" % (key, int(value)) + except ValueError: + try: # Is it a boolean? + if "true" in value or "false" in value: + str_buffer = "%s = %s\n" % (key, value.lower()) + else: + raise ValueError() # Just drop into the except below + except: #Everything else is a string + str_buffer = "%s = \"%s\"\n" % (key, value) - str_buffer = d[u'keyname'] + " = " - if d[u'type'] == 'string': - val = '"%s"' % d['value'] - else: - val = d[u'value'] - val = val if len(val) > 0 else "0" - str_buffer = "%s = %s\n" % (key, val) fh.write(str_buffer.encode('utf-8')) + # ignore squashes unused variable errors from Liquidsoap + fh.write(("ignore(%s)\n" % key).encode('utf-8')) fh.write('log_file = "/var/log/airtime/pypo-liquidsoap/