From c261182c8f2047b7d6d465cf207cd8afc739d1f2 Mon Sep 17 00:00:00 2001 From: drigato Date: Thu, 12 Feb 2015 14:08:06 -0500 Subject: [PATCH 01/60] Skeleton player form/view/controller --- airtime_mvc/application/configs/ACL.php | 4 ++- .../application/configs/navigation.php | 7 +++++ .../EmbeddableplayerController.php | 31 +++++++++++++++++++ .../application/forms/EmbeddablePlayer.php | 20 ++++++++++++ .../scripts/embeddableplayer/index.phtml | 15 +++++++++ .../views/scripts/form/embeddableplayer.html | 6 ++++ 6 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 airtime_mvc/application/controllers/EmbeddableplayerController.php create mode 100644 airtime_mvc/application/forms/EmbeddablePlayer.php create mode 100644 airtime_mvc/application/views/scripts/embeddableplayer/index.phtml create mode 100644 airtime_mvc/application/views/scripts/form/embeddableplayer.html diff --git a/airtime_mvc/application/configs/ACL.php b/airtime_mvc/application/configs/ACL.php index c41f00a47..243e105d3 100644 --- a/airtime_mvc/application/configs/ACL.php +++ b/airtime_mvc/application/configs/ACL.php @@ -36,7 +36,8 @@ $ccAcl->add(new Zend_Acl_Resource('library')) ->add(new Zend_Acl_Resource('rest:media')) ->add(new Zend_Acl_Resource('rest:show-image')) ->add(new Zend_Acl_Resource('billing')) - ->add(new Zend_Acl_Resource('provisioning')); + ->add(new Zend_Acl_Resource('provisioning')) + ->add(new Zend_Acl_Resource('embeddableplayer')); /** Creating permissions */ $ccAcl->allow('G', 'index') @@ -68,6 +69,7 @@ $ccAcl->allow('G', 'index') ->allow('A', 'user') ->allow('A', 'systemstatus') ->allow('A', 'preference') + ->allow('A', 'embeddableplayer') ->allow('S', 'billing'); diff --git a/airtime_mvc/application/configs/navigation.php b/airtime_mvc/application/configs/navigation.php index 14438bdfe..01c8aa385 100644 --- a/airtime_mvc/application/configs/navigation.php +++ b/airtime_mvc/application/configs/navigation.php @@ -85,6 +85,13 @@ $pages = array( 'controller' => 'listenerstat', 'action' => 'index', 'resource' => 'listenerstat' + ), + array( + 'label' => _('Embeddable Player'), + 'module' => 'default', + 'controller' => 'embeddableplayer', + 'action' => 'index', + 'resource' => 'embeddableplayer' ) ) ), diff --git a/airtime_mvc/application/controllers/EmbeddableplayerController.php b/airtime_mvc/application/controllers/EmbeddableplayerController.php new file mode 100644 index 000000000..3cd0e3af4 --- /dev/null +++ b/airtime_mvc/application/controllers/EmbeddableplayerController.php @@ -0,0 +1,31 @@ +getRequest(); + + if ($request->isPost()) { + $formValues = $request->getPost(); + if ($form->isValid($formValues)) { + + $this->view->statusMsg = "
". _("Preferences updated.")."
"; + + } else { + + } + + $this->view->form = $form; + } + + $this->view->form = $form; + } +} \ No newline at end of file diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php new file mode 100644 index 000000000..e9dd6b151 --- /dev/null +++ b/airtime_mvc/application/forms/EmbeddablePlayer.php @@ -0,0 +1,20 @@ +setDecorators(array( + array('ViewScript', array('viewScript' => 'form/embeddableplayer.html')) + )); + + + $displayTrackMetadata = new Zend_Form_Element_Checkbox('display_track_metadata'); + $displayTrackMetadata->setValue(true); + $displayTrackMetadata->setLabel(_('Display track metadata?')); + $this->addElement($displayTrackMetadata); + + $submit = new Zend_Form_Element_Submit('submit'); + $this->addElement($submit); + } +} \ No newline at end of file diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml new file mode 100644 index 000000000..df666df29 --- /dev/null +++ b/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml @@ -0,0 +1,15 @@ +
+

+ +
+ + form->getElement('submit')->render() ?> +
+ statusMsg; + echo $this->form; + ?> +
+
+
diff --git a/airtime_mvc/application/views/scripts/form/embeddableplayer.html b/airtime_mvc/application/views/scripts/form/embeddableplayer.html new file mode 100644 index 000000000..4a8844f58 --- /dev/null +++ b/airtime_mvc/application/views/scripts/form/embeddableplayer.html @@ -0,0 +1,6 @@ +
+
+ element->getElement('display_track_metadata'); ?> + +
+
\ No newline at end of file From 56cae342594c311a126148c74bec86ffc8eb29f0 Mon Sep 17 00:00:00 2001 From: drigato Date: Thu, 12 Feb 2015 14:20:54 -0500 Subject: [PATCH 02/60] Fix typo --- .../application/views/scripts/embeddableplayer/index.phtml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml index df666df29..51e00dc03 100644 --- a/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml +++ b/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml @@ -1,15 +1,16 @@

-
+ + - form->getElement('submit')->render() ?>
statusMsg; echo $this->form; ?> + form->getElement('submit')->render() ?>
From 4fd7b4c622315ef94e3c16b03eaae271c0acddb3 Mon Sep 17 00:00:00 2001 From: drigato Date: Tue, 17 Feb 2015 11:48:43 -0500 Subject: [PATCH 03/60] SAAS-585: Create Embeddable Player form Added stream urls - hardcoded for now --- airtime_mvc/application/forms/EmbeddablePlayer.php | 9 ++++++++- .../application/views/scripts/form/embeddableplayer.html | 2 ++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php index e9dd6b151..57c46bed9 100644 --- a/airtime_mvc/application/forms/EmbeddablePlayer.php +++ b/airtime_mvc/application/forms/EmbeddablePlayer.php @@ -8,12 +8,19 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm array('ViewScript', array('viewScript' => 'form/embeddableplayer.html')) )); - $displayTrackMetadata = new Zend_Form_Element_Checkbox('display_track_metadata'); $displayTrackMetadata->setValue(true); $displayTrackMetadata->setLabel(_('Display track metadata?')); $this->addElement($displayTrackMetadata); + $streamURL = new Zend_Form_Element_Radio('stream_url'); + $streamURL->setMultiOptions(array( + 'AAC' => 'http://127.0.0.1:8000/airtime_a', + 'MP3' => 'http://127.0.0.1:8000/airtime_b' + )); + $streamURL->setLabel(_('Select stream:')); + $this->addElement($streamURL); + $submit = new Zend_Form_Element_Submit('submit'); $this->addElement($submit); } diff --git a/airtime_mvc/application/views/scripts/form/embeddableplayer.html b/airtime_mvc/application/views/scripts/form/embeddableplayer.html index 4a8844f58..8a1ad551e 100644 --- a/airtime_mvc/application/views/scripts/form/embeddableplayer.html +++ b/airtime_mvc/application/views/scripts/form/embeddableplayer.html @@ -2,5 +2,7 @@
element->getElement('display_track_metadata'); ?> + element->getElement('stream_url'); ?> +
\ No newline at end of file From a931e282e13f4a0870188d1dbce5c640d8c254f9 Mon Sep 17 00:00:00 2001 From: drigato Date: Fri, 20 Feb 2015 15:44:25 -0500 Subject: [PATCH 04/60] SAAS-585: Create Embeddable Player form Fixed up the stream urls options --- airtime_mvc/application/forms/EmbeddablePlayer.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php index 57c46bed9..a8eb137ce 100644 --- a/airtime_mvc/application/forms/EmbeddablePlayer.php +++ b/airtime_mvc/application/forms/EmbeddablePlayer.php @@ -14,10 +14,13 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm $this->addElement($displayTrackMetadata); $streamURL = new Zend_Form_Element_Radio('stream_url'); - $streamURL->setMultiOptions(array( - 'AAC' => 'http://127.0.0.1:8000/airtime_a', - 'MP3' => 'http://127.0.0.1:8000/airtime_b' - )); + $urlOptions = Array(); + foreach(Application_Model_StreamSetting::getStreamUrls() as $type => $url) { + $urlOptions[$url] = $type; + } + $streamURL->setMultiOptions( + $urlOptions + ); $streamURL->setLabel(_('Select stream:')); $this->addElement($streamURL); From 6dcc7ee2fce0d4432c058fbec613b0e749c92d72 Mon Sep 17 00:00:00 2001 From: drigato Date: Fri, 20 Feb 2015 15:50:40 -0500 Subject: [PATCH 05/60] SAAS-587: Add stream urls to station-metadata API --- .../application/controllers/ApiController.php | 1 + .../application/forms/EmbeddablePlayer.php | 2 +- airtime_mvc/application/models/StreamSetting.php | 16 ++++++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/airtime_mvc/application/controllers/ApiController.php b/airtime_mvc/application/controllers/ApiController.php index 124b4b4d0..5f1847f77 100644 --- a/airtime_mvc/application/controllers/ApiController.php +++ b/airtime_mvc/application/controllers/ApiController.php @@ -637,6 +637,7 @@ class ApiController extends Zend_Controller_Action $result["description"] = Application_Model_Preference::GetStationDescription(); $result["timezone"] = Application_Model_Preference::GetDefaultTimezone(); $result["locale"] = Application_Model_Preference::GetDefaultLocale(); + $result["enabled_stream_urls"] = Application_Model_StreamSetting::getStreamUrls(); // used by caller to determine if the airtime they are running or widgets in use is out of date. $result['AIRTIME_API_VERSION'] = AIRTIME_API_VERSION; diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php index a8eb137ce..2accf23a5 100644 --- a/airtime_mvc/application/forms/EmbeddablePlayer.php +++ b/airtime_mvc/application/forms/EmbeddablePlayer.php @@ -15,7 +15,7 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm $streamURL = new Zend_Form_Element_Radio('stream_url'); $urlOptions = Array(); - foreach(Application_Model_StreamSetting::getStreamUrls() as $type => $url) { + foreach(Application_Model_StreamSetting::getEnabledStreamUrls() as $type => $url) { $urlOptions[$url] = $type; } $streamURL->setMultiOptions( diff --git a/airtime_mvc/application/models/StreamSetting.php b/airtime_mvc/application/models/StreamSetting.php index c34c09a2e..3bdac8a31 100644 --- a/airtime_mvc/application/models/StreamSetting.php +++ b/airtime_mvc/application/models/StreamSetting.php @@ -62,6 +62,22 @@ class Application_Model_StreamSetting return $result ? $result : ""; } + public static function getEnabledStreamUrls() + { + $urls = Array(); + $streamIds = Application_Model_StreamSetting::getEnabledStreamIds(); + foreach ($streamIds as $id) { + $prefix = $id."_"; + $streamData = Application_Model_StreamSetting::getStreamData($id); + $host = $streamData[$prefix."host"]; + $port = $streamData[$prefix."port"]; + $mount = $streamData[$prefix."mount"]; + $type = $streamData[$prefix."type"]; + $urls[$type] = "http://$host:$port/$mount"; + } + return $urls; + } + /* Returns the id's of all streams that are enabled in an array. An * example of the array returned in JSON notation is ["s1", "s2", "s3"] */ public static function getEnabledStreamIds() From 5e9252a562c1bf7a799d2c00df467a2a2d58991c Mon Sep 17 00:00:00 2001 From: drigato Date: Fri, 20 Feb 2015 15:52:13 -0500 Subject: [PATCH 06/60] SAAS-587: Add stream urls to station-metadata API Fix typo --- airtime_mvc/application/controllers/ApiController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/airtime_mvc/application/controllers/ApiController.php b/airtime_mvc/application/controllers/ApiController.php index 5f1847f77..2e8b2a55b 100644 --- a/airtime_mvc/application/controllers/ApiController.php +++ b/airtime_mvc/application/controllers/ApiController.php @@ -637,7 +637,7 @@ class ApiController extends Zend_Controller_Action $result["description"] = Application_Model_Preference::GetStationDescription(); $result["timezone"] = Application_Model_Preference::GetDefaultTimezone(); $result["locale"] = Application_Model_Preference::GetDefaultLocale(); - $result["enabled_stream_urls"] = Application_Model_StreamSetting::getStreamUrls(); + $result["enabled_stream_urls"] = Application_Model_StreamSetting::getEnabledStreamUrls(); // used by caller to determine if the airtime they are running or widgets in use is out of date. $result['AIRTIME_API_VERSION'] = AIRTIME_API_VERSION; From 2272451e08a575676dffe590e3aaba2fa9b478de Mon Sep 17 00:00:00 2001 From: drigato Date: Wed, 25 Feb 2015 17:10:41 -0500 Subject: [PATCH 07/60] Added placeholders for player embed code and preview --- airtime_mvc/application/configs/conf.php | 2 +- .../EmbeddableplayerController.php | 19 ++++--------------- .../application/forms/EmbeddablePlayer.php | 16 +++++++++++----- .../scripts/embeddableplayer/index.phtml | 7 ++----- .../views/scripts/form/embeddableplayer.html | 8 -------- .../views/scripts/form/embeddableplayer.phtml | 13 +++++++++++++ airtime_mvc/public/css/embed-player.css | 4 ++++ 7 files changed, 35 insertions(+), 34 deletions(-) delete mode 100644 airtime_mvc/application/views/scripts/form/embeddableplayer.html create mode 100644 airtime_mvc/application/views/scripts/form/embeddableplayer.phtml create mode 100644 airtime_mvc/public/css/embed-player.css diff --git a/airtime_mvc/application/configs/conf.php b/airtime_mvc/application/configs/conf.php index d38a03797..6cf5f9d6c 100644 --- a/airtime_mvc/application/configs/conf.php +++ b/airtime_mvc/application/configs/conf.php @@ -92,7 +92,7 @@ class Config { public static function setAirtimeVersion() { $airtime_version = Application_Model_Preference::GetAirtimeVersion(); $uniqueid = Application_Model_Preference::GetUniqueId(); - $buildVersion = file_get_contents(self::$rootDir."/../VERSION"); + $buildVersion = @file_get_contents(self::$rootDir."/../VERSION"); self::$CC_CONFIG['airtime_version'] = md5($airtime_version.$buildVersion); } diff --git a/airtime_mvc/application/controllers/EmbeddableplayerController.php b/airtime_mvc/application/controllers/EmbeddableplayerController.php index 3cd0e3af4..f30683b79 100644 --- a/airtime_mvc/application/controllers/EmbeddableplayerController.php +++ b/airtime_mvc/application/controllers/EmbeddableplayerController.php @@ -9,23 +9,12 @@ class EmbeddablePlayerController extends Zend_Controller_Action public function indexAction() { + $CC_CONFIG = Config::getConfig(); + $baseUrl = Application_Common_OsPath::getBaseDir(); + $this->view->headLink()->appendStylesheet($baseUrl.'css/embed-player.css?'.$CC_CONFIG['airtime_version']); + $form = new Application_Form_EmbeddablePlayer(); - $request = $this->getRequest(); - - if ($request->isPost()) { - $formValues = $request->getPost(); - if ($form->isValid($formValues)) { - - $this->view->statusMsg = "
". _("Preferences updated.")."
"; - - } else { - - } - - $this->view->form = $form; - } - $this->view->form = $form; } } \ No newline at end of file diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php index 2accf23a5..00f49384a 100644 --- a/airtime_mvc/application/forms/EmbeddablePlayer.php +++ b/airtime_mvc/application/forms/EmbeddablePlayer.php @@ -5,15 +5,22 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm public function init() { $this->setDecorators(array( - array('ViewScript', array('viewScript' => 'form/embeddableplayer.html')) + array('ViewScript', array('viewScript' => 'form/embeddableplayer.phtml')) )); - $displayTrackMetadata = new Zend_Form_Element_Checkbox('display_track_metadata'); + $embedSrc = new Zend_Form_Element_Text('player_embed_src'); + $embedSrc->setAttrib("readonly", "readonly"); + $embedSrc->setAttrib("class", "player_embed_src"); + $embedSrc->setValue(''); + $embedSrc->removeDecorator('label'); + $this->addElement($embedSrc); + + $displayTrackMetadata = new Zend_Form_Element_Checkbox('player_display_track_metadata'); $displayTrackMetadata->setValue(true); $displayTrackMetadata->setLabel(_('Display track metadata?')); $this->addElement($displayTrackMetadata); - $streamURL = new Zend_Form_Element_Radio('stream_url'); + $streamURL = new Zend_Form_Element_Radio('player_stream_url'); $urlOptions = Array(); foreach(Application_Model_StreamSetting::getEnabledStreamUrls() as $type => $url) { $urlOptions[$url] = $type; @@ -21,10 +28,9 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm $streamURL->setMultiOptions( $urlOptions ); + $streamURL->setValue(0); $streamURL->setLabel(_('Select stream:')); $this->addElement($streamURL); - $submit = new Zend_Form_Element_Submit('submit'); - $this->addElement($submit); } } \ No newline at end of file diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml index 51e00dc03..0a9e66daa 100644 --- a/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml +++ b/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml @@ -1,16 +1,13 @@

