senza-sdk 3.21.0 → 3.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bundle.js CHANGED
@@ -1 +1 @@
1
- !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.senza=t():e.senza=t()}(this,(()=>(()=>{"use strict";var e={d:(t,n)=>{for(var i in n)e.o(n,i)&&!e.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:n[i]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},t={};e.r(t),e.d(t,{ClientAssertionError:()=>M,ConnectReason:()=>$,alarmManager:()=>S,auth:()=>N,deviceManager:()=>h,envInfo:()=>x,getClientAssertion:()=>z,getConnectReason:()=>L,getDeviceInfo:()=>Q,getPlatformInfo:()=>R,getTriggerEvent:()=>P,init:()=>q,isRunningE2E:()=>J,lifecycle:()=>c,messageManager:()=>b,remotePlayer:()=>p,setTimezone:()=>X,uiReady:()=>D,writeLicenseResponse:()=>U});var n={};e.r(n),e.d(n,{ClientAssertionError:()=>M,ConnectReason:()=>$,alarmManager:()=>S,auth:()=>N,deviceManager:()=>h,envInfo:()=>x,getClientAssertion:()=>z,getConnectReason:()=>L,getDeviceInfo:()=>Q,getPlatformInfo:()=>R,getTriggerEvent:()=>P,init:()=>q,isRunningE2E:()=>J,lifecycle:()=>c,messageManager:()=>b,remotePlayer:()=>p,setTimezone:()=>X,uiReady:()=>D,writeLicenseResponse:()=>U});const i={version:"3.21.0"},{version:s}=i;function o(){return Math.round(1e5*Math.random())+"-"+R().sessionInfo?.connectionId}class r{constructor(e){this.logFields=e}debug(...e){console.debug(this.formatLogString(e))}log(...e){console.log(this.formatLogString(e))}info(...e){console.info(this.formatLogString(e))}warn(...e){console.warn(this.formatLogString(e))}error(...e){console.error(this.formatLogString(e))}withFields(e){return new r({...this.logFields,...e})}formatLogString(e){let t="[hs-sdk] "+e.join(" ");return this.logFields&&(t+=" [log-fields] "+JSON.stringify(this.logFields)),t}}const a=new r({sdkVersion:s,url:window?.location?.href??""}),d=new class{sessionInfoStr="{}";get sessionInfoObj(){try{return JSON.parse(this.sessionInfoStr)}catch(e){return void a.warn("Failed to return sdk")}}setSessionInfoStr(e){try{JSON.parse(e)}catch(e){throw Error("Failed to parse sessionInfo")}this.sessionInfoStr=e}};class l extends EventTarget{constructor(){super(),"undefined"!=typeof document&&document.addEventListener("hs/uistatechange",(e=>{a.log("Got hs/uistatechange",e.detail);const t=new Event("onstatechange");t.state=e.detail,this.dispatchEvent(t)}))}getState(){if(window.cefQuery)return new Promise(((e,t)=>{window.cefQuery&&window.cefQuery({request:"uiState",persistent:!1,onSuccess:t=>{a.log(`uiState request successfully returned '${t}'`),e(t)},onFailure:(e,n)=>{a.error(`uiState request failed: ${e} ${n}`),t(n)}})}));a.warn("lifecycle getState is not supported if NOT running e2e")}moveToForeground(){if(window.cefQuery){const e=o(),t=a.withFields({FCID:e});t.log("lifecycle moveToForeground: sending uiActiveRequest action"),window.cefQuery({request:JSON.stringify({action:"uiActiveRequest",fcid:e}),persistent:!1,onSuccess:()=>{t.log("uiActiveRequest successfully sent")},onFailure:(e,n)=>{t.error(`uiActiveRequest failed: ${e} ${n}`)}})}else a.error("lifecycle moveToForeground: window.cefQuery is undefined")}moveToBackground(){if(window.cefQuery){const e=o(),t=a.withFields({FCID:e});t.log("lifecycle moveToBackground: sending play action"),window.cefQuery({request:JSON.stringify({action:"play",fcid:e}),persistent:!1,onSuccess:()=>{t.log("[ moveToBackground ] play successfully sent")},onFailure:(e,n)=>{t.error(`[ moveToBackground ] play failed: ${e} ${n}`)}})}else a.error("lifecycle moveToBackground: window.cefQuery is undefined")}switchTenant(e){if(e&&e.length>0){if(e===R().sessionInfo?.tenantId)return a.warn(`SwitchTenant requires a different tenantId than the current one. CurrentTenantId=${R().sessionInfo?.tenantId} and tenantId=${e}`),Promise.reject("SwitchTenant requires a different tenantId than the current one");const t=R().sessionInfo?.homeSessionInfo?.tenantInfo?.contentHubTenantId,n=R().sessionInfo?.homeSessionInfo?.tenantId;return a.log(`SwitchTenant for ${e}`),window.cefQuery?new Promise(((i,s)=>{const r=o(),d=a.withFields({FCID:r}),l={type:"reconnect",fcid:r,session:btoa(JSON.stringify({tenantId:e,...R().sessionInfo?.tenantId===t&&e!==n&&{returnToTenantId:t}}))},c={target:"TC",waitForResponse:!1,message:JSON.stringify(l)};window.cefQuery({request:JSON.stringify(c),persistent:!1,onSuccess:()=>{d.log("SwitchTenant request successfully sent"),i(!0)},onFailure:(e,t)=>{d.error(`SwitchTenant failed: ${e} ${t}`),s(`SwitchTenant failed: ${e} ${t}`)}})})):(a.warn("SwitchTenant is not supported if NOT running e2e"),Promise.reject("SwitchTenant is not supported if NOT running e2e"))}return a.warn("SwitchTenant requires a valid tenantId string parameter"),Promise.reject("SwitchTenant requires a valid tenantId string parameter")}exitApplication(){return window.cefQuery?new Promise(((e,t)=>{const n=o(),i=a.withFields({FCID:n});let s,r;const l=d.sessionInfoObj;l?.homeSessionInfo&&(l?.returnToTenantId||l?.homeSessionInfo.tenantId!==l?.tenantId)?(r={type:"reconnect",splashUrl:l?.homeSessionInfo.tenantInfo.tenantSettings.applicationSwitchSplashUrl,fcid:n},l?.returnToTenantId&&(l?.returnToTenantId===l?.homeSessionInfo.tenantInfo.contentHubTenantId&&(r.splashUrl=l?.homeSessionInfo.contentHubTenantInfo.tenantSettings.applicationSwitchSplashUrl),r.session=btoa(JSON.stringify({tenantId:l?.returnToTenantId}))),s={target:"TC",waitForResponse:!1,message:JSON.stringify(r)}):(r={type:"launchHomeApplication",fcid:n},s={target:"UI-Streamer",waitForResponse:!1,message:JSON.stringify(r)}),window.cefQuery({request:JSON.stringify(s),persistent:!1,onSuccess:()=>{i.log(`exitApplication request with type: '${r.type}' successfully sent`),e(!0)},onFailure:(e,n)=>{i.error(`exitApplication request with type: '${r.type}' failed: ${e} ${n}`),t(`exitApplication request with type: '${r.type}' failed: ${e} ${n}`)}})})):(a.warn("exitApplication is not supported if NOT running e2e"),Promise.reject("exitApplication is not supported if NOT running e2e"))}}const c=new l,u=e=>JSON.parse(JSON.stringify(e));class f extends Error{constructor(e,t){super(t),this.code=e,this.msg=t}}function g(){const e=window.getPlaybackInfo?window.getPlaybackInfo():JSON.stringify({playbackPosition:0,assetDuration:0});let t;try{t=JSON.parse(e)}catch(n){a.error(`Playback Info parse failed. playbackStr = ${e}`),t={playbackPosition:0,assetDuration:0}}return t}class y extends EventTarget{constructor(){super(),this._config={preferredAudioLanguage:"",preferredSubtitlesLanguage:""},this._selectedAudioTrack="",this._selectedSubtitlesTrack="",this._availableAudioTracks=[],this._availableTextTracks=[],this._textTrackVisibility=!1,this._ptsSessionId=0,this._videoElement=void 0,this._isInitialized=!1,"undefined"!=typeof document&&document.addEventListener("hs/playbackInfoEvent",(()=>{a.info("Got hs/playbackInfoEvent"),this.dispatchEvent(new Event("timeupdate"))})),"undefined"!=typeof document&&document.addEventListener("hs/playback",(e=>{a.info("Got hs/playback event with detail",JSON.stringify(e?.detail)),this._availabilityStartTime=e?.detail?.availabilityStartTime,this._updateTracks(e?.detail),this.dispatchEvent(new Event("tracksupdate"))})),"undefined"!=typeof document&&document.addEventListener("EOS",(()=>{a.info("Got EOS event"),this.dispatchEvent(new Event("ended"))})),"undefined"!=typeof document&&document.addEventListener("hs/EOS",(()=>{a.info("Got hs/EOS event"),this.dispatchEvent(new Event("ended"))})),"undefined"!=typeof document&&document.addEventListener("hs/ui_inactive",(()=>{a.info("Got hs/ui_inactive event")})),"undefined"!=typeof document&&document.addEventListener("hs/senzaPlayerSetRate",(e=>{this._videoElement&&(this._videoElement.playbackRate=e.detail.rate)})),"undefined"!=typeof document&&document.addEventListener("ERR",(e=>{delete e?.detail?.type,delete e?.detail?.eventCode,a.info("Got ERR event",JSON.stringify(e?.detail)),this.dispatchEvent(new CustomEvent("error",e))})),"undefined"!=typeof document&&document.addEventListener("hs/ERR",(e=>{a.info("Got hs/ERR event"),delete e?.detail?.type,delete e?.detail?.eventCode,this.dispatchEvent(new CustomEvent("error",e))})),"undefined"!=typeof document&&document.addEventListener("hs/getLicense",(e=>{a.info("Got hs/getLicense event");const t=e?.detail,n=Uint8Array.from(t.request,(e=>e.charCodeAt(0))),i=new ArrayBuffer(n.byteLength);new Uint8Array(i).set(n),this.licenseRequest=i;const s=t.fcid,o=t.sessionId,r=new CustomEvent("license-request",{detail:{licenseRequest:i}});r.writeLicenseResponse=(e,t)=>{U(e,t,s,o)},this.dispatchEvent(r)}))}LoadMode=Object.freeze({NOT_LOADED:"notLoaded",LOADING:"loading",LOADED:"loaded"});async _init(e,t){let n={isLoaded:!1,playbackUrl:""};if(window.cefQuery){const e=o(),t=a.withFields({FCID:e}),i={type:"playerState",fcid:e},s={target:"UI-Streamer",waitForResponse:!1,message:JSON.stringify(i)};try{const e=await new Promise(((e,n)=>{window.cefQuery({request:JSON.stringify(s),persistent:!1,onSuccess:n=>{t.log("playerState request successfully returned",n),e(n)},onFailure:(e,i)=>{t.error(`playerState request failed: ${e} ${i}`),n()}})}));n=JSON.parse(e)}catch{t.error("either failed to get or failed to parse player state")}}this._loadMode=n?.isLoaded?this.LoadMode.LOADED:this.LoadMode.NOT_LOADED,this._loadedUrl=n?.playbackUrl||"",this._isInitialized=!0,this._setPlayableUriTimeout=e?.setPlayableUriTimeout??5e3,this._requestVideoFrameInfo=e?.requestVideoFrameInfo??!0;let i={};try{i=JSON.parse(t?.playbackMetadata||"{}")}catch(e){a.error(`failed to parse playbackMetadata: ${e.message}`)}this._availabilityStartTime=i.availabilityStartTime,this._updateTracks(i)}_updateTracks(e){if(this._availableAudioTracks=e?.availableAudioTracks||this._availableAudioTracks,this._availableTextTracks=e?.availableSubtitlesTracks||this._availableTextTracks,"VOD"===e?.assetType&&(this._availableTextTracks=function(e){if(!e||e.length<1)return e;e.sort(((e,t)=>e.lang.toLowerCase()>t.lang.toLowerCase()?1:-1));const t=[{lang:"af",id:"*:af"},{lang:"ar",id:"*:ar"},{lang:"az",id:"*:az"},{lang:"bg",id:"*:bg"},{lang:"bs",id:"*:bs"},{lang:"ca",id:"*:ca"},{lang:"cs",id:"*:cs"},{lang:"cy",id:"*:cy"},{lang:"da",id:"*:da"},{lang:"de",id:"*:de"},{lang:"el",id:"*:el"},{lang:"en",id:"*:en"},{lang:"es",id:"*:es"},{lang:"es-MX",id:"*:es-MX"},{lang:"et",id:"*:et"},{lang:"fi",id:"*:fi"},{lang:"fr",id:"*:fr"},{lang:"fr-CA",id:"*:fr-CA"},{lang:"ga",id:"*:ga"},{lang:"ha",id:"*:ha"},{lang:"he",id:"*:he"},{lang:"hr",id:"*:hr"},{lang:"ht",id:"*:ht"},{lang:"hu",id:"*:hu"},{lang:"id",id:"*:id"},{lang:"is",id:"*:is"},{lang:"it",id:"*:it"},{lang:"kk",id:"*:kk"},{lang:"lt",id:"*:lt"},{lang:"lv",id:"*:lv"},{lang:"mk",id:"*:mk"},{lang:"mn",id:"*:mn"},{lang:"ms",id:"*:ms"},{lang:"mt",id:"*:mt"},{lang:"nl",id:"*:nl"},{lang:"no",id:"*:no"},{lang:"pl",id:"*:pl"},{lang:"pt",id:"*:pt"},{lang:"pt-PT",id:"*:pt-PT"},{lang:"ro",id:"*:ro"},{lang:"ru",id:"*:ru"},{lang:"sk",id:"*:sk"},{lang:"sl",id:"*:sl"},{lang:"so",id:"*:so"},{lang:"sq",id:"*:sq"},{lang:"sr",id:"*:sr"},{lang:"sv",id:"*:sv"},{lang:"sw",id:"*:sw"},{lang:"tl",id:"*:tl"},{lang:"tr",id:"*:tr"},{lang:"uk",id:"*:uk"},{lang:"uz",id:"*:uz"},{lang:"vi",id:"*:vi"},{lang:"zh",id:"*:zh"}],n=[...e];for(const i of t)e.find((e=>e.lang===i.lang))||(i.autoTranslate=!0,n.push(i));return n}(this._availableTextTracks)),this._availableAudioTracks){const e=this._availableAudioTracks.find((e=>!0===e.selected));this._selectedAudioTrack=e?.id||""}if(this._availableTextTracks){const e=this._availableTextTracks.find((e=>!0===e.selected));e?(this._selectedSubtitlesTrack=e.id,this._textTrackVisibility=!0):(this._selectedSubtitlesTrack="",this._textTrackVisibility=!1)}}getConfiguration(){return u(this._config)}configure(e){Object.entries(e).forEach((([e,t])=>{void 0!==this._config[e]&&(this._config[e]=t)}))}_changeLoadMode(e){this._loadMode!==e&&(this._loadMode=e,this.dispatchEvent(new Event("onloadmodechange")))}_handle_video_frame_info(e){if(!this._requestVideoFrameInfo||void 0===e)return void(this._videoElement=void 0);const t=o(),n=a.withFields({fcid:t}),i=(e,n)=>{const s={type:"currentFramePTS",fcid:t,currentFramePTS:n.mediaTime.toString(),ptsSessionId:this._ptsSessionId},o={target:"UI-Streamer",waitForResponse:!1,message:JSON.stringify(s)};window.cefQuery({request:JSON.stringify(o),persistent:!1}),this._videoElement?.requestVideoFrameCallback(i)};n.log("handle_video_frame_pts: requesting video frame info"),void 0!==this._videoElement&&this._videoElement===e||(e.requestVideoFrameCallback(i),e.addEventListener("loadstart",(e=>{this._ptsSessionId++,a.info("videoElement, loadstart ptsSessionId=",this._ptsSessionId," event=",e)}))),this._videoElement=e}_reset(){this._availableAudioTracks=[],this._availableTextTracks=[],this._selectedAudioTrack="",this._selectedSubtitlesTrack="",this._availabilityStartTime=void 0}registerVideoElement(e){this._handle_video_frame_info(e)}async load(e,t){if(!this._isInitialized)throw new f(6500,"Cannot call load() if remote player is not initialized");if(e&&window.cefQuery){const n=await c.getState();if("background"===n||"inTransitionToBackground"===n)throw new f(6002,"Cannot call load() while in state 'background' or 'inTransitionToBackground'");if(this._loadMode===this.LoadMode.LOADING)throw new f(6501,"Cannot call load() while previous load is still in progress");this._reset();const i=this._loadMode;return this._changeLoadMode(this.LoadMode.LOADING),new Promise(((n,s)=>{this.currentTime=0;const r=o(),d=t??0,l=a.withFields({FCID:r,loadUrl:e,playbackPosition:d});l.log("remotePlayer load: sending setPlayableUri request");const c={type:"setPlayableUri",url:e,timeout:this._setPlayableUriTimeout,autoPlay:!1,playbackPosition:d,fcid:r},u={target:"TC",waitForResponse:!0,message:JSON.stringify(c)};let g=0;const y=Date.now(),p=window.cefQuery({request:JSON.stringify(u),persistent:!1,onSuccess:()=>{const i=Date.now()-y;l.withFields({duration:i}).log(`setPlayableUri completed successfully after ${i} ms`),t>0&&(this.currentTime=t),g&&(clearTimeout(g),g=0),this._changeLoadMode(this.LoadMode.LOADED),this._loadedUrl=e,n()},onFailure:(e,t)=>{const n=Date.now()-y;l.withFields({duration:n}).log(`setPlayableUri failed after ${n} ms. Error code: ${e}, error message: ${t}`),g&&(clearTimeout(g),g=0),99===e?this._changeLoadMode(i):(this._changeLoadMode(this.LoadMode.NOT_LOADED),this._loadedUrl=""),s(new f(e,t))}});l.log(`window.cefQuery for setPlayableUri returned query id ${p}`);const w=this._setPlayableUriTimeout+1e3;g=setTimeout((()=>{l.log(`setPlayableUri reached timeout of ${w} ms, canceling query id ${p}`),window.cefQueryCancel(p),this._changeLoadMode(this.LoadMode.NOT_LOADED),this._loadedUrl="",s(new f(6e3,`load reached timeout of ${w} ms`))}),w,p)}))}a.error("remotePlayer load: either window.cefQuery or url is undefined")}unload(){a.warn("unload() api is deprecated since version 3.14.0, no need to call unload() anymore at the end of playback")}play(e=!0){if(!this._isInitialized)throw new f(6500,"Cannot call play() if remote player is not initialized");if(window.cefQuery){if(this._loadMode!==this.LoadMode.LOADED)throw new f(6001,"Cannot call play() if player is not loaded");const t=o(),n=a.withFields({FCID:t});n.log("remotePlayer play: sending play action");const i=this._selectedAudioTrack||this._config.preferredAudioLanguage||"";let s="";if(this._textTrackVisibility&&(s=this._selectedSubtitlesTrack||this._config.preferredSubtitlesLanguage||""),e)window.cefQuery({request:JSON.stringify({action:"play",fcid:t,audioLanguage:i,subtitlesLanguage:s}),persistent:!1,onSuccess:()=>{n.log("play action was successfully sent")},onFailure:(e,t)=>{n.log(`failed to send play action: ${e} ${t}`)}});else{const e={type:"remotePlayer.play",class:"remotePlayer",action:"play",fcid:t,audioLanguage:i,subtitlesLanguage:s,playbackPosition:this.currentTime},o={target:"TC",waitForResponse:!1,message:JSON.stringify(e)};window.cefQuery({request:JSON.stringify(o),persistent:!1,onSuccess:()=>{n.log("remotePlayer play request successfully sent")},onFailure:(e,t)=>{n.error(`remotePlayer play request failed: ${e} ${t}`)}})}}else a.error("remotePlayer play: window.cefQuery is undefined")}pause(){if(!this._isInitialized)throw new f(6500,"Cannot call pause() if remote player is not initialized");if(window.cefQuery){if(this._loadMode!==this.LoadMode.LOADED)throw new f(6001,"Cannot call pause() if player is not loaded");const e=o(),t=a.withFields({FCID:e});t.log("remotePlayer pause: sending pause request");const n={type:"remotePlayer.pause",class:"remotePlayer",action:"pause",fcid:e},i={target:"TC",waitForResponse:!1,message:JSON.stringify(n)};window.cefQuery({request:JSON.stringify(i),persistent:!1,onSuccess:()=>{t.log("remotePlayer pause request successfully sent")},onFailure:(e,n)=>{t.error(`remotePlayer pause request failed: ${e} ${n}`)}})}else a.error("remotePlayer pause: window.cefQuery is undefined")}getAssetUri(){if(!this._isInitialized)throw new f(6500,"Cannot call getAssetUri() if remote player is not initialized");return this._loadedUrl}getLoadMode(){if(!this._isInitialized)throw new f(6500,"Cannot call getLoadMode() if remote player is not initialized");return this._loadMode}getTextTracks(){return u(this._availableTextTracks)}getAudioTracks(){return u(this._availableAudioTracks)}selectAudioTrack(e){for(const t of this.getAudioTracks())if(t.id===e)return void(this._selectedAudioTrack=e);a.warn(`Invalid audioTrackId ${e}`)}selectTextTrack(e){for(const t of this.getTextTracks())if(t.id===e)return void(this._selectedSubtitlesTrack=e);a.warn(`Invalid textTrackId ${e}`)}setTextTrackVisibility(e){const t=this._textTrackVisibility;if("boolean"!=typeof e)throw new TypeError("visible parameter must be a boolean");const n=e;n!==t&&(this._textTrackVisibility=n,n||(this._selectedSubtitlesTrack=""))}get currentTime(){return g()?.playbackPosition}set currentTime(e){!function(e){try{const t=JSON.stringify(e);window.setPlaybackInfo&&window.setPlaybackInfo(t)}catch(e){a.error("Playback Info to json string failed")}}({playbackPosition:e})}get duration(){return g()?.assetDuration}get textTrackVisibility(){return this._textTrackVisibility}getPresentationStartTimeAsDate(){return void 0===this._availabilityStartTime?null:new Date(1e3*this._availabilityStartTime)}}const p=new y;"undefined"!=typeof window&&(window.remotePlayer=p);const w={};class m extends EventTarget{constructor(){super(),w.level=0,w.quality=0,w.ssid="unknown",w.bssid="unknown","undefined"!=typeof document&&document.addEventListener("wifiSignalReport",(e=>{a.log("Got wifiSignalReport",JSON.stringify(e.detail)),w.level=e.detail.level,w.quality=e.detail.quality,w.ssid=e.detail.ssid,w.bssid=e.detail.bssid,this.dispatchEvent(new Event("wifiInfoUpdated"))}))}get deviceInfo(){const e=d.sessionInfoObj;return J()&&e?{deviceId:e.deviceId,connectionId:e.connectionId,community:e.community,tenant:e.tenant,clientIp:e.clientIp,countryCode:e.general?.location?.["x-country-code"]}:(a.log("getDeviceInfo running locally, returning dummy info"),{deviceId:"123456789",connectionId:"dummy",community:"LocalDev",tenant:"XXXXXX",clientIp:"0.0.0.0",countryCode:"XX"})}get wifiInfo(){return w}reboot(){return new Promise(((e,t)=>{if(window.cefQuery){const n=o(),i=a.withFields({FCID:n}),s={type:"reboot",fcid:n},r={target:"TC",waitForResponse:!1,message:JSON.stringify(s)};window.cefQuery({request:JSON.stringify(r),persistent:!1,onSuccess:()=>{i.log("reboot request successfully sent"),e(!0)},onFailure:(e,n)=>{i.error(`reboot failed: ${e} ${n}`),t(`reboot failed: ${e} ${n}`)}})}else a.warn("reboot is not supported if NOT running e2e"),t("reboot is not supported if NOT running e2e")}))}clearWifi(){return new Promise(((e,t)=>{const n=o(),i=a.withFields({FCID:n}),s={type:"resetWifi",fcid:n},r={target:"TC",waitForResponse:!1,message:JSON.stringify(s)};window.cefQuery({request:JSON.stringify(r),persistent:!1,onSuccess:()=>{i.log("clearWifi successfully sent"),e(!0)},onFailure:(e,n)=>{i.error(`clearWifi failed: ${e} ${n}`),t(`clearWifi failed: ${e} ${n}`)}})}))}sendDataToDevice(e){if("string"!=typeof e)throw new Error("data must be of type 'string'");return new Promise(((t,n)=>{const i=o(),s=a.withFields({FCID:i}),r={type:"externalCommand",data:{command:"forward",payload:e},fcid:i},d={target:"TC",waitForResponse:!1,message:JSON.stringify(r)};window.cefQuery({request:JSON.stringify(d),persistent:!1,onSuccess:()=>{s.log("externalCommand successfully sent"),t()},onFailure:(e,t)=>{s.error(`externalCommand failed: ${e} ${t}`),n(`externalCommand failed: ${e} ${t}`)}})}))}async factoryReset(e=!0){if("boolean"!=typeof e)throw new Error("reboot param must be of type 'boolean'");return new Promise(((t,n)=>{const i=o(),s=a.withFields({FCID:i}),r={type:"factoryReset",fcid:i,reboot:e},d={target:"TC",waitForResponse:!0,message:JSON.stringify(r)};let l=0;const c=window.cefQuery({request:JSON.stringify(d),persistent:!1,onSuccess:()=>{l&&clearTimeout(l),s.log("factoryReset successfully sent"),t(!0)},onFailure:(e,t)=>{l&&clearTimeout(l),s.error(`factoryReset failed: ${e} ${t}`),n(`factoryReset failed: ${e} ${t}`)}});l=setTimeout((()=>{s.error("factoryReset failed: reached timeout of 5000 ms"),window.cefQueryCancel(c),n("factoryReset failed: reached timeout of 5000 ms")}),5e3)}))}}const h=new m;class v extends EventTarget{constructor(){super(),"undefined"!=typeof document&&document.addEventListener("hs/alarmFiredEvent",(e=>{a.log("Got hs/alarmFiredEvent",JSON.stringify(e.detail)),e.detail?.alarmName&&this.dispatchEvent(new CustomEvent(e.detail.alarmName,{detail:e.detail.payload}))}))}addAlarm(e,t,n){if("string"!=typeof n)throw Error("data must be a string");const i=o(),s=a.withFields({alarmName:e,FCID:i});if(s.log(`addAlarm called for ${e} to be fired at ${t}`),window.cefQuery){const o={type:"addAlarm",fcid:i,alarmName:e,alarmTime:t,payload:n},r={target:"TC",waitForResponse:!1,message:JSON.stringify(o)};window.cefQuery({request:JSON.stringify(r),persistent:!1,onSuccess:()=>{s.log("addAlarm request successfully sent")},onFailure:(e,t)=>{s.error(`addAlarm failed: ${e} ${t}`)}})}else s.warn("addAlarm is not supported if NOT running e2e")}deleteAlarm(e){const t=o(),n=a.withFields({alarmName:e,FCID:t});if(n.log(`deleteAlarm called for ${e}`),window.cefQuery){const i={type:"deleteAlarm",fcid:t,alarmName:e},s={target:"TC",waitForResponse:!1,message:JSON.stringify(i)};window.cefQuery({request:JSON.stringify(s),persistent:!1,onSuccess:()=>{n.log("deleteAlarm request successfully sent")},onFailure:(e,t)=>{n.error(`deleteAlarm failed: ${e} ${t}`)}})}else n.warn("deleteAlarm is not supported if NOT running e2e")}deleteAllAlarms(){if(window.cefQuery){const e=o(),t=a.withFields({FCID:e}),n={type:"deleteAllAlarms",fcid:e},i={target:"TC",waitForResponse:!1,message:JSON.stringify(n)};window.cefQuery({request:JSON.stringify(i),persistent:!1,onSuccess:()=>{t.log("deleteAllAlarms request successfully sent")},onFailure:(e,n)=>{t.error(`deleteAllAlarms failed: ${e} ${n}`)}})}else a.warn("deleteAllAlarms is not supported if NOT running e2e")}getActiveAlarms(){throw Error("NOT IMPLEMENTED")}}const S=new v;"undefined"!=typeof window&&(window.alarmManager=S);class T extends EventTarget{constructor(){super(),"undefined"!=typeof document&&document.addEventListener("hs/externalEvent",(e=>{a.log("Got hs/externalEvent",JSON.stringify(e.detail)),this.dispatchEvent(new CustomEvent("message",{detail:{eventName:e.detail.eventName,payload:e.detail.payload,fcid:e.detail.fcid}}))}))}async registerGroups(e){return a.log(`register called for ${e}`),new Promise(((t,n)=>{if(window.cefQuery){const i=o(),s=a.withFields({FCID:i}),r={type:"registerGroupEvent",fcid:i,groups:e},d={target:"UI-Streamer",waitForResponse:!1,message:JSON.stringify(r)};window.cefQuery({request:JSON.stringify(d),persistent:!1,onSuccess:()=>{s.log("registerGroupEvent request successfully sent"),t(!0)},onFailure:(e,t)=>{s.error(`registerGroupEvent failed: ${e} ${t}`),n(`registerGroupEvent failed: ${e} ${t}`)}})}else a.warn("registerGroupEvent is not supported if NOT running e2e"),n("registerGroupEvent is not supported if NOT running e2e")}))}}const b=new T;let I,k;"undefined"!=typeof window&&(window.messageManager=b),c.getState()?.then((e=>{k=e})),c.addEventListener("onstatechange",(e=>{k=e.state}));const E=e=>{"background"!==k&&"inTransitionToBackground"!==k||(I&&clearTimeout(I),I=setTimeout((()=>{"background"!==k&&"inTransitionToBackground"!==k||a.log(`${e.type} event received while in '${k}' state and there was no call to lifecycle.moveToForeground() for 500 ms. Make sure to call it if you want to move to foreground.`),I=0}),500))};"undefined"!=typeof document&&document.addEventListener("keydown",E),p.addEventListener("error",E),p.addEventListener("ended",E);const{version:_}=i;let O;const F="1.0";"undefined"!=typeof document&&document.addEventListener("keydown",(e=>{a.log(`Got ${e.key} key`)}));const N={getToken:async function(){return O?Promise.resolve(O):(a.log("getToken wait for promise updateSession event"),new Promise((e=>{document.addEventListener("updateSession",(t=>{O=t.detail?.updateObj,a.log(`onUpdateSessionEvent: token= ${O}`),e(O)}),{once:!0})})))},forceTokenUpdate:function(){if(O=null,window.cefQuery){const e=o(),t=a.withFields({FCID:e});t.log("forceTokenUpdate: sending updateSessionRequest");const n={type:"updateSessionRequest",updateKey:"authorization",parentPath:"settings.webUI.backendHeaders.Authorization",fcid:e},i={target:"TC",waitForResponse:!1,message:JSON.stringify(n)};window.cefQuery({request:JSON.stringify(i),persistent:!1,onSuccess:()=>{t.log("updateSessionRequest successfully sent")},onFailure:(e,n)=>{t.error(`updateSessionRequest failed: ${e} ${n}`)}})}else a.error("forceTokenUpdate: window.cefQuery is undefined")},getClientAssertion:z},$=Object.freeze({UNKNOWN:"unknown",INITIAL_CONNECTION:"initial_connection",UI_RELEASE:"ui_release",UI_TERMINATION:"ui_termination",WEBRTC_ERROR:"webrtc_error",UI_WATCHDOG:"ui_watchdog"});let C=$.UNKNOWN,A={};async function q(){if(a.log(`init ${_}`),window.diagnostics||a.error("[ init ] window.diagnostics is undefined"),window.cefQuery){await new Promise(((e,t)=>{window.cefQuery({request:"apiVersion "+F,persistent:!1,onSuccess:()=>{a.log("api version compatability check succeeded"),e()},onFailure:(e,n)=>{a.error("api version compatability check failed: "+n),t(n)}})}));const e=await new Promise((e=>{window.cefQuery({request:"sessionInfo",persistent:!1,onSuccess:t=>{a.log("sessionInfo request successfully returned "+t),e(t)},onFailure:(e,t)=>{a.error(`sessionInfo request failed: ${e} ${t}`)}})}));d.setSessionInfoStr(e);const t=JSON.parse(e);O=t?.settings?.webUI?.backendHeaders?.Authorization,a.log(`authToken: token = ${O}`),document.addEventListener("updateSession",(e=>{O=e.detail?.updateObj,a.log(`onUpdateSessionEvent: token = ${O}`)})),t?.settings?.["ui-streamer"]?.enableKeyPressDuration&&function(){const e=document.createElement("div");e.setAttribute("style","height: 8px; width: 8px; background-color: red; position: absolute; left: 0px; top: 0px; z-index: 9999;"),document.body.appendChild(e),document.addEventListener("keydown",(()=>{"red"===e.style.backgroundColor?e.style.backgroundColor="blue":"blue"===e.style.backgroundColor?e.style.backgroundColor="green":e.style.backgroundColor="red"}))}(),C=await new Promise((e=>{const t=o(),n=a.withFields({FCID:t}),i={type:"connectReason",fcid:t},s={target:"UI-Streamer",waitForResponse:!1,message:JSON.stringify(i)};window.cefQuery({request:JSON.stringify(s),persistent:!1,onSuccess:t=>{n.log(`connectReason request successfully returned '${t}'`),e(t)},onFailure:(t,i)=>{n.error(`connectReason request failed: ${t} ${i}`),e($.UNKNOWN)}})}));const n=await new Promise((e=>{const t=o(),n=a.withFields({FCID:t}),i={type:"triggerEvent",fcid:t},s={target:"UI-Streamer",waitForResponse:!1,message:JSON.stringify(i)};window.cefQuery({request:JSON.stringify(s),persistent:!1,onSuccess:t=>{n.log(`triggerEvent request successfully returned '${t}'`),e(t)},onFailure:(t,i)=>{n.error(`triggerEvent request failed: ${t} ${i}`),e("")}})}));A={};let i={};if(n)try{i=JSON.parse(n),A.type=i.type,"keyPressEvent"===A.type?A.data={keyValue:i.keyValue}:"alarmFiredEvent"===A.type?A.data={alarmName:i.alarmName,payload:i.payload}:"userAlertEvent"===A.type?A.data={eventCode:i.eventCode,message:i.message}:"externalEvent"===A.type?A.data={eventName:i.eventName,payload:i.payload}:"videoPlaybackEvent"===A.type?A.data={eventCode:i.eventCode,errorCode:i.errorCode}:a.warn("unknown trigger event type",A.type)}catch(e){a.error(`failed to parse trigger event string ${n}: ${e.message}`)}await p._init(t?.settings?.["ui-streamer"],i)}else O=R().sessionInfo?.settings?.webUI?.backendHeaders?.Authorization,a.log(`authToken dummy: token = ${O}`);window.auth=N,window.close=()=>{a.warn("window.close is disabled on Senza platform. Use lifecycle.exitApplication() instead.")}}function L(){return C}function P(){return A}function R(){if("undefined"==typeof window||!window.diagnostics)return"undefined"==typeof window||window.diagnostics||a.error("[ getPlatformInfo ] window.diagnostics is undefined"),{version:"X.X.XX-X",pod:"ui-streamer-X.X.XX-X-QWERT-ASDFG-XXX-XXXXXX-XXXXX",podIP:"0.0.0.0",sessionInfo:{userAgent:"SynamediaSenza/XX.YY.ZZ",connectionId:"dummy",deviceId:"123456789",community:"LocalDev",tenant:"XXXXXX",tenantId:"XXXXXX",manifest:{transcontainer:"X.X.XX-X"},settings:{webUI:{backendHeaders:{Authorization:"Bearer dummytoken"}}},homeSessionInfo:{tenantId:"XXXXXX",community:"LocalDev"}}};try{const e=window.diagnostics()||{};return e.sessionInfo=d.sessionInfoObj,e}catch(e){a.error("Could not get platform info",e.stack)}}function X(e){if(window.cefQuery){const t={message:JSON.stringify({type:"setTimeZone",timezone:e}),waitForResponse:!1,target:"UI-Streamer"};window.cefQuery({request:JSON.stringify(t),persistent:!1,onSuccess:()=>{a.log("timezome is successfully set to",e)},onFailure:(t,n)=>{a.error(`error occurred setting timezone to ${e}: ${t} ${n}`)}})}}function J(){return!("undefined"==typeof window||!window.cefQuery)}function D(){window.cefQuery?window.cefQuery({request:"uiReady",persistent:!1,onSuccess:()=>{a.log("uiReady request successfully sent")},onFailure:(e,t)=>{a.error(`uiReady request failed: ${e} ${t}`)}}):a.error("uiReady: window.cefQuery is undefined")}function Q(){const e=d.sessionInfoObj;return J()?{deviceId:e.deviceId,connectionId:e.connectionId,community:e.community,tenant:e.tenant,clientIp:e.clientIp}:(a.log("getDeviceInfo running locally, returning dummy info"),{deviceId:"123456789",connectionId:"dummy",community:"LocalDev",tenant:"XXXXXX",clientIp:"0.0.0.0"})}const x={remoteBrowserIp:window.diagnostics?window.diagnostics().podIP:"127.0.0.1",sdkVersion:_};function U(e,t,n,i){if(200===e&&(t=window.btoa(String.fromCharCode.apply(null,new Uint8Array(t)))),window.cefQuery){const s={type:"updateLicense",sessionId:i,fcid:n};s[200===e?"response":"error"]=t;const o={target:"TC",waitForResponse:!1,message:JSON.stringify(s)};window.cefQuery({request:JSON.stringify(o),persistent:!1,onSuccess:()=>{a.log("updateLicense request successfully sent")},onFailure:(e,t)=>{a.error(`updateLicense request failed: ${e} ${t}`)}})}}class M extends Error{constructor(e,t){super(t),this.code=e}}function z(){if(window.cefQuery)return a.log("getClientAssertion is called"),new Promise(((e,t)=>{window.cefQuery({request:"client_assertion",persistent:!1,onSuccess:n=>{try{const t=JSON.parse(n);a.log(`client_assertion request successfully returned ${n}`),e(t)}catch(e){a.error(`Failed to parse client assertion ${n}`),t(new M(0,"Failed to parse client assertion"))}},onFailure:(e,n)=>{a.log(`client_assertion request failed: ${e} ${n}`),t(new M(e,n))}})}));a.warn("getClientAssertion is not supported if NOT running e2e")}return"undefined"!=typeof window&&(window.hs=n),t})()));
1
+ !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.senza=t():e.senza=t()}(this,(()=>(()=>{"use strict";var e={d:(t,n)=>{for(var i in n)e.o(n,i)&&!e.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:n[i]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},t={};e.r(t),e.d(t,{ClientAssertionError:()=>G,ConnectReason:()=>C,alarmManager:()=>I,auth:()=>A,deviceManager:()=>h,envInfo:()=>M,getClientAssertion:()=>j,getConnectReason:()=>R,getDeviceInfo:()=>U,getPlatformInfo:()=>X,getTriggerEvent:()=>J,init:()=>P,isRunningE2E:()=>Q,lifecycle:()=>c,messageManager:()=>k,platformManager:()=>S,remotePlayer:()=>p,setTimezone:()=>D,uiReady:()=>x,writeLicenseResponse:()=>z});var n={};e.r(n),e.d(n,{ClientAssertionError:()=>G,ConnectReason:()=>C,alarmManager:()=>I,auth:()=>A,deviceManager:()=>h,envInfo:()=>M,getClientAssertion:()=>j,getConnectReason:()=>R,getDeviceInfo:()=>U,getPlatformInfo:()=>X,getTriggerEvent:()=>J,init:()=>P,isRunningE2E:()=>Q,lifecycle:()=>c,messageManager:()=>k,platformManager:()=>S,remotePlayer:()=>p,setTimezone:()=>D,uiReady:()=>x,writeLicenseResponse:()=>z});const i={version:"3.22.1"},{version:s}=i;function o(){return Math.round(1e5*Math.random())+"-"+X().sessionInfo?.connectionId}class r{constructor(e){this.logFields=e}debug(...e){console.debug(this.formatLogString(e))}log(...e){console.log(this.formatLogString(e))}info(...e){console.info(this.formatLogString(e))}warn(...e){console.warn(this.formatLogString(e))}error(...e){console.error(this.formatLogString(e))}withFields(e){return new r({...this.logFields,...e})}formatLogString(e){let t="[hs-sdk] "+e.join(" ");return this.logFields&&(t+=" [log-fields] "+JSON.stringify(this.logFields)),t}}const a=new r({sdkVersion:s,url:window?.location?.href??""}),d=new class{sessionInfoStr="{}";get sessionInfoObj(){try{return JSON.parse(this.sessionInfoStr)}catch(e){return void a.warn("Failed to return sdk")}}setSessionInfoStr(e){try{JSON.parse(e)}catch(e){throw Error("Failed to parse sessionInfo")}this.sessionInfoStr=e}};class l extends EventTarget{constructor(){super(),"undefined"!=typeof document&&document.addEventListener("hs/uistatechange",(e=>{a.log("Got hs/uistatechange",e.detail);const t=new Event("onstatechange");t.state=e.detail,this.dispatchEvent(t)}))}getState(){if(window.cefQuery)return new Promise(((e,t)=>{window.cefQuery&&window.cefQuery({request:"uiState",persistent:!1,onSuccess:t=>{a.log(`uiState request successfully returned '${t}'`),e(t)},onFailure:(e,n)=>{a.error(`uiState request failed: ${e} ${n}`),t(n)}})}));a.warn("lifecycle getState is not supported if NOT running e2e")}moveToForeground(){if(window.cefQuery){const e=o(),t=a.withFields({FCID:e});t.log("lifecycle moveToForeground: sending uiActiveRequest action"),window.cefQuery({request:JSON.stringify({action:"uiActiveRequest",fcid:e}),persistent:!1,onSuccess:()=>{t.log("uiActiveRequest successfully sent")},onFailure:(e,n)=>{t.error(`uiActiveRequest failed: ${e} ${n}`)}})}else a.error("lifecycle moveToForeground: window.cefQuery is undefined")}moveToBackground(){if(window.cefQuery){const e=o(),t=a.withFields({FCID:e});t.log("lifecycle moveToBackground: sending play action"),window.cefQuery({request:JSON.stringify({action:"play",fcid:e}),persistent:!1,onSuccess:()=>{t.log("[ moveToBackground ] play successfully sent")},onFailure:(e,n)=>{t.error(`[ moveToBackground ] play failed: ${e} ${n}`)}})}else a.error("lifecycle moveToBackground: window.cefQuery is undefined")}switchTenant(e){if(e&&e.length>0){if(e===X().sessionInfo?.tenantId)return a.warn(`SwitchTenant requires a different tenantId than the current one. CurrentTenantId=${X().sessionInfo?.tenantId} and tenantId=${e}`),Promise.reject("SwitchTenant requires a different tenantId than the current one");const t=X().sessionInfo?.homeSessionInfo?.tenantInfo?.contentHubTenantId,n=X().sessionInfo?.homeSessionInfo?.tenantId;return a.log(`SwitchTenant for ${e}`),window.cefQuery?new Promise(((i,s)=>{const r=o(),d=a.withFields({FCID:r}),l={type:"reconnect",fcid:r,session:btoa(JSON.stringify({tenantId:e,...X().sessionInfo?.tenantId===t&&e!==n&&{returnToTenantId:t}}))},c={target:"TC",waitForResponse:!1,message:JSON.stringify(l)};window.cefQuery({request:JSON.stringify(c),persistent:!1,onSuccess:()=>{d.log("SwitchTenant request successfully sent"),i(!0)},onFailure:(e,t)=>{d.error(`SwitchTenant failed: ${e} ${t}`),s(`SwitchTenant failed: ${e} ${t}`)}})})):(a.warn("SwitchTenant is not supported if NOT running e2e"),Promise.reject("SwitchTenant is not supported if NOT running e2e"))}return a.warn("SwitchTenant requires a valid tenantId string parameter"),Promise.reject("SwitchTenant requires a valid tenantId string parameter")}exitApplication(){return window.cefQuery?new Promise(((e,t)=>{const n=o(),i=a.withFields({FCID:n});let s,r;const l=d.sessionInfoObj;l?.homeSessionInfo&&(l?.returnToTenantId||l?.homeSessionInfo.tenantId!==l?.tenantId)?(r={type:"reconnect",splashUrl:l?.homeSessionInfo.tenantInfo.tenantSettings.applicationSwitchSplashUrl,fcid:n},l?.returnToTenantId&&(l?.returnToTenantId===l?.homeSessionInfo.tenantInfo.contentHubTenantId&&(r.splashUrl=l?.homeSessionInfo.contentHubTenantInfo.tenantSettings.applicationSwitchSplashUrl),r.session=btoa(JSON.stringify({tenantId:l?.returnToTenantId}))),s={target:"TC",waitForResponse:!1,message:JSON.stringify(r)}):(r={type:"launchHomeApplication",fcid:n},s={target:"UI-Streamer",waitForResponse:!1,message:JSON.stringify(r)}),window.cefQuery({request:JSON.stringify(s),persistent:!1,onSuccess:()=>{i.log(`exitApplication request with type: '${r.type}' successfully sent`),e(!0)},onFailure:(e,n)=>{i.error(`exitApplication request with type: '${r.type}' failed: ${e} ${n}`),t(`exitApplication request with type: '${r.type}' failed: ${e} ${n}`)}})})):(a.warn("exitApplication is not supported if NOT running e2e"),Promise.reject("exitApplication is not supported if NOT running e2e"))}}const c=new l,u=e=>JSON.parse(JSON.stringify(e));class f extends Error{constructor(e,t){super(t),this.code=e,this.msg=t}}function g(){const e=window.getPlaybackInfo?window.getPlaybackInfo():JSON.stringify({playbackPosition:0,assetDuration:0});let t;try{t=JSON.parse(e)}catch(n){a.error(`Playback Info parse failed. playbackStr = ${e}`),t={playbackPosition:0,assetDuration:0}}return t}class y extends EventTarget{constructor(){super(),this._config={preferredAudioLanguage:"",preferredSubtitlesLanguage:""},this._selectedAudioTrack="",this._selectedSubtitlesTrack="",this._availableAudioTracks=[],this._availableTextTracks=[],this._textTrackVisibility=!1,this._ptsSessionId=0,this._videoElement=void 0,this._isInitialized=!1,this._defaultAutoBackground=!0,"undefined"!=typeof document&&document.addEventListener("hs/playbackInfoEvent",(()=>{a.info("Got hs/playbackInfoEvent"),this.dispatchEvent(new Event("timeupdate"))})),"undefined"!=typeof document&&document.addEventListener("hs/playback",(e=>{a.info("Got hs/playback event with detail",JSON.stringify(e?.detail)),this._availabilityStartTime=e?.detail?.availabilityStartTime,this._updateTracks(e?.detail),this.dispatchEvent(new Event("tracksupdate"))})),"undefined"!=typeof document&&document.addEventListener("EOS",(()=>{a.info("Got EOS event"),this.dispatchEvent(new Event("ended"))})),"undefined"!=typeof document&&document.addEventListener("hs/EOS",(()=>{a.info("Got hs/EOS event"),this.dispatchEvent(new Event("ended"))})),"undefined"!=typeof document&&document.addEventListener("hs/ui_inactive",(()=>{a.info("Got hs/ui_inactive event")})),"undefined"!=typeof document&&document.addEventListener("hs/senzaPlayerSetRate",(e=>{this._videoElement&&(this._videoElement.playbackRate=e.detail.rate)})),"undefined"!=typeof document&&document.addEventListener("ERR",(e=>{delete e?.detail?.type,delete e?.detail?.eventCode,a.info("Got ERR event",JSON.stringify(e?.detail)),this.dispatchEvent(new CustomEvent("error",e))})),"undefined"!=typeof document&&document.addEventListener("hs/ERR",(e=>{a.info("Got hs/ERR event"),delete e?.detail?.type,delete e?.detail?.eventCode,this.dispatchEvent(new CustomEvent("error",e))})),"undefined"!=typeof document&&document.addEventListener("hs/getLicense",(e=>{a.info("Got hs/getLicense event");const t=e?.detail,n=Uint8Array.from(t.request,(e=>e.charCodeAt(0))),i=new ArrayBuffer(n.byteLength);new Uint8Array(i).set(n),this.licenseRequest=i;const s=t.fcid,o=t.sessionId,r=new CustomEvent("license-request",{detail:{licenseRequest:i}});r.writeLicenseResponse=(e,t)=>{z(e,t,s,o)},this.dispatchEvent(r)}))}LoadMode=Object.freeze({NOT_LOADED:"notLoaded",LOADING:"loading",LOADED:"loaded"});async _init(e,t){let n={isLoaded:!1,playbackUrl:""};if(window.cefQuery){const e=o(),t=a.withFields({FCID:e}),i={type:"playerState",fcid:e},s={target:"UI-Streamer",waitForResponse:!1,message:JSON.stringify(i)};try{const e=await new Promise(((e,n)=>{window.cefQuery({request:JSON.stringify(s),persistent:!1,onSuccess:n=>{t.log("playerState request successfully returned",n),e(n)},onFailure:(e,i)=>{t.error(`playerState request failed: ${e} ${i}`),n()}})}));n=JSON.parse(e)}catch{t.error("either failed to get or failed to parse player state")}}this._loadMode=n?.isLoaded?this.LoadMode.LOADED:this.LoadMode.NOT_LOADED,this._loadedUrl=n?.playbackUrl||"",this._isInitialized=!0,this._setPlayableUriTimeout=e?.setPlayableUriTimeout??5e3,this._requestVideoFrameInfo=e?.requestVideoFrameInfo??!0,this._defaultAutoBackground=e?.playAutoBackground??!0;let i={};try{i=JSON.parse(t?.playbackMetadata||"{}")}catch(e){a.error(`failed to parse playbackMetadata: ${e.message}`)}this._availabilityStartTime=i.availabilityStartTime,this._updateTracks(i)}_updateTracks(e){if(this._availableAudioTracks=e?.availableAudioTracks||this._availableAudioTracks,this._availableTextTracks=e?.availableSubtitlesTracks||this._availableTextTracks,"VOD"===e?.assetType&&(this._availableTextTracks=function(e){if(!e||e.length<1)return e;e.sort(((e,t)=>e.lang.toLowerCase()>t.lang.toLowerCase()?1:-1));const t=[{lang:"af",id:"*:af"},{lang:"ar",id:"*:ar"},{lang:"az",id:"*:az"},{lang:"bg",id:"*:bg"},{lang:"bs",id:"*:bs"},{lang:"ca",id:"*:ca"},{lang:"cs",id:"*:cs"},{lang:"cy",id:"*:cy"},{lang:"da",id:"*:da"},{lang:"de",id:"*:de"},{lang:"el",id:"*:el"},{lang:"en",id:"*:en"},{lang:"es",id:"*:es"},{lang:"es-MX",id:"*:es-MX"},{lang:"et",id:"*:et"},{lang:"fi",id:"*:fi"},{lang:"fr",id:"*:fr"},{lang:"fr-CA",id:"*:fr-CA"},{lang:"ga",id:"*:ga"},{lang:"ha",id:"*:ha"},{lang:"he",id:"*:he"},{lang:"hr",id:"*:hr"},{lang:"ht",id:"*:ht"},{lang:"hu",id:"*:hu"},{lang:"id",id:"*:id"},{lang:"is",id:"*:is"},{lang:"it",id:"*:it"},{lang:"kk",id:"*:kk"},{lang:"lt",id:"*:lt"},{lang:"lv",id:"*:lv"},{lang:"mk",id:"*:mk"},{lang:"mn",id:"*:mn"},{lang:"ms",id:"*:ms"},{lang:"mt",id:"*:mt"},{lang:"nl",id:"*:nl"},{lang:"no",id:"*:no"},{lang:"pl",id:"*:pl"},{lang:"pt",id:"*:pt"},{lang:"pt-PT",id:"*:pt-PT"},{lang:"ro",id:"*:ro"},{lang:"ru",id:"*:ru"},{lang:"sk",id:"*:sk"},{lang:"sl",id:"*:sl"},{lang:"so",id:"*:so"},{lang:"sq",id:"*:sq"},{lang:"sr",id:"*:sr"},{lang:"sv",id:"*:sv"},{lang:"sw",id:"*:sw"},{lang:"tl",id:"*:tl"},{lang:"tr",id:"*:tr"},{lang:"uk",id:"*:uk"},{lang:"uz",id:"*:uz"},{lang:"vi",id:"*:vi"},{lang:"zh",id:"*:zh"}],n=[...e];for(const i of t)e.find((e=>e.lang===i.lang))||(i.autoTranslate=!0,n.push(i));return n}(this._availableTextTracks)),this._availableAudioTracks){const e=this._availableAudioTracks.find((e=>!0===e.selected));this._selectedAudioTrack=e?.id||""}if(this._availableTextTracks){const e=this._availableTextTracks.find((e=>!0===e.selected));e?(this._selectedSubtitlesTrack=e.id,this._textTrackVisibility=!0):(this._selectedSubtitlesTrack="",this._textTrackVisibility=!1)}}getConfiguration(){return u(this._config)}configure(e){Object.entries(e).forEach((([e,t])=>{void 0!==this._config[e]&&(this._config[e]=t)}))}_changeLoadMode(e){this._loadMode!==e&&(this._loadMode=e,this.dispatchEvent(new Event("onloadmodechange")))}_handle_video_frame_info(e){if(!this._requestVideoFrameInfo||void 0===e)return void(this._videoElement=void 0);const t=o(),n=a.withFields({fcid:t}),i=(e,n)=>{const s={type:"currentFramePTS",fcid:t,currentFramePTS:n.mediaTime.toString(),ptsSessionId:this._ptsSessionId},o={target:"UI-Streamer",waitForResponse:!1,message:JSON.stringify(s)};window.cefQuery({request:JSON.stringify(o),persistent:!1}),this._videoElement?.requestVideoFrameCallback(i)};n.log("handle_video_frame_pts: requesting video frame info"),void 0!==this._videoElement&&this._videoElement===e||(e.requestVideoFrameCallback(i),e.addEventListener("loadstart",(e=>{this._ptsSessionId++,a.info("videoElement, loadstart ptsSessionId=",this._ptsSessionId," event=",e)}))),this._videoElement=e}_reset(){this._availableAudioTracks=[],this._availableTextTracks=[],this._selectedAudioTrack="",this._selectedSubtitlesTrack="",this._availabilityStartTime=void 0}registerVideoElement(e){this.attach(e)}attach(e){this._handle_video_frame_info(e)}async load(e,t){if(!this._isInitialized)throw new f(6500,"Cannot call load() if remote player is not initialized");if(e&&window.cefQuery){const n=await c.getState();if("background"===n||"inTransitionToBackground"===n)throw new f(6002,"Cannot call load() while in state 'background' or 'inTransitionToBackground'");if(this._loadMode===this.LoadMode.LOADING)throw new f(6501,"Cannot call load() while previous load is still in progress");this._reset();const i=this._loadMode;return this._changeLoadMode(this.LoadMode.LOADING),new Promise(((n,s)=>{this.currentTime=0;const r=o(),d=t??0,l=a.withFields({FCID:r,loadUrl:e,playbackPosition:d});l.log("remotePlayer load: sending setPlayableUri request");const c={type:"setPlayableUri",url:e,timeout:this._setPlayableUriTimeout,autoPlay:!1,playbackPosition:d,fcid:r},u={target:"TC",waitForResponse:!0,message:JSON.stringify(c)};let g=0;const y=Date.now(),p=window.cefQuery({request:JSON.stringify(u),persistent:!1,onSuccess:()=>{const i=Date.now()-y;l.withFields({duration:i}).log(`setPlayableUri completed successfully after ${i} ms`),t>0&&(this.currentTime=t),g&&(clearTimeout(g),g=0),this._changeLoadMode(this.LoadMode.LOADED),this._loadedUrl=e,this.dispatchEvent(new Event("canPlay")),n()},onFailure:(e,t)=>{const n=Date.now()-y;l.withFields({duration:n}).log(`setPlayableUri failed after ${n} ms. Error code: ${e}, error message: ${t}`),g&&(clearTimeout(g),g=0),99===e?this._changeLoadMode(i):(this._changeLoadMode(this.LoadMode.NOT_LOADED),this._loadedUrl=""),s(new f(e,t))}});l.log(`window.cefQuery for setPlayableUri returned query id ${p}`);const w=this._setPlayableUriTimeout+1e3;g=setTimeout((()=>{l.log(`setPlayableUri reached timeout of ${w} ms, canceling query id ${p}`),window.cefQueryCancel(p),this._changeLoadMode(this.LoadMode.NOT_LOADED),this._loadedUrl="",s(new f(6e3,`load reached timeout of ${w} ms`))}),w,p)}))}a.error("remotePlayer load: either window.cefQuery or url is undefined")}unload(){a.warn("unload() api is deprecated since version 3.14.0, no need to call unload() anymore at the end of playback")}play(e){if(!this._isInitialized)throw new f(6500,"Cannot call play() if remote player is not initialized");if(window.cefQuery){if(this._loadMode!==this.LoadMode.LOADED)throw new f(6001,"Cannot call play() if player is not loaded");const t=o(),n=a.withFields({FCID:t});n.log("remotePlayer play: sending play action");const i=this._selectedAudioTrack||this._config.preferredAudioLanguage||"";let s="";if(this._textTrackVisibility&&(s=this._selectedSubtitlesTrack||this._config.preferredSubtitlesLanguage||""),e??this._config.autoBackground??this._defaultAutoBackground)window.cefQuery({request:JSON.stringify({action:"play",fcid:t,audioLanguage:i,subtitlesLanguage:s}),persistent:!1,onSuccess:()=>{n.log("play action was successfully sent")},onFailure:(e,t)=>{n.log(`failed to send play action: ${e} ${t}`)}});else{const e={type:"remotePlayer.play",class:"remotePlayer",action:"play",fcid:t,audioLanguage:i,subtitlesLanguage:s,playbackPosition:this.currentTime},o={target:"TC",waitForResponse:!1,message:JSON.stringify(e)};window.cefQuery({request:JSON.stringify(o),persistent:!1,onSuccess:()=>{n.log("remotePlayer play request successfully sent")},onFailure:(e,t)=>{n.error(`remotePlayer play request failed: ${e} ${t}`)}})}}else a.error("remotePlayer play: window.cefQuery is undefined")}pause(){if(!this._isInitialized)throw new f(6500,"Cannot call pause() if remote player is not initialized");if(window.cefQuery){if(this._loadMode!==this.LoadMode.LOADED)throw new f(6001,"Cannot call pause() if player is not loaded");const e=o(),t=a.withFields({FCID:e});t.log("remotePlayer pause: sending pause request");const n={type:"remotePlayer.pause",class:"remotePlayer",action:"pause",fcid:e},i={target:"TC",waitForResponse:!1,message:JSON.stringify(n)};window.cefQuery({request:JSON.stringify(i),persistent:!1,onSuccess:()=>{t.log("remotePlayer pause request successfully sent")},onFailure:(e,n)=>{t.error(`remotePlayer pause request failed: ${e} ${n}`)}})}else a.error("remotePlayer pause: window.cefQuery is undefined")}getAssetUri(){if(!this._isInitialized)throw new f(6500,"Cannot call getAssetUri() if remote player is not initialized");return this._loadedUrl}getLoadMode(){if(!this._isInitialized)throw new f(6500,"Cannot call getLoadMode() if remote player is not initialized");return this._loadMode}getTextTracks(){return u(this._availableTextTracks)}getAudioTracks(){return u(this._availableAudioTracks)}selectAudioTrack(e){for(const t of this.getAudioTracks())if(t.id===e)return void(this._selectedAudioTrack=e);a.warn(`Invalid audioTrackId ${e}`)}selectTextTrack(e){for(const t of this.getTextTracks())if(t.id===e)return void(this._selectedSubtitlesTrack=e);a.warn(`Invalid textTrackId ${e}`)}setTextTrackVisibility(e){const t=this._textTrackVisibility;if("boolean"!=typeof e)throw new TypeError("visible parameter must be a boolean");const n=e;n!==t&&(this._textTrackVisibility=n,n||(this._selectedSubtitlesTrack=""))}get currentTime(){return g()?.playbackPosition}set currentTime(e){!function(e){try{const t=JSON.stringify(e);window.setPlaybackInfo&&window.setPlaybackInfo(t)}catch(e){a.error("Playback Info to json string failed")}}({playbackPosition:e})}get duration(){return g()?.assetDuration}get textTrackVisibility(){return this._textTrackVisibility}getPresentationStartTimeAsDate(){return void 0===this._availabilityStartTime?null:new Date(1e3*this._availabilityStartTime)}}const p=new y;"undefined"!=typeof window&&(window.remotePlayer=p);const w={};class m extends EventTarget{constructor(){super(),w.level=0,w.quality=0,w.ssid="unknown",w.bssid="unknown","undefined"!=typeof document&&document.addEventListener("wifiSignalReport",(e=>{a.log("Got wifiSignalReport",JSON.stringify(e.detail)),w.level=e.detail.level,w.quality=e.detail.quality,w.ssid=e.detail.ssid,w.bssid=e.detail.bssid,this.dispatchEvent(new Event("wifiInfoUpdated"))}))}get deviceInfo(){const e=d.sessionInfoObj;return Q()&&e?{deviceId:e.deviceId,connectionId:e.connectionId,community:e.community,tenant:e.tenant,clientIp:e.clientIp,countryCode:e.general?.location?.["x-country-code"]}:(a.log("getDeviceInfo running locally, returning dummy info"),{deviceId:"123456789",connectionId:"dummy",community:"LocalDev",tenant:"XXXXXX",clientIp:"0.0.0.0",countryCode:"XX"})}get wifiInfo(){return w}reboot(){return new Promise(((e,t)=>{if(window.cefQuery){const n=o(),i=a.withFields({FCID:n}),s={type:"reboot",fcid:n},r={target:"TC",waitForResponse:!1,message:JSON.stringify(s)};window.cefQuery({request:JSON.stringify(r),persistent:!1,onSuccess:()=>{i.log("reboot request successfully sent"),e(!0)},onFailure:(e,n)=>{i.error(`reboot failed: ${e} ${n}`),t(`reboot failed: ${e} ${n}`)}})}else a.warn("reboot is not supported if NOT running e2e"),t("reboot is not supported if NOT running e2e")}))}clearWifi(){return new Promise(((e,t)=>{const n=o(),i=a.withFields({FCID:n}),s={type:"resetWifi",fcid:n},r={target:"TC",waitForResponse:!1,message:JSON.stringify(s)};window.cefQuery({request:JSON.stringify(r),persistent:!1,onSuccess:()=>{i.log("clearWifi successfully sent"),e(!0)},onFailure:(e,n)=>{i.error(`clearWifi failed: ${e} ${n}`),t(`clearWifi failed: ${e} ${n}`)}})}))}sendDataToDevice(e){if("string"!=typeof e)throw new Error("data must be of type 'string'");return new Promise(((t,n)=>{const i=o(),s=a.withFields({FCID:i}),r={type:"externalCommand",data:{command:"forward",payload:e},fcid:i},d={target:"TC",waitForResponse:!1,message:JSON.stringify(r)};window.cefQuery({request:JSON.stringify(d),persistent:!1,onSuccess:()=>{s.log("externalCommand successfully sent"),t()},onFailure:(e,t)=>{s.error(`externalCommand failed: ${e} ${t}`),n(`externalCommand failed: ${e} ${t}`)}})}))}async factoryReset(e=!0){if("boolean"!=typeof e)throw new Error("reboot param must be of type 'boolean'");return new Promise(((t,n)=>{const i=o(),s=a.withFields({FCID:i}),r={type:"factoryReset",fcid:i,reboot:e},d={target:"TC",waitForResponse:!0,message:JSON.stringify(r)};let l=0;const c=window.cefQuery({request:JSON.stringify(d),persistent:!1,onSuccess:()=>{l&&clearTimeout(l),s.log("factoryReset successfully sent"),t(!0)},onFailure:(e,t)=>{l&&clearTimeout(l),s.error(`factoryReset failed: ${e} ${t}`),n(`factoryReset failed: ${e} ${t}`)}});l=setTimeout((()=>{s.error("factoryReset failed: reached timeout of 5000 ms"),window.cefQueryCancel(c),n("factoryReset failed: reached timeout of 5000 ms")}),5e3)}))}}const h=new m;class v extends EventTarget{constructor(){super()}get appConfig(){const e=d.sessionInfoObj,t=e.homeSessionInfo?.appConfig||{};return a.info("PlatformManager get appConfig: \n"+JSON.stringify(t,null,2)),t}setTimezone(e){if(window.cefQuery){const t={message:JSON.stringify({type:"setTimeZone",timezone:e}),waitForResponse:!1,target:"UI-Streamer"};window.cefQuery({request:JSON.stringify(t),persistent:!1,onSuccess:()=>{a.log("PlatformManager timezome is successfully set to",e)},onFailure:(t,n)=>{a.error(`PlatformManager error occurred setting timezone to ${e}: ${t} ${n}`)}})}}}const S=new v;class T extends EventTarget{constructor(){super(),"undefined"!=typeof document&&document.addEventListener("hs/alarmFiredEvent",(e=>{a.log("Got hs/alarmFiredEvent",JSON.stringify(e.detail)),e.detail?.alarmName&&this.dispatchEvent(new CustomEvent(e.detail.alarmName,{detail:e.detail.payload}))}))}addAlarm(e,t,n=""){if("string"!=typeof n)throw Error("data must be a string");const i=o(),s=a.withFields({alarmName:e,FCID:i});if(s.log(`addAlarm called for ${e} to be fired at ${t}`),window.cefQuery){const o={type:"addAlarm",fcid:i,alarmName:e,alarmTime:t,payload:n},r={target:"TC",waitForResponse:!1,message:JSON.stringify(o)};window.cefQuery({request:JSON.stringify(r),persistent:!1,onSuccess:()=>{s.log("addAlarm request successfully sent")},onFailure:(e,t)=>{s.error(`addAlarm failed: ${e} ${t}`)}})}else s.warn("addAlarm is not supported if NOT running e2e")}deleteAlarm(e){const t=o(),n=a.withFields({alarmName:e,FCID:t});if(n.log(`deleteAlarm called for ${e}`),window.cefQuery){const i={type:"deleteAlarm",fcid:t,alarmName:e},s={target:"TC",waitForResponse:!1,message:JSON.stringify(i)};window.cefQuery({request:JSON.stringify(s),persistent:!1,onSuccess:()=>{n.log("deleteAlarm request successfully sent")},onFailure:(e,t)=>{n.error(`deleteAlarm failed: ${e} ${t}`)}})}else n.warn("deleteAlarm is not supported if NOT running e2e")}deleteAllAlarms(){if(window.cefQuery){const e=o(),t=a.withFields({FCID:e}),n={type:"deleteAllAlarms",fcid:e},i={target:"TC",waitForResponse:!1,message:JSON.stringify(n)};window.cefQuery({request:JSON.stringify(i),persistent:!1,onSuccess:()=>{t.log("deleteAllAlarms request successfully sent")},onFailure:(e,n)=>{t.error(`deleteAllAlarms failed: ${e} ${n}`)}})}else a.warn("deleteAllAlarms is not supported if NOT running e2e")}getActiveAlarms(){throw Error("NOT IMPLEMENTED")}}const I=new T;"undefined"!=typeof window&&(window.alarmManager=I);class b extends EventTarget{constructor(){super(),"undefined"!=typeof document&&document.addEventListener("hs/externalEvent",(e=>{a.log("Got hs/externalEvent",JSON.stringify(e.detail)),this.dispatchEvent(new CustomEvent("message",{detail:{eventName:e.detail.eventName,payload:e.detail.payload,fcid:e.detail.fcid}}))}))}async registerGroups(e){return a.log(`register called for ${e}`),new Promise(((t,n)=>{if(window.cefQuery){const i=o(),s=a.withFields({FCID:i}),r={type:"registerGroupEvent",fcid:i,groups:e},d={target:"UI-Streamer",waitForResponse:!1,message:JSON.stringify(r)};window.cefQuery({request:JSON.stringify(d),persistent:!1,onSuccess:()=>{s.log("registerGroupEvent request successfully sent"),t(!0)},onFailure:(e,t)=>{s.error(`registerGroupEvent failed: ${e} ${t}`),n(`registerGroupEvent failed: ${e} ${t}`)}})}else a.warn("registerGroupEvent is not supported if NOT running e2e"),n("registerGroupEvent is not supported if NOT running e2e")}))}}const k=new b;let E,_;"undefined"!=typeof window&&(window.messageManager=k),c.getState()?.then((e=>{_=e})),c.addEventListener("onstatechange",(e=>{_=e.state}));const O=e=>{"background"!==_&&"inTransitionToBackground"!==_||(E&&clearTimeout(E),E=setTimeout((()=>{"background"!==_&&"inTransitionToBackground"!==_||a.log(`${e.type} event received while in '${_}' state and there was no call to lifecycle.moveToForeground() for 500 ms. Make sure to call it if you want to move to foreground.`),E=0}),500))};"undefined"!=typeof document&&document.addEventListener("keydown",O),p.addEventListener("error",O),p.addEventListener("ended",O);const{version:N}=i;let F;const $="1.0";"undefined"!=typeof document&&document.addEventListener("keydown",(e=>{a.log(`Got ${e.key} key`)}));const A={getToken:async function(){return F?Promise.resolve(F):(a.log("getToken wait for promise updateSession event"),new Promise((e=>{document.addEventListener("updateSession",(t=>{F=t.detail?.updateObj,a.log(`onUpdateSessionEvent: token= ${F}`),e(F)}),{once:!0})})))},forceTokenUpdate:function(){if(F=null,window.cefQuery){const e=o(),t=a.withFields({FCID:e});t.log("forceTokenUpdate: sending updateSessionRequest");const n={type:"updateSessionRequest",updateKey:"authorization",parentPath:"settings.webUI.backendHeaders.Authorization",fcid:e},i={target:"TC",waitForResponse:!1,message:JSON.stringify(n)};window.cefQuery({request:JSON.stringify(i),persistent:!1,onSuccess:()=>{t.log("updateSessionRequest successfully sent")},onFailure:(e,n)=>{t.error(`updateSessionRequest failed: ${e} ${n}`)}})}else a.error("forceTokenUpdate: window.cefQuery is undefined")},getClientAssertion:j},C=Object.freeze({UNKNOWN:"unknown",INITIAL_CONNECTION:"initial_connection",UI_RELEASE:"ui_release",UI_TERMINATION:"ui_termination",WEBRTC_ERROR:"webrtc_error",UI_WATCHDOG:"ui_watchdog"});let q=C.UNKNOWN,L={};async function P(){if(a.log(`init ${N}`),window.diagnostics||a.error("[ init ] window.diagnostics is undefined"),window.cefQuery){await new Promise(((e,t)=>{window.cefQuery({request:"apiVersion "+$,persistent:!1,onSuccess:()=>{a.log("api version compatability check succeeded"),e()},onFailure:(e,n)=>{a.error("api version compatability check failed: "+n),t(n)}})}));const e=await new Promise((e=>{window.cefQuery({request:"sessionInfo",persistent:!1,onSuccess:t=>{a.log("sessionInfo request successfully returned "+t),e(t)},onFailure:(e,t)=>{a.error(`sessionInfo request failed: ${e} ${t}`)}})}));d.setSessionInfoStr(e);const t=JSON.parse(e);F=t?.settings?.webUI?.backendHeaders?.Authorization,a.log(`authToken: token = ${F}`),document.addEventListener("updateSession",(e=>{F=e.detail?.updateObj,a.log(`onUpdateSessionEvent: token = ${F}`)})),t?.settings?.["ui-streamer"]?.enableKeyPressDuration&&function(){const e=document.createElement("div");e.setAttribute("style","height: 8px; width: 8px; background-color: red; position: absolute; left: 0px; top: 0px; z-index: 9999;"),document.body.appendChild(e),document.addEventListener("keydown",(()=>{"red"===e.style.backgroundColor?e.style.backgroundColor="blue":"blue"===e.style.backgroundColor?e.style.backgroundColor="green":e.style.backgroundColor="red"}))}(),q=await new Promise((e=>{const t=o(),n=a.withFields({FCID:t}),i={type:"connectReason",fcid:t},s={target:"UI-Streamer",waitForResponse:!1,message:JSON.stringify(i)};window.cefQuery({request:JSON.stringify(s),persistent:!1,onSuccess:t=>{n.log(`connectReason request successfully returned '${t}'`),e(t)},onFailure:(t,i)=>{n.error(`connectReason request failed: ${t} ${i}`),e(C.UNKNOWN)}})}));const n=await new Promise((e=>{const t=o(),n=a.withFields({FCID:t}),i={type:"triggerEvent",fcid:t},s={target:"UI-Streamer",waitForResponse:!1,message:JSON.stringify(i)};window.cefQuery({request:JSON.stringify(s),persistent:!1,onSuccess:t=>{n.log(`triggerEvent request successfully returned '${t}'`),e(t)},onFailure:(t,i)=>{n.error(`triggerEvent request failed: ${t} ${i}`),e("")}})}));L={};let i={};if(n)try{i=JSON.parse(n),L.type=i.type,"keyPressEvent"===L.type?L.data={keyValue:i.keyValue}:"alarmFiredEvent"===L.type?L.data={alarmName:i.alarmName,payload:i.payload}:"userAlertEvent"===L.type?L.data={eventCode:i.eventCode,message:i.message}:"externalEvent"===L.type?L.data={eventName:i.eventName,payload:i.payload}:"videoPlaybackEvent"===L.type?L.data={eventCode:i.eventCode,errorCode:i.errorCode}:a.warn("unknown trigger event type",L.type)}catch(e){a.error(`failed to parse trigger event string ${n}: ${e.message}`)}await p._init(t?.settings?.["ui-streamer"],i)}else F=X().sessionInfo?.settings?.webUI?.backendHeaders?.Authorization,a.log(`authToken dummy: token = ${F}`);window.auth=A,window.close=()=>{a.warn("window.close is disabled on Senza platform. Use lifecycle.exitApplication() instead.")}}function R(){return q}function J(){return L}function X(){if("undefined"==typeof window||!window.diagnostics)return"undefined"==typeof window||window.diagnostics||a.error("[ getPlatformInfo ] window.diagnostics is undefined"),{version:"X.X.XX-X",pod:"ui-streamer-X.X.XX-X-QWERT-ASDFG-XXX-XXXXXX-XXXXX",podIP:"0.0.0.0",sessionInfo:{userAgent:"SynamediaSenza/XX.YY.ZZ",connectionId:"dummy",deviceId:"123456789",community:"LocalDev",tenant:"XXXXXX",tenantId:"XXXXXX",manifest:{transcontainer:"X.X.XX-X"},settings:{webUI:{backendHeaders:{Authorization:"Bearer dummytoken"}}},homeSessionInfo:{tenantId:"XXXXXX",community:"LocalDev"}}};try{const e=window.diagnostics()||{};return e.sessionInfo=d.sessionInfoObj,e}catch(e){a.error("Could not get platform info",e.stack)}}function D(e){if(window.cefQuery){const t={message:JSON.stringify({type:"setTimeZone",timezone:e}),waitForResponse:!1,target:"UI-Streamer"};window.cefQuery({request:JSON.stringify(t),persistent:!1,onSuccess:()=>{a.log("timezome is successfully set to",e)},onFailure:(t,n)=>{a.error(`error occurred setting timezone to ${e}: ${t} ${n}`)}})}}function Q(){return!("undefined"==typeof window||!window.cefQuery)}function x(){window.cefQuery?window.cefQuery({request:"uiReady",persistent:!1,onSuccess:()=>{a.log("uiReady request successfully sent")},onFailure:(e,t)=>{a.error(`uiReady request failed: ${e} ${t}`)}}):a.error("uiReady: window.cefQuery is undefined")}function U(){const e=d.sessionInfoObj;return Q()?{deviceId:e.deviceId,connectionId:e.connectionId,community:e.community,tenant:e.tenant,clientIp:e.clientIp}:(a.log("getDeviceInfo running locally, returning dummy info"),{deviceId:"123456789",connectionId:"dummy",community:"LocalDev",tenant:"XXXXXX",clientIp:"0.0.0.0"})}const M={remoteBrowserIp:window.diagnostics?window.diagnostics().podIP:"127.0.0.1",sdkVersion:N};function z(e,t,n,i){if(200===e&&(t=window.btoa(String.fromCharCode.apply(null,new Uint8Array(t)))),window.cefQuery){const s={type:"updateLicense",sessionId:i,fcid:n};s[200===e?"response":"error"]=t;const o={target:"TC",waitForResponse:!1,message:JSON.stringify(s)};window.cefQuery({request:JSON.stringify(o),persistent:!1,onSuccess:()=>{a.log("updateLicense request successfully sent")},onFailure:(e,t)=>{a.error(`updateLicense request failed: ${e} ${t}`)}})}}class G extends Error{constructor(e,t){super(t),this.code=e}}function j(){if(window.cefQuery)return a.log("getClientAssertion is called"),new Promise(((e,t)=>{window.cefQuery({request:"client_assertion",persistent:!1,onSuccess:n=>{try{const t=JSON.parse(n);a.log(`client_assertion request successfully returned ${n}`),e(t)}catch(e){a.error(`Failed to parse client assertion ${n}`),t(new G(0,"Failed to parse client assertion"))}},onFailure:(e,n)=>{a.log(`client_assertion request failed: ${e} ${n}`),t(new G(e,n))}})}));a.warn("getClientAssertion is not supported if NOT running e2e")}return"undefined"!=typeof window&&(window.hs=n),t})()));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "senza-sdk",
3
- "version": "3.21.0",
3
+ "version": "3.22.1",
4
4
  "main": "./src/api.js",
5
5
  "description": "API for Senza application",
6
6
  "license": "MIT",
@@ -45,4 +45,4 @@
45
45
  }
