From 5bf62dd9cb5627b31b3f908f0885811168bdb6e7 Mon Sep 17 00:00:00 2001 From: jo Date: Tue, 6 Sep 2022 12:00:50 +0200 Subject: [PATCH] feat(legacy): read stream config from file - We don't delete the stream preferences from the database to prevent data loss. This will be handled in a future release. --- .../legacy/migrations/sql/data.sql | 5 - legacy/application/configs/conf.php | 118 +++++ .../controllers/PreferenceController.php | 129 +---- .../forms/LiveStreamingPreferences.php | 75 +-- legacy/application/forms/StreamSetting.php | 113 ++--- .../forms/StreamSettingSubForm.php | 214 +++----- legacy/application/models/ListenerStat.php | 23 - legacy/application/models/Preference.php | 115 +---- legacy/application/models/StreamSetting.php | 467 +++++------------- .../scripts/dashboard/stream-player.phtml | 4 +- .../scripts/form/preferences_livestream.phtml | 18 +- .../scripts/form/stream-setting-form.phtml | 254 ++++------ .../scripts/preference/stream-setting.phtml | 36 +- .../js/airtime/preferences/streamsetting.js | 164 +----- 14 files changed, 498 insertions(+), 1237 deletions(-) diff --git a/api/libretime_api/legacy/migrations/sql/data.sql b/api/libretime_api/legacy/migrations/sql/data.sql index 6e7e7f2aa..d0a272a5d 100644 --- a/api/libretime_api/legacy/migrations/sql/data.sql +++ b/api/libretime_api/legacy/migrations/sql/data.sql @@ -7,18 +7,13 @@ INSERT INTO cc_live_log ("state", "start_time") VALUES ('S', now() at time zone INSERT INTO cc_pref ("keystr", "valstr") VALUES ('import_timestamp', '0'); INSERT INTO cc_pref ("keystr", "valstr") VALUES ('timezone', 'UTC'); -INSERT INTO cc_pref ("keystr", "valstr") VALUES ('default_stream_mount_point', 'main'); INSERT INTO cc_pref ("keystr", "valstr") VALUES ('off_air_meta', 'LibreTime - offline'); INSERT INTO cc_pref ("keystr", "valstr") VALUES ('enable_replay_gain', 1); INSERT INTO cc_pref ("keystr", "valstr") VALUES ('locale', 'en_US'); -INSERT INTO cc_pref ("keystr", "valstr") VALUES ('max_bitrate', '320'); -INSERT INTO cc_pref ("keystr", "valstr") VALUES ('num_of_streams', '3'); INSERT INTO cc_pref ("keystr", "valstr") VALUES ('plan_level', 'disabled'); INSERT INTO cc_pref ("keystr", "valstr") VALUES ('podcast_album_override', 1); INSERT INTO cc_pref ("keystr", "valstr") VALUES ('podcast_auto_smartblock', 0); INSERT INTO cc_pref ("keystr", "valstr") VALUES ('scheduled_play_switch', 'on'); -INSERT INTO cc_pref ("keystr", "valstr") VALUES ('stream_bitrate', '24, 32, 48, 64, 96, 128, 160, 192, 224, 256, 320'); -INSERT INTO cc_pref ("keystr", "valstr") VALUES ('stream_type', 'ogg, mp3, opus, aac'); INSERT INTO cc_pref ("keystr", "valstr") VALUES ('whats_new_dialog_viewed', 1); INSERT INTO cc_subjs ("login", "type", "pass") VALUES ('admin', 'A', md5('admin')); diff --git a/legacy/application/configs/conf.php b/legacy/application/configs/conf.php index 45507969b..252a6dcfd 100644 --- a/legacy/application/configs/conf.php +++ b/legacy/application/configs/conf.php @@ -23,6 +23,10 @@ class Schema implements ConfigurationInterface return rtrim($v, '/') . '/'; }; + $trim_leading_slash = function ($v) { + return ltrim($v, '/'); + }; + $treeBuilder = new TreeBuilder(''); $treeBuilder->getRootNode() ->children() @@ -89,6 +93,111 @@ class Schema implements ConfigurationInterface /**/->ignoreExtraKeys() ->end() + // Stream schema + ->arrayNode('stream')->ignoreExtraKeys()->addDefaultsIfNotSet()->children() + + // Stream inputs + ->arrayNode('inputs')->addDefaultsIfNotSet()->children() + /**/->arrayNode('main')->addDefaultsIfNotSet()->children() + /* */->booleanNode('enabled')->defaultTrue()->end() + /* */->enumNode('kind')->values(['harbor'])->defaultValue('harbor')->end() + /* */->scalarNode('public_url')->end() + /* */->scalarNode('mount')->defaultValue("main") + /* */->validate()->ifString()->then($trim_leading_slash)->end() + /* */->end() + /* */->integerNode('port')->defaultValue(8001)->end() + /**/->end()->end() + /**/->arrayNode('show')->addDefaultsIfNotSet()->children() + /* */->booleanNode('enabled')->defaultTrue()->end() + /* */->enumNode('kind')->values(['harbor'])->defaultValue('harbor')->end() + /* */->scalarNode('public_url')->end() + /* */->scalarNode('mount')->defaultValue("show") + /* */->validate()->ifString()->then($trim_leading_slash)->end() + /* */->end() + /* */->integerNode('port')->defaultValue(8002)->end() + /**/->end()->end() + ->end()->end() + + // Stream outputs + ->arrayNode('outputs')->ignoreExtraKeys()->addDefaultsIfNotSet()->children() + + // Icecast outputs + /**/->arrayNode('icecast')->arrayPrototype()->children() + /* */->booleanNode('enabled')->defaultFalse()->end() + /* */->enumNode('kind')->values(['icecast'])->defaultValue('icecast')->end() + /* */->scalarNode('public_url')->end() + /* */->scalarNode('host')->defaultValue('localhost')->end() + /* */->integerNode('port')->defaultValue(8000)->end() + /* */->scalarNode('mount')->cannotBeEmpty() + /* */->validate()->ifString()->then($trim_leading_slash)->end() + /* */->end() + /* */->scalarNode('source_user')->defaultValue('source')->end() + /* */->scalarNode('source_password')->cannotBeEmpty()->end() + /* */->scalarNode('admin_user')->defaultValue('admin')->end() + /* */->scalarNode('admin_password')->end() + /* */->arrayNode('audio')->addDefaultsIfNotSet()->children() + /* */->scalarNode('channels')->defaultValue('stereo') + /* */->validate()->ifNotInArray(['stereo', 'mono']) + /* */->thenInvalid('invalid stream.outputs.icecast.audio.channels %s') + /* */->end() + /* */->end() + /* */->scalarNode('format')->cannotBeEmpty() + /* */->validate()->ifNotInArray(['aac', 'mp3', 'ogg', 'opus']) + /* */->thenInvalid('invalid stream.outputs.icecast.audio.format %s') + /* */->end() + /* */->end() + /* */->integerNode('bitrate')->isRequired()->end() + /* */->booleanNode('enable_metadata')->defaultFalse()->end() + /* */->end()->end() + /* */->scalarNode('name')->end() + /* */->scalarNode('description')->end() + /* */->scalarNode('website')->end() + /* */->scalarNode('genre')->end() + /**/->end()->end()->end() + + // Shoutcast outputs + /**/->arrayNode('shoutcast')->arrayPrototype()->children() + /* */->booleanNode('enabled')->defaultFalse()->end() + /* */->enumNode('kind')->values(['shoutcast'])->defaultValue('shoutcast')->end() + /* */->scalarNode('public_url')->end() + /* */->scalarNode('host')->defaultValue('localhost')->end() + /* */->integerNode('port')->defaultValue(8000)->end() + /* */->scalarNode('source_user')->defaultValue('source')->end() + /* */->scalarNode('source_password')->cannotBeEmpty()->end() + /* */->scalarNode('admin_user')->defaultValue('admin')->end() + /* */->scalarNode('admin_password')->end() + /* */->arrayNode('audio')->addDefaultsIfNotSet()->children() + /* */->scalarNode('channels')->defaultValue('stereo') + /* */->validate()->ifNotInArray(['stereo', 'mono']) + /* */->thenInvalid('invalid stream.outputs.shoutcast.audio.channels %s') + /* */->end() + /* */->end() + /* */->scalarNode('format')->cannotBeEmpty() + /* */->validate()->ifNotInArray(['aac', 'mp3']) + /* */->thenInvalid('invalid stream.outputs.shoutcast.audio.format %s') + /* */->end() + /* */->end() + /* */->integerNode('bitrate')->isRequired()->end() + /* */->end()->end() + /* */->scalarNode('name')->end() + /* */->scalarNode('website')->end() + /* */->scalarNode('genre')->end() + /**/->end()->end()->end() + + // System outputs + /**/->arrayNode('system')->arrayPrototype()->children() + /* */->booleanNode('enabled')->defaultFalse()->end() + /* */->scalarNode('kind')->defaultValue('alsa') + /* */->validate()->ifNotInArray(["alsa", "ao", "oss", "portaudio", "pulseaudio"]) + /* */->thenInvalid('invalid stream.outputs.system.kind %s') + /* */->end()->end() + /**/->end()->end()->end() + + ->end()->end() + + // END Stream schema + ->end()->end() + // END Schema ->end(); @@ -138,6 +247,12 @@ class Config exit; } + // Merge Icecast and Shoutcast outputs + $values['stream']['outputs']['merged'] = array_merge( + $values['stream']['outputs']['icecast'], + $values['stream']['outputs']['shoutcast'] + ); + self::$values = $values; self::fillLegacyValues($values); self::$dot_values = new Dot($values); @@ -237,6 +352,9 @@ class Config // Storage $legacy_values['storagePath'] = $values['storage']['path']; + // Stream + $legacy_values['stream'] = $values['stream']; + // Facebook (DEPRECATED) if (isset($values['facebook']['facebook_app_id'])) { $legacy_values['facebook-app-id'] = $values['facebook']['facebook_app_id']; diff --git a/legacy/application/controllers/PreferenceController.php b/legacy/application/controllers/PreferenceController.php index 11a7d62ac..278340ca0 100644 --- a/legacy/application/controllers/PreferenceController.php +++ b/legacy/application/controllers/PreferenceController.php @@ -13,7 +13,6 @@ 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') ->addActionContext('get-admin-password-status', 'json') ->initContext(); } @@ -162,28 +161,6 @@ class PreferenceController extends Zend_Controller_Action $live_stream_subform = new Application_Form_LiveStreamingPreferences(); $form->addSubForm($live_stream_subform, 'live_stream_subform'); - // get predefined type and bitrate from pref table - $temp_types = Application_Model_Preference::GetStreamType(); - $stream_types = []; - foreach ($temp_types as $type) { - $type = strtolower(trim($type)); - if (isset($name_map[$type])) { - $name = $name_map[$type]; - } else { - $name = $type; - } - $stream_types[$type] = $name; - } - - $temp_bitrate = Application_Model_Preference::GetStreamBitrate(); - $max_bitrate = intval(Application_Model_Preference::GetMaxBitrate()); - $stream_bitrates = []; - foreach ($temp_bitrate as $type) { - if (intval($type) <= $max_bitrate) { - $stream_bitrates[trim($type)] = strtoupper(trim($type)) . ' kbit/s'; - } - } - // get current settings $setting = Application_Model_StreamSetting::getStreamSetting(); $form->setSetting($setting); @@ -192,10 +169,7 @@ class PreferenceController extends Zend_Controller_Action $subform = new Application_Form_StreamSettingSubForm(); $subform->setPrefix($i); $subform->setSetting($setting); - $subform->setStreamTypes($stream_types); - $subform->setStreamBitrates($stream_bitrates); $subform->startForm(); - $subform->toggleState(); $form->addSubForm($subform, 's' . $i . '_subform'); } @@ -208,48 +182,14 @@ class PreferenceController extends Zend_Controller_Action * $form->isValid() is expecting it in */ $postData = explode('&', $params['data']); - $s1_data = []; - $s2_data = []; - $s3_data = []; - $s4_data = []; $values = []; + foreach ($postData as $k => $v) { $v = explode('=', urldecode($v)); - if (strpos($v[0], 's1_data') !== false) { - /* In this case $v[0] may be 's1_data[enable]' , for example. - * We only want the 'enable' part - */ - preg_match('/\[(.*)\]/', $v[0], $matches); - $s1_data[$matches[1]] = $v[1]; - } elseif (strpos($v[0], 's2_data') !== false) { - preg_match('/\[(.*)\]/', $v[0], $matches); - $s2_data[$matches[1]] = $v[1]; - } 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]; - } + $values[$v[0]] = $v[1]; } - $values['s1_data'] = $s1_data; - $values['s2_data'] = $s2_data; - $values['s3_data'] = $s3_data; - $values['s4_data'] = $s4_data; if ($form->isValid($values)) { - Application_Model_StreamSetting::setStreamSetting($values); - - /* If the admin password values are empty then we should not - * set the pseudo password ('xxxxxx') on the front-end - */ - $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 $this->setStreamPreferences($values); @@ -264,47 +204,9 @@ class PreferenceController extends Zend_Controller_Action // Application_Model_RabbitMq::PushSchedule(); } - // pulling this from the 2.5.x branch - if (!Application_Model_Preference::GetMasterDjConnectionUrlOverride()) { - $master_connection_url = 'http://' . $_SERVER['SERVER_NAME'] . ':' . $values['master_source_port'] . $values['master_source_mount']; - if (empty($values['master_source_port']) || empty($values['master_source_mount'])) { - Application_Model_Preference::SetMasterDJSourceConnectionURL('N/A'); - } else { - Application_Model_Preference::SetMasterDJSourceConnectionURL($master_connection_url); - } - } else { - Application_Model_Preference::SetMasterDJSourceConnectionURL($values['master_source_host']); - } - - if (!Application_Model_Preference::GetLiveDjConnectionUrlOverride()) { - $live_connection_url = 'http://' . $_SERVER['SERVER_NAME'] . ':' . $values['show_source_port'] . $values['show_source_mount']; - if (empty($values['show_source_port']) || empty($values['show_source_mount'])) { - Application_Model_Preference::SetLiveDJSourceConnectionURL('N/A'); - } else { - Application_Model_Preference::SetLiveDJSourceConnectionURL($live_connection_url); - } - } else { - Application_Model_Preference::SetLiveDJSourceConnectionURL($values['show_source_host']); - } - - Application_Model_StreamSetting::setMasterLiveStreamPort($values['master_source_port']); - Application_Model_StreamSetting::setMasterLiveStreamMountPoint($values['master_source_mount']); - Application_Model_StreamSetting::setDjLiveStreamPort($values['show_source_port']); - Application_Model_StreamSetting::setDjLiveStreamMountPoint($values['show_source_mount']); - - Application_Model_Preference::setOffAirMeta($values['offAirMeta']); - // store stream update timestamp Application_Model_Preference::SetStreamUpdateTimestamp(); - $data = []; - $info = Application_Model_StreamSetting::getStreamSetting(); - $data['setting'] = $info; - for ($i = 1; $i <= $num_of_stream; ++$i) { - Application_Model_Preference::setLiquidsoapError($i, 'waiting'); - } - - Application_Model_RabbitMq::SendMessageToPypo('update_stream_setting', $data); $this->view->statusMsg = "
" . _('Stream Setting Updated.') . '
'; } } @@ -312,15 +214,12 @@ class PreferenceController extends Zend_Controller_Action $this->view->num_stream = $num_of_stream; $this->view->enable_stream_conf = Application_Model_Preference::GetEnableStreamConf(); $this->view->form = $form; + if ($request->isPost()) { if ($form->isValid($values)) { $this->_helper->json->sendJson([ 'valid' => 'true', 'html' => $this->view->render('preference/stream-setting.phtml'), - '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 { $this->_helper->json->sendJson(['valid' => 'false', 'html' => $this->view->render('preference/stream-setting.phtml')]); @@ -335,7 +234,7 @@ class PreferenceController extends Zend_Controller_Action */ private function setStreamPreferences($values) { - Application_Model_Preference::setUsingCustomStreamSettings($values['customStreamSettings']); + Application_Model_Preference::setOffAirMeta($values['offAirMeta']); Application_Model_Preference::SetStreamLabelFormat($values['streamFormat']); Application_Model_Preference::SetLiveStreamMasterUsername($values['master_username']); Application_Model_Preference::SetLiveStreamMasterPassword($values['master_password']); @@ -405,26 +304,6 @@ class PreferenceController extends Zend_Controller_Action $this->_helper->json->sendJson($out); } - public function setSourceConnectionUrlAction() - { - SessionHelper::reopenSessionForWriting(); - - $request = $this->getRequest(); - $type = $request->getParam('type', null); - $url = urldecode($request->getParam('url', null)); - $override = $request->getParam('override', false); - - if ($type == 'masterdj') { - Application_Model_Preference::SetMasterDJSourceConnectionURL($url); - Application_Model_Preference::SetMasterDjConnectionUrlOverride($override); - } elseif ($type == 'livedj') { - Application_Model_Preference::SetLiveDJSourceConnectionURL($url); - Application_Model_Preference::SetLiveDjConnectionUrlOverride($override); - } - - $this->_helper->json->sendJson(null); - } - public function getAdminPasswordStatusAction() { SessionHelper::reopenSessionForWriting(); diff --git a/legacy/application/forms/LiveStreamingPreferences.php b/legacy/application/forms/LiveStreamingPreferences.php index 69fe75178..a028a35c4 100644 --- a/legacy/application/forms/LiveStreamingPreferences.php +++ b/legacy/application/forms/LiveStreamingPreferences.php @@ -4,9 +4,6 @@ class Application_Form_LiveStreamingPreferences extends Zend_Form_SubForm { public function init() { - $CC_CONFIG = Config::getConfig(); - $isDemo = isset($CC_CONFIG['demo']) && $CC_CONFIG['demo'] == 1; - $defaultFade = Application_Model_Preference::GetDefaultTransitionFade(); $this->setDecorators([ @@ -46,13 +43,9 @@ class Application_Form_LiveStreamingPreferences extends Zend_Form_SubForm $this->addElement($master_username); // Master password - if ($isDemo) { - $master_password = new Zend_Form_Element_Text('master_password'); - } else { - $master_password = new Zend_Form_Element_Password('master_password'); - $master_password->setAttrib('renderPassword', 'true'); - } - $master_password->setAttrib('autocomplete', 'off') + $master_password = new Zend_Form_Element_Password('master_password'); + $master_password + ->setAttrib('autocomplete', 'off') ->setAttrib('renderPassword', 'true') ->setAllowEmpty(true) ->setValue(Application_Model_Preference::GetLiveStreamMasterPassword()) @@ -60,74 +53,53 @@ class Application_Form_LiveStreamingPreferences extends Zend_Form_SubForm ->setFilters(['StringTrim']); $this->addElement($master_password); - $masterSourceParams = parse_url(Application_Model_Preference::GetMasterDJSourceConnectionURL()); - // Master source connection url parameters $masterSourceHost = new Zend_Form_Element_Text('master_source_host'); - $masterSourceHost->setLabel(_('Master Source Host:')) + $masterSourceHost + ->setLabel(_('Master Source Host:')) ->setAttrib('readonly', true) ->setValue(Application_Model_Preference::GetMasterDJSourceConnectionURL()); $this->addElement($masterSourceHost); - // liquidsoap harbor.input port - $betweenValidator = Application_Form_Helper_ValidationTypes::overrideBetweenValidator(1024, 49151); - - $m_port = Application_Model_StreamSetting::getMasterLiveStreamPort(); - $masterSourcePort = new Zend_Form_Element_Text('master_source_port'); - $masterSourcePort->setLabel(_('Master Source Port:')) - ->setValue($m_port) - ->setValidators([$betweenValidator]) - ->addValidator('regex', false, ['pattern' => '/^[0-9]+$/', 'messages' => ['regexNotMatch' => _('Only numbers are allowed.')]]); - + $masterSourcePort + ->setLabel(_('Master Source Port:')) + ->setAttrib('readonly', true) + ->setValue(Application_Model_StreamSetting::getMasterLiveStreamPort()); $this->addElement($masterSourcePort); - $m_mount = Application_Model_StreamSetting::getMasterLiveStreamMountPoint(); $masterSourceMount = new Zend_Form_Element_Text('master_source_mount'); - $masterSourceMount->setLabel(_('Master Source Mount:')) - ->setValue($m_mount) - ->setValidators([ - ['regex', false, ['/^[^ &<>]+$/', 'messages' => _('Invalid character entered')]], - ]); + $masterSourceMount + ->setLabel(_('Master Source Mount:')) + ->setAttrib('readonly', true) + ->setValue(Application_Model_StreamSetting::getMasterLiveStreamMountPoint()); $this->addElement($masterSourceMount); - $showSourceParams = parse_url(Application_Model_Preference::GetLiveDJSourceConnectionURL()); - // Show source connection url parameters $showSourceHost = new Zend_Form_Element_Text('show_source_host'); - $showSourceHost->setLabel(_('Show Source Host:')) + $showSourceHost + ->setLabel(_('Show Source Host:')) ->setAttrib('readonly', true) ->setValue(Application_Model_Preference::GetLiveDJSourceConnectionURL()); $this->addElement($showSourceHost); - // liquidsoap harbor.input port - $l_port = Application_Model_StreamSetting::getDjLiveStreamPort(); - $showSourcePort = new Zend_Form_Element_Text('show_source_port'); - $showSourcePort->setLabel(_('Show Source Port:')) - ->setValue($l_port) - ->setValidators([$betweenValidator]) - ->addValidator('regex', false, ['pattern' => '/^[0-9]+$/', 'messages' => ['regexNotMatch' => _('Only numbers are allowed.')]]); + $showSourcePort + ->setLabel(_('Show Source Port:')) + ->setAttrib('readonly', true) + ->setValue(Application_Model_StreamSetting::getDjLiveStreamPort()); $this->addElement($showSourcePort); - $l_mount = Application_Model_StreamSetting::getDjLiveStreamMountPoint(); $showSourceMount = new Zend_Form_Element_Text('show_source_mount'); - $showSourceMount->setLabel(_('Show Source Mount:')) - ->setValue($l_mount) - ->setValidators([ - ['regex', false, ['/^[^ &<>]+$/', 'messages' => _('Invalid character entered')]], - ]); + $showSourceMount + ->setLabel(_('Show Source Mount:')) + ->setAttrib('readonly', true) + ->setValue(Application_Model_StreamSetting::getDjLiveStreamMountPoint()); $this->addElement($showSourceMount); } public function updateVariables() { - $CC_CONFIG = Config::getConfig(); - - $isDemo = isset($CC_CONFIG['demo']) && $CC_CONFIG['demo'] == 1; - $masterSourceParams = parse_url(Application_Model_Preference::GetMasterDJSourceConnectionURL()); - $showSourceParams = parse_url(Application_Model_Preference::GetLiveDJSourceConnectionURL()); - $this->setDecorators( [ [ @@ -140,7 +112,6 @@ class Application_Form_LiveStreamingPreferences extends Zend_Form_SubForm 'show_source_host' => isset($showSourceHost) ? Application_Model_Preference::GetLiveDJSourceConnectionURL() : '', 'show_source_port' => isset($showSourcePort) ? Application_Model_StreamSetting::getDjLiveStreamPort() : '', 'show_source_mount' => isset($showSourceMount) ? Application_Model_StreamSetting::getDjLiveStreamMountPoint() : '', - 'isDemo' => $isDemo, ], ], ] diff --git a/legacy/application/forms/StreamSetting.php b/legacy/application/forms/StreamSetting.php index 44979f0b3..9cc9392eb 100644 --- a/legacy/application/forms/StreamSetting.php +++ b/legacy/application/forms/StreamSetting.php @@ -21,88 +21,55 @@ class Application_Form_StreamSetting extends Zend_Form $setting = $this->setting; + $stream_format = new Zend_Form_Element_Radio('streamFormat'); + $stream_format + ->setLabel(_('Stream Label:')) + ->setMultiOptions([ + _('Artist - Title'), + _('Show - Artist - Title'), + _('Station name - Show name'), + ]) + ->setValue(Application_Model_Preference::GetStreamLabelFormat()) + ->setDecorators(['ViewHelper']); + $this->addElement($stream_format); + + $offAirMeta = new Zend_Form_Element_Text('offAirMeta'); + $offAirMeta + ->setLabel(_('Off Air Metadata')) + ->setValue(Application_Model_Preference::getOffAirMeta()) + ->setDecorators(['ViewHelper']); + $this->addElement($offAirMeta); + + $enable_replay_gain = new Zend_Form_Element_Checkbox('enableReplayGain'); + $enable_replay_gain + ->setLabel(_('Enable Replay Gain')) + ->setValue(Application_Model_Preference::GetEnableReplayGain()) + ->setDecorators(['ViewHelper']); + $this->addElement($enable_replay_gain); + + $replay_gain = new Zend_Form_Element_Hidden('replayGainModifier'); + $replay_gain + ->setLabel(_('Replay Gain Modifier')) + ->setValue(Application_Model_Preference::getReplayGainModifier()) + ->setAttribs(['style' => 'border: 0; color: #f6931f; font-weight: bold;']) + ->setDecorators(['ViewHelper']); + $this->addElement($replay_gain); + $output_sound_device = new Zend_Form_Element_Checkbox('output_sound_device'); - $output_sound_device->setLabel(_('Hardware Audio Output:')) + $output_sound_device + ->setLabel(_('Hardware Audio Output:')) + ->setAttrib('readonly', true) ->setRequired(false) ->setValue(($setting['output_sound_device'] == 'true') ? 1 : 0) ->setDecorators(['ViewHelper']); $this->addElement($output_sound_device); $output_sound_device_type = new Zend_Form_Element_Select('output_sound_device_type'); - $output_sound_device_type->setLabel(_('Output Type')) - ->setMultiOptions([ - 'ALSA' => _('ALSA'), - 'AO' => _('AO'), - 'OSS' => _('OSS'), - 'Portaudio' => _('Portaudio'), - 'Pulseaudio' => _('Pulseaudio'), - 'Jack' => _('Jack'), - ]) + $output_sound_device_type + ->setLabel(_('Output Type')) + ->setAttrib('readonly', true) ->setValue(isset($setting['output_sound_device_type']) ? $setting['output_sound_device_type'] : 0) ->setDecorators(['ViewHelper']); $this->addElement($output_sound_device_type); - - $icecast_vorbis_metadata = new Zend_Form_Element_Checkbox('icecast_vorbis_metadata'); - $icecast_vorbis_metadata->setLabel(_('Icecast Vorbis Metadata')) - ->setRequired(false) - ->setValue(($setting['icecast_vorbis_metadata'] == 'true') ? 1 : 0) - ->setDecorators(['ViewHelper']); - if (Application_Model_Preference::GetEnableStreamConf() == 'false') { - $icecast_vorbis_metadata->setAttrib('readonly', true); - } - $this->addElement($icecast_vorbis_metadata); - - $stream_format = new Zend_Form_Element_Radio('streamFormat'); - $stream_format->setLabel(_('Stream Label:')); - $stream_format->setMultiOptions([ - _('Artist - Title'), - _('Show - Artist - Title'), - _('Station name - Show name'), - ]); - $stream_format->setValue(Application_Model_Preference::GetStreamLabelFormat()); - $stream_format->setDecorators(['ViewHelper']); - $this->addElement($stream_format); - - $offAirMeta = new Zend_Form_Element_Text('offAirMeta'); - $offAirMeta->setLabel(_('Off Air Metadata')) - ->setValue(Application_Model_Preference::getOffAirMeta()) - ->setDecorators(['ViewHelper']); - $this->addElement($offAirMeta); - - $enable_replay_gain = new Zend_Form_Element_Checkbox('enableReplayGain'); - $enable_replay_gain->setLabel(_('Enable Replay Gain')) - ->setValue(Application_Model_Preference::GetEnableReplayGain()) - ->setDecorators(['ViewHelper']); - $this->addElement($enable_replay_gain); - - $replay_gain = new Zend_Form_Element_Hidden('replayGainModifier'); - $replay_gain->setLabel(_('Replay Gain Modifier')) - ->setValue(Application_Model_Preference::getReplayGainModifier()) - ->setAttribs(['style' => 'border: 0; color: #f6931f; font-weight: bold;']) - ->setDecorators(['ViewHelper']); - $this->addElement($replay_gain); - - $custom = Application_Model_Preference::getUsingCustomStreamSettings(); - $customSettings = new Zend_Form_Element_Radio('customStreamSettings'); - $customSettings->setLabel(_('Streaming Server:')); - $customSettings->setMultiOptions([_('Default Streaming'), _('Custom / 3rd Party Streaming')]); - $customSettings->setValue(!empty($custom) ? $custom : 0); - $this->addElement($customSettings); - } - - public function isValid($data) - { - if (isset($data['output_sound_device'])) { - $d = []; - $d['output_sound_device'] = $data['output_sound_device']; - $d['icecast_vorbis_metadata'] = $data['icecast_vorbis_metadata']; - if (isset($data['output_sound_device_type'])) { - $d['output_sound_device_type'] = $data['output_sound_device_type']; - } - $d['streamFormat'] = $data['streamFormat']; - $this->populate($d); - } - - return parent::isValid($data); } } diff --git a/legacy/application/forms/StreamSettingSubForm.php b/legacy/application/forms/StreamSettingSubForm.php index 15aeb86a5..079ba0de5 100644 --- a/legacy/application/forms/StreamSettingSubForm.php +++ b/legacy/application/forms/StreamSettingSubForm.php @@ -4,8 +4,6 @@ class Application_Form_StreamSettingSubForm extends Zend_Form_SubForm { private $prefix; private $setting; - private $stream_types; - private $stream_bitrates; public static $customizable; @@ -23,171 +21,127 @@ class Application_Form_StreamSettingSubForm extends Zend_Form_SubForm $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; - - $streamDefaults = Application_Model_StreamSetting::getDefaults($prefix); - // If we're not using custom stream settings, use the defaults - $useDefaults = !Application_Model_Preference::getUsingCustomStreamSettings(); $this->setIsArray(true); $this->setElementsBelongTo($prefix . '_data'); $enable = new Zend_Form_Element_Checkbox('enable'); - $enable->setLabel(_('Enabled:')) + $enable + ->setLabel(_('Enabled:')) + ->setAttrib('disabled', true) ->setValue($setting[$prefix . '_enable'] == 'true' ? 1 : 0) ->setDecorators(['ViewHelper']); $this->addElement($enable); - static::$customizable[] = $enable->getName(); $mobile = new Zend_Form_Element_Checkbox('mobile'); - $mobile->setLabel(_('Mobile:')); - $mobile->setValue($setting[$prefix . '_mobile']); - $mobile->setDecorators(['ViewHelper']); + $mobile + ->setLabel(_('Mobile:')) + ->setAttrib('disabled', true) + ->setValue($setting[$prefix . '_mobile']) + ->setDecorators(['ViewHelper']); $this->addElement($mobile); - static::$customizable[] = $mobile->getName(); - $type = new Zend_Form_Element_Select('type'); - $type->setLabel(_('Stream Type:')) - ->setMultiOptions($stream_types) + $type = new Zend_Form_Element_Text('type'); + $type + ->setLabel(_('Stream Type:')) + ->setAttrib('readonly', true) ->setValue(isset($setting[$prefix . '_type']) ? $setting[$prefix . '_type'] : 0) ->setDecorators(['ViewHelper']); $this->addElement($type); - static::$customizable[] = $type->getName(); - $bitrate = new Zend_Form_Element_Select('bitrate'); - $bitrate->setLabel(_('Bit Rate:')) - ->setMultiOptions($stream_bitrates) + $bitrate = new Zend_Form_Element_Text('bitrate'); + $bitrate + ->setLabel(_('Bit Rate:')) + ->setAttrib('readonly', true) ->setValue(isset($setting[$prefix . '_bitrate']) ? $setting[$prefix . '_bitrate'] : 0) ->setDecorators(['ViewHelper']); $this->addElement($bitrate); - static::$customizable[] = $bitrate->getName(); - $output = new Zend_Form_Element_Select('output'); - $output->setLabel(_('Service Type:')) - ->setMultiOptions(['icecast' => 'Icecast', 'shoutcast' => 'SHOUTcast']) - ->setValue($useDefaults ? $streamDefaults['output'] : (isset($setting[$prefix . '_output']) ? $setting[$prefix . '_output'] : 'icecast')) + $output = new Zend_Form_Element_Text('output'); + $output + ->setLabel(_('Service Type:')) + ->setAttrib('readonly', true) + ->setValue((isset($setting[$prefix . '_output']) ? $setting[$prefix . '_output'] : 'icecast')) ->setDecorators(['ViewHelper']); $this->addElement($output); - $channels = new Zend_Form_Element_Select('channels'); - $channels->setLabel(_('Channels:')) - ->setMultiOptions(['mono' => _('1 - Mono'), 'stereo' => _('2 - Stereo')]) + $channels = new Zend_Form_Element_Text('channels'); + $channels + ->setLabel(_('Channels:')) + ->setAttrib('readonly', true) ->setValue(isset($setting[$prefix . '_channels']) ? $setting[$prefix . '_channels'] : 'stereo') ->setDecorators(['ViewHelper']); $this->addElement($channels); - static::$customizable[] = $channels->getName(); $host = new Zend_Form_Element_Text('host'); - $host->setLabel(_('Server')) - ->setValue($useDefaults ? $streamDefaults['host'] : (isset($setting[$prefix . '_host']) ? $setting[$prefix . '_host'] : '')) - ->setValidators([ - ['regex', false, ['/^[0-9a-zA-Z-_.]+$/', 'messages' => _('Invalid character entered')]], - ]) + $host + ->setLabel(_('Server')) + ->setAttrib('readonly', true) + ->setValue((isset($setting[$prefix . '_host']) ? $setting[$prefix . '_host'] : '')) ->setDecorators(['ViewHelper']); $host->setAttrib('alt', 'domain'); $this->addElement($host); $port = new Zend_Form_Element_Text('port'); - $port->setLabel(_('Port')) - ->setValue($useDefaults ? $streamDefaults['port'] : (isset($setting[$prefix . '_port']) ? $setting[$prefix . '_port'] : '')) - ->setValidators([new Zend_Validate_Between(['min' => 0, 'max' => 99999])]) - ->addValidator('regex', false, ['pattern' => '/^[0-9]+$/', 'messages' => ['regexNotMatch' => _('Only numbers are allowed.')]]) + $port + ->setLabel(_('Port')) + ->setAttrib('readonly', true) + ->setValue((isset($setting[$prefix . '_port']) ? $setting[$prefix . '_port'] : '')) ->setDecorators(['ViewHelper']); $this->addElement($port); - $pass = new Zend_Form_Element_Text('pass'); - $pass->setLabel(_('Password')) - ->setValue($useDefaults ? $streamDefaults['pass'] : (isset($setting[$prefix . '_pass']) ? $setting[$prefix . '_pass'] : '')) - ->setValidators([ - ['regex', false, ['/^[^ &<>]+$/', 'messages' => _('Invalid character entered')]], - ]) + $mount = new Zend_Form_Element_Text('mount'); + $mount + ->setLabel(_('Mount Point')) + ->setAttrib('readonly', true) + ->setValue((isset($setting[$prefix . '_mount']) ? $setting[$prefix . '_mount'] : '')) ->setDecorators(['ViewHelper']); - $pass->setAttrib('alt', 'regular_text'); - $this->addElement($pass); + $mount->setAttrib('alt', 'regular_text'); + $this->addElement($mount); + + $name = new Zend_Form_Element_Text('name'); + $name + ->setLabel(_('Name')) + ->setAttrib('readonly', true) + ->setValue(isset($setting[$prefix . '_name']) ? $setting[$prefix . '_name'] : '') + ->setDecorators(['ViewHelper']); + $this->addElement($name); $genre = new Zend_Form_Element_Text('genre'); - $genre->setLabel(_('Genre')) + $genre + ->setAttrib('readonly', true) + ->setLabel(_('Genre')) ->setValue(isset($setting[$prefix . '_genre']) ? $setting[$prefix . '_genre'] : '') ->setDecorators(['ViewHelper']); $this->addElement($genre); $url = new Zend_Form_Element_Text('url'); - $url->setLabel(_('URL')) + $url + ->setLabel(_('URL')) + ->setAttrib('readonly', true) ->setValue(isset($setting[$prefix . '_url']) ? $setting[$prefix . '_url'] : '') - ->setValidators([ - ['regex', false, ['/^[0-9a-zA-Z\-_.:\/]+$/', 'messages' => _('Invalid character entered')]], - ]) ->setDecorators(['ViewHelper']); $url->setAttrib('alt', 'url'); $this->addElement($url); - $name = new Zend_Form_Element_Text('name'); - $name->setLabel(_('Name')) - ->setValue(isset($setting[$prefix . '_name']) ? $setting[$prefix . '_name'] : '') - ->setDecorators(['ViewHelper']); - $this->addElement($name); - $description = new Zend_Form_Element_Text('description'); - $description->setLabel(_('Description')) + $description + ->setLabel(_('Description')) + ->setAttrib('readonly', true) ->setValue(isset($setting[$prefix . '_description']) ? $setting[$prefix . '_description'] : '') ->setDecorators(['ViewHelper']); $this->addElement($description); - $mount = new Zend_Form_Element_Text('mount'); - $mount->setLabel(_('Mount Point')) - ->setValue($useDefaults ? $streamDefaults['mount'] : (isset($setting[$prefix . '_mount']) ? $setting[$prefix . '_mount'] : '')) - ->setValidators([ - ['regex', false, ['/^[^ &<>]+$/', 'messages' => _('Invalid character entered')]], - ]) - ->setDecorators(['ViewHelper']); - $mount->setAttrib('alt', 'regular_text'); - $this->addElement($mount); - - $user = new Zend_Form_Element_Text('user'); - $user->setLabel(_('Username')) - ->setValue($useDefaults ? $streamDefaults['user'] : (isset($setting[$prefix . '_user']) ? $setting[$prefix . '_user'] : '')) - ->setValidators([ - ['regex', false, ['/^[^ &<>]+$/', 'messages' => _('Invalid character entered')]], - ]) - ->setDecorators(['ViewHelper']); - $user->setAttrib('alt', 'regular_text'); - $this->addElement($user); - - $adminUser = new Zend_Form_Element_Text('admin_user'); - $adminUser->setLabel(_('Admin User')) - ->setValue(Application_Model_StreamSetting::getAdminUser($prefix)) - ->setValidators([ - ['regex', false, ['/^[^ &<>]+$/', 'messages' => _('Invalid character entered')]], - ]) - ->setDecorators(['ViewHelper']); - $adminUser->setAttrib('alt', 'regular_text'); - $this->addElement($adminUser); - - $adminPass = new Zend_Form_Element_Password('admin_pass'); - $adminPass->setLabel(_('Admin Password')) - ->setValue(Application_Model_StreamSetting::getAdminPass($prefix)) - ->setValidators([ - ['regex', false, ['/^[^ &<>]+$/', 'messages' => _('Invalid character entered')]], - ]) - ->setDecorators(['ViewHelper']); - $adminPass->setAttrib('alt', 'regular_text'); - $this->addElement($adminPass); + $public_url = new Zend_Form_Element_Text('public_url'); + $public_url + ->setLabel(_('Stream URL')) + ->setValue($setting[$prefix . '_public_url'] ?? ''); + $this->addElement($public_url); $liquidsoap_error_msg = '

' . _('Getting information from the server...') . '

'; @@ -200,48 +154,4 @@ class Application_Form_StreamSettingSubForm extends Zend_Form_SubForm ]], ]); } - - public function isValid($data) - { - $f_data = $data['s' . $this->prefix . '_data']; - $isValid = parent::isValid($f_data); - // XXX: A couple of ugly workarounds here, but I guess that's what you get when you - // combine an already-complex POST and GET into a single action... - if (Application_Model_Preference::getUsingCustomStreamSettings() && $f_data) { - if ($f_data['enable'] == 1 && isset($f_data['host'])) { - if ($f_data['host'] == '') { - $element = $this->getElement('host'); - $element->addError(_('Server cannot be empty.')); - $isValid = false; - } - if ($f_data['port'] == '') { - $element = $this->getElement('port'); - $element->addError(_('Port cannot be empty.')); - $isValid = false; - } - if ($f_data['output'] == 'icecast') { - if ($f_data['mount'] == '') { - $element = $this->getElement('mount'); - $element->addError(_('Mount cannot be empty with Icecast server.')); - $isValid = false; - } - } - } - } - - return $isValid; - } - - public function toggleState() - { - $elements = $this->getElements(); - foreach ($elements as $element) { - if (Application_Model_Preference::getUsingCustomStreamSettings()) { - $element->setAttrib('disabled', null); - } elseif (!(in_array($element->getName(), static::$customizable) - || $element->getType() == 'Zend_Form_Element_Hidden')) { - $element->setAttrib('disabled', 'disabled'); - } - } - } } diff --git a/legacy/application/models/ListenerStat.php b/legacy/application/models/ListenerStat.php index 090affdcd..96713ffc7 100644 --- a/legacy/application/models/ListenerStat.php +++ b/legacy/application/models/ListenerStat.php @@ -58,29 +58,6 @@ SQL; } return $out; - $enabledStreamIds = Application_Model_StreamSetting::getEnabledStreamIds(); - $enabledOut = []; - - foreach ($enabledStreamIds as $sId) { - $sql = 'SELECT value FROM cc_stream_setting' - . ' WHERE keyname = :key'; - - $result = Application_Common_Database::prepareAndExecute($sql, ['key' => $sId . '_mount'], 'single'); - - $enabledMountPoint = $result['value']; - - if (isset($out[$enabledMountPoint])) { - $enabledOut[$enabledMountPoint] = $out[$enabledMountPoint]; - } else { - // TODO fix this hack (here for CC-5254) - // all shoutcast streams are automatically put under "shoutcast" mount point. - if (isset($out['shoutcast'])) { - $enabledOut['shoutcast'] = $out['shoutcast']; - } - } - } - - return $enabledOut; } // this will currently log the average number of listeners to a specific show during a certain range diff --git a/legacy/application/models/Preference.php b/legacy/application/models/Preference.php index 1ddc8713e..2fcf9fb43 100644 --- a/legacy/application/models/Preference.php +++ b/legacy/application/models/Preference.php @@ -795,20 +795,6 @@ class Application_Model_Preference return (int) self::getValue('import_timestamp'); } - public static function GetStreamType() - { - $st = self::getValue('stream_type'); - - return explode(',', $st); - } - - public static function GetStreamBitrate() - { - $sb = self::getValue('stream_bitrate'); - - return explode(',', $sb); - } - public static function SetPrivacyPolicyCheck($flag) { self::setValue('privacy_policy', $flag); @@ -819,36 +805,9 @@ class Application_Model_Preference return self::getValue('privacy_policy'); } - public static function SetNumOfStreams($num) - { - self::setValue('num_of_streams', intval($num)); - - // Enable or disable each stream according to whatever was just changed. - for ($streamIdx = 1; $streamIdx <= MAX_NUM_STREAMS; ++$streamIdx) { - $prefix = 's' . $streamIdx . '_'; - $enable = 'false'; - if ($streamIdx <= intval($num)) { - $enable = 'true'; - } - - // Enable or disable the stream in the Stream Settings DB table. - Application_Model_StreamSetting::setIndividualStreamSetting([$prefix . 'enable' => $enable]); - } - } - public static function GetNumOfStreams() { - return self::getValue('num_of_streams'); - } - - public static function SetMaxBitrate($bitrate) - { - self::setValue('max_bitrate', intval($bitrate)); - } - - public static function GetMaxBitrate() - { - return self::getValue('max_bitrate'); + return count(Config::get('stream.outputs.merged')); } public static function SetEnableStreamConf($bool) @@ -1128,58 +1087,32 @@ class Application_Model_Preference return ($value == null || $value == 'off') ? 'off' : 'on'; } - public static function SetMasterDJSourceConnectionURL($value) - { - self::setValue('master_dj_source_connection_url', $value, false); - } - public static function GetMasterDJSourceConnectionURL() { - $master_connection_url = self::getValue('master_dj_source_connection_url'); - if ($master_connection_url == '') { - $master_connection_url = 'http://' . $_SERVER['SERVER_NAME'] . ':' . Application_Model_StreamSetting::getMasterLiveStreamPort() . Application_Model_StreamSetting::getMasterLiveStreamMountPoint(); + if (Config::has('stream.inputs.main.public_url') && Config::get('stream.inputs.main.public_url')) { + return Config::get('stream.inputs.main.public_url'); } - return $master_connection_url; - } + $host = Config::get('general.public_url_raw')->getHost(); + $port = Application_Model_StreamSetting::getMasterLiveStreamPort(); + $mount = Application_Model_StreamSetting::getMasterLiveStreamMountPoint(); - public static function SetLiveDJSourceConnectionURL($value) - { - self::setValue('live_dj_source_connection_url', $value, false); + return "http://{$host}:{$port}/{$mount}"; } public static function GetLiveDJSourceConnectionURL() { - $livedj_connection_url = self::getValue('live_dj_source_connection_url'); - if ($livedj_connection_url == '') { - $livedj_connection_url = 'http://' . $_SERVER['SERVER_NAME'] . ':' . Application_Model_StreamSetting::getDjLiveStreamPort() . Application_Model_StreamSetting::getDjLiveStreamMountPoint(); + if (Config::has('stream.inputs.show.public_url') && Config::get('stream.inputs.show.public_url')) { + return Config::get('stream.inputs.show.public_url'); } - return $livedj_connection_url; - } + $host = Config::get('general.public_url_raw')->getHost(); + $port = Application_Model_StreamSetting::getDjLiveStreamPort(); + $mount = Application_Model_StreamSetting::getDjLiveStreamMountPoint(); - // Source Connection URL override status starts - public static function GetLiveDjConnectionUrlOverride() - { - return self::getValue('live_dj_connection_url_override'); + return "http://{$host}:{$port}/{$mount}"; } - public static function SetLiveDjConnectionUrlOverride($value) - { - self::setValue('live_dj_connection_url_override', $value, false); - } - - public static function GetMasterDjConnectionUrlOverride() - { - return self::getValue('master_dj_connection_url_override'); - } - - public static function SetMasterDjConnectionUrlOverride($value) - { - self::setValue('master_dj_connection_url_override', $value, false); - } - // Source Connection URL override status ends - public static function SetAutoTransition($value) { self::setValue('auto_transition', $value, false); @@ -1454,28 +1387,6 @@ class Application_Model_Preference // SAAS-876 - Store the default Icecast password to restore when switching // back to Airtime Pro streaming settings - public static function getDefaultIcecastPassword() - { - $val = self::getValue('default_icecast_password'); - - return empty($val) ? DEFAULT_ICECAST_PASS : $val; - } - - public static function setDefaultIcecastPassword($value) - { - self::setValue('default_icecast_password', $value); - } - - public static function getDefaultStreamMountPoint() - { - return self::getValue('default_stream_mount_point'); - } - - public static function setDefaultStreamMountPoint($value) - { - self::setValue('default_stream_mount_point', $value); - } - public static function getRadioPageDisplayLoginButton() { return self::getValue('radio_page_display_login_button'); diff --git a/legacy/application/models/StreamSetting.php b/legacy/application/models/StreamSetting.php index 7587dfa8b..b408b71b8 100644 --- a/legacy/application/models/StreamSetting.php +++ b/legacy/application/models/StreamSetting.php @@ -2,72 +2,106 @@ define('MAX_NUM_STREAMS', 4); +class Application_Model_StreamConfig +{ + private static function toOutputKey($id) + { + return 's' . ($id); + } + + private static function toOutputId($key) + { + return intval(trim($key, 's')); + } + + public static function getOutput($key, $add_prefix = false) + { + $id = self::toOutputId($key); + $config_id = $id - 1; + $prefix = $add_prefix ? "s{$id}_" : ''; + + if (!Config::has("stream.outputs.merged.{$config_id}")) { + $result = [ + $prefix . 'enable' => 'false', + $prefix . 'public_url' => '', + $prefix . 'output' => 'icecast', + $prefix . 'host' => 'localhost', + $prefix . 'port' => 8000, + $prefix . 'mount' => '', + $prefix . 'user' => 'source', + $prefix . 'pass' => '', + $prefix . 'admin_user' => 'admin', + $prefix . 'admin_pass' => '', + $prefix . 'channels' => 'stereo', + $prefix . 'bitrate' => 128, + $prefix . 'type' => '', + $prefix . 'name' => '', + $prefix . 'description' => '', + $prefix . 'genre' => '', + $prefix . 'url' => '', + $prefix . 'mobile' => 'false', + ]; + } else { + $output = Config::get("stream.outputs.merged.{$config_id}"); + + $result = [ + $prefix . 'enable' => $output['enabled'] ?? 'false', + $prefix . 'output' => $output['kind'] ?? 'icecast', + $prefix . 'public_url' => $output['public_url'] ?? '', + $prefix . 'host' => $output['host'] ?? 'localhost', + $prefix . 'port' => $output['port'] ?? 8000, + $prefix . 'mount' => $output['mount'] ?? '', + $prefix . 'user' => $output['source_user'] ?? 'source', + $prefix . 'pass' => $output['source_password'] ?? '', + $prefix . 'admin_user' => $output['admin_user'] ?? 'admin', + $prefix . 'admin_pass' => $output['admin_password'] ?? '', + $prefix . 'channels' => $output['audio']['channels'] ?? 'stereo', + $prefix . 'bitrate' => $output['audio']['bitrate'] ?? 128, + $prefix . 'type' => $output['audio']['format'], + $prefix . 'name' => $output['name'] ?? '', + $prefix . 'description' => $output['description'] ?? '', + $prefix . 'genre' => $output['genre'] ?? '', + $prefix . 'url' => $output['website'] ?? '', + $prefix . 'mobile' => 'false', + // $prefix . 'liquidsoap_error' => 'waiting', + ]; + } + + if (!$result[$prefix . 'public_url']) { + $host = $result[$prefix . 'host']; + if ($host == 'localhost') { + $host = Config::get('general.public_url_raw')->getHost(); + } + $port = $result[$prefix . 'port']; + $mount = $result[$prefix . 'mount']; + + $result[$prefix . 'public_url'] = "http://{$host}:{$port}/{$mount}"; + + if ($result[$prefix . 'output'] == 'shoutcast') { + // The semi-colon is important to make Shoutcast stream URLs play instead turn into a page. + $result[$prefix . 'public_url'] .= ';'; + } + } + + return $result; + } + + public static function getOutputEnabledKeys() + { + $keys = []; + + foreach (Config::get('stream.outputs.merged') as $id => $output) { + if ($output['enabled'] ?? false) { + $keys[] = self::toOutputKey($id + 1); + } + } + + return $keys; + } +} + class Application_Model_StreamSetting { - public static function setValue($key, $value, $type) - { - $con = Propel::getConnection(); - - // Check if key already exists - $sql = 'SELECT COUNT(*) FROM cc_stream_setting' - . ' WHERE keyname = :key'; - - $stmt = $con->prepare($sql); - $stmt->bindParam(':key', $key); - - if ($stmt->execute()) { - $result = $stmt->fetchColumn(0); - } else { - $msg = implode(',', $stmt->errorInfo()); - - throw new Exception("Error: {$msg}"); - } - - 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)'; - } - - $stmt = $con->prepare($sql); - $stmt->bindParam(':key', $key); - $stmt->bindParam(':value', $value); - $stmt->bindParam(':type', $type); - - if ($stmt->execute()) { - // do nothing - } else { - $msg = implode(',', $stmt->errorInfo()); - - throw new Exception("Error: {$msg}"); - } - } - - public static function getValue($key, $default = '') - { - $con = Propel::getConnection(); - - // Check if key already exists - $sql = 'SELECT value FROM cc_stream_setting' - . ' WHERE keyname = :key'; - - $stmt = $con->prepare($sql); - $stmt->bindParam(':key', $key); - - if ($stmt->execute()) { - $result = $stmt->fetchColumn(0); - } else { - $msg = implode(',', $stmt->errorInfo()); - - throw new Exception("Error: {$msg}"); - } - - return $result ? $result : $default; - } - public static function getEnabledStreamData() { $streams = []; @@ -75,16 +109,8 @@ class Application_Model_StreamSetting foreach ($streamIds as $id) { $streamData = self::getStreamData($id); $prefix = $id . '_'; - $host = $streamData[$prefix . 'host']; - $port = $streamData[$prefix . 'port']; - $mount = $streamData[$prefix . 'mount']; - if ($streamData[$prefix . 'output'] == 'shoutcast') { - $url = "http://{$host}:{$port}/;"; // The semi-colon is important to make Shoutcast stream URLs play instead turn into a page. - } else { // Icecast - $url = "http://{$host}:{$port}/{$mount}"; - } $streams[$id] = [ - 'url' => $url, + 'url' => $streamData[$prefix . 'public_url'], 'codec' => $streamData[$prefix . 'type'], 'bitrate' => $streamData[$prefix . 'bitrate'], 'mobile' => $streamData[$prefix . 'mobile'], @@ -98,102 +124,21 @@ class Application_Model_StreamSetting * example of the array returned in JSON notation is ["s1", "s2", "s3"] */ public static function getEnabledStreamIds() { - $con = Propel::getConnection(); - $sql = 'SELECT * ' - . 'FROM cc_stream_setting ' - . "WHERE keyname LIKE '%_enable' " - . "AND value='true'"; - - $ids = []; - - $rows = Application_Common_Database::prepareAndExecute($sql, [], 'all'); - - foreach ($rows as $row) { - $ids[] = substr($row['keyname'], 0, strpos($row['keyname'], '_')); - } - - return $ids; + return Application_Model_StreamConfig::getOutputEnabledKeys(); } /* Returns all information related to a specific stream. An example * of a stream id is 's1' or 's2'. */ public static function getStreamData($p_streamId) { - $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 = []; - foreach ($rows as $row) { - $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); - self::ensureKeyExists($keyPrefix . 'mobile', $data); - - return $data; + return Application_Model_StreamConfig::getOutput($p_streamId, true); } /* Similar to getStreamData, but removes all sX prefixes to * make data easier to iterate over */ public static function getStreamDataNormalized($p_streamId) { - $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; - } - - private static function ensureKeyExists($key, &$array, $default = '') - { - if (!array_key_exists($key, $array)) { - $array[$key] = $default; - } - - return $array; + return Application_Model_StreamConfig::getOutput($p_streamId, false); } public static function getStreamSetting() @@ -215,125 +160,9 @@ class Application_Model_StreamSetting return $settings; } - private static function saveStreamSetting($key, $value) - { - $stream_setting = CcStreamSettingQuery::create()->filterByDbKeyName($key)->findOne(); - if (is_null($stream_setting)) { - // throw new Exception("Keyname $key does not exist!"); - $stream_setting = new CcStreamSetting(); - $stream_setting->setDbKeyName($key); - $stream_setting->setDbType(''); - } - - $stream_setting->setDbValue($value); - $stream_setting->save(); - } - - /* - * function that take all the information of stream and sets them. - * This is used by stream setting via UI. - * - * @param $data - array that contains all the data. $data is [][] which - * contains multiple stream information - */ - public static function setStreamSetting($data) - { - foreach ($data as $key => $d) { - if ($key == 'output_sound_device' || $key == 'icecast_vorbis_metadata') { - $v = ($d == 1) ? 'true' : 'false'; - - self::saveStreamSetting($key, $v); - } elseif ($key == 'output_sound_device_type') { - self::saveStreamSetting($key, $d); - } elseif (is_array($d)) { - $temp = explode('_', $key); - $prefix = $temp[0]; - // SAAS-876 - If we're using Airtime Pro streaming, set the stream to use the default settings - if (!Application_Model_Preference::getUsingCustomStreamSettings()) { - $d = array_merge($d, static::getDefaults($prefix)); - } - foreach ($d as $k => $v) { - $keyname = $prefix . '_' . $k; - if ($k == 'enable') { - $v = $d['enable'] == 1 ? 'true' : 'false'; - } - $v = trim($v); - if ($k != 'admin_pass') { - self::saveStreamSetting($keyname, $v); - } elseif ($v != 'xxxxxx') { - // We use 'xxxxxx' as the admin password placeholder so we - // only want to save it when it is a different string - self::saveStreamSetting($keyname, $v); - } - } - } - } - } - - /** - * SAAS-876 - Get the default stream settings values for Airtime Pro streaming. - * - * @param int $prefix - * - * @return array array of default stream setting values - */ - public static function getDefaults($prefix) - { - $config = Config::getConfig(); - - return [ - 'host' => $config['public_url_raw']->getHost(), - 'port' => DEFAULT_ICECAST_PORT, - 'output' => 'icecast', - 'user' => $config['stationId'], - 'pass' => Application_Model_Preference::getDefaultIcecastPassword(), - // Manually setting default mountpoint - 'mount' => Application_Model_Preference::getDefaultStreamMountpoint(), - ]; - } - - /* - * Sets individual stream setting. - * - * $data - data array. $data is []. - * TODO: Make this SQL a prepared statement! - * - * Do not remove this function. It is called by airtime-system.php - */ - public static function setIndividualStreamSetting($data) - { - foreach ($data as $keyname => $v) { - $sql = 'UPDATE cc_stream_setting SET value=:v WHERE keyname=:keyname'; - $map = [':v' => $v, ':keyname' => $keyname]; - - $res = Application_Common_Database::prepareAndExecute( - $sql, - $map, - Application_Common_Database::EXECUTE - ); - } - } - public static function getStreamEnabled($stream_id) { - $con = Propel::getConnection(); - - $keyname = 's' . $stream_id . '_enable'; - $sql = 'SELECT value FROM cc_stream_setting' - . ' WHERE keyname = :keyname'; - - $stmt = $con->prepare($sql); - $stmt->bindParam(':keyname', $keyname); - - if ($stmt->execute()) { - $result = $stmt->fetchColumn(0); - } else { - $msg = implode(',', $stmt->errorInfo()); - - throw new Exception("Error: {$msg}"); - } - - return $result != 'false'; + return in_array('s' . $stream_id, self::getEnabledStreamIds()); } /* @@ -342,112 +171,66 @@ class Application_Model_StreamSetting */ public static function getStreamInfoForDataCollection() { - $con = Propel::getConnection(); + $result = []; + $stream_ids = self::getEnabledStreamIds(); - $out = []; - $enabled_stream = self::getEnabledStreamIds(); - - foreach ($enabled_stream as $stream) { - $keys = ["{$stream}_output", "{$stream}_type", "{$stream}_bitrate", "{$stream}_host"]; - $key_csv = implode(',', $keys); - - $sql = 'SELECT keyname, value FROM cc_stream_setting' - . ' WHERE keyname IN (:key_csv)'; - - $stmt = $con->prepare($sql); - $stmt->bindParam(':key_csv', $key_csv); - - if ($stmt->execute()) { - $rows = $stmt->fetchAll(); - } else { - $msg = implode(',', $stmt->errorInfo()); - - throw new Exception("Error: {$msg}"); - } - - $info = []; - foreach ($rows as $r) { - $temp = explode('_', $r['keyname']); - $info[$temp[1]] = $r['value']; - $out[$stream] = $info; - } + foreach ($stream_ids as $stream_id) { + $stream = self::getStreamDataNormalized($stream_id); + $keys = array_flip(['output', 'type', 'bitrate', 'host']); + $result[$stream_id] = array_intersect_key($stream, $keys); } - return $out; - } - - public static function setMasterLiveStreamPort($value) - { - self::setValue('master_live_stream_port', $value, 'integer'); + return $result; } public static function getMasterLiveStreamPort() { - return self::getValue('master_live_stream_port', 8001); - } - - public static function setMasterLiveStreamMountPoint($value) - { - self::setValue('master_live_stream_mp', $value, 'string'); + return Config::get('stream.inputs.main.port') ?? 8001; } public static function getMasterLiveStreamMountPoint() { - return self::getValue('master_live_stream_mp', '/master'); - } - - public static function setDjLiveStreamPort($value) - { - self::setValue('dj_live_stream_port', $value, 'integer'); + return Config::get('stream.inputs.main.mount') ?? 'main'; } public static function getDjLiveStreamPort() { - return self::getValue('dj_live_stream_port', 8002); - } - - public static function setDjLiveStreamMountPoint($value) - { - self::setValue('dj_live_stream_mp', $value, 'string'); + return Config::get('stream.inputs.show.port') ?? 8002; } public static function getDjLiveStreamMountPoint() { - return self::getValue('dj_live_stream_mp', '/show'); + return Config::get('stream.inputs.show.mount') ?? 'show'; } public static function getAdminUser($stream) { - return self::getValue($stream . '_admin_user'); - } - - public static function setAdminUser($stream, $v) - { - self::setValue($stream . '_admin_user', $v, 'string'); + return self::getStreamDataNormalized($stream)['admin_user']; } public static function getAdminPass($stream) { - return self::getValue($stream . '_admin_pass'); - } - - public static function setAdminPass($stream, $v) - { - self::setValue($stream . '_admin_pass', $v, 'string'); + return self::getStreamDataNormalized($stream)['admin_pass']; } public static function getIcecastVorbisMetadata() { - return self::getValue('icecast_vorbis_metadata', ''); + foreach (Config::get('stream.outputs.merged') as $output) { + if ($output['audio']['enable_metadata'] ?? false) { + return true; + } + } + + return ''; } public static function getOutputSoundDevice() { - return self::getValue('output_sound_device', 'false'); + return Config::get('stream.outputs.system.0.enabled') ?? 'false'; } public static function getOutputSoundDeviceType() { - return self::getValue('output_sound_device_type', ''); + return Config::get('stream.outputs.system.0.kind') ?? ''; } } diff --git a/legacy/application/views/scripts/dashboard/stream-player.phtml b/legacy/application/views/scripts/dashboard/stream-player.phtml index f8e00e963..242339091 100644 --- a/legacy/application/views/scripts/dashboard/stream-player.phtml +++ b/legacy/application/views/scripts/dashboard/stream-player.phtml @@ -36,7 +36,7 @@ if (count($ids) > 0) { $id = $ids[0]; $streamData = Application_Model_StreamSetting::getStreamData($id); - $url = "http://" . $streamData["${id}_host"] . ":" . $streamData["${id}_port"] . "/" . $streamData["${id}_mount"]; + $url = $streamData["${id}_public_url"]; $type = $streamData["${id}_type"]; $serverType = $streamData["${id}_output"]; if ($type == "ogg") @@ -68,7 +68,7 @@ element->getElement('master_username')->render() ?> element->getElement('master_password')->render() ?> - element->getElement("master_source_host")->render() ?> -    -
- -
+ element->getElement("master_source_host")->render() ?> element->getElement("master_source_port")->render() ?> element->getElement("master_source_mount")->render() ?> @@ -31,15 +25,7 @@

- - element->getElement("show_source_host")->render() ?> -    - -
- -
+ element->getElement("show_source_host")->render() ?> element->getElement("show_source_port")->render() ?> element->getElement("show_source_mount")->render() ?> diff --git a/legacy/application/views/scripts/form/stream-setting-form.phtml b/legacy/application/views/scripts/form/stream-setting-form.phtml index e839afcc6..bd53a32b3 100644 --- a/legacy/application/views/scripts/form/stream-setting-form.phtml +++ b/legacy/application/views/scripts/form/stream-setting-form.phtml @@ -15,27 +15,13 @@ $s_name = "s" . $this->stream_number; element->getElement('enable') ?> -
- +
+
-
- element->getElement('mobile') ?> +
+ element->getElement('output') ?>
-
- -
-
- element->getElement('type') ?> - -
- -
- -
-
- element->getElement('bitrate') ?> -
@@ -64,12 +50,6 @@ $s_name = "s" . $this->stream_number; -
- -
-
- element->getElement('output') ?> -
@@ -78,144 +58,100 @@ $s_name = "s" . $this->stream_number; element->getElement('channels') ?> -
- - - - -
-
- -
-
- element->getElement('user') ?> - element->getElement('user')->hasErrors()) : ?> -
    - element->getElement('user')->getMessages() as $error) : ?> -
  • - -
- -
-
- -
-
- element->getElement('pass') ?> - element->getElement('pass')->hasErrors()) : ?> -
    - element->getElement('pass')->getMessages() as $error) : ?> -
  • - -
- -
-
- -
-
- element->getElement('admin_user') ?> - element->getElement('admin_user')->hasErrors()) : ?> -
    - element->getElement('admin_user')->getMessages() as $error) : ?> -
  • - -
