From 76f541798e65a7a475ff91c865cfe73fa58715d7 Mon Sep 17 00:00:00 2001 From: Matt Sandler Date: Thu, 6 May 2021 10:39:40 -0400 Subject: [PATCH 1/8] Made changes for chromecast --- src/speaker.js | 74 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 26 deletions(-) diff --git a/src/speaker.js b/src/speaker.js index 9c4de0d7..00f1b94f 100644 --- a/src/speaker.js +++ b/src/speaker.js @@ -72,6 +72,8 @@ const IOS = [ // iPad on iOS 13 detection || (navigator.userAgent.includes('Mac') && 'ontouchend' in document); +const CHROMECAST = navigator.userAgent.includes("CrKey"); + const brokenWebkit = IOS && /OS 13_[543210]/i.test(navigator.userAgent); const SILENCE = IOS ? @@ -275,10 +277,14 @@ Speaker.prototype = { log('initialize audio called from', e); } + if (!CHROMECAST){ + this.fading = this._createAudio(SILENCE); + this.preparing = this._createAudio(this.prepareWhenReady ? this.prepareWhenReady : SILENCE); + } + this.audioContext = createAudioContext(); this.active = this._createAudio(SILENCE); - this.fading = this._createAudio(SILENCE); const pwr = this.prepareWhenReady; if (pwr) { @@ -392,7 +398,7 @@ Speaker.prototype = { return; } - if (audio === this.fading.audio) { + if (!CHROMECAST && (audio === this.fading.audio)) { audio.src = SILENCE; this.fading.sound = null; return; @@ -420,7 +426,7 @@ Speaker.prototype = { return; } - if ((audio === this.fading.audio) && this.fading.sound) { + if (!CHROMECAST && audio === this.fading.audio && this.fading.sound) { if (this.fading.sound.endPosition && (audio.currentTime >= (this.fading.sound.endPosition / 1000))) { this.fading.sound = null; this.fading.audio.src = SILENCE; @@ -561,7 +567,14 @@ Speaker.prototype = { this.outstandingSounds[sound.id] = sound; // start loading sound, if we can - //this.prepare(url, optionsAndCallbacks.startPosition); + if (!this.active || !this.active.audio) { + log('no audio prepared yet, so preparing when ready'); + this.prepareWhenReady = sound.url; + + } else if (!CHROMECAST && this.preparing.audio.src === SILENCE) { + log('preparing sound now'); + this._prepare(sound.url, sound.startPosition); + } return sound; }, @@ -665,18 +678,17 @@ Speaker.prototype = { // empty out any pending request this.prepareWhenReady = null; - if (!url) { - return false; - } + if (CHROMECAST){ + log('preparing ' + url); - if (this.preparing && (this.preparing.audio.src === url) && this.preparing.canplaythrough) { - log('play already prepared!'); - // song is already prepared! - return true; - } + if (this.active.audio.playing) { + this.active.audio.pause(); + } - if (this.preparing.audio.src !== url) { - log('preparing', url); + this.active.audio.src = url; + } + else if (this.preparing.audio.src !== url) { + log('preparing ' + url); if (this.preparing.audio.playing) { this.preparing.audio.pause(); @@ -686,7 +698,11 @@ Speaker.prototype = { this.preparing.audio.src = url; } - if (startPosition && (this.preparing.audio.currentTime !== startPosition)) { + if (CHROMECAST && (startPosition && this.active.audio.currentTime !== startPosition)) { + log('advancing preparing audio to', startPosition / 1000); + this.active.audio.currentTime = startPosition / 1000; + } + else if (startPosition && (this.preparing.audio.currentTime !== startPosition)) { log('advancing preparing audio to', startPosition / 1000); this.preparing.audio.currentTime = startPosition / 1000; } @@ -724,7 +740,7 @@ Speaker.prototype = { sound.trigger('finish'); }); - if (this.fading.sound) { + if (!CHROMECAST && this.fading.sound) { this.fading.audio.play() .then(function () { log('resumed fading playback'); @@ -743,7 +759,7 @@ Speaker.prototype = { } } else { - if (this.preparing.audio.src !== sound.url) { + if (!CHROMECAST && this.preparing.audio.src !== sound.url) { // hopefully, by this time, any sound that was destroyed before its // play() call completed has actually completed its play call. Otherwise // this will trigger an exception in the play preparation. @@ -758,8 +774,10 @@ Speaker.prototype = { // swap prepared -> active var active = this.active; - this.active = this.preparing; - this.preparing = active; + if (!CHROMECAST){ + this.active = this.preparing; + this.preparing = active; // don't throw sound object in active until playback starts (below) + } this.preparing.canplaythrough = false; this.preparing.audio.src = SILENCE; @@ -769,7 +787,9 @@ Speaker.prototype = { this._setVolume(this.active, sound); // notify clients that whatever was previously playing has finished - if (this.preparing.sound) { + if (!CHROMECAST && this.preparing.sound) { + this.preparing.audio.src = SILENCE; + var finishedSound = this.preparing.sound; this.preparing.sound = null; finishedSound.trigger('finish'); @@ -857,11 +877,13 @@ Speaker.prototype = { this._setVolume(this.active); // active becomes fading, and fading becomes active - var fading = this.fading; - this.fading = this.active; - this.active = fading; - - this.active.sound = null; // not used any more + if (!CHROMECAST) + { + var fading = this.fading; + this.fading = this.active; + this.active = fading; + this.active.sound = null; + } // not used any more } } else { @@ -897,7 +919,7 @@ Speaker.prototype = { } } - if (this.fading && this.fading.audio) { + if (!CHROMECAST && this.fading && this.fading.audio) { this.fading.audio.pause(); } }, From 82b562cc539201573417751682f0c7f21c54210f Mon Sep 17 00:00:00 2001 From: Matt Sandler Date: Thu, 6 May 2021 12:29:56 -0400 Subject: [PATCH 2/8] fixed an issue with audio being set --- src/speaker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/speaker.js b/src/speaker.js index 00f1b94f..84e3e8e5 100644 --- a/src/speaker.js +++ b/src/speaker.js @@ -571,7 +571,7 @@ Speaker.prototype = { log('no audio prepared yet, so preparing when ready'); this.prepareWhenReady = sound.url; - } else if (!CHROMECAST && this.preparing.audio.src === SILENCE) { + } else if (CHROMECAST || this.preparing.audio.src === SILENCE) { log('preparing sound now'); this._prepare(sound.url, sound.startPosition); } From f6a48d4f17cfca43bcd5bd22b364366f6652a65d Mon Sep 17 00:00:00 2001 From: Matt Sandler Date: Tue, 25 May 2021 21:51:01 -0400 Subject: [PATCH 3/8] made some adjustments to allow for pausing --- src/player.js | 1 + src/speaker.js | 47 ++++++++++++++++++++++++++++++++++------------- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/src/player.js b/src/player.js index 8fd11456..a08865b0 100644 --- a/src/player.js +++ b/src/player.js @@ -484,6 +484,7 @@ Player.prototype._onSoundPause = function (playId) { }; Player.prototype._onSoundFinish = function (playId, withError) { + if (!this.state.activePlay || (this.state.activePlay.id !== playId)) { log('received sound finish, but active play does not match', this.state.activePlay, playId); return; diff --git a/src/speaker.js b/src/speaker.js index 84e3e8e5..a000be0f 100644 --- a/src/speaker.js +++ b/src/speaker.js @@ -72,7 +72,7 @@ const IOS = [ // iPad on iOS 13 detection || (navigator.userAgent.includes('Mac') && 'ontouchend' in document); -const CHROMECAST = navigator.userAgent.includes("CrKey"); +const CHROMECAST = navigator.userAgent.includes('CrKey'); const brokenWebkit = IOS && /OS 13_[543210]/i.test(navigator.userAgent); @@ -83,6 +83,8 @@ const SILENCE = IOS ? //const SILENCE = 'https://dgase5ckewowv.cloudfront.net/feedfm-audio/1573592316-88123.m4a'; var Sound = function (speaker, options, id, url) { + + var obj = Object.assign(this, Events); obj.id = id; @@ -93,6 +95,9 @@ var Sound = function (speaker, options, id, url) { obj.speaker = speaker; obj.loaded = false; + obj.savedSrc = ''; + obj.savedPos = 0; + if (options) { this.startPosition = +options.startPosition; this.endPosition = +options.endPosition; @@ -146,7 +151,10 @@ Sound.prototype = { // pause playback of the current sound clip pause: function () { log('sound ' + this.id + ' pause'); + return this.speaker._pauseSound(this); + + }, // resume playback of the current sound clip @@ -459,10 +467,9 @@ Speaker.prototype = { this.active.sound = null; this.active.audio.src = SILENCE; - sound.trigger('finish'); - } else if (this.active.sound.fadeOutEnd && (audio.currentTime >= this.active.sound.fadeOutStart)) { + } else if (!CHROMECAST && this.active.sound.fadeOutEnd && (audio.currentTime >= this.active.sound.fadeOutStart)) { // song hit start of fade out this._setVolume(this.active); @@ -470,7 +477,6 @@ Speaker.prototype = { var fading = this.fading; this.fading = this.active; this.active = fading; - this.active.sound = null; // not used any more // pretend the song finished @@ -598,8 +604,8 @@ Speaker.prototype = { } var ranges = this.active.audio.buffered; - if ((ranges.length > 0) && (ranges.end(ranges.length - 1) >= this.active.audio.duration)) { - log('active song has loaded enough, so preparing', url); + if (!CHROMECAST && (ranges.length > 0) && (ranges.end(ranges.length - 1) >= this.active.audio.duration)) { + log('active song has loaded enough, to preparing', url); return this._prepare(url, startPosition); } else if (this.active.audio.src === SILENCE) { @@ -724,9 +730,13 @@ Speaker.prototype = { } if (this.active.sound === sound) { - if (this.active.audio.paused) { + if (this.active.audio.paused || this.active.audio.src === 'not-a-real-file' ) { log(sound.id + ' was paused, so resuming'); - + if (CHROMECAST) + { + this.active.audio.currentTime = sound.savedPos; + this.active.audio.src = sound.savedSrc; + } // resume playback this.active.audio.play() .then(function () { @@ -879,10 +889,10 @@ Speaker.prototype = { // active becomes fading, and fading becomes active if (!CHROMECAST) { - var fading = this.fading; - this.fading = this.active; - this.active = fading; - this.active.sound = null; + var fading = this.fading; + this.fading = this.active; + this.active = fading; + this.active.sound = null; } // not used any more } @@ -910,7 +920,18 @@ Speaker.prototype = { _pauseSound: function (sound) { if (this.active && (sound.url === this.active.audio.src)) { if (this.active.sound === sound) { - this.active.audio.pause(); + if (CHROMECAST) + { + sound.savedPos = this.active.audio.currentTime; + sound.savedSrc =this.active.audio.src; + this.active.audio.src = 'not-a-real-file'; + } + else + { + this.active.audio.pause(); + } + + // } else { // if active.sound isn't assigned, then the song is still being loaded. // if we try to pause() right now, it will cause the play() to throw an From 83427488067059e80c6aaa25f97a42d7cb5aafa4 Mon Sep 17 00:00:00 2001 From: Matt Sandler Date: Thu, 8 Jul 2021 14:30:16 -0400 Subject: [PATCH 4/8] hopefully this change was meant to be put in --- src/speaker.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/speaker.js b/src/speaker.js index a000be0f..4ca485d0 100644 --- a/src/speaker.js +++ b/src/speaker.js @@ -730,7 +730,7 @@ Speaker.prototype = { } if (this.active.sound === sound) { - if (this.active.audio.paused || this.active.audio.src === 'not-a-real-file' ) { + if (this.active.audio.paused || this.active.audio.src === 'not-a-real-file-paused' ) { log(sound.id + ' was paused, so resuming'); if (CHROMECAST) { @@ -924,7 +924,7 @@ Speaker.prototype = { { sound.savedPos = this.active.audio.currentTime; sound.savedSrc =this.active.audio.src; - this.active.audio.src = 'not-a-real-file'; + this.active.audio.src = 'not-a-real-file-paused'; } else { From bc79437308065829386900aa91ff5932177fe248 Mon Sep 17 00:00:00 2001 From: Matt Sandler Date: Wed, 8 Sep 2021 07:52:22 -0400 Subject: [PATCH 5/8] bringing chromecastbranch up to date --- dist/feed-media-audio-player.min.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dist/feed-media-audio-player.min.js b/dist/feed-media-audio-player.min.js index 7b54b036..e1d1ba74 100644 --- a/dist/feed-media-audio-player.min.js +++ b/dist/feed-media-audio-player.min.js @@ -1 +1 @@ -var Feed=function(){"use strict";function t(t,e){return Object.prototype.hasOwnProperty.call(t,e)}function e(t){var e=t.charAt(t.length-1),i=parseInt(t,10),n=new Date;switch(e){case"Y":n.setFullYear(n.getFullYear()+i);break;case"M":n.setMonth(n.getMonth()+i);break;case"D":n.setDate(n.getDate()+i);break;case"h":n.setHours(n.getHours()+i);break;case"m":n.setMinutes(n.getMinutes()+i);break;case"s":n.setSeconds(n.getSeconds()+i);break;default:n=new Date(t)}return n}function i(){return(i=Object.assign||function(t){for(var e=1;e500&&t.history.shift()};r.history=[],r.enable=function(){o=!0},r.reset=function(){var t=r.history;return r.history=[],t};var u=0;function l(t){return t+ ++u}var c=Array.prototype.indexOf;function d(t,e,i,n){"function"==typeof e&&(n=i,i=e,e=!1);var s=i?t.map(i,n):t,a=[],o=[];return s.forEach((function(i,n){var s,r;(e?n&&o[o.length-1]===i:(r=i,null!==(s=o)&&(c&&s.indexOf===c?-1!=s.indexOf(r):s.some((function(t){return t===r})))))||(o.push(i),a.push(t[n]))})),a}function h(t,e){var i=e.map((function(t){return new RegExp(t)}));return d(t).filter((function(t){return i.find((function(e){return e.test(t)}))}))}function p(t,e,i){(t=t?2*t:200)>e&&(t=e),setTimeout((function(){i(t)}),t)}var f="https://feed.fm";function y(){return f}function g(t){f=function(t,e){return"//"===t.slice(0,2)&&(t=!0===e?"https:"+t:!1===e?"http:"+t:"http"===window.location.protocol.substr(0,4)?window.location.protocol+t:"http"),t}(t)}var v,m="undefined"==typeof document,_=null;function P(){return m?_:n("cid")}function S(t){m?_=t:s("cid",t,{expires:3650,path:"/"})}function b(){if(!v)var t=v=new Promise((function(e){!function t(e,i){var n=P();if(n)return e(n);fetch(y()+"/api/v2/client",{method:"POST"}).then((function(t){return t.json()})).then((function(n){n.success?e(n.client_id):p(i,2e3,(function(i){t(e,i)}))})).catch((function(n){if(403===n.status)try{var s=JSON.parse(n.responseText);r("error trying to get client id:",s)}catch(t){r("unknown response for client id request",t.message)}else r("unknown client id response status",n.status);p(i,2e3,(function(i){t(e,i)}))}))}((function(i){v===t?(S(i),e(i)):v?v.then((function(t){e(t)})):b().then((function(t){e(t)}))}))}));return v}var k=P,T=S;function A(t){return(A="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function w(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function O(t,e){for(var i=0;it.length)&&(e=t.length);for(var i=0,n=new Array(e);i=t.length?{done:!0}:{done:!1,value:t[e++]}},e:function(t){throw t},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var n,s,a=!0,o=!1;return{s:function(){n=t[Symbol.iterator]()},n:function(){var t=n.next();return a=t.done,t},e:function(t){o=!0,s=t},f:function(){try{a||null==n.return||n.return()}finally{if(o)throw s}}}}for(var L=Array.prototype.slice,q={on:function(t,e,i){return R(this,"on",t,[e,i])&&e?(this._events||(this._events={}),(this._events[t]||(this._events[t]=[])).push({callback:e,context:i,ctx:i||this}),this):this},once:function(t,e,i){if(!R(this,"once",t,[e,i])||!e)return this;var n,s,a,o=this,r=(n=function(){o.off(t,r),e.apply(this,arguments)},a=!1,function(){return a||(a=!0,s=n.apply(this,arguments),n=null),s});return r._callback=e,this.on(t,r,i)},off:function(t,e,i){var n,s,a,o,r,u,l,c;if(!this._events||!R(this,"off",t,[e,i]))return this;if(!t&&!e&&!i)return this._events={},this;for(r=0,u=(o=t?[t]:Object.keys(this._events)).length;r20&&i.play.duration_in_seconds-i.seconds_since_start>20&&(n=15e3)}}else if(i.error&&19===i.error.code)return e._state="music-unavailable",void e.trigger("music-unavailable");e._timeout=setTimeout((function(){e.onTimeout(t)}),n)})).catch((function(i){if(403===i.status)try{var n=JSON.parse(i.responseText);if(n.error&&19===n.error.code){try{e._state="music-unavailable",e.trigger("music-unavailable")}catch(t){}return}console.log("unexpected error:",n)}catch(t){console.log("bad response",t.message)}else console.log("odd response",i);e._timeout=setTimeout((function(){e.onTimeout(t)}),15e3)}))}},{key:"getCurrentState",value:function(){return this._state}},{key:"getCurrentPlay",value:function(){return this._activePlay}}]),t}();function $(){try{return"localStorage"in window&&null!==window.localStorage}catch(t){return!1}}function F(t,e){$()&&localStorage.setItem(t,e)}function H(t){$()&&localStorage.removeItem(t)}function J(t){return $()?localStorage.getItem(t):null}function W(t){var e=J("feedfm:active");if(e){var i=JSON.parse(e);if(i.timestamp+t>Date.now()){var n=parseFloat(J("feedfm:elapsed_time"),10);return[i.state,n]}}return[]}var K=function(t,e,i){Object.assign(this,q),t&&e&&((i=i||{}).baseUrl&&g(i.baseUrl),this.config={remoteLogging:!!i.remoteLogging,formats:"mp3,aac",maxBitrate:128,timeOffset:0,current:null,pendingRequest:null,pendingPlay:null},t&&e&&this.setCredentials(t,e),i.remoteLogging&&(r("remote logging enabled",this.config),this._submitLogHistory()))};K.prototype.setCredentials=function(t,e){this.config.token=t,this.config.secret=e},K.prototype.setStationId=function(t,e,i){if(this.config.stations){var n=""+t,s=""+this.config.stationId!==n;if(s||e){var a=this.config.stations.find((function(t){return""+t.id===n}));a&&(this.config.stationId=t,this.config.station=a,s&&this.trigger("station-changed",t,a),this.config.pendingRequest=null,this.config.pendingPlay=null,this._assignCurrentPlay(null,!0),this._requestNextPlay(0,e,i))}}},K.prototype.setFormats=function(t){this.config.formats=t,this.isTuned()&&this.tune()},K.prototype.setMaxBitrate=function(t){this.config.maxBitrate=t},K.prototype.tune=function(){if(!this.config.token)throw new Error("no token set with setCredentials()");if(!this.config.secret)throw new Error("no secret set with setCredentials()");this.config.pendingRequest=null,this.config.pendingPlay=null,this._assignCurrentPlay(null,!0),this._getDefaultPlacementInformation()},K.prototype._getDefaultPlacementInformation=function(t){var e=this;this.config.placementId&&this.config.placement&&this.config.placement.id===this.config.placementId?this._requestNextPlay():(r("requesting default placement information from server"),e._signedAjax(y()+"/api/v2/session",{method:"POST",body:JSON.stringify({client_id:k()}),headers:{"Content-Type":"application/json"}}).then((function(t){return t.json()})).then((function(t){return t.session&&t.session.client_id&&T(t.session.client_id),e._getClientId().then((function(){return t}))})).then(e._receiveDefaultPlacementInformation.bind(e)).catch(e._failedDefaultPlacementInformation.bind(e,t)))},K.prototype._receiveDefaultPlacementInformation=function(t){t&&t.success&&t.placement?(this.config.placement=t.placement,this.config.stations=t.stations,this.config.placementId=t.placement.id,this.trigger("placement",this.config.placement),this.config.stations.length>0&&(this.config.stationId=this.config.stations[0].id,this.config.station=this.config.stations[0],this.trigger("station-changed",this.config.stationId,this.config.station)),this.trigger("stations",this.config.stations),this._requestNextPlay()):this.trigger("music-unavailable")},K.prototype._failedDefaultPlacementInformation=function(t,e){var i=this;if(401===e.status)try{var n=JSON.parse(e.responseText);if(n.error&&5===n.error.code)return void this.trigger("invalid-credentials")}catch(t){}else console.warn("error from placement request",e);t=t?2*t:500,setTimeout((function(){i._getDefaultPlacementInformation(t)}),t)},K.prototype.getActivePlacement=function(){return this.config.placement?this.config.placement:null},K.prototype.getActivePlay=function(){return this.config.current?this.config.current.play:null},K.prototype.isTuned=function(){return this.config.current||this.config.pendingRequest},K.prototype.hasActivePlayStarted=function(){return this.config.current&&this.config.current.started},K.prototype.reportPlayStarted=function(){if(!this.config.current)throw new Error("attempt to report a play started, but there is no active play");this._startPlay(this.config.current.play)},K.prototype.reportPlayElapsed=function(t){if(!this.config.current)throw new Error("attempt to report elapsed play time, but the play hasn't started");this._signedAjax(y()+"/api/v2/play/"+this.config.current.play.id+"/elapse",{method:"POST",body:JSON.stringify({seconds:t}),headers:{"Content-Type":"application/json"}})},K.prototype.reportPlayCompleted=function(){if(!this.config.current||!this.config.current.started)throw r("finish on non-active or playing song"),new Error("no active or playing song");this._signedAjax(y()+"/api/v2/play/"+this.config.current.play.id+"/complete",{method:"POST"}).finally(this._receivePlayCompleted.bind(this))},K.prototype._receivePlayCompleted=function(){if(this.config.pendingRequest)r("song finished, but we're still waiting for next one to return"),this._assignCurrentPlay(null,!0);else{r("song finished, and no outstanding request, so playing pendingPlay");var t=this.config.pendingPlay;this.config.pendingPlay=null,this._assignCurrentPlay(t)}},K.prototype.reportPlayStopped=function(t){this.config.current&&this.config.current.started&&this._signedAjax(y()+"/api/v2/play/"+this.config.current.play.id+"/elapse",{method:"POST",body:JSON.stringify({seconds:t}),headers:{"Content-Type":"application/json"}}),this.config.pendingRequest=null,this.config.pendingPlay=null,this._assignCurrentPlay(null,!0)},K.prototype.requestSkip=function(){var t=this;if(!this.config.current)throw new Error("No song being played");if(!this.config.current.started)throw new Error("No song has been started");this.config.current.canSkip?this._signedAjax(y()+"/api/v2/play/"+this.config.current.play.id+"/skip",{method:"POST"}).then((function(t){return t.json()})).then(this._receiveSkip.bind(this,this.config.current.play)).catch(this._failSkip.bind(this,this.config.current.play)):setTimeout((function(){t.trigger("skip-denied")}),1)},K.prototype.requestInvalidate=function(){if(!this.config.current)throw new Error("No active song to invalidate!");this._sendInvalidate(this.config.current.play)},K.prototype._sendInvalidate=function(t,e){this._signedAjax(y()+"/api/v2/play/"+t.id+"/invalidate",{method:"POST"}).then((function(t){return t.json()})).then(this._receiveInvalidate.bind(this,t)).catch(this._failInvalidate.bind(this,e,t))},K.prototype._failInvalidate=function(t,e,i){var n=this;(t=t?2*t:200)<3e3?setTimeout((function(){n._sendInvalidate(e)}),t):r("gave up trying to invalidate play",i)},K.prototype._receiveInvalidate=function(t,e){var i=this;if(r("invalidate response"),this._submitLogHistory(),setTimeout((function(){r("5 second follow up after invalidate"),i._submitLogHistory()}),5e3),this.config.current&&this.config.current.play===t)if(e.success)if(this.config.pendingPlay){r("invalidating to song already queued up");var n=this.config.pendingPlay;this.config.pendingPlay=null,this._assignCurrentPlay(n)}else r("invalidating current song"),this._assignCurrentPlay(null,!0),this.config.pendingRequest||(r("queueing up new song"),this._requestNextPlay());else r("failed invalidate! - technically this is impossible")},K.prototype._failSkip=function(t){this.config.current&&this.config.current.play===t&&this.trigger("skip-denied")},K.prototype._receiveSkip=function(t,e){if(this.config.current&&this.config.current.play===t){if(!e.success)return r("failed skip!"),void this.trigger("skip-denied");if(this.config.pendingPlay){r("skipping to song already queued up");var i=this.config.pendingPlay;this.config.pendingPlay=null,this._assignCurrentPlay(i)}else this.config.pendingRequest?(r("skipping to what is queued up"),this._assignCurrentPlay(null,!0)):(r("skipping to what is queued up"),this._assignCurrentPlay(null))}},K.prototype._startPlay=function(t){this.config.current.retryCount>2?this._receiveStartPlay(t,{success:!0,can_skip:!0}):(r("telling server we're starting the play",t),this._signedAjax(y()+"/api/v2/play/"+t.id+"/start",{method:"POST"}).then((function(t){return t.json()})).then(this._receiveStartPlay.bind(this,t)).catch(this._failStartPlay.bind(this,t)))},K.prototype._receiveStartPlay=function(t,e){e.success?this.config.current&&this.config.current.play===t?(this.config.current.canSkip=e.can_skip,this.config.current.started=!0,this._requestNextPlay(),this.trigger("play-started",t)):r("received start play, but not waiting any more"):r("received failed start success")},K.prototype._failStartPlay=function(t,e){var i=this,n=this;if(r("start failed",e),this._submitLogHistory(),setTimeout((function(){r("5 second follow up after start failure"),n._submitLogHistory()}),5e3),this.config.current&&this.config.current.play===t){if(403===e.status)try{var s=JSON.parse(e.responseText);if(s.error&&20===s.error.code)return this._receiveStartPlay(t,{success:!0,can_skip:!0})}catch(t){r("unable to parse start play response",t.message)}r("request failed - trying again in 1 second",e),this.config.current.retryCount++,setTimeout((function(){i._startPlay(t)}))}else r("startPlay failed, but we don't care any more")},K.prototype._assignCurrentPlay=function(t,e){if(this.config.current){var i=this.config.current.play;this.config.current=null,this.trigger("play-completed",i)}null===t?e?r("nothing to play... waiting"):(r("nothing to play from the current station"),this.trigger("plays-exhausted")):(this.config.current={play:t,canSkip:!1,started:!1,retryCount:0},r("activated new song"),this.trigger("play-active",t))},K.prototype._requestNextPlay=function(t,e,i){var n=this;n._getClientId().then((function(s){if(n.config.pendingRequest){if(t){if(t>6e4)return r("giving up on retrieving next play"),n.config.pendingRequest=null,void(null===n.config.current&&n._assignCurrentPlay(null));r("retrying pending request"),n.config.pendingRequest.retryCount++;var a=n.config.pendingRequest.ajax;return void n._signedAjax(n.config.pendingRequest.url,a).then((function(t){return t.json()})).then(n._receiveNextPlay.bind(n,a)).catch(n._failedNextPlay.bind(n,t,a))}r("already waiting for a request to finish")}else{var o={formats:n.config.formats,client_id:s,max_bitrate:n.config.maxBitrate,secure:!0};n.config.placementId&&(o.placement_id=n.config.placementId),n.config.stationId&&(o.station_id=n.config.stationId),e&&(o.at=e,i&&(o.crossfade=i));var u={method:"POST",body:JSON.stringify(o),headers:{"Content-Type":"application/json"}};n.config.pendingRequest={url:y()+"/api/v2/play",ajax:u,retryCount:0},r("requesting new play from server",u),n._signedAjax(y()+"/api/v2/play",u).then((function(t){return t.json()})).then(n._receiveNextPlay.bind(n,u)).catch(n._failedNextPlay.bind(n,t,u))}}))},K.prototype._receiveNextPlay=function(t,e){this.config.pendingRequest&&this.config.pendingRequest.ajax===t?(this.config.pendingRequest=null,e.success?(this.trigger("prepare-sound",e.play.audio_file.url,e.play.start_at),this.config.current?(r("received play, but we're already playing, so queueing up",e.play),this.config.pendingPlay=e.play):(r("received play and no current song, making active now",e.play),this._assignCurrentPlay(e.play))):e.error&&9===e.error.code?this.config.current?(r("ran out of music to play, but we're already playing"),this.config.pendingPlay=null):(r("ran out of music, and nothing playing now"),this.trigger("plays-exhausted")):e.error&&6===e.error.code?this.trigger("forbidden",e.error.message):r("unsuccessful response",e)):r("nextPlay succeeded, but we don't care")},K.prototype._failedNextPlay=function(t,e,i){var n=this;if(r("next play failed",i),this._submitLogHistory(),setTimeout((function(){r("5 second follow up after next play failure"),n._submitLogHistory()}),5e3),this.config.pendingRequest&&this.config.pendingRequest.ajax===e){if(403===i.status)try{var s=JSON.parse(i.responseText);if(s.error&&19===s.error.code)return this.trigger("music-unavailable",s.error.message),void this.trigger("not-in-us",s.error.message)}catch(t){r("problem parsing 403 response",t.message)}t=Math.min(t?2*t:500,2e3),r("request failed - trying again after "+t+"ms"),setTimeout((function(){n._requestNextPlay(t)}),t)}else r("nextPlay failed, but we don't care")},K.prototype.maybeCanSkip=function(){return this.config.current&&this.config.current.started&&this.config.current.canSkip},K.prototype.likePlay=function(t){this._signedAjax(y()+"/api/v2/play/"+t+"/like",{method:"POST"}),this.config.current&&this.config.current.play.id===t&&(this.config.current.play.liked=!0)},K.prototype.unlikePlay=function(t){this._signedAjax(y()+"/api/v2/play/"+t+"/like",{method:"DELETE"}),this.config.current&&this.config.current.play.id===t&&delete this.config.current.play.liked},K.prototype.dislikePlay=function(t){this._signedAjax(y()+"/api/v2/play/"+t+"/dislike",{method:"POST"}),this.config.current&&this.config.current.play.id===t&&(this.config.current.play.liked=!1)};K.prototype._getStoredCid=function(){return n("cid")},K.prototype._setStoredCid=function(t){s("cid",t,{expires:3650,path:"/"})},K.prototype._deleteStoredCid=function(){a("cid")},K.prototype._sign=function(t){var e;if(t||(t={}),e="Basic "+btoa(this.config.token+":"+this.config.secret),t.headers?t.headers.Authorization=e:t.headers={Authorization:e},t.headers["X-Feed-SDK"]="1.101.1 js",this.extraHeaders)for(var i in this.extraHeaders)this.extraHeaders.hasOwnProperty(i)&&(t.headers[i]=this.extraHeaders[i]);return t},K.prototype._signedAjax=function(t,e){return this._ajax(t,this._sign(e))},K.prototype._ajax=function(t,e){return fetch(t,e)},K.prototype._submitLogHistory=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,e=this,i=r.history;if(r.history=[],this.config.remoteLogging)return this._signedAjax(y()+"/api/v2/session/event",{method:"POST",body:JSON.stringify({event:"playerHistory",parameters:i}),headers:{"Content-Type":"application/json"}}).catch((function(){t<2&&setTimeout((function(){r.history=i.concat(["failed log report attempt, try #"+t],r.history),e._submitLogHistory(t+1)}),5e3)}))},K.prototype._getClientId=function(){return b()};var Y=["iPad Simulator","iPhone Simulator","iPod Simulator","iPad","iPhone","iPod"].includes(navigator.platform)||navigator.userAgent.includes("Mac")&&"ontouchend"in document,G=Y&&/OS 13_[543210]/i.test(navigator.userAgent),X=Y?"https://u9e9h7z5.map2.ssl.hwcdn.net/feedfm-audio/250-milliseconds-of-silence.mp3":"data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA",Z=function(t,e,i,n){var s=Object.assign(this,q);if(s.id=i,s.url=n,s.speaker=t,s.loaded=!1,e){this.startPosition=+e.startPosition,this.endPosition=+e.endPosition,this.fadeInSeconds=+e.fadeInSeconds,this.fadeInSeconds?(this.fadeInStart=this.startPosition?this.startPosition/1e3:0,this.fadeInEnd=this.fadeInStart+this.fadeInSeconds):(this.fadeInStart=0,this.fadeInEnd=0),this.fadeOutSeconds=+e.fadeOutSeconds,this.fadeOutSeconds&&(this.endPosition?(this.fadeOutStart=this.endPosition/1e3-this.fadeOutSeconds,this.fadeOutEnd=this.endPosition/1e3):(this.fadeOutStart=0,this.fadeOutEnd=0));for(var a=0,o=["play","pause","finish","elapse"];a=this.fading.sound.endPosition/1e3?(this.fading.sound=null,this.fading.audio.src=X):this._setVolume(this.fading);else if(e===this.active.audio&&this.active.sound)if(this.active.sound.url===e.src){if(this.active.sound.endPosition&&this.active.sound.endPosition/1e3<=e.currentTime){var i=this.active.sound;this.active.sound=null,this.active.audio.src=X,i.trigger("finish")}else if(this.active.sound.fadeOutEnd&&e.currentTime>=this.active.sound.fadeOutStart){this._setVolume(this.active);var n=this.fading;this.fading=this.active,this.active=n,this.active.sound=null,this.fading.sound.trigger("finish")}else this._setVolume(this.active),this.active.sound.trigger("elapse");this.prepareWhenReady&&this.prepare(this.prepareWhenReady.url,this.prepareWhenReady.startPosition)}else r("active audio elapsed, but no matching sound, so ignoring",e.src)},_setVolume:function(t,e){e||(e=t.sound);var i=t.audio.currentTime,n=t.volume,s=e.gainAdjustedVolume(this.vol);e.fadeInStart!==e.fadeInEnd&&i=e.fadeInStart&&i<=e.fadeInEnd?(s=(i-e.fadeInStart)/(e.fadeInEnd-e.fadeInStart)*s,r("ramping \u25b2 volume",{currentTime:i,currentVolume:n,calculatedVolume:s,sound:e})):e.fadeOutStart!==e.fadeOutEnd&&i>e.fadeOutEnd?(s=0,r("post-fade-out volume is 0")):e.fadeOutStart!==e.fadeOutEnd&&i>=e.fadeOutStart&&i<=e.fadeOutEnd&&(s=(1-(i-e.fadeOutStart)/(e.fadeOutEnd-e.fadeOutStart))*s,r("ramping \u25bc volume",{currentTime:i,currentVolume:n,calculatedVolume:s,sound:e})),n!==s&&(tt.IOS?G||(t.gain.value=s):t.audio.volume=s,t.volume=s)},_debugAudioObject:function(t){for(var e=["abort","load","loadend","loadstart","loadeddata","loadedmetadata","canplay","canplaythrough","seeked","seeking","stalled","timeupdate","volumechange","waiting","durationchange","progress","emptied","ended","play","pause"],i=this,n=0;n1&&void 0!==arguments[1]?arguments[1]:0;if(!this.active||!this.active.audio)return r("saving url to prepare when audio is initialized",{url:t,startPosition:e}),this.prepareWhenReady={url:t,startPosition:e},!1;var i=this.active.audio.buffered;return i.length>0&&i.end(i.length-1)>=this.active.audio.duration?(r("active song has loaded enough, so preparing",t),this._prepare(t,e)):this.active.audio.src===X?(r("preparing over silence"),this._prepare(t,e)):(r("still loading primary, so waiting to do active prepare",{activeUrl:this.active.audio.src}),this.prepareWhenReady={url:t,startPosition:e},!1)},logState:function(t){for(var e in console.group("speaker: "+(t||"")),this.active?(console.group("active"),console.log("audio.src: ".concat(this.active.audio.src)),console.log("audio.paused: ".concat(this.active.audio.paused)),console.log("sound: ".concat(this.active.sound?this.active.sound.id:"NULL")),console.log("volume: ".concat(this.active.volume)),console.groupEnd(),console.group("preparing"),console.log("audio.src: ".concat(this.preparing.audio.src)),console.log("audio.paused: ".concat(this.preparing.audio.paused)),console.log("sound: ".concat(this.preparing.sound?this.preparing.sound.id:"NULL")),console.log("volume: ".concat(this.preparing.volume)),console.groupEnd(),console.group("fading"),console.log("audio.src: ".concat(this.fading.audio.src)),console.log("audio.paused: ".concat(this.fading.audio.paused)),console.log("sound: ".concat(this.fading.sound?this.fading.sound.id:"NULL")),console.log("volume: ".concat(this.fading.volume)),console.groupEnd()):(console.group("active"),console.log("uninitialized"),console.groupEnd(),console.group("preparing"),console.log("uninitialized"),console.groupEnd(),console.group("fading"),console.log("uninitialized"),console.groupEnd()),console.group("outstanding sounds"),this.outstandingSounds){var i=this.outstandingSounds[e];console.log(i.id+": "+i.url)}console.groupEnd(),console.groupEnd()},_prepare:function(t,e){return this.prepareWhenReady=null,!!t&&(this.preparing&&this.preparing.audio.src===t&&this.preparing.canplaythrough?(r("play already prepared!"),!0):(this.preparing.audio.src!==t&&(r("preparing",t),this.preparing.audio.playing&&this.preparing.audio.pause(),this.preparing.canplaythrough=!1,this.preparing.audio.src=t),e&&this.preparing.audio.currentTime!==e&&(r("advancing preparing audio to",e/1e3),this.preparing.audio.currentTime=e/1e3),!1))},_playSound:function(t){var e=this;if(this.active&&this.active.audio)if(this.active.sound===t)this.active.audio.paused?(r(t.id+" was paused, so resuming"),this.active.audio.play().then((function(){r("resumed playback"),t.trigger("play")})).catch((function(i){r("error resuming playback",i.name,i.message,i.stack,t.id),e.active.sound=null,t.trigger("finish")})),this.fading.sound&&this.fading.audio.play().then((function(){r("resumed fading playback")})).catch((function(i){r("error resuming fading playback",i.name,i.message,i.stack,t.id),e.fading.sound=null,e.fading.audio.src=X}))):r(t.id+" is already playing");else{this.preparing.audio.src!==t.url&&this._prepare(t.url,t.startPosition);var i=this.active;if(this.active=this.preparing,this.preparing=i,this.preparing.canplaythrough=!1,this.preparing.audio.src=X,this.active.sound=null,this._setVolume(this.active,t),this.preparing.sound){var n=this.preparing.sound;this.preparing.sound=null,n.trigger("finish")}r(t.id+" initiating play()");var s=this.active;this.active.audio.play().then((function(){if(!e.outstandingSounds[t.id])return r(t.id+" play() succeeded, but sound has been destroyed"),void(s.audio&&s.audio.src===t.url&&(r(t.id+" being paused and unloaded"),s.audio.pause(),s.audio.src=X));r(t.id+" play() succeeded"),s.sound=t,t.fadeOutSeconds&&0===t.fadeOutEnd&&(t.fadeOutStart=s.audio.duration-t.fadeOutSeconds,t.fadeOutEnd=s.audio.duration),t.startPosition&&(r("updating start position"),s.audio.currentTime=t.startPosition/1e3,r("updated"));var i=s.audio.paused;t.trigger("play"),s.pauseAfterPlay?s.audio.pause():i&&t.trigger("pause")})).catch((function(e){r("error starting playback with sound "+t.id,e.name,e.message,e.stack),t.trigger("finish",e)}))}else console.error("**** player.initializeAudio() *** not called before playback!")},_destroySound:function(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1];if(t.off(),this.active&&this.active.sound===t)if(e&&t.fadeOutSeconds){r("destroy triggered for current sound (with fadeout)",t.id);var i=this.active.audio;t.fadeOutStart=i.currentTime,t.endPosition?(t.fadeOutEnd=Math.min(i.currentTime+t.fadeOutSeconds,t.endPosition/1e3),t.endPosition=Math.min(1e3*t.fadeOutEnd,t.endPosition)):(t.fadeOutEnd=i.currentTime+t.fadeOutSeconds,t.endPosition=1e3*t.fadeOutEnd),this._setVolume(this.active);var n=this.fading;this.fading=this.active,this.active=n,this.active.sound=null}else r("destroy triggered for current sound (no fadeout)",t.id),this.active.audio.pause(),this.active.audio.src=X;else r("destroy triggered for inactive sound",t.id);delete this.outstandingSounds[t.id]},flush:function(){for(var t in this.outstandingSounds)this.outstandingSounds[t].destroy()},_pauseSound:function(t){this.active&&t.url===this.active.audio.src&&(this.active.sound===t?this.active.audio.pause():this.active.pauseAfterPlay=!0),this.fading&&this.fading.audio&&this.fading.audio.pause()},_position:function(t){return this.active&&t===this.active.sound?(t.url!==this.active.audio.src&&r("trying to get current song position, but it is not in the active audio player"),Math.floor(1e3*this.active.audio.currentTime)):0},_duration:function(t){if(t===this.active.sound){t.url!==this.active.audio.src&&r("trying to get current song duration, but it is not in the active audio player");var e=this.active.audio.duration;return isNaN(e)?0:Math.floor(1e3*e)}return 0},setVolume:function(t){return void 0!==t&&(this.vol=t,this.active&&this.active.sound&&this._setVolume(this.active),this.trigger("volume",t)),this.vol},getVolume:function(){return this.vol}},Object.assign(tt.prototype,q);var it=function(t,e,i){var n=this;if(e){i=i||{},this.options=i,this.state={paused:!0,simulcast:i.simulcast},i.debug&&r.enable(),this.trimming=!1!==i.trimming,this.normalizeVolume=!("normalizeVolume"in i)||i.normalizeVolume,this.secondsOfCrossfade=i.secondsOfCrossfade||0,this.crossfadeIn=!!i.crossfadeIn,this._stationsPromise=new Promise((function(t,e){n._stationsResolve=t,n._stationsReject=e}));var s=this.speaker=new tt,a=this.session=new K(t,e,i);if(i.brokenWebkitFormats&&tt.brokenWebkit){var o=i.brokenWebkitFormats.split(","),u=s.getSupportedFormats().split(","),l=h(o,u),c=l.join(",");r("input format list is",o,u),r("final support list is",c),0===l.length&&(c=s.getSupportedFormats()),a.setFormats(c)}else if(i.formats){var d=i.formats.split(","),p=s.getSupportedFormats().split(","),f=h(d,p),y=f.join(",");0===f.length&&(y=s.getSupportedFormats()),r("input format list is",d,p),r("final support list is",y),a.setFormats(y)}else a.setFormats(s.getSupportedFormats())}else this._restore(t);Object.assign(this,q),this.session.on("play-active",this._onPlayActive,this),this.session.on("play-started",this._onPlayStarted,this),this.session.on("play-completed",this._onPlayCompleted,this),this.session.on("plays-exhausted",this._onPlaysExhausted,this),this.session.on("prepare-sound",this._onPrepareSound,this),this.session.on("placement",this._onPlacement,this),this.session.on("stations",this._onStations,this),this.session.on("station-changed",this._onStationChanged,this);for(var g=this,v=function(){var t=_[m];n.session.on(t,(function(){g.trigger.apply(g,[t].concat(Array.prototype.slice.call(arguments,0)))}))},m=0,_=["music-unavailable","not-in-us","invalid-credentials","skip-denied","play-active","forbidden"];m<_.length;m++)v();this.setMuted(this.isMuted())};it.prototype._persist=function(){var t=nt(this.state);return t.activePlay&&(t.activePlay=nt(t.activePlay),delete t.activePlay.sound),{state:t,options:this.options,trimming:this.trimming,normalizeVolume:this.normalizeVolume,secondsOfCrossfade:this.secondsOfCrossfade,crossfadeIn:this.crossfadeIn,_station:this._station,_stations:this._stations,_placement:this._placement,sessionConfig:this.session.config}},it.prototype._restore=function(t){var e=this,i=t.persisted,n=t.elapsed;i.options.debug&&r.enable(),r("restoring!");var s=i.sessionConfig,a=s.current;s.current=null,s.pendingRequest=null,s.pendingPlay=null,this.session=new K,this.session.config=s,this.speaker=new tt,this.options=i.options,this.state={paused:!0,simulcast:this.options.simulcast},this.trimming=i.trimming,this.normalizeVolume=i.normalizeVolume,this.secondsOfCrossfade=i.secondsOfCrossfade,this.crossfadeIn=i.crossfadeIn,this._stationsPromise=new Promise((function(t,i){e._stationsResolve=t,e._stationsReject=i})),this.tune=function(){var t=this;return Promise.resolve(!0).then((function(){t._station=i._station,t._stations=i._stations,t._placement=i._placement,t._stationsResolve(i._stations),t.trigger("placement",t._placement),t.trigger("station-changed",t._station),t.trigger("stations",t._stations),t.session.config.current=a,t.session.config.current.started=!1;var e=t.session.config.current.play;e.start_at=n/1e3,t.session.trigger("play-active",e),t.session.config.current.started=!0,t.state.paused=!1,t.session.trigger("play-started",e,!0),t.state.paused=!0,t.trigger("play-paused",e,!0)})).then((function(){return t._stationsPromise}))}},it.prototype.initializeAudio=function(){r("INTIALIZE AUDIO"),this.speaker.initializeAudio()},it.prototype._onPlacement=function(t){this._placement=t,t.options&&t.options.crossfade_seconds&&(this.secondsOfCrossfade=t.options.crossfade_seconds),this.trigger("placement",t)},it.prototype._onStations=function(t){this._stations=t,this._stationsResolve(t),this.trigger("stations",t)},it.prototype._onStationChanged=function(t,e){this._station=e,e.options&&"crossfade_seconds"in e.options?this.secondsOfCrossfade=e.options.crossfade_seconds:this._placement.options&&"crossfade_seconds"in this._placement.options&&(this.secondsOfCrossfade=this._placement.options.crossfade_seconds),this.trigger("station-changed",t,e)},it.prototype.setStationId=function(t,e){var i,n=!1;!0===e?(n=e,r("SET STATION ID (WITH FADE)",t)):e&&r("SET STATION ID (WITH ADVANCE)",t,i=e),n&&this.state.activePlay&&(this.state.activePlay.fadeOnDestroy=!0),this.session.setStationId(t,i,this.crossfadeIn)},it.prototype._onPlayActive=function(t){var e={play:this._onSoundPlay.bind(this,t.id),pause:this._onSoundPause.bind(this,t.id),finish:this._onSoundFinish.bind(this,t.id),elapse:this._onSoundElapse.bind(this,t.id)};this.normalizeVolume&&(e.gain=(t.audio_file.replaygain_track_gain||0)+(t.station.pre_gain||0)),t.start_at?e.startPosition=1e3*t.start_at:this.trimming&&t.audio_file.extra&&t.audio_file.extra.trim_start&&(e.startPosition=1e3*t.audio_file.extra.trim_start),this.trimming&&t.audio_file.extra&&t.audio_file.extra.trim_end&&t.audio_file.duration_in_seconds&&(e.endPosition=1e3*(t.audio_file.duration_in_seconds-t.audio_file.extra.trim_end)),this.secondsOfCrossfade&&(this.crossfadeIn&&(e.fadeInSeconds=this.secondsOfCrossfade),e.fadeOutSeconds=this.secondsOfCrossfade);var i=this.speaker.create(t.audio_file.url,e);(this.state.activePlay={id:t.id,sound:i,startReportedToServer:!1,soundCompleted:!1,playStarted:!1,fadeOnDestroy:!1,previousPosition:0},this.state.paused)||this.state.activePlay.sound.play()},it.prototype._onSoundPlay=function(t){if(this.state.activePlay&&this.state.activePlay.id===t){this.state.paused=!1;var e,i,n=this.state.activePlay.playStarted;if(this.state.activePlay.playStarted=!0,!this.state.activePlay.startReportedToServer)return e=this._persist(),i=Date.now(),F("feedfm:active",JSON.stringify({state:e,timestamp:i})),F("feedfm:elapsed_time","0"),r("persisted state",{timestamp:i,state:e}),this.session.reportPlayStarted();n||this.trigger("play-resumed",this.session.getActivePlay())}else r("received sound play, but active play does not match",this.state.activePlay,t)},it.prototype.getActivePlay=function(){return this.session.getActivePlay()},it.prototype.hasActivePlayStarted=function(){return this.session.hasActivePlayStarted()},it.prototype.getActivePlacement=function(){return this.session.getActivePlacement()},it.prototype._onSoundPause=function(t){this.state.activePlay&&this.state.activePlay.id===t?(this.state.paused=!0,this.trigger("play-paused",this.session.getActivePlay())):r("received sound pause, but active play does not match",this.state.activePlay,t)},it.prototype._onSoundFinish=function(t,e){if(this.state.activePlay&&this.state.activePlay.id===t)return this.state.activePlay.soundCompleted=!0,e&&(this.state.activePlay.soundCompletedWithError=!0,"NotAllowedError"===e.name)?(console.error('Feed.fm: first call to "initializeAudio()" or "play()" must be made in user-initiated event handler'),void this.stop()):this.state.activePlay.playStarted?void(this.state.activePlay.startReportedToServer&&(e?(r("song completed with error - marking as invalid",e),this.trigger("invalidated",t),this.session.requestInvalidate()):this.session.reportPlayCompleted())):(this.trigger("invalidated",t),void this.session.requestInvalidate());r("received sound finish, but active play does not match",this.state.activePlay,t)},it.prototype._onSoundElapse=function(t){if(this.state.activePlay&&this.state.activePlay.id===t){var e=this.state.activePlay.sound.position(),i=Math.floor(this.state.activePlay.previousPosition/3e4),n=Math.floor(e/3e4);F("feedfm:elapsed_time",e.toString()),this.state.activePlay.previousPosition=e,n!==i&&this.session.reportPlayElapsed(Math.floor(e/1e3))}else r("received sound elapse, but active play does not match",this.state.activePlay,t)},it.prototype._onPlayStarted=function(t){var e=this,i=this.session;this.state.activePlay&&this.state.activePlay.id===t.id?(this.state.activePlay.startReportedToServer=!0,this.state.activePlay.soundCompleted&&(r("sound completed before we finished reporting start",this.state.activePlay),this.state.activePlay.soundCompletedWithError?setTimeout((function(){e.trigger("invalidated",t.id),i.requestInvalidate()}),1):setTimeout((function(){return i.reportPlayCompleted()}),1)),this.updateSimulcast(),this.trigger("play-started",t)):r("received play started, but it does not match active play",t,this.state.activePlay)},it.prototype._onPlayCompleted=function(t){if(this.state.activePlay&&this.state.activePlay.id===t.id){this.state.activePlay.sound.destroy(this.state.activePlay.fadeOnDestroy);var e=this.state.activePlay.playStarted;delete this.state.activePlay,e&&this.trigger("play-completed",t)}else r("received play completed, but it does not match active play",t,this.state.activePlay)},it.prototype._onPlaysExhausted=function(){this.state.paused=!1,this.updateSimulcast(),this.trigger("plays-exhausted")},it.prototype._onPrepareSound=function(t,e){r("preparing",t,e),this.speaker.prepare(t,1e3*e)},it.prototype.isPaused=function(){return this.session.isTuned()&&this.state.paused},it.prototype.getStationInformation=function(t){return this.session.getStationInformation(t)},it.prototype.tune=function(){return r("TUNE"),this.session.isTuned()||this.session.tune(),this._stationsPromise},it.prototype.prepare=function(){var t=this;r("PREPARE"),this.speaker.initializeAudio();var e=this.state.activePlay;return e?this.speaker.prepare(e.sound.url,e.sound.startPosition)?Promise.resolve(!0).then((function(){r("already prepared"),t.trigger("prepared")})):new Promise((function(e){r("waiting for prepared event"),t.speaker.on("prepared",(function(){return e(!0)}))})).then((function(){t.trigger("prepared")})):new Promise((function(e){t.session.once("play-active",(function(i){var n;r("play active"),i.start_at?n=1e3*i.start_at:t.trimming&&i.audio_file.extra&&i.audio_file.extra.trim_start&&(n=1e3*i.audio_file.extra.trim_start),t.speaker.prepare(i.audio_file.url,n)?(r("song is prepared!"),e(!0)):t.speaker.on("prepared",e)})),t.session.isTuned()||(r("tuning"),t.session.tune())})).then((function(){return t.trigger("prepared")}))},it.prototype.play=function(){r("PLAY");var t=this.session,e=this.state;if(this.speaker.initializeAudio(),!t.isTuned())return e.paused=!1,t.tune();t.getActivePlay()&&e.activePlay&&e.paused&&(e.activePlay.playStarted?e.activePlay.sound.resume():e.activePlay.sound.play()),e.paused=!1,this.updateSimulcast()},it.prototype.pause=function(){r("PAUSE"),this.session.hasActivePlayStarted()&&this.state.activePlay&&!this.state.paused&&(this.state.activePlay.sound.pause(),this.state.paused=!0,this.updateSimulcast())},it.prototype.like=function(){r("LIKE"),this.session.hasActivePlayStarted()&&(this.session.likePlay(this.state.activePlay.id),this.trigger("play-liked"))},it.prototype.unlike=function(){r("UNLIKE"),this.session.hasActivePlayStarted()&&(this.session.unlikePlay(this.state.activePlay.id),this.trigger("play-unliked"))},it.prototype.dislike=function(){r("DISLIKE"),this.session.hasActivePlayStarted()&&(this.session.dislikePlay(this.state.activePlay.id),this.trigger("play-disliked"),this.state.paused=!1,this.skip())},it.prototype.skip=function(){r("SKIP"),this.session.hasActivePlayStarted()&&(this.state.paused=!1,this.session.requestSkip())},it.prototype.stop=function(){r("STOP"),H("feedfm:active"),H("feedfm:elapsed_time"),this.state.paused=!0;var t=this.state.activePlay;if(t&&t.sound){if(r("stopping active play",t),t.startReportedToServer){var e=t.sound.position();this.session.reportPlayStopped(Math.floor(e/1e3))}t.sound.pause(),t.sound.destroy()}else r("no active play");delete this.state.activePlay,this.speaker.flush(),this.trigger("play-stopped"),this.updateSimulcast()},it.prototype.destroy=function(){this.session=null,this.state.activePlay&&this.state.activePlay.sound&&this.state.activePlay.sound.destroy()},it.prototype.getCurrentState=function(){return this.session.hasActivePlayStarted()?this.state.paused?"paused":"playing":"idle"},it.prototype.getPosition=function(){return this.state.activePlay&&this.state.activePlay.sound?this.state.activePlay.sound.position():0},it.prototype.getDuration=function(){return this.state.activePlay&&this.state.activePlay.sound?this.state.activePlay.sound.duration():0},it.prototype.maybeCanSkip=function(){return!!this.session.maybeCanSkip()};function nt(t){return null===t?null:Object.assign({},t)}it.prototype.isMuted=function(){return!(!et()||!("muted"in localStorage))&&"true"===localStorage.muted},it.prototype.setMuted=function(t){t?(this.speaker.setVolume(0),et()&&(localStorage.muted=!0),this.trigger("muted")):(this.speaker.setVolume(100),et()&&(localStorage.muted=!1),this.trigger("unmuted"))},it.prototype.getVolume=function(){return this.speaker.getVolume()},it.prototype.setVolume=function(t){this.speaker.setVolume(t)},it.prototype.getStations=function(){return this._stationsPromise},it.prototype.updateSimulcast=function(){var t=this;if(this.state.simulcast){var e=this.getCurrentState();b().then((function(i){t.session._signedAjax(y()+"/api/v2/simulcast/".concat(t.state.simulcast,"/in-progress"),{method:"POST",body:JSON.stringify({state:e,client_id:i}),headers:{"Content-Type":"application/json"}})}))}},window.NodeList&&!NodeList.prototype.forEach&&(NodeList.prototype.forEach=function(t,e){e=e||window;for(var i=0;i"+t.audio_file.track.title+" by "+t.audio_file.artist.name+" on "+t.audio_file.release.title+""},st.prototype.renderStatus=function(t){var e=this;void 0!==t&&(this.displayText=t),this.alertId||this.$el.querySelectorAll(".status").forEach((function(t){t.innerHTML=e.displayText,t.classList.remove("alert")}))},st.prototype.renderPosition=function(t,e){if(this.$el.querySelectorAll(".elapsed").forEach((function(e){e.innerHTML=at(t)})),this.$el.querySelectorAll(".duration").forEach((function(t){t.innerHTML=at(e)})),0===e)this.$el.querySelectorAll(".progress").forEach((function(t){t.style.width="0"}));else{var i=Math.round((t+1e3)/e*100);i=i>100?100:i,this.$el.querySelectorAll(".progress").forEach((function(t){t.style.width=i+"%"}))}},st.prototype.renderAlert=function(t){this.alertId&&window.clearTimeout(this.alertId),this.$el.querySelectorAll(".status").forEach((function(e){e.innerHTML=t,e.classList.add("alert")}));var e=this;this.alertId=window.setTimeout((function(){e.alertId=null,e.renderStatus()}),3e3)},st.prototype._onSuspend=function(){this._enableButtonsBasedOnState()},st.prototype._enableButtonsBasedOnState=function(){var t,e,i=this.player.getCurrentState();switch(i){case"playing":t=[".pause-button",".like-button",".dislike-button"],e=[".play-button",".start-button",".resume-button"],this.player.maybeCanSkip()?t.push(".skip-button"):e.push(".skip-button");break;case"paused":t=[".play-button",".resume-button",".like-button",".dislike-button"],e=[".pause-button",".start-button"],this.player.maybeCanSkip()?t.push(".skip-button"):e.push(".skip-button");break;default:t=[".play-button",".start-button"],e=[".resume-button",".pause-button",".like-button",".dislike-button",".skip-button"]}var n,s=j(e);try{for(s.s();!(n=s.n()).done;){var a=n.value;this.$el.querySelectorAll(a).forEach((function(t){t.classList.remove("button-enabled"),t.classList.add("button-disabled"),t.disabled=!0}))}}catch(t){s.e(t)}finally{s.f()}var o,r=j(t);try{for(r.s();!(o=r.n()).done;){var u=o.value;this.$el.querySelectorAll(u).forEach((function(t){t.classList.remove("button-disabled"),t.classList.add("button-enabled"),t.disabled=!1}))}}catch(t){r.e(t)}finally{r.f()}var l=this.$el.classList;l.remove("state-playing"),l.remove("state-paused"),l.remove("state-idle"),l.add("state-"+i)};var ot=function(){function t(e){w(this,t),Object.assign(this,q),this._speaker=new tt,this._uuid=e,this._state="idle",this._activePlay=null,this._activeSound=null,this._metadataTimeout=null,this._tryingToPlay=!1,this._retries=0}return E(t,[{key:"initializeAudio",value:function(){r("INTIALIZE AUDIO"),this._speaker.initializeAudio()}},{key:"connect",value:function(){if(r("CONNECT to ".concat(this._uuid)),this._tryingToPlay)r("ignoring pointless connect to ".concat(this._uuid));else if("idle"===this._state){this._tryingToPlay=!0,this._speaker.initializeAudio(),this._setState("connecting");var t=new URL(y());this._streamUrl="https://cast."+t.hostname+"/"+this._uuid,this._requestStream()}else r("ignoring connect() since we're already connected")}},{key:"_onSoundPlay",value:function(){var t=this;r("sound play!"),this._retries=0,this._lastElapsedAt=Date.now(),"connecting"===this._state?(this._setState("connected"),fetch(this._streamUrl+"/play?elapsed="+this._elapsed).then((function(t){return t.json()})).then((function(e){e.success?(t._activePlay=e.play,t.trigger("play-started",t._activePlay),t._scheduleMetadataTimeout()):t._scheduleMetadataTimeout(3e3)})).catch((function(){t._scheduleMetadataTimeout(2e3)}))):this._metadataTimeout||this._scheduleMetadataTimeout()}},{key:"_scheduleMetadataTimeout",value:function(){var t=this,e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1e4;this._cancelMetadataTimeout(),this._metadataTimeout=setTimeout((function(){t._onMetadataTimeout()}),e)}},{key:"_cancelMetadataTimeout",value:function(){this._metadataTimeout&&clearTimeout(this._metadataTimeout),this._metadataTimeout=null}},{key:"_onSoundElapse",value:function(){if(this._activeSound){var t=this._elapsed;(this._elapsed=this._activeSound.position())-t>0&&(this._lastElapsedAt=Date.now())}}},{key:"_requestStream",value:function(){r("requesting stream"),this._tryingToPlay&&(this._activeSound&&(this._activeSound.destroy(),this._activeSound=null),this._cancelMetadataTimeout(),this._activePlay=null,this._activeSound=this._speaker.create(this._streamUrl,{play:this._onSoundPlay.bind(this),finish:this._onSoundFinish.bind(this),elapse:this._onSoundElapse.bind(this)}),this._activeSound.play(),this._elapsed=0,this._lastElapsedAt=Date.now())}},{key:"_onMetadataTimeout",value:function(){var t=this;this._cancelMetadataTimeout(),fetch(this._streamUrl+"/play?elapsed="+this._elapsed).then((function(t){return t.json()})).then((function(e){e.success&&(null===e.play&&null!==t._activePlay||null!==e.play&&null===t._activePlay||null!==e.play&&null!==t._activePlay&&e.play.audio_file.id!==t._activePlay.audio_file.id)&&(t._activePlay=e.play,r("current play updated",t._activePlay),t.trigger("play-started",t._activePlay)),t._scheduleMetadataTimeout();var i=Date.now()-t._lastElapsedAt;i>8e3&&(r("stream has not advanced for ".concat(i," ms, so reconnecting"),t.toObject()),t._requestStream())})).catch((function(){var e=Date.now()-t._lastElapsedAt;e>8e3?(r("stream has not advanced for ".concat(e," ms, so reconnecting"),t.toObject()),t._requestStream()):t._scheduleMetadataTimeout()}))}},{key:"_onSoundFinish",value:function(t){var e=this;r("sound finished",this.toObject()),"connecting"===this._state&&t?(this._tryingToPlay=!1,this._setState("music-unavailable"),this.trigger("music-unavailable")):(r("reconnecting after stream ended",t),this._activeSound&&(this._activeSound.destroy(),this._activeSound=null),this._cancelMetadataTimeout(),this._activePlay=null,this._retries+=1,setTimeout((function(){e._tryingToPlay&&(r("retrying connection after stream ended"),e._requestStream())}),Math.pow(2,this._retries))),this._logEvents()}},{key:"disconnect",value:function(){r("DISCONNECT",this.toObject()),this._tryingToPlay&&(this._tryingToPlay=!1,this._activePlay=null,this._elapsed=0,this._cancelMetadataTimeout(),this._activeSound&&(this._activeSound.destroy(),this._activeSound=null),this._setState("idle"),this._logEvents())}},{key:"getVolume",value:function(){return this._speaker.getVolume()}},{key:"setVolume",value:function(t){this._speaker.setVolume(t)}},{key:"_setState",value:function(t){this._state!==t&&(r("state transition ".concat(this._state," -> ").concat(t)),this._state=t,this.trigger("state-changed",this._state))}},{key:"getCurrentState",value:function(){return this._state}},{key:"getCurrentPlay",value:function(){return this._activePlay}},{key:"_logEvents",value:function(){var t=r.reset();return fetch(y()+"/api/v2/session/event",{method:"POST",body:JSON.stringify({event:"playerHistory",parameters:t}),headers:{"Content-Type":"application/json","X-Feed-SDK":"1.101.1 js"}})}},{key:"toObject",value:function(){return{state:this._state,activePlay:this._activePlay,uuid:this._uuid,metadataTimeoutIsNull:null===this._metadataTimeout,tryingToPlay:this._tryingToPlay,elapsed:this._elapsed,retries:this._retries}}},{key:"toString",value:function(){return JSON.stringify(this.toString())}}]),t}();return{Speaker:tt,Session:K,Player:it,Listener:U,PlayerView:st,SimulcastPlayer:ot,log:r,version:"1.101.1",resetClientId:function(){m?_=null:a("cid"),v=null},getClientId:b,setBaseUrl:g,resumable:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:4e3,e=W(t);if(2===e.length){var i=I(e,2),n=i[0],s=i[1],a=new it({persisted:n,elapsed:s});return a}return null}}}(); +var Feed=function(){"use strict";function t(t,e){return Object.prototype.hasOwnProperty.call(t,e)}function e(t){var e=t.charAt(t.length-1),i=parseInt(t,10),n=new Date;switch(e){case"Y":n.setFullYear(n.getFullYear()+i);break;case"M":n.setMonth(n.getMonth()+i);break;case"D":n.setDate(n.getDate()+i);break;case"h":n.setHours(n.getHours()+i);break;case"m":n.setMinutes(n.getMinutes()+i);break;case"s":n.setSeconds(n.getSeconds()+i);break;default:n=new Date(t)}return n}function i(){return(i=Object.assign||function(t){for(var e=1;e500&&t.history.shift()};r.history=[],r.enable=function(){o=!0},r.reset=function(){var t=r.history;return r.history=[],t};var u=0;function l(t){return t+ ++u}var c=Array.prototype.indexOf;function d(t,e,i,n){"function"==typeof e&&(n=i,i=e,e=!1);var s=i?t.map(i,n):t,a=[],o=[];return s.forEach((function(i,n){var s,r;(e?n&&o[o.length-1]===i:(r=i,null!==(s=o)&&(c&&s.indexOf===c?-1!=s.indexOf(r):s.some((function(t){return t===r})))))||(o.push(i),a.push(t[n]))})),a}function h(t,e){var i=e.map((function(t){return new RegExp(t)}));return d(t).filter((function(t){return i.find((function(e){return e.test(t)}))}))}function p(t,e,i){(t=t?2*t:200)>e&&(t=e),setTimeout((function(){i(t)}),t)}var f="https://feed.fm";function y(){return f}function g(t){f=function(t,e){return"//"===t.slice(0,2)&&(t=!0===e?"https:"+t:!1===e?"http:"+t:"http"===window.location.protocol.substr(0,4)?window.location.protocol+t:"http"),t}(t)}var v,m="undefined"==typeof document,_=null;function P(){return m?_:n("cid")}function S(t){m?_=t:s("cid",t,{expires:3650,path:"/"})}function b(){if(!v)var t=v=new Promise((function(e){!function t(e,i){var n=P();if(n)return e(n);fetch(y()+"/api/v2/client",{method:"POST"}).then((function(t){return t.json()})).then((function(n){n.success?e(n.client_id):p(i,2e3,(function(i){t(e,i)}))})).catch((function(n){if(403===n.status)try{var s=JSON.parse(n.responseText);r("error trying to get client id:",s)}catch(t){r("unknown response for client id request",t.message)}else r("unknown client id response status",n.status);p(i,2e3,(function(i){t(e,i)}))}))}((function(i){v===t?(S(i),e(i)):v?v.then((function(t){e(t)})):b().then((function(t){e(t)}))}))}));return v}var k=P,T=S;function A(t){return(A="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function w(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function O(t,e){for(var i=0;it.length)&&(e=t.length);for(var i=0,n=new Array(e);i=t.length?{done:!0}:{done:!1,value:t[e++]}},e:function(t){throw t},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var n,s,a=!0,o=!1;return{s:function(){n=t[Symbol.iterator]()},n:function(){var t=n.next();return a=t.done,t},e:function(t){o=!0,s=t},f:function(){try{a||null==n.return||n.return()}finally{if(o)throw s}}}}for(var L=Array.prototype.slice,q={on:function(t,e,i){return R(this,"on",t,[e,i])&&e?(this._events||(this._events={}),(this._events[t]||(this._events[t]=[])).push({callback:e,context:i,ctx:i||this}),this):this},once:function(t,e,i){if(!R(this,"once",t,[e,i])||!e)return this;var n,s,a,o=this,r=(n=function(){o.off(t,r),e.apply(this,arguments)},a=!1,function(){return a||(a=!0,s=n.apply(this,arguments),n=null),s});return r._callback=e,this.on(t,r,i)},off:function(t,e,i){var n,s,a,o,r,u,l,c;if(!this._events||!R(this,"off",t,[e,i]))return this;if(!t&&!e&&!i)return this._events={},this;for(r=0,u=(o=t?[t]:Object.keys(this._events)).length;r20&&i.play.duration_in_seconds-i.seconds_since_start>20&&(n=15e3)}}else if(i.error&&19===i.error.code)return e._state="music-unavailable",void e.trigger("music-unavailable");e._timeout=setTimeout((function(){e.onTimeout(t)}),n)})).catch((function(i){if(403===i.status)try{var n=JSON.parse(i.responseText);if(n.error&&19===n.error.code){try{e._state="music-unavailable",e.trigger("music-unavailable")}catch(t){}return}console.log("unexpected error:",n)}catch(t){console.log("bad response",t.message)}else console.log("odd response",i);e._timeout=setTimeout((function(){e.onTimeout(t)}),15e3)}))}},{key:"getCurrentState",value:function(){return this._state}},{key:"getCurrentPlay",value:function(){return this._activePlay}}]),t}();function $(){try{return"localStorage"in window&&null!==window.localStorage}catch(t){return!1}}function F(t,e){$()&&localStorage.setItem(t,e)}function H(t){$()&&localStorage.removeItem(t)}function W(t){return $()?localStorage.getItem(t):null}function J(t){var e=W("feedfm:active");if(e){var i=JSON.parse(e);if(i.timestamp+t>Date.now()){var n=parseFloat(W("feedfm:elapsed_time"),10);return[i.state,n]}}return[]}var K=function(t,e,i){Object.assign(this,q),t&&e&&((i=i||{}).baseUrl&&g(i.baseUrl),this.config={remoteLogging:!!i.remoteLogging,formats:"mp3,aac",maxBitrate:128,timeOffset:0,current:null,pendingRequest:null,pendingPlay:null},t&&e&&this.setCredentials(t,e),i.remoteLogging&&(r("remote logging enabled",this.config),this._submitLogHistory()))};K.prototype.setCredentials=function(t,e){this.config.token=t,this.config.secret=e},K.prototype.setStationId=function(t,e,i){if(this.config.stations){var n=""+t,s=""+this.config.stationId!==n;if(s||e){var a=this.config.stations.find((function(t){return""+t.id===n}));a&&(this.config.stationId=t,this.config.station=a,s&&this.trigger("station-changed",t,a),this.config.pendingRequest=null,this.config.pendingPlay=null,this._assignCurrentPlay(null,!0),this._requestNextPlay(0,e,i))}}},K.prototype.setFormats=function(t){this.config.formats=t,this.isTuned()&&this.tune()},K.prototype.setMaxBitrate=function(t){this.config.maxBitrate=t},K.prototype.tune=function(){if(!this.config.token)throw new Error("no token set with setCredentials()");if(!this.config.secret)throw new Error("no secret set with setCredentials()");this.config.pendingRequest=null,this.config.pendingPlay=null,this._assignCurrentPlay(null,!0),this._getDefaultPlacementInformation()},K.prototype._getDefaultPlacementInformation=function(t){var e=this;this.config.placementId&&this.config.placement&&this.config.placement.id===this.config.placementId?this._requestNextPlay():(r("requesting default placement information from server"),e._signedAjax(y()+"/api/v2/session",{method:"POST",body:JSON.stringify({client_id:k()}),headers:{"Content-Type":"application/json"}}).then((function(t){return t.json()})).then((function(t){return t.session&&t.session.client_id&&T(t.session.client_id),e._getClientId().then((function(){return t}))})).then(e._receiveDefaultPlacementInformation.bind(e)).catch(e._failedDefaultPlacementInformation.bind(e,t)))},K.prototype._receiveDefaultPlacementInformation=function(t){t&&t.success&&t.placement?(this.config.placement=t.placement,this.config.stations=t.stations,this.config.placementId=t.placement.id,this.trigger("placement",this.config.placement),this.config.stations.length>0&&(this.config.stationId=this.config.stations[0].id,this.config.station=this.config.stations[0],this.trigger("station-changed",this.config.stationId,this.config.station)),this.trigger("stations",this.config.stations),this._requestNextPlay()):this.trigger("music-unavailable")},K.prototype._failedDefaultPlacementInformation=function(t,e){var i=this;if(401===e.status)try{var n=JSON.parse(e.responseText);if(n.error&&5===n.error.code)return void this.trigger("invalid-credentials")}catch(t){}else console.warn("error from placement request",e);t=t?2*t:500,setTimeout((function(){i._getDefaultPlacementInformation(t)}),t)},K.prototype.getActivePlacement=function(){return this.config.placement?this.config.placement:null},K.prototype.getActivePlay=function(){return this.config.current?this.config.current.play:null},K.prototype.isTuned=function(){return this.config.current||this.config.pendingRequest},K.prototype.hasActivePlayStarted=function(){return this.config.current&&this.config.current.started},K.prototype.reportPlayStarted=function(){if(!this.config.current)throw new Error("attempt to report a play started, but there is no active play");this._startPlay(this.config.current.play)},K.prototype.reportPlayElapsed=function(t){if(!this.config.current)throw new Error("attempt to report elapsed play time, but the play hasn't started");this._signedAjax(y()+"/api/v2/play/"+this.config.current.play.id+"/elapse",{method:"POST",body:JSON.stringify({seconds:t}),headers:{"Content-Type":"application/json"}})},K.prototype.reportPlayCompleted=function(){if(!this.config.current||!this.config.current.started)throw r("finish on non-active or playing song"),new Error("no active or playing song");this._signedAjax(y()+"/api/v2/play/"+this.config.current.play.id+"/complete",{method:"POST"}).finally(this._receivePlayCompleted.bind(this))},K.prototype._receivePlayCompleted=function(){if(this.config.pendingRequest)r("song finished, but we're still waiting for next one to return"),this._assignCurrentPlay(null,!0);else{r("song finished, and no outstanding request, so playing pendingPlay");var t=this.config.pendingPlay;this.config.pendingPlay=null,this._assignCurrentPlay(t)}},K.prototype.reportPlayStopped=function(t){this.config.current&&this.config.current.started&&this._signedAjax(y()+"/api/v2/play/"+this.config.current.play.id+"/elapse",{method:"POST",body:JSON.stringify({seconds:t}),headers:{"Content-Type":"application/json"}}),this.config.pendingRequest=null,this.config.pendingPlay=null,this._assignCurrentPlay(null,!0)},K.prototype.requestSkip=function(){var t=this;if(!this.config.current)throw new Error("No song being played");if(!this.config.current.started)throw new Error("No song has been started");this.config.current.canSkip?this._signedAjax(y()+"/api/v2/play/"+this.config.current.play.id+"/skip",{method:"POST"}).then((function(t){return t.json()})).then(this._receiveSkip.bind(this,this.config.current.play)).catch(this._failSkip.bind(this,this.config.current.play)):setTimeout((function(){t.trigger("skip-denied")}),1)},K.prototype.requestInvalidate=function(){if(!this.config.current)throw new Error("No active song to invalidate!");this._sendInvalidate(this.config.current.play)},K.prototype._sendInvalidate=function(t,e){this._signedAjax(y()+"/api/v2/play/"+t.id+"/invalidate",{method:"POST"}).then((function(t){return t.json()})).then(this._receiveInvalidate.bind(this,t)).catch(this._failInvalidate.bind(this,e,t))},K.prototype._failInvalidate=function(t,e,i){var n=this;(t=t?2*t:200)<3e3?setTimeout((function(){n._sendInvalidate(e)}),t):r("gave up trying to invalidate play",i)},K.prototype._receiveInvalidate=function(t,e){var i=this;if(r("invalidate response"),this._submitLogHistory(),setTimeout((function(){r("5 second follow up after invalidate"),i._submitLogHistory()}),5e3),this.config.current&&this.config.current.play===t)if(e.success)if(this.config.pendingPlay){r("invalidating to song already queued up");var n=this.config.pendingPlay;this.config.pendingPlay=null,this._assignCurrentPlay(n)}else r("invalidating current song"),this._assignCurrentPlay(null,!0),this.config.pendingRequest||(r("queueing up new song"),this._requestNextPlay());else r("failed invalidate! - technically this is impossible")},K.prototype._failSkip=function(t){this.config.current&&this.config.current.play===t&&this.trigger("skip-denied")},K.prototype._receiveSkip=function(t,e){if(this.config.current&&this.config.current.play===t){if(!e.success)return r("failed skip!"),void this.trigger("skip-denied");if(this.config.pendingPlay){r("skipping to song already queued up");var i=this.config.pendingPlay;this.config.pendingPlay=null,this._assignCurrentPlay(i)}else this.config.pendingRequest?(r("skipping to what is queued up"),this._assignCurrentPlay(null,!0)):(r("skipping to what is queued up"),this._assignCurrentPlay(null))}},K.prototype._startPlay=function(t){this.config.current.retryCount>2?this._receiveStartPlay(t,{success:!0,can_skip:!0}):(r("telling server we're starting the play",t),this._signedAjax(y()+"/api/v2/play/"+t.id+"/start",{method:"POST"}).then((function(t){return t.json()})).then(this._receiveStartPlay.bind(this,t)).catch(this._failStartPlay.bind(this,t)))},K.prototype._receiveStartPlay=function(t,e){e.success?this.config.current&&this.config.current.play===t?(this.config.current.canSkip=e.can_skip,this.config.current.started=!0,this._requestNextPlay(),this.trigger("play-started",t)):r("received start play, but not waiting any more"):r("received failed start success")},K.prototype._failStartPlay=function(t,e){var i=this,n=this;if(r("start failed",e),this._submitLogHistory(),setTimeout((function(){r("5 second follow up after start failure"),n._submitLogHistory()}),5e3),this.config.current&&this.config.current.play===t){if(403===e.status)try{var s=JSON.parse(e.responseText);if(s.error&&20===s.error.code)return this._receiveStartPlay(t,{success:!0,can_skip:!0})}catch(t){r("unable to parse start play response",t.message)}r("request failed - trying again in 1 second",e),this.config.current.retryCount++,setTimeout((function(){i._startPlay(t)}))}else r("startPlay failed, but we don't care any more")},K.prototype._assignCurrentPlay=function(t,e){if(this.config.current){var i=this.config.current.play;this.config.current=null,this.trigger("play-completed",i)}null===t?e?r("nothing to play... waiting"):(r("nothing to play from the current station"),this.trigger("plays-exhausted")):(this.config.current={play:t,canSkip:!1,started:!1,retryCount:0},r("activated new song"),this.trigger("play-active",t))},K.prototype._requestNextPlay=function(t,e,i){var n=this;n._getClientId().then((function(s){if(n.config.pendingRequest){if(t){if(t>6e4)return r("giving up on retrieving next play"),n.config.pendingRequest=null,void(null===n.config.current&&n._assignCurrentPlay(null));r("retrying pending request"),n.config.pendingRequest.retryCount++;var a=n.config.pendingRequest.ajax;return void n._signedAjax(n.config.pendingRequest.url,a).then((function(t){return t.json()})).then(n._receiveNextPlay.bind(n,a)).catch(n._failedNextPlay.bind(n,t,a))}r("already waiting for a request to finish")}else{var o={formats:n.config.formats,client_id:s,max_bitrate:n.config.maxBitrate,secure:!0};n.config.placementId&&(o.placement_id=n.config.placementId),n.config.stationId&&(o.station_id=n.config.stationId),e&&(o.at=e,i&&(o.crossfade=i));var u={method:"POST",body:JSON.stringify(o),headers:{"Content-Type":"application/json"}};n.config.pendingRequest={url:y()+"/api/v2/play",ajax:u,retryCount:0},r("requesting new play from server",u),n._signedAjax(y()+"/api/v2/play",u).then((function(t){return t.json()})).then(n._receiveNextPlay.bind(n,u)).catch(n._failedNextPlay.bind(n,t,u))}}))},K.prototype._receiveNextPlay=function(t,e){this.config.pendingRequest&&this.config.pendingRequest.ajax===t?(this.config.pendingRequest=null,e.success?(this.trigger("prepare-sound",e.play.audio_file.url,e.play.start_at),this.config.current?(r("received play, but we're already playing, so queueing up",e.play),this.config.pendingPlay=e.play):(r("received play and no current song, making active now",e.play),this._assignCurrentPlay(e.play))):e.error&&9===e.error.code?this.config.current?(r("ran out of music to play, but we're already playing"),this.config.pendingPlay=null):(r("ran out of music, and nothing playing now"),this.trigger("plays-exhausted")):e.error&&6===e.error.code?this.trigger("forbidden",e.error.message):r("unsuccessful response",e)):r("nextPlay succeeded, but we don't care")},K.prototype._failedNextPlay=function(t,e,i){var n=this;if(r("next play failed",i),this._submitLogHistory(),setTimeout((function(){r("5 second follow up after next play failure"),n._submitLogHistory()}),5e3),this.config.pendingRequest&&this.config.pendingRequest.ajax===e){if(403===i.status)try{var s=JSON.parse(i.responseText);if(s.error&&19===s.error.code)return this.trigger("music-unavailable",s.error.message),void this.trigger("not-in-us",s.error.message)}catch(t){r("problem parsing 403 response",t.message)}t=Math.min(t?2*t:500,2e3),r("request failed - trying again after "+t+"ms"),setTimeout((function(){n._requestNextPlay(t)}),t)}else r("nextPlay failed, but we don't care")},K.prototype.maybeCanSkip=function(){return this.config.current&&this.config.current.started&&this.config.current.canSkip},K.prototype.likePlay=function(t){this._signedAjax(y()+"/api/v2/play/"+t+"/like",{method:"POST"}),this.config.current&&this.config.current.play.id===t&&(this.config.current.play.liked=!0)},K.prototype.unlikePlay=function(t){this._signedAjax(y()+"/api/v2/play/"+t+"/like",{method:"DELETE"}),this.config.current&&this.config.current.play.id===t&&delete this.config.current.play.liked},K.prototype.dislikePlay=function(t){this._signedAjax(y()+"/api/v2/play/"+t+"/dislike",{method:"POST"}),this.config.current&&this.config.current.play.id===t&&(this.config.current.play.liked=!1)};K.prototype._getStoredCid=function(){return n("cid")},K.prototype._setStoredCid=function(t){s("cid",t,{expires:3650,path:"/"})},K.prototype._deleteStoredCid=function(){a("cid")},K.prototype._sign=function(t){var e;if(t||(t={}),e="Basic "+btoa(this.config.token+":"+this.config.secret),t.headers?t.headers.Authorization=e:t.headers={Authorization:e},t.headers["X-Feed-SDK"]="1.101.1 js",this.extraHeaders)for(var i in this.extraHeaders)this.extraHeaders.hasOwnProperty(i)&&(t.headers[i]=this.extraHeaders[i]);return t},K.prototype._signedAjax=function(t,e){return this._ajax(t,this._sign(e))},K.prototype._ajax=function(t,e){return fetch(t,e)},K.prototype._submitLogHistory=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,e=this,i=r.history;if(r.history=[],this.config.remoteLogging)return this._signedAjax(y()+"/api/v2/session/event",{method:"POST",body:JSON.stringify({event:"playerHistory",parameters:i}),headers:{"Content-Type":"application/json"}}).catch((function(){t<2&&setTimeout((function(){r.history=i.concat(["failed log report attempt, try #"+t],r.history),e._submitLogHistory(t+1)}),5e3)}))},K.prototype._getClientId=function(){return b()};var Y=["iPad Simulator","iPhone Simulator","iPod Simulator","iPad","iPhone","iPod"].includes(navigator.platform)||navigator.userAgent.includes("Mac")&&"ontouchend"in document,G=navigator.userAgent.includes("CrKey"),X=Y&&/OS 13_[543210]/i.test(navigator.userAgent),Z=Y?"https://u9e9h7z5.map2.ssl.hwcdn.net/feedfm-audio/250-milliseconds-of-silence.mp3":"data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA",Q=function(t,e,i,n){var s=Object.assign(this,q);if(s.id=i,s.url=n,s.speaker=t,s.loaded=!1,s.savedSrc="",s.savedPos=0,e){this.startPosition=+e.startPosition,this.endPosition=+e.endPosition,this.fadeInSeconds=+e.fadeInSeconds,this.fadeInSeconds?(this.fadeInStart=this.startPosition?this.startPosition/1e3:0,this.fadeInEnd=this.fadeInStart+this.fadeInSeconds):(this.fadeInStart=0,this.fadeInEnd=0),this.fadeOutSeconds=+e.fadeOutSeconds,this.fadeOutSeconds&&(this.endPosition?(this.fadeOutStart=this.endPosition/1e3-this.fadeOutSeconds,this.fadeOutEnd=this.endPosition/1e3):(this.fadeOutStart=0,this.fadeOutEnd=0));for(var a=0,o=["play","pause","finish","elapse"];a=this.active.sound.fadeOutStart){this._setVolume(this.active);var n=this.fading;this.fading=this.active,this.active=n,this.active.sound=null,this.fading.sound.trigger("finish")}else this._setVolume(this.active),this.active.sound.trigger("elapse");this.prepareWhenReady&&this.prepare(this.prepareWhenReady.url,this.prepareWhenReady.startPosition)}else r("active audio elapsed, but no matching sound, so ignoring",e.src)}else this.fading.sound.endPosition&&e.currentTime>=this.fading.sound.endPosition/1e3?(this.fading.sound=null,this.fading.audio.src=Z):this._setVolume(this.fading)},_setVolume:function(t,e){e||(e=t.sound);var i=t.audio.currentTime,n=t.volume,s=e.gainAdjustedVolume(this.vol);e.fadeInStart!==e.fadeInEnd&&i=e.fadeInStart&&i<=e.fadeInEnd?(s=(i-e.fadeInStart)/(e.fadeInEnd-e.fadeInStart)*s,r("ramping \u25b2 volume",{currentTime:i,currentVolume:n,calculatedVolume:s,sound:e})):e.fadeOutStart!==e.fadeOutEnd&&i>e.fadeOutEnd?(s=0,r("post-fade-out volume is 0")):e.fadeOutStart!==e.fadeOutEnd&&i>=e.fadeOutStart&&i<=e.fadeOutEnd&&(s=(1-(i-e.fadeOutStart)/(e.fadeOutEnd-e.fadeOutStart))*s,r("ramping \u25bc volume",{currentTime:i,currentVolume:n,calculatedVolume:s,sound:e})),n!==s&&(et.IOS?X||(t.gain.value=s):t.audio.volume=s,t.volume=s)},_debugAudioObject:function(t){for(var e=["abort","load","loadend","loadstart","loadeddata","loadedmetadata","canplay","canplaythrough","seeked","seeking","stalled","timeupdate","volumechange","waiting","durationchange","progress","emptied","ended","play","pause"],i=this,n=0;n1&&void 0!==arguments[1]?arguments[1]:0;if(!this.active||!this.active.audio)return r("saving url to prepare when audio is initialized",{url:t,startPosition:e}),this.prepareWhenReady={url:t,startPosition:e},!1;var i=this.active.audio.buffered;return!G&&i.length>0&&i.end(i.length-1)>=this.active.audio.duration?(r("active song has loaded enough, to preparing",t),this._prepare(t,e)):this.active.audio.src===Z?(r("preparing over silence"),this._prepare(t,e)):(r("still loading primary, so waiting to do active prepare",{activeUrl:this.active.audio.src}),this.prepareWhenReady={url:t,startPosition:e},!1)},logState:function(t){for(var e in console.group("speaker: "+(t||"")),this.active?(console.group("active"),console.log("audio.src: ".concat(this.active.audio.src)),console.log("audio.paused: ".concat(this.active.audio.paused)),console.log("sound: ".concat(this.active.sound?this.active.sound.id:"NULL")),console.log("volume: ".concat(this.active.volume)),console.groupEnd(),console.group("preparing"),console.log("audio.src: ".concat(this.preparing.audio.src)),console.log("audio.paused: ".concat(this.preparing.audio.paused)),console.log("sound: ".concat(this.preparing.sound?this.preparing.sound.id:"NULL")),console.log("volume: ".concat(this.preparing.volume)),console.groupEnd(),console.group("fading"),console.log("audio.src: ".concat(this.fading.audio.src)),console.log("audio.paused: ".concat(this.fading.audio.paused)),console.log("sound: ".concat(this.fading.sound?this.fading.sound.id:"NULL")),console.log("volume: ".concat(this.fading.volume)),console.groupEnd()):(console.group("active"),console.log("uninitialized"),console.groupEnd(),console.group("preparing"),console.log("uninitialized"),console.groupEnd(),console.group("fading"),console.log("uninitialized"),console.groupEnd()),console.group("outstanding sounds"),this.outstandingSounds){var i=this.outstandingSounds[e];console.log(i.id+": "+i.url)}console.groupEnd(),console.groupEnd()},_prepare:function(t,e){return this.prepareWhenReady=null,G?(r("preparing "+t),this.active.audio.playing&&this.active.audio.pause(),this.active.audio.src=t):this.preparing.audio.src!==t&&(r("preparing "+t),this.preparing.audio.playing&&this.preparing.audio.pause(),this.preparing.canplaythrough=!1,this.preparing.audio.src=t),G&&e&&this.active.audio.currentTime!==e?(r("advancing preparing audio to",e/1e3),this.active.audio.currentTime=e/1e3):e&&this.preparing.audio.currentTime!==e&&(r("advancing preparing audio to",e/1e3),this.preparing.audio.currentTime=e/1e3),!1},_playSound:function(t){var e=this;if(this.active&&this.active.audio)if(this.active.sound===t)this.active.audio.paused||"not-a-real-file-paused"===this.active.audio.src?(r(t.id+" was paused, so resuming"),G&&(this.active.audio.currentTime=t.savedPos,this.active.audio.src=t.savedSrc),this.active.audio.play().then((function(){r("resumed playback"),t.trigger("play")})).catch((function(i){r("error resuming playback",i.name,i.message,i.stack,t.id),e.active.sound=null,t.trigger("finish")})),!G&&this.fading.sound&&this.fading.audio.play().then((function(){r("resumed fading playback")})).catch((function(i){r("error resuming fading playback",i.name,i.message,i.stack,t.id),e.fading.sound=null,e.fading.audio.src=Z}))):r(t.id+" is already playing");else{G||this.preparing.audio.src===t.url||this._prepare(t.url,t.startPosition);var i=this.active;if(G||(this.active=this.preparing,this.preparing=i),this.preparing.canplaythrough=!1,this.preparing.audio.src=Z,this.active.sound=null,this._setVolume(this.active,t),!G&&this.preparing.sound){this.preparing.audio.src=Z;var n=this.preparing.sound;this.preparing.sound=null,n.trigger("finish")}r(t.id+" initiating play()");var s=this.active;this.active.audio.play().then((function(){if(!e.outstandingSounds[t.id])return r(t.id+" play() succeeded, but sound has been destroyed"),void(s.audio&&s.audio.src===t.url&&(r(t.id+" being paused and unloaded"),s.audio.pause(),s.audio.src=Z));r(t.id+" play() succeeded"),s.sound=t,t.fadeOutSeconds&&0===t.fadeOutEnd&&(t.fadeOutStart=s.audio.duration-t.fadeOutSeconds,t.fadeOutEnd=s.audio.duration),t.startPosition&&(r("updating start position"),s.audio.currentTime=t.startPosition/1e3,r("updated"));var i=s.audio.paused;t.trigger("play"),s.pauseAfterPlay?s.audio.pause():i&&t.trigger("pause")})).catch((function(e){r("error starting playback with sound "+t.id,e.name,e.message,e.stack),t.trigger("finish",e)}))}else console.error("**** player.initializeAudio() *** not called before playback!")},_destroySound:function(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1];if(t.off(),this.active&&this.active.sound===t)if(e&&t.fadeOutSeconds){r("destroy triggered for current sound (with fadeout)",t.id);var i=this.active.audio;if(t.fadeOutStart=i.currentTime,t.endPosition?(t.fadeOutEnd=Math.min(i.currentTime+t.fadeOutSeconds,t.endPosition/1e3),t.endPosition=Math.min(1e3*t.fadeOutEnd,t.endPosition)):(t.fadeOutEnd=i.currentTime+t.fadeOutSeconds,t.endPosition=1e3*t.fadeOutEnd),this._setVolume(this.active),!G){var n=this.fading;this.fading=this.active,this.active=n,this.active.sound=null}}else r("destroy triggered for current sound (no fadeout)",t.id),this.active.audio.pause(),this.active.audio.src=Z;else r("destroy triggered for inactive sound",t.id);delete this.outstandingSounds[t.id]},flush:function(){for(var t in this.outstandingSounds)this.outstandingSounds[t].destroy()},_pauseSound:function(t){this.active&&t.url===this.active.audio.src&&(this.active.sound===t?G?(t.savedPos=this.active.audio.currentTime,t.savedSrc=this.active.audio.src,this.active.audio.src="not-a-real-file-paused"):this.active.audio.pause():this.active.pauseAfterPlay=!0),!G&&this.fading&&this.fading.audio&&this.fading.audio.pause()},_position:function(t){return this.active&&t===this.active.sound?(t.url!==this.active.audio.src&&r("trying to get current song position, but it is not in the active audio player"),Math.floor(1e3*this.active.audio.currentTime)):0},_duration:function(t){if(t===this.active.sound){t.url!==this.active.audio.src&&r("trying to get current song duration, but it is not in the active audio player");var e=this.active.audio.duration;return isNaN(e)?0:Math.floor(1e3*e)}return 0},setVolume:function(t){return void 0!==t&&(this.vol=t,this.active&&this.active.sound&&this._setVolume(this.active),this.trigger("volume",t)),this.vol},getVolume:function(){return this.vol}},Object.assign(et.prototype,q);var nt=function(t,e,i){var n=this;if(e){i=i||{},this.options=i,this.state={paused:!0,simulcast:i.simulcast},i.debug&&r.enable(),this.trimming=!1!==i.trimming,this.normalizeVolume=!("normalizeVolume"in i)||i.normalizeVolume,this.secondsOfCrossfade=i.secondsOfCrossfade||0,this.crossfadeIn=!!i.crossfadeIn,this._stationsPromise=new Promise((function(t,e){n._stationsResolve=t,n._stationsReject=e}));var s=this.speaker=new et,a=this.session=new K(t,e,i);if(i.brokenWebkitFormats&&et.brokenWebkit){var o=i.brokenWebkitFormats.split(","),u=s.getSupportedFormats().split(","),l=h(o,u),c=l.join(",");r("input format list is",o,u),r("final support list is",c),0===l.length&&(c=s.getSupportedFormats()),a.setFormats(c)}else if(i.formats){var d=i.formats.split(","),p=s.getSupportedFormats().split(","),f=h(d,p),y=f.join(",");0===f.length&&(y=s.getSupportedFormats()),r("input format list is",d,p),r("final support list is",y),a.setFormats(y)}else a.setFormats(s.getSupportedFormats())}else this._restore(t);Object.assign(this,q),this.session.on("play-active",this._onPlayActive,this),this.session.on("play-started",this._onPlayStarted,this),this.session.on("play-completed",this._onPlayCompleted,this),this.session.on("plays-exhausted",this._onPlaysExhausted,this),this.session.on("prepare-sound",this._onPrepareSound,this),this.session.on("placement",this._onPlacement,this),this.session.on("stations",this._onStations,this),this.session.on("station-changed",this._onStationChanged,this);for(var g=this,v=function(){var t=_[m];n.session.on(t,(function(){g.trigger.apply(g,[t].concat(Array.prototype.slice.call(arguments,0)))}))},m=0,_=["music-unavailable","not-in-us","invalid-credentials","skip-denied","play-active","forbidden"];m<_.length;m++)v();this.setMuted(this.isMuted())};nt.prototype._persist=function(){var t=st(this.state);return t.activePlay&&(t.activePlay=st(t.activePlay),delete t.activePlay.sound),{state:t,options:this.options,trimming:this.trimming,normalizeVolume:this.normalizeVolume,secondsOfCrossfade:this.secondsOfCrossfade,crossfadeIn:this.crossfadeIn,_station:this._station,_stations:this._stations,_placement:this._placement,sessionConfig:this.session.config}},nt.prototype._restore=function(t){var e=this,i=t.persisted,n=t.elapsed;i.options.debug&&r.enable(),r("restoring!");var s=i.sessionConfig,a=s.current;s.current=null,s.pendingRequest=null,s.pendingPlay=null,this.session=new K,this.session.config=s,this.speaker=new et,this.options=i.options,this.state={paused:!0,simulcast:this.options.simulcast},this.trimming=i.trimming,this.normalizeVolume=i.normalizeVolume,this.secondsOfCrossfade=i.secondsOfCrossfade,this.crossfadeIn=i.crossfadeIn,this._stationsPromise=new Promise((function(t,i){e._stationsResolve=t,e._stationsReject=i})),this.tune=function(){var t=this;return Promise.resolve(!0).then((function(){t._station=i._station,t._stations=i._stations,t._placement=i._placement,t._stationsResolve(i._stations),t.trigger("placement",t._placement),t.trigger("station-changed",t._station),t.trigger("stations",t._stations),t.session.config.current=a,t.session.config.current.started=!1;var e=t.session.config.current.play;e.start_at=n/1e3,t.session.trigger("play-active",e),t.session.config.current.started=!0,t.state.paused=!1,t.session.trigger("play-started",e,!0),t.state.paused=!0,t.trigger("play-paused",e,!0)})).then((function(){return t._stationsPromise}))}},nt.prototype.initializeAudio=function(){r("INTIALIZE AUDIO"),this.speaker.initializeAudio()},nt.prototype._onPlacement=function(t){this._placement=t,t.options&&t.options.crossfade_seconds&&(this.secondsOfCrossfade=t.options.crossfade_seconds),this.trigger("placement",t)},nt.prototype._onStations=function(t){this._stations=t,this._stationsResolve(t),this.trigger("stations",t)},nt.prototype._onStationChanged=function(t,e){this._station=e,e.options&&"crossfade_seconds"in e.options?this.secondsOfCrossfade=e.options.crossfade_seconds:this._placement.options&&"crossfade_seconds"in this._placement.options&&(this.secondsOfCrossfade=this._placement.options.crossfade_seconds),this.trigger("station-changed",t,e)},nt.prototype.setStationId=function(t,e){var i,n=!1;!0===e?(n=e,r("SET STATION ID (WITH FADE)",t)):e&&r("SET STATION ID (WITH ADVANCE)",t,i=e),n&&this.state.activePlay&&(this.state.activePlay.fadeOnDestroy=!0),this.session.setStationId(t,i,this.crossfadeIn)},nt.prototype._onPlayActive=function(t){var e={play:this._onSoundPlay.bind(this,t.id),pause:this._onSoundPause.bind(this,t.id),finish:this._onSoundFinish.bind(this,t.id),elapse:this._onSoundElapse.bind(this,t.id)};this.normalizeVolume&&(e.gain=(t.audio_file.replaygain_track_gain||0)+(t.station.pre_gain||0)),t.start_at?e.startPosition=1e3*t.start_at:this.trimming&&t.audio_file.extra&&t.audio_file.extra.trim_start&&(e.startPosition=1e3*t.audio_file.extra.trim_start),this.trimming&&t.audio_file.extra&&t.audio_file.extra.trim_end&&t.audio_file.duration_in_seconds&&(e.endPosition=1e3*(t.audio_file.duration_in_seconds-t.audio_file.extra.trim_end)),this.secondsOfCrossfade&&(this.crossfadeIn&&(e.fadeInSeconds=this.secondsOfCrossfade),e.fadeOutSeconds=this.secondsOfCrossfade);var i=this.speaker.create(t.audio_file.url,e);(this.state.activePlay={id:t.id,sound:i,startReportedToServer:!1,soundCompleted:!1,playStarted:!1,fadeOnDestroy:!1,previousPosition:0},this.state.paused)||this.state.activePlay.sound.play()},nt.prototype._onSoundPlay=function(t){if(this.state.activePlay&&this.state.activePlay.id===t){this.state.paused=!1;var e,i,n=this.state.activePlay.playStarted;if(this.state.activePlay.playStarted=!0,!this.state.activePlay.startReportedToServer)return e=this._persist(),i=Date.now(),F("feedfm:active",JSON.stringify({state:e,timestamp:i})),F("feedfm:elapsed_time","0"),r("persisted state",{timestamp:i,state:e}),this.session.reportPlayStarted();n||this.trigger("play-resumed",this.session.getActivePlay())}else r("received sound play, but active play does not match",this.state.activePlay,t)},nt.prototype.getActivePlay=function(){return this.session.getActivePlay()},nt.prototype.hasActivePlayStarted=function(){return this.session.hasActivePlayStarted()},nt.prototype.getActivePlacement=function(){return this.session.getActivePlacement()},nt.prototype._onSoundPause=function(t){this.state.activePlay&&this.state.activePlay.id===t?(this.state.paused=!0,this.trigger("play-paused",this.session.getActivePlay())):r("received sound pause, but active play does not match",this.state.activePlay,t)},nt.prototype._onSoundFinish=function(t,e){if(this.state.activePlay&&this.state.activePlay.id===t)return this.state.activePlay.soundCompleted=!0,e&&(this.state.activePlay.soundCompletedWithError=!0,"NotAllowedError"===e.name)?(console.error('Feed.fm: first call to "initializeAudio()" or "play()" must be made in user-initiated event handler'),void this.stop()):this.state.activePlay.playStarted?void(this.state.activePlay.startReportedToServer&&(e?(r("song completed with error - marking as invalid",e),this.trigger("invalidated",t),this.session.requestInvalidate()):this.session.reportPlayCompleted())):(this.trigger("invalidated",t),void this.session.requestInvalidate());r("received sound finish, but active play does not match",this.state.activePlay,t)},nt.prototype._onSoundElapse=function(t){if(this.state.activePlay&&this.state.activePlay.id===t){var e=this.state.activePlay.sound.position(),i=Math.floor(this.state.activePlay.previousPosition/3e4),n=Math.floor(e/3e4);F("feedfm:elapsed_time",e.toString()),this.state.activePlay.previousPosition=e,n!==i&&this.session.reportPlayElapsed(Math.floor(e/1e3))}else r("received sound elapse, but active play does not match",this.state.activePlay,t)},nt.prototype._onPlayStarted=function(t){var e=this,i=this.session;this.state.activePlay&&this.state.activePlay.id===t.id?(this.state.activePlay.startReportedToServer=!0,this.state.activePlay.soundCompleted&&(r("sound completed before we finished reporting start",this.state.activePlay),this.state.activePlay.soundCompletedWithError?setTimeout((function(){e.trigger("invalidated",t.id),i.requestInvalidate()}),1):setTimeout((function(){return i.reportPlayCompleted()}),1)),this.updateSimulcast(),this.trigger("play-started",t)):r("received play started, but it does not match active play",t,this.state.activePlay)},nt.prototype._onPlayCompleted=function(t){if(this.state.activePlay&&this.state.activePlay.id===t.id){this.state.activePlay.sound.destroy(this.state.activePlay.fadeOnDestroy);var e=this.state.activePlay.playStarted;delete this.state.activePlay,e&&this.trigger("play-completed",t)}else r("received play completed, but it does not match active play",t,this.state.activePlay)},nt.prototype._onPlaysExhausted=function(){this.state.paused=!1,this.updateSimulcast(),this.trigger("plays-exhausted")},nt.prototype._onPrepareSound=function(t,e){r("preparing",t,e),this.speaker.prepare(t,1e3*e)},nt.prototype.isPaused=function(){return this.session.isTuned()&&this.state.paused},nt.prototype.getStationInformation=function(t){return this.session.getStationInformation(t)},nt.prototype.tune=function(){return r("TUNE"),this.session.isTuned()||this.session.tune(),this._stationsPromise},nt.prototype.prepare=function(){var t=this;r("PREPARE"),this.speaker.initializeAudio();var e=this.state.activePlay;return e?this.speaker.prepare(e.sound.url,e.sound.startPosition)?Promise.resolve(!0).then((function(){r("already prepared"),t.trigger("prepared")})):new Promise((function(e){r("waiting for prepared event"),t.speaker.on("prepared",(function(){return e(!0)}))})).then((function(){t.trigger("prepared")})):new Promise((function(e){t.session.once("play-active",(function(i){var n;r("play active"),i.start_at?n=1e3*i.start_at:t.trimming&&i.audio_file.extra&&i.audio_file.extra.trim_start&&(n=1e3*i.audio_file.extra.trim_start),t.speaker.prepare(i.audio_file.url,n)?(r("song is prepared!"),e(!0)):t.speaker.on("prepared",e)})),t.session.isTuned()||(r("tuning"),t.session.tune())})).then((function(){return t.trigger("prepared")}))},nt.prototype.play=function(){r("PLAY");var t=this.session,e=this.state;if(this.speaker.initializeAudio(),!t.isTuned())return e.paused=!1,t.tune();t.getActivePlay()&&e.activePlay&&e.paused&&(e.activePlay.playStarted?e.activePlay.sound.resume():e.activePlay.sound.play()),e.paused=!1,this.updateSimulcast()},nt.prototype.pause=function(){r("PAUSE"),this.session.hasActivePlayStarted()&&this.state.activePlay&&!this.state.paused&&(this.state.activePlay.sound.pause(),this.state.paused=!0,this.updateSimulcast())},nt.prototype.like=function(){r("LIKE"),this.session.hasActivePlayStarted()&&(this.session.likePlay(this.state.activePlay.id),this.trigger("play-liked"))},nt.prototype.unlike=function(){r("UNLIKE"),this.session.hasActivePlayStarted()&&(this.session.unlikePlay(this.state.activePlay.id),this.trigger("play-unliked"))},nt.prototype.dislike=function(){r("DISLIKE"),this.session.hasActivePlayStarted()&&(this.session.dislikePlay(this.state.activePlay.id),this.trigger("play-disliked"),this.state.paused=!1,this.skip())},nt.prototype.skip=function(){r("SKIP"),this.session.hasActivePlayStarted()&&(this.state.paused=!1,this.session.requestSkip())},nt.prototype.stop=function(){r("STOP"),H("feedfm:active"),H("feedfm:elapsed_time"),this.state.paused=!0;var t=this.state.activePlay;if(t&&t.sound){if(r("stopping active play",t),t.startReportedToServer){var e=t.sound.position();this.session.reportPlayStopped(Math.floor(e/1e3))}t.sound.pause(),t.sound.destroy()}else r("no active play");delete this.state.activePlay,this.speaker.flush(),this.trigger("play-stopped"),this.updateSimulcast()},nt.prototype.destroy=function(){this.session=null,this.state.activePlay&&this.state.activePlay.sound&&this.state.activePlay.sound.destroy()},nt.prototype.getCurrentState=function(){return this.session.hasActivePlayStarted()?this.state.paused?"paused":"playing":"idle"},nt.prototype.getPosition=function(){return this.state.activePlay&&this.state.activePlay.sound?this.state.activePlay.sound.position():0},nt.prototype.getDuration=function(){return this.state.activePlay&&this.state.activePlay.sound?this.state.activePlay.sound.duration():0},nt.prototype.maybeCanSkip=function(){return!!this.session.maybeCanSkip()};function st(t){return null===t?null:Object.assign({},t)}nt.prototype.isMuted=function(){return!(!it()||!("muted"in localStorage))&&"true"===localStorage.muted},nt.prototype.setMuted=function(t){t?(this.speaker.setVolume(0),it()&&(localStorage.muted=!0),this.trigger("muted")):(this.speaker.setVolume(100),it()&&(localStorage.muted=!1),this.trigger("unmuted"))},nt.prototype.getVolume=function(){return this.speaker.getVolume()},nt.prototype.setVolume=function(t){this.speaker.setVolume(t)},nt.prototype.getStations=function(){return this._stationsPromise},nt.prototype.updateSimulcast=function(){var t=this;if(this.state.simulcast){var e=this.getCurrentState();b().then((function(i){t.session._signedAjax(y()+"/api/v2/simulcast/".concat(t.state.simulcast,"/in-progress"),{method:"POST",body:JSON.stringify({state:e,client_id:i}),headers:{"Content-Type":"application/json"}})}))}},window.NodeList&&!NodeList.prototype.forEach&&(NodeList.prototype.forEach=function(t,e){e=e||window;for(var i=0;i"+t.audio_file.track.title+" by "+t.audio_file.artist.name+" on "+t.audio_file.release.title+""},at.prototype.renderStatus=function(t){var e=this;void 0!==t&&(this.displayText=t),this.alertId||this.$el.querySelectorAll(".status").forEach((function(t){t.innerHTML=e.displayText,t.classList.remove("alert")}))},at.prototype.renderPosition=function(t,e){if(this.$el.querySelectorAll(".elapsed").forEach((function(e){e.innerHTML=ot(t)})),this.$el.querySelectorAll(".duration").forEach((function(t){t.innerHTML=ot(e)})),0===e)this.$el.querySelectorAll(".progress").forEach((function(t){t.style.width="0"}));else{var i=Math.round((t+1e3)/e*100);i=i>100?100:i,this.$el.querySelectorAll(".progress").forEach((function(t){t.style.width=i+"%"}))}},at.prototype.renderAlert=function(t){this.alertId&&window.clearTimeout(this.alertId),this.$el.querySelectorAll(".status").forEach((function(e){e.innerHTML=t,e.classList.add("alert")}));var e=this;this.alertId=window.setTimeout((function(){e.alertId=null,e.renderStatus()}),3e3)},at.prototype._onSuspend=function(){this._enableButtonsBasedOnState()},at.prototype._enableButtonsBasedOnState=function(){var t,e,i=this.player.getCurrentState();switch(i){case"playing":t=[".pause-button",".like-button",".dislike-button"],e=[".play-button",".start-button",".resume-button"],this.player.maybeCanSkip()?t.push(".skip-button"):e.push(".skip-button");break;case"paused":t=[".play-button",".resume-button",".like-button",".dislike-button"],e=[".pause-button",".start-button"],this.player.maybeCanSkip()?t.push(".skip-button"):e.push(".skip-button");break;default:t=[".play-button",".start-button"],e=[".resume-button",".pause-button",".like-button",".dislike-button",".skip-button"]}var n,s=j(e);try{for(s.s();!(n=s.n()).done;){var a=n.value;this.$el.querySelectorAll(a).forEach((function(t){t.classList.remove("button-enabled"),t.classList.add("button-disabled"),t.disabled=!0}))}}catch(t){s.e(t)}finally{s.f()}var o,r=j(t);try{for(r.s();!(o=r.n()).done;){var u=o.value;this.$el.querySelectorAll(u).forEach((function(t){t.classList.remove("button-disabled"),t.classList.add("button-enabled"),t.disabled=!1}))}}catch(t){r.e(t)}finally{r.f()}var l=this.$el.classList;l.remove("state-playing"),l.remove("state-paused"),l.remove("state-idle"),l.add("state-"+i)};var rt=function(){function t(e){w(this,t),Object.assign(this,q),this._speaker=new et,this._uuid=e,this._state="idle",this._activePlay=null,this._activeSound=null,this._metadataTimeout=null,this._tryingToPlay=!1,this._retries=0}return E(t,[{key:"initializeAudio",value:function(){r("INTIALIZE AUDIO"),this._speaker.initializeAudio()}},{key:"connect",value:function(){if(r("CONNECT to ".concat(this._uuid)),this._tryingToPlay)r("ignoring pointless connect to ".concat(this._uuid));else if("idle"===this._state){this._tryingToPlay=!0,this._speaker.initializeAudio(),this._setState("connecting");var t=new URL(y());this._streamUrl="https://cast."+t.hostname+"/"+this._uuid,this._requestStream()}else r("ignoring connect() since we're already connected")}},{key:"_onSoundPlay",value:function(){var t=this;r("sound play!"),this._retries=0,this._lastElapsedAt=Date.now(),"connecting"===this._state?(this._setState("connected"),fetch(this._streamUrl+"/play?elapsed="+this._elapsed).then((function(t){return t.json()})).then((function(e){e.success?(t._activePlay=e.play,t.trigger("play-started",t._activePlay),t._scheduleMetadataTimeout()):t._scheduleMetadataTimeout(3e3)})).catch((function(){t._scheduleMetadataTimeout(2e3)}))):this._metadataTimeout||this._scheduleMetadataTimeout()}},{key:"_scheduleMetadataTimeout",value:function(){var t=this,e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1e4;this._cancelMetadataTimeout(),this._metadataTimeout=setTimeout((function(){t._onMetadataTimeout()}),e)}},{key:"_cancelMetadataTimeout",value:function(){this._metadataTimeout&&clearTimeout(this._metadataTimeout),this._metadataTimeout=null}},{key:"_onSoundElapse",value:function(){if(this._activeSound){var t=this._elapsed;(this._elapsed=this._activeSound.position())-t>0&&(this._lastElapsedAt=Date.now())}}},{key:"_requestStream",value:function(){r("requesting stream"),this._tryingToPlay&&(this._activeSound&&(this._activeSound.destroy(),this._activeSound=null),this._cancelMetadataTimeout(),this._activePlay=null,this._activeSound=this._speaker.create(this._streamUrl,{play:this._onSoundPlay.bind(this),finish:this._onSoundFinish.bind(this),elapse:this._onSoundElapse.bind(this)}),this._activeSound.play(),this._elapsed=0,this._lastElapsedAt=Date.now())}},{key:"_onMetadataTimeout",value:function(){var t=this;this._cancelMetadataTimeout(),fetch(this._streamUrl+"/play?elapsed="+this._elapsed).then((function(t){return t.json()})).then((function(e){e.success&&(null===e.play&&null!==t._activePlay||null!==e.play&&null===t._activePlay||null!==e.play&&null!==t._activePlay&&e.play.audio_file.id!==t._activePlay.audio_file.id)&&(t._activePlay=e.play,r("current play updated",t._activePlay),t.trigger("play-started",t._activePlay)),t._scheduleMetadataTimeout();var i=Date.now()-t._lastElapsedAt;i>8e3&&(r("stream has not advanced for ".concat(i," ms, so reconnecting"),t.toObject()),t._requestStream())})).catch((function(){var e=Date.now()-t._lastElapsedAt;e>8e3?(r("stream has not advanced for ".concat(e," ms, so reconnecting"),t.toObject()),t._requestStream()):t._scheduleMetadataTimeout()}))}},{key:"_onSoundFinish",value:function(t){var e=this;r("sound finished",this.toObject()),"connecting"===this._state&&t?(this._tryingToPlay=!1,this._setState("music-unavailable"),this.trigger("music-unavailable")):(r("reconnecting after stream ended",t),this._activeSound&&(this._activeSound.destroy(),this._activeSound=null),this._cancelMetadataTimeout(),this._activePlay=null,this._retries+=1,setTimeout((function(){e._tryingToPlay&&(r("retrying connection after stream ended"),e._requestStream())}),Math.pow(2,this._retries))),this._logEvents()}},{key:"disconnect",value:function(){r("DISCONNECT",this.toObject()),this._tryingToPlay&&(this._tryingToPlay=!1,this._activePlay=null,this._elapsed=0,this._cancelMetadataTimeout(),this._activeSound&&(this._activeSound.destroy(),this._activeSound=null),this._setState("idle"),this._logEvents())}},{key:"getVolume",value:function(){return this._speaker.getVolume()}},{key:"setVolume",value:function(t){this._speaker.setVolume(t)}},{key:"_setState",value:function(t){this._state!==t&&(r("state transition ".concat(this._state," -> ").concat(t)),this._state=t,this.trigger("state-changed",this._state))}},{key:"getCurrentState",value:function(){return this._state}},{key:"getCurrentPlay",value:function(){return this._activePlay}},{key:"_logEvents",value:function(){var t=r.reset();return fetch(y()+"/api/v2/session/event",{method:"POST",body:JSON.stringify({event:"playerHistory",parameters:t}),headers:{"Content-Type":"application/json","X-Feed-SDK":"1.101.1 js"}})}},{key:"toObject",value:function(){return{state:this._state,activePlay:this._activePlay,uuid:this._uuid,metadataTimeoutIsNull:null===this._metadataTimeout,tryingToPlay:this._tryingToPlay,elapsed:this._elapsed,retries:this._retries}}},{key:"toString",value:function(){return JSON.stringify(this.toString())}}]),t}();return{Speaker:et,Session:K,Player:nt,Listener:U,PlayerView:at,SimulcastPlayer:rt,log:r,version:"1.101.1",resetClientId:function(){m?_=null:a("cid"),v=null},getClientId:b,setBaseUrl:g,resumable:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:4e3,e=J(t);if(2===e.length){var i=I(e,2),n=i[0],s=i[1],a=new nt({persisted:n,elapsed:s});return a}return null}}}(); From e0cdadc23e8ad29bad3a7b3b0807be60514ebb57 Mon Sep 17 00:00:00 2001 From: Eric Lambrecht Date: Tue, 1 Mar 2022 14:01:15 -0800 Subject: [PATCH 6/8] chore: updated for country testing --- html/manual.html | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/html/manual.html b/html/manual.html index d8070f95..b59bb6d1 100644 --- a/html/manual.html +++ b/html/manual.html @@ -42,22 +42,43 @@
+
+ +
+