+
- form; ?> - echo $this->statusMsg; - echo $this->form; - ?> - form->getElement('submit')->render() ?>
diff --git a/airtime_mvc/application/views/scripts/form/embeddableplayer.html b/airtime_mvc/application/views/scripts/form/embeddableplayer.html deleted file mode 100644 index 8a1ad551e..000000000 --- a/airtime_mvc/application/views/scripts/form/embeddableplayer.html +++ /dev/null @@ -1,8 +0,0 @@ -
-
- element->getElement('display_track_metadata'); ?> - - element->getElement('stream_url'); ?> - -
-
\ No newline at end of file diff --git a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml new file mode 100644 index 000000000..f1ca8d478 --- /dev/null +++ b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml @@ -0,0 +1,13 @@ +
+
+ + element->getElement('player_embed_src'); ?> + + element->getElement('player_display_track_metadata'); ?> + + element->getElement('player_stream_url'); ?> + +
+
player preview holder
+
+
\ No newline at end of file diff --git a/airtime_mvc/public/css/embed-player.css b/airtime_mvc/public/css/embed-player.css new file mode 100644 index 000000000..1f19319e8 --- /dev/null +++ b/airtime_mvc/public/css/embed-player.css @@ -0,0 +1,4 @@ +#embed_player_preview { + margin-top:20px; + border: 1px solid; +} From d61b75f105e234927c607f2bcf8886430e6c40dd Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Tue, 3 Mar 2015 16:08:53 -0500 Subject: [PATCH 08/60] Added a working 4th stream --- .../controllers/PreferenceController.php | 8 +++++++- airtime_mvc/build/sql/defaultdata.sql | 18 ++++++++++++++++++ .../js/airtime/preferences/streamsetting.js | 9 ++++++--- .../pypo/liquidsoap_scripts/liquidsoap.cfg | 18 +++++++++++++++--- .../pypo/liquidsoap_scripts/ls_script.liq | 16 +++++++++++++++- 5 files changed, 61 insertions(+), 8 deletions(-) diff --git a/airtime_mvc/application/controllers/PreferenceController.php b/airtime_mvc/application/controllers/PreferenceController.php index 219e35e01..6a0ba3541 100644 --- a/airtime_mvc/application/controllers/PreferenceController.php +++ b/airtime_mvc/application/controllers/PreferenceController.php @@ -223,6 +223,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 +233,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 +249,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 +295,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 +447,7 @@ class PreferenceController extends Zend_Controller_Action public function getAdminPasswordStatusAction() { $out = array(); - for ($i=1; $i<=3; $i++) { + for ($i=1; $i<=4; $i++) { if (Application_Model_StreamSetting::getAdminPass('s'.$i)=='') { $out["s".$i] = false; } else { 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/liquidsoap.cfg b/python_apps/pypo/liquidsoap_scripts/liquidsoap.cfg index d76e3af3d..bb6c6d88f 100644 --- a/python_apps/pypo/liquidsoap_scripts/liquidsoap.cfg +++ b/python_apps/pypo/liquidsoap_scripts/liquidsoap.cfg @@ -10,18 +10,22 @@ output_sound_device_type = "ALSA" s1_output = "icecast" s2_output = "icecast" s3_output = "icecast" +s4_output = "icecast" s1_enable = true s2_enable = false s3_enable = false +s4_enable = false s1_type = "ogg" s2_type = "ogg" s3_type = "mp3" +s4_type = "mp3" s1_bitrate = 128 s2_bitrate = 128 s3_bitrate = 160 +s4_bitrate = 160 ########################################### # Logging settings # @@ -35,31 +39,39 @@ log_file = "/var/log/airtime/pypo-liquidsoap/ + + + + + + + + + + + + + \ No newline at end of file diff --git a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml index f1ca8d478..568540d7f 100644 --- a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml +++ b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml @@ -8,6 +8,6 @@ element->getElement('player_stream_url'); ?>
-
player preview holder
+ \ No newline at end of file diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean.xml b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean.xml new file mode 100644 index 000000000..57d7c3eab --- /dev/null +++ b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/bg.png b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/bg.png new file mode 100644 index 0000000000000000000000000000000000000000..a399e16be7eeeb3a6a26d2488b98293dbf0eb29e GIT binary patch literal 3649 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 literal 0 HcmV?d00001 diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/statusstop.png b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/statusstop.png new file mode 100644 index 0000000000000000000000000000000000000000..e0cce0d1a8407d07b2b8470cfedcbb3b7a0c96b8 GIT binary patch literal 136 zcmeAS@N?(olHy`uVBq!ia0vp^Od!m`#=yYHy3uwMki(Mh=OQOYu8I4U$VqC zq9iy!t)x7$D3!r6B|j-u!8128JvAsbF{QHbWU38Nk(8&4V@SoVq#x%Gd|*>(kZ@pe gXfS-ozOjLU!C@|IGjG!oQ=lpaPgg&ebxsLQ0I(4y>;M1& literal 0 HcmV?d00001 diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/stop.jpg b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/stop.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c7fda38d84c849610b89f211a34fd222b515e527 GIT binary patch literal 1459 zcmex=U71|~s9Wv5vvV>sGBC0-!bO1$W+oO^ zHg*mH21XV}CKh(M6blnGD;pz&fP#=PyP%=5vxumwATZomnV49(xS^^Tfp!QAv9KBn zD>^C}iLeDGHZI)g6x3uanzTvTIl1|;X{(u=5Can<&^N4blfk-J1QZMv3xxs~UR2s7 z40IF|D>Dl-%wa&UC<=TqbPPfy4{RtzLf>K?Y#OoP(|vZ$t%wmSC{MBoxfR%Blm34U;m~atepuMWK7qM zN_!q#&kDM&q&P*ZE2V6qwr!MX4=6(m(!pI2J;@qgIRT3UFN%X+iAT1U(=kt8GW4`zA z-u9hG*VpFoPoHRgqenbbZm+fY6n5)UDT|-1#hyNGjcJ+u-?(RMU$|Jbih0>hzuc)U zGyS66)4!_68e8RFclkOsF4A?!AC)R)`zkO3f*+H?wzFZ?b3WvUb^e>(28xAKUh)|MQP8vp?Y+f92QVmDj)56n>BA z|5Wm8A|z;-8SNE!B>A~dXlP4%vtEGr^zsk`eP;HkM4Ly3c^w+3Ox7j8;reL$>g=nB zV*0rn)%SE18l3(!ELy9)VP>I|X~nv-z(t&&9xiBX%ww5)YSVm2e)+6y_`AZwS*NcnSZflM&3_^wO$b=v3e2{OvsvSRI; zDu^0pkeWq2dym-!7yLeG^Qa_X8s|>0bB}{x@4iv9QS7+D0_%`d9d6DM8^9V6>0Ln1 z!Dmu~0^ENBn&(z5t!!^93T5)Ty3pT2UFeE&17@t;}MmCo2V&r0gT zJ+YH}VoGPZwro5wEnpFwr#Hi`9d9@5lqqfPnBm5B@REYld<)sP$ytvRQde>bJ(zhV zZ7G-V4VM25N0;OTYnq+B&K9oo&$gfw?n!|qhj=I0Wt1vBl$Tg^F!q{W2ggkXia^`Ch*Y)&TOcz(UPQ3NjrnuL5(WxHhhFnDMeB`G}Vu>#7U(B{sLt j-kf*rV_i&&<6WDi@4L2qSJ@SU71|~s9WHUGB7bS!bO1$7FK39 zb`AlcdPZgzgcLIi6Du2o0HcDCFuRems4>uRMn*PfRyKC1W=1Av76w5@Az@a-L=ne8 zqa@?Tg-T6}O^cLOQbf(%gn;Uqm{~dDRsneof&zvt3JW(L6jDqqoTwBetjsFR2n=9m zCN{WRfxb{Q6mU%Z5U5btIC0^@jTayOzs0}<=To%oqgm!(Z^e_nIR#2;!L0}4xn!tS(#FmqULlZGtIhMayI*X^3PN4 zJHjKor=G8xb#?W1oBG;{$EU8z%{rt_P#zplnFbF5(A z+l`9z78R*Wdzvm+WN>^1mS+aZU(wF-WL|aZ_TwuD%9h{gVpV#x&$DVp{FV({ru#!o zVPdmqS}hj+epl_VK>n zQsq9YTA!T~$#-5xb`@x0)Bgmd< z=4-Y2%lg9G=1r2EC$X+$O6JnbTB(!V+4~qG7f&x-+UKGgXK7yQ?j{pDbrrLwSo-bN z-h0C9O8K6Bve7AY@(DHzZqJv_$ojW^#fx2MR@eE92Tyu4>z3S^AD=en{YilV z<&aVC`!e>jKcg$Fd0H{HIo)qkamiFH(hp19Q78$G(qf8YK$b=sRc_2V;hj#diz zu3Ej!y2(2-&@^PVXl+d4t1BLtPKBAyQF=b{;^#+zJ+V+17`Zj5}uJ7Z0I+uIX zE{PYFetk2m)*HLSy(zGq_l2{|iJtbh=AeaUH;Mda<%hx=S$@xh>GuPpA4&bH?18aW5ttXwvAs;ezpW#^c}VUzIn)?DEk kn{NKJ^9{XofU6-j@721uzV2CCj2i+HXA}zk*#G|~0Q5EfJpcdz literal 0 HcmV?d00001 diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js b/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js new file mode 100644 index 000000000..74bc30836 --- /dev/null +++ b/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js @@ -0,0 +1,3012 @@ +(function(n) { + function w(a, c) { + function r() {} + r.prototype = a; + var b = new r, + f; + for (f in c) b[f] = c[f]; + c.toString !== Object.prototype.toString && (b.toString = c.toString); + return b + } + + function B(a) { + return a instanceof Array ? function() { + return m.iter(a) + } : "function" == typeof a.iterator ? p(a, a.iterator) : a.iterator + } + + function p(a, c) { + if (null == c) return null; + null == c.__id__ && (c.__id__ = G++); + var b; + null == a.hx__closures__ ? a.hx__closures__ = {} : b = a.hx__closures__[c.__id__]; + null == b && (b = function() { + return b.method.apply(b.scope, arguments) + }, + b.scope = a, b.method = c, a.hx__closures__[c.__id__] = b); + return b + } + n.muses = n.muses || {}; + var s = function(a, c) { + c = c.split("u").join(""); + this.r = new RegExp(a, c) + }; + s.__name__ = !0; + s.prototype = { + r: null, + match: function(a) { + this.r.global && (this.r.lastIndex = 0); + this.r.m = this.r.exec(a); + this.r.s = a; + return null != this.r.m + }, + matched: function(a) { + if (null != this.r.m && 0 <= a && a < this.r.m.length) return this.r.m[a]; + throw "EReg::matched"; + }, + __class__: s + }; + var m = function() {}; + m.__name__ = !0; + m.cca = function(a, c) { + var b = a.charCodeAt(c); + return b != b ? void 0 : + b + }; + m.substr = function(a, c, b) { + if (null != c && 0 != c && null != b && 0 > b) return ""; + null == b && (b = a.length); + 0 > c ? (c = a.length + c, 0 > c && (c = 0)) : 0 > b && (b = a.length + b - c); + return a.substr(c, b) + }; + m.indexOf = function(a, c, b) { + var e = a.length; + 0 > b && (b += e, 0 > b && (b = 0)); + for (; b < e;) { + if (a[b] === c) return b; + b++ + } + return -1 + }; + m.remove = function(a, c) { + var b = m.indexOf(a, c, 0); + if (-1 == b) return !1; + a.splice(b, 1); + return !0 + }; + m.iter = function(a) { + return { + cur: 0, + arr: a, + hasNext: function() { + return this.cur < this.arr.length + }, + next: function() { + return this.arr[this.cur++] + } + } + }; + var x = + function() {}; + x.__name__ = !0; + x.exists = function(a, c) { + for (var b = B(a)(); b.hasNext();) { + var e = b.next(); + if (c(e)) return !0 + } + return !1 + }; + var A = function() { + this.length = 0 + }; + A.__name__ = !0; + A.prototype = { + h: null, + length: null, + iterator: function() { + return { + h: this.h, + hasNext: function() { + return null != this.h + }, + next: function() { + if (null == this.h) return null; + var a = this.h[0]; + this.h = this.h[1]; + return a + } + } + }, + __class__: A + }; + var g = n.MRP = function() {}; + g.__name__ = !0; + g.setObject = function() { + eval("MRP.instance = document." + g.objectId + ";"); + null == g.instance && + (g.instance = document.getElementById(g.objectId)) + }; + g.setElementId = function(a) { + g.elementId = a + }; + g.setObjectId = function(a) { + g.objectId = a; + g.setObject() + }; + g.play = function() { + g.instance.playSound() + }; + g.stop = function() { + g.instance.stopSound() + }; + g.setVolume = function(a) { + g.instance.setVolume(a / 100) + }; + g.showInfo = function(a) { + g.instance.showInfo(a) + }; + g.setTitle = function(a) { + g.instance.setTitle(a) + }; + g.setUrl = function(a) { + g.instance.setUrl(a) + }; + g.setFallbackUrl = function(a) { + g.instance.setFallbackUrl(a) + }; + g.setCallbackFunction = + function(a) { + musesCallback = a + }; + g.callbackExists = function() { + var a = "error", + a = typeof musesCallback; + return "undefined" != a && "error" != a + }; + g.getScriptBaseHREF = function() { + return ("https:" == window.document.location.protocol ? "https://" : "http://") + "hosted.muses.org" + }; + g.getSkin = function(a, c) { + return -1 != a.indexOf("/") || c && ("original" == a || "tiny" == a) ? a : g.getScriptBaseHREF() + "/muses-" + a + ".xml" + }; + g.insert = function(a) { + null == a.elementId && null != g.elementId && (a.elementId = g.elementId); + FlashDetect.versionAtLeast(10, 1) ? g.flashInsert(a) : + g.jsInsert(a) + }; + g.jsInsert = function(a) { + a.autoplay = !1; + g.playerCounter++; + var c = "MusesRadioPlayer-HTML5-player-" + g.playerCounter, + b = '
'; + null == a.elementId ? window.document.write(b) : window.document.getElementById(a.elementId).innerHTML = b; + a.elementId = c; + a.skin = g.getSkin(a.skin, !1); + new d.Muses(a) + }; + g.flashInsert = function(a) { + null == a.wmode && (a.wmode = "window"); + null == a.id && (a.id = g.objectId); + var c = "url=" + a.url, + c = c + ("&lang=" + (null != a.lang ? a.lang : + "auto")), + c = c + ("&codec=" + a.codec), + c = c + "&tracking=true" + ("&volume=" + (null != a.volume ? a.volume : 100)); + null != a.introurl && (c += "&introurl=" + a.introurl); + null != a.autoplay && (c += "&autoplay=" + (a.autoplay ? "true" : "false")); + null != a.jsevents && (c += "&jsevents=" + (a.jsevents ? "true" : "false")); + null != a.buffering && (c += "&buffering=" + a.buffering); + null != a.metadataProxy && (c += "&metadataproxy=" + a.metadataProxy); + null != a.reconnectTime && (c += "&reconnecttime=" + a.reconnectTime); + null != a.fallbackUrl && (c += "&fallback=" + a.fallbackUrl); + var c = + c + ("&skin=" + g.getSkin(a.skin, !0)), + c = c + ("&title=" + a.title), + c = c + ("&welcome=" + a.welcome), + b = g.getScriptBaseHREF() + "/muses-hosted.swf", + e = 'width="' + a.width + '" height="' + a.height + '" '; + null != a.bgcolor && (e += 'bgcolor="' + a.bgcolor + '" '); + var f = '", + f = f + ('') + (''), + f = f + (''), + f = f + '', + f = f + ''; + null != a.bgcolor && (f += ''); + f += ''; + f += ""; + null != a.callbackFunction ? g.setCallbackFunction(a.callbackFunction) : 1 != a.jsevents || g.callbackExists() || g.setCallbackFunction(function(a, c) {}); + null == a.elementId ? window.document.write(f) : window.document.getElementById(a.elementId).innerHTML = + f; + g.setObject() + }; + g.main = function() { + g.getScriptBaseHREF() + }; + var z = function() {}; + z.__name__ = !0; + z.prototype = { + exists: null, + remove: null, + iterator: null, + __class__: z + }; + Math.__name__ = !0; + var v = function() {}; + v.__name__ = !0; + v.field = function(a, c) { + try { + return a[c] + } catch (b) { + return null + } + }; + v.setField = function(a, c, b) { + a[c] = b + }; + v.isFunction = function(a) { + return "function" == typeof a && !(a.__name__ || a.__ename__) + }; + var y = function() {}; + y.__name__ = !0; + y.string = function(a) { + return u.Boot.__string_rec(a, "") + }; + y.parseInt = function(a) { + var c = parseInt(a, + 10); + 0 != c || 120 != m.cca(a, 1) && 88 != m.cca(a, 1) || (c = parseInt(a)); + return isNaN(c) ? null : c + }; + var C = function() { + this.b = "" + }; + C.__name__ = !0; + C.prototype = { + b: null, + add: function(a) { + this.b += y.string(a) + }, + addSub: function(a, c, b) { + this.b = null == b ? this.b + m.substr(a, c, null) : this.b + m.substr(a, c, b) + }, + __class__: C + }; + var t = function() {}; + t.__name__ = !0; + t.urlEncode = function(a) { + return encodeURIComponent(a) + }; + t.isSpace = function(a, c) { + var b = m.cca(a, c); + return 8 < b && 14 > b || 32 == b + }; + t.ltrim = function(a) { + for (var c = a.length, b = 0; b < c && t.isSpace(a, b);) b++; + return 0 < b ? m.substr(a, b, c - b) : a + }; + t.rtrim = function(a) { + for (var c = a.length, b = 0; b < c && t.isSpace(a, c - b - 1);) b++; + return 0 < b ? m.substr(a, 0, c - b) : a + }; + t.trim = function(a) { + return t.ltrim(t.rtrim(a)) + }; + t.replace = function(a, c, b) { + return a.split(c).join(b) + }; + t.fastCodeAt = function(a, c) { + return a.charCodeAt(c) + }; + var D = function() {}; + D.__name__ = !0; + D.getInstanceFields = function(a) { + var c = [], + b; + for (b in a.prototype) c.push(b); + m.remove(c, "__class__"); + m.remove(c, "__properties__"); + return c + }; + var h = function() {}; + h.__name__ = !0; + h.parse = function(a) { + return q.xml.Parser.parse(a) + }; + h.createElement = function(a) { + var c = new h; + c.nodeType = h.Element; + c._children = []; + c._attributes = new q.ds.StringMap; + c.set_nodeName(a); + return c + }; + h.createPCData = function(a) { + var c = new h; + c.nodeType = h.PCData; + c.set_nodeValue(a); + return c + }; + h.createCData = function(a) { + var c = new h; + c.nodeType = h.CData; + c.set_nodeValue(a); + return c + }; + h.createComment = function(a) { + var c = new h; + c.nodeType = h.Comment; + c.set_nodeValue(a); + return c + }; + h.createDocType = function(a) { + var c = new h; + c.nodeType = h.DocType; + c.set_nodeValue(a); + return c + }; + h.createProcessingInstruction = + function(a) { + var c = new h; + c.nodeType = h.ProcessingInstruction; + c.set_nodeValue(a); + return c + }; + h.createDocument = function() { + var a = new h; + a.nodeType = h.Document; + a._children = []; + return a + }; + h.prototype = { + nodeType: null, + _nodeName: null, + _nodeValue: null, + _attributes: null, + _children: null, + _parent: null, + get_nodeName: function() { + if (this.nodeType != h.Element) throw "bad nodeType"; + return this._nodeName + }, + set_nodeName: function(a) { + if (this.nodeType != h.Element) throw "bad nodeType"; + return this._nodeName = a + }, + set_nodeValue: function(a) { + if (this.nodeType == + h.Element || this.nodeType == h.Document) throw "bad nodeType"; + return this._nodeValue = a + }, + get: function(a) { + if (this.nodeType != h.Element) throw "bad nodeType"; + return this._attributes.get(a) + }, + set: function(a, c) { + if (this.nodeType != h.Element) throw "bad nodeType"; + this._attributes.set(a, c) + }, + exists: function(a) { + if (this.nodeType != h.Element) throw "bad nodeType"; + return this._attributes.exists(a) + }, + attributes: function() { + if (this.nodeType != h.Element) throw "bad nodeType"; + return this._attributes.keys() + }, + elements: function() { + if (null == + this._children) throw "bad nodetype"; + return { + cur: 0, + x: this._children, + hasNext: function() { + for (var a = this.cur, c = this.x.length; a < c && this.x[a].nodeType != h.Element;) a += 1; + this.cur = a; + return a < c + }, + next: function() { + for (var a = this.cur, c = this.x.length; a < c;) { + var b = this.x[a], + a = a + 1; + if (b.nodeType == h.Element) return this.cur = a, b + } + return null + } + } + }, + addChild: function(a) { + if (null == this._children) throw "bad nodetype"; + null != a._parent && m.remove(a._parent._children, a); + a._parent = this; + this._children.push(a) + }, + __class__: h + }; + var b = { + Campaign: function(a) { + this.responseCount = + 0; + "direct" != a && "organic" != a && "referral" != a && b.Tracker._raiseError("Campaign type has to be one of the Campaign::TYPE_* constant values.", "Campaign.new"); + this.type = a; + switch (a) { + case "direct": + this.source = this.name = "(direct)"; + this.medium = "(none)"; + break; + case "referral": + this.name = "(referral)"; + this.medium = "referral"; + break; + case "organic": + this.name = "(organic)", this.medium = "organic" + } + this.creationTime = new b.DateTime + } + }; + b.Campaign.__name__ = !0; + b.Campaign.createFromReferrer = function(a) { + var c = new b.Campaign("referral"); + a = new b.URLParser(a); + c.source = a.host; + c.content = a.path; + return c + }; + b.Campaign.prototype = { + type: null, + creationTime: null, + responseCount: null, + id: null, + source: null, + gClickId: null, + dClickId: null, + name: null, + medium: null, + term: null, + content: null, + validate: function() { + null == this.source && b.Tracker._raiseError('Campaigns need to have at least the "source" attribute defined.', "Campaign.validate") + }, + setType: function(a) { + this.type = a + }, + getType: function() { + return this.type + }, + setCreationTime: function(a) { + this.creationTime = a + }, + getCreationTime: function() { + return this.creationTime + }, + setResponseCount: function(a) { + this.responseCount = a + }, + getResponseCount: function() { + return this.responseCount + }, + increaseResponseCount: function(a) { + null == a && (a = 1); + this.responseCount += a + }, + setId: function(a) { + this.id = a + }, + getId: function() { + return this.id + }, + setSource: function(a) { + this.source = a + }, + getSource: function() { + return this.source + }, + setGClickId: function(a) { + this.gClickId = a + }, + getGClickId: function() { + return this.gClickId + }, + setDClickId: function(a) { + this.dClickId = a + }, + getDClickId: function() { + return this.dClickId + }, + setName: function(a) { + this.name = + a + }, + getName: function() { + return this.name + }, + setMedium: function(a) { + this.medium = a + }, + getMedium: function() { + return this.medium + }, + setTerm: function(a) { + this.term = a + }, + getTerm: function() { + return this.term + }, + setContent: function(a) { + this.content = a + }, + getContent: function() { + return this.content + }, + __class__: b.Campaign + }; + b.Config = function(a) { + null == a && (a = !1); + this.sitespeedSampleRate = 1; + this.endPointPath = "/__utm.gif"; + this.endPointHost = "www.google-analytics.com"; + this.urlScheme = "http"; + this.requestTimeout = 1; + this.sendOnShutdown = this.fireAndForget = !1; + this.errorSeverity = 2; + this.setUrlScheme("http" + (a ? "s" : "")) + }; + b.Config.__name__ = !0; + b.Config.prototype = { + errorSeverity: null, + sendOnShutdown: null, + fireAndForget: null, + loggingCallback: null, + requestTimeout: null, + urlScheme: null, + endPointHost: null, + endPointPath: null, + sitespeedSampleRate: null, + getErrorSeverity: function() { + return this.errorSeverity + }, + setErrorSeverity: function(a) { + this.errorSeverity = a + }, + getSendOnShutdown: function() { + return this.sendOnShutdown + }, + setSendOnShutdown: function(a) { + this.sendOnShutdown = a + }, + getFireAndForget: function() { + return this.fireAndForget + }, + setFireAndForget: function(a) { + this.fireAndForget = a + }, + getLoggingCallback: function() { + return this.loggingCallback + }, + setLoggingCallback: function(a) { + this.loggingCallback = a + }, + getRequestTimeout: function() { + return this.requestTimeout + }, + setRequestTimeout: function(a) { + this.requestTimeout = a + }, + getUrlScheme: function() { + return this.urlScheme + }, + setUrlScheme: function(a) { + return this.urlScheme = a + }, + getEndPointHost: function() { + return this.endPointHost + }, + setEndPointHost: function(a) { + this.endPointHost = a + }, + getEndPointPath: function() { + return this.endPointPath + }, + setEndPointPath: function(a) { + this.endPointPath = a + }, + getSitespeedSampleRate: function() { + return this.sitespeedSampleRate + }, + setSitespeedSampleRate: function(a) { + 0 > a || 100 < a ? b.Tracker._raiseError("For consistency with ga.js, sample rates must be specified as a number between 0 and 100.", "config.setSitespeedSampleRate") : this.sitespeedSampleRate = a + }, + __class__: b.Config + }; + b.CustomVariable = function(a, c, b, e) { + null == e && (e = 0); + null == a && (a = 0); + this.scope = 3; + 0 != a && this.setIndex(a); + null != c && this.setName(c); + null != b && this.setValue(b); + 0 != e && this.setScope(e) + }; + b.CustomVariable.__name__ = !0; + b.CustomVariable.prototype = { + index: null, + name: null, + value: null, + scope: null, + validate: function() { + 128 < (this.name + y.string(this.value)).length && b.Tracker._raiseError("Custom Variable combined name and value length must not be larger than 128 bytes.", "CustomVariable.validate") + }, + getIndex: function() { + return this.index + }, + setIndex: function(a) { + (1 > a || 5 < a) && b.Tracker._raiseError("Custom Variable index has to be between 1 and 5.", "CustomVariable.setIndex"); + this.index = + a + }, + getName: function() { + return this.name + }, + setName: function(a) { + this.name = a + }, + getValue: function() { + return this.value + }, + setValue: function(a) { + this.value = a + }, + getScope: function() { + return this.scope + }, + setScope: function(a) { + 3 != a && 2 != a && 1 != a && b.Tracker._raiseError("Custom Variable scope has to be one of the CustomVariable::SCOPE_* constant values.", "CustomVariable.setScope"); + this.scope = a + }, + __class__: b.CustomVariable + }; + b.DateTime = function(a) { + this.date = null == a ? Math.round((new Date).getTime()) + "" : a + }; + b.DateTime.__name__ = !0; + b.DateTime.prototype = { + date: null, + toString: function() { + return this.date + }, + __class__: b.DateTime + }; + b.Event = function(a, c, b, e, f) { + null == f && (f = !1); + null == e && (e = 0); + this.noninteraction = !1; + null != a && this.setCategory(a); + null != c && this.setAction(c); + null != b && this.setLabel(b); + this.setValue(e); + this.setNoninteraction(f) + }; + b.Event.__name__ = !0; + b.Event.prototype = { + category: null, + action: null, + label: null, + value: null, + noninteraction: null, + validate: function() { + null != this.category && null != this.action || b.Tracker._raiseError("Events need at least to have a category and action defined.", + "Event.validate") + }, + getCategory: function() { + return this.category + }, + setCategory: function(a) { + this.category = a + }, + getAction: function() { + return this.action + }, + setAction: function(a) { + this.action = a + }, + getLabel: function() { + return this.label + }, + setLabel: function(a) { + this.label = a + }, + getValue: function() { + return this.value + }, + setValue: function(a) { + this.value = a + }, + getNoninteraction: function() { + return this.noninteraction + }, + setNoninteraction: function(a) { + this.noninteraction = a + }, + __class__: b.Event + }; + b.Item = function() { + this.quantity = 1 + }; + b.Item.__name__ = !0; + b.Item.prototype = { + orderId: null, + sku: null, + name: null, + variation: null, + price: null, + quantity: null, + validate: function() { + null == this.sku && b.Tracker._raiseError("Items need to have a sku/product code defined.", "Item.validate") + }, + getOrderId: function() { + return this.orderId + }, + setOrderId: function(a) { + this.orderId = a + }, + getSku: function() { + return this.sku + }, + setSku: function(a) { + this.sku = a + }, + getName: function() { + return this.name + }, + setName: function(a) { + this.name = a + }, + getVariation: function() { + return this.variation + }, + setVariation: function(a) { + this.variation = + a + }, + getPrice: function() { + return this.price + }, + setPrice: function(a) { + this.price = a + }, + getQuantity: function() { + return this.quantity + }, + setQuantity: function(a) { + this.quantity = a + }, + __class__: b.Item + }; + b.Page = function(a) { + this.setPath(a) + }; + b.Page.__name__ = !0; + b.Page.prototype = { + path: null, + title: null, + charset: null, + referrer: null, + loadTime: null, + setPath: function(a) { + null != a && "/" != a.charAt(0) && b.Tracker._raiseError('The page path should always start with a slash ("/").', "Page.setPath"); + this.path = a + }, + getPath: function() { + return this.path + }, + setTitle: function(a) { + this.title = a + }, + getTitle: function() { + return this.title + }, + setCharset: function(a) { + this.charset = a + }, + getCharset: function() { + return this.charset + }, + setReferrer: function(a) { + this.referrer = a + }, + getReferrer: function() { + return this.referrer + }, + setLoadTime: function(a) { + this.loadTime = a + }, + getLoadTime: function() { + return this.loadTime + }, + __class__: b.Page + }; + b.Session = function() { + this.setSessionId(this.generateSessionId()); + this.setTrackCount(0); + this.setStartTime(new b.DateTime) + }; + b.Session.__name__ = !0; + b.Session.prototype = { + sessionId: null, + trackCount: null, + startTime: null, + fromUtmb: function(a) { + a = a.split("."); + if (4 != a.length) return b.Tracker._raiseError('The given "__utmb" cookie value is invalid.', "Session.fromUtmb"), this; + this.setTrackCount(b.internals.Util.parseInt(a[1], 0)); + this.setStartTime(new b.DateTime(a[3])); + return this + }, + generateSessionId: function() { + return b.internals.Util.generate32bitRandom() + }, + getSessionId: function() { + return this.sessionId + }, + setSessionId: function(a) { + this.sessionId = a + }, + getTrackCount: function() { + return this.trackCount + }, + setTrackCount: function(a) { + this.trackCount = a + }, + increaseTrackCount: function(a) { + null == a && (a = 1); + this.trackCount += a + }, + getStartTime: function() { + return this.startTime + }, + setStartTime: function(a) { + this.startTime = a + }, + __class__: b.Session + }; + b.SocialInteraction = function(a, c, b) { + null != a && this.setNetwork(a); + null != c && this.setAction(c); + null != b && this.setTarget(b) + }; + b.SocialInteraction.__name__ = !0; + b.SocialInteraction.prototype = { + network: null, + action: null, + target: null, + validate: function() { + null != this.network && null != this.action || b.Tracker._raiseError('Social interactions need to have at least the "network" and "action" attributes defined.', + "SocialInteraction.validate") + }, + setNetwork: function(a) { + this.network = a + }, + getNetwork: function() { + return this.network + }, + setAction: function(a) { + this.action = a + }, + getAction: function() { + return this.action + }, + setTarget: function(a) { + this.target = a + }, + getTarget: function() { + return this.target + }, + __class__: b.SocialInteraction + }; + b.Stats = function() {}; + b.Stats.__name__ = !0; + b.Stats.init = function(a, c) { + null == b.Stats.accountId && (b.Stats.accountId = a, b.Stats.domainName = c, b.Stats.tracker = new b.Tracker(a, c), b.Stats.cache = new q.ds.StringMap, + b.Stats.session = new b.Session, b.Stats.loadVisitor()) + }; + b.Stats.trackPageview = function(a, c) { + var r = "page:" + a; + if (!b.Stats.cache.exists(r)) { + var e = new b.Page(a); + null != c && e.setTitle(c); + e = new b._Stats.GATrackObject(e, null); + b.Stats.cache.set(r, e) + } + b.Stats.track(r) + }; + b.Stats.trackEvent = function(a, c, r, e) { + null == e && (e = 0); + var f = "event:" + a + "/" + c + "/" + r + ":" + e; + b.Stats.cache.exists(f) || (a = new b._Stats.GATrackObject(null, new b.Event(a, c, r, e)), b.Stats.cache.set(f, a)); + b.Stats.track(f) + }; + b.Stats.track = function(a) { + b.Stats.cache.get(a).track(b.Stats.tracker, + b.Stats.visitor, b.Stats.session); + b.Stats.persistVisitor() + }; + b.Stats.loadVisitor = function() { + b.Stats.visitor = new b.Visitor; + b.Stats.visitor.setUserAgent("-not-set- [haxe]"); + b.Stats.visitor.setScreenResolution("1024x768"); + b.Stats.visitor.setLocale("en_US"); + b.Stats.visitor.getUniqueId(); + b.Stats.visitor.addSession(b.Stats.session); + b.Stats.persistVisitor() + }; + b.Stats.persistVisitor = function() {}; + b._Stats = {}; + b._Stats.GATrackObject = function(a, c) { + this.page = a; + this.event = c + }; + b._Stats.GATrackObject.__name__ = !0; + b._Stats.GATrackObject.prototype = { + event: null, + page: null, + track: function(a, c, b) { + null != this.page && a.trackPageview(this.page, b, c); + null != this.event && a.trackEvent(this.event, b, c) + }, + __class__: b._Stats.GATrackObject + }; + b.Tracker = function(a, c, r) { + this.allowHash = !0; + this.customVariables = []; + b.Tracker.setConfig(null != r ? r : new b.Config); + this.setAccountId(a); + this.setDomainName(c) + }; + b.Tracker.__name__ = !0; + b.Tracker.getConfig = function() { + return b.Tracker.config + }; + b.Tracker.setConfig = function(a) { + b.Tracker.config = a + }; + b.Tracker._raiseError = function(a, c) { + a = c + "(): " + + a; + switch (null != b.Tracker.config ? b.Tracker.config.getErrorSeverity() : 0) { + case 1: + console.log(a); + break; + case 2: + throw a; + } + }; + b.Tracker.prototype = { + accountId: null, + domainName: null, + allowHash: null, + customVariables: null, + campaign: null, + setAccountId: function(a) { + (new s("^(UA|MO)-[0-9]*-[0-9]*$", "")).match(a) || b.Tracker._raiseError('"' + a + '" is not a valid Google Analytics account ID.', "Tracker.setAccountId"); + this.accountId = a + }, + getAccountId: function() { + return this.accountId + }, + setDomainName: function(a) { + this.domainName = a + }, + getDomainName: function() { + return this.domainName + }, + setAllowHash: function(a) { + this.allowHash = a + }, + getAllowHash: function() { + return this.allowHash + }, + addCustomVariable: function(a) { + a.validate(); + this.customVariables[a.getIndex()] = a + }, + getCustomVariables: function() { + return this.customVariables + }, + removeCustomVariable: function(a) { + m.remove(this.customVariables, this.customVariables[a]) + }, + setCampaign: function(a) { + null != a && a.validate(); + this.campaign = a + }, + getCampaign: function() { + return this.campaign + }, + trackPageview: function(a, + c, r) { + var e = new b.internals.request.PageviewRequest(b.Tracker.config); + e.setPage(a); + e.setSession(c); + e.setVisitor(r); + e.setTracker(this); + e.send() + }, + trackEvent: function(a, c, r) { + a.validate(); + var e = new b.internals.request.EventRequest(b.Tracker.config); + e.setEvent(a); + e.setSession(c); + e.setVisitor(r); + e.setTracker(this); + e.send() + }, + trackTransaction: function(a, c, r) { + a.validate(); + var e = new b.internals.request.TransactionRequest(b.Tracker.config); + e.setTransaction(a); + e.setSession(c); + e.setVisitor(r); + e.setTracker(this); + e.send(); + for (a = a.getItems().iterator(); a.hasNext();) { + e = a.next(); + e.validate(); + var f = new b.internals.request.ItemRequest(b.Tracker.config); + f.setItem(e); + f.setSession(c); + f.setVisitor(r); + f.setTracker(this); + f.send() + } + }, + trackSocial: function(a, c, r, e) { + var f = new b.internals.request.SocialInteractionRequest(b.Tracker.config); + f.setSocialInteraction(a); + f.setPage(c); + f.setSession(r); + f.setVisitor(e); + f.setTracker(this); + f.send() + }, + __class__: b.Tracker + }; + b.Transaction = function() { + this.items = new q.ds.StringMap + }; + b.Transaction.__name__ = !0; + b.Transaction.prototype = { + orderId: null, + affiliation: null, + total: null, + tax: null, + shipping: null, + city: null, + region: null, + country: null, + items: null, + validate: function() { + null == this.items && b.Tracker._raiseError("Transactions need to consist of at least one item.", "Transaction.validate") + }, + addItem: function(a) { + a.setOrderId(this.orderId); + var c = a.getSku(); + this.items.set(c, a) + }, + getItems: function() { + return this.items + }, + getOrderId: function() { + return this.orderId + }, + setOrderId: function(a) { + this.orderId = a; + for (var c = this.items.iterator(); c.hasNext();) c.next().setOrderId(a) + }, + getAffiliation: function() { + return this.affiliation + }, + setAffiliation: function(a) { + this.affiliation = a + }, + getTotal: function() { + return this.total + }, + setTotal: function(a) { + this.total = a + }, + getTax: function() { + return this.tax + }, + setTax: function(a) { + this.tax = a + }, + getShipping: function() { + return this.shipping + }, + setShipping: function(a) { + this.shipping = a + }, + getCity: function() { + return this.city + }, + setCity: function(a) { + this.city = a + }, + getRegion: function() { + return this.region + }, + setRegion: function(a) { + this.region = a + }, + getCountry: function() { + return this.country + }, + setCountry: function(a) { + this.country = a + }, + __class__: b.Transaction + }; + b.URLParser = function(a) { + this.url = a; + var c = new s("^(?:(?![^:@]+:[^:@/]*@)([^:/?#.]+):)?(?://)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:/?#]*)(?::(\\d*))?)(((/(?:[^?#](?![^?#/]*\\.[^?#/.]+(?:[?#]|$)))*/?)?([^?#/]*))(?:\\?([^#]*))?(?:#(.*))?)", ""); + c.match(a); + a = 0; + for (var r = b.URLParser.parts.length; a < r;) { + var e = a++; + v.setField(this, b.URLParser.parts[e], c.matched(e)) + } + }; + b.URLParser.__name__ = !0; + b.URLParser.parse = function(a) { + return new b.URLParser(a) + }; + b.URLParser.prototype = { + url: null, + source: null, + protocol: null, + authority: null, + userInfo: null, + user: null, + password: null, + host: null, + port: null, + relative: null, + path: null, + directory: null, + file: null, + query: null, + anchor: null, + toString: function() { + for (var a = "For Url -> " + this.url + "\n", c = 0, r = b.URLParser.parts.length; c < r;) var e = c++, + a = a + (b.URLParser.parts[e] + ": " + y.string(v.field(this, b.URLParser.parts[e])) + (e == b.URLParser.parts.length - 1 ? "" : "\n")); + return a + }, + __class__: b.URLParser + }; + b.Visitor = function() { + var a = new b.DateTime; + this.uniqueId = + 0; + this.setFirstVisitTime(a); + this.setPreviousVisitTime(a); + this.setCurrentVisitTime(a); + this.setVisitCount(1) + }; + b.Visitor.__name__ = !0; + b.Visitor.prototype = { + uniqueId: null, + firstVisitTime: null, + previousVisitTime: null, + currentVisitTime: null, + visitCount: null, + ipAddress: null, + userAgent: null, + locale: null, + flashVersion: null, + javaEnabled: null, + screenColorDepth: null, + screenResolution: null, + fromUtma: function(a) { + a = a.split("."); + if (6 != a.length) return b.Tracker._raiseError('The given "__utma" cookie value is invalid.', "Visitor.fromUtma"), + this; + this.setUniqueId(b.internals.Util.parseInt(a[1], 0)); + this.setFirstVisitTime(new b.DateTime(a[2])); + this.setPreviousVisitTime(new b.DateTime(a[3])); + this.setCurrentVisitTime(new b.DateTime(a[4])); + this.setVisitCount(b.internals.Util.parseInt(a[5], 0)); + return this + }, + generateHash: function() { + return b.internals.Util.generateHash(this.userAgent + this.screenResolution + this.screenColorDepth) + }, + generateUniqueId: function() { + return (b.internals.Util.generate32bitRandom() ^ this.generateHash()) & 2147483647 + }, + setUniqueId: function(a) { + (0 > + a || 2147483647 < a) && b.Tracker._raiseError("Visitor unique ID has to be a 32-bit integer between 0 and 2147483647.", "Visitor.setUniqueId"); + this.uniqueId = a + }, + getUniqueId: function() { + 0 == this.uniqueId && (this.uniqueId = this.generateUniqueId()); + return this.uniqueId + }, + addSession: function(a) { + a = a.getStartTime(); + a != this.currentVisitTime && (this.previousVisitTime = this.currentVisitTime, this.currentVisitTime = a, ++this.visitCount) + }, + setFirstVisitTime: function(a) { + this.firstVisitTime = a + }, + getFirstVisitTime: function() { + return this.firstVisitTime + }, + setPreviousVisitTime: function(a) { + this.previousVisitTime = a + }, + getPreviousVisitTime: function() { + return this.previousVisitTime + }, + setCurrentVisitTime: function(a) { + this.currentVisitTime = a + }, + getCurrentVisitTime: function() { + return this.currentVisitTime + }, + setVisitCount: function(a) { + this.visitCount = a + }, + getVisitCount: function() { + return this.visitCount + }, + setIpAddress: function(a) { + this.ipAddress = a + }, + getIpAddress: function() { + return this.ipAddress + }, + setUserAgent: function(a) { + this.userAgent = a + }, + getUserAgent: function() { + return this.userAgent + }, + setLocale: function(a) { + this.locale = a + }, + getLocale: function() { + return this.locale + }, + setFlashVersion: function(a) { + this.flashVersion = a + }, + getFlashVersion: function() { + return this.flashVersion + }, + setJavaEnabled: function(a) { + this.javaEnabled = a + }, + getJavaEnabled: function() { + return this.javaEnabled + }, + setScreenColorDepth: function(a) { + this.screenColorDepth = a + }, + getScreenColorDepth: function() { + return this.screenColorDepth + }, + setScreenResolution: function(a) { + this.screenResolution = a + }, + getScreenResolution: function() { + return this.screenResolution + }, + __class__: b.Visitor + }; + b.internals = {}; + b.internals.ParameterHolder = function() { + this.utmwv = "5.2.5"; + this.utmr = this.utmcs = this.utmfl = this.utmje = "0" + }; + b.internals.ParameterHolder.__name__ = !0; + b.internals.ParameterHolder.prototype = { + utmwv: null, + utmac: null, + utmhn: null, + utmvid: null, + utmt: null, + utms: null, + utmn: null, + utmcc: null, + utme: null, + utmni: null, + utmu: null, + utmp: null, + utmdt: null, + utmcs: null, + utmr: null, + utmip: null, + utmul: null, + utmfl: null, + utmje: null, + utmsc: null, + utmsr: null, + __utma: null, + utmhid: null, + __utmb: null, + __utmc: null, + utmipc: null, + utmipn: null, + utmipr: null, + utmiqt: null, + utmiva: null, + utmtid: null, + utmtst: null, + utmtto: null, + utmttx: null, + utmtsp: null, + utmtci: null, + utmtrg: null, + utmtco: null, + utmcn: null, + utmcr: null, + utmcid: null, + utmcsr: null, + utmgclid: null, + utmdclid: null, + utmccn: null, + utmcmd: null, + utmctr: null, + utmcct: null, + utmcvr: null, + __utmz: null, + utmsn: null, + utmsa: null, + utmsid: null, + __utmx: null, + __utmv: null, + toHashTable: function() { + for (var a = new q.ds.StringMap, c = 0, r = D.getInstanceFields(b.internals.ParameterHolder); c < r.length;) { + var e = r[c]; + ++c; + if ("_" != e.charAt(0) && + !v.isFunction(v.field(this, e))) { + var f = v.field(this, e); + a.set(e, f) + } + } + return a + }, + toQueryString: function() { + for (var a = "", c = 0, r = D.getInstanceFields(b.internals.ParameterHolder); c < r.length;) { + var e = r[c]; + ++c; + "_" == e.charAt(0) || v.isFunction(v.field(this, e)) || null == v.field(this, e) || "null" == v.field(this, e) || (a += e + "=" + t.replace(y.string(v.field(this, e)) + "", "&", "%26") + "&") + } + return a + }, + __class__: b.internals.ParameterHolder + }; + b.internals.Util = function() {}; + b.internals.Util.__name__ = !0; + b.internals.Util.encodeUriComponent = + function(a) { + return b.internals.Util.convertToUriComponentEncoding(t.urlEncode(a)) + }; + b.internals.Util.stringReplaceArray = function(a, c, b) { + for (var e = 0, f = c.length; e < f;) { + var d = e++; + null != c[d] && (a = t.replace(a + " ", c[d], b[d])) + } + return t.trim(a) + }; + b.internals.Util.parseInt = function(a, c) { + return null == a ? c : y.parseInt(a) + }; + b.internals.Util.convertToUriComponentEncoding = function(a) { + return b.internals.Util.stringReplaceArray(a, "!*'() +".split(""), "%21 %2A %27 %28 %29 %20 %20".split(" ")) + }; + b.internals.Util.generate32bitRandom = + function() { + return Math.round(2147483647 * Math.random()) + }; + b.internals.Util.generateHash = function(a) { + var c = 1, + b; + if (null != a && "" != a) + for (var c = 0, e = a.length - 1; 0 <= e;) b = m.cca(a, e), c = (c << 6 & 268435455) + b + (b << 14), b = c & 266338304, 0 != b && (c ^= b >> 21), e--; + return c + }; + b.internals.X10 = function() { + this.projectData = new q.ds.StringMap; + this.KEY = "k"; + this.VALUE = "v"; + this.SET = ["k", "v"]; + this.DELIM_BEGIN = "("; + this.DELIM_END = ")"; + this.DELIM_SET = "*"; + this.DELIM_NUM_VALUE = "!"; + this.MINIMUM = 1; + this.ESCAPE_CHAR_MAP = new q.ds.StringMap; + this.ESCAPE_CHAR_MAP.set("'", + "'0"); + this.ESCAPE_CHAR_MAP.set(")", "'1"); + this.ESCAPE_CHAR_MAP.set("*", "'2"); + this.ESCAPE_CHAR_MAP.set("!", "'3") + }; + b.internals.X10.__name__ = !0; + b.internals.X10.prototype = { + projectData: null, + KEY: null, + VALUE: null, + SET: null, + DELIM_BEGIN: null, + DELIM_END: null, + DELIM_SET: null, + DELIM_NUM_VALUE: null, + ESCAPE_CHAR_MAP: null, + MINIMUM: null, + hasProject: function(a) { + return this.projectData.exists(a) + }, + setKey: function(a, c, b) { + this.setInternal(a, this.KEY, c, b) + }, + getKey: function(a, c) { + return this.getInternal(a, this.KEY, c) + }, + clearKey: function(a) { + this.clearInternal(a, + this.KEY) + }, + setValue: function(a, c, b) { + this.setInternal(a, this.VALUE, c, b) + }, + getValue: function(a, c) { + return this.getInternal(a, this.VALUE, c) + }, + clearValue: function(a) { + this.clearInternal(a, this.VALUE) + }, + setInternal: function(a, c, b, e) { + if (!this.projectData.exists(a)) { + var f = new q.ds.StringMap; + this.projectData.set(a, f) + } + a = this.projectData.get(a); + a.exists(c) || a.set(c, []); + a.get(c)[b] = e + }, + getInternal: function(a, c, b) { + if (!this.projectData.exists(a)) return null; + a = this.projectData.get(a); + if (!a.exists(c)) return null; + c = a.get(c); + return null == c[b] ? null : c[b] + }, + clearInternal: function(a, c) { + var b; + if (b = this.projectData.exists(a)) b = this.projectData.get(a).exists(c); + b && this.projectData.get(a).remove(c) + }, + escapeExtensibleValue: function(a) { + for (var c = "", b = 0, e = a.length; b < e;) var f = b++, + f = a.charAt(f), + c = this.ESCAPE_CHAR_MAP.exists(f) ? c + this.ESCAPE_CHAR_MAP.get(f) : c + f; + return c + }, + SORT_NUMERIC: function(a, c) { + return a == c ? 0 : a > c ? 1 : -1 + }, + renderDataType: function(a) { + for (var c = [], b = 0, e = 0, f = a.length; e < f;) { + var d = e++, + g = a[d]; + if (null != g) { + var k = ""; + d != this.MINIMUM && + d - 1 != b && (k += d, k += this.DELIM_NUM_VALUE); + k += this.escapeExtensibleValue(g); + c.push(k) + } + b = d + } + return this.DELIM_BEGIN + c.join(this.DELIM_SET) + this.DELIM_END + }, + renderProject: function(a) { + for (var c = "", b = !1, e = 0, f = this.SET.length; e < f;) { + var d = e++; + a.exists(this.SET[d]) ? (b && (c += this.SET[d]), c += this.renderDataType(a.get(this.SET[d])), b = !1) : b = !0 + } + return c + }, + renderUrlString: function() { + for (var a = "", c = this.projectData.keys(); c.hasNext();) var b = c.next(), + a = a + (b + this.renderProject(this.projectData.get(b))); + return a + }, + __class__: b.internals.X10 + }; + b.internals.request = {}; + b.internals.request.Request = function(a) { + this.setConfig(null != a ? a : new b.Config) + }; + b.internals.request.Request.__name__ = !0; + b.internals.request.Request.onError = function(a) {}; + b.internals.request.Request.prototype = { + type: null, + config: null, + userAgent: null, + tracker: null, + visitor: null, + session: null, + getConfig: function() { + return this.config + }, + setConfig: function(a) { + this.config = a + }, + setUserAgent: function(a) { + this.userAgent = a + }, + getTracker: function() { + return this.tracker + }, + setTracker: function(a) { + this.tracker = + a + }, + getVisitor: function() { + return this.visitor + }, + setVisitor: function(a) { + this.visitor = a + }, + getSession: function() { + return this.session + }, + setSession: function(a) { + this.session = a + }, + increaseTrackCount: function() { + this.session.increaseTrackCount(); + 500 < this.session.getTrackCount() && b.Tracker._raiseError("Google Analytics does not guarantee to process more than 500 requests per session.", "Request.buildHttpRequest"); + null != this.tracker.getCampaign() && this.tracker.getCampaign().increaseResponseCount() + }, + send: function() { + if (null != + this.config.getEndPointHost()) { + var a = this.buildParameters(); + null != this.visitor && (this.setUserAgent(this.visitor.getUserAgent()), a.utmvid = this.visitor.getUniqueId()); + a = b.internals.Util.convertToUriComponentEncoding(a.toQueryString()); + a = this.config.getUrlScheme() + "://" + this.config.getEndPointHost() + this.config.getEndPointPath() + "?" + a; + this.increaseTrackCount(); + (new Image).src = a + } + }, + getType: function() { + return null + }, + buildParameters: function() { + var a = new b.internals.ParameterHolder; + a.utmac = this.tracker.getAccountId(); + a.utmhn = this.tracker.getDomainName(); + a.utmt = "" + this.getType(); + a.utmn = b.internals.Util.generate32bitRandom(); + a.utmip = this.visitor.getIpAddress(); + a.utmhid = this.session.getSessionId(); + a.utms = this.session.getTrackCount(); + a = this.buildVisitorParameters(a); + a = this.buildCustomVariablesParameter(a); + a = this.buildCampaignParameters(a); + return a = this.buildCookieParameters(a) + }, + buildVisitorParameters: function(a) { + null != this.visitor.getLocale() && (a.utmul = t.replace(this.visitor.getLocale(), "_", "-").toLowerCase()); + null != + this.visitor.getFlashVersion() && (a.utmfl = this.visitor.getFlashVersion()); + this.visitor.getJavaEnabled() ? a.utmje = "1" : a.utmje = "0"; + null != this.visitor.getScreenColorDepth() && (a.utmsc = this.visitor.getScreenColorDepth() + "-bit"); + a.utmsr = this.visitor.getScreenResolution(); + return a + }, + buildCustomVariablesParameter: function(a) { + var c = this.tracker.getCustomVariables(); + if (null == c) return a; + 5 < c.length && b.Tracker._raiseError("The sum of all custom variables cannot exceed 5 in any given request.", "Request.buildCustomVariablesParameter"); + var r = new b.internals.X10, + e, f; + r.clearKey("8"); + r.clearKey("9"); + r.clearKey("11"); + for (var d = 0; d < c.length;) { + var g = c[d]; + ++d; + e = b.internals.Util.encodeUriComponent(g.getName()); + f = b.internals.Util.encodeUriComponent(g.getValue()); + r.setKey("8", g.getIndex(), e); + r.setKey("9", g.getIndex(), f); + 3 != g.getScope() && r.setKey("11", g.getIndex(), g.getScope()) + } + c = r.renderUrlString(); + null != c && (a.utme = null == a.utme ? c : a.utme + c); + return a + }, + buildCookieParameters: function(a) { + var c = this.generateDomainHash(); + a.__utma = c + "."; + a.__utma += + this.visitor.getUniqueId() + "."; + a.__utma += this.visitor.getFirstVisitTime().toString() + "."; + a.__utma += this.visitor.getPreviousVisitTime().toString() + "."; + a.__utma += this.visitor.getCurrentVisitTime().toString() + "."; + a.__utma += this.visitor.getVisitCount(); + a.__utmb = c + "."; + a.__utmb += this.session.getTrackCount() + "."; + a.__utmb += "10."; + a.__utmb += this.session.getStartTime().toString(); + a.__utmc = c; + c = "__utma=" + a.__utma + ";"; + null != a.__utmz && (c += "+__utmz=" + a.__utmz + ";"); + null != a.__utmv && (c += "+__utmv=" + a.__utmv + ";"); + a.utmcc = + c; + return a + }, + buildCampaignParameters: function(a) { + var c = this.tracker.getCampaign(); + if (null == c) return a; + a.__utmz = this.generateDomainHash() + "."; + a.__utmz += c.getCreationTime().toString() + "."; + a.__utmz += this.visitor.getVisitCount() + "."; + a.__utmz += c.getResponseCount() + "."; + c = "utmcid=" + c.getId() + "|utmcsr=" + c.getSource() + "|utmgclid=" + c.getGClickId() + "|utmdclid=" + c.getDClickId() + "|utmccn=" + c.getName() + "|utmcmd=" + c.getMedium() + "|utmctr=" + c.getTerm() + "|utmcct=" + c.getContent(); + a.__utmz += t.replace(t.replace(c, "+", + "%20"), " ", "%20"); + return a + }, + generateDomainHash: function() { + var a = 1; + this.tracker.getAllowHash() && (a = b.internals.Util.generateHash(this.tracker.getDomainName())); + return a + }, + __class__: b.internals.request.Request + }; + b.internals.request.EventRequest = function(a) { + b.internals.request.Request.call(this, a) + }; + b.internals.request.EventRequest.__name__ = !0; + b.internals.request.EventRequest.__super__ = b.internals.request.Request; + b.internals.request.EventRequest.prototype = w(b.internals.request.Request.prototype, { + event: null, + getType: function() { + return "event" + }, + buildParameters: function() { + var a = b.internals.request.Request.prototype.buildParameters.call(this), + c = new b.internals.X10; + c.clearKey("5"); + c.clearValue("5"); + c.setKey("5", 1, this.event.getCategory()); + c.setKey("5", 2, this.event.getAction()); + null != this.event.getLabel() && c.setKey("5", 3, this.event.getLabel()); + 0 != this.event.getValue() && c.setValue("5", 1, this.event.getValue()); + c = c.renderUrlString(); + null != c && (a.utme = null == a.utme ? c : a.utme + c); + this.event.getNoninteraction() && (a.utmni = + 1); + return a + }, + getEvent: function() { + return this.event + }, + setEvent: function(a) { + this.event = a + }, + __class__: b.internals.request.EventRequest + }); + b.internals.request.ItemRequest = function(a) { + b.internals.request.Request.call(this, a) + }; + b.internals.request.ItemRequest.__name__ = !0; + b.internals.request.ItemRequest.__super__ = b.internals.request.Request; + b.internals.request.ItemRequest.prototype = w(b.internals.request.Request.prototype, { + item: null, + getType: function() { + return "item" + }, + buildParameters: function() { + var a = b.internals.request.Request.prototype.buildParameters.call(this); + a.utmtid = this.item.getOrderId(); + a.utmipc = this.item.getSku(); + a.utmipn = this.item.getName(); + a.utmiva = this.item.getVariation(); + a.utmipr = this.item.getPrice(); + a.utmiqt = this.item.getQuantity(); + return a + }, + buildVisitorParameters: function(a) { + return a + }, + buildCustomVariablesParameter: function(a) { + return a + }, + getItem: function() { + return this.item + }, + setItem: function(a) { + this.item = a + }, + __class__: b.internals.request.ItemRequest + }); + b.internals.request.PageviewRequest = function(a) { + b.internals.request.Request.call(this, a) + }; + b.internals.request.PageviewRequest.__name__ = !0; + b.internals.request.PageviewRequest.__super__ = b.internals.request.Request; + b.internals.request.PageviewRequest.prototype = w(b.internals.request.Request.prototype, { + page: null, + getType: function() { + return null + }, + buildParameters: function() { + var a = b.internals.request.Request.prototype.buildParameters.call(this); + a.utmp = this.page.getPath(); + a.utmdt = this.page.getTitle(); + null != this.page.getCharset() && (a.utmcs = this.page.getCharset()); + null != this.page.getReferrer() && (a.utmr = this.page.getReferrer()); + 0 != this.page.getLoadTime() && + a.utmn % 100 < this.config.getSitespeedSampleRate() && (a.utme = null == a.utme ? "0" : a.utme + 0); + return a + }, + getPage: function() { + return this.page + }, + setPage: function(a) { + this.page = a + }, + __class__: b.internals.request.PageviewRequest + }); + b.internals.request.SocialInteractionRequest = function(a) { + b.internals.request.PageviewRequest.call(this, a) + }; + b.internals.request.SocialInteractionRequest.__name__ = !0; + b.internals.request.SocialInteractionRequest.__super__ = b.internals.request.PageviewRequest; + b.internals.request.SocialInteractionRequest.prototype = + w(b.internals.request.PageviewRequest.prototype, { + socialInteraction: null, + getType: function() { + return "social" + }, + buildParameters: function() { + var a = b.internals.request.PageviewRequest.prototype.buildParameters.call(this); + a.utmsn = this.socialInteraction.getNetwork(); + a.utmsa = this.socialInteraction.getAction(); + a.utmsid = this.socialInteraction.getTarget(); + null == a.utmsid && (a.utmsid = this.page.getPath()); + return a + }, + getSocialInteraction: function() { + return this.socialInteraction + }, + setSocialInteraction: function(a) { + this.socialInteraction = + a + }, + __class__: b.internals.request.SocialInteractionRequest + }); + b.internals.request.TransactionRequest = function(a) { + b.internals.request.Request.call(this, a) + }; + b.internals.request.TransactionRequest.__name__ = !0; + b.internals.request.TransactionRequest.__super__ = b.internals.request.Request; + b.internals.request.TransactionRequest.prototype = w(b.internals.request.Request.prototype, { + transaction: null, + getType: function() { + return "tran" + }, + buildParameters: function() { + var a = b.internals.request.Request.prototype.buildParameters.call(this); + a.utmtid = this.transaction.getOrderId(); + a.utmtst = this.transaction.getAffiliation(); + a.utmtto = this.transaction.getTotal(); + a.utmttx = this.transaction.getTax(); + a.utmtsp = this.transaction.getShipping(); + a.utmtci = this.transaction.getCity(); + a.utmtrg = this.transaction.getRegion(); + a.utmtco = this.transaction.getCountry(); + return a + }, + buildVisitorParameters: function(a) { + return a + }, + buildCustomVariablesParameter: function(a) { + return a + }, + getTransaction: function() { + return this.transaction + }, + setTransaction: function(a) { + this.transaction = + a + }, + __class__: b.internals.request.TransactionRequest + }); + var q = { + Http: function(a) { + this.url = a; + this.headers = new A; + this.params = new A; + this.async = !0 + } + }; + q.Http.__name__ = !0; + q.Http.requestUrl = function(a) { + a = new q.Http(a); + a.async = !1; + var c = null; + a.onData = function(a) { + c = a + }; + a.onError = function(a) { + throw a; + }; + a.request(!1); + return c + }; + q.Http.prototype = { + url: null, + responseData: null, + async: null, + postData: null, + headers: null, + params: null, + req: null, + request: function(a) { + var c = this; + c.responseData = null; + var b = this.req = u.Browser.createXMLHttpRequest(), + e = function(a) { + if (4 == b.readyState) { + var e; + try { + e = b.status + } catch (f) { + e = null + } + void 0 == e && (e = null); + if (null != e) c.onStatus(e); + if (null != e && 200 <= e && 400 > e) c.req = null, c.onData(c.responseData = b.responseText); + else if (null == e) c.req = null, c.onError("Failed to connect or resolve host"); + else switch (e) { + case 12029: + c.req = null; + c.onError("Failed to connect to host"); + break; + case 12007: + c.req = null; + c.onError("Unknown host"); + break; + default: + c.req = null, c.responseData = b.responseText, c.onError("Http Error #" + b.status) + } + } + }; + this.async && + (b.onreadystatechange = e); + var f = this.postData; + if (null != f) a = !0; + else + for (var d = this.params.iterator(); d.hasNext();) var g = d.next(), + f = null == f ? "" : f + "&", + f = f + (encodeURIComponent(g.param) + "=" + encodeURIComponent(g.value)); + try { + if (a) b.open("POST", this.url, this.async); + else if (null != f) { + var k = 1 >= this.url.split("?").length; + b.open("GET", this.url + (k ? "?" : "&") + f, this.async); + f = null + } else b.open("GET", this.url, this.async) + } catch (h) { + c.req = null; + this.onError(h.toString()); + return + }!x.exists(this.headers, function(a) { + return "Content-Type" == + a.header + }) && a && null == this.postData && b.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); + for (a = this.headers.iterator(); a.hasNext();) d = a.next(), b.setRequestHeader(d.header, d.value); + b.send(f); + this.async || e(null) + }, + onData: function(a) {}, + onError: function(a) {}, + onStatus: function(a) {}, + __class__: q.Http + }; + q.Timer = function(a) { + var c = this; + this.id = setInterval(function() { + c.run() + }, a) + }; + q.Timer.__name__ = !0; + q.Timer.delay = function(a, c) { + var b = new q.Timer(c); + b.run = function() { + b.stop(); + a() + }; + return b + }; + q.Timer.prototype = { + id: null, + stop: function() { + null != this.id && (clearInterval(this.id), this.id = null) + }, + run: function() {}, + __class__: q.Timer + }; + q.ds = {}; + q.ds.StringMap = function() { + this.h = {} + }; + q.ds.StringMap.__name__ = !0; + q.ds.StringMap.__interfaces__ = [z]; + q.ds.StringMap.prototype = { + h: null, + set: function(a, c) { + this.h["$" + a] = c + }, + get: function(a) { + return this.h["$" + a] + }, + exists: function(a) { + return this.h.hasOwnProperty("$" + a) + }, + remove: function(a) { + a = "$" + a; + if (!this.h.hasOwnProperty(a)) return !1; + delete this.h[a]; + return !0 + }, + keys: function() { + var a = [], + c; + for (c in this.h) this.h.hasOwnProperty(c) && a.push(c.substr(1)); + return m.iter(a) + }, + iterator: function() { + return { + ref: this.h, + it: this.keys(), + hasNext: function() { + return this.it.hasNext() + }, + next: function() { + var a = this.it.next(); + return this.ref["$" + a] + } + } + }, + __class__: q.ds.StringMap + }; + q.io = {}; + q.io.Eof = function() {}; + q.io.Eof.__name__ = !0; + q.io.Eof.prototype = { + toString: function() { + return "Eof" + }, + __class__: q.io.Eof + }; + q.xml = {}; + q.xml.Parser = function() {}; + q.xml.Parser.__name__ = !0; + q.xml.Parser.parse = function(a) { + var c = h.createDocument(); + q.xml.Parser.doParse(a, 0, c); + return c + }; + q.xml.Parser.doParse = function(a, c, b) { + null == c && (c = 0); + for (var e = null, f = 1, d = 1, g = null, k = 0, p = 0, n = 0, l = a.charCodeAt(c), s = new C; l == l;) { + switch (f) { + case 0: + switch (l) { + case 10: + case 13: + case 9: + case 32: + break; + default: + f = d; + continue + } + break; + case 1: + switch (l) { + case 60: + f = 0; + d = 2; + break; + default: + k = c; + f = 13; + continue + } + break; + case 13: + 60 == l ? (d = h.createPCData(s.b + m.substr(a, k, c - k)), s = new C, b.addChild(d), p++, f = 0, d = 2) : 38 == l && (s.addSub(a, k, c - k), f = 18, d = 13, k = c + 1); + break; + case 17: + 93 == l && 93 == a.charCodeAt(c + 1) && + 62 == a.charCodeAt(c + 2) && (f = h.createCData(m.substr(a, k, c - k)), b.addChild(f), p++, c += 2, f = 1); + break; + case 2: + switch (l) { + case 33: + if (91 == a.charCodeAt(c + 1)) { + c += 2; + if ("CDATA[" != m.substr(a, c, 6).toUpperCase()) throw "Expected = l || 65 <= l && 90 >= l || 48 <= l && 57 >= l || 58 == l || 46 == l || 95 == l || 45 == l)) { + if (c == k) throw "Expected node name"; + e = h.createElement(m.substr(a, k, c - k)); + b.addChild(e); + f = 0; + d = 4; + continue + } + break; + case 4: + switch (l) { + case 47: + f = 11; + p++; + break; + case 62: + f = 9; + p++; + break; + default: + f = 5; + k = c; + continue + } + break; + case 5: + if (!(97 <= l && 122 >= l || 65 <= l && 90 >= l || 48 <= l && 57 >= l || 58 == l || 46 == l || 95 == l || 45 == l)) { + if (k == c) throw "Expected attribute name"; + g = m.substr(a, + k, c - k); + if (e.exists(g)) throw "Duplicate attribute"; + f = 0; + d = 6; + continue + } + break; + case 6: + switch (l) { + case 61: + f = 0; + d = 7; + break; + default: + throw "Expected ="; + } + break; + case 7: + switch (l) { + case 34: + case 39: + f = 8; + k = c; + break; + default: + throw 'Expected "'; + } + break; + case 8: + l == a.charCodeAt(k) && (d = m.substr(a, k + 1, c - k - 1), e.set(g, d), f = 0, d = 4); + break; + case 9: + k = c = q.xml.Parser.doParse(a, c, e); + f = 1; + break; + case 11: + switch (l) { + case 62: + f = 1; + break; + default: + throw "Expected >"; + } + break; + case 12: + switch (l) { + case 62: + return 0 == p && b.addChild(h.createPCData("")), c; + default: + throw "Expected >"; + } + case 10: + if (!(97 <= l && 122 >= l || 65 <= l && 90 >= l || 48 <= l && 57 >= l || 58 == l || 46 == l || 95 == l || 45 == l)) { + if (k == c) throw "Expected node name"; + if (m.substr(a, k, c - k) != b.get_nodeName()) throw "Expected "; + f = 0; + d = 12; + continue + } + break; + case 15: + 45 == l && 45 == a.charCodeAt(c + 1) && 62 == a.charCodeAt(c + 2) && (b.addChild(h.createComment(m.substr(a, k, c - k))), c += 2, f = 1); + break; + case 16: + 91 == l ? n++ : 93 == l ? n-- : 62 == l && 0 == n && (b.addChild(h.createDocType(m.substr(a, k, c - k))), f = 1); + break; + case 14: + 63 == l && 62 == a.charCodeAt(c + 1) && (c++, f = m.substr(a, + k + 1, c - k - 2), b.addChild(h.createProcessingInstruction(f)), f = 1); + break; + case 18: + 59 == l && (k = m.substr(a, k, c - k), 35 == k.charCodeAt(0) ? (k = 120 == k.charCodeAt(1) ? y.parseInt("0" + m.substr(k, 1, k.length - 1)) : y.parseInt(m.substr(k, 1, k.length - 1)), s.add(String.fromCharCode(k))) : q.xml.Parser.escapes.exists(k) ? s.add(q.xml.Parser.escapes.get(k)) : s.b += y.string("&" + k + ";"), k = c + 1, f = d) + } + l = t.fastCodeAt(a, ++c) + } + 1 == f && (k = c, f = 13); + if (13 == f) return c == k && 0 != p || b.addChild(h.createPCData(s.b + m.substr(a, k, c - k))), c; + throw "Unexpected end"; + }; + var u = { + Boot: function() {} + }; + u.Boot.__name__ = !0; + u.Boot.getClass = function(a) { + return a instanceof Array && null == a.__enum__ ? Array : a.__class__ + }; + u.Boot.__string_rec = function(a, c) { + if (null == a) return "null"; + if (5 <= c.length) return "<...>"; + var b = typeof a; + "function" == b && (a.__name__ || a.__ename__) && (b = "object"); + switch (b) { + case "object": + if (a instanceof Array) { + if (a.__enum__) { + if (2 == a.length) return a[0]; + b = a[0] + "("; + c += "\t"; + for (var e = 2, d = a.length; e < d;) var g = e++, + b = 2 != g ? b + ("," + u.Boot.__string_rec(a[g], c)) : b + u.Boot.__string_rec(a[g], + c); + return b + ")" + } + b = a.length; + e = "["; + c += "\t"; + for (d = 0; d < b;) g = d++, e += (0 < g ? "," : "") + u.Boot.__string_rec(a[g], c); + return e + "]" + } + try { + e = a.toString + } catch (h) { + return "???" + } + if (null != e && e != Object.toString && (b = a.toString(), "[object Object]" != b)) return b; + b = null; + e = "{\n"; + c += "\t"; + d = null != a.hasOwnProperty; + for (b in a) d && !a.hasOwnProperty(b) || "prototype" == b || "__class__" == b || "__super__" == b || "__interfaces__" == b || "__properties__" == b || (2 != e.length && (e += ", \n"), e += c + b + " : " + u.Boot.__string_rec(a[b], c)); + c = c.substring(1); + return e + + ("\n" + c + "}"); + case "function": + return ""; + case "string": + return a; + default: + return String(a) + } + }; + u.Boot.__interfLoop = function(a, c) { + if (null == a) return !1; + if (a == c) return !0; + var b = a.__interfaces__; + if (null != b) + for (var e = 0, d = b.length; e < d;) { + var g = e++, + g = b[g]; + if (g == c || u.Boot.__interfLoop(g, c)) return !0 + } + return u.Boot.__interfLoop(a.__super__, c) + }; + u.Boot.__instanceof = function(a, c) { + if (null == c) return !1; + switch (c) { + case H: + return (a | 0) === a; + case E: + return "number" == typeof a; + case F: + return "boolean" == typeof a; + case String: + return "string" == + typeof a; + case Array: + return a instanceof Array && null == a.__enum__; + case I: + return !0; + default: + if (null != a) { + if ("function" == typeof c && (a instanceof c || u.Boot.__interfLoop(u.Boot.getClass(a), c))) return !0 + } else return !1; + return c == J && null != a.__name__ || c == K && null != a.__ename__ ? !0 : a.__enum__ == c + } + }; + u.Browser = function() {}; + u.Browser.__name__ = !0; + u.Browser.createXMLHttpRequest = function() { + if ("undefined" != typeof XMLHttpRequest) return new XMLHttpRequest; + if ("undefined" != typeof ActiveXObject) return new ActiveXObject("Microsoft.XMLHTTP"); + throw "Unable to create XMLHttpRequest object."; + }; + var d = {}; + d.Muses = n.muses.Muses = function(a) { + this.src = this.name = this.lastMessage = null; + this.progress = 0; + this.lastAudioName = null; + this.playURL = ""; + this.playTimeout = this.bufferingTimeout = 0; + this.desiredStatus = "stop"; + this.audio = this.lastAudioStatus = this.lastAudioSrc = null; + this.src = a.url; + this.name = a.title; + this.audio = new Audio; + this.ui = new d.UI(this, a); + a.autoplay && (a = window.navigator.userAgent.toLowerCase(), -1 == a.indexOf("iphone") && -1 == a.indexOf("ipad") && -1 == a.indexOf("ipod") && + this.playAudio()) + }; + d.Muses.__name__ = !0; + d.Muses.initTimer = function(a) { + -1 == m.indexOf(d.Muses.instances, a, 0) && d.Muses.instances.push(a); + null == d.Muses.statusTimer && (d.Muses.statusTimer = new q.Timer(500), d.Muses.statusTimer.run = function() { + for (var a = 0, b = d.Muses.instances; a < b.length;) { + var e = b[a]; + ++a; + try { + e.checkAudioStatus() + } catch (f) { + if (u.Boot.__instanceof(f, String)) console.log("Error: " + f); + else throw f; + } + } + }) + }; + d.Muses.prototype = { + audio: null, + lastAudioStatus: null, + lastAudioSrc: null, + desiredStatus: null, + playTimeout: null, + bufferingTimeout: null, + playURL: null, + lastAudioName: null, + progress: null, + src: null, + name: null, + lastMessage: null, + ui: null, + playAudio: function() { + d.Muses.initTimer(this); + this.stopAudio(!1); + this.playURL = this.src; + this.desiredStatus = "play"; + this.playTimeout = 3600; + this.bufferingTimeout = 40; + this.lastAudioSrc = this.audio.src = this.src; + this.lastAudioName = this.name; + this.lastAudioStatus = null; + this.audio.autoplay = !0; + this.audio.play(); + this.ui.setPlaying(); + d.Tracker.track(this.src, this.name, this.ui, !0) + }, + stopAudio: function(a) { + this.desiredStatus = + "stop"; + null != this.audio && (this.audio.pause(), this.audio.src = ""); + a && (this.lastAudioStatus = 4) + }, + retryAudio: function() { + var a = this; + this.lastAudioStatus = -1; + q.Timer.delay(function() { + -1 == a.lastAudioStatus && a.playAudio() + }, 2E3) + }, + setVolume: function(a) { + this.audio.volume = a; + null != this.ui && this.ui.setVolume(a) + }, + checkAudioStatus: function() { + var a = "", + a = null; + if (null != this.audio) { + a = this.audio.networkState; + y.string(this.audio.error); + if (2 == a || 1 == a) a = 0 == this.audio.played.length ? 1 : 2; + if (null != this.audio.error || 4 == this.lastAudioStatus) a = + 3 + } + 0 == a ? (a = "Error al conectar", this.lastMessage != a && this.ui.setError()) : -1 == a ? a = "retry..." : null == a ? a = "init" : 1 == a ? (this.bufferingTimeout--, 0 == this.bufferingTimeout && this.retryAudio(), a = "Buffering... " + Math.round(this.bufferingTimeout / 2), this.lastMessage != a && this.ui.setBuffering()) : 2 == a ? (this.playTimeout--, 0 == this.playTimeout && this.retryAudio(), a = "Playing... ", this.lastMessage != a && this.ui.setPlaying()) : 4 == a || 3 == a ? "play" == this.desiredStatus ? (a = "Error de red", this.retryAudio(), this.lastMessage != a && this.ui.setError()) : + (a = "Stopped.", this.lastMessage != a && this.ui.setStopped()) : (a = "ERROR: " + a, console.log(a)); + this.lastMessage = a + }, + __class__: d.Muses + }; + d.Tracker = function() {}; + d.Tracker.__name__ = !0; + d.Tracker.track = function(a, c, g, e) { + d.Tracker.enabled && (null == d.Tracker.tracked && (d.Tracker.tracked = new q.ds.StringMap, b.Stats.init("UA-12297597-1", "hosted.musesradioplayer.com")), e && d.Tracker.tracked.get(a) || (b.Stats.trackPageview("/tracker/track.php?version=0.2 beta&url=" + a + "&player=HTML5&skin=" + g.skin, "Muses - HTML5 Tracking [Radio: " + + c + "]"), d.Tracker.tracked.set(a, !0))) + }; + d.UI = n.muses.UI = function(a, c) { + this.skinFolder = this.baseURL = this.skinDomain = ""; + this.togglePlayStopEnabled = this.lastToggleValue = !1; + this.mainDiv = this.playButton = this.stopButton = this.volumeControl = this.bg = this.statusText = this.artistText = this.songTitleText = this.statusLed = null; + this.skin = ""; + var b = this; + this.title = c.title; + this.skin = c.skin; + this.muses = a; + this.mainDiv = window.document.getElementById(c.elementId); + this.mainDiv.style.position = "relative"; + this.statusText = new d.skin.TitleText(this); + this.artistText = new d.skin.TitleText(this); + this.songTitleText = new d.skin.TitleText(this); + this.statusLed = new d.skin.StatusLed(this); + this.volumeControl = new d.skin.VolumeControl(this, this.muses); + this.volumeControl.setVolume(c.volume / 100); + this.playButton = new d.skin.Button(this, "play"); + this.stopButton = new d.skin.Button(this, "stop"); + this.loadSkin(this.skin); + this.statusLed.configured && this.mainDiv.appendChild(this.statusLed.container); + this.statusText.configured && this.mainDiv.appendChild(this.statusText.container); + this.artistText.configured && this.mainDiv.appendChild(this.artistText.container); + this.songTitleText.configured && this.mainDiv.appendChild(this.songTitleText.container); + this.volumeControl.configured && this.mainDiv.appendChild(this.volumeControl.container); + this.mainDiv.appendChild(this.playButton.container); + this.mainDiv.appendChild(this.stopButton.container); + this.stopButton.container.onclick = function(a) { + b.muses.stopAudio(!1) + }; + this.playButton.container.onclick = function(a) { + b.muses.playAudio() + }; + this.showInfo(c.welcome) + }; + d.UI.__name__ = !0; + d.UI.parseInt = function(a, c) { + return null == a ? c : y.parseInt(a) + }; + d.UI.prototype = { + skin: null, + mainDiv: null, + playButton: null, + stopButton: null, + volumeControl: null, + bg: null, + statusText: null, + artistText: null, + songTitleText: null, + statusLed: null, + togglePlayStopEnabled: null, + lastToggleValue: null, + skinFolder: null, + baseURL: null, + skinDomain: null, + title: null, + titleTimer: null, + muses: null, + XmlToLower: function(a) { + for (var c = a.attributes(); c.hasNext();) { + var b = c.next(); + a.set(b.toLowerCase(), a.get(b)) + } + }, + enablePlayStopToggle: function() { + this.togglePlayStopEnabled = !0; + this.togglePlayStop(this.lastToggleValue) + }, + togglePlayStop: function(a) { + this.lastToggleValue = a; + this.togglePlayStopEnabled && (this.playButton.setVisible(!a), this.stopButton.setVisible(a)) + }, + makeAbsolute: function(a) { + return -1 != a.indexOf("://") ? a : "/" == a.charAt(0) ? this.skinDomain + a : this.baseURL + a + }, + getDomainName: function(a) { + a += "/"; + var c = a.indexOf("://"); + if (-1 == c) return ""; + c = a.indexOf("/", c + 3); + return m.substr(a, 0, c) + }, + getDirName: function(a) { + var c = a.lastIndexOf("/"); + return -1 == c ? "" : m.substr(a, 0, c + 1) + }, + loadSkin: function(a) { + var c = + q.Http.requestUrl(a); + this.baseURL = this.getDirName(a); + this.skinDomain = this.getDomainName(a); + a = !1; + for (c = h.parse(c).elements(); c.hasNext();) { + var b = c.next(); + if ("ffmp3-skin" != b.get_nodeName().toLowerCase() && "muses-skin" != b.get_nodeName().toLowerCase()) break; + this.XmlToLower(b); + null == b.get("folder") ? this.skinFolder = "" : this.skinFolder = b.get("folder"); + (a = null == b.get("toggleplaystop") ? !1 : "true" == b.get("toggleplaystop")) && this.enablePlayStopToggle(); + 0 < this.skinFolder.length && "/" != this.skinFolder.charAt(this.skinFolder.length - + 1) && (this.skinFolder += "/"); + this.skinFolder = this.makeAbsolute(this.skinFolder); + for (a = b.elements(); a.hasNext();) switch (b = a.next(), this.XmlToLower(b), b.get_nodeName().toLowerCase()) { + case "bg": + this.configureBG(b); + break; + case "play": + this.playButton.configure(b); + break; + case "stop": + this.stopButton.configure(b); + break; + case "text": + this.statusText.configureText(b, "left"); + break; + case "status": + this.statusLed.configure(b); + break; + case "volume": + this.volumeControl.configure(b); + break; + case "artist": + this.artistText.configureText(b, + "left"); + break; + case "songtitle": + this.songTitleText.configureText(b, "left") + } + } + }, + loadImage: function(a, c) { + a.src = this.skinFolder + c + }, + configureBG: function(a) { + this.bg = new Image; + this.loadImage(this.bg, a.get("image")); + this.bg.style.position = "absolute"; + this.bg.style.left = d.UI.parseInt(a.get("x"), 0) + "px"; + this.bg.style.top = d.UI.parseInt(a.get("y"), 0) + "px"; + this.mainDiv.appendChild(this.bg) + }, + configureButton: function(a, c) { + a.src = this.skinFolder + c.get("image"); + a.style.position = "absolute"; + a.style.left = d.UI.parseInt(c.get("x"), + 0) + "px"; + a.style.top = d.UI.parseInt(c.get("y"), 0) + "px" + }, + setPlaying: function() { + this.showInfo("Play"); + this.statusLed.on(); + this.togglePlayStop(!0) + }, + setStopped: function() { + this.showInfo("Stop"); + this.statusLed.off(); + this.togglePlayStop(!1) + }, + setBuffering: function() { + this.showInfo("Buffering"); + this.statusLed.on(); + this.togglePlayStop(!0) + }, + setError: function() { + this.showInfo("Error"); + this.statusLed.off() + }, + setVolume: function(a) { + this.volumeControl.setVolume(a); + this.showInfo("Volume: " + Math.round(100 * a) + "%") + }, + showInfo: function(a, + c) { + null == c && (c = !0); + null == a ? this.restoreTitle() : (null != this.titleTimer && this.titleTimer.stop(), this.statusText.setText(a), c && (this.titleTimer = new q.Timer(2E3), this.titleTimer.run = p(this, this.restoreTitle))) + }, + restoreTitle: function() { + null != this.titleTimer && this.titleTimer.stop(); + this.statusText.setText(this.title) + }, + __class__: d.UI + }; + d.skin = {}; + d.skin.UIComponent = function(a) { + this.ui = a; + this.configured = !1; + this.container = window.document.createElement("div"); + this.container.style.position = "absolute" + }; + d.skin.UIComponent.__name__ = !0; + d.skin.UIComponent.prototype = { + container: null, + configured: null, + ui: null, + setVisible: function(a) { + this.container.style.display = a ? "block" : "none" + }, + configure: function(a) { + this.configured = !0; + this.container.style.left = d.UI.parseInt(a.get("x"), 0) + "px"; + this.container.style.top = d.UI.parseInt(a.get("y"), 0) + "px"; + null != a.get("width") && (this.container.style.width = d.UI.parseInt(a.get("width"), 0) + "px"); + null != a.get("height") && (this.container.style.height = d.UI.parseInt(a.get("height"), 0) + "px") + }, + appendChild: function(a, + c) { + null == c && (c = !0); + a.style.position = "absolute"; + a.style.left = a.style.top = "0px"; + a.style.display = c ? "block" : "none"; + this.container.appendChild(a) + }, + __class__: d.skin.UIComponent + }; + d.skin.Button = function(a, c) { + var b = this; + d.skin.UIComponent.call(this, a); + this.mouseOverState = new Image; + this.mouseDownState = new Image; + this.noMouseState = new Image; + this.container.title = c; + this.mouseDownState.style.opacity = "0"; + this.mouseOverState.style.opacity = "0"; + this.container.onmouseup = function(a) { + b.mouseDownState.style.opacity = "0"; + b.mouseOverState.style.opacity = "1" + }; + this.container.onmousedown = function(a) { + b.mouseDownState.style.opacity = "1"; + b.mouseOverState.style.opacity = "0" + }; + this.container.onmouseover = function(a) { + b.mouseOverState.style.opacity = "1" + }; + this.container.onmouseout = function(a) { + b.mouseDownState.style.opacity = "0"; + b.mouseOverState.style.opacity = "0" + } + }; + d.skin.Button.__name__ = !0; + d.skin.Button.__super__ = d.skin.UIComponent; + d.skin.Button.prototype = w(d.skin.UIComponent.prototype, { + mouseOverState: null, + mouseDownState: null, + noMouseState: null, + configure: function(a) { + d.skin.UIComponent.prototype.configure.call(this, a); + null != a.get("bgimage") && (this.ui.loadImage(this.noMouseState, a.get("bgimage")), this.appendChild(this.noMouseState)); + null != a.get("clickimage") && (this.ui.loadImage(this.mouseDownState, a.get("clickimage")), this.appendChild(this.mouseDownState)); + this.ui.loadImage(this.mouseOverState, a.get("image")); + this.appendChild(this.mouseOverState) + }, + __class__: d.skin.Button + }); + d.skin.StatusLed = function(a) { + d.skin.UIComponent.call(this, a); + this.playMC = + new Image; + this.stopMC = new Image + }; + d.skin.StatusLed.__name__ = !0; + d.skin.StatusLed.__super__ = d.skin.UIComponent; + d.skin.StatusLed.prototype = w(d.skin.UIComponent.prototype, { + playMC: null, + stopMC: null, + configure: function(a) { + d.skin.UIComponent.prototype.configure.call(this, a); + null != a.get("imageplay") && -1 == a.get("imageplay").indexOf(".swf") && (this.ui.loadImage(this.playMC, a.get("imageplay")), this.appendChild(this.playMC, !1)); + null != a.get("imagestop") && -1 == a.get("imagestop").indexOf(".swf") && (this.ui.loadImage(this.stopMC, + a.get("imagestop")), this.appendChild(this.stopMC, !0)) + }, + on: function() { + this.playMC.style.display = "block"; + this.stopMC.style.display = "none" + }, + off: function() { + this.playMC.style.display = "none"; + this.stopMC.style.display = "block" + }, + __class__: d.skin.StatusLed + }); + d.skin.TitleText = function(a) { + d.skin.UIComponent.call(this, a); + this.container.style.fontFamily = "Silkscreen"; + this.container.style.fontSize = "12px" + }; + d.skin.TitleText.__name__ = !0; + d.skin.TitleText.__super__ = d.skin.UIComponent; + d.skin.TitleText.prototype = w(d.skin.UIComponent.prototype, { + configureText: function(a, b) { + this.configure(a); + switch (a.get("align")) { + case "center": + this.container.style.textAlign = "center"; + break; + case "right": + this.container.style.textAlign = "right"; + break; + default: + this.container.style.textAlign = b + } + this.container.style.padding = "2px"; + this.container.style.whiteSpace = "nowrap"; + this.container.style.fontFamily = a.get("font"); + this.container.style.fontSize = d.UI.parseInt(a.get("size"), 12) + "px"; + this.container.style.color = a.get("color"); + this.container.style.overflow = "hidden" + }, + setText: function(a) { + this.container.innerHTML = + a + }, + __class__: d.skin.TitleText + }); + d.skin.VolumeControl = function(a, b) { + d.skin.UIComponent.call(this, a); + this.muses = b; + this.firstDraw = !0; + this.bars = null; + this.mousePressed = !1; + this.volume = 1; + this.setMode("bars"); + this.draw(this.container); + this.vertMargin = this.horizMargin = this.height = this.width = 0; + this.barStep = 2; + this.barWidth = 1; + this.barColors = this.bgColors = null + }; + d.skin.VolumeControl.__name__ = !0; + d.skin.VolumeControl.__super__ = d.skin.UIComponent; + d.skin.VolumeControl.prototype = w(d.skin.UIComponent.prototype, { + volume: null, + width: null, + height: null, + horizMargin: null, + horizDesp: null, + vertMargin: null, + vertDesp: null, + barStep: null, + barWidth: null, + bgColors: null, + barColors: null, + bars: null, + cover: null, + spriteBar: null, + firstDraw: null, + mode: null, + holder: null, + mousePressed: null, + muses: null, + draw: function(a) {}, + setMode: function(a) { + switch (a.toLowerCase()) { + case "bars": + this.draw = p(this, this.drawBars); + break; + case "holder": + this.draw = p(this, this.drawHolder); + break; + case "vholder": + this.draw = p(this, this.drawVHolder) + } + this.mode = a + }, + drawHolder: function(a) { + this.holder.style.left = + this.volume * (this.width - this.holder.width) + "px" + }, + drawVHolder: function(a) { + this.holder.style.top = (1 - this.volume) * (this.height - this.holder.height) + "px" + }, + drawBars: function(a) { + if (null != this.barColors && 0 != this.barStep && (a = Math.round((this.width - 2 * this.horizMargin) / this.barStep), 0 != a)) { + var b = (this.height - 2 * this.vertMargin + 1) / a, + d = this.height - this.vertMargin, + e = this.horizMargin; + if (null == this.bars) { + this.bars = []; + for (var f = 0; f < a;) { + var g = f++, + h; + h = window.document.createElement("div"); + this.bars.push(h); + this.appendChild(h); + h.style.left = e + g * this.barStep + "px"; + h.style.top = d - g * b + "px"; + h.style.width = Math.round(this.barWidth) + "px"; + h.style.height = Math.ceil(g * b) + "px" + } + } + b = 0; + for (d = Math.round(this.volume * a); b < d;) e = b++, this.bars[e].style.backgroundColor = this.barColors[0]; + for (b = Math.round(this.volume * a); b < a;) d = b++, this.bars[d].style.backgroundColor = this.barColors[1] + } + }, + setVolume: function(a) { + this.volume != a && (this.volume = a, 1 < this.volume && (this.volume = 1), 0 > this.volume && (this.volume = 0), this.muses.setVolume(this.volume), this.draw(this.container)) + }, + getVolume: function() { + return this.volume + }, + mouseDown: function(a) { + var b; + this.mousePressed = !0; + "vholder" != this.mode ? (a = a.layerX, b = this.width) : (a = this.height - a.layerY, b = this.height); + a -= .06 * b; + 0 > a && (a = 0); + a = Math.round(1.06 * a); + a > b && (a = b); + this.setVolume(a / (b - 2)) + }, + mouseUp: function(a) { + this.mousePressed = !1 + }, + mouseMove: function(a) { + this.mousePressed && this.mouseDown(a) + }, + mouseWheel: function(a) { + 0 < a.wheelDelta ? this.setVolume(this.volume + .025) : this.setVolume(this.volume - .025) + }, + configure: function(a) { + d.skin.UIComponent.prototype.configure.call(this, + a); + this.width = d.UI.parseInt(a.get("width"), 0); + this.height = d.UI.parseInt(a.get("height"), 0); + this.barColors = [a.get("color1"), a.get("color2")]; + this.barStep = d.UI.parseInt(a.get("barstep"), 2); + this.barWidth = d.UI.parseInt(a.get("barwidth"), 1); + var b; + b = null != a.get("mode") ? a.get("mode").toLowerCase() : null; + this.setMode(b); + if ("holder" == b || "vholder" == b) this.holder = new Image, this.holder.onload = p(this, this.holderLoad), this.ui.loadImage(this.holder, a.get("holderimage")), this.appendChild(this.holder); + this.draw(this.container); + this.cover = window.document.createElement("div"); + this.cover.onmousedown = p(this, this.mouseDown); + this.cover.onmousemove = p(this, this.mouseMove); + this.cover.onmousewheel = p(this, this.mouseWheel); + this.cover.onmouseup = p(this, this.mouseUp); + this.cover.onmouseout = p(this, this.mouseUp); + this.cover.style.width = this.container.style.width; + this.cover.style.height = this.container.style.height; + this.appendChild(this.cover) + }, + holderLoad: function(a) { + this.holder.style.left = .5 * (this.width - this.holder.width) + "px"; + this.holder.style.top = + .5 * (this.height - this.holder.height) + "px"; + this.draw(this.container) + }, + __class__: d.skin.VolumeControl + }); + var G = 0; + Array.prototype.indexOf && (m.indexOf = function(a, b, d) { + return Array.prototype.indexOf.call(a, b, d) + }); + Math.NaN = Number.NaN; + Math.NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY; + Math.POSITIVE_INFINITY = Number.POSITIVE_INFINITY; + Math.isFinite = function(a) { + return isFinite(a) + }; + Math.isNaN = function(a) { + return isNaN(a) + }; + String.prototype.__class__ = String; + String.__name__ = !0; + Array.__name__ = !0; + Date.prototype.__class__ = + Date; + Date.__name__ = ["Date"]; + var H = { + __name__: ["Int"] + }, + I = { + __name__: ["Dynamic"] + }, + E = Number; + E.__name__ = ["Float"]; + var F = Boolean; + F.__ename__ = ["Bool"]; + var J = { + __name__: ["Class"] + }, + K = {}; + h.Element = "element"; + h.PCData = "pcdata"; + h.CData = "cdata"; + h.Comment = "comment"; + h.DocType = "doctype"; + h.ProcessingInstruction = "processingInstruction"; + h.Document = "document"; + g.objectId = "MRPObject"; + g.playerCounter = 0; + g.__hostPrefix = "hosted"; + g.__hostMidfix = "muses"; + b.Campaign.TYPE_DIRECT = "direct"; + b.Campaign.TYPE_ORGANIC = "organic"; + b.Campaign.TYPE_REFERRAL = + "referral"; + b.Config.ERROR_SEVERITY_SILENCE = 0; + b.Config.ERROR_SEVERITY_TRACE = 1; + b.Config.ERROR_SEVERITY_EXCEPTIONS = 2; + b.CustomVariable.SCOPE_VISITOR = 1; + b.CustomVariable.SCOPE_SESSION = 2; + b.CustomVariable.SCOPE_PAGE = 3; + b.Page.REFERRER_INTERNAL = "0"; + b.Tracker.VERSION = "5.2.5"; + b.URLParser.parts = "source protocol authority userInfo user password host port relative path directory file query anchor".split(" "); + b.internals.X10.OBJECT_KEY_NUM = 1; + b.internals.X10.TYPE_KEY_NUM = 2; + b.internals.X10.LABEL_KEY_NUM = 3; + b.internals.X10.VALUE_VALUE_NUM = + 1; + b.internals.request.Request.TYPE_EVENT = "event"; + b.internals.request.Request.TYPE_TRANSACTION = "tran"; + b.internals.request.Request.TYPE_ITEM = "item"; + b.internals.request.Request.TYPE_SOCIAL = "social"; + b.internals.request.Request.TYPE_CUSTOMVARIABLE = "var"; + b.internals.request.Request.X10_CUSTOMVAR_NAME_PROJECT_ID = "8"; + b.internals.request.Request.X10_CUSTOMVAR_VALUE_PROJECT_ID = "9"; + b.internals.request.Request.X10_CUSTOMVAR_SCOPE_PROJECT_ID = "11"; + b.internals.request.Request.CAMPAIGN_DELIMITER = "|"; + b.internals.request.EventRequest.X10_EVENT_PROJECT_ID = + "5"; + q.xml.Parser.escapes = function(a) { + a = new q.ds.StringMap; + a.set("lt", "<"); + a.set("gt", ">"); + a.set("amp", "&"); + a.set("quot", '"'); + a.set("apos", "'"); + a.set("nbsp", String.fromCharCode(160)); + return a + }(this); + d.Muses.VERSION = "0.2 beta"; + d.Muses.instances = []; + d.Tracker.enabled = !0; + g.main() +})("undefined" != typeof window ? window : exports); +var FlashDetect = new function() { + var n = this; + n.installed = !1; + n.raw = ""; + n.major = -1; + n.minor = -1; + n.revision = -1; + n.revisionStr = ""; + var w = [{ + name: "ShockwaveFlash.ShockwaveFlash.7", + version: function(p) { + return B(p) + } + }, { + name: "ShockwaveFlash.ShockwaveFlash.6", + version: function(p) { + var n = "6,0,21"; + try { + p.AllowScriptAccess = "always", n = B(p) + } catch (m) {} + return n + } + }, { + name: "ShockwaveFlash.ShockwaveFlash", + version: function(p) { + return B(p) + } + }], + B = function(p) { + var n = -1; + try { + n = p.GetVariable("$version") + } catch (m) {} + return n + }; + n.majorAtLeast = function(p) { + return n.major >= + p + }; + n.minorAtLeast = function(p) { + return n.minor >= p + }; + n.revisionAtLeast = function(p) { + return n.revision >= p + }; + n.versionAtLeast = function(p) { + var s = [n.major, n.minor, n.revision], + m = Math.min(s.length, arguments.length); + for (i = 0; i < m; i++) + if (s[i] >= arguments[i]) { + if (!(i + 1 < m && s[i] == arguments[i])) return !0 + } else return !1 + }; + n.FlashDetect = function() { + var p, s, m, x, A; + if (navigator.plugins && 0 < navigator.plugins.length) { + var g = navigator.mimeTypes; + if (g && g["application/x-shockwave-flash"] && g["application/x-shockwave-flash"].enabledPlugin && + g["application/x-shockwave-flash"].enabledPlugin.description) { + p = g = g["application/x-shockwave-flash"].enabledPlugin.description; + var g = p.split(/ +/), + z = g[2].split(/\./), + g = g[3]; + s = parseInt(z[0], 10); + m = parseInt(z[1], 10); + x = g; + A = parseInt(g.replace(/[a-zA-Z]/g, ""), 10) || n.revision; + n.raw = p; + n.major = s; + n.minor = m; + n.revisionStr = x; + n.revision = A; + n.installed = !0 + } + } else if (-1 == navigator.appVersion.indexOf("Mac") && window.execScript) + for (g = -1, z = 0; z < w.length && -1 == g; z++) { + p = -1; + try { + p = new ActiveXObject(w[z].name) + } catch (v) { + p = { + activeXError: !0 + } + } + p.activeXError || + (n.installed = !0, g = w[z].version(p), -1 != g && (p = g, x = p.split(","), s = parseInt(x[0].split(" ")[1], 10), m = parseInt(x[1], 10), A = parseInt(x[2], 10), x = x[2], n.raw = p, n.major = s, n.minor = m, n.revision = A, n.revisionStr = x)) + } + }() +}; +FlashDetect.JS_RELEASE = "1.0.4"; \ No newline at end of file diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/muses.swf b/airtime_mvc/public/js/airtime/embeddableplayer/muses.swf new file mode 100644 index 0000000000000000000000000000000000000000..0a23f07cf1ece131ba9c4b902c855d4ea246ebbf GIT binary patch literal 74589 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 Szwqxq*An{+`1%+A*h7G?D}~+w literal 0 HcmV?d00001 From 7744e6b6560c0c366d4ac3f3401a67fdfe7dc2ec Mon Sep 17 00:00:00 2001 From: drigato Date: Tue, 10 Mar 2015 16:34:06 -0400 Subject: [PATCH 12/60] Delete player css file for now --- airtime_mvc/public/css/embed-player.css | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 airtime_mvc/public/css/embed-player.css diff --git a/airtime_mvc/public/css/embed-player.css b/airtime_mvc/public/css/embed-player.css deleted file mode 100644 index 1f19319e8..000000000 --- a/airtime_mvc/public/css/embed-player.css +++ /dev/null @@ -1,4 +0,0 @@ -#embed_player_preview { - margin-top:20px; - border: 1px solid; -} From 8198d89095575e69214230d6ca1426cf587cf4d9 Mon Sep 17 00:00:00 2001 From: drigato Date: Tue, 10 Mar 2015 16:47:08 -0400 Subject: [PATCH 13/60] small change to player form --- .../application/controllers/EmbeddableplayerController.php | 2 +- airtime_mvc/application/forms/EmbeddablePlayer.php | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/airtime_mvc/application/controllers/EmbeddableplayerController.php b/airtime_mvc/application/controllers/EmbeddableplayerController.php index 4536d7e18..6fc2d9e13 100644 --- a/airtime_mvc/application/controllers/EmbeddableplayerController.php +++ b/airtime_mvc/application/controllers/EmbeddableplayerController.php @@ -17,5 +17,5 @@ class EmbeddablePlayerController extends Zend_Controller_Action public function embedCodeAction() { $this->view->layout()->disableLayout(); - } + } } \ No newline at end of file diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php index 4b9353aad..230037de7 100644 --- a/airtime_mvc/application/forms/EmbeddablePlayer.php +++ b/airtime_mvc/application/forms/EmbeddablePlayer.php @@ -10,7 +10,6 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm $embedSrc = new Zend_Form_Element_Text('player_embed_src'); $embedSrc->setAttrib("readonly", "readonly"); - $embedSrc->setAttrib("class", "player_embed_src"); $embedSrc->setValue(''); $embedSrc->removeDecorator('label'); $this->addElement($embedSrc); From 0042fb50fe3ca792e9b73fd39d5189cf42e1d32e Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Tue, 10 Mar 2015 19:15:38 -0400 Subject: [PATCH 14/60] Refactor some stuff related to four streams, Liquidsoap is a piece of shit too - no dynamic variables --- .../application/controllers/ApiController.php | 2 +- .../controllers/PreferenceController.php | 10 +- .../application/models/StreamSetting.php | 203 +++++++++--------- .../generate_liquidsoap_cfg.py | 23 +- .../pypo/liquidsoap_scripts/ls_script.liq | 5 +- python_apps/pypo/listenerstat.py | 4 +- python_apps/pypo/pypofetch.py | 93 +------- python_apps/pypo/pypoliquidsoap.py | 1 + python_apps/pypo/pyponotify.py | 10 +- 9 files changed, 130 insertions(+), 221 deletions(-) diff --git a/airtime_mvc/application/controllers/ApiController.php b/airtime_mvc/application/controllers/ApiController.php index c90b41c22..b07cccd51 100644 --- a/airtime_mvc/application/controllers/ApiController.php +++ b/airtime_mvc/application/controllers/ApiController.php @@ -1308,7 +1308,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 6a0ba3541..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)); @@ -447,7 +444,8 @@ class PreferenceController extends Zend_Controller_Action public function getAdminPasswordStatusAction() { $out = array(); - for ($i=1; $i<=4; $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 c34c09a2e..832849474 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; } @@ -134,76 +149,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; } @@ -211,7 +191,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); @@ -411,7 +394,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) @@ -421,7 +404,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) @@ -431,7 +414,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) @@ -441,7 +424,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){ @@ -488,4 +471,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/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/ + - + - + - + \ No newline at end of file diff --git a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml index 568540d7f..d4f481199 100644 --- a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml +++ b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml @@ -8,6 +8,6 @@ element->getElement('player_stream_url'); ?>
- + element->getElement('player_embed_src')->getValue(); ?> \ No newline at end of file From dc0855de186d1f4bb4a87030afe44283d8da7d52 Mon Sep 17 00:00:00 2001 From: drigato Date: Mon, 16 Mar 2015 11:29:24 -0400 Subject: [PATCH 16/60] SAAS-643: Embed Player -> Restrict the setting of an OPUS stream --- .../application/controllers/EmbeddableplayerController.php | 7 ++++++- airtime_mvc/application/forms/EmbeddablePlayer.php | 2 ++ .../application/views/scripts/embeddableplayer/index.phtml | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/airtime_mvc/application/controllers/EmbeddableplayerController.php b/airtime_mvc/application/controllers/EmbeddableplayerController.php index fa37e2861..d7a16104b 100644 --- a/airtime_mvc/application/controllers/EmbeddableplayerController.php +++ b/airtime_mvc/application/controllers/EmbeddableplayerController.php @@ -11,7 +11,12 @@ class EmbeddablePlayerController extends Zend_Controller_Action { $form = new Application_Form_EmbeddablePlayer(); - $this->view->form = $form; + if ($form->getElement('player_stream_url')->getAttrib('numberOfEnabledStreams') > 0) { + $this->view->form = $form; + } else { + $this->view->errorMsg = "You need to enable at least one MP3, AAC, or OGG stream to use this feature."; + } + } public function embedCodeAction() diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php index 7a89660ff..520a5318b 100644 --- a/airtime_mvc/application/forms/EmbeddablePlayer.php +++ b/airtime_mvc/application/forms/EmbeddablePlayer.php @@ -16,6 +16,7 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm $streamURL = new Zend_Form_Element_Radio('player_stream_url'); $urlOptions = Array(); foreach(Application_Model_StreamSetting::getEnabledStreamUrls() as $type => $url) { + if ($type == "opus") continue; $urlOptions[$url] = $type; } $streamURL->setMultiOptions( @@ -24,6 +25,7 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm $streamURL->setValue(array_keys($urlOptions)[0]); $streamURL->setLabel(_('Select stream:')); $streamURL->setAttrib('codec', array_values($urlOptions)[0]); + $streamURL->setAttrib('numberOfEnabledStreams', sizeof($urlOptions)); $this->addElement($streamURL); $url = $streamURL->getValue(); diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml index 0a9e66daa..f762892b4 100644 --- a/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml +++ b/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml @@ -6,6 +6,7 @@
+ errorMsg; ?> form; ?>
From 1f2f8a27a55775c9b76be895421520f70f01dfdb Mon Sep 17 00:00:00 2001 From: drigato Date: Mon, 16 Mar 2015 13:24:58 -0400 Subject: [PATCH 17/60] SAAS-650: Fix up player page UI in Airtime --- .../application/controllers/EmbeddableplayerController.php | 3 +++ airtime_mvc/application/forms/EmbeddablePlayer.php | 5 +++++ .../application/views/scripts/embeddableplayer/index.phtml | 6 ++---- .../application/views/scripts/form/embeddableplayer.phtml | 5 ++++- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/airtime_mvc/application/controllers/EmbeddableplayerController.php b/airtime_mvc/application/controllers/EmbeddableplayerController.php index d7a16104b..ec16317b5 100644 --- a/airtime_mvc/application/controllers/EmbeddableplayerController.php +++ b/airtime_mvc/application/controllers/EmbeddableplayerController.php @@ -9,6 +9,9 @@ class EmbeddablePlayerController extends Zend_Controller_Action public function indexAction() { + $CC_CONFIG = Config::getConfig(); + $baseUrl = Application_Common_OsPath::getBaseDir(); + $this->view->headLink()->appendStylesheet($baseUrl.'css/embeddableplayer.css?'.$CC_CONFIG['airtime_version']); $form = new Application_Form_EmbeddablePlayer(); if ($form->getElement('player_stream_url')->getAttrib('numberOfEnabledStreams') > 0) { diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php index 520a5318b..a77ae5f1d 100644 --- a/airtime_mvc/application/forms/EmbeddablePlayer.php +++ b/airtime_mvc/application/forms/EmbeddablePlayer.php @@ -34,8 +34,13 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm $embedSrc = new Zend_Form_Element_Text('player_embed_src'); $embedSrc->setAttrib("readonly", "readonly"); $embedSrc->setValue(''); + $embedSrc->setAttrib("class", "embed-player-text-box"); $embedSrc->removeDecorator('label'); $this->addElement($embedSrc); + $previewLabel = new Zend_Form_Element_Text('player_preview_label'); + $previewLabel->setLabel("Preview:"); + $this->addElement($previewLabel); + } } \ No newline at end of file diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml index f762892b4..7a069af6d 100644 --- a/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml +++ b/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml @@ -1,14 +1,12 @@ -
+

- - +
errorMsg; ?> form; ?> -
diff --git a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml index d4f481199..5153189e8 100644 --- a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml +++ b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml @@ -7,7 +7,10 @@ element->getElement('player_stream_url'); ?> + element->getElement('player_preview_label')->renderLabel(); ?>
- element->getElement('player_embed_src')->getValue(); ?> +
+ element->getElement('player_embed_src')->getValue(); ?> +
\ No newline at end of file From ed891fb145647ad7cd3d222fde6fc15748af36a1 Mon Sep 17 00:00:00 2001 From: drigato Date: Wed, 18 Mar 2015 14:23:38 -0400 Subject: [PATCH 18/60] Committing lots of trial and error embed player code changes --- .../EmbeddableplayerController.php | 14 +++++--- .../application/forms/EmbeddablePlayer.php | 4 ++- .../scripts/embeddableplayer/embed-code.phtml | 35 ++++++++++++++----- .../scripts/embeddableplayer/index.phtml | 4 +-- .../views/scripts/form/embeddableplayer.phtml | 22 ++++++++++++ airtime_mvc/public/css/embeddableplayer.css | 14 ++++++++ .../embeddableplayer/embeddableplayer.js | 28 +++++++++++++++ .../public/js/airtime/embeddableplayer/mrp.js | 3 +- 8 files changed, 107 insertions(+), 17 deletions(-) create mode 100644 airtime_mvc/public/css/embeddableplayer.css create mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js diff --git a/airtime_mvc/application/controllers/EmbeddableplayerController.php b/airtime_mvc/application/controllers/EmbeddableplayerController.php index ec16317b5..6c2ccfbd8 100644 --- a/airtime_mvc/application/controllers/EmbeddableplayerController.php +++ b/airtime_mvc/application/controllers/EmbeddableplayerController.php @@ -12,6 +12,10 @@ class EmbeddablePlayerController extends Zend_Controller_Action $CC_CONFIG = Config::getConfig(); $baseUrl = Application_Common_OsPath::getBaseDir(); $this->view->headLink()->appendStylesheet($baseUrl.'css/embeddableplayer.css?'.$CC_CONFIG['airtime_version']); + $this->view->headScript()->appendFile($baseUrl.'js/airtime/embeddableplayer/mrp.js?'.$CC_CONFIG['airtime_version']); + $this->view->headScript()->appendFile($baseUrl.'js/airtime/embeddableplayer/embeddableplayer.js?'.$CC_CONFIG['airtime_version']); + + $form = new Application_Form_EmbeddablePlayer(); if ($form->getElement('player_stream_url')->getAttrib('numberOfEnabledStreams') > 0) { @@ -28,11 +32,13 @@ class EmbeddablePlayerController extends Zend_Controller_Action $request = $this->getRequest(); - $this->view->mrp_js = Application_Common_HTTPHelper::getStationUrl() . "/js/airtime/embeddableplayer/mrp.js"; - $this->view->muses_swf = Application_Common_HTTPHelper::getStationUrl() . "/js/airtime/embeddableplayer/muses.swf"; - $this->view->skin = Application_Common_HTTPHelper::getStationUrl() . "/js/airtime/embeddableplayer/ffmp3-mcclean.xml"; + $this->view->mrp_js = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/embeddableplayer/mrp.js"; + $this->view->muses_swf = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/embeddableplayer/muses.swf"; + $this->view->skin = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/embeddableplayer/ffmp3-mcclean.xml"; $this->view->codec = $request->getParam('codec'); - $this->view->streamURL = $request->getParam('url'); + //$this->view->streamURL = $request->getParam('url'); + //$stream = $request->getParam('stream'); + $this->view->streamURL = "http://127.0.0.1:8000/airtime_128"; $this->view->displayMetadata = $request->getParam('display_metadata'); } } \ No newline at end of file diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php index a77ae5f1d..febf1379a 100644 --- a/airtime_mvc/application/forms/EmbeddablePlayer.php +++ b/airtime_mvc/application/forms/EmbeddablePlayer.php @@ -22,6 +22,7 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm $streamURL->setMultiOptions( $urlOptions ); + Logging::info($urlOptions); $streamURL->setValue(array_keys($urlOptions)[0]); $streamURL->setLabel(_('Select stream:')); $streamURL->setAttrib('codec', array_values($urlOptions)[0]); @@ -33,8 +34,9 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm $embedSrc = new Zend_Form_Element_Text('player_embed_src'); $embedSrc->setAttrib("readonly", "readonly"); - $embedSrc->setValue(''); $embedSrc->setAttrib("class", "embed-player-text-box"); + //$embedSrc->setValue(''); + $embedSrc->setValue(''); $embedSrc->removeDecorator('label'); $this->addElement($embedSrc); diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml index 73db907b7..cc5e96804 100644 --- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml +++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml @@ -3,16 +3,33 @@ + + - - - - - - - - - + + + \ No newline at end of file diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml index 7a069af6d..e4c37849b 100644 --- a/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml +++ b/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml @@ -1,9 +1,9 @@ -
+

- +
errorMsg; ?> form; ?> diff --git a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml index 5153189e8..dacb80cd7 100644 --- a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml +++ b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml @@ -8,9 +8,31 @@ element->getElement('player_stream_url'); ?> element->getElement('player_preview_label')->renderLabel(); ?> + +
+
+
play
+
stop
+
+ + +
element->getElement('player_embed_src')->getValue(); ?>
+ + \ No newline at end of file diff --git a/airtime_mvc/public/css/embeddableplayer.css b/airtime_mvc/public/css/embeddableplayer.css new file mode 100644 index 000000000..a1e12cbc0 --- /dev/null +++ b/airtime_mvc/public/css/embeddableplayer.css @@ -0,0 +1,14 @@ +.embed-player-text-box { + padding-right: 0px !important; + width: 100% !important; +} +.embed-player-form { + width: 70%; +} +.embed-player-form dd { + width: 100% !important; + float: left; + margin: 0; + padding: 4px 0px 4px 0px; +} + diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js new file mode 100644 index 000000000..ece8902a3 --- /dev/null +++ b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js @@ -0,0 +1,28 @@ +function generateEmbedSrc() +{ + document.getElementById('embed_player_preview').textContent=""; +} + +function setupPlayer() +{ + MRP.insert({ + 'url':"http://127.0.0.1:8000/airtime_128", + 'codec':"mp3", + 'volume':100, + 'jsevents':true, + 'autoplay':false, + 'buffering':5, + 'title':'test', + 'bgcolor':'#FFFFFF', + 'skin':-1, + 'width':180, + 'height':60 + }); +} + +window.onload = function() { + setupPlayer(); + document.getElementById('player_display_track_metadata').onchange = generateEmbedSrc; + document.getElementById('muses_play').click = MRP.play(); + document.getElementById('muses_stop').click = MRP.stop(); +} diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js b/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js index 74bc30836..3308a8f55 100644 --- a/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js +++ b/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js @@ -203,7 +203,8 @@ c + ("&skin=" + g.getSkin(a.skin, !0)), c = c + ("&title=" + a.title), c = c + ("&welcome=" + a.welcome), - b = g.getScriptBaseHREF() + "/muses-hosted.swf", + //b = g.getScriptBaseHREF() + "/muses-hosted.swf", + b = "http://localhost/js/airtime/embeddableplayer/muses.swf", e = 'width="' + a.width + '" height="' + a.height + '" '; null != a.bgcolor && (e += 'bgcolor="' + a.bgcolor + '" '); var f = '", From bafd9eeb6f6cce3c494803869803b326ff253db5 Mon Sep 17 00:00:00 2001 From: drigato Date: Wed, 18 Mar 2015 15:03:34 -0400 Subject: [PATCH 19/60] Cleaning up player code --- .../views/scripts/form/embeddableplayer.phtml | 19 ------------- .../embeddableplayer/embeddableplayer.js | 27 +++---------------- 2 files changed, 4 insertions(+), 42 deletions(-) diff --git a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml index dacb80cd7..815c9abf0 100644 --- a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml +++ b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml @@ -9,25 +9,6 @@ element->getElement('player_preview_label')->renderLabel(); ?> -
-
-
play
-
stop
-
- - -
element->getElement('player_embed_src')->getValue(); ?> diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js index ece8902a3..345e283ed 100644 --- a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js +++ b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js @@ -1,28 +1,9 @@ +window.onload = function() { + document.getElementById('player_display_track_metadata').onchange = generateEmbedSrc; +} + function generateEmbedSrc() { document.getElementById('embed_player_preview').textContent=""; } -function setupPlayer() -{ - MRP.insert({ - 'url':"http://127.0.0.1:8000/airtime_128", - 'codec':"mp3", - 'volume':100, - 'jsevents':true, - 'autoplay':false, - 'buffering':5, - 'title':'test', - 'bgcolor':'#FFFFFF', - 'skin':-1, - 'width':180, - 'height':60 - }); -} - -window.onload = function() { - setupPlayer(); - document.getElementById('player_display_track_metadata').onchange = generateEmbedSrc; - document.getElementById('muses_play').click = MRP.play(); - document.getElementById('muses_stop').click = MRP.stop(); -} From 875ed0e41ec01a70bdab3d3508233919e09691bc Mon Sep 17 00:00:00 2001 From: drigato Date: Thu, 19 Mar 2015 13:42:19 -0400 Subject: [PATCH 20/60] Got muses working without a skin Had to leave the skin visible but "hide" it by setting the width and height to 1px --- .../scripts/embeddableplayer/embed-code.phtml | 47 ++++++++++++------- .../public/js/airtime/embeddableplayer/mrp.js | 4 +- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml index cc5e96804..26070fabf 100644 --- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml +++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml @@ -10,26 +10,41 @@ //MRP.setUrl("http://sourcefabric.out.airtime.pro:8000/sourcefabric_b"); } } - + + + + - + + MRP.insert({ + 'url':"streamURL ?>", + 'codec':"codec ?>", + 'volume':100, + 'jsevents':true, + 'autoplay':false, + 'buffering':5, + 'title':'test', + 'bgcolor':'#FFFFFF', + 'skin':'mcclean', + 'width':180, + 'height':60 + }); + +
+ +
+ play +
+
+ stop +
\ No newline at end of file diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js b/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js index 3308a8f55..4377dddd5 100644 --- a/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js +++ b/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js @@ -203,8 +203,8 @@ c + ("&skin=" + g.getSkin(a.skin, !0)), c = c + ("&title=" + a.title), c = c + ("&welcome=" + a.welcome), - //b = g.getScriptBaseHREF() + "/muses-hosted.swf", - b = "http://localhost/js/airtime/embeddableplayer/muses.swf", + b = g.getScriptBaseHREF() + "/muses-hosted.swf", + //b = "http://localhost/js/airtime/embeddableplayer/muses.swf", e = 'width="' + a.width + '" height="' + a.height + '" '; null != a.bgcolor && (e += 'bgcolor="' + a.bgcolor + '" '); var f = '", From 16ddf09d6d20932cdc3bc52b8d9fbc859fd7691b Mon Sep 17 00:00:00 2001 From: drigato Date: Thu, 19 Mar 2015 16:59:05 -0400 Subject: [PATCH 21/60] SAAS-655: Extract muses player events into our own js object --- .../scripts/embeddableplayer/embed-code.phtml | 35 ++++++++++++++----- .../views/scripts/form/embeddableplayer.phtml | 5 +-- .../embeddableplayer/embeddableplayer.js | 2 +- 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml index 26070fabf..adba9fd8a 100644 --- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml +++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml @@ -5,10 +5,31 @@ @@ -21,8 +42,6 @@
-
+ -
+ diff --git a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml index 815c9abf0..aed5bc181 100644 --- a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml +++ b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml @@ -10,10 +10,7 @@ element->getElement('player_preview_label')->renderLabel(); ?>
-
- element->getElement('player_embed_src')->getValue(); ?> -
- + element->getElement('player_embed_src')->getValue(); ?> \ No newline at end of file diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js index 345e283ed..d228625af 100644 --- a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js +++ b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js @@ -4,6 +4,6 @@ window.onload = function() { function generateEmbedSrc() { - document.getElementById('embed_player_preview').textContent=""; + } From 20d774874ecef8306d4956e09f490aa6e7c73319 Mon Sep 17 00:00:00 2001 From: drigato Date: Fri, 20 Mar 2015 07:35:18 -0400 Subject: [PATCH 22/60] SAAS-655: Extract muses player events into our own js object Added skeleton functions for setVolume and setURL --- .../scripts/embeddableplayer/embed-code.phtml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml index adba9fd8a..8d953d7a4 100644 --- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml +++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml @@ -8,13 +8,23 @@ var MusesPlayer = function() { this.flashDetect = FlashDetect.versionAtLeast(10, 1) ? true : false; }; + MusesPlayer.prototype.play = function() { this.flashDetect ? MRP.play() : musesHTMLPlayClick(); }; + MusesPlayer.prototype.stop = function() { this.flashDetect ? MRP.stop() : musesHTMLStopClick(); }; - //TODO: setVolume, setURL + + MusesPlayer.prototype.setVolume = function(value) { + //this.flashDetect ? MRP.setVolume(value) : null; + //TODO - maybe + }; + + MusesPlayer.prototype.setURL = function() { + //TODO + }; var musesPlayer = new MusesPlayer(); @@ -55,6 +65,8 @@ 'width':180, 'height':60 }); + + musesPlayer.setVolume(50);
From 28786e7bf11940db0ff6f072378129134d8c9d47 Mon Sep 17 00:00:00 2001 From: drigato Date: Fri, 20 Mar 2015 07:41:10 -0400 Subject: [PATCH 23/60] SAAS-655: Extract muses player events into our own js object Moved player creation into musesPlayer constructor --- .../scripts/embeddableplayer/embed-code.phtml | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml index 8d953d7a4..adab3876e 100644 --- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml +++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml @@ -6,6 +6,20 @@
From 0764ca60e6d418e6770594731f9c1b4b29ed3d79 Mon Sep 17 00:00:00 2001 From: drigato Date: Fri, 20 Mar 2015 09:09:09 -0400 Subject: [PATCH 24/60] Delete muses skin files --- .../airtime/embeddableplayer/ffmp3-mcclean.xml | 10 ---------- .../embeddableplayer/ffmp3-mcclean/bg.png | Bin 3649 -> 0 bytes .../embeddableplayer/ffmp3-mcclean/holder.png | Bin 830 -> 0 bytes .../embeddableplayer/ffmp3-mcclean/play.gif | Bin 1493 -> 0 bytes .../embeddableplayer/ffmp3-mcclean/playclick.jpg | Bin 1422 -> 0 bytes .../ffmp3-mcclean/statusplay.png | Bin 138 -> 0 bytes .../ffmp3-mcclean/statusstop.png | Bin 136 -> 0 bytes .../embeddableplayer/ffmp3-mcclean/stop.jpg | Bin 1459 -> 0 bytes .../embeddableplayer/ffmp3-mcclean/stopclick.jpg | Bin 1459 -> 0 bytes 9 files changed, 10 deletions(-) delete mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean.xml delete mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/bg.png delete mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/holder.png delete mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/play.gif delete mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/playclick.jpg delete mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/statusplay.png delete mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/statusstop.png delete mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/stop.jpg delete mode 100644 airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/stopclick.jpg diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean.xml b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean.xml deleted file mode 100644 index 57d7c3eab..000000000 --- a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/bg.png b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/bg.png deleted file mode 100644 index a399e16be7eeeb3a6a26d2488b98293dbf0eb29e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3649 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 diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/statusstop.png b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/statusstop.png deleted file mode 100644 index e0cce0d1a8407d07b2b8470cfedcbb3b7a0c96b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 136 zcmeAS@N?(olHy`uVBq!ia0vp^Od!m`#=yYHy3uwMki(Mh=OQOYu8I4U$VqC zq9iy!t)x7$D3!r6B|j-u!8128JvAsbF{QHbWU38Nk(8&4V@SoVq#x%Gd|*>(kZ@pe gXfS-ozOjLU!C@|IGjG!oQ=lpaPgg&ebxsLQ0I(4y>;M1& diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/stop.jpg b/airtime_mvc/public/js/airtime/embeddableplayer/ffmp3-mcclean/stop.jpg deleted file mode 100644 index c7fda38d84c849610b89f211a34fd222b515e527..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1459 zcmex=U71|~s9Wv5vvV>sGBC0-!bO1$W+oO^ zHg*mH21XV}CKh(M6blnGD;pz&fP#=PyP%=5vxumwATZomnV49(xS^^Tfp!QAv9KBn zD>^C}iLeDGHZI)g6x3uanzTvTIl1|;X{(u=5Can<&^N4blfk-J1QZMv3xxs~UR2s7 z40IF|D>Dl-%wa&UC<=TqbPPfy4{RtzLf>K?Y#OoP(|vZ$t%wmSC{MBoxfR%Blm34U;m~atepuMWK7qM zN_!q#&kDM&q&P*ZE2V6qwr!MX4=6(m(!pI2J;@qgIRT3UFN%X+iAT1U(=kt8GW4`zA z-u9hG*VpFoPoHRgqenbbZm+fY6n5)UDT|-1#hyNGjcJ+u-?(RMU$|Jbih0>hzuc)U zGyS66)4!_68e8RFclkOsF4A?!AC)R)`zkO3f*+H?wzFZ?b3WvUb^e>(28xAKUh)|MQP8vp?Y+f92QVmDj)56n>BA z|5Wm8A|z;-8SNE!B>A~dXlP4%vtEGr^zsk`eP;HkM4Ly3c^w+3Ox7j8;reL$>g=nB zV*0rn)%SE18l3(!ELy9)VP>I|X~nv-z(t&&9xiBX%ww5)YSVm2e)+6y_`AZwS*NcnSZflM&3_^wO$b=v3e2{OvsvSRI; zDu^0pkeWq2dym-!7yLeG^Qa_X8s|>0bB}{x@4iv9QS7+D0_%`d9d6DM8^9V6>0Ln1 z!Dmu~0^ENBn&(z5t!!^93T5)Ty3pT2UFeE&17@t;}MmCo2V&r0gT zJ+YH}VoGPZwro5wEnpFwr#Hi`9d9@5lqqfPnBm5B@REYld<)sP$ytvRQde>bJ(zhV zZ7G-V4VM25N0;OTYnq+B&K9oo&$gfw?n!|qhj=I0Wt1vBl$Tg^F!q{W2ggkXia^`Ch*Y)&TOcz(UPQ3NjrnuL5(WxHhhFnDMeB`G}Vu>#7U(B{sLt j-kf*rV_i&&<6WDi@4L2qSJ@SU71|~s9WHUGB7bS!bO1$7FK39 zb`AlcdPZgzgcLIi6Du2o0HcDCFuRems4>uRMn*PfRyKC1W=1Av76w5@Az@a-L=ne8 zqa@?Tg-T6}O^cLOQbf(%gn;Uqm{~dDRsneof&zvt3JW(L6jDqqoTwBetjsFR2n=9m zCN{WRfxb{Q6mU%Z5U5btIC0^@jTayOzs0}<=To%oqgm!(Z^e_nIR#2;!L0}4xn!tS(#FmqULlZGtIhMayI*X^3PN4 zJHjKor=G8xb#?W1oBG;{$EU8z%{rt_P#zplnFbF5(A z+l`9z78R*Wdzvm+WN>^1mS+aZU(wF-WL|aZ_TwuD%9h{gVpV#x&$DVp{FV({ru#!o zVPdmqS}hj+epl_VK>n zQsq9YTA!T~$#-5xb`@x0)Bgmd< z=4-Y2%lg9G=1r2EC$X+$O6JnbTB(!V+4~qG7f&x-+UKGgXK7yQ?j{pDbrrLwSo-bN z-h0C9O8K6Bve7AY@(DHzZqJv_$ojW^#fx2MR@eE92Tyu4>z3S^AD=en{YilV z<&aVC`!e>jKcg$Fd0H{HIo)qkamiFH(hp19Q78$G(qf8YK$b=sRc_2V;hj#diz zu3Ej!y2(2-&@^PVXl+d4t1BLtPKBAyQF=b{;^#+zJ+V+17`Zj5}uJ7Z0I+uIX zE{PYFetk2m)*HLSy(zGq_l2{|iJtbh=AeaUH;Mda<%hx=S$@xh>GuPpA4&bH?18aW5ttXwvAs;ezpW#^c}VUzIn)?DEk kn{NKJ^9{XofU6-j@721uzV2CCj2i+HXA}zk*#G|~0Q5EfJpcdz From 5c4533d7859857e90b44e895543880c7c1dbf24b Mon Sep 17 00:00:00 2001 From: drigato Date: Mon, 23 Mar 2015 10:11:33 -0400 Subject: [PATCH 25/60] SAAS-644: Embed Player -> Update embed src code and preview when an option changes --- .../embeddableplayer/embeddableplayer.js | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js index d228625af..16cfb95e3 100644 --- a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js +++ b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js @@ -1,9 +1,38 @@ -window.onload = function() { - document.getElementById('player_display_track_metadata').onchange = generateEmbedSrc; -} - function generateEmbedSrc() { + var $embedCodeParams = "?"; + var $streamMode = getStreamMode(); + if ($streamMode == "b") { + var $stream = $("input[name=player_stream_url]:radio:checked").val(); + $embedCodeParams += "stream-mode=b&stream="+$stream; + } else if ($streamMode == "a") { + $embedCodeParams += "stream-mode=a"; + } + $embedCodeParams += "\""; + $("input[name=player_embed_src]").val(function(index, value) { + return value.replace(/\?.*?"/, $embedCodeParams); + }); } +function getStreamMode() { + return $("input[name=player_stream_mode]:radio:checked").val(); +} + +$(document).ready(function() { + $("#player_stream_mode-element").change(function() { + var $streamMode = getStreamMode(); + if ($streamMode == "a") { + $("#player_stream_url-element input[type='radio']").attr("disabled", "disabled"); + } else if ($streamMode == "b") { + $("#player_stream_url-element input[type='radio']").removeAttr("disabled"); + } + + generateEmbedSrc(); + }); + + $("#player_stream_url-element").change(function() { + generateEmbedSrc(); + }); +}); + From 2ae4d6c1c323828ee1d4ac714226a029d478d346 Mon Sep 17 00:00:00 2001 From: drigato Date: Mon, 23 Mar 2015 12:37:22 -0400 Subject: [PATCH 26/60] Embed Player Added stream modes Unhardcoded some values Disabled opus streams --- .../EmbeddableplayerController.php | 11 +++-- .../application/forms/EmbeddablePlayer.php | 44 +++++++++++++------ .../application/models/StreamSetting.php | 19 ++++++++ .../views/scripts/form/embeddableplayer.phtml | 2 + .../embeddableplayer/embeddableplayer.js | 13 ++++-- 5 files changed, 67 insertions(+), 22 deletions(-) diff --git a/airtime_mvc/application/controllers/EmbeddableplayerController.php b/airtime_mvc/application/controllers/EmbeddableplayerController.php index 6c2ccfbd8..8efc33c2b 100644 --- a/airtime_mvc/application/controllers/EmbeddableplayerController.php +++ b/airtime_mvc/application/controllers/EmbeddableplayerController.php @@ -15,7 +15,6 @@ class EmbeddablePlayerController extends Zend_Controller_Action $this->view->headScript()->appendFile($baseUrl.'js/airtime/embeddableplayer/mrp.js?'.$CC_CONFIG['airtime_version']); $this->view->headScript()->appendFile($baseUrl.'js/airtime/embeddableplayer/embeddableplayer.js?'.$CC_CONFIG['airtime_version']); - $form = new Application_Form_EmbeddablePlayer(); if ($form->getElement('player_stream_url')->getAttrib('numberOfEnabledStreams') > 0) { @@ -34,11 +33,11 @@ class EmbeddablePlayerController extends Zend_Controller_Action $this->view->mrp_js = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/embeddableplayer/mrp.js"; $this->view->muses_swf = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/embeddableplayer/muses.swf"; - $this->view->skin = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/embeddableplayer/ffmp3-mcclean.xml"; - $this->view->codec = $request->getParam('codec'); - //$this->view->streamURL = $request->getParam('url'); - //$stream = $request->getParam('stream'); - $this->view->streamURL = "http://127.0.0.1:8000/airtime_128"; + $stream = $request->getParam('stream'); + $streamData = Application_Model_StreamSetting::getEnabledStreamData(); + $selectedStreamData = $streamData[$stream]; + $this->view->streamURL = $selectedStreamData["url"]; + $this->view->codec = $selectedStreamData["codec"]; $this->view->displayMetadata = $request->getParam('display_metadata'); } } \ No newline at end of file diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php index febf1379a..537abd39a 100644 --- a/airtime_mvc/application/forms/EmbeddablePlayer.php +++ b/airtime_mvc/application/forms/EmbeddablePlayer.php @@ -13,30 +13,48 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm $displayTrackMetadata->setLabel(_('Display track metadata?')); $this->addElement($displayTrackMetadata); + $streamMode = new Zend_Form_Element_Radio('player_stream_mode'); + $streamMode->setLabel(_('Select Stream:')); + $streamMode->setMultiOptions( + array( + "a" => "Use a mobile stream if possible, when appropriate. Otherwise use the highest quality stream.", + "b" => "Select a stream" + ) + ); + $streamMode->setValue("a"); + $this->addElement($streamMode); + $streamURL = new Zend_Form_Element_Radio('player_stream_url'); + $opusStreamCount = 0; $urlOptions = Array(); - foreach(Application_Model_StreamSetting::getEnabledStreamUrls() as $type => $url) { - if ($type == "opus") continue; - $urlOptions[$url] = $type; + foreach(Application_Model_StreamSetting::getEnabledStreamData() as $stream => $data) { + $urlOptions[$stream] = $data["codec"]." - ".$data["bitrate"]."kbps"; + if ($data["codec"] == "opus") { + $opusStreamCount += 1; + $urlOptions[$stream] .=" - The player does not support Opus streams."; + } } $streamURL->setMultiOptions( $urlOptions ); - Logging::info($urlOptions); - $streamURL->setValue(array_keys($urlOptions)[0]); - $streamURL->setLabel(_('Select stream:')); - $streamURL->setAttrib('codec', array_values($urlOptions)[0]); - $streamURL->setAttrib('numberOfEnabledStreams', sizeof($urlOptions)); - $this->addElement($streamURL); - $url = $streamURL->getValue(); - $codec = $streamURL->getAttrib('codec'); + foreach ($urlOptions as $o => $v) { + if (strpos($v, "opus") !== false) { + continue; + } else { + $streamURL->setValue($o); + break; + } + } + + $streamURL->setAttrib('numberOfEnabledStreams', sizeof($urlOptions)-$opusStreamCount); + $streamURL->setAttrib("disabled", "disabled"); + $this->addElement($streamURL); $embedSrc = new Zend_Form_Element_Text('player_embed_src'); $embedSrc->setAttrib("readonly", "readonly"); $embedSrc->setAttrib("class", "embed-player-text-box"); - //$embedSrc->setValue(''); - $embedSrc->setValue(''); + $embedSrc->setValue(''); $embedSrc->removeDecorator('label'); $this->addElement($embedSrc); diff --git a/airtime_mvc/application/models/StreamSetting.php b/airtime_mvc/application/models/StreamSetting.php index 3bdac8a31..49ec7a072 100644 --- a/airtime_mvc/application/models/StreamSetting.php +++ b/airtime_mvc/application/models/StreamSetting.php @@ -78,6 +78,25 @@ class Application_Model_StreamSetting return $urls; } + public static function getEnabledStreamData() + { + $streams = Array(); + $streamIds = self::getEnabledStreamIds(); + foreach ($streamIds as $id) { + $streamData = self::getStreamData($id); + $prefix = $id."_"; + $host = $streamData[$prefix."host"]; + $port = $streamData[$prefix."port"]; + $mount = $streamData[$prefix."mount"]; + $streams[$id] = Array( + "url" => "http://$host:$port/$mount", + "codec" => $streamData[$prefix."type"], + "bitrate" => $streamData[$prefix."bitrate"] + ); + } + return $streams; + } + /* Returns the id's of all streams that are enabled in an array. An * example of the array returned in JSON notation is ["s1", "s2", "s3"] */ public static function getEnabledStreamIds() diff --git a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml index aed5bc181..7ab6cb227 100644 --- a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml +++ b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml @@ -5,6 +5,8 @@ element->getElement('player_display_track_metadata'); ?> + element->getElement('player_stream_mode'); ?> + element->getElement('player_stream_url'); ?> element->getElement('player_preview_label')->renderLabel(); ?> diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js index 16cfb95e3..a07a293f2 100644 --- a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js +++ b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js @@ -1,4 +1,4 @@ -function generateEmbedSrc() +function updateEmbedSrcParams() { var $embedCodeParams = "?"; var $streamMode = getStreamMode(); @@ -20,19 +20,26 @@ function getStreamMode() { } $(document).ready(function() { + $("#player_stream_mode-element").change(function() { var $streamMode = getStreamMode(); if ($streamMode == "a") { $("#player_stream_url-element input[type='radio']").attr("disabled", "disabled"); } else if ($streamMode == "b") { $("#player_stream_url-element input[type='radio']").removeAttr("disabled"); + + $("input[name=player_stream_url]").each(function(i, obj) { + if ($(this).parent().text().indexOf("opus") >= 0) { + $(this).attr("disabled", "disabled"); + } + }); } - generateEmbedSrc(); + updateEmbedSrcParams(); }); $("#player_stream_url-element").change(function() { - generateEmbedSrc(); + updateEmbedSrcParams(); }); }); From e32744668f5f1e80f509ebef94de8b847ca8a98d Mon Sep 17 00:00:00 2001 From: drigato Date: Mon, 23 Mar 2015 16:06:35 -0400 Subject: [PATCH 27/60] SAAS-661: Add mobile stream identifier on Stream Settings page --- airtime_mvc/application/forms/EmbeddablePlayer.php | 5 ++++- airtime_mvc/application/forms/StreamSettingSubForm.php | 6 ++++++ airtime_mvc/application/models/StreamSetting.php | 3 ++- .../views/scripts/form/stream-setting-form.phtml | 7 +++++++ .../public/js/airtime/embeddableplayer/embeddableplayer.js | 2 +- 5 files changed, 20 insertions(+), 3 deletions(-) diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php index 537abd39a..ba7c5fce9 100644 --- a/airtime_mvc/application/forms/EmbeddablePlayer.php +++ b/airtime_mvc/application/forms/EmbeddablePlayer.php @@ -28,7 +28,10 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm $opusStreamCount = 0; $urlOptions = Array(); foreach(Application_Model_StreamSetting::getEnabledStreamData() as $stream => $data) { - $urlOptions[$stream] = $data["codec"]." - ".$data["bitrate"]."kbps"; + $urlOptions[$stream] = strtoupper($data["codec"])." - ".$data["bitrate"]."kbps"; + if ($data["mobile"]) { + $urlOptions[$stream] .= " - Mobile friendly"; + } if ($data["codec"] == "opus") { $opusStreamCount += 1; $urlOptions[$stream] .=" - The player does not support Opus streams."; diff --git a/airtime_mvc/application/forms/StreamSettingSubForm.php b/airtime_mvc/application/forms/StreamSettingSubForm.php index 874f38dc5..b84adf63d 100644 --- a/airtime_mvc/application/forms/StreamSettingSubForm.php +++ b/airtime_mvc/application/forms/StreamSettingSubForm.php @@ -53,6 +53,12 @@ class Application_Form_StreamSettingSubForm extends Zend_Form_SubForm } $this->addElement($enable); + $mobile = new Zend_Form_Element_Checkbox('mobile'); + $mobile->setLabel(_('Good for mobile?')); + $mobile->setValue($setting[$prefix.'_mobile']); + $mobile->setDecorators(array('ViewHelper')); + $this->addElement($mobile); + $type = new Zend_Form_Element_Select('type'); $type->setLabel(_("Stream Type:")) ->setMultiOptions($stream_types) diff --git a/airtime_mvc/application/models/StreamSetting.php b/airtime_mvc/application/models/StreamSetting.php index a85fad988..19a147798 100644 --- a/airtime_mvc/application/models/StreamSetting.php +++ b/airtime_mvc/application/models/StreamSetting.php @@ -94,7 +94,8 @@ class Application_Model_StreamSetting $streams[$id] = Array( "url" => "http://$host:$port/$mount", "codec" => $streamData[$prefix."type"], - "bitrate" => $streamData[$prefix."bitrate"] + "bitrate" => $streamData[$prefix."bitrate"], + "mobile" => $streamData[$prefix."mobile"] ); } return $streams; diff --git a/airtime_mvc/application/views/scripts/form/stream-setting-form.phtml b/airtime_mvc/application/views/scripts/form/stream-setting-form.phtml index 6b76ab84a..a8d61d247 100644 --- a/airtime_mvc/application/views/scripts/form/stream-setting-form.phtml +++ b/airtime_mvc/application/views/scripts/form/stream-setting-form.phtml @@ -14,6 +14,13 @@
element->getElement('enable')?>
+ +
+ +
+
+ element->getElement('mobile')?> +
diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js index a07a293f2..376c64e57 100644 --- a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js +++ b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js @@ -29,7 +29,7 @@ $(document).ready(function() { $("#player_stream_url-element input[type='radio']").removeAttr("disabled"); $("input[name=player_stream_url]").each(function(i, obj) { - if ($(this).parent().text().indexOf("opus") >= 0) { + if ($(this).parent().text().toLowerCase().indexOf("opus") >= 0) { $(this).attr("disabled", "disabled"); } }); From 17358a761fdef63d08e39343f21f0188402a6d5b Mon Sep 17 00:00:00 2001 From: drigato Date: Wed, 25 Mar 2015 11:44:28 -0400 Subject: [PATCH 28/60] SAAS-663: Integrate player design --- .../EmbeddableplayerController.php | 6 +- .../application/forms/EmbeddablePlayer.php | 10 +- .../scripts/embeddableplayer/embed-code.phtml | 90 ++++++++- .../views/scripts/form/embeddableplayer.phtml | 4 +- .../css/colorpicker/embeddable-player.css | 0 .../css/embed-player-images/airtime_logo.png | Bin 0 -> 1162 bytes .../public/css/embed-player-images/mute.png | Bin 0 -> 1338 bytes .../css/embed-player-images/pause_button.png | Bin 0 -> 1077 bytes .../css/embed-player-images/play_button.png | Bin 0 -> 1590 bytes .../public/css/embed-player-images/unmute.png | Bin 0 -> 1378 bytes ...eplayer.css => embeddable-player-form.css} | 2 + airtime_mvc/public/css/embeddable-player.css | 190 ++++++++++++++++++ .../embeddableplayer/embeddableplayer.js | 20 +- 13 files changed, 307 insertions(+), 15 deletions(-) create mode 100644 airtime_mvc/public/css/colorpicker/embeddable-player.css create mode 100644 airtime_mvc/public/css/embed-player-images/airtime_logo.png create mode 100644 airtime_mvc/public/css/embed-player-images/mute.png create mode 100644 airtime_mvc/public/css/embed-player-images/pause_button.png create mode 100644 airtime_mvc/public/css/embed-player-images/play_button.png create mode 100644 airtime_mvc/public/css/embed-player-images/unmute.png rename airtime_mvc/public/css/{embeddableplayer.css => embeddable-player-form.css} (99%) create mode 100644 airtime_mvc/public/css/embeddable-player.css diff --git a/airtime_mvc/application/controllers/EmbeddableplayerController.php b/airtime_mvc/application/controllers/EmbeddableplayerController.php index 8efc33c2b..2a66d0b7e 100644 --- a/airtime_mvc/application/controllers/EmbeddableplayerController.php +++ b/airtime_mvc/application/controllers/EmbeddableplayerController.php @@ -11,7 +11,7 @@ class EmbeddablePlayerController extends Zend_Controller_Action { $CC_CONFIG = Config::getConfig(); $baseUrl = Application_Common_OsPath::getBaseDir(); - $this->view->headLink()->appendStylesheet($baseUrl.'css/embeddableplayer.css?'.$CC_CONFIG['airtime_version']); + $this->view->headLink()->appendStylesheet($baseUrl.'css/embeddable-player-form.css?'.$CC_CONFIG['airtime_version']); $this->view->headScript()->appendFile($baseUrl.'js/airtime/embeddableplayer/mrp.js?'.$CC_CONFIG['airtime_version']); $this->view->headScript()->appendFile($baseUrl.'js/airtime/embeddableplayer/embeddableplayer.js?'.$CC_CONFIG['airtime_version']); @@ -31,8 +31,12 @@ class EmbeddablePlayerController extends Zend_Controller_Action $request = $this->getRequest(); + $this->view->css = Application_Common_HTTPHelper::getStationUrl() . "css/embeddable-player.css"; $this->view->mrp_js = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/embeddableplayer/mrp.js"; + $this->view->jquery = Application_Common_HTTPHelper::getStationUrl() . "js/libs/jquery-1.10.2.js"; $this->view->muses_swf = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/embeddableplayer/muses.swf"; + $this->view->metadata_api_url = Application_Common_HTTPHelper::getStationUrl() . "api/live-info"; + $this->view->station_name = Application_Model_Preference::GetStationName(); $stream = $request->getParam('stream'); $streamData = Application_Model_StreamSetting::getEnabledStreamData(); $selectedStreamData = $streamData[$stream]; diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php index ba7c5fce9..e5086716a 100644 --- a/airtime_mvc/application/forms/EmbeddablePlayer.php +++ b/airtime_mvc/application/forms/EmbeddablePlayer.php @@ -17,11 +17,11 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm $streamMode->setLabel(_('Select Stream:')); $streamMode->setMultiOptions( array( - "a" => "Use a mobile stream if possible, when appropriate. Otherwise use the highest quality stream.", - "b" => "Select a stream" + "auto" => "Auto detect the most appropriate stream to use.", + "manual" => "Select a stream:" ) ); - $streamMode->setValue("a"); + $streamMode->setValue("auto"); $this->addElement($streamMode); $streamURL = new Zend_Form_Element_Radio('player_stream_url'); @@ -42,7 +42,7 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm ); foreach ($urlOptions as $o => $v) { - if (strpos($v, "opus") !== false) { + if (strpos(strtolower($v), "opus") !== false) { continue; } else { $streamURL->setValue($o); @@ -57,7 +57,7 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm $embedSrc = new Zend_Form_Element_Text('player_embed_src'); $embedSrc->setAttrib("readonly", "readonly"); $embedSrc->setAttrib("class", "embed-player-text-box"); - $embedSrc->setValue(''); + $embedSrc->setValue(''); $embedSrc->removeDecorator('label'); $this->addElement($embedSrc); diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml index adab3876e..47e713e42 100644 --- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml +++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml @@ -2,7 +2,9 @@ + + + @@ -62,18 +110,58 @@ +
+ +
+

fff

+ airtime.pro +
+ +
+ +
+ + +
+

+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+

Next

+
    +
  • John Legend - Ordinary People
  • +
+
+ +
+
+ \ No newline at end of file diff --git a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml index 7ab6cb227..18305c20b 100644 --- a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml +++ b/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml @@ -3,12 +3,12 @@ element->getElement('player_embed_src'); ?> - element->getElement('player_display_track_metadata'); ?> - element->getElement('player_stream_mode'); ?> element->getElement('player_stream_url'); ?> + element->getElement('player_display_track_metadata'); ?> + element->getElement('player_preview_label')->renderLabel(); ?>
diff --git a/airtime_mvc/public/css/colorpicker/embeddable-player.css b/airtime_mvc/public/css/colorpicker/embeddable-player.css new file mode 100644 index 000000000..e69de29bb diff --git a/airtime_mvc/public/css/embed-player-images/airtime_logo.png b/airtime_mvc/public/css/embed-player-images/airtime_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..db8e5fb816358773294e4bb922cc58ca07cf69a3 GIT binary patch literal 1162 zcmaJ>TWs4@7${+%;P#~sSaW?I<6s5G}T2^ zMykH@>gQ;ZVfr|uQYF>Wi;9L#UiC4&XWEp_Fq0|IR<$M~poSI=E6M$`af<_np5#u& zOJd2+p@uQD>Y(}6*^0K>)Dk+EIu0g1g$kI6sK7IqELZW8+_tVl=l-_9fo%wBCbYhxz`euv=NNkx)i1UUoFvxcaCc z%2sj?QVDh{7%z2Cajt<0b{p6Rxp^6koiZ#Px7@?q_)Uk(;VXh!a5Ef!tQOspyFazU-oD4G)U2Yz0%O=h!y`?Ew4ao*!dT*x}R1HrEEO z2kssLFAsDkE`>h`ef?*8>5KHpy-?@OS#MxH6!~PIzSY+rW~T$~XZr3g92kA+pcrh& zzq!JIcRN>qPi<{ntOg$obHj;!AZ!WS-o*uTX-%iWK> zRrvLABQ3GgTIBK*UuA~azn|J~HTkpVrsL*wiDnz2M`E!X+lSk2zX}hWy8u QpZR}>VqrFaJ-cx3A7~43IsgCw literal 0 HcmV?d00001 diff --git a/airtime_mvc/public/css/embed-player-images/mute.png b/airtime_mvc/public/css/embed-player-images/mute.png new file mode 100644 index 0000000000000000000000000000000000000000..0276df62e7bae7cbe95915c4a590d5d0c0cd1e62 GIT binary patch literal 1338 zcmeAS@N?(olHy`uVBq!ia0vp@Ak4uAB#T}@sR2@wC9V-A!TD(=<%vb942~)JNvR5+ zxryniL8*x;m4zo$Z5SAsl`=yjN+NuHtdjF{^%6m9^eS=-fVvqNZ0suv5|gu2OB9k) z(=+pImEP~(ucVNfVyhHx>TBRz;GCL~=}}db8eHWUl3bOYY?-2DZ>L~WVFffGH?<^D zp&~aYuh^=>Rtapb6_5=Q)>l#hD=EpgRf0Gw!Z$#{Ilm}X!Bo#!H`&0@P{GVh&(Orw z%*;?n!N|bSNZ$a6%ybP+tW3?UjLa3FKnZADQA(Oskc%7CE+EfVDWjyMz)D}gyu4hm z+*mKaC|%#s($W%ShLMpjP=#)BWnM{Qg>GK4GRy>*)Z*l#%z~24{5%DaiHS-1r6smX zK$k+ikXryZHm?{OOuzusuShJ=H`Fr#c?qV_*B8Ii++4Wo;*y|LgnO|XTpUtakg6Y) zTAW{6lnjixG-Z%g1y;^Qsfi`|MIrh5Ij~R+$jC3rFV4s>P;d@5Q_u*{%uC5HFV+OB z_w}{%%quQQ%u7!7bg@+enxL1NnPO#PV&G!rWZ~lMYUF5W=xSo=X5`}P>||tO>|$hK zY2ggh>yn>bnwy$e0@Is<(Cdm*FDNPG765H_NiE7OOHFYr%Fk5*d)X=zw_BWWng`XJ zg4-?5IQ8lS9itD5Sfq%C2?0|NhzU=&Kn^_Nr{)1udl4{MmrBOJWnf@j=jq}YQgJIM zXumg8qQt*+}r=PbvoZwI6Yel3`VjI<&M+rg_oQ ze~m2~;_U`T6Z%5>URT=hJFrPy?#Dg(^Pm4cn0#Z8W`p>KMneO}Wt&+q*)Lh@qqbSJ z*UjH;@x`*WVY{7t*mNAX&8cT`YH(v&fBm%6!T{-gn?tl@Z*4n!>ggxJi5`yZhYm#P zh;fH&O`Ui9ZQ8DN#`Di#ciUKOBNy**L_qm;%w2d{zohp3dLak`Qg!r{#rk;<=AJ6?^so5Yn!=u3Yqqb)7ngETObCZ0SILu2F z5A`d4yO6cDOz?J&*=%X0V_~MPjtp3UqPt++* z+##YJ@K*fOvpeQOk5@hVf3dpZ(8-*$+ZmV{rv8~4yV-Z!6i{jA>FVdQ&MBb@0Lzx( Ae%^Y2EohVzDoUWlJCnjgM8~C88 zsGuTVL2)P|_@Lk(L{XU{h&K>@P|-(WA}E^=;)HoQscrSa8j_p~-}n9h`Ty@6XlY(M zwQ61!MNw1Z>!bu3tI0Qi(nRu4zuUNp40CZbgt=`^zBNb#T?^4|LD?r;5tz}} z_1UnsuQ{pqWz~9(Zd?r-@*)v1AXY%$*k(FnK13IEMKX7{SsD}|I2)pWCzX<0Km^$k z1R1|q^>G{!1cnO)1%X=ucpt~JKJp4)E+7U4k*@>AhbGZ%EiERbSTPn^h3E{%mdLWX zT#m{48Dw{}Tz!4LtHJYLg77-MCRXxZ(^*_nkf5X5x`lOQ0#{M#LOnP{lT3df!LZ7* zrc*2vDHxkqES6(@?vYABS^huNFv@5LC*Yra|0(Pwdo9Q&po4mBl{7BB*bQZg5gRHP z*-3=9m8#g1K^Qq1WPwPl0G74sriOCP@&aC##klEU#Z+Nj3eiM?(REF%3&c2{Z}LT= zQ9s8;15JD^x^iVWCisGNejy-~xDrx(3~1sKSNp@|Dso*b7#4{vL0jJewU~_zP&l%v zSIi|Gt*BSzY87({$0~AJk__uM_OC{lwupP&Y1y`9Q8qp_iQ8>r>-5>vCb<%q<5D=8 zfAjI=wW|AI#=bi#?&4lNdGyD#p_Yd)YP<`V3=J-Qom_u(50e|IS@84Q&EDB+a_vj~ zEx0h{us;(Xmmcv<_bq+iHSNf`gPv)t-kY1VC$GrEJ3Ed&ne3U~o}JUL57wTV^>mD0 z#6P(GC2JoNZ%Dv1bN`z0^ynEdd*FQS*P6SJpATKS{=LIF-hO+cHDT+(aKpWY{bQ%M jB%kj3e5Ui&=JD0krx}eWKCD;(+>0EKHcMBVI(Pp9Z|`BS literal 0 HcmV?d00001 diff --git a/airtime_mvc/public/css/embed-player-images/play_button.png b/airtime_mvc/public/css/embed-player-images/play_button.png new file mode 100644 index 0000000000000000000000000000000000000000..bff38adbc4fb4fb1da43231742f93568d8827ae2 GIT binary patch literal 1590 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 literal 0 HcmV?d00001 diff --git a/airtime_mvc/public/css/embeddableplayer.css b/airtime_mvc/public/css/embeddable-player-form.css similarity index 99% rename from airtime_mvc/public/css/embeddableplayer.css rename to airtime_mvc/public/css/embeddable-player-form.css index a1e12cbc0..9a6fe20d8 100644 --- a/airtime_mvc/public/css/embeddableplayer.css +++ b/airtime_mvc/public/css/embeddable-player-form.css @@ -12,3 +12,5 @@ padding: 4px 0px 4px 0px; } + + diff --git a/airtime_mvc/public/css/embeddable-player.css b/airtime_mvc/public/css/embeddable-player.css new file mode 100644 index 000000000..6c770c693 --- /dev/null +++ b/airtime_mvc/public/css/embeddable-player.css @@ -0,0 +1,190 @@ +.airtime_player { + max-width: 270px; + position: relative; + font-family: Arial, Helvetica, sans-serif; + color: #fff; + background: rgba(53, 53, 53, 0.9); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 3px 5px rgba(0,0,0,0.1) inset,0 1px 0 rgba(255,255,255,0.1),0 0 1px #000 inset; + -moz-box-shadow: 0 3px 5px rgba(0,0,0,0.1) inset,0 1px 0 rgba(255,255,255,0.1),0 0 1px #000 inset; + box-shadow: 0 3px 5px rgba(0,0,0,0.1) inset,0 1px 0 rgba(255,255,255,0.1),0 0 1px #000 inset; +} + +.airtime_header { + background: rgba(53, 53, 53, 0.9); + -webkit-box-shadow: 0 3px 5px rgba(0,0,0,0.1) inset,0 1px 0 rgba(255,255,255,0.1),0 0 1px #000 inset; + -moz-box-shadow: 0 3px 5px rgba(0,0,0,0.1) inset,0 1px 0 rgba(255,255,255,0.1),0 0 1px #000 inset; + box-shadow: 0 3px 5px rgba(0,0,0,0.1) inset,0 1px 0 rgba(255,255,255,0.1),0 0 1px #000 inset; + height: 37px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.airtime_box { + margin-top: 15px; + float: left; + width: 100%; +} +.station_name { + font-size: 14px; + padding-top: 10px; + padding-left: 20px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + padding-right: 30px; +} +.airtime_pro { + position: absolute; + right: 15px; + top: 10px; + color: #fff; + font-size: 12px; + text-decoration: none; +} +.airtime_pro span { + display: inline-block; + vertical-align: 2px; + margin-right: 5px; +} +.airtime_pro:hover span { + display: inline-block; + vertical-align: 2px; + margin-right: 5px; +} +.airtime_box .airtime_button { + text-indent: -9999px; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + background: rgb(100,100,100); + background: -moz-linear-gradient(top, rgba(107, 107, 107, 1) 0%, rgba(88,88,88,1) 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(100,100,100,1)), color-stop(100%,rgba(88,88,88,1))); + background: -webkit-linear-gradient(top, rgba(107, 107, 107, 1) 0%,rgba(88,88,88,1) 100%); + background: -o-linear-gradient(top, rgba(107, 107, 107, 1) 0%,rgba(88,88,88,1) 100%); + background: -ms-linear-gradient(top, rgba(107, 107, 107, 1) 0%,rgba(88,88,88,1) 100%); + background: linear-gradient(to bottom, rgba(107, 107, 107, 1) 0%,rgba(88,88,88,1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#646464', endColorstr='#585858',GradientType=0 ); + -webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.2) inset; + -moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.2) inset; + box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.2) inset; + width: 47px; + height: 47px; + display: inline-block; + float: left; + cursor: pointer; + margin-left: 20px; + margin-right: 15px; +} + +.airtime_box .airtime_button:hover { + background: rgb(147,147,147); + background: -moz-linear-gradient(top, rgba(147,147,147,1) 0%, rgba(117,117,117,1) 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(147,147,147,1)), color-stop(100%,rgba(117,117,117,1))); + background: -webkit-linear-gradient(top, rgba(147,147,147,1) 0%,rgba(117,117,117,1) 100%); + background: -o-linear-gradient(top, rgba(147,147,147,1) 0%,rgba(117,117,117,1) 100%); + background: -ms-linear-gradient(top, rgba(147,147,147,1) 0%,rgba(117,117,117,1) 100%); + background: linear-gradient(to bottom, rgba(147,147,147,1) 0%,rgba(117,117,117,1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#939393', endColorstr='#757575',GradientType=0 ); +} + +.airtime_box .airtime_button .play_button { + display: block; + background: url("embed-player-images/play_button.png") center no-repeat; + width: 47px; + height: 47px; +} + +.airtime_box .airtime_button .stop_button { + display: block; + background: url("embed-player-images/pause_button.png") center no-repeat; + width: 47px; + height: 47px; +} + +.hide_button { + display:none !important; +} + +.now_playing { + margin-top: 8px; + margin-left: 15px; + margin-right: 15px; + display: block; + font-size: 14px; + color: #fff; + width: auto; +} + +.now_playing span { + display: block; + color: #aaaaaa; +} + +.airtime_volume { + padding: 10px 0px 15px 0px; + clear: both; +} + +.airtime_volume .volume_control { + margin-left: 55px; + float: left; + display: inline-block; +} + +.airtime_volume .mute { + background: url("embed-player-images/mute.png") center no-repeat; + display: block; + margin-top: -4px; + width: 15px; + height: 15px; + cursor: pointer; +} + +.airtime_volume_bar { + border-color: #262526 #262526 #5E5E5E; + border-style: solid; + border-width: 1px; + background-color: #393939; + width: auto; + height: 5px; + cursor: pointer; + margin-left: 80px; + margin-right: 40px; +} + +.airtime_volume_bar_value { + background-color: #ff9122; + width: 0px; + height: 5px; +} + +.airtime_schedule { + margin: 0px 20px 10px 20px; + padding-top: 10px; + font-size: 14px; + color: #aaaaaa; + border-top: 1px solid rgba(255, 255, 255, 0.1); +} + +.airtime_next { + float: left; + margin: 0px; +} + +.schedule_list { + list-style: none; + padding-left: 0px; + padding-bottom: 10px; + margin-top: 0px; + margin-left: 60px; + line-height: 130%; +} + +.schedule_list li { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} \ No newline at end of file diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js index 376c64e57..be4bbc7c3 100644 --- a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js +++ b/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js @@ -2,17 +2,25 @@ function updateEmbedSrcParams() { var $embedCodeParams = "?"; var $streamMode = getStreamMode(); - if ($streamMode == "b") { + if ($streamMode == "manual") { var $stream = $("input[name=player_stream_url]:radio:checked").val(); - $embedCodeParams += "stream-mode=b&stream="+$stream; - } else if ($streamMode == "a") { - $embedCodeParams += "stream-mode=a"; + $embedCodeParams += "stream="+$stream; + } else if ($streamMode == "auto") { + $embedCodeParams += "stream=auto"; } $embedCodeParams += "\""; $("input[name=player_embed_src]").val(function(index, value) { return value.replace(/\?.*?"/, $embedCodeParams); }); + + updatePlayerIframeSrc($("input[name=player_embed_src]").val()); +} + +function updatePlayerIframeSrc(iframe_text) { + var $player_iframe = $("#player_form iframe"); + var player_iframe_src = iframe_text.match(/http.*?"/)[0].slice(0, -1); + $player_iframe.attr('src', player_iframe_src); } function getStreamMode() { @@ -23,9 +31,9 @@ $(document).ready(function() { $("#player_stream_mode-element").change(function() { var $streamMode = getStreamMode(); - if ($streamMode == "a") { + if ($streamMode == "auto") { $("#player_stream_url-element input[type='radio']").attr("disabled", "disabled"); - } else if ($streamMode == "b") { + } else if ($streamMode == "manual") { $("#player_stream_url-element input[type='radio']").removeAttr("disabled"); $("input[name=player_stream_url]").each(function(i, obj) { From 3d2b189dbadfe28a651716d9f8c703edc6cd39be Mon Sep 17 00:00:00 2001 From: drigato Date: Wed, 25 Mar 2015 11:47:23 -0400 Subject: [PATCH 29/60] removed logging statement --- .../application/views/scripts/embeddableplayer/embed-code.phtml | 1 - 1 file changed, 1 deletion(-) diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml index 47e713e42..f650ed509 100644 --- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml +++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml @@ -83,7 +83,6 @@ data: {type:"interval",limit:"5"}, dataType: "jsonp", success: function(data) { - console.log("fetching metadata"); var current_track_end_time = new Date(data.current.ends); var current_time = new Date(); current_time = new Date(current_time.getTime() + current_time.getTimezoneOffset()*60*1000); From d0f7f820a78516c096acaa61b2b9c077eea4389b Mon Sep 17 00:00:00 2001 From: drigato Date: Fri, 27 Mar 2015 16:34:04 -0400 Subject: [PATCH 30/60] SAAS-675: Implement "auto" mode --- .../EmbeddableplayerController.php | 25 ++- .../scripts/embeddableplayer/embed-code.phtml | 150 ++++++++++++++---- 2 files changed, 143 insertions(+), 32 deletions(-) diff --git a/airtime_mvc/application/controllers/EmbeddableplayerController.php b/airtime_mvc/application/controllers/EmbeddableplayerController.php index 2a66d0b7e..2d70c08a2 100644 --- a/airtime_mvc/application/controllers/EmbeddableplayerController.php +++ b/airtime_mvc/application/controllers/EmbeddableplayerController.php @@ -39,9 +39,26 @@ class EmbeddablePlayerController extends Zend_Controller_Action $this->view->station_name = Application_Model_Preference::GetStationName(); $stream = $request->getParam('stream'); $streamData = Application_Model_StreamSetting::getEnabledStreamData(); - $selectedStreamData = $streamData[$stream]; - $this->view->streamURL = $selectedStreamData["url"]; - $this->view->codec = $selectedStreamData["codec"]; - $this->view->displayMetadata = $request->getParam('display_metadata'); + + if ($stream == "auto") { + $this->view->playerMode = "auto"; + $availableMobileStreams = array(); + $availableDesktopStreams = array(); + foreach ($streamData as $s) { + if ($s["mobile"]) { + array_push($availableMobileStreams, $s); + } else if (!$s["mobile"]) { + array_push($availableDesktopStreams, $s); + } + } + $this->view->availableMobileStreams = json_encode($availableMobileStreams); + $this->view->availableDesktopStreams = json_encode($availableDesktopStreams); + } else { + $this->view->playerMode = "manual"; + $selectedStreamData = $streamData[$stream]; + $this->view->streamURL = $selectedStreamData["url"]; + $this->view->codec = $selectedStreamData["codec"]; + } + //$this->view->displayMetadata = $request->getParam('display_metadata'); } } \ No newline at end of file diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml index f650ed509..940850be9 100644 --- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml +++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml @@ -8,19 +8,42 @@ - - \ No newline at end of file diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js b/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js index 4377dddd5..ca7140dc1 100644 --- a/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js +++ b/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js @@ -2298,6 +2298,7 @@ this.ui = new d.UI(this, a); a.autoplay && (a = window.navigator.userAgent.toLowerCase(), -1 == a.indexOf("iphone") && -1 == a.indexOf("ipad") && -1 == a.indexOf("ipod") && this.playAudio()) + n.MRP.html = this; }; d.Muses.__name__ = !0; d.Muses.initTimer = function(a) { From 15a8e3fa1f5e8fb2accfa58d63e6cfd814ced198 Mon Sep 17 00:00:00 2001 From: drigato Date: Tue, 31 Mar 2015 17:20:42 -0400 Subject: [PATCH 32/60] Moved html5 error listener to MusesPlayer constructor --- .../scripts/embeddableplayer/embed-code.phtml | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml index 5c1a57b74..076b6c38f 100644 --- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml +++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml @@ -39,6 +39,16 @@ $("p.station_name").html("station_name?>"); getMetadata(); + + // detects errors in HTML5 mode + if (!this.flashDetect) { + MRP.html.audio.addEventListener('error', function failed(e) { + var stream = musesPlayer.getNextAvailableStream(); + console.log(stream); + MRP.html.audio.src = stream["url"]; + MRP.html.audio.play(); + }, true); + } }; MusesPlayer.prototype.mobileDetect = function() { @@ -120,13 +130,6 @@ MRP.html.audio.src = MRP.html.src; MRP.html.audio.play(); - - // detects errors in HTML5 mode - MRP.html.audio.addEventListener('error', function failed(e) { - var stream = musesPlayer.getNextAvailableStream(); - MRP.html.audio.src = stream["url"]; - MRP.html.audio.play(); - }, true); } function musesHTMLStopClick() { From 57cd2eda13dd00aa98c587859cb1d7ab20218c48 Mon Sep 17 00:00:00 2001 From: drigato Date: Tue, 31 Mar 2015 18:21:25 -0400 Subject: [PATCH 33/60] bad merge --- airtime_mvc/application/configs/ACL.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/airtime_mvc/application/configs/ACL.php b/airtime_mvc/application/configs/ACL.php index fe6e4d3d6..1386d1dee 100644 --- a/airtime_mvc/application/configs/ACL.php +++ b/airtime_mvc/application/configs/ACL.php @@ -71,11 +71,8 @@ $ccAcl->allow('G', 'index') ->allow('A', 'user') ->allow('A', 'systemstatus') ->allow('A', 'preference') -<<<<<<< HEAD ->allow('A', 'embeddableplayer') -======= ->allow('S', 'thank-you') ->>>>>>> saas ->allow('S', 'billing'); From c1038cd92fe0b28ead6b39afa476e7f53b5e1531 Mon Sep 17 00:00:00 2001 From: drigato Date: Wed, 1 Apr 2015 11:25:58 -0400 Subject: [PATCH 34/60] SAAS-706: Remove volume bar from player --- .../views/scripts/embeddableplayer/embed-code.phtml | 5 +++-- airtime_mvc/public/css/embeddable-player.css | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml index 076b6c38f..0af07296e 100644 --- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml +++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml @@ -209,7 +209,7 @@ -
+ +

Next

diff --git a/airtime_mvc/public/css/embeddable-player.css b/airtime_mvc/public/css/embeddable-player.css index 6c770c693..be1a06d9d 100644 --- a/airtime_mvc/public/css/embeddable-player.css +++ b/airtime_mvc/public/css/embeddable-player.css @@ -162,7 +162,7 @@ } .airtime_schedule { - margin: 0px 20px 10px 20px; + margin: 10px 20px 10px 20px; padding-top: 10px; font-size: 14px; color: #aaaaaa; From eaeed9be77a04b3f95164b479f1ce7de091d7794 Mon Sep 17 00:00:00 2001 From: drigato Date: Wed, 1 Apr 2015 12:50:49 -0400 Subject: [PATCH 35/60] SAAS-669: Long station names overlap with link to airtime.pro --- .../views/scripts/embeddableplayer/embed-code.phtml | 3 ++- airtime_mvc/public/css/embeddable-player.css | 12 ++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml index 0af07296e..d2aa129db 100644 --- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml +++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml @@ -196,7 +196,6 @@

fff

- airtime.pro
@@ -227,8 +226,10 @@
+ Powered by Airtime Pro
+
diff --git a/airtime_mvc/public/css/embeddable-player.css b/airtime_mvc/public/css/embeddable-player.css index be1a06d9d..88f3ee187 100644 --- a/airtime_mvc/public/css/embeddable-player.css +++ b/airtime_mvc/public/css/embeddable-player.css @@ -37,13 +37,15 @@ padding-right: 30px; } .airtime_pro { - position: absolute; - right: 15px; - top: 10px; color: #fff; - font-size: 12px; + font-size: 10px; text-decoration: none; } +.airtime_pro_logo { + background: url("embed-player-images/airtime_logo.png") center no-repeat; + width: 16px; + height: 16px; +} .airtime_pro span { display: inline-block; vertical-align: 2px; @@ -167,6 +169,7 @@ font-size: 14px; color: #aaaaaa; border-top: 1px solid rgba(255, 255, 255, 0.1); + padding-bottom: 5px; } .airtime_next { @@ -180,6 +183,7 @@ padding-bottom: 10px; margin-top: 0px; margin-left: 60px; + margin-bottom: 0px; line-height: 130%; } From 0bffa07ed9129995b3420d184432733e267e22e7 Mon Sep 17 00:00:00 2001 From: drigato Date: Wed, 1 Apr 2015 12:59:31 -0400 Subject: [PATCH 36/60] SAAS-669: Long station names overlap with link to airtime.pro --- airtime_mvc/public/css/embeddable-player.css | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/airtime_mvc/public/css/embeddable-player.css b/airtime_mvc/public/css/embeddable-player.css index 88f3ee187..30ce8beac 100644 --- a/airtime_mvc/public/css/embeddable-player.css +++ b/airtime_mvc/public/css/embeddable-player.css @@ -45,8 +45,9 @@ background: url("embed-player-images/airtime_logo.png") center no-repeat; width: 16px; height: 16px; + display:inline-block; } -.airtime_pro span { +/*.airtime_pro span { display: inline-block; vertical-align: 2px; margin-right: 5px; @@ -55,7 +56,7 @@ display: inline-block; vertical-align: 2px; margin-right: 5px; -} +}*/ .airtime_box .airtime_button { text-indent: -9999px; -webkit-border-radius: 2px; From 353bfe86a5f9c7ac915503dff569d1530a83438d Mon Sep 17 00:00:00 2001 From: drigato Date: Wed, 1 Apr 2015 13:05:08 -0400 Subject: [PATCH 37/60] Addded default for mobile stream setting --- airtime_mvc/application/models/StreamSetting.php | 1 + 1 file changed, 1 insertion(+) diff --git a/airtime_mvc/application/models/StreamSetting.php b/airtime_mvc/application/models/StreamSetting.php index 19a147798..c51995d6d 100644 --- a/airtime_mvc/application/models/StreamSetting.php +++ b/airtime_mvc/application/models/StreamSetting.php @@ -177,6 +177,7 @@ class Application_Model_StreamSetting self::ensureKeyExists($keyPrefix . 'type', $data); self::ensureKeyExists($keyPrefix . 'url', $data); self::ensureKeyExists($keyPrefix . 'user', $data); + self::ensureKeyExists($keyPrefix . 'mobile', $data); return $data; } From 06f43ef2d7c3420d57831f8fdd0366790a39e17d Mon Sep 17 00:00:00 2001 From: drigato Date: Thu, 2 Apr 2015 12:45:05 -0400 Subject: [PATCH 38/60] CSS modifications Added fixed width and height to player. Floated Airtime badge to the right --- airtime_mvc/public/css/embeddable-player.css | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/airtime_mvc/public/css/embeddable-player.css b/airtime_mvc/public/css/embeddable-player.css index 30ce8beac..420d12ede 100644 --- a/airtime_mvc/public/css/embeddable-player.css +++ b/airtime_mvc/public/css/embeddable-player.css @@ -1,5 +1,6 @@ .airtime_player { - max-width: 270px; + width: 270px; + height: 172px; position: relative; font-family: Arial, Helvetica, sans-serif; color: #fff; @@ -40,6 +41,8 @@ color: #fff; font-size: 10px; text-decoration: none; + display:inline-block; + float:right; } .airtime_pro_logo { background: url("embed-player-images/airtime_logo.png") center no-repeat; @@ -47,6 +50,7 @@ height: 16px; display:inline-block; } + /*.airtime_pro span { display: inline-block; vertical-align: 2px; From fdd8cdfaeaf5ff9ffc77fe43877461d5fd52a100 Mon Sep 17 00:00:00 2001 From: drigato Date: Thu, 2 Apr 2015 14:35:13 -0400 Subject: [PATCH 39/60] Fixed Airtime badge spacing --- .../views/scripts/embeddableplayer/embed-code.phtml | 2 +- airtime_mvc/public/css/embeddable-player.css | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml index d2aa129db..d1047885c 100644 --- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml +++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml @@ -226,8 +226,8 @@
- Powered by Airtime Pro
+ Powered by Airtime Pro
diff --git a/airtime_mvc/public/css/embeddable-player.css b/airtime_mvc/public/css/embeddable-player.css index 420d12ede..261a6496f 100644 --- a/airtime_mvc/public/css/embeddable-player.css +++ b/airtime_mvc/public/css/embeddable-player.css @@ -1,6 +1,6 @@ .airtime_player { width: 270px; - height: 172px; + height: 180px; position: relative; font-family: Arial, Helvetica, sans-serif; color: #fff; @@ -38,6 +38,7 @@ padding-right: 30px; } .airtime_pro { + margin: 0px 20px; color: #fff; font-size: 10px; text-decoration: none; @@ -169,12 +170,13 @@ } .airtime_schedule { - margin: 10px 20px 10px 20px; + margin: 10px 20px 5px 20px; padding-top: 10px; font-size: 14px; color: #aaaaaa; border-top: 1px solid rgba(255, 255, 255, 0.1); - padding-bottom: 5px; + border-bottom: 1px solid rgba(255, 255, 255, 0.1); + padding-bottom: 0px; } .airtime_next { From 4ab4fe5cb9886dc0e24e8104091d96cba22e7e15 Mon Sep 17 00:00:00 2001 From: drigato Date: Thu, 2 Apr 2015 15:00:46 -0400 Subject: [PATCH 40/60] Fixed player css so long artist and track names don't overflow --- airtime_mvc/public/css/embeddable-player.css | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/airtime_mvc/public/css/embeddable-player.css b/airtime_mvc/public/css/embeddable-player.css index 261a6496f..3c9ef0f08 100644 --- a/airtime_mvc/public/css/embeddable-player.css +++ b/airtime_mvc/public/css/embeddable-player.css @@ -1,6 +1,6 @@ .airtime_player { width: 270px; - height: 180px; + height: 185px; position: relative; font-family: Arial, Helvetica, sans-serif; color: #fff; @@ -123,12 +123,19 @@ display: block; font-size: 14px; color: #fff; - width: auto; + width: 170px; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; } .now_playing span { display: block; color: #aaaaaa; + width: 170px; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; } .airtime_volume { From 369a59c564ad1212360acfc85053eeaedf6f0bbf Mon Sep 17 00:00:00 2001 From: drigato Date: Thu, 2 Apr 2015 15:13:34 -0400 Subject: [PATCH 41/60] Changed mobile option text on streams page --- airtime_mvc/application/forms/StreamSettingSubForm.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/airtime_mvc/application/forms/StreamSettingSubForm.php b/airtime_mvc/application/forms/StreamSettingSubForm.php index b84adf63d..8d1f96f43 100644 --- a/airtime_mvc/application/forms/StreamSettingSubForm.php +++ b/airtime_mvc/application/forms/StreamSettingSubForm.php @@ -54,7 +54,7 @@ class Application_Form_StreamSettingSubForm extends Zend_Form_SubForm $this->addElement($enable); $mobile = new Zend_Form_Element_Checkbox('mobile'); - $mobile->setLabel(_('Good for mobile?')); + $mobile->setLabel(_('Mobile:')); $mobile->setValue($setting[$prefix.'_mobile']); $mobile->setDecorators(array('ViewHelper')); $this->addElement($mobile); From e8c8fde8bde50325d7c1c81b5a64146ec02b7752 Mon Sep 17 00:00:00 2001 From: drigato Date: Thu, 2 Apr 2015 15:27:01 -0400 Subject: [PATCH 42/60] Fix airtime.pro link on player --- .../application/views/scripts/embeddableplayer/embed-code.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml index d1047885c..4ab35b768 100644 --- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml +++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml @@ -227,7 +227,7 @@
  • - Powered by Airtime Pro + Powered by Airtime Pro From faee0fba98123587b5ae9646cca4b93ef902c1c9 Mon Sep 17 00:00:00 2001 From: drigato Date: Thu, 2 Apr 2015 16:54:57 -0400 Subject: [PATCH 43/60] SAAS-673: Warn if public api is not enabled under Preferences --- .../controllers/EmbeddableplayerController.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/airtime_mvc/application/controllers/EmbeddableplayerController.php b/airtime_mvc/application/controllers/EmbeddableplayerController.php index 6a00df36b..3552ee47e 100644 --- a/airtime_mvc/application/controllers/EmbeddableplayerController.php +++ b/airtime_mvc/application/controllers/EmbeddableplayerController.php @@ -17,10 +17,15 @@ class EmbeddablePlayerController extends Zend_Controller_Action $form = new Application_Form_EmbeddablePlayer(); - if ($form->getElement('player_stream_url')->getAttrib('numberOfEnabledStreams') > 0) { + $apiEnabled = Application_Model_Preference::GetAllow3rdPartyApi(); + $numEnabledStreams = $form->getElement('player_stream_url')->getAttrib('numberOfEnabledStreams'); + + if ($numEnabledStreams > 0 && $apiEnabled) { $this->view->form = $form; } else { - $this->view->errorMsg = "You need to enable at least one MP3, AAC, or OGG stream to use this feature."; + $this->view->errorMsg = "To configure and use the embeddable player you must:

    + 1. Enable at least one MP3, AAC, or OGG stream under System -> Streams
    + 2. Enable the Public Airtime API under System -> Preferences"; } } From 481d21ff70a6bfd77dde5d4835d7d0ab01c01850 Mon Sep 17 00:00:00 2001 From: drigato Date: Tue, 7 Apr 2015 11:34:21 -0400 Subject: [PATCH 44/60] SAAS-662: Make player auto-connect if there is a problem with the stream HTML5 error handling --- .../scripts/embeddableplayer/embed-code.phtml | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml index 4ab35b768..66117609a 100644 --- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml +++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml @@ -15,7 +15,7 @@ 'volume': 100, 'jsevents': true, 'autoplay': false, - 'buffering': 5, + 'buffering': 0, 'title': 'test', 'bgcolor': '#FFFFFF', 'skin': 'mcclean', @@ -26,27 +26,37 @@ if (this.playerMode == "manual") { this.settings.url = "streamURL ?>"; this.settings.codec = "codec ?>"; - MRP.insert(this.settings); } else if (this.playerMode == "auto") { this.availableMobileStreamQueue = availableMobileStreams?>; this.availableDesktopStreamQueue = availableDesktopStreams?>; var stream = this.getNextAvailableStream(); this.settings.url = stream["url"]; this.settings.codec = stream["codec"]; - MRP.insert(this.settings); } + MRP.insert(this.settings); + $("p.station_name").html("station_name?>"); getMetadata(); - // detects errors in HTML5 mode + // detects events in HTML5 mode if (!this.flashDetect) { + MRP.html.audio.addEventListener('error', function failed(e) { + console.log("HTML error"); var stream = musesPlayer.getNextAvailableStream(); - console.log(stream); - MRP.html.audio.src = stream["url"]; - MRP.html.audio.play(); + var audio = $(MRP.html.audio); + audio.src = stream["url"]; + audio[0].load(); + audio[0].play(); + }, true); + + MRP.html.audio.addEventListener('pause', function paused(e) { + //this is when pause happens + console.log("HTML paused"); + //src = MRP.html.audio.src; + //MRP.html.audio.src = ""; }, true); } }; @@ -109,6 +119,7 @@ }; MusesPlayer.prototype.setURL = function(url) { + console.log("setURL"); MRP.setUrl(url); }; From f6d5b34cca21493931e8243476a5dbecd0685221 Mon Sep 17 00:00:00 2001 From: drigato Date: Tue, 7 Apr 2015 17:49:21 -0400 Subject: [PATCH 45/60] Embed player - code review fixes --- .../application/controllers/ApiController.php | 2 +- .../EmbeddableplayerController.php | 17 +++- .../application/forms/EmbeddablePlayer.php | 19 +++-- .../application/models/StreamSetting.php | 16 ---- .../scripts/embeddableplayer/embed-code.phtml | 83 ++++++++++++++----- 5 files changed, 89 insertions(+), 48 deletions(-) diff --git a/airtime_mvc/application/controllers/ApiController.php b/airtime_mvc/application/controllers/ApiController.php index 80429db08..5ecd5f1da 100644 --- a/airtime_mvc/application/controllers/ApiController.php +++ b/airtime_mvc/application/controllers/ApiController.php @@ -523,7 +523,7 @@ class ApiController extends Zend_Controller_Action $result["description"] = Application_Model_Preference::GetStationDescription(); $result["timezone"] = Application_Model_Preference::GetDefaultTimezone(); $result["locale"] = Application_Model_Preference::GetDefaultLocale(); - $result["enabled_stream_urls"] = Application_Model_StreamSetting::getEnabledStreamUrls(); + $result["stream_data"] = Application_Model_StreamSetting::getEnabledStreamData(); // used by caller to determine if the airtime they are running or widgets in use is out of date. $result['AIRTIME_API_VERSION'] = AIRTIME_API_VERSION; diff --git a/airtime_mvc/application/controllers/EmbeddableplayerController.php b/airtime_mvc/application/controllers/EmbeddableplayerController.php index 3552ee47e..43e8be2d5 100644 --- a/airtime_mvc/application/controllers/EmbeddableplayerController.php +++ b/airtime_mvc/application/controllers/EmbeddableplayerController.php @@ -30,18 +30,29 @@ class EmbeddablePlayerController extends Zend_Controller_Action } + /** + * This is the action that is called to insert the player onto a web page. + * It passes all the js and css files to the view, as well as all the + * stream customization information. + * + * The view for this action contains all the inline javascript needed to + * create the player. + */ public function embedCodeAction() { $this->view->layout()->disableLayout(); + $CC_CONFIG = Config::getConfig(); + $request = $this->getRequest(); - $this->view->css = Application_Common_HTTPHelper::getStationUrl() . "css/embeddable-player.css"; - $this->view->mrp_js = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/embeddableplayer/mrp.js"; + $this->view->css = Application_Common_HTTPHelper::getStationUrl() . "css/embeddable-player.css?".$CC_CONFIG['airtime_version']; + $this->view->mrp_js = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/embeddableplayer/mrp.js?".$CC_CONFIG['airtime_version']; $this->view->jquery = Application_Common_HTTPHelper::getStationUrl() . "js/libs/jquery-1.10.2.js"; $this->view->muses_swf = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/embeddableplayer/muses.swf"; $this->view->metadata_api_url = Application_Common_HTTPHelper::getStationUrl() . "api/live-info"; - $this->view->station_name = Application_Model_Preference::GetStationName(); + $this->view->station_name = addslashes(Application_Model_Preference::GetStationName()); + $stream = $request->getParam('stream'); $streamData = Application_Model_StreamSetting::getEnabledStreamData(); $availableMobileStreams = array(); diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/EmbeddablePlayer.php index e5086716a..ca8ca45c9 100644 --- a/airtime_mvc/application/forms/EmbeddablePlayer.php +++ b/airtime_mvc/application/forms/EmbeddablePlayer.php @@ -1,5 +1,7 @@ 'form/embeddableplayer.phtml')) )); + /* We will use this option in the future $displayTrackMetadata = new Zend_Form_Element_Checkbox('player_display_track_metadata'); $displayTrackMetadata->setValue(true); $displayTrackMetadata->setLabel(_('Display track metadata?')); $this->addElement($displayTrackMetadata); + */ $streamMode = new Zend_Form_Element_Radio('player_stream_mode'); $streamMode->setLabel(_('Select Stream:')); $streamMode->setMultiOptions( array( - "auto" => "Auto detect the most appropriate stream to use.", - "manual" => "Select a stream:" + "auto" => _("Auto detect the most appropriate stream to use."), + "manual" => _("Select a stream:") ) ); $streamMode->setValue("auto"); @@ -30,19 +34,20 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm foreach(Application_Model_StreamSetting::getEnabledStreamData() as $stream => $data) { $urlOptions[$stream] = strtoupper($data["codec"])." - ".$data["bitrate"]."kbps"; if ($data["mobile"]) { - $urlOptions[$stream] .= " - Mobile friendly"; + $urlOptions[$stream] .= _(" - Mobile friendly"); } - if ($data["codec"] == "opus") { + if ($data["codec"] == OPUS) { $opusStreamCount += 1; - $urlOptions[$stream] .=" - The player does not support Opus streams."; + $urlOptions[$stream] .= _(" - The player does not support Opus streams."); } } $streamURL->setMultiOptions( $urlOptions ); + // Set default value to the first non-opus stream we find foreach ($urlOptions as $o => $v) { - if (strpos(strtolower($v), "opus") !== false) { + if (strpos(strtolower($v), OPUS) !== false) { continue; } else { $streamURL->setValue($o); @@ -62,7 +67,7 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm $this->addElement($embedSrc); $previewLabel = new Zend_Form_Element_Text('player_preview_label'); - $previewLabel->setLabel("Preview:"); + $previewLabel->setLabel(_("Preview:")); $this->addElement($previewLabel); } diff --git a/airtime_mvc/application/models/StreamSetting.php b/airtime_mvc/application/models/StreamSetting.php index c51995d6d..688ddc397 100644 --- a/airtime_mvc/application/models/StreamSetting.php +++ b/airtime_mvc/application/models/StreamSetting.php @@ -65,22 +65,6 @@ class Application_Model_StreamSetting return $result ? $result : $default; } - public static function getEnabledStreamUrls() - { - $urls = Array(); - $streamIds = Application_Model_StreamSetting::getEnabledStreamIds(); - foreach ($streamIds as $id) { - $prefix = $id."_"; - $streamData = Application_Model_StreamSetting::getStreamData($id); - $host = $streamData[$prefix."host"]; - $port = $streamData[$prefix."port"]; - $mount = $streamData[$prefix."mount"]; - $type = $streamData[$prefix."type"]; - $urls[$type] = "http://$host:$port/$mount"; - } - return $urls; - } - public static function getEnabledStreamData() { $streams = Array(); diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml index 66117609a..f079a4564 100644 --- a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml +++ b/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml @@ -7,6 +7,17 @@ + @@ -219,7 +259,8 @@ - + + -->
    @@ -240,7 +282,6 @@
    Powered by Airtime Pro -
    From 23bf866211187ac341eb6fbe2e44945b3614594f Mon Sep 17 00:00:00 2001 From: drigato Date: Wed, 8 Apr 2015 14:01:57 -0400 Subject: [PATCH 46/60] SAAS-712: UI Improvements --- airtime_mvc/application/configs/ACL.php | 4 +- .../application/configs/navigation.php | 7 ++-- ...yerController.php => PlayerController.php} | 20 +++++----- .../{EmbeddablePlayer.php => Player.php} | 10 ++--- .../{embeddableplayer.phtml => player.phtml} | 27 +++++++++----- .../index.phtml => player/customize.phtml} | 4 +- .../embed-code.phtml => player/index.phtml} | 0 .../public/css/embeddable-player-form.css | 16 -------- airtime_mvc/public/css/player-form.css | 35 ++++++++++++++++++ .../css/{embeddable-player.css => player.css} | 0 .../{embeddableplayer => player}/mrp.js | 0 .../{embeddableplayer => player}/muses.swf | Bin .../embeddableplayer.js => player/player.js} | 8 +++- 13 files changed, 81 insertions(+), 50 deletions(-) rename airtime_mvc/application/controllers/{EmbeddableplayerController.php => PlayerController.php} (82%) rename airtime_mvc/application/forms/{EmbeddablePlayer.php => Player.php} (86%) rename airtime_mvc/application/views/scripts/form/{embeddableplayer.phtml => player.phtml} (55%) rename airtime_mvc/application/views/scripts/{embeddableplayer/index.phtml => player/customize.phtml} (84%) rename airtime_mvc/application/views/scripts/{embeddableplayer/embed-code.phtml => player/index.phtml} (100%) delete mode 100644 airtime_mvc/public/css/embeddable-player-form.css create mode 100644 airtime_mvc/public/css/player-form.css rename airtime_mvc/public/css/{embeddable-player.css => player.css} (100%) rename airtime_mvc/public/js/airtime/{embeddableplayer => player}/mrp.js (100%) rename airtime_mvc/public/js/airtime/{embeddableplayer => player}/muses.swf (100%) rename airtime_mvc/public/js/airtime/{embeddableplayer/embeddableplayer.js => player/player.js} (89%) diff --git a/airtime_mvc/application/configs/ACL.php b/airtime_mvc/application/configs/ACL.php index 1386d1dee..c58986f1e 100644 --- a/airtime_mvc/application/configs/ACL.php +++ b/airtime_mvc/application/configs/ACL.php @@ -38,7 +38,7 @@ $ccAcl->add(new Zend_Acl_Resource('library')) ->add(new Zend_Acl_Resource('billing')) ->add(new Zend_Acl_Resource('thank-you')) ->add(new Zend_Acl_Resource('provisioning')) - ->add(new Zend_Acl_Resource('embeddableplayer')); + ->add(new Zend_Acl_Resource('player')); /** Creating permissions */ $ccAcl->allow('G', 'index') @@ -71,7 +71,7 @@ $ccAcl->allow('G', 'index') ->allow('A', 'user') ->allow('A', 'systemstatus') ->allow('A', 'preference') - ->allow('A', 'embeddableplayer') + ->allow('A', 'player') ->allow('S', 'thank-you') ->allow('S', 'billing'); diff --git a/airtime_mvc/application/configs/navigation.php b/airtime_mvc/application/configs/navigation.php index 01c8aa385..1aeab45d5 100644 --- a/airtime_mvc/application/configs/navigation.php +++ b/airtime_mvc/application/configs/navigation.php @@ -87,11 +87,10 @@ $pages = array( 'resource' => 'listenerstat' ), array( - 'label' => _('Embeddable Player'), + 'label' => _('Player'), 'module' => 'default', - 'controller' => 'embeddableplayer', - 'action' => 'index', - 'resource' => 'embeddableplayer' + 'controller' => 'player', + 'action' => 'customize' ) ) ), diff --git a/airtime_mvc/application/controllers/EmbeddableplayerController.php b/airtime_mvc/application/controllers/PlayerController.php similarity index 82% rename from airtime_mvc/application/controllers/EmbeddableplayerController.php rename to airtime_mvc/application/controllers/PlayerController.php index 43e8be2d5..2775d1c55 100644 --- a/airtime_mvc/application/controllers/EmbeddableplayerController.php +++ b/airtime_mvc/application/controllers/PlayerController.php @@ -1,21 +1,20 @@ view->headLink()->appendStylesheet($baseUrl.'css/embeddable-player-form.css?'.$CC_CONFIG['airtime_version']); - $this->view->headScript()->appendFile($baseUrl.'js/airtime/embeddableplayer/mrp.js?'.$CC_CONFIG['airtime_version']); - $this->view->headScript()->appendFile($baseUrl.'js/airtime/embeddableplayer/embeddableplayer.js?'.$CC_CONFIG['airtime_version']); + $this->view->headLink()->appendStylesheet($baseUrl.'css/player-form.css?'.$CC_CONFIG['airtime_version']); + $this->view->headScript()->appendFile($baseUrl.'js/airtime/player/player.js?'.$CC_CONFIG['airtime_version']); - $form = new Application_Form_EmbeddablePlayer(); + $form = new Application_Form_Player(); $apiEnabled = Application_Model_Preference::GetAllow3rdPartyApi(); $numEnabledStreams = $form->getElement('player_stream_url')->getAttrib('numberOfEnabledStreams'); @@ -38,18 +37,19 @@ class EmbeddablePlayerController extends Zend_Controller_Action * The view for this action contains all the inline javascript needed to * create the player. */ - public function embedCodeAction() + public function indexAction() { $this->view->layout()->disableLayout(); $CC_CONFIG = Config::getConfig(); + $request = $this->getRequest(); - $this->view->css = Application_Common_HTTPHelper::getStationUrl() . "css/embeddable-player.css?".$CC_CONFIG['airtime_version']; - $this->view->mrp_js = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/embeddableplayer/mrp.js?".$CC_CONFIG['airtime_version']; + $this->view->css = Application_Common_HTTPHelper::getStationUrl() . "css/player.css?".$CC_CONFIG['airtime_version']; + $this->view->mrp_js = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/player/mrp.js?".$CC_CONFIG['airtime_version']; $this->view->jquery = Application_Common_HTTPHelper::getStationUrl() . "js/libs/jquery-1.10.2.js"; - $this->view->muses_swf = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/embeddableplayer/muses.swf"; + $this->view->muses_swf = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/player/muses.swf"; $this->view->metadata_api_url = Application_Common_HTTPHelper::getStationUrl() . "api/live-info"; $this->view->station_name = addslashes(Application_Model_Preference::GetStationName()); diff --git a/airtime_mvc/application/forms/EmbeddablePlayer.php b/airtime_mvc/application/forms/Player.php similarity index 86% rename from airtime_mvc/application/forms/EmbeddablePlayer.php rename to airtime_mvc/application/forms/Player.php index ca8ca45c9..4cad32e53 100644 --- a/airtime_mvc/application/forms/EmbeddablePlayer.php +++ b/airtime_mvc/application/forms/Player.php @@ -2,12 +2,12 @@ define("OPUS", "opus"); -class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm +class Application_Form_Player extends Zend_Form_SubForm { public function init() { $this->setDecorators(array( - array('ViewScript', array('viewScript' => 'form/embeddableplayer.phtml')) + array('ViewScript', array('viewScript' => 'form/player.phtml')) )); /* We will use this option in the future @@ -56,14 +56,14 @@ class Application_Form_EmbeddablePlayer extends Zend_Form_SubForm } $streamURL->setAttrib('numberOfEnabledStreams', sizeof($urlOptions)-$opusStreamCount); - $streamURL->setAttrib("disabled", "disabled"); + $streamURL->removeDecorator('label'); $this->addElement($streamURL); $embedSrc = new Zend_Form_Element_Text('player_embed_src'); $embedSrc->setAttrib("readonly", "readonly"); $embedSrc->setAttrib("class", "embed-player-text-box"); - $embedSrc->setValue(''); - $embedSrc->removeDecorator('label'); + $embedSrc->setLabel(_("Embeddable code:")); + $embedSrc->setValue(''); $this->addElement($embedSrc); $previewLabel = new Zend_Form_Element_Text('player_preview_label'); diff --git a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml b/airtime_mvc/application/views/scripts/form/player.phtml similarity index 55% rename from airtime_mvc/application/views/scripts/form/embeddableplayer.phtml rename to airtime_mvc/application/views/scripts/form/player.phtml index 18305c20b..c47deaccf 100644 --- a/airtime_mvc/application/views/scripts/form/embeddableplayer.phtml +++ b/airtime_mvc/application/views/scripts/form/player.phtml @@ -1,18 +1,27 @@
    - element->getElement('player_embed_src'); ?> - - element->getElement('player_stream_mode'); ?> - - element->getElement('player_stream_url'); ?> - - element->getElement('player_display_track_metadata'); ?> - element->getElement('player_preview_label')->renderLabel(); ?>
    - element->getElement('player_embed_src')->getValue(); ?> +
    + element->getElement('player_embed_src')->getValue(); ?> +
    + +
    + Customize the player by configuring the options below. Once you are happy with the player + copy the embeddable code below into your websites HTML. +
    + + element->getElement('player_stream_mode')->render(); ?> + + element->getElement('player_stream_url'); ?> + + element->getElement('player_embed_src')->render(); ?> + + element->getElement('player_display_track_metadata'); ?> + +
    \ No newline at end of file diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml b/airtime_mvc/application/views/scripts/player/customize.phtml similarity index 84% rename from airtime_mvc/application/views/scripts/embeddableplayer/index.phtml rename to airtime_mvc/application/views/scripts/player/customize.phtml index e4c37849b..56c70f8a4 100644 --- a/airtime_mvc/application/views/scripts/embeddableplayer/index.phtml +++ b/airtime_mvc/application/views/scripts/player/customize.phtml @@ -1,9 +1,9 @@
    -

    + - +

    errorMsg; ?> form; ?> diff --git a/airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml b/airtime_mvc/application/views/scripts/player/index.phtml similarity index 100% rename from airtime_mvc/application/views/scripts/embeddableplayer/embed-code.phtml rename to airtime_mvc/application/views/scripts/player/index.phtml diff --git a/airtime_mvc/public/css/embeddable-player-form.css b/airtime_mvc/public/css/embeddable-player-form.css deleted file mode 100644 index 9a6fe20d8..000000000 --- a/airtime_mvc/public/css/embeddable-player-form.css +++ /dev/null @@ -1,16 +0,0 @@ -.embed-player-text-box { - padding-right: 0px !important; - width: 100% !important; -} -.embed-player-form { - width: 70%; -} -.embed-player-form dd { - width: 100% !important; - float: left; - margin: 0; - padding: 4px 0px 4px 0px; -} - - - diff --git a/airtime_mvc/public/css/player-form.css b/airtime_mvc/public/css/player-form.css new file mode 100644 index 000000000..663a304cf --- /dev/null +++ b/airtime_mvc/public/css/player-form.css @@ -0,0 +1,35 @@ +.embed-player-text-box { + padding-right: 0px !important; + width: 100% !important; +} +.embed-player-form { + width: 98%; +} +.embed-player-form dd { + width: 100% !important; + float: left; + margin: 0; + padding: 4px 0px 4px 0px; +} +.player-preview { + width: 100%; +} +.player-preview iframe { + margin: 0 auto; + display: block; +} +#player_form { + width: 50%; + margin: 0 auto; +} +#player_instructions { + border-bottom: 1px solid; + padding-bottom: 10px; + font-size: 14px; + font-weight: bold; + color: #5b5b5b; + margin-bottom: 10px; +} + + + diff --git a/airtime_mvc/public/css/embeddable-player.css b/airtime_mvc/public/css/player.css similarity index 100% rename from airtime_mvc/public/css/embeddable-player.css rename to airtime_mvc/public/css/player.css diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/mrp.js b/airtime_mvc/public/js/airtime/player/mrp.js similarity index 100% rename from airtime_mvc/public/js/airtime/embeddableplayer/mrp.js rename to airtime_mvc/public/js/airtime/player/mrp.js diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/muses.swf b/airtime_mvc/public/js/airtime/player/muses.swf similarity index 100% rename from airtime_mvc/public/js/airtime/embeddableplayer/muses.swf rename to airtime_mvc/public/js/airtime/player/muses.swf diff --git a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js b/airtime_mvc/public/js/airtime/player/player.js similarity index 89% rename from airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js rename to airtime_mvc/public/js/airtime/player/player.js index be4bbc7c3..ea5fb5588 100644 --- a/airtime_mvc/public/js/airtime/embeddableplayer/embeddableplayer.js +++ b/airtime_mvc/public/js/airtime/player/player.js @@ -29,12 +29,16 @@ function getStreamMode() { $(document).ready(function() { + $("#player_stream_url-element").hide(); + $("#player_stream_mode-element").change(function() { var $streamMode = getStreamMode(); + if ($streamMode == "auto") { - $("#player_stream_url-element input[type='radio']").attr("disabled", "disabled"); + $("#player_stream_url-element").hide(); + } else if ($streamMode == "manual") { - $("#player_stream_url-element input[type='radio']").removeAttr("disabled"); + $("#player_stream_url-element").show(); $("input[name=player_stream_url]").each(function(i, obj) { if ($(this).parent().text().toLowerCase().indexOf("opus") >= 0) { From 94a7643ebc62082034abfd6d35e19b4cda140e0f Mon Sep 17 00:00:00 2001 From: drigato Date: Wed, 8 Apr 2015 15:00:02 -0400 Subject: [PATCH 47/60] Escape stream urls in the player js --- .../application/views/scripts/player/index.phtml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/airtime_mvc/application/views/scripts/player/index.phtml b/airtime_mvc/application/views/scripts/player/index.phtml index f079a4564..3f198e642 100644 --- a/airtime_mvc/application/views/scripts/player/index.phtml +++ b/airtime_mvc/application/views/scripts/player/index.phtml @@ -35,20 +35,21 @@ }; if (this.playerMode == "manual") { - this.settings.url = "streamURL ?>"; + this.settings.url = htmlEscape("streamURL ?>"); this.settings.codec = "codec ?>"; } else if (this.playerMode == "auto") { this.availableMobileStreamQueue = availableMobileStreams?>; this.availableDesktopStreamQueue = availableDesktopStreams?>; var stream = this.getNextAvailableStream(); - this.settings.url = stream["url"]; + this.settings.url = htmlEscape(stream["url"]); this.settings.codec = stream["codec"]; } // Create the Muses player object MRP.insert(this.settings); - $("p.station_name").html(htmlEscape("station_name?>")); + var station_name = htmlEscape("station_name?>"); + $("p.station_name").html(station_name); attachStreamMetadataToPlayer(); @@ -132,7 +133,6 @@ }; MusesPlayer.prototype.setURL = function(url) { - console.log("setURL"); MRP.setUrl(url); }; @@ -143,7 +143,7 @@ // connection limit reached or problem connecting to stream if (value === "0") { var stream = musesPlayer.getNextAvailableStream(); - musesPlayer.setURL(stream["url"]); + musesPlayer.setURL(htmlEscape(stream["url"])); musesPlayer.play(); } } From 78b2631980a7c6569cb41a38db6cad6e1a33ebce Mon Sep 17 00:00:00 2001 From: drigato Date: Wed, 8 Apr 2015 15:19:22 -0400 Subject: [PATCH 48/60] Remove stream url js escaping and do it on server side instead --- .../controllers/PlayerController.php | 4 ++-- .../views/scripts/player/index.phtml | 18 ++++-------------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/airtime_mvc/application/controllers/PlayerController.php b/airtime_mvc/application/controllers/PlayerController.php index 2775d1c55..92501bbd4 100644 --- a/airtime_mvc/application/controllers/PlayerController.php +++ b/airtime_mvc/application/controllers/PlayerController.php @@ -51,7 +51,7 @@ class PlayerController extends Zend_Controller_Action $this->view->jquery = Application_Common_HTTPHelper::getStationUrl() . "js/libs/jquery-1.10.2.js"; $this->view->muses_swf = Application_Common_HTTPHelper::getStationUrl() . "js/airtime/player/muses.swf"; $this->view->metadata_api_url = Application_Common_HTTPHelper::getStationUrl() . "api/live-info"; - $this->view->station_name = addslashes(Application_Model_Preference::GetStationName()); + $this->view->station_name = json_encode(Application_Model_Preference::GetStationName()); $stream = $request->getParam('stream'); $streamData = Application_Model_StreamSetting::getEnabledStreamData(); @@ -70,7 +70,7 @@ class PlayerController extends Zend_Controller_Action } else { $this->view->playerMode = "manual"; $selectedStreamData = $streamData[$stream]; - $this->view->streamURL = $selectedStreamData["url"]; + $this->view->streamURL = json_encode($selectedStreamData["url"]); $this->view->codec = $selectedStreamData["codec"]; } $this->view->availableMobileStreams = json_encode($availableMobileStreams); diff --git a/airtime_mvc/application/views/scripts/player/index.phtml b/airtime_mvc/application/views/scripts/player/index.phtml index 3f198e642..ee19b337c 100644 --- a/airtime_mvc/application/views/scripts/player/index.phtml +++ b/airtime_mvc/application/views/scripts/player/index.phtml @@ -35,21 +35,20 @@ }; if (this.playerMode == "manual") { - this.settings.url = htmlEscape("streamURL ?>"); + this.settings.url = "streamURL ?>"; this.settings.codec = "codec ?>"; } else if (this.playerMode == "auto") { this.availableMobileStreamQueue = availableMobileStreams?>; this.availableDesktopStreamQueue = availableDesktopStreams?>; var stream = this.getNextAvailableStream(); - this.settings.url = htmlEscape(stream["url"]); + this.settings.url = stream["url"]; this.settings.codec = stream["codec"]; } // Create the Muses player object MRP.insert(this.settings); - var station_name = htmlEscape("station_name?>"); - $("p.station_name").html(station_name); + $("p.station_name").html("station_name?>"); attachStreamMetadataToPlayer(); @@ -143,7 +142,7 @@ // connection limit reached or problem connecting to stream if (value === "0") { var stream = musesPlayer.getNextAvailableStream(); - musesPlayer.setURL(htmlEscape(stream["url"])); + musesPlayer.setURL(stream["url"]); musesPlayer.play(); } } @@ -218,15 +217,6 @@ setTimeout(attachStreamMetadataToPlayer, time_to_next_track_starts); } - function htmlEscape(str) { - return String(str) - .replace(/&/g, '&') - .replace(/"/g, '"') - .replace(/'/g, ''') - .replace(//g, '>'); - } -