@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.
- package/dist/assets/__vite-browser-external-DeMPM02e.js +2 -0
- package/dist/assets/__vite-browser-external-DeMPM02e.js.map +1 -0
- package/dist/assets/chunk-DzMEjpoC.js +1 -0
- package/dist/assets/{html2canvas-BAfZNSwU.js → html2canvas-EikzC5d8.js} +2 -2
- package/dist/assets/{html2canvas-BAfZNSwU.js.map → html2canvas-EikzC5d8.js.map} +1 -1
- package/dist/assets/main-CRdq5ifQ.js +3 -0
- package/dist/assets/{main-vwJkNw4Y.js.map → main-CRdq5ifQ.js.map} +1 -1
- package/dist/assets/main-DTR2QDcF.js +108 -0
- package/dist/assets/main-DTR2QDcF.js.map +1 -0
- package/dist/assets/{pdf-Bxz9Nzto.js → pdf-CMz6puSt.js} +1 -1
- package/dist/assets/{pdf-Bxz9Nzto.js.map → pdf-CMz6puSt.js.map} +1 -1
- package/dist/assets/{setup-B4gZX38p.js → setup-Bw8T9Qq6.js} +2 -2
- package/dist/assets/{setup-B4gZX38p.js.map → setup-Bw8T9Qq6.js.map} +1 -1
- package/dist/assets/src-A5KHvitf.js +2 -0
- package/dist/assets/{src-CROvYSP8.js.map → src-A5KHvitf.js.map} +1 -1
- package/dist/assets/{src-DAB0dqGG.js → src-BHsN2u2P.js} +2 -2
- package/dist/assets/{src-DAB0dqGG.js.map → src-BHsN2u2P.js.map} +1 -1
- package/dist/assets/src-BLUMUwZR.js +1 -0
- package/dist/assets/src-BXXcWcHh.js +1 -0
- package/dist/assets/src-BxSOopk7.js +1 -0
- package/dist/assets/{src-WDu491CE.js → src-BxaX1gGg.js} +2 -2
- package/dist/assets/{src-WDu491CE.js.map → src-BxaX1gGg.js.map} +1 -1
- package/dist/assets/{src-BtVLiVYZ.js → src-CCAyzQUp.js} +3 -3
- package/dist/assets/{src-BtVLiVYZ.js.map → src-CCAyzQUp.js.map} +1 -1
- package/dist/assets/src-CWJcD3kA.js +1 -0
- package/dist/assets/{src-Cx3tXAAu.js → src-CZ1k5h23.js} +3 -3
- package/dist/assets/{src-Cx3tXAAu.js.map → src-CZ1k5h23.js.map} +1 -1
- package/dist/assets/src-ClrziKzV.js +16 -0
- package/dist/assets/src-ClrziKzV.js.map +1 -0
- package/dist/assets/{src-C_Lx4lXp.js → src-CtjjclS4.js} +2 -2
- package/dist/assets/{src-C_Lx4lXp.js.map → src-CtjjclS4.js.map} +1 -1
- package/dist/assets/src-CuVaZcMo.js +2 -0
- package/dist/assets/{src-B_BNICay.js.map → src-CuVaZcMo.js.map} +1 -1
- package/dist/assets/src-Cy5OUviT.js +1 -0
- package/dist/assets/src-DK5BYonP.js +630 -0
- package/dist/assets/src-DK5BYonP.js.map +1 -0
- package/dist/assets/src-Dk-W3N33.js +1 -0
- package/dist/assets/{src-cUopH0nN.js → src-xPTO7Ts6.js} +3 -3
- package/dist/assets/{src-cUopH0nN.js.map → src-xPTO7Ts6.js.map} +1 -1
- package/dist/assets/sync-manager-zf1tikPt.js +2 -0
- package/dist/assets/sync-manager-zf1tikPt.js.map +1 -0
- package/dist/index.html +1 -1
- package/dist/setup.html +3 -4
- package/dist/sw-pwa.js +2 -2
- package/dist/sw-pwa.js.map +1 -1
- package/package.json +15 -13
- package/dist/assets/chunk-7ZXdHUL4.js +0 -1
- package/dist/assets/main-oacre7st.js +0 -108
- package/dist/assets/main-oacre7st.js.map +0 -1
- package/dist/assets/main-vwJkNw4Y.js +0 -3
- package/dist/assets/src-B_BNICay.js +0 -2
- package/dist/assets/src-Bjt9ooXK.js +0 -16
- package/dist/assets/src-Bjt9ooXK.js.map +0 -1
- package/dist/assets/src-CKpVxGpH.js +0 -629
- package/dist/assets/src-CKpVxGpH.js.map +0 -1
- package/dist/assets/src-CROvYSP8.js +0 -2
- package/dist/assets/sync-manager-8Z-qwkod.js +0 -2
- 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
|