46
46
  }
47
47
  }
48
- }
48
+ }
@@ -34,7 +34,7 @@ class AlarmManager extends EventTarget {
34
34
  * @param {string} [data] data to be passed back when the alarm is fired
35
35
  *
36
36
  * */
37
- addAlarm(alarmName, alarmTime, data) {
37
+ addAlarm(alarmName, alarmTime, data = "") {
38
38
  if (typeof data !== "string") {
39
39
  throw Error("data must be a string");
40
40
  }
package/src/api.js CHANGED
@@ -257,15 +257,19 @@ export function getPlatformInfo() {
257
257
  };
258
258
  }
259
259
  }
260
-
261
260
  /**
262
261
  *
262
+ * Returns the device information, including device id, connection id, community, tenant and client ip
263
+ * */
264
+ /**
265
+ * @deprecated use platformManager.setTimezone instead.
263
266
  * @param {string} timezone the timezone to set to
264
267
  * the format of the timezone is according to the standard TZ identifier
265
268
  * (e.g. America/Los_Angeles, Asia/Tokyo, Europe/Brussels)
266
269
  * for a full list of TZ identifiers, see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
267
270
  */
268
271
  export function setTimezone(timezone) {
272
+ // STOP DO NOT CHANGE THIS FUNCTION AS IT IS DEPRECATED!!!!
269
273
  if (window.cefQuery) {
270
274
  const request = {message: JSON.stringify({type: "setTimeZone", timezone}), waitForResponse: false, target: "UI-Streamer"};
271
275
  window.cefQuery({
@@ -374,9 +378,9 @@ export function getDeviceInfo() {
374
378
  };
375
379
  }
376
380
 
377
-
378
381
  export {lifecycle} from "./lifecycle";
379
382
  export {deviceManager} from "./deviceManager";
383
+ export {platformManager} from "./platformManager";
380
384
  export {alarmManager} from "./alarmManager";
381
385
  export {messageManager} from "./messageManager";
382
386
  import "./devHelper";
@@ -488,6 +492,7 @@ export function getClientAssertion() {
488
492
  sdkLogger.warn("getClientAssertion is not supported if NOT running e2e");
489
493
  }
490
494
 
495
+
491
496
  // Assign the senza library to the old name (hs) for backward compatibility
492
497
  import * as senzaSDK from "./api.js";
493
498
  if (typeof window !== "undefined") {
@@ -0,0 +1,65 @@
1
+ import { sdkLogger } from "./utils";
2
+ import {sessionInfo} from "./SessionInfo";
3
+
4
+
5
+ /**
6
+ * PlatformManager is a singleton class that manages the platform
7
+ */
8
+ class PlatformManager extends EventTarget {
9
+
10
+ constructor() {
11
+ super();
12
+ }
13
+
14
+ /**
15
+ * @returns {Object} appConfig object
16
+ * @property {String[]} territories - a list of territories configured for the tenant.
17
+ * if the list is undefined or empty - there are no restrictions.
18
+ * @example
19
+ * import { platformManager } from "senza-sdk";
20
+ * const appConfig = platformManager.appConfig
21
+ * */
22
+ get appConfig() {
23
+ const sessionInfoObj = sessionInfo.sessionInfoObj;
24
+ const appConfig = sessionInfoObj.homeSessionInfo?.["appConfig"] || {};
25
+ sdkLogger.info("PlatformManager get appConfig: \n" + JSON.stringify(appConfig, null,2));
26
+ return appConfig;
27
+ }
28
+
29
+ /**
30
+ *
31
+ * @param {string} timezone the timezone to set to
32
+ * the format of the timezone is according to the standard TZ identifier
33
+ * (e.g. America/Los_Angeles, Asia/Tokyo, Europe/Brussels)
34
+ * for a full list of TZ identifiers, see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
35
+ */
36
+ setTimezone(timezone) {
37
+ if (window.cefQuery) {
38
+ const request = {message: JSON.stringify({type: "setTimeZone", timezone}), waitForResponse: false, target: "UI-Streamer"};
39
+ window.cefQuery({
40
+ request: JSON.stringify(request),
41
+ persistent: false,
42
+ onSuccess: () => {
43
+ sdkLogger.log("PlatformManager timezome is successfully set to", timezone);
44
+ },
45
+ onFailure: (code, msg) => {
46
+ sdkLogger.error(`PlatformManager error occurred setting timezone to ${timezone}: ${code} ${msg}`);
47
+ }
48
+ });
49
+ }
50
+ }
51
+ }
52
+
53
+ /**
54
+ *
55
+ * @module
56
+ * @example
57
+ * import { platformManager } from "senza-sdk";
58
+ * console.info(platformManager.appConfig);
59
+ * platformManager.setTimezone("Europe/Brussels");
60
+ *
61
+ * @return {PlatformManager} pointer to the PlatformManager singleton
62
+ */
63
+ export const platformManager = new PlatformManager();
64
+
65
+
@@ -11,20 +11,9 @@ const cloneDeep = (element) => {
11
11
  return JSON.parse(JSON.stringify(element));
12
12
  };
13
13
 
14
+ // TODO: check that the link below to the error list is working on dashreadme
14
15
  /** Error object to be thrown on remotePlayer api failures.
15
- * Possible error codes:
16
- *
17
- * | Error Code | Description |
18
- * | :--------- | :---------------------------------------------------------------------------------------------- |
19
- * | 6000 | The call to load() has reached the configurable timeout with no response from the remote player |
20
- * | 6001 | play() was called while the remote player is not loaded |
21
- * | 6002 | load() was called while the application was in state 'background' or 'inTransitionToBackground' |
22
- * | 6500 | remotePlayer api was called before initializing remotePlayer |
23
- * | 6501 | load() was called while previous load was still in progress |
24
- * | 23 | load() failed due to remote player initialization error |
25
- * | 98 | load() failed due to remote player failure to send message to the client |
26
- * | 99 | load() failed due to remote player reporting invalid message |
27
- * | 1000-1001 | load() failed due to remote player reporting CDM failure |
16
+ * [See error list]{@link RemotePlayer#error}
28
17
  */
29
18
  class RemotePlayerError extends Error {
30
19
  constructor(code, message) {
@@ -62,6 +51,8 @@ function setPlaybackInfo(playbackInfo) {
62
51
  * @typedef {Object} Config
63
52
  * @property {string} preferredAudioLanguage
64
53
  * @property {string} preferredSubtitlesLanguage
54
+ * @property {boolean} autoBackground - upon start playing automatically move to background
55
+ * @property {boolean} autoPlay - (Not implemented yet) upon loading start playing automatically
65
56
  */
66
57
 
67
58
  /**
@@ -71,6 +62,9 @@ function setPlaybackInfo(playbackInfo) {
71
62
  * @fires ended
72
63
  * @fires error
73
64
  * @fires onloadmodechange
65
+ * @fires seeking (Not implemented yet)
66
+ * @fires seeked (Not implemented yet)
67
+ * @fires loadedmetadata (Not implemented yet)
74
68
  */
75
69
  class RemotePlayer extends EventTarget {
76
70
  constructor() {
@@ -124,6 +118,22 @@ class RemotePlayer extends EventTarget {
124
118
  */
125
119
  this._isInitialized = false;
126
120
 
121
+ /**
122
+ * @type {boolean}
123
+ * @private
124
+ * */
125
+ this._defaultAutoBackground = true;
126
+
127
+ /**
128
+ * @event RemotePlayer#canPlay
129
+ * @description canPlay event will be rised when the remote player can start play the event
130
+ * @example
131
+ * remotePlayer.addEventListener("canPlay", () => {
132
+ * console.info("remotePlayer canPlay");
133
+ * remotePlayer.play();
134
+ * });
135
+ * */
136
+
127
137
  /**
128
138
  *
129
139
  * @event RemotePlayer#timeupdate
@@ -172,7 +182,9 @@ class RemotePlayer extends EventTarget {
172
182
  this.dispatchEvent(new Event("ended"));
173
183
  });
174
184
 
185
+ /* istanbul ignore next */
175
186
  typeof document !== "undefined" && document.addEventListener("hs/ui_inactive", () => {
187
+ /* istanbul ignore next */
176
188
  sdkLogger.info("Got hs/ui_inactive event");
177
189
  });
178
190
  typeof document !== "undefined" && document.addEventListener("hs/senzaPlayerSetRate", (event) => {
@@ -188,40 +200,48 @@ class RemotePlayer extends EventTarget {
188
200
  *
189
201
  * @see Possible error codes:
190
202
  *
191
- * | Code | Domain | Description |
192
- * | :-------- | :---------------- | :------------------------------------------------------------------------------------------- |
193
- * | 1000 | Encrypted content | Failed to create or initialise the CDM |
194
- * | 1001 | Encrypted content | Failed to create a CDM session |
195
- * | 1002 | Encrypted content | CDM failed to generate a license request |
196
- * | 1003 | Encrypted content | The CDM rejected the license server response |
197
- * | 1004 | Encrypted content | The CDM rejected the license server certificate |
198
- * | 1005 | Encrypted content | All keys in the license have expired |
199
- * | 1006 | Encrypted content | Output device is incompatible with the license requirements (HDCP) |
200
- * | 1007 | Encrypted content | The device has been revoked |
201
- * | 1008 | Encrypted content | The device secrets aren't available |
202
- * | 1999 | Encrypted content | An unknown encrypted content error |
203
- * | 2000 | Player | Content makes reference to no or unsupported key system |
204
- * | 3000 | Player | Unexpected problem with playback, only used if no more specific code in 3xxx range applies |
205
- * | 3001 | Player | Problem accessing content manifest, only used if no more specific code in 8xxx range applies |
206
- * | 3002 | Player | Unexpectedly stopped playback |
207
- * | 3100 | Player | Problem parsing MP4 content |
208
- * | 3200 | Player | Problem with decoder |
209
- * | 3300 | Player | DRM keys unavailable, player waited for keys but none arrived |
210
- * | 3400 | Player | Problem accessing segments, only used if no more specific code in 34xx range applies |
211
- * | 3401 | Player | Problem accessing segments, connection issue or timeout |
212
- * | 3402 | Player | Problem accessing segments, server returned HTTP error code |
213
- * | 3403 | Player | Problem accessing segments, server authentication issue |
214
- * | 3404 | Player | Problem accessing segments, server returned not found |
215
- * | 3900-3999 | Player | Internal player error |
216
- * | 8001 | Player | Error pulling manifest. bad parameters |
217
- * | 8002 | Player | Error pulling manifest. filters returned no data |
218
- * | 8003 | Player | Error pulling manifest. fetch error |
219
- * | 8004 | Player | Error pulling manifest. parse error |
220
- * | 8005 | Player | Error pulling manifest. stale manifest detected |
221
- * | 8006 | Player | Error updating manifest. internal cache error |
222
- * | 8007 | Player | Error updating manifest. internal error during backoff |
223
- * | 8008 | Player | Error pulling manifest. sidx parsing error |
224
- * | 8009 | Player | Error pulling manifest. internal error |
203
+ * | Code | Domain | Description |
204
+ * | :-------- | :---------------- | :-----------------------------------------------------------------------------------------------|
205
+ * | 23 | Player | load() failed due to remote player initialization error |
206
+ * | 98 | Player | load() failed due to remote player failure to send message to the client |
207
+ * | 99 | Player | load() failed due to remote player reporting invalid message |
208
+ * | 1000 | Encrypted content | Failed to create or initialise the CDM |
209
+ * | 1001 | Encrypted content | Failed to create a CDM session |
210
+ * | 1002 | Encrypted content | CDM failed to generate a license request |
211
+ * | 1003 | Encrypted content | The CDM rejected the license server response |
212
+ * | 1004 | Encrypted content | The CDM rejected the license server certificate |
213
+ * | 1005 | Encrypted content | All keys in the license have expired |
214
+ * | 1006 | Encrypted content | Output device is incompatible with the license requirements (HDCP) |
215
+ * | 1007 | Encrypted content | The device has been revoked |
216
+ * | 1008 | Encrypted content | The device secrets aren't available |
217
+ * | 1999 | Encrypted content | An unknown encrypted content error |
218
+ * | 2000 | Player | Content makes reference to no or unsupported key system |
219
+ * | 3000 | Player | Unexpected problem with playback, only used if no more specific code in 3xxx range applies |
220
+ * | 3001 | Player | Problem accessing content manifest, only used if no more specific code in 8xxx range applies |
221
+ * | 3002 | Player | Unexpectedly stopped playback |
222
+ * | 3100 | Player | Problem parsing MP4 content |
223
+ * | 3200 | Player | Problem with decoder |
224
+ * | 3300 | Player | DRM keys unavailable, player waited for keys but none arrived |
225
+ * | 3400 | Player | Problem accessing segments, only used if no more specific code in 34xx range applies |
226
+ * | 3401 | Player | Problem accessing segments, connection issue or timeout |
227
+ * | 3402 | Player | Problem accessing segments, server returned HTTP error code |
228
+ * | 3403 | Player | Problem accessing segments, server authentication issue |
229
+ * | 3404 | Player | Problem accessing segments, server returned not found |
230
+ * | 3900-3999 | Player | Internal player error |
231
+ * | 6000 | Player | The call to load() has reached the configurable timeout with no response from the remote player |
232
+ * | 6001 | Player | play() was called while the remote player is not loaded |
233
+ * | 6002 | Player | load() was called while the application was in state 'background' or 'inTransitionToBackground' |
234
+ * | 6500 | Player | remotePlayer api was called before initializing remotePlayer |
235
+ * | 6501 | Player | load() was called while previous load was still in progress |
236
+ * | 8001 | Player | Error pulling manifest. bad parameters |
237
+ * | 8002 | Player | Error pulling manifest. filters returned no data |
238
+ * | 8003 | Player | Error pulling manifest. fetch error |
239
+ * | 8004 | Player | Error pulling manifest. parse error |
240
+ * | 8005 | Player | Error pulling manifest. stale manifest detected |
241
+ * | 8006 | Player | Error updating manifest. internal cache error |
242
+ * | 8007 | Player | Error updating manifest. internal error during backoff |
243
+ * | 8008 | Player | Error pulling manifest. sidx parsing error |
244
+ * | 8009 | Player | Error pulling manifest. internal error |
225
245
  *
226
246
  * @example
227
247
  * remotePlayer.addEventListener("error", (event) => {
@@ -245,15 +265,57 @@ class RemotePlayer extends EventTarget {
245
265
 
246
266
  /**
247
267
  *
248
- * @event RemotePlayer#getLicense
249
- * @type {object}
250
- * @property {object} detail - object containing data related to the event:
251
- * sessionId, fcid, licenseRequest.
252
- * The 'hs/getLicense' event is fired from the platform when it (the platform) receives the license request.
253
- * after receiving the event, the function fires a 'license-request' event
254
- * with the contents of the 'hs/getLicense' event.
255
- * The 'hs/getLicense' request contains: fcid, sessionId, base64 encoded licenseRequest
256
- */
268
+ * @event RemotePlayer#license-request
269
+ * @description Fired whenever the platform requires a license to play encrypted content.
270
+ * The Web App is responsible for passing the (opaque) license request blob to the license server and passing the (opaque) license server response to the CDM by calling the `writeLicenseResponse` method on the event.
271
+ * @type {LicenseRequestEvent}
272
+ * @property {object} detail - Object containing ievent data
273
+ * @property {string} detail.licenseRequest - Base64 coded opaque license request
274
+ * @property {writeLicenseResponse} writeLicenseResponse - Write the license server response to the CDM.
275
+ *
276
+ * @example
277
+ * Whilst the payload structure and access controls are specific to each license server implementation, the Widevine UAT license server requires no authentication and minimal payload formatting and therefore serves as a useful case study that may be adapted.
278
+ *
279
+ * remotePlayer.addEventListener("license-request", async (event) => {
280
+ * console.log("Got license-request event");
281
+ * const requestBuffer = event?.detail?.licenseRequest;
282
+ * const requestBufferStr = String.fromCharCode.apply(null, new Uint8Array(requestBuffer));
283
+ * console.log("License Request in base64:", requestBufferStr);
284
+ * const decodedLicenseRequest = window.atob(requestBufferStr); // from base 64
285
+ * const licenseRequestBytes = Uint8Array.from(decodedLicenseRequest, (l) => l.charCodeAt(0));
286
+ * // call Google API
287
+ * const res = await getLicenseFromServer(licenseRequestBytes.buffer);
288
+ * console.log("Writing response to platform ", res.code, res.responseBody);
289
+ * event.writeLicenseResponse(res.code, res.responseBody);
290
+ * });
291
+
292
+ * async function getLicenseFromServer(licenseRequest) {
293
+ * console.log("Requesting License from Widevine server");
294
+ * const response = await fetch("https://proxy.uat.widevine.com/proxy", {
295
+ * "method": "POST",
296
+ * "body": licenseRequest,
297
+ * "headers" : {
298
+ * "Content-Type": "application/octet-stream"
299
+ * }
300
+ * });
301
+ * const code = response.status;
302
+ * if (code !== 200) {
303
+ * console.error("failed to to get response from widevine:", code);
304
+ * const responseBody = await response.text();
305
+ * console.error(responseBody);
306
+ * return {code, responseBody};
307
+ * }
308
+ * const responseBody = await response.arrayBuffer();
309
+ * console.info("Got response: ");
310
+ * return {code, responseBody};
311
+ * }
312
+ **/
313
+ /**
314
+ * @function writeLicenseResponse
315
+ * @param {number} statusCode - License server HTTP response code, e.g. 200, 401, etc. Must be 200 to indicate a successful license exchange.
316
+ * @param {string} response - License server response as opaque binary data in an ArrayBuffer.
317
+ *
318
+ * */
257
319
  typeof document !== "undefined" && document.addEventListener("hs/getLicense", (event) => {
258
320
  sdkLogger.info("Got hs/getLicense event");
259
321
  const getLicenseEventData = event?.detail;
@@ -295,12 +357,12 @@ class RemotePlayer extends EventTarget {
295
357
  };
296
358
  if (window.cefQuery) {
297
359
  const FCID = getFCID();
298
- const logger = sdkLogger.withFields({FCID});
360
+ const logger = sdkLogger.withFields({ FCID });
299
361
  const message = {
300
362
  type: "playerState",
301
363
  fcid: FCID
302
364
  };
303
- const request = {target: "UI-Streamer", waitForResponse: false, message: JSON.stringify(message)};
365
+ const request = { target: "UI-Streamer", waitForResponse: false, message: JSON.stringify(message) };
304
366
  try {
305
367
  const playerStateStr = await new Promise((resolve, reject) => {
306
368
  window.cefQuery({
@@ -326,6 +388,8 @@ class RemotePlayer extends EventTarget {
326
388
  this._isInitialized = true;
327
389
  this._setPlayableUriTimeout = uiStreamerSettings?.setPlayableUriTimeout ?? DEFAULT_SET_PLAYABLE_URI_TIMEOUT;
328
390
  this._requestVideoFrameInfo = uiStreamerSettings?.requestVideoFrameInfo ?? true;
391
+ this._defaultAutoBackground = uiStreamerSettings?.playAutoBackground ?? true;
392
+
329
393
  let playbackMetadata = {};
330
394
  try {
331
395
  playbackMetadata = JSON.parse(triggerEvent?.playbackMetadata || "{}");
@@ -369,7 +433,7 @@ class RemotePlayer extends EventTarget {
369
433
  }
370
434
 
371
435
  /** setting values for properties in the player configuration using an object.
372
- * if the config does not support a property this is a no-op
436
+ * If the config does not support a property this is a no-op.
373
437
  * @param {Object} props the object with all the different properties to change
374
438
  * @example
375
439
  * remotePlayer.configure({ preferredAudioLanguage: 'en-US' })
@@ -410,7 +474,7 @@ class RemotePlayer extends EventTarget {
410
474
  }
411
475
 
412
476
  const fcid = getFCID();
413
- const logger = sdkLogger.withFields({fcid});
477
+ const logger = sdkLogger.withFields({ fcid });
414
478
 
415
479
  const videoFrameCallback = (now, metadata) => {
416
480
  const message = {
@@ -419,7 +483,7 @@ class RemotePlayer extends EventTarget {
419
483
  currentFramePTS: metadata.mediaTime.toString(),
420
484
  ptsSessionId: this._ptsSessionId
421
485
  };
422
- const request = {target: "UI-Streamer", waitForResponse: false, message: JSON.stringify(message)};
486
+ const request = { target: "UI-Streamer", waitForResponse: false, message: JSON.stringify(message) };
423
487
  window.cefQuery({
424
488
  request: JSON.stringify(request),
425
489
  persistent: false
@@ -450,13 +514,22 @@ class RemotePlayer extends EventTarget {
450
514
  /** In order to support a seamless switch between the video in the UI and ABR, the web application must
451
515
  * register the video element being used for the currently played video before calling the load and play apis.
452
516
  * @param {object} video The video element currently playing video in the web application
517
+ * @deprecated use attach function instead
453
518
  * */
454
519
  registerVideoElement(video) {
520
+ this.attach(video);
521
+ }
522
+
523
+ /** In order to support a seamless switch between the video in the UI and ABR, the web application must
524
+ * attach the video element being used for the currently played video before calling the load and play apis.
525
+ * @param {object} video The video element currently playing video in the web application
526
+ * */
527
+ attach(video) {
455
528
  this._handle_video_frame_info(video);
456
529
  }
457
530
 
458
531
 
459
- /** Tell the remote player to load the given URL
532
+ /** Tell the remote player to load the given URL.
460
533
  * @param {string} url url to load
461
534
  * @param {number} [position] start position in seconds (if not provided, start from beginning (VOD) or current time (LTV))
462
535
  * @returns {Promise}
@@ -483,7 +556,7 @@ class RemotePlayer extends EventTarget {
483
556
  this.currentTime = 0;
484
557
  const FCID = getFCID();
485
558
  const playbackPosition = position ?? 0;
486
- const logger = sdkLogger.withFields({FCID, loadUrl: url, playbackPosition});
559
+ const logger = sdkLogger.withFields({ FCID, loadUrl: url, playbackPosition });
487
560
  logger.log("remotePlayer load: sending setPlayableUri request");
488
561
  const message = {
489
562
  type: "setPlayableUri",
@@ -501,7 +574,7 @@ class RemotePlayer extends EventTarget {
501
574
  persistent: false,
502
575
  onSuccess: () => {
503
576
  const duration = Date.now() - timeBeforeSendingRequest;
504
- logger.withFields({duration}).log(`setPlayableUri completed successfully after ${duration} ms`);
577
+ logger.withFields({ duration }).log(`setPlayableUri completed successfully after ${duration} ms`);
505
578
  if (position > 0) {
506
579
  this.currentTime = position;
507
580
  }
@@ -511,11 +584,12 @@ class RemotePlayer extends EventTarget {
511
584
  }
512
585
  this._changeLoadMode(this.LoadMode.LOADED);
513
586
  this._loadedUrl = url;
587
+ this.dispatchEvent(new Event("canPlay"));
514
588
  resolve();
515
589
  },
516
590
  onFailure: (code, msg) => {
517
591
  const duration = Date.now() - timeBeforeSendingRequest;
518
- logger.withFields({duration}).log(`setPlayableUri failed after ${duration} ms. Error code: ${code}, error message: ${msg}`);
592
+ logger.withFields({ duration }).log(`setPlayableUri failed after ${duration} ms. Error code: ${code}, error message: ${msg}`);
519
593
  if (timerId) {
520
594
  clearTimeout(timerId);
521
595
  timerId = 0;
@@ -554,20 +628,22 @@ class RemotePlayer extends EventTarget {
554
628
 
555
629
  /**
556
630
  * Play loaded URL. Assuming load was called before.
557
- * @experimental @param {boolean} [moveToBackground=true] if true, the UI will automatically move to background state
631
+ * @param {boolean} [moveToBackground=true] if true, the UI will automatically move to background state
558
632
  * if false, the UI will remain in foreground state, need to call lifecycle.moveToBackground() to move to background
559
- * This is an experimental feature and may not work as expected
633
+ * This is an experimental feature and may not work as expected.
634
+ * This is deprectaed now see Config.autoBackground
560
635
  * @example
561
636
  * remotePlayer.load("https://example.com/video.mp4", 0);
562
- * remotePlayer.play(false);
637
+ * remotePlayer.configure({autoBackground:false})
638
+ * remotePlayer.play();
563
639
  * lifecycle.moveToBackground();
564
640
  *
565
- * // if moveToBackground=true
641
+ * // if Config.autoBackground=true
566
642
  * remotePlayer.load("https://example.com/video.mp4", 0);
567
643
  * remotePlayer.play();
568
644
  * @throws {RemotePlayerError} error object contains code & msg
569
645
  */
570
- play(moveToBackground = true) {
646
+ play(moveToBackground) {
571
647
  if (!this._isInitialized) {
572
648
  throw new RemotePlayerError(6500, "Cannot call play() if remote player is not initialized");
573
649
  }
@@ -576,14 +652,14 @@ class RemotePlayer extends EventTarget {
576
652
  throw new RemotePlayerError(6001, "Cannot call play() if player is not loaded");
577
653
  }
578
654
  const FCID = getFCID();
579
- const logger = sdkLogger.withFields({FCID});
655
+ const logger = sdkLogger.withFields({ FCID });
580
656
  logger.log("remotePlayer play: sending play action");
581
657
  const audioLanguage = this._selectedAudioTrack || this._config.preferredAudioLanguage || "";
582
658
  let subtitlesLanguage = "";
583
659
  if (this._textTrackVisibility) {
584
660
  subtitlesLanguage = this._selectedSubtitlesTrack || this._config.preferredSubtitlesLanguage || "";
585
661
  }
586
- if (moveToBackground) {
662
+ if (moveToBackground ?? this._config.autoBackground ?? this._defaultAutoBackground) {
587
663
  window.cefQuery({
588
664
  request: JSON.stringify({ action: "play", fcid: FCID, audioLanguage, subtitlesLanguage }),
589
665
  persistent: false,
@@ -621,7 +697,7 @@ class RemotePlayer extends EventTarget {
621
697
  }
622
698
  }
623
699
 
624
- /** pauses the currently playing video
700
+ /** pauses the currently playing audio or video
625
701
  * @throws {RemotePlayerError} error object contains code & msg
626
702
  *
627
703
  * */
@@ -634,7 +710,7 @@ class RemotePlayer extends EventTarget {
634
710
  throw new RemotePlayerError(6001, "Cannot call pause() if player is not loaded");
635
711
  }
636
712
  const FCID = getFCID();
637
- const logger = sdkLogger.withFields({FCID});
713
+ const logger = sdkLogger.withFields({ FCID });
638
714
  logger.log("remotePlayer pause: sending pause request");
639
715
  const message = {
640
716
  type: "remotePlayer.pause",
@@ -658,7 +734,7 @@ class RemotePlayer extends EventTarget {
658
734
  }
659
735
  }
660
736
 
661
- /** get the currently loaded uri, or empty string is player is not loaded
737
+ /** Get the currently loaded uri, or empty string is player is not loaded.
662
738
  * @returns {string} loaded uri
663
739
  * @throws {RemotePlayerError} error object contains code & msg
664
740
  *
@@ -670,7 +746,7 @@ class RemotePlayer extends EventTarget {
670
746
  return this._loadedUrl;
671
747
  }
672
748
 
673
- /** get the current load mode (either NOT_LOADED or LOADING or LOADED)
749
+ /** Get the current load mode (either NOT_LOADED or LOADING or LOADED).
674
750
  * @returns {LoadMode} current load mode
675
751
  * @throws {RemotePlayerError} error object contains code & msg
676
752
  * @example
@@ -695,13 +771,13 @@ class RemotePlayer extends EventTarget {
695
771
  * @property {boolean} selected - Whether the track is selected.
696
772
  * @property {boolean} autoTranslate - (Optional) Whether the track is an auto-translated language.
697
773
  */
698
- /** get all the text (subtitles) tracks
699
- * text tracks are available only after playing content and returning to the UI
700
- * when text tracks are updated, the @event tracksupdate if fired.
774
+ /** Get all the text (subtitles) tracks.
775
+ * Text tracks are available only after playing content and returning to the UI.
776
+ * When text tracks are updated, the @event tracksupdate if fired.
701
777
  * Auto Translation languages are returned only for VOD assets where there is at least one text track in the manifest to be used for translation.
702
778
  * The list of tracks is sorted ascending to two parts by the lang key in the following order:
703
- * 1. The actual text tracks which is available in the asset manifest and the selected track
704
- * 2. Auto-Translation tracks
779
+ * 1. The actual text tracks which is available in the asset manifest and the selected track
780
+ * 2. Auto-Translation tracks
705
781
  * @returns {TextTrack[]} an array of TextTracks if available, otherwise - empty array
706
782
  *
707
783
  * */
@@ -714,9 +790,9 @@ class RemotePlayer extends EventTarget {
714
790
  * @property {string} lang - The track's language.
715
791
  * @property {boolean} selected - Whether the track is selected.
716
792
  */
717
- /** get all the audio tracks
718
- * text tracks are available only after playing content and returning to the UI
719
- * when audio tracks are updated, teh @event tracksupdate is fired.
793
+ /** Get all the audio tracks.
794
+ * Text tracks are available only after playing content and returning to the UI.
795
+ * When audio tracks are updated, the @event tracksupdate is fired.
720
796
  * @returns {AudioTrack[]} an array of objects if available, otherwise - empty array
721
797
  *
722
798
  * */
@@ -724,9 +800,9 @@ class RemotePlayer extends EventTarget {
724
800
  return cloneDeep(this._availableAudioTracks);
725
801
  }
726
802
  /** Select a specific audio track.
727
- * track id should come from a call to getAudioTracks.
728
- * if no tracks exist - this is a no-op.
729
- * if the id does not match the id of any of the existing tracks - this is a no-op.
803
+ * Track id should come from a call to getAudioTracks.
804
+ * Tf no tracks exist - this is a no-op.
805
+ * Tf the id does not match the id of any of the existing tracks - this is a no-op.
730
806
  * @param {string} audioTrackId the selected audio track id
731
807
  *
732
808
  * */
@@ -740,9 +816,9 @@ class RemotePlayer extends EventTarget {
740
816
  sdkLogger.warn(`Invalid audioTrackId ${audioTrackId}`);
741
817
  }
742
818
  /** Select a specific text (subtitle) track.
743
- * track id should come from a call to getTextTracks.
744
- * if no tracks exist - this is a no-op.
745
- * if the id does not match the id of any of the existing tracks - this is a no-op.
819
+ * Track id should come from a call to getTextTracks.
820
+ * If no tracks exist - this is a no-op.
821
+ * If the id does not match the id of any of the existing tracks - this is a no-op.
746
822
  * @param {string} textTrackId the selected text track id
747
823
  *
748
824
  * */
@@ -758,7 +834,7 @@ class RemotePlayer extends EventTarget {
758
834
 
759
835
  /**
760
836
  * Enable or disable the subtitles.
761
- * if the player is in an unloaded state, the request will be applied next time content is played.
837
+ * If the player is in an unloaded state, the request will be applied next time content is played.
762
838
  * @param {boolean} visible whether the subtitles are visible or not
763
839
  * @throws {TypeError} if visible is not a boolean variable
764
840
  */