@xiboplayer/pwa 0.7.14 → 0.7.16
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/assets/chunk-7ZXdHUL4.js +1 -0
- package/dist/assets/html2canvas-Cjd84h1M.js +6 -0
- package/dist/assets/{html2canvas-DU_xJI0n.js.map → html2canvas-Cjd84h1M.js.map} +1 -1
- package/dist/assets/main-BxyDlH8x.js +108 -0
- package/dist/assets/main-BxyDlH8x.js.map +1 -0
- package/dist/assets/main-DpLXt_A1.js +3 -0
- package/dist/assets/main-DpLXt_A1.js.map +1 -0
- package/dist/assets/{pdf-hfnsgC3n.js → pdf-CfAvK6QT.js} +2 -2
- package/dist/assets/{pdf-hfnsgC3n.js.map → pdf-CfAvK6QT.js.map} +1 -1
- package/dist/assets/{setup-b3Q5km6i.js → setup-Dr31Tx8X.js} +2 -2
- package/dist/assets/{setup-b3Q5km6i.js.map → setup-Dr31Tx8X.js.map} +1 -1
- package/dist/assets/{src-CKldR3nU.js → src-B-j3XW3-.js} +3 -3
- package/dist/assets/{src-CKldR3nU.js.map → src-B-j3XW3-.js.map} +1 -1
- package/dist/assets/{src-mlm9mrth.js → src-BCLLyeh_.js} +3 -3
- package/dist/assets/{src-mlm9mrth.js.map → src-BCLLyeh_.js.map} +1 -1
- package/dist/assets/src-BSReyr0v.js +2 -0
- package/dist/assets/{src-CfQQmLAv.js.map → src-BSReyr0v.js.map} +1 -1
- package/dist/assets/src-D8PF0mN4.js +2 -0
- package/dist/assets/{src-dsFkiC6D.js.map → src-D8PF0mN4.js.map} +1 -1
- package/dist/assets/{src-BSutLb7d.js → src-DAN2Deef.js} +2 -2
- package/dist/assets/{src-BSutLb7d.js.map → src-DAN2Deef.js.map} +1 -1
- package/dist/assets/src-DlR7dlm-.js +3 -0
- package/dist/assets/src-DlR7dlm-.js.map +1 -0
- package/dist/assets/{src-CovGdth3.js → src-Kaan1uxV.js} +2 -2
- package/dist/assets/{src-CovGdth3.js.map → src-Kaan1uxV.js.map} +1 -1
- package/dist/assets/src-Xntm4zXY.js +629 -0
- package/dist/assets/src-Xntm4zXY.js.map +1 -0
- package/dist/assets/src-bWHpkXu3.js +16 -0
- package/dist/assets/{src-DJc_Dx_C.js.map → src-bWHpkXu3.js.map} +1 -1
- package/dist/assets/{src-BFGx-eLp.js → src-vZDSh8Wj.js} +2 -2
- package/dist/assets/{src-BFGx-eLp.js.map → src-vZDSh8Wj.js.map} +1 -1
- package/dist/assets/{sync-manager-lUvs9V17.js → sync-manager-D6eMk5NM.js} +2 -2
- package/dist/assets/{sync-manager-lUvs9V17.js.map → sync-manager-D6eMk5NM.js.map} +1 -1
- package/dist/index.html +6 -7
- package/dist/setup.html +5 -7
- package/dist/sw-pwa.js +2 -2
- package/dist/sw-pwa.js.map +1 -1
- package/package.json +13 -13
- package/dist/assets/html2canvas-DU_xJI0n.js +0 -6
- package/dist/assets/main-CGf_D3Ae.js +0 -735
- package/dist/assets/main-CGf_D3Ae.js.map +0 -1
- package/dist/assets/src-BFiB-6vY.js +0 -1
- package/dist/assets/src-CZQ9f8VU.js +0 -1
- package/dist/assets/src-CfQQmLAv.js +0 -2
- package/dist/assets/src-DF2sXd4c.js +0 -1
- package/dist/assets/src-DJc_Dx_C.js +0 -16
- package/dist/assets/src-dsFkiC6D.js +0 -2
- /package/dist/assets/{modulepreload-polyfill-wMinxHhO.js → modulepreload-polyfill-Cf3xff8G.js} +0 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./src-Kaan1uxV.js","./src-B-j3XW3-.js","./chunk-7ZXdHUL4.js","./src-D8PF0mN4.js","./src-bWHpkXu3.js","./src-BSReyr0v.js","./src-vZDSh8Wj.js","./src-BCLLyeh_.js","./src-DAN2Deef.js","./src-DlR7dlm-.js","./src-Xntm4zXY.js","./main-DpLXt_A1.js","./modulepreload-polyfill-Cf3xff8G.js","./sync-manager-D6eMk5NM.js","./html2canvas-Cjd84h1M.js"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{r as e}from"./chunk-7ZXdHUL4.js";import{t}from"./main-DpLXt_A1.js";import{f as n,i as r,t as i,u as a}from"./src-B-j3XW3-.js";import{a as o,i as s,o as c}from"./src-D8PF0mN4.js";import{i as l,r as u}from"./src-BSReyr0v.js";import{CORE_EVENTS as d,PlayerCore as f}from"./src-DlR7dlm-.js";import{RendererLite as p}from"./src-Xntm4zXY.js";var m=class{overlay=null;config;updateTimer=null;_visible=!1;_getProgress=null;constructor(e){this.config={updateInterval:1e3,autoHide:!0,...e},this.config.enabled&&(this.createOverlay(),this.overlay.style.display=`none`)}createOverlay(){this.overlay=document.createElement(`div`),this.overlay.id=`download-overlay`,this.overlay.style.cssText=`
|
|
3
|
+
position: fixed;
|
|
4
|
+
top: 1.5vh;
|
|
5
|
+
left: 1.5vw;
|
|
6
|
+
background: rgba(0, 0, 0, 0.88);
|
|
7
|
+
color: #fff;
|
|
8
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
9
|
+
font-size: 1.4vw;
|
|
10
|
+
padding: 1vh 1.2vw;
|
|
11
|
+
border-radius: 0.4vw;
|
|
12
|
+
border: 1px solid rgba(255, 255, 255, 0.25);
|
|
13
|
+
z-index: 999999;
|
|
14
|
+
max-width: 35vw;
|
|
15
|
+
box-shadow: 0 0.3vh 1.2vw rgba(0, 0, 0, 0.5);
|
|
16
|
+
`,document.body.appendChild(this.overlay)}setProgressCallback(e){this._getProgress=e}updateOverlay(){if(!this.overlay)return;let e=this._getProgress?this._getProgress():{},t=this.renderStatus(e);t?(this.overlay.innerHTML=t,this.overlay.style.display=`block`):this._visible?(this.overlay.innerHTML=`<div style="color: #6c6; font-size: 1.4vw;">✓ All downloads complete</div>`,this.overlay.style.display=`block`):(this.stopUpdating(),this.overlay.style.display=`none`)}renderStatus(e){let t=e||{};if(Object.keys(t).length===0)return this.config.autoHide?``:`<div style="color: #6c6;">✓ No downloads</div>`;let n=`<div style="font-weight: 600; margin-bottom: 0.8vh; font-size: 1.4vw;">Downloads: ${Object.keys(t).length} active</div>`;for(let[e,r]of Object.entries(t)){let t=this.extractFilename(e),i=Math.round(r.percent||0),a=this.formatBytes(r.downloaded||0),o=this.formatBytes(r.total||0);n+=`
|
|
17
|
+
<div style="margin-bottom: 0.6vh; padding-bottom: 0.6vh; border-bottom: 1px solid rgba(255,255,255,0.1);">
|
|
18
|
+
<div style="font-size: 1.2vw; margin-bottom: 0.2vh;">${t}</div>
|
|
19
|
+
<div style="background: rgba(255,255,255,0.1); height: 0.4vh; border-radius: 0.2vw; overflow: hidden;">
|
|
20
|
+
<div style="width: ${i}%; height: 100%; background: #4a9eff; transition: width 0.3s;"></div>
|
|
21
|
+
</div>
|
|
22
|
+
<div style="color: #999; font-size: 1.1vw; margin-top: 0.2vh;">
|
|
23
|
+
${i}% · ${a} / ${o}
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
`}return n}extractFilename(e){return e||`unknown`}formatBytes(e){if(e<1024)return`${e} B`;let t=e/1024;if(t<1024)return`${t.toFixed(1)} KB`;let n=t/1024;return n<1024?`${n.toFixed(1)} MB`:`${(n/1024).toFixed(1)} GB`}toggle(){this.overlay&&(this._visible=!this._visible,this._visible?(this.overlay.style.display=`block`,this.updateOverlay(),this.startUpdating()):(this.overlay.style.display=`none`,this.stopUpdating()))}startUpdating(){this.updateTimer||(this.updateTimer=window.setInterval(()=>{this.updateOverlay()},this.config.updateInterval),this.updateOverlay())}stopUpdating(){this.updateTimer&&=(clearInterval(this.updateTimer),null)}destroy(){this.stopUpdating(),this.overlay&&=(this.overlay.remove(),null)}setEnabled(e){this.config.enabled=e,e&&!this.overlay?this.createOverlay():!e&&this.overlay&&this.destroy()}};function h(){let e=new URLSearchParams(window.location.search).get(`showDownloads`);if(e!==null)return{enabled:e!==`0`&&e!==`false`};let t=localStorage.getItem(`xibo_show_download_overlay`);return t===null?{enabled:!1}:{enabled:t===`true`}}var g=class{overlay=null;visible;timeline=[];currentLayoutId=null;layoutStartedAt=null;currentDuration=null;currentIsDefault=!1;previousLayout=null;offline=!1;onLayoutClick=null;refreshTimer=null;constructor(e=!1,t){this.visible=e,this.onLayoutClick=t||null,this.createOverlay(),this.visible||(this.overlay.style.display=`none`),this.refreshTimer=setInterval(()=>this.render(),5e3)}createOverlay(){this.overlay=document.createElement(`div`),this.overlay.id=`timeline-overlay`,this.overlay.style.cssText=`
|
|
27
|
+
position: fixed;
|
|
28
|
+
bottom: 1.5vh;
|
|
29
|
+
left: 1.5vw;
|
|
30
|
+
background: rgba(0, 0, 0, 0.88);
|
|
31
|
+
color: #fff;
|
|
32
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
33
|
+
font-size: 1.4vw;
|
|
34
|
+
padding: 1vh 1.2vw;
|
|
35
|
+
border-radius: 0.4vw;
|
|
36
|
+
border: 1px solid rgba(255, 255, 255, 0.25);
|
|
37
|
+
z-index: 999999;
|
|
38
|
+
max-width: 35vw;
|
|
39
|
+
box-shadow: 0 0.3vh 1.2vw rgba(0, 0, 0, 0.5);
|
|
40
|
+
pointer-events: auto;
|
|
41
|
+
`,this.overlay.addEventListener(`click`,e=>{let t=e.target.closest(`[data-layout-id]`);if(!t||!this.onLayoutClick)return;let n=parseInt(t.dataset.layoutId,10);isNaN(n)||n===this.currentLayoutId||this.onLayoutClick(n)}),document.body.appendChild(this.overlay)}toggle(){this.visible=!this.visible,this.overlay&&(this.overlay.style.display=this.visible?`block`:`none`),this.visible&&this.render(),localStorage.setItem(`xibo_show_timeline_overlay`,String(this.visible))}setOffline(e){this.offline=e,this.render()}update(e,t,n){t!==null&&(t!==this.currentLayoutId&&(this.currentLayoutId!==null&&this.currentDuration!==null&&this.layoutStartedAt!==null&&(this.previousLayout={id:this.currentLayoutId,duration:this.currentDuration,startedAt:this.layoutStartedAt}),this.currentLayoutId=t,this.currentIsDefault=!1),this.layoutStartedAt=Date.now(),n!==void 0&&(this.currentDuration=n)),e!==null&&(this.timeline=e),this.render()}render(){if(!this.overlay||!this.visible)return;if(this.timeline.length===0&&!this.previousLayout&&!this.currentLayoutId){this.overlay.innerHTML=`<div style="color: #999;">Timeline — no upcoming layouts</div>`;return}let e=Date.now(),t=this.onLayoutClick!==null,n=!1,r=[];for(let e of this.timeline){let t=l(e.layoutFile);if(!n&&t===this.currentLayoutId){n=!0;continue}r.push(e)}let i=(this.previousLayout?1:0)+(this.currentLayoutId?1:0)+r.length,a=`<div style="font-weight: 600; margin-bottom: 0.8vh; font-size: 1.4vw; color: #ccc;">Timeline (${i} scheduled)${this.offline?` <span style="color: #ff4444; font-size: 1.1vw;">OFFLINE</span>`:``}</div>`,o=0;if(this.previousLayout&&o<8){let e=this.previousLayout,n=this.formatDuration(e.duration).padStart(7).replace(/ /g,` `),r=`#${e.id}`.padEnd(6).replace(/ /g,` `),i=new Date(e.startedAt),s=new Date(e.startedAt+e.duration*1e3),c=`${this.formatTime(i)}–${this.formatTime(s)} `,l=t?`cursor: pointer;`:``,u=t?`onmouseover="this.style.background='rgba(255,255,255,0.1)'" onmouseout="this.style.background='none'"`:``;a+=`<div data-layout-id="${e.id}" style="border-left: 0.25vw solid #555; padding-left: 0.6vw; color: #666; text-decoration: line-through; ${l} margin-bottom: 0.3vh; font-family: monospace; font-size: 1.3vw; line-height: 1.5; white-space: nowrap;" ${u}>`,a+=`${c}${r}${n}`,a+=`</div>`,o++}if(this.currentLayoutId!==null&&o<8){let t,n=``;if(this.currentDuration!==null&&this.layoutStartedAt!==null){let r=(e-this.layoutStartedAt)/1e3,i=Math.max(0,Math.round(this.currentDuration-r));t=this.formatDuration(i);let a=new Date(this.layoutStartedAt),o=new Date(this.layoutStartedAt+this.currentDuration*1e3);n=`${this.formatTime(a)}–${this.formatTime(o)} `}else t=`---`;let r=t.padStart(7).replace(/ /g,` `),i=`#${this.currentLayoutId}`.padEnd(6).replace(/ /g,` `);a+=`<div data-layout-id="${this.currentLayoutId}" style="border-left: 0.25vw solid #4a9eff; padding-left: 0.6vw; color: #fff; font-weight: 600; margin-bottom: 0.3vh; font-family: monospace; font-size: 1.3vw; line-height: 1.5; white-space: nowrap;">`,a+=`${n}${i}${r}`,this.currentIsDefault&&(a+=` <span style="color: #888;">[def]</span>`),a+=`</div>`,o++}let s=this.layoutStartedAt!==null&&this.currentDuration!==null?this.layoutStartedAt+this.currentDuration*1e3:e;for(let e of r){if(o>=8)break;let n=l(e.layoutFile),r=e.missingMedia&&e.missingMedia.length>0,i=this.formatDuration(e.duration),c=s+e.duration*1e3,u=this.formatTime(new Date(s)),d=this.formatTime(new Date(c)),f,p;r?(f=`border-left: 0.25vw solid #ff4444; padding-left: 0.6vw;`,p=`color: #ff6666;`):(f=`padding-left: 0.85vw;`,p=`color: #aaa;`),a+=`<div data-layout-id="${n}" style="${f} ${p} ${t?`cursor: pointer;`:``} margin-bottom: 0.3vh; font-family: monospace; font-size: 1.3vw; line-height: 1.5; white-space: nowrap;" ${t?`onmouseover="this.style.background='rgba(255,255,255,0.1)'" onmouseout="this.style.background='none'"`:``}>`;let m=`#${n}`.padEnd(6).replace(/ /g,` `),h=i.padStart(7).replace(/ /g,` `);if(a+=`${u}–${d} ${m}${h}`,e.isDefault&&(a+=` <span style="color: #888;">[def]</span>`),r){let t=e.missingMedia.join(`, `);a+=` <span style="color: #ff4444; font-size: 1.1vw;" title="Missing: ${t}">⚠ ${e.missingMedia.length}</span>`}if(e.hidden&&e.hidden.length>0){let t=e.hidden.map(e=>`#${e.file.replace(`.xlf`,``)} (p${e.priority})`).join(`, `);a+=` <span style="color: #8899aa; font-size: 1.1vw;" title="Also scheduled: ${t}">+${e.hidden.length}</span>`}a+=`</div>`,s=c,o++}i>8&&(a+=`<div style="padding-left: 0.85vw; color: #888; font-size: 1.1vw; margin-top: 0.3vh;">+${i-8} more</div>`),this.overlay.innerHTML=a}formatTime(e){return e.toLocaleTimeString(`en-GB`,{hour:`2-digit`,minute:`2-digit`,second:`2-digit`})}formatDuration(e){let t=Math.floor(e/60),n=Math.round(e%60);return t>0?`${t}m ${n.toString().padStart(2,`0`)}s`:`${n}s`}destroy(){this.refreshTimer&&=(clearInterval(this.refreshTimer),null),this.overlay&&=(this.overlay.remove(),null)}};function _(){let e=new URLSearchParams(window.location.search).get(`showTimeline`);if(e!==null)return e!==`0`&&e!==`false`;let t=localStorage.getItem(`xibo_show_timeline_overlay`);return t===null?!1:t===`true`}var v=a(`SetupOverlay`),y=class{backdrop=null;gateCard=null;iframe=null;cancelBtn=null;visible=!1;show(){this.visible||(this.visible=!0,this.backdrop||this.create(),this.showGate(),this.backdrop.style.display=`flex`,v.info(`[SetupOverlay] Opened`))}hide(){this.visible&&(this.visible=!1,this.backdrop&&(this.backdrop.style.display=`none`),this.iframe&&(this.iframe.src=`about:blank`,this.iframe.style.display=`none`),v.info(`[SetupOverlay] Closed`))}toggle(){this.visible?this.hide():this.show()}isVisible(){return this.visible}showGate(){this.gateCard&&(this.gateCard.style.display=`block`),this.iframe&&(this.iframe.style.display=`none`),this.cancelBtn&&(this.cancelBtn.style.display=`none`);let e=this.gateCard?.querySelector(`#gate-key`);e&&(e.value=``,requestAnimationFrame(()=>e.focus()));let t=this.gateCard?.querySelector(`#gate-error`);t&&(t.style.display=`none`)}showSetup(){this.gateCard&&(this.gateCard.style.display=`none`),this.cancelBtn&&(this.cancelBtn.style.display=`block`),this.iframe&&(this.iframe.style.display=`block`,this.iframe.src=`./setup.html?unlocked=1`)}create(){this.backdrop=document.createElement(`div`),this.backdrop.id=`setup-overlay-backdrop`,this.backdrop.style.cssText=`
|
|
42
|
+
position: fixed;
|
|
43
|
+
inset: 0;
|
|
44
|
+
background: rgba(0, 0, 0, 0.85);
|
|
45
|
+
z-index: 1000000;
|
|
46
|
+
display: none;
|
|
47
|
+
align-items: center;
|
|
48
|
+
justify-content: center;
|
|
49
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
50
|
+
`,this.cancelBtn=document.createElement(`button`),this.cancelBtn.textContent=`Cancel`,this.cancelBtn.style.cssText=`
|
|
51
|
+
position: absolute;
|
|
52
|
+
top: 12px;
|
|
53
|
+
right: 16px;
|
|
54
|
+
background: transparent;
|
|
55
|
+
border: 1px solid rgba(255, 255, 255, 0.3);
|
|
56
|
+
color: #aaa;
|
|
57
|
+
font-size: 14px;
|
|
58
|
+
padding: 6px 18px;
|
|
59
|
+
border-radius: 6px;
|
|
60
|
+
cursor: pointer;
|
|
61
|
+
z-index: 1000001;
|
|
62
|
+
display: none;
|
|
63
|
+
transition: background 0.2s, color 0.2s;
|
|
64
|
+
`,this.cancelBtn.addEventListener(`mouseenter`,()=>{this.cancelBtn.style.background=`rgba(255,255,255,0.1)`,this.cancelBtn.style.color=`#fff`}),this.cancelBtn.addEventListener(`mouseleave`,()=>{this.cancelBtn.style.background=`transparent`,this.cancelBtn.style.color=`#aaa`}),this.cancelBtn.addEventListener(`click`,()=>this.hide()),this.gateCard=document.createElement(`div`),this.gateCard.style.cssText=`
|
|
65
|
+
background: #2A2A2A;
|
|
66
|
+
border-radius: 16px;
|
|
67
|
+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
|
68
|
+
padding: 48px;
|
|
69
|
+
max-width: 480px;
|
|
70
|
+
width: 90vw;
|
|
71
|
+
color: #E0E0E0;
|
|
72
|
+
`,this.gateCard.innerHTML=`
|
|
73
|
+
<div style="text-align: center; margin-bottom: 32px;">
|
|
74
|
+
<div style="font-size: 36px; font-weight: 700; color: #fff; letter-spacing: -0.5px;">
|
|
75
|
+
<span style="color: #0097D8;">xibo</span> player
|
|
76
|
+
</div>
|
|
77
|
+
<div style="font-size: 14px; color: #888; margin-top: 4px;">PWA Digital Signage</div>
|
|
78
|
+
</div>
|
|
79
|
+
<div style="font-size: 18px; font-weight: 600; color: #fff; margin-bottom: 8px; text-align: center;">
|
|
80
|
+
Reconfigure Display
|
|
81
|
+
</div>
|
|
82
|
+
<div style="font-size: 13px; color: #888; margin-bottom: 20px; text-align: center; line-height: 1.5;">
|
|
83
|
+
Enter the current CMS Key to change settings.
|
|
84
|
+
</div>
|
|
85
|
+
<form id="gate-form">
|
|
86
|
+
<div style="margin-bottom: 20px;">
|
|
87
|
+
<label style="display: block; margin-bottom: 6px; color: #AAA; font-size: 13px; font-weight: 500; text-transform: uppercase; letter-spacing: 0.5px;">
|
|
88
|
+
CMS Key
|
|
89
|
+
</label>
|
|
90
|
+
<input type="password" id="gate-key" placeholder="Current CMS key" required
|
|
91
|
+
style="width: 100%; padding: 12px 14px; background: #1D1D1D; border: 2px solid #3A3A3A; border-radius: 8px; font-size: 15px; color: #E0E0E0; transition: border-color 0.2s; box-sizing: border-box;">
|
|
92
|
+
</div>
|
|
93
|
+
<button type="submit" style="width: 100%; padding: 14px; background: #0097D8; color: white; border: none; border-radius: 8px; font-size: 15px; font-weight: 600; cursor: pointer; transition: background 0.2s, transform 0.1s;">
|
|
94
|
+
Unlock
|
|
95
|
+
</button>
|
|
96
|
+
</form>
|
|
97
|
+
<div id="gate-error" style="margin-top: 16px; padding: 12px 14px; background: rgba(244, 67, 54, 0.15); border: 1px solid rgba(244, 67, 54, 0.3); border-radius: 8px; color: #EF9A9A; font-size: 14px; display: none;"></div>
|
|
98
|
+
<button id="gate-cancel" style="width: 100%; padding: 14px; background: transparent; border: 1px solid #3A3A3A; color: #AAA; border-radius: 8px; font-size: 15px; font-weight: 600; cursor: pointer; margin-top: 8px; transition: background 0.2s;">
|
|
99
|
+
Cancel
|
|
100
|
+
</button>
|
|
101
|
+
`,this.iframe=document.createElement(`iframe`),this.iframe.style.cssText=`
|
|
102
|
+
width: 100%;
|
|
103
|
+
height: 100%;
|
|
104
|
+
border: none;
|
|
105
|
+
background: #1D1D1D;
|
|
106
|
+
display: none;
|
|
107
|
+
`,this.iframe.addEventListener(`load`,()=>{try{if((this.iframe.contentWindow?.location?.href||``).includes(`index.html`)){this.hide(),window.location.reload();return}let e=this.iframe.contentDocument;if(!e)return;e.addEventListener(`keydown`,e=>{e.key===`Escape`&&(e.preventDefault(),this.hide())})}catch{}}),this.backdrop.appendChild(this.cancelBtn),this.backdrop.appendChild(this.gateCard),this.backdrop.appendChild(this.iframe),document.body.appendChild(this.backdrop);let e=this.gateCard.querySelector(`#gate-form`),t=this.gateCard.querySelector(`#gate-key`),n=this.gateCard.querySelector(`#gate-error`),i=this.gateCard.querySelector(`#gate-cancel`);t.addEventListener(`focus`,()=>{t.style.borderColor=`#0097D8`}),t.addEventListener(`blur`,()=>{t.style.borderColor=`#3A3A3A`}),e.addEventListener(`submit`,e=>{e.preventDefault(),t.value.trim()===r.cmsKey?this.showSetup():(n.textContent=`Incorrect CMS key`,n.style.display=`block`,t.focus(),t.select())}),i.addEventListener(`click`,()=>this.hide()),this.backdrop.addEventListener(`keydown`,e=>{e.key===`Escape`&&(e.preventDefault(),this.hide()),e.stopPropagation()})}},b=a(`PWA`),x=i.slice(1),S=new URL(`./`,window.location.href).pathname.replace(/\/$/,``),C,w,T,E,D,O,k,A,j,M,N,P,F,I,L,R,z={},B=class{renderer;core;xmds;downloadOverlay=null;timelineOverlay=null;setupOverlay=null;statsCollector=null;logReporter=null;displaySettings=null;currentScheduleId=-1;scheduledLayoutIds=new Set;preparingLayoutId=null;_pendingRetryLayoutId=null;_screenshotInterval=null;_screenshotMethod=null;_html2canvasMod=null;_screenshotInFlight=!1;_wakeLock=null;syncManager=null;_currentLayoutEnableStat=!0;_probeTimer=null;_mediaStatusTimer=null;_pendingFollowerStats=null;_pendingFollowerLogs=null;_iframeObserver=null;_swIcHandler=null;_chunkConfig=null;_fileIdToSaveAs=new Map;_cachedMediaKeys=new Set;protocolDetector=null;async init(){if(b.info(`Initializing player with RendererLite + PlayerCore...`),await this.loadCoreModules(),`serviceWorker`in navigator)try{let e=await navigator.serviceWorker.register(`${S}/sw-pwa.js?v=${Date.now()}`,{scope:`${S}/`,type:`module`,updateViaCache:`none`});b.info(`Service Worker registered for offline mode:`,e.scope),navigator.storage&&navigator.storage.persist&&(await navigator.storage.persist()?b.info(`Persistent storage granted - cache won't be evicted`):b.warn(`Persistent storage denied - cache may be evicted`))}catch(e){b.warn(`Service Worker registration failed:`,e)}b.info(`Initializing cache clients...`),A=new c;let{calculateChunkConfig:e}=await t(async()=>{let{calculateChunkConfig:e}=await import(`./src-Kaan1uxV.js`);return{calculateChunkConfig:e}},__vite__mapDeps([0,1,2]),import.meta.url);this._chunkConfig=e(b),j=new o({concurrency:this._chunkConfig.concurrency,chunkSize:this._chunkConfig.chunkSize,chunksPerFile:2}),b.info(`Cache clients ready — StoreClient + DownloadManager`);let n=document.getElementById(`player-container`);if(!n)throw Error(`No #player-container found`);this.renderer=new p({cmsUrl:T.cmsUrl,hardwareKey:T.hardwareKey},n,{fileIdToSaveAs:this._fileIdToSaveAs,getWidgetHtml:async e=>{let t=`${i}/widgets/${e.layoutId}/${e.regionId}/${e.id}`;b.debug(`Looking for widget HTML at: ${t}`,e);try{if(await A.has(`${x}/widgets`,`${e.layoutId}/${e.regionId}/${e.id}`))return b.debug(`Widget HTML found in store, using mirror URL for iframe`),{url:t,fallback:e.raw||``};b.warn(`No widget HTML found in store: ${t}`)}catch(t){b.error(`Failed to check widget HTML for ${e.id}:`,t)}return b.warn(`Using widget.raw fallback for ${e.id}`),e.raw||``}}),this.core=new f({config:T,xmds:this.xmds,cache:A,schedule:w,renderer:this.renderer,xmrWrapper:k,statsCollector:this.statsCollector,displaySettings:this.displaySettings,cmsId:T.activeCmsId}),this.setupCoreEventHandlers(),this.setupRendererEventHandlers(),this.setupInteractiveControl(),this.setupDataConnectorNotify(),this.setupRemoteControls(),this.updateConfigDisplay(),window.addEventListener(`online`,()=>{b.info(`Browser reports online — triggering immediate collection`),this.updateStatus(`Back online, syncing...`),this.removeOfflineIndicator(),this.core.collectNow().catch(e=>{b.error(`Failed to collect after coming online:`,e)})}),window.addEventListener(`offline`,()=>{b.warn(`Browser reports offline — continuing playback with cached data`),this.updateStatus(`Offline mode — using cached content`),this.showOfflineIndicator()});let r=(this.getControls().keyboard||{}).debugOverlays===!0,a=h();a.enabled&&r&&(this.downloadOverlay=new m(a),this.downloadOverlay.setProgressCallback(()=>j.getProgress()),b.info(`Download overlay enabled (hover bottom-right corner)`)),_()&&r&&(this.timelineOverlay=new g(!0,e=>this.skipToLayout(e))),this.setupCertWarnings(),this.setupXmrWarning(),await this.requestWakeLock(),document.addEventListener(`visibilitychange`,()=>{document.visibilityState===`visible`&&this.requestWakeLock()}),await this.core.collect(),b.info(`Player initialized successfully`)}async requestWakeLock(){if(!(`wakeLock`in navigator)){b.debug(`Wake Lock API not supported`);return}try{this._wakeLock=await navigator.wakeLock.request(`screen`),b.info(`Screen Wake Lock acquired — display will stay on`),this._wakeLock.addEventListener(`release`,()=>{b.debug(`Screen Wake Lock released`),this._wakeLock=null})}catch(e){b.warn(`Wake Lock request failed:`,e?.message)}}setupCertWarnings(){let e=new Set;window.addEventListener(`cert-warning`,(t=>{let{host:n,error:r}=t.detail;if(e.has(n))return;e.add(n),b.warn(`Invalid SSL certificate accepted for stream: ${n} (${r})`);let i=document.getElementById(`overlay`),a=!1;if(!i){i=document.createElement(`div`),i.id=`overlay`;let e=document.createElement(`div`);e.id=`config-info`,i.appendChild(e);let t=document.createElement(`div`);t.id=`status`,i.appendChild(t),document.body.appendChild(i),a=!0}let o=document.getElementById(`cert-warnings`);if(!o){o=document.createElement(`span`),o.id=`cert-warnings`,o.style.cssText=`color: #ffaa33; flex: 0 0 auto;`;let e=document.getElementById(`status`);i.insertBefore(o,e)}let s=[...e].join(`, `);o.textContent=`\u26A0 SSL: ${s}`,a&&this.updateConfigDisplay()}))}setupXmrWarning(){this.core.on(`xmr-status`,({connected:e})=>{let t=document.getElementById(`overlay`);if(!t)return;let n=document.getElementById(`xmr-warning`);if(e)n?.remove();else{if(!n){n=document.createElement(`span`),n.id=`xmr-warning`,n.style.cssText=`color: #ff6666; flex: 0 0 auto;`;let e=document.getElementById(`cert-warnings`)||document.getElementById(`status`);t.insertBefore(n,e)}n.textContent=`⚠ XMR disconnected`}})}async loadCoreModules(){try{let[e,r,i,a,o,s,c,l,u,d]=await Promise.all([t(()=>import(`./src-D8PF0mN4.js`).then(e=>e.t),__vite__mapDeps([3,2,1]),import.meta.url),t(()=>import(`./src-bWHpkXu3.js`).then(e=>e.t),__vite__mapDeps([4,2,1]),import.meta.url),t(()=>import(`./src-BSReyr0v.js`).then(e=>e.t),__vite__mapDeps([5,2,1]),import.meta.url),t(()=>import(`./src-B-j3XW3-.js`).then(e=>e.n),__vite__mapDeps([1,2]),import.meta.url),t(()=>import(`./src-vZDSh8Wj.js`),__vite__mapDeps([6,1,2]),import.meta.url),t(()=>import(`./src-BCLLyeh_.js`),__vite__mapDeps([7,1,2]),import.meta.url),t(()=>import(`./src-DAN2Deef.js`),__vite__mapDeps([8,1,2]),import.meta.url),t(()=>import(`./src-DlR7dlm-.js`),__vite__mapDeps([9,3,2,1,5]),import.meta.url),t(()=>import(`./src-Xntm4zXY.js`),__vite__mapDeps([10,11,12,3,2,1,5]),import.meta.url),t(()=>import(`./sync-manager-D6eMk5NM.js`),__vite__mapDeps([13,1,2]),import.meta.url)]);if(C=e.cacheWidgetHtml,L=d.SyncManager,R=d.computeStagger,w=i.scheduleManager,T=a.config,E=r.RestClient,D=r.XmdsClient,O=r.ProtocolDetector,k=o.XmrWrapper,M=s.StatsCollector,N=s.formatStats,P=s.LogReporter,F=s.formatLogs,I=c.DisplaySettings,z.core=l.VERSION||`?`,z.cache=e.VERSION||`?`,z.renderer=u.VERSION||`?`,z.schedule=i.VERSION||`?`,z.xmds=r.VERSION||`?`,z.xmr=o.VERSION||`?`,z.utils=a.VERSION||`?`,z.stats=s.VERSION||`?`,z.settings=c.VERSION||`?`,window.electronAPI?.getSystemInfo)try{let e=await window.electronAPI.getSystemInfo();e.macAddress&&(T.macAddress=e.macAddress)}catch{}let f=T.transport===`auto`?void 0:T.transport,p=new URLSearchParams(window.location.search).get(`transport`)||(S.includes(`pwa-xmds`)?`xmds`:null)||f||`auto`;this.protocolDetector=new O(T.cmsUrl,E,D);let m=p===`auto`?void 0:p,{client:h}=await this.protocolDetector.detect(T,m);this.xmds=h;let g=T.activeCmsId;this.statsCollector=new M(g),await this.statsCollector.init(),b.info(`Stats collector initialized${g?` (CMS: ${g})`:``}`),this.logReporter=new P(g),await this.logReporter.init(),b.info(`Log reporter initialized${g?` (CMS: ${g})`:``}`);let _=e=>e.map(e=>typeof e==`string`?e:JSON.stringify(e)).join(` `);n(({level:e,name:t,args:n})=>{if(!this.logReporter)return;let r=_(n);this.logReporter.log(e,`[${t}] ${r}`,`PLAYER`).catch(()=>{})});let v=T.debug;if(v?.consoleLogs){let e=(v.consoleLogsInterval||10)*1e3,t=[],r=null,i=()=>{if(t.length===0)return;let e=t;t=[],r=null,fetch(`/debug/log`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(e)}).catch(()=>{})};n(({level:n,name:a,args:o})=>{let s=_(o);t.push({level:n,name:a,message:s,ts:new Date().toISOString()}),r||=setTimeout(i,e)}),b.info(`Console log forwarding to proxy enabled (flush every ${e/1e3}s)`)}this.displaySettings=new I,b.info(`Display settings manager initialized`);let y=`0.7.16`;b.info(`v${y} built 2026-04-07T19:53:44.301Z`);let x=Object.entries(z).map(([e,t])=>`${e}=${t}`).join(` `);b.info(`SDK: ${x}`);let A=!!window.electronAPI,j=A?navigator.userAgent.match(/Electron\/([\d.]+)/)?.[1]||`?`:null,B=navigator.userAgent.match(/Chrome\/([\d.]+)/)?.[1]||`?`,V=A?`Electron ${j} / Chrome ${B}`:`Chrome ${B}`;b.info(`Env: PWA v${y} | ${V} | ${navigator.platform} | ${screen.width}x${screen.height}`),b.info(`Core modules loaded`)}catch(e){throw b.error(`Failed to load core modules:`,e),e}}setupCoreEventHandlers(){this.setupSyncEventHandlers(),this.setupDownloadEventHandlers(),this.setupCommandEventHandlers(),this.core.on(d.COLLECTION_START,()=>{this.updateStatus(`Collecting data from CMS...`)}),this.core.on(d.REGISTER_COMPLETE,e=>{let t=this.displaySettings?.getDisplayName()||e.displayName||T.hardwareKey;this.updateStatus(`Registered: ${t}`),this.displaySettings&&(document.title=`xiboplayer - ${this.displaySettings.getDisplayName()}`);let n=parseFloat(e?.settings?.latitude),r=parseFloat(e?.settings?.longitude);n&&r&&!isNaN(n)&&!isNaN(r)?(b.info(`Display location from CMS: ${n.toFixed(4)}, ${r.toFixed(4)}`),w?.setLocation&&w.setLocation(n,r)):this.core.requestGeoLocation&&(b.info(`No CMS coordinates, requesting browser geolocation...`),this.core.requestGeoLocation()),!e.syncConfig&&T.data?.sync&&(b.info(`[Sync] Using local sync config (CMS did not provide syncConfig)`),this.core.syncConfig=T.data.sync,this.core.emit(d.SYNC_CONFIG,T.data.sync))}),this.core.on(d.OFFLINE_MODE,e=>{e?(this.updateStatus(`Offline mode — using cached content`),this.showOfflineIndicator()):(this.updateStatus(`Back online`),this.removeOfflineIndicator())}),this.core.on(d.SCHEDULE_RECEIVED,e=>{if(this.updateStatus(`Processing schedule...`),e.layouts&&e.layouts.length>0?this.currentScheduleId=parseInt(e.layouts[0].scheduleid)||-1:e.campaigns&&e.campaigns.length>0&&(this.currentScheduleId=parseInt(e.campaigns[0].scheduleid)||-1),this.renderer?.layoutPool){let t=new Set;if(e.layouts)for(let n of e.layouts){let e=l(n.file||n.id||n);e&&t.add(e)}if(e.campaigns){for(let n of e.campaigns)if(n.layouts)for(let e of n.layouts){let n=l(e.file||e.id||e);n&&t.add(n)}}let n=this.renderer.layoutPool.clearWarmNotIn(t);n>0&&b.info(`Cleared ${n} preloaded layout(s) no longer in schedule`),this.scheduledLayoutIds=t}b.debug(`Current scheduleId for stats:`,this.currentScheduleId)}),this.core.on(d.LAYOUT_PREPARE_REQUEST,async e=>{await this.prepareLayout(e),(!this.syncManager||this.renderer.getCurrentLayoutId()===null)&&this.renderer.showLayout(e)}),this.core.on(d.LAYOUT_ALREADY_PLAYING,e=>{this.renderer.hasActiveLayoutTimer()||(b.warn(`Layout ${e} has no active timer — restarting layout`),this.renderer.stopCurrentLayout())}),this.core.on(d.LAYOUT_EXPIRE_CURRENT,()=>{b.info(`Schedule changed — expiring current layout`),this.renderer.stopCurrentLayout()}),this.core.on(d.NO_LAYOUTS_SCHEDULED,()=>{this.updateStatus(`No layouts scheduled`)}),this.core.on(d.COLLECTION_COMPLETE,()=>{let e=this.core.getCurrentLayoutId();e?this.updateStatus(`Playing layout ${e}`):this.preparingLayoutId&&this.updateStatus(`Downloading layout ${this.preparingLayoutId}...`)}),this.core.on(d.COLLECTION_ERROR,async e=>{this.updateStatus(`Collection error: ${e}`,`error`);let t=e?.message||String(e);if(t.includes(`403`)&&(t.includes(`Display not found`)||t.includes(`not authorized`))){b.warn(`Display not registered or not authorized — showing setup screen`),this.setupOverlay||=new y,this.setupOverlay.show();return}this.reportFault(`COLLECTION_FAILED`,`Collection cycle failed: ${e?.message||e}`)}),this.core.on(d.XMR_CONNECTED,e=>{b.info(`XMR connected:`,e)}),this.core.on(d.XMR_MISCONFIGURED,e=>{b.warn(`XMR misconfigured (${e.reason}): ${e.message}`)}),this.core.on(d.LOG_LEVEL_CHANGED,()=>{b.info(`Log level changed`)}),this.core.on(d.OVERLAY_LAYOUT_REQUEST,async e=>{b.info(`Overlay layout requested:`,e),await this.prepareLayout(e),this.renderer.showLayout(e)}),this.core.on(d.REVERT_TO_SCHEDULE,()=>{b.info(`Reverting to scheduled content`),this.updateStatus(`Reverting to schedule...`)}),this.displaySettings&&(this.displaySettings.on(`interval-changed`,e=>{b.info(`Collection interval changed to ${e}s`)}),this.displaySettings.on(`settings-applied`,(e,t)=>{t.length>0&&b.info(`Settings updated from CMS:`,t.join(`, `)),this._screenshotInterval||this.startScreenshotInterval()})),this.core.on(d.SUBMIT_STATS_REQUEST,async()=>{await this.submitStats()}),this.core.on(d.SUBMIT_LOGS_REQUEST,async()=>{await this.submitLogs()}),this.core.on(d.SCREENSHOT_REQUEST,async()=>{await this.captureAndSubmitScreenshot()}),this.core.on(d.CHECK_PENDING_LAYOUT,async e=>{await this.prepareLayout(e),this.renderer.showLayout(e)}),this.core.on(d.NAVIGATE_TO_WIDGET,e=>{e.targetId?this.renderer.navigateToWidget(e.targetId):b.warn(`navigate-to-widget action has no targetId:`,e)}),this.core.on(d.TIMELINE_UPDATED,e=>{let t=this.core.getCurrentLayoutId(),n=t?this.core.getLayoutDuration(t):void 0;this.timelineOverlay?.update(e,t,n)})}setupSyncEventHandlers(){this.core.on(d.OFFLINE_MODE,e=>{e&&!this.syncManager&&T.data?.sync&&(b.info(`[Sync] Offline mode with local sync config — starting sync`),this.core.syncConfig=T.data.sync,this.core.emit(d.SYNC_CONFIG,T.data.sync))}),this.core.on(d.SYNC_CONFIG,async e=>{if(this.syncManager&&this.syncManager.stop(),e.syncPublisherPort)if(e.syncGroupId&&(e.syncGroup=String(e.syncGroupId)),e.isLead)e.relayUrl=`ws://localhost:${e.syncPublisherPort}/sync`,fetch(`/system/advertise-sync`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({syncGroupId:e.syncGroupId,port:e.syncPublisherPort,displayId:T.hardwareKey})}).catch(()=>{});else{let t=e.syncGroup;try{let n=await fetch(`/system/discover-lead?syncGroupId=${e.syncGroupId}`);if(n.ok){let{host:e,port:r}=await n.json();t=e,b.info(`mDNS discovered lead at ${e}:${r}`)}}catch{b.warn(`mDNS discovery failed, using CMS-provided IP`)}e.relayUrl=`ws://${t}:${e.syncPublisherPort}/sync`}let{syncToken:t,...n}=e,r={...T.data?.sync||{},...n};window.electronAPI?.setConfig?window.electronAPI.setConfig({sync:r}):fetch(`/config`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sync:r})}).catch(()=>{}),e.syncToken||=T.cmsKey,this.syncManager=new L({displayId:T.hardwareKey,syncConfig:e,onLayoutChange:async t=>{let n=(e.layoutMap||T.sync?.layoutMap)?.[t]??t;n!==t&&b.info(`[Sync] Wall mode: lead layout ${t} → local layout ${n}`),b.info(`[Sync] Preparing layout ${n} (waiting for show signal)`),await this.prepareLayout(parseInt(String(n),10)),this.syncManager?.reportReady(t)},onLayoutShow:t=>{let n=(e.layoutMap||T.sync?.layoutMap)?.[t]??t,r=parseInt(String(n),10),i=e.choreography||`simultaneous`,a={choreography:i,staggerMs:e.staggerMs??150};e.topology?(a.topology=e.topology,a.gridCols=e.gridCols??1,a.gridRows=e.gridRows??1):(a.position=e.position??0,a.totalDisplays=e.totalDisplays??1);let o=R(a);o>0?(b.info(`[Sync] Show layout ${r} with ${o}ms choreography delay (${i})`),setTimeout(()=>this.renderer.showLayout(r),o)):(b.info(`[Sync] Show layout ${r}`),this.renderer.showLayout(r))},onVideoStart:(e,t)=>{b.info(`[Sync] Video start: layout ${e} region ${t}`),this.renderer.resumeRegionMedia?.(t)},onStatsReport:async(e,t,n)=>{b.info(`[Sync] Submitting stats for follower ${e}`);try{await this.xmds.submitStats(t,e)&&n()}catch(t){b.warn(`[Sync] Stats submission failed for follower ${e}:`,t)}},onLogsReport:async(e,t,n)=>{b.info(`[Sync] Submitting logs for follower ${e}`);try{await this.xmds.submitLog(t,e)&&n()}catch(t){b.warn(`[Sync] Log submission failed for follower ${e}:`,t)}},onStatsAck:async e=>{b.info(`[Sync] Lead confirmed stats submission`),this._pendingFollowerStats&&this.statsCollector&&(await this.statsCollector.clearSubmittedStats(this._pendingFollowerStats),this._pendingFollowerStats=null)},onLogsAck:async e=>{b.info(`[Sync] Lead confirmed logs submission`),this._pendingFollowerLogs&&this.logReporter&&(await this.logReporter.clearSubmittedLogs(this._pendingFollowerLogs),this._pendingFollowerLogs=null)},onGroupUpdate:(t,n)=>{b.info(`[Sync] Group update: ${t} displays, topology: ${JSON.stringify(n)}`),e.totalDisplays=t}}),this.core.setSyncManager(this.syncManager),this.syncManager.start(),b.info(`[Sync] SyncManager started as ${e.isLead?`LEAD`:`FOLLOWER`}`),this.updateConfigDisplay()})}setupDownloadEventHandlers(){this.core.on(d.FILES_RECEIVED,e=>{this.updateStatus(`Downloading ${e.length} files...`)}),this.core.on(d.DOWNLOAD_REQUEST,async e=>{this.downloadOverlay?.startUpdating();try{let t=this.xmds?.getToken?.()||null;t&&await fetch(`/auth-token`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({token:t})}),await this.enqueueDownloads(e),b.info(`Download enqueue complete`)}catch(e){b.error(`Download request failed:`,e),this.updateStatus(`Download failed: `+e,`error`)}}),this.core.on(d.PURGE_REQUEST,async e=>{try{let t=await A.remove(e);b.info(`Purge complete: ${t.deleted}/${t.total} files deleted`)}catch(e){b.warn(`Purge failed:`,e)}}),this.core.on(d.PURGE_ALL_REQUEST,async()=>{b.info(`Purging all cached content...`),this.updateStatus(`Purging cache...`);try{let e=await A.list();if(e.length>0){let t=await A.remove(e);b.info(`Purged ${t.deleted} files from ContentStore`)}let t=await caches.keys();t.length>0&&(await Promise.all(t.map(e=>caches.delete(e))),b.info(`Purged ${t.length} legacy caches`))}catch(e){b.error(`Cache purge failed:`,e)}})}setupCommandEventHandlers(){this.core.on(d.EXECUTE_NATIVE_COMMAND,async e=>{let t;if(window.electronAPI?.executeShellCommand)t=await window.electronAPI.executeShellCommand({commandString:e.commandString});else try{t=await(await fetch(`/shell-command`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({commandString:e.commandString})})).json()}catch(e){t={success:!1,reason:e.message}}this.core.emit(d.COMMAND_RESULT,{code:e.code,...t})}),this.core.on(d.COMMAND_RESULT,e=>{b.info(`Command result:`,e),e.success||this.reportFault(`COMMAND_FAILED`,`Command ${e.code} failed: ${e.reason||`unknown`}`)}),this.core.on(d.SCHEDULED_COMMAND,e=>{b.info(`Scheduled command: ${e.code}`),this.core.executeCommand(e.code)})}setupInteractiveControl(){this._swIcHandler=e=>{if(e.data?.type!==`INTERACTIVE_CONTROL`)return;let{method:t,path:n,search:r,body:i}=e.data,a=e.ports?.[0];if(!a)return;let o=this.handleInteractiveControl(t,n,r,i);a.postMessage(o)},navigator.serviceWorker?.addEventListener(`message`,this._swIcHandler)}setupDataConnectorNotify(){this.core.getDataConnectorManager().on(`data-changed`,e=>{let t=document.querySelectorAll(`iframe`),n={ctrl:`rtNotifyData`,data:{dataKey:e}};for(let e of t)try{e.contentWindow?.postMessage(n,`*`)}catch{}})}setupRemoteControls(){window.addEventListener(`blur`,()=>{this.setupOverlay?.isVisible()||setTimeout(()=>window.focus(),200)});let e=e=>{let t=()=>{try{let t=e.contentDocument||e.contentWindow?.document;if(!t||e.__keyForwarderAttached)return;e.__keyForwarderAttached=!0,t.addEventListener(`keydown`,e=>{if(this.setupOverlay?.isVisible())return;let t=new KeyboardEvent(`keydown`,{key:e.key,code:e.code,keyCode:e.keyCode,ctrlKey:e.ctrlKey,shiftKey:e.shiftKey,altKey:e.altKey,metaKey:e.metaKey,bubbles:!0,cancelable:!0});document.dispatchEvent(t)||e.preventDefault()})}catch{}};e.addEventListener(`load`,t),t()};Array.from(document.querySelectorAll(`iframe`)).forEach(t=>e(t)),this._iframeObserver=new MutationObserver(t=>{for(let n of t)for(let t of n.addedNodes)t instanceof HTMLIFrameElement&&e(t),t instanceof HTMLElement&&t.querySelectorAll(`iframe`).forEach(t=>e(t))}),this._iframeObserver.observe(document.body,{childList:!0,subtree:!0});let{keyboard:t={}}=this.getControls(),n=t.debugOverlays===!0,r=t.setupKey===!0,i=t.playbackControl===!0,a=t.videoControls===!0;document.addEventListener(`keydown`,e=>{if(e.key===`q`&&(e.ctrlKey||e.metaKey)){e.preventDefault(),b.info(`[Remote] Quit requested (Ctrl+Q)`),fetch(`/quit`,{method:`POST`}).catch(()=>{});return}switch(e.key){case`t`:case`T`:if(!n)break;this.timelineOverlay||=new g(!0,e=>this.skipToLayout(e)),this.timelineOverlay.toggle();break;case`d`:case`D`:if(!n)break;this.downloadOverlay||(this.downloadOverlay=new m({enabled:!0,autoHide:!1}),this.downloadOverlay.setProgressCallback(()=>j.getProgress())),this.downloadOverlay.toggle();break;case`v`:case`V`:{if(!a)break;let e=[...document.querySelectorAll(`video`)];document.querySelectorAll(`iframe`).forEach(t=>{try{e.push(...t.contentDocument.querySelectorAll(`video`))}catch{}});let t=e.length>0&&!e[0].controls;e.forEach(e=>e.controls=t);break}case`ArrowRight`:case`PageDown`:if(!i)break;b.info(`[Remote] Next layout (keyboard)`),this.core.advanceToNextLayout(),e.preventDefault();break;case`ArrowLeft`:case`PageUp`:if(!i)break;b.info(`[Remote] Previous layout (keyboard)`),this.core.advanceToPreviousLayout(),e.preventDefault();break;case` `:if(!i)break;b.info(`[Remote] Toggle pause (keyboard)`),this.renderer.isPaused()?this.renderer.resume():this.renderer.pause(),e.preventDefault();break;case`r`:case`R`:if(!i)break;this.core.isLayoutOverridden()&&(b.info(`[Remote] Revert to schedule (keyboard)`),this.core.revertToSchedule());break;case`s`:case`S`:if(!r)break;this.setupOverlay||=new y,this.setupOverlay.toggle(),e.preventDefault();break}}),i&&`mediaSession`in navigator&&(navigator.mediaSession.setActionHandler(`nexttrack`,()=>{b.info(`[Remote] Next layout (MediaSession)`),this.core.advanceToNextLayout()}),navigator.mediaSession.setActionHandler(`previoustrack`,()=>{b.info(`[Remote] Previous layout (MediaSession)`),this.core.advanceToPreviousLayout()}),navigator.mediaSession.setActionHandler(`pause`,()=>{b.info(`[Remote] Pause (MediaSession)`),this.renderer.pause()}),navigator.mediaSession.setActionHandler(`play`,()=>{b.info(`[Remote] Resume (MediaSession)`),this.renderer.resume()})),b.info(`Remote controls initialized (keyboard + MediaSession)`)}getControls(){return T.controls}skipToLayout(e){b.info(`Skipping to layout ${e} (timeline click)`),this.core.changeLayout(e)}parseBody(e){try{return e?JSON.parse(e):{}}catch{return{}}}handleInteractiveControl(e,t,n,r){switch(b.debug(`IC request:`,e,t,n),t){case`/info`:return{status:200,body:JSON.stringify({hardwareKey:T.hardwareKey,displayName:T.displayName,playerType:`pwa`,currentLayoutId:this.core.getCurrentLayoutId()})};case`/trigger`:{let e=this.parseBody(r);return this.renderer.emit(`interactiveTrigger`,{targetId:e.id,triggerCode:e.trigger}),e.trigger&&this.core.handleTrigger(e.trigger),{status:200,body:`OK`}}case`/duration/expire`:{let e=this.parseBody(r);return b.info(`IC: Widget duration expire requested for`,e.id),this.renderer.emit(`widgetExpire`,{widgetId:e.id}),{status:200,body:`OK`}}case`/duration/extend`:{let e=this.parseBody(r);return b.info(`IC: Widget duration extend by`,e.duration,`for`,e.id),this.renderer.emit(`widgetExtendDuration`,{widgetId:e.id,duration:parseInt(e.duration)}),{status:200,body:`OK`}}case`/duration/set`:{let e=this.parseBody(r);return b.info(`IC: Widget duration set to`,e.duration,`for`,e.id),this.renderer.emit(`widgetSetDuration`,{widgetId:e.id,duration:parseInt(e.duration)}),{status:200,body:`OK`}}case`/fault`:{let e=this.parseBody(r);return this.reportFault(e.code||`WIDGET_FAULT`,e.reason||`Widget reported fault`,{layoutId:e.layoutId,regionId:e.regionId,widgetId:e.widgetId}),{status:200,body:`OK`}}case`/realtime`:{let e=new URLSearchParams(n).get(`dataKey`);if(b.debug(`IC: Realtime data request for key:`,e),!e)return{status:400,body:JSON.stringify({error:`Missing dataKey parameter`})};let t=this.core.getDataConnectorManager().getData(e);return t===null?{status:404,body:JSON.stringify({error:`No data available for key: ${e}`})}:{status:200,body:typeof t==`string`?t:JSON.stringify(t)}}case`/criteria`:return{status:200,body:JSON.stringify({displayId:T.displayId,hardwareKey:T.hardwareKey,displayName:T.displayName,width:window.innerWidth,height:window.innerHeight,latitude:T.latitude||null,longitude:T.longitude||null,playerType:`pwa`})};default:return{status:404,body:JSON.stringify({error:`Unknown IC route`})}}}notifyFileCached(e,t){if(b.debug(`Download complete: ${t}/${e}`),t===`layout`)this.core.notifyMediaReady(parseInt(e),t);else if(t===`media`){let n=this._fileIdToSaveAs.get(e)||e;this._cachedMediaKeys.add(n),this.core.notifyMediaReady(n,t)}else this._cachedMediaKeys.add(e);this._probeTimer&&clearTimeout(this._probeTimer),this._probeTimer=setTimeout(()=>{this._probeTimer=null,this.probeLayoutDurations().catch(()=>{})},3e3),this._mediaStatusTimer&&clearTimeout(this._mediaStatusTimer),this._mediaStatusTimer=setTimeout(()=>{this._mediaStatusTimer=null,this.checkTimelineMediaStatus().catch(()=>{})},2e3)}async enqueueDownloads(e){let{extractMediaIdsFromXlf:n}=await t(async()=>{let{extractMediaIdsFromXlf:e}=await import(`./src-Kaan1uxV.js`);return{extractMediaIdsFromXlf:e}},__vite__mapDeps([0,1,2]),import.meta.url),{layoutOrder:r,files:i,layoutDependants:a}=e,o=e=>(e.path||``).split(`?`)[0].replace(/^\/+/,``)||`${e.type||`media`}/${e.id}`;for(let e of i)e.saveAs&&this._fileIdToSaveAs.set(String(e.id),e.saveAs);let c=new Map,l=[],u=new Map,d=new Map;for(let e of i)if(e.type===`layout`)c.set(parseInt(e.id),e);else if(e.type===`static`)l.push(e);else{let t=`${e.type}:${e.id}`;u.set(t,e);let n=String(e.id);d.has(n)||d.set(n,[]),d.get(n).push(t)}b.info(`Download: ${r.length} layouts, ${u.size} media, ${l.length} resources`);let f=new Map,p=[...r,...[...c.keys()].filter(e=>!r.includes(e))].map(async e=>{let t=c.get(e);if(!t?.path)return;let r;try{let n={};t.cmsDownloadUrl&&(n[`X-Cms-Download-Url`]=t.cmsDownloadUrl);let i=await fetch(t.path,Object.keys(n).length?{headers:n}:void 0);i.ok&&(r=await i.text(),b.info(`Fetched XLF ${e} (${r.length} bytes)`),await A.put(`${x}/layouts`,String(e),new Blob([r],{type:`text/xml`})),this.notifyFileCached(String(e),`layout`))}catch{}r&&f.set(e,n(r,b))});await Promise.allSettled(p),b.info(`Parsed ${f.size} XLFs`);let m=async(e,t)=>{if(!t.path||t.path===`null`||t.path===`undefined`)return!1;let n=o(t);try{if((await fetch(`/store/${n}`,{method:`HEAD`})).status===200)return!1}catch{}let r=`${t.type}/${t.id}`;if(j.getTask(r))return!1;try{let e=await fetch(`/store/missing-chunks/${n}`);if(e.ok){let{missing:r,numChunks:i}=await e.json();if(i>0&&r.length<i){let e=new Set;for(let t=0;t<i;t++)r.includes(t)||e.add(t);t.skipChunks=e,b.info(`Resuming ${n}: ${e.size}/${i} chunks cached, ${r.length} to download`)}}}catch{}let i=e.addFile(t);return i.state===`pending`?(i.wait().then(e=>{let i=parseInt(t.size)||e.size;b.info(`Download complete:`,n,`(${i} bytes)`),i>this._chunkConfig.chunkSize&&fetch(`/store/mark-complete`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({storeKey:n})}).catch(e=>b.warn(`mark-complete failed:`,n,e.message)),this.notifyFileCached(String(t.id),t.type),j.removeCompleted(r)}).catch(e=>{b.error(`Download failed:`,t.id,e),j.removeCompleted(r)}),!0):!1},h=j.createTaskBuilder();await Promise.all(l.map(e=>m(h,e)));let g=await h.build();g.length>0&&(g.push(s),j.enqueueOrderedTasks(g));let _=new Set,v=[...f.keys()].filter(e=>!r.includes(e)),y=new Map;for(let[e,t]of u)t.saveAs&&y.set(t.saveAs,e);let S=new Map;if(a)for(let[e,t]of Object.entries(a))S.set(parseInt(e,10),t);for(let e of r){let t=f.get(e);if(!t)continue;let n=new Set(t);for(let e of v){let t=f.get(e);if(t)for(let e of t)n.add(e)}let r=S.get(e)||[];for(let e of r){let t=y.get(e);t&&n.add(t)}let i=[];for(let e of n){if(u.has(e)&&!_.has(e)){i.push(u.get(e)),_.add(e);continue}let t=d.get(String(e))||[];for(let e of t)_.has(e)||(i.push(u.get(e)),_.add(e))}if(i.length===0)continue;b.info(`Layout ${e}: ${i.length} media`),i.sort((e,t)=>(e.size||0)-(t.size||0));let a=j.createTaskBuilder();await Promise.all(i.map(e=>m(a,e)));let o=await a.build();o.length>0&&(o.push(s),j.enqueueOrderedTasks(o))}let C=[...u.keys()].filter(e=>!_.has(e));if(C.length>0){b.info(`${C.length} media not in any XLF`);let e=j.createTaskBuilder();await Promise.all(C.map(t=>{let n=u.get(t);return n?m(e,n):Promise.resolve(!1)}));let t=await e.build();t.length>0&&j.enqueueOrderedTasks(t)}b.info(`Downloads active:`,j.running,`, queued:`,j.queued)}setupRendererEventHandlers(){this.renderer.on(`layoutStart`,(e,t)=>{b.info(`Layout started:`,e),this.updateStatus(`Playing layout ${e}`),this.core.setCurrentLayout(e),this._currentLayoutEnableStat=t?.enableStat!==!1;let n=this.core.getLayoutDuration(e)||t?.duration;this.timelineOverlay?.update(null,e,n),this.statsCollector&&this._currentLayoutEnableStat&&this.statsCollector.startLayout(e,this.currentScheduleId).catch(e=>{b.error(`Failed to start layout stat:`,e)})}),this.renderer.on(`layoutEnd`,e=>{if(b.info(`Layout ended:`,e),w?.recordPlay(e.toString()),this.statsCollector&&this._currentLayoutEnableStat&&this.statsCollector.endLayout(e,this.currentScheduleId).catch(e=>{b.error(`Failed to end layout stat:`,e)}),this.renderer.getCurrentLayoutId()&&this.renderer.getCurrentLayoutId()!==e){b.debug(`Layout ${e} ended but ${this.renderer.getCurrentLayoutId()} already playing, skipping advance`);return}if(this.preparingLayoutId&&this.preparingLayoutId!==e){b.debug(`Layout ${e} ended but ${this.preparingLayoutId} being prepared, skipping advance`);return}this.core.notifyLayoutStatus(e),this.core.clearCurrentLayout();let t=this.core.getPendingLayouts();if(t.length>0){b.info(`Layout ${t[0]} pending download, skipping advance`);return}b.info(`Layout cycle completed, advancing to next layout...`),this.core.advanceToNextLayout()}),this.renderer.on(`widgetStart`,e=>{let{widgetId:t,layoutId:n,mediaId:r}=e;b.debug(`Widget started:`,e.type,t,`media:`,r),this.statsCollector&&r&&e.enableStat!==!1&&this.statsCollector.startWidget(r,n,this.currentScheduleId).catch(e=>{b.error(`Failed to start widget stat:`,e)})}),this.renderer.on(`widgetEnd`,e=>{let{widgetId:t,layoutId:n,mediaId:r}=e;b.debug(`Widget ended:`,e.type,t,`media:`,r),this.statsCollector&&r&&e.enableStat!==!1&&this.statsCollector.endWidget(r,n,this.currentScheduleId).catch(e=>{b.error(`Failed to end widget stat:`,e)})}),this.renderer.on(`widgetCommand`,e=>{b.info(`Widget command:`,e.commandCode);let t={[e.commandCode]:{commandString:e.commandString}};this.core.executeCommand(e.commandCode,t)}),this.renderer.on(`error`,e=>{b.error(`Renderer error:`,e),this.updateStatus(`Error: ${e.type}`,`error`),this.reportFault(e.type||`RENDERER_ERROR`,`Renderer error: ${e.message||e.type}`,{layoutId:e.layoutId,regionId:e.regionId,widgetId:e.widgetId})}),this.renderer.on(`action-trigger`,e=>{let{actionType:t,triggerCode:n,layoutCode:r,targetId:i,commandCode:a}=e;switch(b.info(`Action trigger:`,t,e),t){case`navLayout`:case`navigateToLayout`:n?this.core.handleTrigger(n):r&&this.core.changeLayout(r);break;case`navWidget`:case`navigateToWidget`:n?this.core.handleTrigger(n):i&&this.renderer.navigateToWidget(i);break;case`previousWidget`:this.renderer.previousWidget(e.source?.regionId);break;case`nextWidget`:this.renderer.nextWidget(e.source?.regionId);break;case`command`:a&&this.core.executeCommand(a);break;default:b.warn(`Unknown action type:`,t)}this.statsCollector&&this.statsCollector.recordEvent(`touch`,this.core.getCurrentLayoutId(),e.targetId||null,this.currentScheduleId)}),this.renderer.on(`widgetAction`,e=>{e.type===`durationEnd`&&e.url&&(b.info(`Widget ${e.widgetId} duration ended, calling webhook: ${e.url}`),this.statsCollector&&this.statsCollector.recordEvent(`webhook`,e.layoutId,e.widgetId,this.currentScheduleId),fetch(e.url,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({widgetId:e.widgetId,layoutId:e.layoutId,regionId:e.regionId,event:`durationEnd`,timestamp:new Date().toISOString()})}).catch(e=>b.warn(`Webhook failed (non-critical):`,e)))}),this.renderer.on(`layoutDurationUpdated`,(e,t,n)=>{this.core.recordLayoutDuration(String(e),t,n)}),this.renderer.on(`request-next-layout-preload`,async()=>{try{let e=this.core.peekNextLayout();if(!e){b.debug(`No next layout to preload (single layout schedule or same layout)`);return}let t=e.layoutId;if(this.renderer.layoutPool.has(t)){b.debug(`Layout ${t} already in preload pool`);return}if(this.renderer._preloadingLayoutId===t){b.debug(`Layout ${t} preload already in-flight`);return}b.info(`Preloading next layout ${t}...`);let n=await A.get(`${x}/layouts`,t);if(!n){b.debug(`Layout ${t} XLF not cached, skipping preload`);return}let r=await n.text(),i=new DOMParser().parseFromString(r,`text/xml`),{allMedia:a}=this.getMediaIds(i);if(!await this.checkAllMediaCached(a)){b.debug(`Media not fully cached for layout ${t}, skipping preload`);return}await this.fetchWidgetHtml(i,t),await this.renderer.preloadLayout(r,t)?b.info(`Layout ${t} preloaded successfully`):b.warn(`Layout ${t} preload failed (will fall back to normal render)`)}catch(e){b.warn(`Layout preload failed (non-blocking):`,e)}}),this.renderer.on(`videoError`,async({storedAs:e})=>{if(!e)return;let t=`${i.slice(1)}/media/file/${e}`;try{let{missing:n}=await(await fetch(`/store/missing-chunks/${t}`)).json();if(n.length===0){b.warn(`Video ${e}: corrupt file (all chunks present), deleting for re-download`),await fetch(`/store/delete`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({files:[{key:t}]})});let n=this.core.getCurrentLayoutId();n&&this.core.setPendingLayout(n,[e]),this.core.collectNow().catch(t=>{b.error(`Failed to trigger re-download for ${e}:`,t.message)});return}b.warn(`Video ${e}: ${n.length} missing chunks (${n.join(`, `)}), re-downloading`),await fetch(`/store/unmark-complete`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({storeKey:t})}),this.core.collectNow().catch(t=>{b.error(`Failed to trigger re-download for ${e}:`,t.message)})}catch(t){b.error(`Failed to check/re-download ${e}:`,t.message)}})}async prepareLayout(e){if(this.renderer.getCurrentLayoutId()===e){b.debug(`Layout ${e} replay`),this.core.clearPreparingLayout(),await this.renderer.renderLayout(``,e);return}if(this.preparingLayoutId===e){b.debug(`Layout ${e} preparation in progress, will retry after it completes`),this._pendingRetryLayoutId=e;return}this.preparingLayoutId=e;try{let t=await A.get(`${x}/layouts`,e);if(!t){b.info(`Layout not in cache yet, marking as pending:`,e),this.core.setPendingLayout(e,[String(e)]),this.updateStatus(`Downloading layout ${e}...`);return}let n=await t.text(),r=new DOMParser().parseFromString(n,`text/xml`),{allMedia:i}=this.getMediaIds(r);if(!await this.checkAllMediaCached(i)){j.prioritizeLayoutFiles(i.map(String)),b.info(`Waiting for media to finish downloading for layout ${e}`),this.updateStatus(`Preparing layout ${e}...`),this.core.setPendingLayout(e,i);return}this.renderer.hasPreloadedLayout(e)||await this.fetchWidgetHtml(r,e),await this.renderer.preloadLayout(n,e),this.core.pendingLayouts.delete(e),b.info(`Layout ${e} ready`)}catch(t){b.error(`Failed to prepare layout:`,e,t),this.updateStatus(`Failed to load layout ${e}`,`error`),this.reportFault(`LAYOUT_LOAD_FAILED`,`Failed to prepare layout ${e}: ${t?.message||t}`,{layoutId:e})}finally{this.preparingLayoutId=null,this.core.clearPreparingLayout();let e=this._pendingRetryLayoutId;this._pendingRetryLayoutId=null,e!=null&&this.core.getCurrentLayoutId()!==e&&(b.debug(`Retrying preparation for layout ${e} after 500ms`),setTimeout(()=>this.prepareLayout(e),500))}}getMediaIds(e){let t=typeof e==`string`?new DOMParser().parseFromString(e,`text/xml`):e,n=[],r=[];t.querySelectorAll(`media[fileId]`).forEach(e=>{let t=e.getAttribute(`fileId`);if(t){let i=this._fileIdToSaveAs.get(t)||t;if(i.endsWith(`.xlf`))return;n.push(i),e.getAttribute(`type`)===`video`&&r.push(i)}});let i=t.querySelector(`layout`)?.getAttribute(`background`);if(i){let e=this._fileIdToSaveAs.get(i)||i;n.includes(e)||n.push(e)}return{allMedia:n,videoMedia:r}}async checkAllMediaCached(e){let t=e.filter(e=>!this._cachedMediaKeys.has(e));if(t.length===0)return!0;let n=t,r=await Promise.all(n.map(async e=>{try{let t=await A.has(x,`media/file/${e}`);return t&&this._cachedMediaKeys.add(e),t}catch{return b.warn(`Unable to verify media ${e}, assuming cached (offline mode)`),!0}})),i=n.filter((e,t)=>!r[t]);return i.length>0?(b.debug(`Media not yet cached: ${i.join(`, `)}`),!1):!0}async fetchWidgetHtml(e,t){let n=typeof e==`string`?new DOMParser().parseFromString(e,`text/xml`):e,r=[];for(let e of n.querySelectorAll(`region`)){let i=e.getAttribute(`id`);for(let a of e.querySelectorAll(`media`)){let e=a.getAttribute(`type`),o=a.getAttribute(`id`);a.getAttribute(`render`)===`html`&&r.push((async()=>{try{let r=`${t}/${i}/${o}`,s=null,c=await A.get(`${x}/widgets`,r);c&&(s=await c.text(),b.debug(`Found cached widget HTML for ${e} ${o}`)),s||(s=await this.xmds.getResource(t,i,o),b.debug(`Retrieved widget HTML for ${e} ${o} from CMS`)),s=(await C(t,i,o,s)).html;let l=a.querySelector(`raw`);if(l)l.textContent=s;else{let e=n.createElement(`raw`);e.textContent=s,a.appendChild(e)}}catch(t){b.warn(`Failed to get widget HTML for ${e} ${o}:`,t)}})())}}r.length>0&&(b.info(`Fetching ${r.length} widget HTML resources in parallel...`),await Promise.all(r),b.debug(`All widget HTML fetched`))}async checkTimelineMediaStatus(){if(this.scheduledLayoutIds.size!==0){for(let e of this.scheduledLayoutIds){let t=`${e}.xlf`;try{let n=await A.get(`${x}/layouts`,e);if(!n)continue;let r=await n.text(),{allMedia:i}=this.getMediaIds(r);if(i.length===0){this.core.setLayoutMediaStatus(t,!0);continue}let a=[];for(let e of i){if(this._cachedMediaKeys.has(e))continue;let t=`${x}/media/file/${e}`;if(j.getTask(t)){a.push(e);continue}try{await A.has(x,`media/file/${e}`)?this._cachedMediaKeys.add(e):a.push(e)}catch{}}this.core.setLayoutMediaStatus(t,a.length===0,a)}catch{}}this.core.logUpcomingTimeline()}}async probeLayoutDurations(){if(this.scheduledLayoutIds.size!==0)for(let e of this.scheduledLayoutIds)try{let t=await A.get(`${x}/layouts`,e);if(!t)continue;let n=await t.text(),{videoMedia:r}=this.getMediaIds(n);if(r.length===0)continue;let a=new DOMParser().parseFromString(n,`text/xml`),o=new Map,s=0;for(let e of a.querySelectorAll(`media[type="video"]`)){if(e.getAttribute(`useDuration`)===`1`)continue;let t=e.getAttribute(`fileId`);if(!t)continue;s++;let n=this._fileIdToSaveAs.get(t)||t;if(!await A.has(x,`media/file/${n}`))continue;let r=await this.probeVideoDuration(`${window.location.origin}${i}/media/file/${n}`);r>0&&o.set(t,r)}if(o.size===0)continue;let c=o.size>=s,{duration:l}=u(n,o);l>0&&this.core.recordLayoutDuration(String(e),l,c)}catch(t){b.debug(`Duration probe failed for layout ${e}:`,t)}}probeVideoDuration(e){return new Promise(t=>{let n=document.createElement(`video`);n.preload=`metadata`,n.muted=!0;let r=()=>{n.removeAttribute(`src`),n.load()};n.addEventListener(`loadedmetadata`,()=>{let e=n.duration;r(),t(e)},{once:!0}),n.addEventListener(`error`,()=>{r(),t(0)},{once:!0}),setTimeout(()=>{r(),t(0)},5e3),n.src=e})}updateConfigDisplay(){let e=document.getElementById(`config-info`);if(e){let t=`0.7.16`,n=`2026-04-07 19:53:44.301Z`.replace(/\.\d+Z$/,``),r=`${n?`v${t} (${n})`:`v${t}`} | CMS: ${T.cmsUrl} | Display: ${T.displayName||`Unknown`} | HW: ${T.hardwareKey}`,i=this.core?.getSyncConfig?.();if(i){let e=i.relayUrl?new URL(i.relayUrl).host:``;r+=` | Sync: ${i.isLead?`LEAD`:`FOLLOWER → ${e}`} (group ${i.syncGroupId||i.syncGroup})`}e.textContent=r}}async submitCollectedData(e){let{name:t,pendingFlag:n,getItems:r,formatFn:i,delegateFn:a,submitFn:o,clearFn:s}=e;if(this[n]!==null){b.debug(`${t} delegation in-flight, skipping`);return}try{let e=await r();if(e.length===0){b.debug(`No ${t} to submit`);return}let c=i(e);if(this.syncManager&&!this.syncManager.isLead&&this._syncLeadAlive()){b.info(`[Sync] Delegating ${e.length} ${t} to lead`),this[n]=e,a(c);return}this.syncManager&&!this.syncManager.isLead&&b.warn(`[Sync] Lead not alive, submitting ${t} directly`),b.info(`Submitting ${e.length} ${t} to CMS...`),await o(c)?(b.info(`${t} submitted successfully`),await s(e)):b.warn(`${t} submission failed (CMS returned false)`)}catch(e){b.error(`Failed to submit ${t}:`,e)}}async submitStats(){if(!this.statsCollector){b.warn(`Stats collector not initialized`);return}let e=this.displaySettings?.getSetting(`aggregationLevel`)||`Individual`;await this.submitCollectedData({name:`stats`,pendingFlag:`_pendingFollowerStats`,getItems:async()=>e===`Aggregate`?this.statsCollector.getAggregatedStatsForSubmission(50):this.statsCollector.getStatsForSubmission(50),formatFn:N,delegateFn:e=>this.syncManager.reportStats(e),submitFn:e=>this.xmds.submitStats(e),clearFn:e=>this.statsCollector.clearSubmittedStats(e)})}async submitLogs(){this.logReporter&&await this.submitCollectedData({name:`logs`,pendingFlag:`_pendingFollowerLogs`,getItems:()=>this.logReporter.getLogsForSubmission(),formatFn:F,delegateFn:e=>this.syncManager.reportLogs(e),submitFn:e=>this.xmds.submitLog(e),clearFn:e=>this.logReporter.clearSubmittedLogs(e)})}reportFault(e,t,n){this.logReporter?.reportFault(e,t),this.submitFault(e,t,n)}submitFault(e,t,n){if(!this.xmds)return;let r=JSON.stringify([{code:e,reason:t,date:new Date().toISOString().replace(`T`,` `).substring(0,19),...n}]);this.xmds.reportFaults(r).catch(e=>{b.debug(`reportFaults failed (non-critical):`,e)})}async captureAndSubmitScreenshot(){if(this._screenshotInFlight){b.debug(`Screenshot capture already in progress, skipping`);return}this._screenshotInFlight=!0;try{let e;if(this._screenshotMethod===`electron`||this._screenshotMethod===null&&window.electronAPI?.captureScreenshot){let t=await window.electronAPI.captureScreenshot();if(t)this._screenshotMethod=`electron`,e=t;else{b.debug(`Electron screenshot not ready yet, will retry next interval`);return}}else if(this._screenshotMethod===`displayMedia`||this._screenshotMethod===null&&typeof navigator.mediaDevices?.getDisplayMedia==`function`)try{e=await this.captureDisplayMedia(),this._screenshotMethod=`displayMedia`}catch(t){b.warn(`getDisplayMedia failed, falling back to html2canvas:`,t.message||t),this._screenshotMethod=null,e=await this.captureHtml2CanvasIsolated(),this._screenshotMethod=`html2canvas`}else this._screenshotMethod=`html2canvas`,e=await this.captureHtml2CanvasIsolated();await this.xmds.submitScreenShot(e)?b.info(`Screenshot submitted (${this._screenshotMethod})`):b.warn(`Screenshot submission failed`)}catch(e){b.error(`Failed to capture screenshot:`,e)}finally{this._screenshotInFlight=!1}}async captureDisplayMedia(){let e=await navigator.mediaDevices.getDisplayMedia({video:!0,audio:!1,preferCurrentTab:!0});try{let t=e.getVideoTracks()[0],n=await new window.ImageCapture(t).grabFrame(),r=document.createElement(`canvas`);return r.width=n.width,r.height=n.height,r.getContext(`2d`).drawImage(n,0,0),n.close(),r.toDataURL(`image/jpeg`,.8).split(`,`)[1]}finally{e.getTracks().forEach(e=>e.stop())}}async captureHtml2CanvasIsolated(){let n=document.createElement(`canvas`);n.width=window.innerWidth,n.height=window.innerHeight;let r=n.getContext(`2d`);r.fillStyle=`#000`,r.fillRect(0,0,n.width,n.height);let i=document.getElementById(`player-container`);if(!i)return n.toDataURL(`image/jpeg`,.8).split(`,`)[1];this._html2canvasMod||=(await t(async()=>{let{default:t}=await import(`./html2canvas-Cjd84h1M.js`).then(t=>e(t.default,1));return{default:t}},__vite__mapDeps([14,2]),import.meta.url)).default,this.renderer&&(this.renderer._resizeSuppressed=!0);let a=i.style.contain||``;i.style.contain=`strict`;try{let e=i.getBoundingClientRect(),t=getComputedStyle(i),a=t.backgroundColor;a&&a!==`transparent`&&a!==`rgba(0, 0, 0, 0)`&&(r.fillStyle=a,r.fillRect(e.left,e.top,e.width,e.height));let o=t.backgroundImage;if(o&&o!==`none`){let t=o.match(/url\(["']?(.*?)["']?\)/);if(t)try{let n=new Image;n.crossOrigin=`anonymous`,await new Promise(e=>{n.onload=()=>e(),n.onerror=()=>e(),setTimeout(()=>e(),2e3),n.src=t[1]}),n.naturalWidth&&r.drawImage(n,e.left,e.top,e.width,e.height)}catch{}}let s=i.querySelectorAll(`img, video, iframe, canvas`),c=0;for(let e of s){let t=e;if(t.style.visibility===`hidden`||t.style.display===`none`)continue;let n=e.getBoundingClientRect();if(!(n.width===0||n.height===0))try{if(e instanceof HTMLImageElement){if(!e.complete||!e.naturalWidth)continue;if(getComputedStyle(e).objectFit===`contain`&&e.naturalWidth&&e.naturalHeight){let t=this.containedRect(e.naturalWidth,e.naturalHeight,n);r.drawImage(e,t.x,t.y,t.w,t.h)}else r.drawImage(e,n.left,n.top,n.width,n.height);c++}else if(e instanceof HTMLVideoElement){if(e.readyState<2)continue;if(getComputedStyle(e).objectFit===`contain`&&e.videoWidth&&e.videoHeight){let t=this.containedRect(e.videoWidth,e.videoHeight,n);r.drawImage(e,t.x,t.y,t.w,t.h)}else r.drawImage(e,n.left,n.top,n.width,n.height);c++}else if(e instanceof HTMLCanvasElement)r.drawImage(e,n.left,n.top,n.width,n.height),c++;else if(e instanceof HTMLIFrameElement){let t=e.contentDocument;if(!t?.body)continue;let i=document.createElement(`div`);i.style.cssText=`position:fixed;left:-9999px;top:0;width:${n.width}px;height:${n.height}px;overflow:hidden;`;let a=[];for(let e of t.querySelectorAll(`style`))i.appendChild(e.cloneNode(!0));for(let e of t.querySelectorAll(`link[rel="stylesheet"]`)){let n=document.createElement(`link`);n.rel=`stylesheet`,n.href=new URL(e.getAttribute(`href`)||``,t.baseURI).href,i.appendChild(n),a.push(new Promise(e=>{n.onload=()=>e(),n.onerror=()=>e()}))}let o=t.body.cloneNode(!0);for(let e of o.querySelectorAll(`img[src]`)){let n=e.getAttribute(`src`)||``;n&&!n.startsWith(`http`)&&!n.startsWith(`data:`)&&!n.startsWith(`blob:`)&&e.setAttribute(`src`,new URL(n,t.baseURI).href)}i.appendChild(o),document.body.appendChild(i);let s=t.querySelectorAll(`img`),l=new Map;s.forEach((e,t)=>{e.naturalWidth&&e.naturalHeight&&l.set(String(t),{nw:e.naturalWidth,nh:e.naturalHeight})}),a.length>0&&await Promise.race([Promise.all(a),new Promise(e=>setTimeout(e,500))]);let u=await this._html2canvasMod(i,{useCORS:!0,allowTaint:!0,logging:!1,backgroundColor:null,width:n.width,height:n.height,onclone:e=>{let t=e.createElement(`style`);t.textContent=`*, *::before, *::after { animation: none !important; transition: none !important; opacity: 1 !important; }`,e.head.appendChild(t),e.querySelectorAll(`img`).forEach((t,n)=>{let r=e.defaultView?.getComputedStyle(t);if(!r||r.objectFit!==`contain`)return;let i=l.get(String(n));if(!i)return;let a=t.clientWidth||parseFloat(r.width)||0,o=t.clientHeight||parseFloat(r.height)||0;if(!a||!o)return;let s=i.nw/i.nh,c=a/o,u,d;s>c?(u=a,d=a/s):(d=o,u=o*s);let f=e.createElement(`div`);f.style.cssText=`width:${a}px;height:${o}px;display:flex;align-items:center;justify-content:center;overflow:hidden;`,t.style.objectFit=`fill`,t.style.width=`${u}px`,t.style.height=`${d}px`,t.parentNode?.insertBefore(f,t),f.appendChild(t)})}});document.body.removeChild(i),r.drawImage(u,n.left,n.top,n.width,n.height);let d=e.getBoundingClientRect();for(let e of t.querySelectorAll(`video`)){if(e.readyState<2)continue;let n=e.getBoundingClientRect();if(!(n.width===0||n.height===0))try{if(t.defaultView?.getComputedStyle(e)?.objectFit===`contain`&&e.videoWidth&&e.videoHeight){let t=this.containedRect(e.videoWidth,e.videoHeight,new DOMRect(d.left+n.left,d.top+n.top,n.width,n.height));r.drawImage(e,t.x,t.y,t.w,t.h)}else r.drawImage(e,d.left+n.left,d.top+n.top,n.width,n.height)}catch{}}for(let e of t.querySelectorAll(`canvas`)){let t=e.getBoundingClientRect();if(!(t.width===0||t.height===0))try{r.drawImage(e,d.left+t.left,d.top+t.top,t.width,t.height)}catch{}}c++}}catch(t){b.warn(`Screenshot: failed to draw element`,e.tagName,t)}}return b.debug(`Screenshot: composed ${c}/${s.length} elements`),n.toDataURL(`image/jpeg`,.8).split(`,`)[1]}finally{i.style.contain=a,this.renderer&&(this.renderer._resizeSuppressed=!1)}}containedRect(e,t,n){let r=e/t,i=n.width/n.height,a,o;return r>i?(a=n.width,o=n.width/r):(o=n.height,a=n.height*r),{x:n.left+(n.width-a)/2,y:n.top+(n.height-o)/2,w:a,h:o}}startScreenshotInterval(){let n=this.displaySettings?.getSetting(`screenshotInterval`)||0;if(!n||n<=0)return;!this._html2canvasMod&&!window.electronAPI&&t(()=>import(`./html2canvas-Cjd84h1M.js`).then(t=>e(t.default,1)).then(e=>{this._html2canvasMod=e.default}),__vite__mapDeps([14,2]),import.meta.url);let r=n*1e3;b.info(`Starting periodic screenshots every ${n}s`),this._screenshotInterval=setInterval(()=>{this.captureAndSubmitScreenshot()},r)}updateStatus(e,t=`info`){let n=document.getElementById(`status`);n&&(n.textContent=e,n.className=`status status-${t}`),t===`error`?b.error(`Status:`,e):b.info(`Status:`,e)}showOfflineIndicator(){this.timelineOverlay?.setOffline(!0)}removeOfflineIndicator(){this.timelineOverlay?.setOffline(!1)}_syncLeadAlive(){if(!this.syncManager)return!1;for(let[,e]of this.syncManager.followers)if(e.role===`lead`&&Date.now()-e.lastSeen<15e3)return!0;return!1}cleanup(){this.core?.cleanup(),this.renderer?.cleanup(),this._screenshotInterval&&=(clearInterval(this._screenshotInterval),null),this._wakeLock&&=(this._wakeLock.release(),null),this.downloadOverlay&&this.downloadOverlay.destroy(),this.timelineOverlay&&this.timelineOverlay.destroy(),this._iframeObserver&&=(this._iframeObserver.disconnect(),null),navigator.serviceWorker&&(this._swIcHandler&&=(navigator.serviceWorker.removeEventListener(`message`,this._swIcHandler),null)),j?.clear(),this._probeTimer&&=(clearTimeout(this._probeTimer),null),this._mediaStatusTimer&&=(clearTimeout(this._mediaStatusTimer),null)}};function V(){let e=new B;e.init().catch(e=>{b.error(`Failed to initialize:`,e)}),window.addEventListener(`beforeunload`,()=>{e.cleanup()})}document.readyState===`loading`?document.addEventListener(`DOMContentLoaded`,V):V();
|
|
108
|
+
//# sourceMappingURL=main-BxyDlH8x.js.map
|