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 +1 -1
- package/package.json +2 -2
- package/src/alarmManager.js +1 -1
- package/src/api.js +7 -2
- package/src/platformManager.js +65 -0
- package/src/remotePlayer.js +167 -91
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
package/src/alarmManager.js
CHANGED
|
@@ -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
|
+
|
package/src/remotePlayer.js
CHANGED
|
@@ -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
|
-
*
|
|
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
|
-
* |
|
|
194
|
-
* |
|
|
195
|
-
* |
|
|
196
|
-
* |
|
|
197
|
-
* |
|
|
198
|
-
* |
|
|
199
|
-
* |
|
|
200
|
-
* |
|
|
201
|
-
* |
|
|
202
|
-
* |
|
|
203
|
-
* |
|
|
204
|
-
* |
|
|
205
|
-
* |
|
|
206
|
-
* |
|
|
207
|
-
* |
|
|
208
|
-
* |
|
|
209
|
-
* |
|
|
210
|
-
* |
|
|
211
|
-
* |
|
|
212
|
-
* |
|
|
213
|
-
* |
|
|
214
|
-
* |
|
|
215
|
-
* |
|
|
216
|
-
* |
|
|
217
|
-
* |
|
|
218
|
-
* |
|
|
219
|
-
* |
|
|
220
|
-
* |
|
|
221
|
-
* |
|
|
222
|
-
* |
|
|
223
|
-
* |
|
|
224
|
-
* |
|
|
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#
|
|
249
|
-
* @
|
|
250
|
-
*
|
|
251
|
-
*
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
-
*
|
|
255
|
-
*
|
|
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
|
-
*
|
|
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
|
-
* @
|
|
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.
|
|
637
|
+
* remotePlayer.configure({autoBackground:false})
|
|
638
|
+
* remotePlayer.play();
|
|
563
639
|
* lifecycle.moveToBackground();
|
|
564
640
|
*
|
|
565
|
-
* // if
|
|
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
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
699
|
-
*
|
|
700
|
-
*
|
|
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
|
-
*
|
|
704
|
-
*
|
|
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
|
-
/**
|
|
718
|
-
*
|
|
719
|
-
*
|
|
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
|
-
*
|
|
728
|
-
*
|
|
729
|
-
*
|
|
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
|
-
*
|
|
744
|
-
*
|
|
745
|
-
*
|
|
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
|
-
*
|
|
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
|
*/
|