@xiboplayer/pwa 0.7.21 → 0.7.23

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.
Files changed (58) hide show
  1. package/dist/assets/__vite-browser-external-DeMPM02e.js +2 -0
  2. package/dist/assets/__vite-browser-external-DeMPM02e.js.map +1 -0
  3. package/dist/assets/chunk-DzMEjpoC.js +1 -0
  4. package/dist/assets/{html2canvas-BAfZNSwU.js → html2canvas-EikzC5d8.js} +2 -2
  5. package/dist/assets/{html2canvas-BAfZNSwU.js.map → html2canvas-EikzC5d8.js.map} +1 -1
  6. package/dist/assets/main-CRdq5ifQ.js +3 -0
  7. package/dist/assets/{main-vwJkNw4Y.js.map → main-CRdq5ifQ.js.map} +1 -1
  8. package/dist/assets/main-DTR2QDcF.js +108 -0
  9. package/dist/assets/main-DTR2QDcF.js.map +1 -0
  10. package/dist/assets/{pdf-Bxz9Nzto.js → pdf-CMz6puSt.js} +1 -1
  11. package/dist/assets/{pdf-Bxz9Nzto.js.map → pdf-CMz6puSt.js.map} +1 -1
  12. package/dist/assets/{setup-B4gZX38p.js → setup-Bw8T9Qq6.js} +2 -2
  13. package/dist/assets/{setup-B4gZX38p.js.map → setup-Bw8T9Qq6.js.map} +1 -1
  14. package/dist/assets/src-A5KHvitf.js +2 -0
  15. package/dist/assets/{src-CROvYSP8.js.map → src-A5KHvitf.js.map} +1 -1
  16. package/dist/assets/{src-DAB0dqGG.js → src-BHsN2u2P.js} +2 -2
  17. package/dist/assets/{src-DAB0dqGG.js.map → src-BHsN2u2P.js.map} +1 -1
  18. package/dist/assets/src-BLUMUwZR.js +1 -0
  19. package/dist/assets/src-BXXcWcHh.js +1 -0
  20. package/dist/assets/src-BxSOopk7.js +1 -0
  21. package/dist/assets/{src-WDu491CE.js → src-BxaX1gGg.js} +2 -2
  22. package/dist/assets/{src-WDu491CE.js.map → src-BxaX1gGg.js.map} +1 -1
  23. package/dist/assets/{src-BtVLiVYZ.js → src-CCAyzQUp.js} +3 -3
  24. package/dist/assets/{src-BtVLiVYZ.js.map → src-CCAyzQUp.js.map} +1 -1
  25. package/dist/assets/src-CWJcD3kA.js +1 -0
  26. package/dist/assets/{src-Cx3tXAAu.js → src-CZ1k5h23.js} +3 -3
  27. package/dist/assets/{src-Cx3tXAAu.js.map → src-CZ1k5h23.js.map} +1 -1
  28. package/dist/assets/src-ClrziKzV.js +16 -0
  29. package/dist/assets/src-ClrziKzV.js.map +1 -0
  30. package/dist/assets/{src-C_Lx4lXp.js → src-CtjjclS4.js} +2 -2
  31. package/dist/assets/{src-C_Lx4lXp.js.map → src-CtjjclS4.js.map} +1 -1
  32. package/dist/assets/src-CuVaZcMo.js +2 -0
  33. package/dist/assets/{src-B_BNICay.js.map → src-CuVaZcMo.js.map} +1 -1
  34. package/dist/assets/src-Cy5OUviT.js +1 -0
  35. package/dist/assets/src-DK5BYonP.js +630 -0
  36. package/dist/assets/src-DK5BYonP.js.map +1 -0
  37. package/dist/assets/src-Dk-W3N33.js +1 -0
  38. package/dist/assets/{src-cUopH0nN.js → src-xPTO7Ts6.js} +3 -3
  39. package/dist/assets/{src-cUopH0nN.js.map → src-xPTO7Ts6.js.map} +1 -1
  40. package/dist/assets/sync-manager-zf1tikPt.js +2 -0
  41. package/dist/assets/sync-manager-zf1tikPt.js.map +1 -0
  42. package/dist/index.html +1 -1
  43. package/dist/setup.html +3 -4
  44. package/dist/sw-pwa.js +2 -2
  45. package/dist/sw-pwa.js.map +1 -1
  46. package/package.json +15 -13
  47. package/dist/assets/chunk-7ZXdHUL4.js +0 -1
  48. package/dist/assets/main-oacre7st.js +0 -108
  49. package/dist/assets/main-oacre7st.js.map +0 -1
  50. package/dist/assets/main-vwJkNw4Y.js +0 -3
  51. package/dist/assets/src-B_BNICay.js +0 -2
  52. package/dist/assets/src-Bjt9ooXK.js +0 -16
  53. package/dist/assets/src-Bjt9ooXK.js.map +0 -1
  54. package/dist/assets/src-CKpVxGpH.js +0 -629
  55. package/dist/assets/src-CKpVxGpH.js.map +0 -1
  56. package/dist/assets/src-CROvYSP8.js +0 -2
  57. package/dist/assets/sync-manager-8Z-qwkod.js +0 -2
  58. package/dist/assets/sync-manager-8Z-qwkod.js.map +0 -1