- -
-
- -
-
- element->getElement('admin_pass') ?> - element->getElement('admin_pass')->hasErrors()) : ?> -
    - element->getElement('admin_pass')->getMessages() as $error) : ?> -
  • - -
- -
-
- -
-
- -
-
- element->getElement('name') ?> - element->getElement('name')->hasErrors()) : ?> -
    - element->getElement('name')->getMessages() as $error) : ?> -
  • - -
- -
-
- -
-
- element->getElement('description') ?> - element->getElement('description')->hasErrors()) : ?> -
    - element->getElement('description')->getMessages() as $error) : ?> -
  • - -
- -
-
- -
-
- element->getElement('url') ?> - - element->getElement('url')->hasErrors()) : ?> -
    - element->getElement('url')->getMessages() as $error) : ?> -
  • - -
- -
-
- -
-
- element->getElement('genre') ?> - element->getElement('genre')->hasErrors()) : ?> -
    - element->getElement('genre')->getMessages() as $error) : ?> -
  • - -
- -
-
- -
-
- element->getElement('mount') ?> - element->getElement('mount')->hasErrors()) : ?> -
    - element->getElement('mount')->getMessages() as $error) : ?> -
  • - -
- -
-
-
+
+ +
+
+ element->getElement('type') ?> + +
+ +
+ +
+
+ element->getElement('bitrate') ?> +
+ + +
+ +
+
+ element->getElement('name') ?> + element->getElement('name')->hasErrors()) : ?> + + +
+
+ +
+
+ element->getElement('description') ?> + element->getElement('description')->hasErrors()) : ?> + + +
+
+ +
+
+ element->getElement('url') ?> + element->getElement('url')->hasErrors()) : ?> + + +
+
+ +
+
+ element->getElement('genre') ?> + element->getElement('genre')->hasErrors()) : ?> + + +
+
+ +
+
+ element->getElement('mount') ?> + element->getElement('mount')->hasErrors()) : ?> + + +
+
+ +
+
+ element->getElement('mobile') ?> +
- +
- + + element->getElement('public_url')->getValue() ?> +
diff --git a/legacy/application/views/scripts/preference/stream-setting.phtml b/legacy/application/views/scripts/preference/stream-setting.phtml index ef732f4c2..3ce7c3fdc 100644 --- a/legacy/application/views/scripts/preference/stream-setting.phtml +++ b/legacy/application/views/scripts/preference/stream-setting.phtml @@ -11,39 +11,11 @@

- form->getElement('output_sound_device') != null) { ?> -
- -
-
- form->getElement('output_sound_device') ?> -
-
- -
-
- form->getElement('output_sound_device_type') ?> -
- -
- -
-
- form->getElement('icecast_vorbis_metadata') ?> -
-

-
+
form->getElement('streamFormat')->getValue(); ?> @@ -52,7 +24,7 @@ > -

+

@@ -65,6 +37,7 @@
+
form->getElement('offAirMeta') ?>
+