@@ -1,629 +0,0 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./pdf-Bxz9Nzto.js","./preload-helper-Chd9yIcd.js"])))=>i.map(i=>d[i]);
2
- import{t as e}from"./preload-helper-Chd9yIcd.js";import{c as t,d as n,t as r,u as i}from"./src-BtVLiVYZ.js";import{n as a}from"./src-B_BNICay.js";import{r as o}from"./src-CROvYSP8.js";var s={name:`@xiboplayer/renderer`,version:`0.7.21`,description:`RendererLite - Fast, efficient XLF layout rendering engine`,type:`module`,main:`./src/index.js`,types:`./src/index.d.ts`,exports:{".":`./src/index.js`,"./renderer-lite":`./src/renderer-lite.js`,"./layout":`./src/layout.js`},scripts:{test:`vitest run`,"test:watch":`vitest`,"test:coverage":`vitest run --coverage`},dependencies:{"@xiboplayer/cache":`workspace:*`,"@xiboplayer/schedule":`workspace:*`,"@xiboplayer/utils":`workspace:*`,"pdfjs-dist":`^5.6.205`},devDependencies:{jsdom:`^29.0.2`,vitest:`^4.1.2`},keywords:[`xibo`,`digital-signage`,`renderer`,`xlf`,`layout`],author:`Pau Aliagas <linuxnow@gmail.com>`,license:`AGPL-3.0-or-later`,repository:{type:`git`,url:`git+https://github.com/xibo-players/xiboplayer.git`,directory:`packages/renderer`},homepage:`https://xiboplayer.org`},c=i(`LayoutPool`),l=class e{constructor(e=2){this.layouts=new Map,this.maxSize=e,this.hotLayoutId=null}has(e){return this.layouts.has(e)}get(e){return this.layouts.get(e)}add(e,t){if(this.layouts.has(e)){let n=this.layouts.get(e);Object.assign(n,t),n.lastAccess=Date.now();return}this.layouts.size>=this.maxSize&&this.evictLRU(),t.status=`warm`,t.lastAccess=Date.now(),this.layouts.set(e,t),c.info(`Added layout ${e} to pool (size: ${this.layouts.size}/${this.maxSize})`)}setHot(e){if(this.hotLayoutId!==null&&this.layouts.has(this.hotLayoutId)&&(this.layouts.get(this.hotLayoutId).status=`warm`),this.layouts.has(e)){let t=this.layouts.get(e);t.status=`hot`,t.lastAccess=Date.now()}this.hotLayoutId=e}evict(t){let n=this.layouts.get(t);if(n){if(c.info(`Evicting layout ${t} from pool`),n.regions)for(let[e,t]of n.regions)t.timer&&=(clearTimeout(t.timer),null);if(n.container&&e.releaseMediaElements(n.container),n.blobUrls&&n.blobUrls.size>0&&(n.blobUrls.forEach(e=>{URL.revokeObjectURL(e)}),c.info(`Revoked ${n.blobUrls.size} blob URLs for layout ${t}`)),n.mediaUrlCache)for(let[e,t]of n.mediaUrlCache)t&&typeof t==`string`&&t.startsWith(`blob:`)&&URL.revokeObjectURL(t);n.container&&n.container.parentNode&&n.container.remove(),this.layouts.delete(t),this.hotLayoutId===t&&(this.hotLayoutId=null)}}static releaseMediaElements(t){requestAnimationFrame(()=>e._releaseMediaElementsSync(t))}static _releaseMediaElementsSync(e){let t=0,n=0;e.querySelectorAll(`video`).forEach(e=>{e._hlsInstance&&(e._hlsInstance.destroy(),e._hlsInstance=null,n++),e._mediaStream&&(e._mediaStream.getTracks().forEach(e=>e.stop()),e._mediaStream=null,e.srcObject=null),e.pause(),e.removeAttribute(`src`),e.load(),t++}),e.querySelectorAll(`audio`).forEach(e=>{e.pause(),e.removeAttribute(`src`),e.load()});let r=0;e.querySelectorAll(`iframe`).forEach(e=>{try{let n=e.contentDocument||e.contentWindow?.document;n&&(n.querySelectorAll(`video`).forEach(e=>{e.pause(),e.removeAttribute(`src`),e.load(),t++}),n.querySelectorAll(`audio`).forEach(e=>{e.pause(),e.removeAttribute(`src`),e.load()}))}catch{}e.src=`about:blank`,r++}),e.querySelectorAll(`.pdf-widget`).forEach(e=>{e._pdfDestroy&&e._pdfDestroy()}),(t>0||r>0)&&c.info(`Released ${t} video(s)${n?` (${n} HLS)`:``}${r?`, ${r} iframe(s)`:``}`)}evictLRU(){let e=null,t=1/0;for(let[n,r]of this.layouts)r.status===`warm`&&r.lastAccess<t&&(e=n,t=r.lastAccess);e!==null&&this.evict(e)}clearWarm(){let e=0,t=[];for(let[e,n]of this.layouts)n.status===`warm`&&t.push(e);for(let n of t)this.evict(n),e++;return e>0&&c.info(`Cleared ${e} warm layout(s) from pool`),e}clearWarmNotIn(e){let t=0,n=[];for(let[t,r]of this.layouts)r.status===`warm`&&!e.has(t)&&n.push(t);for(let e of n)this.evict(e),t++;return t>0&&c.info(`Cleared ${t} warm layout(s) no longer in schedule`),t}getLatest(){let e;for(let t of this.layouts.keys())e=t;return e}clear(){let e=Array.from(this.layouts.keys());for(let t of e)this.evict(t);this.hotLayoutId=null}get size(){return this.layouts.size}},u={fadeIn(e,t){let n=[{opacity:0},{opacity:1}],r={duration:t,easing:`linear`,fill:`forwards`};return e.animate(n,r)},fadeOut(e,t){let n=[{opacity:1},{opacity:0}],r={duration:t,easing:`linear`,fill:`forwards`};return e.animate(n,r)},getFlyKeyframes(e,t,n,r){let i={N:{x:0,y:r?-n:n},NE:{x:r?t:-t,y:r?-n:n},E:{x:r?t:-t,y:0},SE:{x:r?t:-t,y:r?n:-n},S:{x:0,y:r?n:-n},SW:{x:r?-t:t,y:r?n:-n},W:{x:r?-t:t,y:0},NW:{x:r?-t:t,y:r?-n:n}},a=i[e]||i.N;return r?{from:{transform:`translate(${a.x}px, ${a.y}px)`,opacity:0},to:{transform:`translate(0, 0)`,opacity:1}}:{from:{transform:`translate(0, 0)`,opacity:1},to:{transform:`translate(${a.x}px, ${a.y}px)`,opacity:0}}},flyIn(e,t,n,r,i){let a=this.getFlyKeyframes(n,r,i,!0),o={duration:t,easing:`ease-out`,fill:`forwards`};return e.animate([a.from,a.to],o)},flyOut(e,t,n,r,i){let a=this.getFlyKeyframes(n,r,i,!1),o={duration:t,easing:`ease-in`,fill:`forwards`};return e.animate([a.from,a.to],o)},slideIn(e,t,n,r,i){let a={N:{x:0,y:-i},NE:{x:r,y:-i},E:{x:r,y:0},SE:{x:r,y:i},S:{x:0,y:i},SW:{x:-r,y:i},W:{x:-r,y:0},NW:{x:-r,y:-i}},o=a[n]||a.E;return e.animate([{transform:`translate(${o.x}px, ${o.y}px)`},{transform:`translate(0, 0)`}],{duration:t,easing:`ease-out`,fill:`forwards`})},slideOut(e,t,n,r,i){let a={N:{x:0,y:-i},NE:{x:r,y:-i},E:{x:r,y:0},SE:{x:r,y:i},S:{x:0,y:i},SW:{x:-r,y:i},W:{x:-r,y:0},NW:{x:-r,y:-i}},o=a[n]||a.W;return e.animate([{transform:`translate(0, 0)`},{transform:`translate(${o.x}px, ${o.y}px)`}],{duration:t,easing:`ease-in`,fill:`forwards`})},wipeIn(e,t,n){let r={E:{from:`inset(0 100% 0 0)`,to:`inset(0 0 0 0)`},W:{from:`inset(0 0 0 100%)`,to:`inset(0 0 0 0)`},S:{from:`inset(0 0 100% 0)`,to:`inset(0 0 0 0)`},N:{from:`inset(100% 0 0 0)`,to:`inset(0 0 0 0)`},SE:{from:`inset(0 100% 100% 0)`,to:`inset(0 0 0 0)`},SW:{from:`inset(0 0 100% 100%)`,to:`inset(0 0 0 0)`},NE:{from:`inset(100% 100% 0 0)`,to:`inset(0 0 0 0)`},NW:{from:`inset(100% 0 0 100%)`,to:`inset(0 0 0 0)`}},i=r[n]||r.E;return e.animate([{clipPath:i.from},{clipPath:i.to}],{duration:t,easing:`ease-out`,fill:`forwards`})},apply(e,t,n,r,i){if(!t||!t.type)return null;let a=t.type.toLowerCase(),o=t.duration||1e3,s=t.direction||`N`;switch(a){case`fade`:return n?this.fadeIn(e,o):this.fadeOut(e,o);case`fadein`:return n?this.fadeIn(e,o):null;case`fadeout`:return n?null:this.fadeOut(e,o);case`fly`:return n?this.flyIn(e,o,s,r,i):this.flyOut(e,o,s,r,i);case`flyin`:return n?this.flyIn(e,o,s,r,i):null;case`flyout`:return n?null:this.flyOut(e,o,s,r,i);case`slide`:return n?this.slideIn(e,o,s,r,i):this.slideOut(e,o,s,r,i);case`wipe`:return n?this.wipeIn(e,o,s):null;default:return null}}},d=class{constructor(e,n,r={}){this.config=e,this.container=n,this.options=r,this.log=i(`RendererLite`,r.logLevel),this.emitter=new t,this.currentLayout=null,this.currentLayoutId=null,this._preloadingLayoutId=null,this._preloadingPromise=null,this.regions=new Map,this.layoutTimer=null,this.layoutEndEmitted=!1,this._deferredTimerLayoutId=null,this._deferredTimerFallback=null,this._paused=!1,this._layoutTimerStartedAt=null,this._layoutTimerDurationMs=null,this.layoutBlobUrls=new Map,this.audioOverlays=new Map,this._stopWidgetBound=(e,t)=>this.stopWidget(e,t),this._renderWidgetBound=(e,t)=>this.renderWidget(e,t),this.scaleFactor=1,this.offsetX=0,this.offsetY=0,this.overlayContainer=null,this.activeOverlays=new Map,this._keydownHandler=null,this._keyboardActions=[],this._subPlaylistCycleIndex=new Map,this._startedWidgets=new Set,this.layoutPool=new l(2),this.preloadTimer=null,this._preloadRetryTimer=null,this.layoutTransition=this._normalizeLayoutTransition(r.layoutTransition),this.setupContainer(),this.emitter.on(`interactiveTrigger`,e=>this._handleInteractiveTrigger(e)),this.emitter.on(`widgetExpire`,e=>this._handleWidgetExpire(e)),this.emitter.on(`widgetExtendDuration`,e=>this._handleWidgetExtendDuration(e)),this.emitter.on(`widgetSetDuration`,e=>this._handleWidgetSetDuration(e)),this.log.info(`Initialized`)}setupContainer(){if(this.container.style.position=`relative`,this.container.style.width=`100%`,this.container.style.height=`100vh`,this.container.style.overflow=`hidden`,this._resizeSuppressed=!1,typeof ResizeObserver<`u`){let e=null;this.resizeObserver=new ResizeObserver(()=>{this._resizeSuppressed||(e&&clearTimeout(e),e=setTimeout(()=>this.rescaleRegions(),150))}),this.resizeObserver.observe(this.container)}this.overlayContainer=document.createElement(`div`),this.overlayContainer.id=`overlay-container`,this.overlayContainer.style.position=`absolute`,this.overlayContainer.style.top=`0`,this.overlayContainer.style.left=`0`,this.overlayContainer.style.width=`100%`,this.overlayContainer.style.height=`100%`,this.overlayContainer.style.zIndex=`1000`,this.overlayContainer.style.pointerEvents=`none`,this.container.appendChild(this.overlayContainer)}calculateScale(e){let t=this.container.clientWidth,n=this.container.clientHeight;if(!t||!n)return;let r=t/e.width,i=n/e.height;this.scaleFactor=Math.min(r,i),this.offsetX=(t-e.width*this.scaleFactor)/2,this.offsetY=(n-e.height*this.scaleFactor)/2,this.log.info(`Scale: ${this.scaleFactor.toFixed(3)} (${e.width}x${e.height} → ${t}x${n}, offset ${Math.round(this.offsetX)},${Math.round(this.offsetY)})`)}applyRegionScale(e,t){let n=this.scaleFactor;e.style.left=`${t.left*n+this.offsetX}px`,e.style.top=`${t.top*n+this.offsetY}px`,e.style.width=`${t.width*n}px`,e.style.height=`${t.height*n}px`}rescaleRegions(){if(this.currentLayout){this.calculateScale(this.currentLayout);for(let[e,t]of this.regions)this.applyRegionScale(t.element,t.config),t.width=t.config.width*this.scaleFactor,t.height=t.config.height*this.scaleFactor;for(let[e,t]of this.activeOverlays){this.calculateScale(t.layout);for(let[e,n]of t.regions)this.applyRegionScale(n.element,n.config),n.width=n.config.width*this.scaleFactor,n.height=n.config.height*this.scaleFactor}}}on(e,t){this.emitter.on(e,t)}emit(e,...t){this.emitter.emit(e,...t)}parseActions(e){let t=[];for(let n of e.children)n.tagName===`action`&&t.push({id:n.getAttribute(`id`)||``,actionType:n.getAttribute(`actionType`)||``,triggerType:n.getAttribute(`triggerType`)||``,triggerCode:n.getAttribute(`triggerCode`)||``,source:n.getAttribute(`source`)||``,sourceId:n.getAttribute(`sourceId`)||``,target:n.getAttribute(`target`)||``,targetId:n.getAttribute(`targetId`)||``,widgetId:n.getAttribute(`widgetId`)||``,layoutCode:n.getAttribute(`layoutCode`)||``,commandCode:n.getAttribute(`commandCode`)||``});return t}_normalizeLayoutTransition(e){return{type:e?.type||`instant`,duration:Number.isFinite(e?.duration)?e.duration:500,direction:e?.direction||void 0}}_resolveLayoutTransition(e){let t=e?.layoutTransitionIn;return!t||!t.type?this.layoutTransition:{type:t.type,duration:Number.isFinite(t.duration)?t.duration:this.layoutTransition.duration,direction:t.direction||this.layoutTransition.direction}}parseXlf(e){let t=new DOMParser().parseFromString(e,`text/xml`).querySelector(`layout`);if(!t)throw Error(`Invalid XLF: no <layout> element`);let n=t.getAttribute(`duration`),r=t.getAttribute(`layoutTransitionIn`),i=t.getAttribute(`layoutTransitionInDuration`),a=t.getAttribute(`layoutTransitionInDirection`),s={schemaVersion:parseInt(t.getAttribute(`schemaVersion`)||`1`),width:parseInt(t.getAttribute(`width`)||`1920`),height:parseInt(t.getAttribute(`height`)||`1080`),duration:n?parseInt(n):0,bgcolor:t.getAttribute(`backgroundColor`)||t.getAttribute(`bgcolor`)||`#000000`,background:t.getAttribute(`background`)||null,enableStat:t.getAttribute(`enableStat`)!==`0`,actions:this.parseActions(t),layoutTransitionIn:r?{type:r,duration:i?parseInt(i):void 0,direction:a||void 0}:null,regions:[]};s.schemaVersion>1&&this.log.debug(`XLF schema version: ${s.schemaVersion}`),n?this.log.info(`Layout duration from XLF: ${s.duration}s`):this.log.info(`Layout duration NOT in XLF, will calculate from widgets`);let c=t.querySelectorAll(`:scope > region, :scope > drawer`);for(let e of c){let t=e.tagName===`drawer`,n=e.getAttribute(`type`)||null,r={id:e.getAttribute(`id`),width:parseInt(e.getAttribute(`width`)||`0`),height:parseInt(e.getAttribute(`height`)||`0`),top:parseInt(e.getAttribute(`top`)||`0`),left:parseInt(e.getAttribute(`left`)||`0`),zindex:parseInt(e.getAttribute(`zindex`)||(t?`2000`:`0`)),enableStat:e.getAttribute(`enableStat`)!==`0`,actions:this.parseActions(e),exitTransition:null,transitionType:null,transitionDuration:null,transitionDirection:null,loop:!0,isDrawer:t,isCanvas:n===`canvas`,widgets:[]},i=Array.from(e.children).find(e=>e.tagName===`options`);if(i){let e=i.querySelector(`exitTransType`);if(e&&e.textContent){let t=i.querySelector(`exitTransDuration`),n=i.querySelector(`exitTransDirection`);r.exitTransition={type:e.textContent,duration:parseInt(t&&t.textContent||`1000`),direction:n&&n.textContent||`N`}}let t=i.querySelector(`loop`);t&&(r.loop=t.textContent!==`0`);let n=i.querySelector(`transitionType`);if(n&&n.textContent){r.transitionType=n.textContent;let e=i.querySelector(`transitionDuration`),t=i.querySelector(`transitionDirection`);r.transitionDuration=parseInt(e&&e.textContent||`1000`),r.transitionDirection=t&&t.textContent||`N`}}for(let t of e.children){if(t.tagName!==`media`)continue;let e=this.parseWidget(t);r.widgets.push(e)}!r.isCanvas&&r.widgets.some(e=>e.type===`global`)&&(r.isCanvas=!0),s.regions.push(r),t&&this.log.info(`Parsed drawer: id=${r.id} with ${r.widgets.length} widgets`),r.isCanvas&&this.log.info(`Parsed canvas region: id=${r.id} with ${r.widgets.length} widgets (all render simultaneously)`)}if(s.duration===0){let{duration:t,isDynamic:n}=o(e);s.duration=t,s.isDynamic=n,this.log.info(`Calculated layout duration: ${s.duration}s (not specified in XLF)${n?` [dynamic — has useDuration=0 video]`:``}`)}return s}parseWidget(e){let t=e.getAttribute(`type`),n=parseInt(e.getAttribute(`duration`)||`10`),r=parseInt(e.getAttribute(`useDuration`)||`1`),i=e.getAttribute(`id`),a=e.getAttribute(`fileId`),o={},s=e.querySelector(`options`);if(s)for(let e of s.children)o[e.tagName]=e.textContent;let c=e.querySelector(`raw`),l=c?c.textContent:``,u={in:null,out:null};o.transIn&&(u.in={type:o.transIn,duration:parseInt(o.transInDuration||`1000`),direction:o.transInDirection||`N`}),o.transOut&&(u.out={type:o.transOut,duration:parseInt(o.transOutDuration||`1000`),direction:o.transOutDirection||`N`});let d=this.parseActions(e),f=[];for(let t of e.children)if(t.tagName.toLowerCase()===`audio`){let e=t.querySelector(`uri`);e?f.push({mediaId:e.getAttribute(`mediaId`)||null,uri:e.textContent||``,volume:parseInt(e.getAttribute(`volume`)||`100`),loop:e.getAttribute(`loop`)===`1`}):f.push({mediaId:t.getAttribute(`mediaId`)||null,uri:t.getAttribute(`uri`)||``,volume:parseInt(t.getAttribute(`volume`)||`100`),loop:t.getAttribute(`loop`)===`1`})}let p=[],m=Array.from(e.children).find(e=>e.tagName===`commands`);if(m)for(let e of m.children)e.tagName===`command`&&p.push({commandCode:e.getAttribute(`commandCode`)||``,commandString:e.getAttribute(`commandString`)||``});let h=e.getAttribute(`parentWidgetId`)||null,g=parseInt(e.getAttribute(`displayOrder`)||`0`),_=e.getAttribute(`cyclePlayback`)===`1`,v=parseInt(e.getAttribute(`playCount`)||`0`),y=e.getAttribute(`isRandom`)===`1`,b=e.getAttribute(`fromDt`)||e.getAttribute(`fromdt`)||null,x=e.getAttribute(`toDt`)||e.getAttribute(`todt`)||null;return{type:t,duration:n,useDuration:r,id:i,fileId:a,render:e.getAttribute(`render`)||null,fromDt:b,toDt:x,enableStat:e.getAttribute(`enableStat`)!==`0`,webhookUrl:o.webhookUrl||null,options:o,raw:l,transitions:u,actions:d,audioNodes:f,commands:p,parentWidgetId:h,displayOrder:g,cyclePlayback:_,playCount:v,isRandom:y}}trackBlobUrl(e){let t=this._preloadingLayoutId||this.currentLayoutId||0;t||this.log.warn(`trackBlobUrl called without currentLayoutId, tracking under key 0`),this.layoutBlobUrls.has(t)||this.layoutBlobUrls.set(t,new Set),this.layoutBlobUrls.get(t).add(e)}revokeBlobUrlsForLayout(e){let t=this.layoutBlobUrls.get(e);t&&(t.forEach(e=>{URL.revokeObjectURL(e)}),this.layoutBlobUrls.delete(e),this.log.info(`Revoked ${t.size} blob URLs for layout ${e}`))}updateLayoutDuration(){if(!this.currentLayout)return;let e=0;for(let t of this.currentLayout.regions){if(t.isDrawer)continue;let n=0;for(let e of t.widgets)e.duration>0&&(n+=e.duration);e=Math.max(e,n)}if(e>0&&e!==this.currentLayout.duration){let t=this.currentLayout.duration;this.currentLayout.duration=e,this.currentLayout._durationFromMetadata=!0,this.log.info(`Layout duration updated: ${t}s → ${e}s (based on video metadata)`);let n=!this._hasUnprobedVideos();if(this.emit(`layoutDurationUpdated`,this.currentLayoutId,e,n),this._deferredTimerLayoutId===this.currentLayoutId&&!this.layoutTimer)if(this._hasUnprobedVideos())this.log.info(`Layout duration updated to ${e}s but still has unprobed videos — keeping timer deferred`);else{this._deferredTimerFallback&&=(clearTimeout(this._deferredTimerFallback),null);let t=Date.now()-(this._layoutTimerStartedAt||Date.now()),n=Math.max(1e3,e*1e3-t);this._deferredTimerLayoutId=null,this._layoutTimerDurationMs=n,this.layoutTimer=setTimeout(()=>{this.log.info(`Layout ${this.currentLayoutId} duration expired (${this.currentLayout.duration}s)`),this.currentLayoutId&&(this.layoutEndEmitted=!0,this.emit(`layoutEnd`,this.currentLayoutId))},n),this.log.info(`All video durations resolved — deferred timer started: ${(n/1e3).toFixed(1)}s remaining (waited ${(t/1e3).toFixed(1)}s for metadata)`)}else if(this.layoutTimer){clearTimeout(this.layoutTimer);let e=Date.now()-(this._layoutTimerStartedAt||Date.now()),t=Math.max(1e3,this.currentLayout.duration*1e3-e);this.layoutTimer=setTimeout(()=>{this.log.info(`Layout ${this.currentLayoutId} duration expired (${this.currentLayout.duration}s)`),this.currentLayoutId&&(this.layoutEndEmitted=!0,this.emit(`layoutEnd`,this.currentLayoutId))},t),this.log.info(`Layout timer adjusted to ${(t/1e3).toFixed(1)}s remaining (elapsed ${(e/1e3).toFixed(1)}s of ${this.currentLayout.duration}s)`)}else this.log.info(`Layout duration updated to ${e}s (timer not yet started, will use new value)`);this._scheduleNextLayoutPreload(this.currentLayout)}}attachActionListeners(e){let t=[],n=0;for(let r of e.actions||[])r.triggerType===`touch`?(this.attachTouchAction(this.container,r,null,null),n++):r.triggerType?.startsWith(`keyboard:`)&&t.push(r);for(let r of e.regions){let e=this.regions.get(r.id);if(e){for(let i of r.actions||[])i.triggerType===`touch`?(this.attachTouchAction(e.element,i,r.id,null),n++):i.triggerType.startsWith(`keyboard:`)&&t.push(i);for(let i of r.widgets){if(!i.actions||i.actions.length===0)continue;let a=e.widgetElements.get(i.id);if(a)for(let e of i.actions)e.triggerType===`touch`?(this.attachTouchAction(a,e,r.id,i.id),n++):e.triggerType.startsWith(`keyboard:`)&&t.push(e)}}}this.setupKeyboardListener(t),(n>0||t.length>0)&&this.log.info(`Actions attached: ${n} touch, ${t.length} keyboard`)}attachTouchAction(e,t,n,r){e.style.cursor=`pointer`;let i=e=>{e.stopPropagation();let i=r?`widget ${r}`:`region ${n}`;this.log.info(`Touch action fired on ${i}: ${t.actionType}`),this.emit(`action-trigger`,{actionType:t.actionType,triggerType:`touch`,triggerCode:t.triggerCode,layoutCode:t.layoutCode,targetId:t.targetId,commandCode:t.commandCode,source:{regionId:n,widgetId:r}})};e.addEventListener(`click`,i),e._actionHandlers||=[],e._actionHandlers.push(i)}setupKeyboardListener(e){this.removeKeyboardListener(),this._keyboardActions=e,e.length!==0&&(this._keydownHandler=e=>{let t=e.key;for(let e of this._keyboardActions)if(t===e.triggerType.substring(9)){this.log.info(`Keyboard action (key: ${t}): ${e.actionType}`),this.emit(`action-trigger`,{actionType:e.actionType,triggerType:e.triggerType,triggerCode:e.triggerCode,layoutCode:e.layoutCode,targetId:e.targetId,commandCode:e.commandCode,source:{key:t}});break}},document.addEventListener(`keydown`,this._keydownHandler))}removeKeyboardListener(){this._keydownHandler&&=(document.removeEventListener(`keydown`,this._keydownHandler),null),this._keyboardActions=[]}removeActionListeners(){for(let[,e]of this.regions){this._cleanElementActionHandlers(e.element);for(let[,t]of e.widgetElements)this._cleanElementActionHandlers(t)}this.removeKeyboardListener()}_cleanElementActionHandlers(e){if(e._actionHandlers){for(let t of e._actionHandlers)e.removeEventListener(`click`,t);delete e._actionHandlers,e.style.cursor=``}}_findRegionByWidgetId(e){for(let[t,n]of this.regions){let r=n.widgets.findIndex(t=>t.id===e);if(r!==-1)return{regionId:t,region:n,widget:n.widgets[r],widgetIndex:r,regionMap:this.regions}}for(let t of this.activeOverlays.values())if(t.regions)for(let[n,r]of t.regions){let i=r.widgets.findIndex(t=>t.id===e);if(i!==-1)return{regionId:n,region:r,widget:r.widgets[i],widgetIndex:i,regionMap:t.regions}}return null}_advanceRegion(e,t){let n=t.get(e);if(!n)return;n.currentIndex=(n.currentIndex+1)%n.widgets.length;let r=t===this.regions;this._startRegionCycle(n,e,this._renderWidgetBound,this._stopWidgetBound,r?()=>this.checkLayoutComplete():void 0)}_handleInteractiveTrigger({targetId:e,triggerCode:t}){this.log.info(`XIC interactiveTrigger: target=${e} code=${t}`),this._findRegionByWidgetId(e)?this.navigateToWidget(e):this.log.warn(`XIC interactiveTrigger: widget ${e} not found`)}_handleWidgetExpire({widgetId:e}){let t=this._findRegionByWidgetId(e);if(!t){this.log.warn(`XIC widgetExpire: widget ${e} not found`);return}let{regionId:n,region:r,widgetIndex:i,regionMap:a}=t;this.log.info(`XIC widgetExpire: widget=${e} region=${n}`),r.timer&&=(clearTimeout(r.timer),null),this.stopWidget(n,i),this._advanceRegion(n,a)}_handleWidgetExtendDuration({widgetId:e,duration:t}){let n=this._findRegionByWidgetId(e);if(!n){this.log.warn(`XIC widgetExtendDuration: widget ${e} not found`);return}let{regionId:r,region:i}=n;this.log.info(`XIC widgetExtendDuration: widget=${e} +${t}s`),i.timer&&=(clearTimeout(i.timer),null),i.timer=setTimeout(()=>{this.stopWidget(r,i.currentIndex),this._advanceRegion(r,n.regionMap)},t*1e3)}_handleWidgetSetDuration({widgetId:e,duration:t}){let n=this._findRegionByWidgetId(e);if(!n){this.log.warn(`XIC widgetSetDuration: widget ${e} not found`);return}let{regionId:r,region:i}=n;this.log.info(`XIC widgetSetDuration: widget=${e} ${t}s`),i.timer&&=(clearTimeout(i.timer),null),i.timer=setTimeout(()=>{this.stopWidget(r,i.currentIndex),this._advanceRegion(r,n.regionMap)},t*1e3)}navigateToWidget(e){for(let[t,n]of this.regions){let r=n.widgets.findIndex(t=>t.id===e);if(r!==-1){if(this.log.info(`Navigating to widget ${e} in region ${t} (index ${r})`),n.isDrawer&&n.element.style.display===`none`&&(n.element.style.display=``,this.log.info(`Drawer region ${t} revealed`)),n.timer&&=(clearTimeout(n.timer),null),this.stopWidget(t,n.currentIndex),n.currentIndex=r,this.renderWidget(t,r),n.widgets.length>1){let e=n.widgets[r].duration*1e3;n.timer=setTimeout(()=>{this.stopWidget(t,r);let e=(r+1)%n.widgets.length;n.currentIndex=e,n.isDrawer&&e===0?(n.element.style.display=`none`,this.log.info(`Drawer region ${t} hidden (cycle complete)`)):n.isDrawer?this.navigateToWidget(n.widgets[e].id):this.startRegion(t)},e)}else if(n.isDrawer){let e=n.widgets[r].duration*1e3;n.timer=setTimeout(()=>{this.stopWidget(t,r),n.element.style.display=`none`,this.log.info(`Drawer region ${t} hidden (single widget done)`)},e)}return}}this.log.warn(`Target widget ${e} not found in any region`)}nextWidget(e){let t=e?this.regions.get(e):this.regions.values().next().value;if(!t||t.widgets.length<=1)return;let n=(t.currentIndex+1)%t.widgets.length,r=t.widgets[n];this.log.info(`nextWidget → index ${n} (widget ${r.id})`),this.navigateToWidget(r.id)}previousWidget(e){let t=e?this.regions.get(e):this.regions.values().next().value;if(!t||t.widgets.length<=1)return;let n=(t.currentIndex-1+t.widgets.length)%t.widgets.length,r=t.widgets[n];this.log.info(`previousWidget → index ${n} (widget ${r.id})`),this.navigateToWidget(r.id)}_mediaFileUrl(e){return`${window.location.origin}${r}/media/file/${e}`}_positionWidgetElement(e){Object.assign(e.style,{position:`absolute`,top:`0`,left:`0`,width:`100%`,height:`100%`,visibility:`hidden`,opacity:`0`})}_applyBackgroundImage(e,t){Object.assign(e.style,{backgroundImage:`url(${t})`,backgroundSize:`cover`,backgroundPosition:`center`,backgroundRepeat:`no-repeat`})}_clearRegionTimers(e){for(let[,t]of e)t.timer&&=(clearTimeout(t.timer),null)}async renderLayout(e,t){try{if(this.log.info(`Rendering layout ${t}`),this.currentLayoutId===t){this.log.info(`Replaying layout ${t} - reusing elements (no recreation!)`),this._clearRegionTimers(this.regions),this._stopAllRegionWidgets(this.regions,this._stopWidgetBound);for(let[,e]of this.regions)e.currentIndex=0,e.complete=!1;this.layoutTimer&&=(clearTimeout(this.layoutTimer),null),this.layoutEndEmitted=!1,this._deferredTimerLayoutId=null,this._deferredTimerFallback&&=(clearTimeout(this._deferredTimerFallback),null),this.emit(`layoutStart`,t,this.currentLayout);for(let[e,t]of this.regions)t.isDrawer||this.startRegion(e);this.startLayoutTimerWhenReady(t,this.currentLayout),this.log.info(`Layout ${t} restarted (reused elements)`),this._scheduleNextLayoutPreload(this.currentLayout);return}if(this.layoutPool.has(t)){this.log.info(`Layout ${t} found in preload pool - instant swap!`),await this._swapToPreloadedLayout(t);return}this.log.info(`Switching to new layout ${t}`),this.stopCurrentLayout();let n=this.parseXlf(e);if(this.currentLayout=n,this.currentLayoutId=t,this.calculateScale(n),this.container.style.backgroundColor=n.bgcolor,this.container.style.backgroundImage=``,n.background){let e=this.options.fileIdToSaveAs?.get(String(n.background))||n.background;this._applyBackgroundImage(this.container,this._mediaFileUrl(e)),this.log.info(`Background image set: ${n.background} → ${e}`)}for(let e of n.regions)await this.createRegion(e);this.log.info(`Pre-creating widget elements for instant transitions...`);for(let[e,t]of this.regions)for(let n=0;n<t.widgets.length;n++){let r=t.widgets[n];r.layoutId=this.currentLayoutId,r.regionId=e;try{let e=await this.createWidgetElement(r,t);this._positionWidgetElement(e),t.element.appendChild(e),t.widgetElements.set(r.id,e)}catch(e){this.log.error(`Failed to pre-create widget ${r.id}:`,e)}}if(this.log.info(`All widget elements pre-created`),this.attachActionListeners(n),this.emit(`layoutStart`,t,n),n.duration>0){let e=!this._hasUnprobedVideos();this.emit(`layoutDurationUpdated`,t,n.duration,e)}for(let[e,t]of this.regions)t.isDrawer||this.startRegion(e);this.startLayoutTimerWhenReady(t,n),this._scheduleNextLayoutPreload(n),this.log.info(`Layout ${t} started`)}catch(e){throw this.log.error(`Error rendering layout:`,e),this.emit(`error`,{type:`layoutError`,error:e,layoutId:t}),e}}_createRegionEntry(e,t,n,r={}){let{className:i=`renderer-lite-region`,...a}=r,o=document.createElement(`div`);o.id=t,o.className=i,o.style.position=`absolute`,o.style.zIndex=String(e.zindex),o.style.overflow=`hidden`,this.applyRegionScale(o,e),n.appendChild(o);let s=this.scaleFactor;return{element:o,config:e,widgets:e.widgets,currentIndex:0,timer:null,width:e.width*s,height:e.height*s,complete:!1,widgetElements:new Map,...a}}async createRegion(e){let t=this._createRegionEntry(e,`region_${e.id}`,this.container,{isDrawer:e.isDrawer||!1,isCanvas:e.isCanvas||!1});e.isDrawer&&(t.element.style.display=`none`);let n=e.widgets.filter(e=>this._isWidgetActive(e));n.some(e=>e.cyclePlayback)&&(n=this._applyCyclePlayback(n)),t.widgets=n,this.regions.set(e.id,t)}startRegion(e){let t=this.regions.get(e);this._startRegionCycle(t,e,this._renderWidgetBound,this._stopWidgetBound,()=>{this.log.info(`Region ${e} completed one full cycle`),this.checkLayoutComplete()})}async createWidgetElement(e,t){if(e.render===`html`&&e.type!==`pdf`)return await this.renderGenericWidget(e,t);switch(e.type){case`image`:return await this.renderImage(e,t);case`video`:return await this.renderVideo(e,t);case`audio`:return await this.renderAudio(e,t);case`text`:case`ticker`:return await this.renderTextWidget(e,t);case`pdf`:return await this.renderPdf(e,t);case`webpage`:return await this.renderWebpage(e,t);case`localvideo`:return await this.renderVideo(e,t);case`videoin`:return await this.renderVideoIn(e,t);case`powerpoint`:case`flash`:return this.log.warn(`Widget type '${e.type}' is not supported on web players (widget ${e.id})`),this._renderUnsupportedPlaceholder(e,t);default:return await this.renderGenericWidget(e,t)}}findMediaElement(e,t){return e.tagName===t?e:e.querySelector(t.toLowerCase())}updateMediaElement(e,t){let n=this.findMediaElement(e,`VIDEO`)||this.findMediaElement(e,`AUDIO`);if(n){if(n.tagName===`VIDEO`&&n._mediaConstraints&&!n._mediaStream){navigator.mediaDevices.getUserMedia(n._mediaConstraints).then(e=>{n.srcObject=e,n._mediaStream=e,this.log.info(`Webcam stream re-acquired for widget ${t.id}`)}).catch(e=>{this.log.warn(`Failed to re-acquire webcam stream:`,e.message)});return}this._restartMediaElement(n),this.log.info(`${n.tagName===`VIDEO`?`Video`:`Audio`} restarted: ${t.fileId||t.id}`)}}_restartMediaElement(e){e.currentTime=0;let t=()=>{e.removeEventListener(`seeked`,t),e.play().catch(()=>{})};e.addEventListener(`seeked`,t),e.play().catch(()=>{})}waitForWidgetReady(e,t){let n=1e4,r=this.findMediaElement(e,`VIDEO`);if(r)return!r.paused&&r.readyState>=3?Promise.resolve():new Promise(e=>{let i=setTimeout(()=>{this.log.warn(`Video ready timeout (${n}ms) for widget ${t.id}`),e()},n),a=()=>{r.removeEventListener(`playing`,a),clearTimeout(i),this.log.info(`Video widget ${t.id} ready (playing)`),e()};r.addEventListener(`playing`,a)});let i=this.findMediaElement(e,`AUDIO`);if(i)return!i.paused&&i.readyState>=3?Promise.resolve():new Promise(e=>{let r=setTimeout(()=>{this.log.warn(`Audio ready timeout (${n}ms) for widget ${t.id}`),e()},n),a=()=>{i.removeEventListener(`playing`,a),clearTimeout(r),this.log.info(`Audio widget ${t.id} ready (playing)`),e()};i.addEventListener(`playing`,a)});let a=this.findMediaElement(e,`IMG`);return a?a.complete&&a.naturalWidth>0?Promise.resolve():new Promise(e=>{let r=()=>{a.removeEventListener(`load`,r),clearTimeout(i),e()},i=setTimeout(()=>{a.removeEventListener(`load`,r),this.log.warn(`Image ready timeout for widget ${t.id}`),e()},n);a.addEventListener(`load`,r)}):Promise.resolve()}async startLayoutTimerWhenReady(e,t){if(!t||t.duration<=0)return;let n=[];for(let[e,t]of this.regions){if(t.widgets.length===0)continue;let e=t.widgets[t.currentIndex||0],r=t.widgetElements.get(e.id);r&&n.push(this.waitForWidgetReady(r,e))}if(n.length>0&&(this.log.info(`Waiting for ${n.length} widget(s) to be ready before starting layout timer...`),await Promise.all(n),this.log.info(`All widgets ready — starting layout timer`)),this.currentLayoutId!==e){this.log.warn(`Layout changed while waiting for widgets — skipping timer for ${e}`);return}if(t.isDynamic&&!t._durationFromMetadata&&this._hasUnprobedVideos()){this._deferredTimerLayoutId=e,this._layoutTimerStartedAt=Date.now(),this.log.info(`Layout ${e} has unprobed videos — deferring timer until metadata loads`),this._deferredTimerFallback=setTimeout(()=>{this._deferredTimerFallback=null,this._deferredTimerLayoutId===e&&!this.layoutTimer&&(this.log.warn(`Layout ${e}: metadata timeout after 30s — starting timer with ${t.duration}s estimate`),this._deferredTimerLayoutId=null,this._startLayoutTimer(e,t))},3e4);return}this._startLayoutTimer(e,t)}_hasUnprobedVideos(){for(let[,e]of this.regions)for(let t of e.widgets)if(t.type===`video`&&t.useDuration===0&&t._probed)return!1;for(let[,e]of this.regions)for(let t of e.widgets)if(t.type===`video`&&t.useDuration===0)return!0;return!1}_startLayoutTimer(e,t){this._deferredTimerLayoutId=null,this._deferredTimerFallback&&=(clearTimeout(this._deferredTimerFallback),null);let n=t.duration*1e3;this.log.info(`Layout ${e} will end after ${t.duration}s`),this._layoutTimerStartedAt=Date.now(),this._layoutTimerDurationMs=n,this.layoutTimer=setTimeout(()=>{this.log.info(`Layout ${e} duration expired (${t.duration}s)`),this.currentLayoutId&&(this.layoutEndEmitted=!0,this.emit(`layoutEnd`,this.currentLayoutId))},n)}async _showWidget(e,t){let n=e.widgets[t];if(!n)return null;let r=e.widgetElements.get(n.id);if(r||(this.log.warn(`Widget ${n.id} not pre-created, creating now`),r=await this.createWidgetElement(n,e),r.style.position=`absolute`,r.style.top=`0`,r.style.left=`0`,r.style.width=`100%`,r.style.height=`100%`,e.widgetElements.set(n.id,r),e.element.appendChild(r)),!e.isCanvas)for(let[t,r]of e.widgetElements)t!==n.id&&(r.getAnimations?.().forEach(e=>e.cancel()),r.style.visibility=`hidden`,r.style.opacity=`0`);return this.updateMediaElement(r,n),r.getAnimations?.().forEach(e=>e.cancel()),r.style.visibility=`visible`,n.transitions.in?u.apply(r,n.transitions.in,!0,e.width,e.height):r.style.opacity=`1`,r._pdfResume&&r._pdfResume(),this._startAudioOverlays(n),n}_startAudioOverlays(e){if(!e.audioNodes||e.audioNodes.length===0)return;this._stopAudioOverlays(e.id);let t=[];for(let n of e.audioNodes){if(!n.uri)continue;let r=document.createElement(`audio`);r.autoplay=!0,r.loop=n.loop,r.volume=Math.max(0,Math.min(1,n.volume/100)),r.src=n.uri?this._mediaFileUrl(n.uri):``,r.style.display=`none`,this.container.appendChild(r);let i=r.play();i&&i.catch&&i.catch(()=>{}),t.push(r),this.log.info(`Audio overlay started for widget ${e.id}: ${n.uri} (loop=${n.loop}, vol=${n.volume})`)}t.length>0&&this.audioOverlays.set(e.id,t)}_stopAudioOverlays(e){let t=this.audioOverlays.get(e);if(t){for(let e of t)e.pause(),e.removeAttribute(`src`),e.load(),e.parentNode&&e.parentNode.removeChild(e);this.audioOverlays.delete(e),this.log.info(`Audio overlays stopped for widget ${e}`)}}_hideWidget(e,t){let n=e.widgets[t];if(!n)return{widget:null,animPromise:null};let r=e.widgetElements.get(n.id);if(!r)return{widget:null,animPromise:null};let i=null;if(n.transitions.out){let t=u.apply(r,n.transitions.out,!1,e.width,e.height);t&&(i=new Promise(e=>{t.onfinish=e}))}let a=r.querySelector(`video`);if(a&&(a.pause(),a._mediaStream&&(a._mediaStream.getTracks().forEach(e=>e.stop()),a._mediaStream=null,a.srcObject=null),a._hlsInstance&&=(a._hlsInstance.destroy(),null),a.removeAttribute(`src`),a.load(),a._eventCleanup)){for(let[e,t]of a._eventCleanup)a.removeEventListener(e,t);a._eventCleanup=null}let o=r.querySelector(`audio`);if(o&&n.options.loop!==`1`&&o.pause(),o?._eventCleanup){for(let[e,t]of o._eventCleanup)o.removeEventListener(e,t);o._eventCleanup=null}this._stopAudioOverlays(n.id),r._pdfCleanup&&r._pdfCleanup();let s=r.querySelectorAll(`iframe`);for(let e of s){try{let t=e.contentDocument||e.contentWindow?.document;t&&(t.querySelectorAll(`video`).forEach(e=>{e.pause(),e.removeAttribute(`src`),e.load()}),t.querySelectorAll(`audio`).forEach(e=>{e.pause(),e.removeAttribute(`src`),e.load()}))}catch{}e.src=`about:blank`}return{widget:n,animPromise:i}}_isWidgetActive(e){let t=new Date;return!(e.fromDt&&t<new Date(e.fromDt)||e.toDt&&t>new Date(e.toDt))}_parseDurationComments(e,t){let n=t.duration,r=e.match(/<!--\s*DURATION=(\d+)\s*-->/);if(r){let e=parseInt(r[1],10);if(e>0){this.log.info(`Widget ${t.id}: DURATION comment overrides duration ${t.duration}→${e}s`),t.duration=e,t.duration!==n&&this.updateLayoutDuration();return}}let i=e.match(/<!--\s*NUMITEMS=(\d+)\s*-->/);if(i){let e=parseInt(i[1],10);if(e>0&&t.duration>0){let n=e*t.duration;this.log.info(`Widget ${t.id}: NUMITEMS=${e} × ${t.duration}s = ${n}s`),t.duration=n}}t.duration!==n&&this.updateLayoutDuration()}_applyCyclePlayback(e){this._subPlaylistCycleIndex||=new Map;let t=new Map,n=[];for(let r of e)r.parentWidgetId&&r.cyclePlayback?(t.has(r.parentWidgetId)||t.set(r.parentWidgetId,[]),t.get(r.parentWidgetId).push(r)):n.push({type:`direct`,widget:r});for(let[e,r]of t){r.sort((e,t)=>e.displayOrder-t.displayOrder);let t;if(r.some(e=>e.isRandom))t=r[Math.floor(Math.random()*r.length)];else{let n=this._subPlaylistCycleIndex.get(e)||{widgetIdx:0,playsDone:0};t=r[n.widgetIdx%r.length];let i=t.playCount||1;n.playsDone++,n.playsDone>=i&&(n.widgetIdx++,n.playsDone=0),this._subPlaylistCycleIndex.set(e,n)}this.log.info(`Sub-playlist cycle: group ${e} selected widget ${t.id} (${r.length} in group)`),n.push({type:`direct`,widget:t})}return n.map(e=>e.widget)}_startRegionCycle(e,t,n,r,i){if(!e||e.widgets.length===0)return;if(e.isCanvas){this._startCanvasRegion(e,t,n,i);return}if(e.widgets.length===1){n(t,0);return}let a=()=>{let o=e.currentIndex,s=e.widgets[o];n(t,o);let c=s.duration*1e3;this.log.info(`Region ${t} widget ${s.id} (${s.type}) playing for ${s.duration}s (useDuration=${s.useDuration}, index ${o}/${e.widgets.length})`),e.timer=setTimeout(()=>{this._handleWidgetCycleEnd(s,e,t,o,n,r,i,a)},c)};a()}_startCanvasRegion(e,t,n,r){for(let r=0;r<e.widgets.length;r++)n(t,r);let i=Math.max(...e.widgets.map(e=>e.duration))*1e3;i>0?e.timer=setTimeout(()=>{e.complete||(e.complete=!0,r?.())},i):(e.complete=!0,r?.())}_handleWidgetCycleEnd(e,t,n,r,i,a,o,s){e.webhookUrl&&this.emit(`widgetAction`,{type:`durationEnd`,widgetId:e.id,layoutId:this.currentLayoutId,regionId:n,url:e.webhookUrl}),a(n,r);let c=(t.currentIndex+1)%t.widgets.length;if(c===0&&!t.complete&&(t.complete=!0,o?.()),c===0&&t.config?.loop===!1&&t.widgets.length===1){i(n,0);return}this.layoutEndEmitted||(t.currentIndex=c,s())}async renderWidget(e,t){let n=this.regions.get(e);if(n)try{let r=await this._showWidget(n,t);if(r&&(this.log.info(`Showing widget ${r.type} (${r.id}) in region ${e}`),this._startedWidgets.add(`${e}:${t}`),this.emit(`widgetStart`,{widgetId:r.id,regionId:e,layoutId:this.currentLayoutId,mediaId:parseInt(r.fileId||r.id)||null,type:r.type,duration:r.duration,enableStat:r.enableStat}),r.commands&&r.commands.length>0))for(let t of r.commands)this.emit(`widgetCommand`,{commandCode:t.commandCode,commandString:t.commandString,widgetId:r.id,regionId:e,layoutId:this.currentLayoutId})}catch(r){this.log.error(`Error rendering widget:`,r),this.emit(`error`,{type:`widgetError`,error:r,widgetId:n.widgets[t]?.id,regionId:e})}}async stopWidget(e,t){let n=`${e}:${t}`;if(!this._startedWidgets.delete(n))return;let r=this.regions.get(e);if(!r)return;let{widget:i,animPromise:a}=this._hideWidget(r,t);i&&this.emit(`widgetEnd`,{widgetId:i.id,regionId:e,layoutId:this.currentLayoutId,mediaId:parseInt(i.fileId||i.id)||null,type:i.type,enableStat:i.enableStat}),a&&await a}_stopAllRegionWidgets(e,t){for(let[n,r]of e)if(r.isCanvas)for(let e=0;e<r.widgets.length;e++)t(n,e);else r.widgets.length>0&&t(n,r.currentIndex)}async renderImage(e,t){let n=document.createElement(`img`);n.className=`renderer-lite-widget`,n.style.width=`100%`,n.style.height=`100%`;let r=e.options.scaleType,i={stretch:`fill`,center:`contain`,fit:`cover`};n.style.objectFit=i[r]||`contain`;let a={left:`left`,center:`center`,right:`right`},o={top:`top`,middle:`center`,bottom:`bottom`},s=a[e.options.alignId]||`center`,c=o[e.options.valignId]||`center`;return n.style.objectPosition=`${s} ${c}`,n.style.opacity=`0`,n.src=e.options.uri?this._mediaFileUrl(e.options.uri):``,n}async renderVideo(t,n){let r=document.createElement(`video`);r.className=`renderer-lite-widget`,r.style.width=`100%`,r.style.height=`100%`;let i=t.options.scaleType,a={stretch:`fill`,center:`none`,fit:`contain`};r.style.objectFit=a[i]||`contain`,r.style.opacity=`1`,r.autoplay=!0,r.preload=`auto`,r.muted=t.options.mute===`1`,r.loop=!1,r.controls=!1,r.playsInline=!0;let o=t.options.uri||``,s=t.fileId||t.id,c=()=>{t.options.loop===`1`?(r.currentTime=0,this.log.info(`Video ${o} ended - reset to start, waiting for widget cycle to replay`)):this.log.info(`Video ${o} ended - paused on last frame`)};r.addEventListener(`ended`,c);let l=o?this._mediaFileUrl(o):``;if(l.includes(`.m3u8`))if(r.canPlayType(`application/vnd.apple.mpegurl`))this.log.info(`HLS stream (native): ${s}`),r.src=l;else try{let{default:t}=await e(async()=>{let{default:e}=await import(`hls.js`);return{default:e}},[],import.meta.url);if(t.isSupported()){let e=new t({enableWorker:!0,lowLatencyMode:!0});e.loadSource(l),e.attachMedia(r),r._hlsInstance=e,e.on(t.Events.ERROR,(t,n)=>{n.fatal&&(this.log.error(`HLS fatal error: ${n.type}`,n.details),e.destroy(),r._hlsInstance=null)}),this.log.info(`HLS stream (hls.js): ${s}`)}else this.log.warn(`HLS not supported on this browser for ${s}`),r.src=l}catch(e){this.log.warn(`hls.js not available, falling back to native: ${e.message}`),r.src=l}else r.src=l;let u=this._preloadingLayoutId||this.currentLayoutId,d=()=>{let e=r.duration;this.log.info(`Video ${o} duration detected: ${e}s`),(t.duration===0||t.useDuration===0)&&(t.duration=e,t._probed=!0,this.log.info(`Updated widget ${t.id} duration to ${e}s (useDuration=0)`),this.currentLayoutId===u?this.updateLayoutDuration():this.log.info(`Video ${o} duration set but layout timer not updated (preloaded for layout ${u}, current is ${this.currentLayoutId})`))};r.addEventListener(`loadedmetadata`,d);let f=()=>{this.log.info(`Video loaded and ready:`,o)};r.addEventListener(`loadeddata`,f);let p=()=>{let e=r.error,n=e?.code,i=e?.message||`Unknown error`;this.log.warn(`Video error: ${o}, code: ${n}, time: ${r.currentTime.toFixed(1)}s, message: ${i}`),t.useDuration===0&&t.duration===0&&(t.duration=60,this.log.info(`Set fallback duration 60s for errored widget ${t.id}`),this.currentLayoutId===u&&this.updateLayoutDuration()),this.emit(`videoError`,{storedAs:o,fileId:s,errorCode:n,errorMessage:i,currentTime:r.currentTime})};r.addEventListener(`error`,p);let m=()=>{this.log.info(`Video playing:`,o)};return r.addEventListener(`playing`,m),r._eventCleanup=[[`ended`,c],[`loadedmetadata`,d],[`loadeddata`,f],[`error`,p],[`playing`,m]],this.log.info(`Video element created:`,o,r.src),r}async renderVideoIn(e,t){let n=document.createElement(`video`);n.className=`renderer-lite-widget`,n.style.width=`100%`,n.style.height=`100%`,n.style.objectFit=e.options.showFullScreen===`1`?`cover`:`contain`,n.autoplay=!0,n.playsInline=!0,n.controls=!1,n.muted=e.options.mute!==`0`,e.options.mirror===`1`&&(n.style.transform=`scaleX(-1)`);let r={width:{ideal:t.width},height:{ideal:t.height}},i=e.options.sourceId||e.options.deviceId;i?r.deviceId={exact:i}:r.facingMode=e.options.facingMode||`environment`;let a={video:r,audio:e.options.captureAudio===`1`};n._mediaConstraints=a;try{let t=await navigator.mediaDevices.getUserMedia(a);n.srcObject=t,n._mediaStream=t,this.log.info(`Webcam stream acquired for widget ${e.id} (tracks: ${t.getTracks().length})`)}catch(n){return this.log.warn(`getUserMedia failed for widget ${e.id}: ${n.message}`),this._renderUnsupportedPlaceholder({...e,type:`Camera unavailable`},t)}return n}async renderAudio(e,t){let n=document.createElement(`div`);n.className=`renderer-lite-widget audio-widget`,n.style.width=`100%`,n.style.height=`100%`,n.style.display=`flex`,n.style.flexDirection=`column`,n.style.alignItems=`center`,n.style.justifyContent=`center`,n.style.background=`linear-gradient(135deg, #667eea 0%, #764ba2 100%)`,n.style.opacity=`0`;let r=document.createElement(`audio`);r.autoplay=!0,r.loop=e.options.loop===`1`,r.volume=parseFloat(e.options.volume||`100`)/100;let i=e.options.uri||``;e.fileId||e.id,r.src=i?this._mediaFileUrl(i):``;let a=()=>{e.options.loop===`1`?(r.currentTime=0,this.log.info(`Audio ${i} ended - reset to start, waiting for widget cycle to replay`)):this.log.info(`Audio ${i} ended - playback complete`)};r.addEventListener(`ended`,a);let o=this._preloadingLayoutId||this.currentLayoutId,s=()=>{let t=Math.floor(r.duration);this.log.info(`Audio ${i} duration detected: ${t}s`),(e.duration===0||e.useDuration===0)&&(e.duration=t,this.log.info(`Updated widget ${e.id} duration to ${t}s (useDuration=0)`),this.currentLayoutId===o?this.updateLayoutDuration():this.log.info(`Audio ${i} duration set but layout timer not updated (preloaded for layout ${o}, current is ${this.currentLayoutId})`))};r.addEventListener(`loadedmetadata`,s);let c=()=>{let e=r.error;this.log.warn(`Audio error (non-fatal): ${i}, code: ${e?.code}, message: ${e?.message||`Unknown`}`)};r.addEventListener(`error`,c),r._eventCleanup=[[`ended`,a],[`loadedmetadata`,s],[`error`,c]];let l=document.createElement(`div`);l.innerHTML=`♪`,l.style.fontSize=`120px`,l.style.color=`white`,l.style.marginBottom=`20px`;let u=document.createElement(`div`);u.style.color=`white`,u.style.fontSize=`24px`,u.textContent=`Playing Audio`;let d=document.createElement(`div`);return d.style.color=`rgba(255,255,255,0.7)`,d.style.fontSize=`16px`,d.style.marginTop=`10px`,d.textContent=e.options.uri,n.appendChild(r),n.appendChild(l),n.appendChild(u),n.appendChild(d),n}async renderTextWidget(e,t){return await this._renderIframeWidget(e,t)}async renderPdf(t,r){let i=document.createElement(`div`);if(i.className=`renderer-lite-widget pdf-widget`,i.style.width=`100%`,i.style.height=`100%`,i.style.backgroundColor=`transparent`,i.style.opacity=`0`,i.style.position=`relative`,window.pdfjsLib===void 0)try{let t=await e(()=>import(`./pdf-Bxz9Nzto.js`),__vite__mapDeps([0,1]),import.meta.url);window.pdfjsLib=t;let n=window.location.pathname.replace(/\/[^/]*$/,`/`);window.pdfjsLib.GlobalWorkerOptions.workerSrc=`${window.location.origin}${n}pdf.worker.min.mjs`}catch(e){return this.log.error(`PDF.js not available:`,e),i.innerHTML=`<div style="color:white;padding:20px;text-align:center;">PDF viewer unavailable</div>`,i.style.opacity=`1`,i}let a=t.options.uri?this._mediaFileUrl(t.options.uri):``;try{let e=await window.pdfjsLib.getDocument(a).promise,o=e.numPages,s=t.duration||60,c=s*1e3/o;this.log.info(`[pdf] PDF loaded: ${o} pages, ${s}s duration, ${(c/1e3).toFixed(1)}s/page`);let l=await e.getPage(1),u=l.getViewport({scale:1}),d=Math.min(r.width/u.width,r.height/u.height);l.cleanup();let f=document.createElement(`canvas`);f.className=`pdf-page`,f.width=Math.floor(u.width*d),f.height=Math.floor(u.height*d),f.style.cssText=`display:block;margin:auto;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);`;let p=f.getContext(`2d`);i.appendChild(f);let m=document.createElement(`div`);m.style.cssText=`position:absolute;bottom:10px;right:10px;background:rgba(0,0,0,0.7);color:white;padding:8px 12px;border-radius:4px;font:14px system-ui;z-index:1;`,n()||(m.style.display=`none`),i.appendChild(m);let h=1,g=null,_=null,v=!1,y=async()=>{if(v)return;m.textContent=`Page ${h} / ${o}`;let t=await e.getPage(h),n=t.getViewport({scale:d});p.clearRect(0,0,f.width,f.height),_=t.render({canvasContext:p,viewport:n});try{await _.promise}catch(e){if(v)return;throw e}_=null,t.cleanup(),o>1&&!v&&(g=setTimeout(()=>{h=h>=o?1:h+1,y()},c))};await y();let b=null;i._pdfCleanup=()=>{if(v=!0,g&&clearTimeout(g),g=null,_){let e=_;_=null,e.cancel(),b=e.promise.catch(()=>{})}},i._pdfResume=async()=>{i._pdfCleanup(),b&&=(await b,null),v=!1,h=1,y()},i._pdfDestroy=()=>{i._pdfCleanup(),f.width=0,f.height=0,e.destroy()}}catch(e){this.log.error(`PDF render failed:`,e),i.innerHTML=`<div style="color:white;padding:20px;text-align:center;">Failed to load PDF</div>`}return i.style.opacity=`1`,i}async renderWebpage(e,t){if(parseInt(e.options.modeId||`1`)===0)return await this.renderGenericWidget(e,t);let n=document.createElement(`iframe`);return n.className=`renderer-lite-widget`,n.style.width=`100%`,n.style.height=`100%`,n.style.border=`none`,n.style.opacity=`0`,n.src=decodeURIComponent(e.options.uri||``),n}async renderGenericWidget(e,t){return await this._renderIframeWidget(e,t)}async _renderIframeWidget(e,t){let n=document.createElement(`iframe`);n.className=`renderer-lite-widget`,n.style.width=`100%`,n.style.height=`100%`,n.style.border=`none`,n.style.opacity=`0`;let r=e.raw;if(this.options.getWidgetHtml){let t=await this.options.getWidgetHtml(e);if(t&&typeof t==`object`&&t.url)return n.src=t.url,t.fallback&&this._parseDurationComments(t.fallback,e),n;r=t}if(r){this._parseDurationComments(r,e);let t=new Blob([r],{type:`text/html`}),i=URL.createObjectURL(t);n.src=i,this.trackBlobUrl(i)}else this.log.warn(`No HTML for widget ${e.id}`),n.srcdoc=`<div style="padding:20px;">Widget content unavailable</div>`;return n}_renderUnsupportedPlaceholder(e,t){let n=document.createElement(`div`);return n.className=`renderer-lite-widget`,n.style.width=`100%`,n.style.height=`100%`,n.style.display=`flex`,n.style.alignItems=`center`,n.style.justifyContent=`center`,n.style.backgroundColor=`#111`,n.style.color=`#666`,n.style.fontSize=`14px`,n.textContent=`Unsupported: ${e.type}`,n}_scheduleNextLayoutPreload(e){this.preloadTimer&&=(clearTimeout(this.preloadTimer),null),this._preloadRetryTimer&&=(clearTimeout(this._preloadRetryTimer),null);let t=e.duration||60,n=t*1e3*.75,r=t*1e3*.9;this.log.info(`Scheduling next layout preload in ${(n/1e3).toFixed(1)}s (75% of ${t}s)`),this.preloadTimer=setTimeout(()=>{this.preloadTimer=null,this.emit(`request-next-layout-preload`)},n),this._preloadRetryTimer=setTimeout(()=>{this._preloadRetryTimer=null,this.emit(`request-next-layout-preload`)},r)}hasPreloadedLayout(e){return this.layoutPool.has(e)}async preloadLayout(e,t){return this.layoutPool.has(t)?(this.log.info(`Layout ${t} already in preload pool, skipping`),!0):this.currentLayoutId===t?(this.log.info(`Layout ${t} is current, skipping preload`),!0):this._preloadingLayoutId===t&&this._preloadingPromise?(this.log.info(`Layout ${t} preload in-flight, waiting for it...`),this._preloadingPromise):(this._preloadingPromise=this._doPreloadLayout(e,t),this._preloadingPromise)}async _doPreloadLayout(e,t){try{this.log.info(`Preloading layout ${t} into pool...`);let n=this.parseXlf(e);this.calculateScale(n);let r=document.createElement(`div`);if(r.id=`preload_layout_${t}`,r.className=`renderer-lite-preload-wrapper`,r.style.position=`absolute`,r.style.top=`0`,r.style.left=`0`,r.style.width=`100%`,r.style.height=`100%`,r.style.visibility=`hidden`,r.style.zIndex=`-1`,r.style.backgroundColor=n.bgcolor,n.background){let e=this.options.fileIdToSaveAs?.get(String(n.background))||n.background;this._applyBackgroundImage(r,this._mediaFileUrl(e))}let i=this.currentLayoutId,a=new Map;for(let e of n.regions){let n=this._createRegionEntry(e,`preload_region_${t}_${e.id}`,r);a.set(e.id,n)}let o=new Set,s=this.layoutBlobUrls;this.layoutBlobUrls=new Map,this.layoutBlobUrls.set(t,o),this._preloadingLayoutId=t;for(let[e,n]of a)for(let r=0;r<n.widgets.length;r++){let i=n.widgets[r];i.layoutId=t,i.regionId=e;try{let e=await this.createWidgetElement(i,n);this._positionWidgetElement(e),n.element.appendChild(e),n.widgetElements.set(i.id,e)}catch(e){this.log.error(`Preload: Failed to create widget ${i.id}:`,e)}}return this.currentLayoutId=i,r.querySelectorAll(`video`).forEach(e=>e.pause()),(this.layoutBlobUrls.get(t)||new Set).forEach(e=>o.add(e)),this.layoutBlobUrls=s,this.container.appendChild(r),this.layoutPool.add(t,{container:r,layout:n,regions:a,blobUrls:o}),this.log.info(`Layout ${t} preloaded into pool (${a.size} regions)`),!0}catch(e){return this.log.error(`Preload failed for layout ${t}:`,e),!1}finally{this._preloadingLayoutId===t&&(this._preloadingLayoutId=null,this._preloadingPromise=null)}}async _swapToPreloadedLayout(e){let t=this.layoutPool.get(e);if(!t){this.log.error(`Cannot swap: layout ${e} not in pool`);return}let n=this._resolveLayoutTransition(t.layout);return n.type===`instant`?this._swapToPreloadedLayoutInstant(e,t):this._swapToPreloadedLayoutWithTransition(e,t,n)}async _swapToPreloadedLayoutInstant(e,t){this.removeActionListeners(),this._clearLayoutTimers();let n=this.currentLayoutId,r=this.layoutEndEmitted;if(this.layoutEndEmitted=!1,n&&this.layoutPool.has(n))this._clearRegionTimers(this.regions),this._stopAllRegionWidgets(this.regions,this._stopWidgetBound),this.layoutPool.evict(n);else{this._clearRegionTimers(this.regions),this._stopAllRegionWidgets(this.regions,this._stopWidgetBound);for(let[,e]of this.regions)if(l.releaseMediaElements(e.element),e.config?.exitTransition){let t=u.apply(e.element,e.config.exitTransition,!1,e.width,e.height);if(t){let n=e.element;t.onfinish=()=>n.remove()}else e.element.remove()}else e.element.remove();n&&this.revokeBlobUrlsForLayout(n)}this.currentLayout=null,this.currentLayoutId=null,this.regions.clear(),this._activatePreloadedLayout(e,t,n,r),this.log.info(`Swapped to preloaded layout ${e} (instant transition)`),this._logResourceStats(e)}async _swapToPreloadedLayoutWithTransition(e,t,n){this.removeActionListeners(),this._clearLayoutTimers();let r=this.currentLayoutId,i=this.layoutEndEmitted;this.layoutEndEmitted=!1;let a=this.regions,o=r!==null&&this.layoutPool.has(r),s=o?this.layoutPool.get(r).container:null;this._clearRegionTimers(a),this._stopAllRegionWidgets(a,this._stopWidgetBound),this.currentLayout=null,this.currentLayoutId=null,this.regions=new Map,t.container.style.visibility=`visible`,t.container.style.zIndex=`1`,n.type===`fade`&&(t.container.style.opacity=`0`),this._activatePreloadedLayout(e,t,r,i);let c=t.layout.width,l=t.layout.height,d=u.apply(t.container,n,!0,c,l),f=null;s&&(n.type===`fade`||n.type===`slide`)&&(f=u.apply(s,n,!1,c,l));let p=()=>{if(t.container.style.zIndex=`0`,t.container.style.opacity=``,this._teardownOldLayoutAfterTransition(r,a,o),f)try{f.cancel()}catch{}this.log.info(`Swapped to preloaded layout ${e} (${n.type} transition, ${n.duration}ms)`),this._logResourceStats(e)};d?(d.onfinish=p,setTimeout(p,Math.ceil(n.duration*1.5))):p()}_activatePreloadedLayout(e,t,n,r){if(t.container.style.visibility=`visible`,t.container.style.zIndex!==`1`&&(t.container.style.zIndex=`0`),this.layoutPool.setHot(e),this.currentLayout=t.layout,this.currentLayoutId=e,this.regions=t.regions,n&&!r&&this.emit(`layoutEnd`,n),this.container.style.backgroundColor=t.layout.bgcolor,t.container.style.backgroundImage)for(let e of[`backgroundImage`,`backgroundSize`,`backgroundPosition`,`backgroundRepeat`])this.container.style[e]=t.container.style[e];else this.container.style.backgroundImage=``;this.calculateScale(t.layout),this.attachActionListeners(t.layout),this.emit(`layoutStart`,e,t.layout);for(let[e,t]of this.regions)t.currentIndex=0,t.complete=!1,this.startRegion(e);this.updateLayoutDuration(),this.startLayoutTimerWhenReady(e,t.layout),this.preloadTimer||this._scheduleNextLayoutPreload(t.layout)}_teardownOldLayoutAfterTransition(e,t,n){if(n&&e!==null){this.layoutPool.evict(e);return}for(let[,e]of t)if(l.releaseMediaElements(e.element),e.config?.exitTransition){let t=u.apply(e.element,e.config.exitTransition,!1,e.width,e.height);if(t){let n=e.element;t.onfinish=()=>n.remove()}else e.element.remove()}else e.element.remove();e&&this.revokeBlobUrlsForLayout(e)}_logResourceStats(e){let t=document.querySelectorAll(`*`).length,n=document.querySelectorAll(`video`).length,r=document.querySelectorAll(`video[src]`).length,i=document.querySelectorAll(`canvas`).length,a=document.querySelectorAll(`iframe`).length,o=document.querySelectorAll(`img`).length,s=this.layoutPool?this.layoutPool.size:0,c=this.regions?this.regions.size:0,l=[...this.regions?.values()||[]].reduce((e,t)=>e+(t.widgetElements?.size||0),0),u=performance?.memory?{used:Math.round(performance.memory.usedJSHeapSize/1048576),total:Math.round(performance.memory.totalJSHeapSize/1048576),limit:Math.round(performance.memory.jsHeapSizeLimit/1048576)}:null,d=this._blobUrls?[...this._blobUrls.values()].reduce((e,t)=>e+t.size,0):0,f=this._blobUrls?this._blobUrls.size:0,p=document.querySelectorAll(`.renderer-lite-preload-wrapper`).length,m=document.querySelectorAll(`audio`).length,h=u?`heap=${u.used}/${u.total}MB (limit ${u.limit}MB)`:`heap=N/A`;this.log.info(`[Resources] layout=${e} dom=${t} videos=${n}(src=${r}) canvas=${i} iframe=${a} img=${o} audio=${m} pool=${s} preloadWrappers=${p} regions=${c} widgets=${l} blobs=${d}(${f} layouts) ${h}`)}getCurrentLayoutId(){return this.currentLayoutId}showLayout(e){if(e===void 0&&(e=this.layoutPool.getLatest(),e===void 0)){this.log.warn(`showLayout: no preloaded layout to show`);return}if(this.currentLayoutId===e){this.log.info(`showLayout: layout ${e} already showing`);return}if(!this.layoutPool.has(e)){this.log.warn(`showLayout: layout ${e} not in preload pool`);return}this._swapToPreloadedLayout(e)}hasActiveLayoutTimer(){return this.layoutTimer!==null||this._deferredTimerLayoutId!==null}checkLayoutComplete(){let e=!0;for(let[t,n]of this.regions)if(n.widgets.length>1&&!n.complete){e=!1;break}e&&this.currentLayoutId&&this.log.info(`All multi-widget regions completed one cycle`)}_clearLayoutTimers(){this.layoutTimer&&=(clearTimeout(this.layoutTimer),null),this.preloadTimer&&=(clearTimeout(this.preloadTimer),null),this._preloadRetryTimer&&=(clearTimeout(this._preloadRetryTimer),null)}stopCurrentLayout(){if(!this.currentLayout)return;this.log.info(`Stopping layout ${this.currentLayoutId}`);let e=this.currentLayoutId,t=e&&!this.layoutEndEmitted;if(this.layoutEndEmitted=!1,this._deferredTimerLayoutId=null,this._deferredTimerFallback&&=(clearTimeout(this._deferredTimerFallback),null),this.currentLayout=null,this.currentLayoutId=null,this._clearLayoutTimers(),this.removeActionListeners(),e&&this.layoutPool.has(e))this.layoutPool.evict(e);else{e&&this.revokeBlobUrlsForLayout(e),this._clearRegionTimers(this.regions),this._stopAllRegionWidgets(this.regions,this._stopWidgetBound);for(let[,e]of this.regions)if(l.releaseMediaElements(e.element),e.config?.exitTransition){let t=u.apply(e.element,e.config.exitTransition,!1,e.width,e.height);if(t){let n=e.element;t.onfinish=()=>n.remove()}else e.element.remove()}else e.element.remove()}this.regions.clear(),t&&this.emit(`layoutEnd`,e)}async renderOverlay(e,t,n=0){try{if(this.log.info(`Rendering overlay ${t} (priority ${n})`),this.activeOverlays.has(t)){this.log.warn(`Overlay ${t} already active, skipping`);return}let r=this.parseXlf(e),i=document.createElement(`div`);i.id=`overlay_${t}`,i.className=`renderer-lite-overlay`,i.style.position=`absolute`,i.style.top=`0`,i.style.left=`0`,i.style.width=`100%`,i.style.height=`100%`,i.style.zIndex=String(1e3+n),i.style.pointerEvents=`auto`,i.style.backgroundColor=r.bgcolor,this.calculateScale(r);let a=new Map;for(let e of r.regions){let n=this._createRegionEntry(e,`overlay_${t}_region_${e.id}`,i,{className:`renderer-lite-region overlay-region`,isCanvas:e.isCanvas||!1});a.set(e.id,n)}for(let[e,n]of a)for(let r of n.widgets){r.layoutId=t,r.regionId=e;try{let e=await this.createWidgetElement(r,n);this._positionWidgetElement(e),n.element.appendChild(e),n.widgetElements.set(r.id,e)}catch(e){this.log.error(`Failed to pre-create overlay widget ${r.id}:`,e)}}this.overlayContainer.appendChild(i),this.activeOverlays.set(t,{container:i,layout:r,regions:a,timer:null,priority:n}),this.emit(`overlayStart`,t,r);for(let[e,n]of a)this.startOverlayRegion(t,e);if(r.duration>0){let e=r.duration*1e3,n=this.activeOverlays.get(t);n&&(n.timer=setTimeout(()=>{this.log.info(`Overlay ${t} duration expired (${r.duration}s)`),this.emit(`overlayEnd`,t)},e))}this.log.info(`Overlay ${t} started`)}catch(e){throw this.log.error(`Error rendering overlay:`,e),this.emit(`error`,{type:`overlayError`,error:e,layoutId:t}),e}}startOverlayRegion(e,t){let n=this.activeOverlays.get(e);if(!n)return;let r=n.regions.get(t);this._startRegionCycle(r,t,(t,n)=>this.renderOverlayWidget(e,t,n),(t,n)=>this.stopOverlayWidget(e,t,n),()=>this.log.info(`Overlay ${e} region ${t} completed one full cycle`))}async renderOverlayWidget(e,t,n){let r=this.activeOverlays.get(e);if(!r)return;let i=r.regions.get(t);if(i)try{let r=await this._showWidget(i,n);r&&(this.log.info(`Showing overlay widget ${r.type} (${r.id}) in overlay ${e} region ${t}`),this._startedWidgets.add(`overlay:${e}:${t}:${n}`),this.emit(`overlayWidgetStart`,{overlayId:e,widgetId:r.id,regionId:t,type:r.type,duration:r.duration}))}catch(r){this.log.error(`Error rendering overlay widget:`,r),this.emit(`error`,{type:`overlayWidgetError`,error:r,widgetId:i.widgets[n]?.id,regionId:t,overlayId:e})}}async stopOverlayWidget(e,t,n){let r=`overlay:${e}:${t}:${n}`;if(!this._startedWidgets.delete(r))return;let i=this.activeOverlays.get(e);if(!i)return;let a=i.regions.get(t);if(!a)return;let{widget:o,animPromise:s}=this._hideWidget(a,n);o&&this.emit(`overlayWidgetEnd`,{overlayId:e,widgetId:o.id,regionId:t,type:o.type}),s&&await s}stopOverlay(e){let t=this.activeOverlays.get(e);if(!t){this.log.warn(`Overlay ${e} not active`);return}this.log.info(`Stopping overlay ${e}`),t.timer&&=(clearTimeout(t.timer),null);for(let[,e]of t.regions)e.timer&&=(clearTimeout(e.timer),null);this._stopAllRegionWidgets(t.regions,(t,n)=>this.stopOverlayWidget(e,t,n)),t.container&&t.container.remove(),this.revokeBlobUrlsForLayout(e),this.activeOverlays.delete(e),this.emit(`overlayEnd`,e),this.log.info(`Overlay ${e} stopped`)}stopAllOverlays(){let e=Array.from(this.activeOverlays.keys());for(let t of e)this.stopOverlay(t);this.log.info(`All overlays stopped`)}getActiveOverlays(){return Array.from(this.activeOverlays.keys())}pause(){if(!this._paused){this._paused=!0;for(let[,e]of this.regions)e.timer&&=(clearTimeout(e.timer),null);this._forEachMedia(e=>e.pause()),this.emit(`paused`),this.log.info(`Playback paused (layout timer continues)`)}}isPaused(){return this._paused}resume(){if(this._paused){this._paused=!1,this._forEachMedia(e=>e.play().catch(()=>{}));for(let[e]of this.regions)this.startRegion(e);this.emit(`resumed`),this.log.info(`Playback resumed`)}}_forEachMedia(e){for(let[,t]of this.regions)t.element?.querySelectorAll(`video, audio`).forEach(e)}cleanup(){this.stopAllOverlays(),this.stopCurrentLayout(),this._startedWidgets.clear();for(let e of this.audioOverlays.keys())this._stopAudioOverlays(e);this.layoutPool.clear(),this.preloadTimer&&=(clearTimeout(this.preloadTimer),null),this._preloadRetryTimer&&=(clearTimeout(this._preloadRetryTimer),null),this.resizeObserver&&=(this.resizeObserver.disconnect(),null),this.container.innerHTML=``,this.log.info(`Cleaned up`)}},f=i(`Layout`),p=/^(#[0-9a-fA-F]{3,8}|rgba?\(\s*[\d.,\s%]+\)|[a-zA-Z]{1,20}|transparent|inherit)$/,m=e=>p.test(e)?e:`#000000`,h=e=>JSON.stringify(e),g=class{constructor(e){this.xmds=e}async translateXLF(e,t){let n=new DOMParser().parseFromString(t,`text/xml`),r=n.querySelector(`layout`);if(!r)throw Error(`Invalid XLF: no <layout> element`);let i=parseInt(r.getAttribute(`width`)||`1920`),a=parseInt(r.getAttribute(`height`)||`1080`),o=m(r.getAttribute(`bgcolor`)||`#000000`),s=[];for(let t of n.querySelectorAll(`region`))s.push(await this.translateRegion(e,t));return this.generateHTML(i,a,o,s)}async translateRegion(e,t){let n=t.getAttribute(`id`),r=parseInt(t.getAttribute(`width`)),i=parseInt(t.getAttribute(`height`)),a=parseInt(t.getAttribute(`top`)),o=parseInt(t.getAttribute(`left`)),s=parseInt(t.getAttribute(`zindex`)||`0`),c=[];for(let r of t.querySelectorAll(`media`))c.push(await this.translateMedia(e,n,r));return{id:n,width:r,height:i,top:a,left:o,zindex:s,media:c}}async translateMedia(e,t,n){let i=n.getAttribute(`type`),o=parseInt(n.getAttribute(`duration`)||`10`),s=n.getAttribute(`id`),c=n.querySelector(`options`),l=n.querySelector(`raw`),u={};if(c)for(let e of c.children)u[e.tagName]=e.textContent;let d={in:null,out:null},p=n.querySelector(`options > transIn`),m=n.querySelector(`options > transOut`),h=n.querySelector(`options > transInDuration`),g=n.querySelector(`options > transOutDuration`),_=n.querySelector(`options > transInDirection`),v=n.querySelector(`options > transOutDirection`);p&&p.textContent&&(d.in={type:p.textContent,duration:parseInt(h?.textContent||`1000`),direction:_?.textContent||`N`}),m&&m.textContent&&(d.out={type:m.textContent,duration:parseInt(g?.textContent||`1000`),direction:v?.textContent||`N`});let y=l?l.textContent:``;if([`clock`,`clock-digital`,`clock-analogue`,`calendar`,`weather`,`currencies`,`stocks`,`twitter`,`global`,`embedded`,`text`,`ticker`].some(e=>i.includes(e))){let n=null;for(let r=1;r<=3;r++)try{f.info(`Fetching resource for ${i} widget (layout=${e}, region=${t}, media=${s}) - attempt ${r}/3`),y=await this.xmds.getResource(e,t,s),f.info(`Got resource HTML (${y.length} chars)`),u.widgetCacheKey=await a(e,t,s,y);break}catch(e){if(n=e,f.warn(`Failed to get resource (attempt ${r}/3):`,e.message),r<3){let e=r*2e3;f.info(`Retrying in ${e}ms...`),await new Promise(t=>setTimeout(t,e))}}if(!y&&n){f.warn(`All retries failed, checking for cached widget HTML...`);try{let n=await fetch(`/store${r}/widgets/${e}/${t}/${s}`);n.ok?(y=await n.text(),u.widgetCacheKey=`${r}/widgets/${e}/${t}/${s}`,f.info(`Using stored widget HTML (${y.length} chars) - CMS update pending`)):(f.error(`No stored version available for widget ${s}`),y=`<div style="display:flex;align-items:center;justify-content:center;height:100%;color:#999;font-size:18px;">Content updating...</div>`)}catch(e){f.error(`Store fallback failed:`,e),y=`<div style="display:flex;align-items:center;justify-content:center;height:100%;color:#999;font-size:18px;">Content updating...</div>`}}}return{type:i,duration:o,id:s,options:u,raw:y,transitions:d}}generateHTML(e,t,n,r){return`<!DOCTYPE html>
3
- <html>
4
- <head>
5
- <meta charset="utf-8">
6
- <meta name="viewport" content="width=${e}, height=${t}">
7
- <style>
8
- * { margin: 0; padding: 0; box-sizing: border-box; }
9
- html, body { width: 100%; height: 100%; overflow: hidden; }
10
- body { background-color: ${n}; }
11
- .region {
12
- position: absolute;
13
- overflow: hidden;
14
- }
15
- .media {
16
- width: 100%;
17
- height: 100%;
18
- object-fit: contain;
19
- }
20
- iframe {
21
- border: none;
22
- width: 100%;
23
- height: 100%;
24
- }
25
- </style>
26
- </head>
27
- <body>
28
- ${r.map(e=>this.generateRegionHTML(e)).join(`
29
- `)}
30
- <script>
31
- // Transition utilities
32
- window.Transitions = {
33
- fadeIn(element, duration) {
34
- const keyframes = [
35
- { opacity: 0 },
36
- { opacity: 1 }
37
- ];
38
- const timing = {
39
- duration: duration,
40
- easing: 'linear',
41
- fill: 'forwards'
42
- };
43
- return element.animate(keyframes, timing);
44
- },
45
-
46
- fadeOut(element, duration) {
47
- const keyframes = [
48
- { opacity: 1 },
49
- { opacity: 0 }
50
- ];
51
- const timing = {
52
- duration: duration,
53
- easing: 'linear',
54
- fill: 'forwards'
55
- };
56
- return element.animate(keyframes, timing);
57
- },
58
-
59
- getFlyKeyframes(direction, width, height, isIn) {
60
- const dirMap = {
61
- 'N': { x: 0, y: isIn ? -height : height },
62
- 'NE': { x: isIn ? width : -width, y: isIn ? -height : height },
63
- 'E': { x: isIn ? width : -width, y: 0 },
64
- 'SE': { x: isIn ? width : -width, y: isIn ? height : -height },
65
- 'S': { x: 0, y: isIn ? height : -height },
66
- 'SW': { x: isIn ? -width : width, y: isIn ? height : -height },
67
- 'W': { x: isIn ? -width : width, y: 0 },
68
- 'NW': { x: isIn ? -width : width, y: isIn ? -height : height }
69
- };
70
-
71
- const offset = dirMap[direction] || dirMap['N'];
72
-
73
- if (isIn) {
74
- return [
75
- { transform: \`translate(\${offset.x}px, \${offset.y}px)\`, opacity: 0 },
76
- { transform: 'translate(0, 0)', opacity: 1 }
77
- ];
78
- } else {
79
- return [
80
- { transform: 'translate(0, 0)', opacity: 1 },
81
- { transform: \`translate(\${offset.x}px, \${offset.y}px)\`, opacity: 0 }
82
- ];
83
- }
84
- },
85
-
86
- flyIn(element, duration, direction, regionWidth, regionHeight) {
87
- const keyframes = this.getFlyKeyframes(direction, regionWidth, regionHeight, true);
88
- const timing = {
89
- duration: duration,
90
- easing: 'ease-out',
91
- fill: 'forwards'
92
- };
93
- return element.animate(keyframes, timing);
94
- },
95
-
96
- flyOut(element, duration, direction, regionWidth, regionHeight) {
97
- const keyframes = this.getFlyKeyframes(direction, regionWidth, regionHeight, false);
98
- const timing = {
99
- duration: duration,
100
- easing: 'ease-in',
101
- fill: 'forwards'
102
- };
103
- return element.animate(keyframes, timing);
104
- },
105
-
106
- apply(element, transitionConfig, isIn, regionWidth, regionHeight) {
107
- if (!transitionConfig || !transitionConfig.type) {
108
- return null;
109
- }
110
-
111
- const type = transitionConfig.type.toLowerCase();
112
- const duration = transitionConfig.duration || 1000;
113
- const direction = transitionConfig.direction || 'N';
114
-
115
- switch (type) {
116
- case 'fade':
117
- return isIn ? this.fadeIn(element, duration) : this.fadeOut(element, duration);
118
- case 'fadein':
119
- return isIn ? this.fadeIn(element, duration) : null;
120
- case 'fadeout':
121
- return isIn ? null : this.fadeOut(element, duration);
122
- case 'fly':
123
- return isIn
124
- ? this.flyIn(element, duration, direction, regionWidth, regionHeight)
125
- : this.flyOut(element, duration, direction, regionWidth, regionHeight);
126
- case 'flyin':
127
- return isIn ? this.flyIn(element, duration, direction, regionWidth, regionHeight) : null;
128
- case 'flyout':
129
- return isIn ? null : this.flyOut(element, duration, direction, regionWidth, regionHeight);
130
- default:
131
- return null;
132
- }
133
- }
134
- };
135
-
136
- const regions = {
137
- ${r.map(e=>this.generateRegionJS(e)).join(`,
138
- `)}
139
- };
140
-
141
- // Auto-start all regions
142
- Object.keys(regions).forEach(id => {
143
- playRegion(id);
144
- });
145
-
146
- // Track active timers per region so layout teardown can cancel them
147
- const regionTimers = {};
148
-
149
- function playRegion(id) {
150
- const region = regions[id];
151
- if (!region || region.media.length === 0) return;
152
-
153
- regionTimers[id] = [];
154
-
155
- // If only one media item, just show it and don't cycle (arexibo behavior)
156
- if (region.media.length === 1) {
157
- const media = region.media[0];
158
- if (media.start) media.start();
159
- return; // Don't schedule stop/restart
160
- }
161
-
162
- // Multiple media items - cycle normally
163
- let currentIndex = 0;
164
-
165
- function playNext() {
166
- const media = region.media[currentIndex];
167
- if (media.start) media.start();
168
-
169
- const duration = media.duration || 10;
170
- const timerId = setTimeout(() => {
171
- if (media.stop) media.stop();
172
- currentIndex = (currentIndex + 1) % region.media.length;
173
- playNext();
174
- }, duration * 1000);
175
- regionTimers[id].push(timerId);
176
- }
177
-
178
- playNext();
179
- }
180
-
181
- // Cleanup function — called before layout teardown
182
- window._stopAllRegions = function() {
183
- Object.values(regionTimers).forEach(timers => timers.forEach(t => clearTimeout(t)));
184
- };
185
- <\/script>
186
- </body>
187
- </html>`}generateRegionHTML(e){return` <div id="region_${e.id}" class="region" style="
188
- left: ${e.left}px;
189
- top: ${e.top}px;
190
- width: ${e.width}px;
191
- height: ${e.height}px;
192
- z-index: ${e.zindex};
193
- "></div>`}generateRegionJS(e){let t=e.media.map(t=>this.generateMediaJS(t,e.id)).join(`,
194
- `);return` '${e.id}': {
195
- media: [
196
- ${t}
197
- ]
198
- }`}_generateIframeWidgetJS(e,t,n,r,i){let a=`widget_${e}_${t}`;return{startFn:`() => {
199
- const region = document.getElementById('region_${e}');
200
- let iframe = document.getElementById('${a}');
201
- if (!iframe) {
202
- iframe = document.createElement('iframe');
203
- iframe.id = '${a}';
204
- iframe.src = ${h(n)};
205
- iframe.style.width = '100%';
206
- iframe.style.height = '100%';
207
- iframe.style.border = 'none';
208
- iframe.scrolling = 'no';
209
- iframe.style.opacity = '0';
210
- region.innerHTML = '';
211
- region.appendChild(iframe);
212
-
213
- // Apply transition after iframe loads
214
- iframe.onload = () => {
215
- const transIn = ${r};
216
- if (transIn && window.Transitions) {
217
- const regionRect = region.getBoundingClientRect();
218
- window.Transitions.apply(iframe, transIn, true, regionRect.width, regionRect.height);
219
- } else {
220
- iframe.style.opacity = '1';
221
- }
222
- };
223
- } else {
224
- iframe.style.display = 'block';
225
- iframe.style.opacity = '1';
226
- }
227
- }`,stopFn:`() => {
228
- const region = document.getElementById('region_${e}');
229
- const iframe = document.getElementById('${a}');
230
- if (iframe) {
231
- const transOut = ${i};
232
- if (transOut && window.Transitions) {
233
- const regionRect = region.getBoundingClientRect();
234
- const animation = window.Transitions.apply(iframe, transOut, false, regionRect.width, regionRect.height);
235
- if (animation) {
236
- animation.onfinish = () => {
237
- iframe.style.display = 'none';
238
- };
239
- return;
240
- }
241
- }
242
- iframe.style.display = 'none';
243
- }
244
- }`}}generateMediaJS(e,t){let i=e.duration||10,a=e.transitions?.in?JSON.stringify(e.transitions.in):`null`,o=e.transitions?.out?JSON.stringify(e.transitions.out):`null`,s=`null`,c=`null`;switch(e.type){case`image`:s=`() => {
245
- const region = document.getElementById('region_${t}');
246
- const img = document.createElement('img');
247
- img.className = 'media';
248
- img.src = ${h(`${window.location.origin}${r}/media/${e.options.uri}`)};
249
- img.style.opacity = '0';
250
- region.innerHTML = '';
251
- region.appendChild(img);
252
-
253
- // Apply transition
254
- const transIn = ${a};
255
- if (transIn && window.Transitions) {
256
- const regionRect = region.getBoundingClientRect();
257
- window.Transitions.apply(img, transIn, true, regionRect.width, regionRect.height);
258
- } else {
259
- img.style.opacity = '1';
260
- }
261
- }`;break;case`video`:{let n=`${window.location.origin}${r}/media/${e.options.uri}`,i=e.options.uri;s=`() => {
262
- const region = document.getElementById('region_${t}');
263
- const video = document.createElement('video');
264
- video.className = 'media';
265
- video.src = ${h(n)};
266
- video.dataset.filename = ${h(i)};
267
- video.autoplay = true;
268
- video.muted = ${e.options.mute===`1`?`true`:`false`};
269
- video.loop = false;
270
- video.style.width = '100%';
271
- video.style.height = '100%';
272
- video.style.objectFit = 'contain';
273
- video.style.opacity = '0';
274
-
275
- // Retry loading if cache completes while video is playing
276
- const retryOnCache = (event) => {
277
- if (event.detail.filename === ${h(i)} && video.error) {
278
- console.log('[Video] Cache complete, reloading:', '${i}');
279
- video.load();
280
- video.play();
281
- }
282
- };
283
- video._retryOnCache = retryOnCache;
284
- window.addEventListener('media-cached', retryOnCache);
285
-
286
- region.innerHTML = '';
287
- region.appendChild(video);
288
-
289
- // Apply transition
290
- const transIn = ${a};
291
- if (transIn && window.Transitions) {
292
- const regionRect = region.getBoundingClientRect();
293
- window.Transitions.apply(video, transIn, true, regionRect.width, regionRect.height);
294
- } else {
295
- video.style.opacity = '1';
296
- }
297
-
298
- console.log('[Video] Playing:', '${e.options.uri}');
299
- }`,c=`() => {
300
- const region = document.getElementById('region_${t}');
301
- const video = document.querySelector('#region_${t} video');
302
- if (video) {
303
- // Remove global media-cached listener to prevent leak
304
- if (video._retryOnCache) {
305
- window.removeEventListener('media-cached', video._retryOnCache);
306
- video._retryOnCache = null;
307
- }
308
- const transOut = ${o};
309
- if (transOut && window.Transitions) {
310
- const regionRect = region.getBoundingClientRect();
311
- const animation = window.Transitions.apply(video, transOut, false, regionRect.width, regionRect.height);
312
- if (animation) {
313
- animation.onfinish = () => {
314
- video.pause();
315
- video.remove();
316
- };
317
- return;
318
- }
319
- }
320
- video.pause();
321
- video.remove();
322
- }
323
- }`;break}case`text`:case`ticker`:if(e.options.widgetCacheKey){let n=`${window.location.origin}${e.options.widgetCacheKey}`,r=this._generateIframeWidgetJS(t,e.id,n,a,o);s=r.startFn,c=r.stopFn;break}case`audio`:{let n=`${window.location.origin}${r}/media/${e.options.uri}`,i=`audio_${t}_${e.id}`,l=e.options.loop===`1`,u=(parseInt(e.options.volume||`100`)/100).toFixed(2);s=`() => {
324
- const region = document.getElementById('region_${t}');
325
-
326
- // Create audio element
327
- const audio = document.createElement('audio');
328
- audio.id = '${i}';
329
- audio.className = 'media';
330
- audio.src = ${h(n)};
331
- audio.autoplay = true;
332
- audio.loop = ${l};
333
- audio.volume = ${u};
334
-
335
- // Create visual feedback container
336
- const visualContainer = document.createElement('div');
337
- visualContainer.className = 'audio-visual';
338
- visualContainer.style.cssText = \`
339
- width: 100%;
340
- height: 100%;
341
- display: flex;
342
- flex-direction: column;
343
- align-items: center;
344
- justify-content: center;
345
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
346
- opacity: 0;
347
- \`;
348
-
349
- // Audio icon
350
- const icon = document.createElement('div');
351
- icon.innerHTML = '♪';
352
- icon.style.cssText = \`
353
- font-size: 120px;
354
- color: white;
355
- margin-bottom: 20px;
356
- animation: pulse 2s ease-in-out infinite;
357
- \`;
358
-
359
- // Audio info
360
- const info = document.createElement('div');
361
- info.style.cssText = \`
362
- color: white;
363
- font-size: 24px;
364
- text-align: center;
365
- padding: 0 20px;
366
- \`;
367
- info.textContent = 'Playing Audio';
368
-
369
- // Filename
370
- const filename = document.createElement('div');
371
- filename.style.cssText = \`
372
- color: rgba(255,255,255,0.7);
373
- font-size: 16px;
374
- margin-top: 10px;
375
- \`;
376
- filename.textContent = '${e.options.uri}';
377
-
378
- visualContainer.appendChild(icon);
379
- visualContainer.appendChild(info);
380
- visualContainer.appendChild(filename);
381
-
382
- region.innerHTML = '';
383
- region.appendChild(audio);
384
- region.appendChild(visualContainer);
385
-
386
- // Add pulse animation
387
- const style = document.createElement('style');
388
- style.textContent = \`
389
- @keyframes pulse {
390
- 0%, 100% { transform: scale(1); opacity: 1; }
391
- 50% { transform: scale(1.1); opacity: 0.8; }
392
- }
393
- \`;
394
- document.head.appendChild(style);
395
-
396
- // Apply transition
397
- const transIn = ${a};
398
- if (transIn && window.Transitions) {
399
- const regionRect = region.getBoundingClientRect();
400
- window.Transitions.apply(visualContainer, transIn, true, regionRect.width, regionRect.height);
401
- } else {
402
- visualContainer.style.opacity = '1';
403
- }
404
-
405
- console.log('[Audio] Playing:', '${n}', 'Volume:', ${u}, 'Loop:', ${l});
406
- }`,c=`() => {
407
- const audio = document.getElementById('${i}');
408
- if (audio) {
409
- audio.pause();
410
- audio.remove();
411
- }
412
- const region = document.getElementById('region_${t}');
413
- if (region) {
414
- const visualContainer = region.querySelector('.audio-visual');
415
- if (visualContainer) {
416
- const transOut = ${o};
417
- if (transOut && window.Transitions) {
418
- const regionRect = region.getBoundingClientRect();
419
- const animation = window.Transitions.apply(visualContainer, transOut, false, regionRect.width, regionRect.height);
420
- if (animation) {
421
- animation.onfinish = () => visualContainer.remove();
422
- return;
423
- }
424
- }
425
- visualContainer.remove();
426
- }
427
- }
428
- }`;break}case`pdf`:{let l=`${window.location.origin}${r}/media/${e.options.uri}`,u=`pdf_${t}_${e.id}`,d=i;s=`async () => {
429
- const container = document.createElement('div');
430
- container.className = 'media pdf-container';
431
- container.id = '${u}';
432
- container.style.width = '100%';
433
- container.style.height = '100%';
434
- container.style.overflow = 'hidden';
435
- container.style.backgroundColor = '#525659';
436
- container.style.opacity = '0';
437
- container.style.position = 'relative';
438
-
439
- const region = document.getElementById('region_${t}');
440
- region.innerHTML = '';
441
- region.appendChild(container);
442
-
443
- // Load PDF.js if not already loaded
444
- if (typeof pdfjsLib === 'undefined') {
445
- try {
446
- const pdfjsModule = await import('pdfjs-dist');
447
- window.pdfjsLib = pdfjsModule;
448
- pdfjsLib.GlobalWorkerOptions.workerSrc = '${window.location.origin}/player/pdf.worker.min.mjs';
449
- } catch (error) {
450
- console.error('[PDF] Failed to load PDF.js:', error);
451
- container.innerHTML = '<div style="color:white;padding:20px;text-align:center;">PDF viewer unavailable</div>';
452
- return;
453
- }
454
- }
455
-
456
- // Render PDF with multi-page support
457
- try {
458
- const loadingTask = pdfjsLib.getDocument(${h(l)});
459
- const pdf = await loadingTask.promise;
460
- const totalPages = pdf.numPages;
461
-
462
- // Calculate time per page (distribute total duration across all pages)
463
- const timePerPage = (${d} * 1000) / totalPages; // milliseconds per page
464
-
465
- console.log(\`[PDF] Loading: \${totalPages} pages, \${timePerPage}ms per page\`);
466
-
467
- const containerWidth = container.offsetWidth || ${width};
468
- const containerHeight = container.offsetHeight || ${height};
469
-
470
- // Create page indicator
471
- const pageIndicator = document.createElement('div');
472
- pageIndicator.className = 'pdf-page-indicator';
473
- pageIndicator.style.cssText = \`
474
- position: absolute;
475
- bottom: 10px;
476
- right: 10px;
477
- background: rgba(0,0,0,0.7);
478
- color: white;
479
- padding: 8px 12px;
480
- border-radius: 4px;
481
- font-size: 14px;
482
- z-index: 10;
483
- display: ${n()?`block`:`none`};
484
- \`;
485
- container.appendChild(pageIndicator);
486
-
487
- let currentPage = 1;
488
- let pageTimers = [];
489
-
490
- // Function to render a single page
491
- async function renderPage(pageNum) {
492
- const page = await pdf.getPage(pageNum);
493
- const viewport = page.getViewport({ scale: 1 });
494
-
495
- // Calculate scale to fit page within container
496
- const scaleX = containerWidth / viewport.width;
497
- const scaleY = containerHeight / viewport.height;
498
- const scale = Math.min(scaleX, scaleY);
499
-
500
- const scaledViewport = page.getViewport({ scale });
501
-
502
- const canvas = document.createElement('canvas');
503
- canvas.className = 'pdf-page';
504
- const context = canvas.getContext('2d');
505
- canvas.width = scaledViewport.width;
506
- canvas.height = scaledViewport.height;
507
-
508
- // Center canvas in container
509
- canvas.style.cssText = \`
510
- display: block;
511
- margin: auto;
512
- margin-top: \${Math.max(0, (containerHeight - scaledViewport.height) / 2)}px;
513
- position: absolute;
514
- top: 0;
515
- left: 50%;
516
- transform: translateX(-50%);
517
- opacity: 0;
518
- transition: opacity 0.5s ease-in-out;
519
- \`;
520
-
521
- container.appendChild(canvas);
522
-
523
- await page.render({
524
- canvasContext: context,
525
- viewport: scaledViewport
526
- }).promise;
527
-
528
- // Fade in new page
529
- setTimeout(() => canvas.style.opacity = '1', 50);
530
-
531
- return canvas;
532
- }
533
-
534
- // Function to cycle through pages
535
- async function cyclePage() {
536
- // Update page indicator
537
- pageIndicator.textContent = \`Page \${currentPage} / \${totalPages}\`;
538
-
539
- // Remove old pages
540
- const oldPages = container.querySelectorAll('.pdf-page');
541
- oldPages.forEach(oldPage => {
542
- if (oldPage !== container.lastChild) {
543
- oldPage.style.opacity = '0';
544
- setTimeout(() => oldPage.remove(), 500);
545
- }
546
- });
547
-
548
- // Render current page
549
- await renderPage(currentPage);
550
-
551
- console.log(\`[PDF] Showing page \${currentPage}/\${totalPages}\`);
552
-
553
- // Schedule next page
554
- if (totalPages > 1) {
555
- const timer = setTimeout(() => {
556
- currentPage = currentPage >= totalPages ? 1 : currentPage + 1;
557
- cyclePage();
558
- }, timePerPage);
559
- pageTimers.push(timer);
560
- }
561
- }
562
-
563
- // Store live timer array on element for cleanup (not JSON — stays current)
564
- container._pageTimers = pageTimers;
565
-
566
- // Start cycling
567
- await cyclePage();
568
-
569
- // Apply transition to container
570
- const transIn = ${a};
571
- if (transIn && window.Transitions) {
572
- const regionRect = region.getBoundingClientRect();
573
- window.Transitions.apply(container, transIn, true, regionRect.width, regionRect.height);
574
- } else {
575
- container.style.opacity = '1';
576
- }
577
-
578
- } catch (error) {
579
- console.error('[PDF] Render failed:', error);
580
- container.innerHTML = '<div style="color:white;padding:20px;text-align:center;">Failed to load PDF</div>';
581
- container.style.opacity = '1';
582
- }
583
- }`,c=`() => {
584
- const region = document.getElementById('region_${t}');
585
- const container = document.getElementById('${u}');
586
- if (container) {
587
- // Clear page cycling timers (live array, always current)
588
- if (container._pageTimers) {
589
- container._pageTimers.forEach(t => clearTimeout(t));
590
- container._pageTimers.length = 0;
591
- }
592
-
593
- const transOut = ${o};
594
- if (transOut && window.Transitions) {
595
- const regionRect = region.getBoundingClientRect();
596
- const animation = window.Transitions.apply(container, transOut, false, regionRect.width, regionRect.height);
597
- if (animation) {
598
- animation.onfinish = () => {
599
- container.remove();
600
- };
601
- return;
602
- }
603
- }
604
- container.remove();
605
- }
606
- }`;break}case`webpage`:s=`() => {
607
- const region = document.getElementById('region_${t}');
608
- const iframe = document.createElement('iframe');
609
- iframe.src = ${h(decodeURIComponent(e.options.uri||``))};
610
- iframe.style.opacity = '0';
611
- region.innerHTML = '';
612
- region.appendChild(iframe);
613
-
614
- // Apply transition after iframe loads
615
- iframe.onload = () => {
616
- const transIn = ${a};
617
- if (transIn && window.Transitions) {
618
- const regionRect = region.getBoundingClientRect();
619
- window.Transitions.apply(iframe, transIn, true, regionRect.width, regionRect.height);
620
- } else {
621
- iframe.style.opacity = '1';
622
- }
623
- };
624
- }`;break;default:if(e.options.widgetCacheKey){let n=`${window.location.origin}${e.options.widgetCacheKey}`,r=this._generateIframeWidgetJS(t,e.id,n,a,o);s=r.startFn,c=r.stopFn}else f.warn(`Unsupported media type: ${e.type}`),s=`() => console.log('Unsupported media type: ${e.type}')`}return` {
625
- start: ${s},
626
- stop: ${c},
627
- duration: ${i}
628
- }`}},_=s.version;export{l as LayoutPool,g as LayoutTranslator,d as RendererLite,_ as VERSION};
629
- //# sourceMappingURL=src-CKpVxGpH.js.map