@xiboplayer/pwa 0.3.2 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +10 -3
  2. package/package.json +10 -10
  3. package/dist/assets/cache-proxy-CrlayfSe.js +0 -2
  4. package/dist/assets/cache-proxy-CrlayfSe.js.map +0 -1
  5. package/dist/assets/cms-api-Ce7EVg5h.js +0 -2
  6. package/dist/assets/cms-api-Ce7EVg5h.js.map +0 -1
  7. package/dist/assets/html2canvas.esm-CBrSDip1.js +0 -23
  8. package/dist/assets/html2canvas.esm-CBrSDip1.js.map +0 -1
  9. package/dist/assets/index-BF8qB-pu.js +0 -2
  10. package/dist/assets/index-BF8qB-pu.js.map +0 -1
  11. package/dist/assets/index-Baows0WY.js +0 -2
  12. package/dist/assets/index-Baows0WY.js.map +0 -1
  13. package/dist/assets/index-Be_IxwIZ.js +0 -2
  14. package/dist/assets/index-Be_IxwIZ.js.map +0 -1
  15. package/dist/assets/index-BhHwWvzx.js +0 -2
  16. package/dist/assets/index-BhHwWvzx.js.map +0 -1
  17. package/dist/assets/index-C77HSi9N.js +0 -8
  18. package/dist/assets/index-C77HSi9N.js.map +0 -1
  19. package/dist/assets/index-ChPoQ8Bt.js +0 -607
  20. package/dist/assets/index-ChPoQ8Bt.js.map +0 -1
  21. package/dist/assets/index-DPR3fBRV.js +0 -2
  22. package/dist/assets/index-DPR3fBRV.js.map +0 -1
  23. package/dist/assets/index-b1tfCACR.js +0 -2
  24. package/dist/assets/index-b1tfCACR.js.map +0 -1
  25. package/dist/assets/index-es8y3c70.js +0 -2
  26. package/dist/assets/index-es8y3c70.js.map +0 -1
  27. package/dist/assets/main-BUvkpHsV.js +0 -44
  28. package/dist/assets/main-BUvkpHsV.js.map +0 -1
  29. package/dist/assets/modulepreload-polyfill-B5Qt9EMX.js +0 -2
  30. package/dist/assets/modulepreload-polyfill-B5Qt9EMX.js.map +0 -1
  31. package/dist/assets/pdf-BnPRJEQ6.js +0 -13
  32. package/dist/assets/pdf-BnPRJEQ6.js.map +0 -1
  33. package/dist/assets/setup-B9GCkQRS.js +0 -2
  34. package/dist/assets/setup-B9GCkQRS.js.map +0 -1
  35. package/dist/assets/xmds-client-MaDHqpeL.js +0 -16
  36. package/dist/assets/xmds-client-MaDHqpeL.js.map +0 -1
  37. package/dist/index.html +0 -130
  38. package/dist/setup.html +0 -371
  39. package/dist/sw-pwa.js +0 -2
  40. package/dist/sw-pwa.js.map +0 -1
  41. package/dist/sw.test.js +0 -271
@@ -1,2 +0,0 @@
1
- import"./modulepreload-polyfill-B5Qt9EMX.js";import{b as t,C}from"./cms-api-Ce7EVg5h.js";import{R as b,X as B}from"./xmds-client-MaDHqpeL.js";const S=document.getElementById("setup-form"),u=document.getElementById("error"),c=document.getElementById("submit-btn"),h=document.getElementById("phase-setup"),w=document.getElementById("phase-waiting"),f=document.getElementById("countdown"),k=document.getElementById("waiting-display-name"),A=document.getElementById("btn-back"),x=document.getElementById("success-flash"),p=t.hardwareKey;document.getElementById("hw-key-display").textContent=p;document.getElementById("hw-key-waiting").textContent=p;let d=null,l=null,I=15,i=null;async function g(){if(i)return i;try{const e=new b(t);await e.registerDisplay(),console.log("[Setup] Using REST transport"),i=e}catch(e){console.log("[Setup] REST unavailable, using XMDS/SOAP:",e.message),i=new B(t)}return i}function E(e){h.classList.remove("active"),w.classList.remove("active"),e.classList.add("active")}function D(e){u.textContent=e,u.style.display="block"}function K(){u.style.display="none"}function m(){let e=I;f.textContent=e,clearInterval(l),l=setInterval(()=>{e--,f.textContent=Math.max(0,e),e<=0&&clearInterval(l)},1e3)}function y(){x.classList.add("active"),setTimeout(()=>{window.location.href="./index.html"},800)}async function P(){try{const n=await(await g()).registerDisplay();if(console.log("[Setup] Poll result:",n.code,n.message),n.code==="READY"){clearInterval(d),clearInterval(l),y();return}m()}catch(e){console.warn("[Setup] Poll failed:",e.message),m()}}function v(e){k.textContent=e,E(w),m(),d=setInterval(P,I*1e3)}function R(){clearInterval(d),clearInterval(l),d=null}async function z(e,n){const a=document.getElementById("api-client-id").value.trim(),o=document.getElementById("api-client-secret").value.trim();if(!a||!o)return!1;try{const s=new C({baseUrl:e,clientId:a,clientSecret:o});await s.authenticate();const r=await s.findDisplay(n);return r?r.licensed===1?(console.log("[Setup] Display already authorized"),!0):(await s.authorizeDisplay(r.displayId),console.log("[Setup] Display auto-authorized via API!"),t.apiClientId=a,t.apiClientSecret=o,!0):(console.log("[Setup] Display not found via API (may not be registered yet)"),!1)}catch(s){return console.warn("[Setup] Auto-authorize failed:",s.message),!1}}t.isConfigured()&&(document.getElementById("cms-address").value=t.cmsAddress,document.getElementById("cms-key").value=t.cmsKey,document.getElementById("display-name").value=t.displayName);t.apiClientId&&(document.getElementById("api-client-id").value=t.apiClientId,document.getElementById("api-client-secret").value=t.apiClientSecret||"");S.addEventListener("submit",async e=>{e.preventDefault(),K();const n=document.getElementById("cms-address").value.trim().replace(/\/$/,""),a=document.getElementById("cms-key").value.trim(),o=document.getElementById("display-name").value.trim();t.cmsAddress=n,t.cmsKey=a,t.displayName=o,L(t.hardwareKey);try{c.textContent="Connecting...",c.disabled=!0,i=null;const s=await g();if((await s.registerDisplay()).code==="READY")y();else{if(c.textContent="Authorizing...",await z(n,p)&&(await s.registerDisplay()).code==="READY"){y();return}v(o)}}catch(s){D(`Connection failed: ${s.message}`),c.textContent="Connect",c.disabled=!1}});A.addEventListener("click",()=>{R(),E(h),c.textContent="Connect",c.disabled=!1});async function L(e){try{const n=indexedDB.open("xibo-hw-backup",1);n.onupgradeneeded=()=>{const a=n.result;a.objectStoreNames.contains("keys")||a.createObjectStore("keys")},n.onsuccess=()=>{const a=n.result,o=a.transaction("keys","readwrite");o.objectStore("keys").put(e,"hardwareKey"),o.oncomplete=()=>a.close()}}catch(n){console.warn("[Setup] IndexedDB backup failed:",n)}}c.disabled=!1;c.textContent="Connect";t.isConfigured()&&(async()=>{try{(await(await g()).registerDisplay()).code==="READY"?window.location.href="./index.html":v(t.displayName)}catch{console.log("[Setup] Auto-check failed, showing form")}})();
2
- //# sourceMappingURL=setup-B9GCkQRS.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"setup-B9GCkQRS.js","sources":["../../setup.html?html-proxy&index=1.js"],"sourcesContent":["\n import { config, CmsApiClient } from '@xiboplayer/utils';\n import { RestClient, XmdsClient } from '@xiboplayer/xmds';\n\n // ── Elements ──\n const form = document.getElementById('setup-form');\n const errorEl = document.getElementById('error');\n const submitBtn = document.getElementById('submit-btn');\n const phaseSetup = document.getElementById('phase-setup');\n const phaseWaiting = document.getElementById('phase-waiting');\n const countdownEl = document.getElementById('countdown');\n const waitingNameEl = document.getElementById('waiting-display-name');\n const btnBack = document.getElementById('btn-back');\n const successFlash = document.getElementById('success-flash');\n\n // Show hardware key\n const hwKey = config.hardwareKey;\n document.getElementById('hw-key-display').textContent = hwKey;\n document.getElementById('hw-key-waiting').textContent = hwKey;\n\n // ── State ──\n let pollTimer = null;\n let countdownTimer = null;\n let pollSeconds = 15;\n\n // ── Transport: try REST first, fall back to SOAP ──\n let transport = null;\n async function getTransport() {\n if (transport) return transport;\n try {\n const rest = new RestClient(config);\n await rest.registerDisplay();\n console.log('[Setup] Using REST transport');\n transport = rest;\n } catch (e) {\n console.log('[Setup] REST unavailable, using XMDS/SOAP:', e.message);\n transport = new XmdsClient(config);\n }\n return transport;\n }\n\n // ── Helpers ──\n function showPhase(phase) {\n phaseSetup.classList.remove('active');\n phaseWaiting.classList.remove('active');\n phase.classList.add('active');\n }\n\n function showError(msg) {\n errorEl.textContent = msg;\n errorEl.style.display = 'block';\n }\n\n function hideError() {\n errorEl.style.display = 'none';\n }\n\n function startCountdown() {\n let remaining = pollSeconds;\n countdownEl.textContent = remaining;\n clearInterval(countdownTimer);\n countdownTimer = setInterval(() => {\n remaining--;\n countdownEl.textContent = Math.max(0, remaining);\n if (remaining <= 0) clearInterval(countdownTimer);\n }, 1000);\n }\n\n function showSuccess() {\n successFlash.classList.add('active');\n setTimeout(() => {\n window.location.href = './index.html';\n }, 800);\n }\n\n // ── Authorization Polling ──\n async function checkAuthorization() {\n try {\n const client = await getTransport();\n const result = await client.registerDisplay();\n console.log('[Setup] Poll result:', result.code, result.message);\n\n if (result.code === 'READY') {\n // Authorized!\n clearInterval(pollTimer);\n clearInterval(countdownTimer);\n showSuccess();\n return;\n }\n\n // Still waiting — restart countdown\n startCountdown();\n } catch (error) {\n console.warn('[Setup] Poll failed:', error.message);\n startCountdown();\n }\n }\n\n function startPolling(displayName) {\n waitingNameEl.textContent = displayName;\n showPhase(phaseWaiting);\n startCountdown();\n pollTimer = setInterval(checkAuthorization, pollSeconds * 1000);\n }\n\n function stopPolling() {\n clearInterval(pollTimer);\n clearInterval(countdownTimer);\n pollTimer = null;\n }\n\n // ── Auto-authorize via CMS API ──\n async function tryAutoAuthorize(cmsAddress, hardwareKey) {\n const clientId = document.getElementById('api-client-id').value.trim();\n const clientSecret = document.getElementById('api-client-secret').value.trim();\n if (!clientId || !clientSecret) return false;\n\n try {\n const api = new CmsApiClient({ baseUrl: cmsAddress, clientId, clientSecret });\n await api.authenticate();\n\n const display = await api.findDisplay(hardwareKey);\n if (!display) {\n console.log('[Setup] Display not found via API (may not be registered yet)');\n return false;\n }\n\n if (display.licensed === 1) {\n console.log('[Setup] Display already authorized');\n return true;\n }\n\n // Auto-authorize\n await api.authorizeDisplay(display.displayId);\n console.log('[Setup] Display auto-authorized via API!');\n\n // Save API credentials for future use\n config.apiClientId = clientId;\n config.apiClientSecret = clientSecret;\n\n return true;\n } catch (error) {\n console.warn('[Setup] Auto-authorize failed:', error.message);\n return false;\n }\n }\n\n // ── Pre-fill if already configured ──\n if (config.isConfigured()) {\n document.getElementById('cms-address').value = config.cmsAddress;\n document.getElementById('cms-key').value = config.cmsKey;\n document.getElementById('display-name').value = config.displayName;\n }\n // Pre-fill API credentials if saved\n if (config.apiClientId) {\n document.getElementById('api-client-id').value = config.apiClientId;\n document.getElementById('api-client-secret').value = config.apiClientSecret || '';\n }\n\n // ── Form Submit ──\n form.addEventListener('submit', async (e) => {\n e.preventDefault();\n hideError();\n\n const cmsAddress = document.getElementById('cms-address').value.trim().replace(/\\/$/, '');\n const cmsKey = document.getElementById('cms-key').value.trim();\n const displayName = document.getElementById('display-name').value.trim();\n\n // Save config\n config.cmsAddress = cmsAddress;\n config.cmsKey = cmsKey;\n config.displayName = displayName;\n\n // Also backup hardware key to IndexedDB for stability\n backupHardwareKey(config.hardwareKey);\n\n // Test connection\n try {\n submitBtn.textContent = 'Connecting...';\n submitBtn.disabled = true;\n\n // Try REST first, fall back to SOAP\n transport = null; // reset transport for fresh detection\n const client = await getTransport();\n const result = await client.registerDisplay();\n\n if (result.code === 'READY') {\n showSuccess();\n } else {\n // Try auto-authorize via CMS API if credentials provided\n submitBtn.textContent = 'Authorizing...';\n const autoAuthed = await tryAutoAuthorize(cmsAddress, hwKey);\n\n if (autoAuthed) {\n // Verify registration\n const recheck = await client.registerDisplay();\n if (recheck.code === 'READY') {\n showSuccess();\n return;\n }\n }\n\n // Not authorized yet — switch to polling phase\n startPolling(displayName);\n }\n } catch (error) {\n showError(`Connection failed: ${error.message}`);\n submitBtn.textContent = 'Connect';\n submitBtn.disabled = false;\n }\n });\n\n // ── Back button ──\n btnBack.addEventListener('click', () => {\n stopPolling();\n showPhase(phaseSetup);\n submitBtn.textContent = 'Connect';\n submitBtn.disabled = false;\n });\n\n // ── IndexedDB hardware key backup ──\n async function backupHardwareKey(key) {\n try {\n const req = indexedDB.open('xibo-hw-backup', 1);\n req.onupgradeneeded = () => {\n const db = req.result;\n if (!db.objectStoreNames.contains('keys')) {\n db.createObjectStore('keys');\n }\n };\n req.onsuccess = () => {\n const db = req.result;\n const tx = db.transaction('keys', 'readwrite');\n tx.objectStore('keys').put(key, 'hardwareKey');\n tx.oncomplete = () => db.close();\n };\n } catch (e) {\n console.warn('[Setup] IndexedDB backup failed:', e);\n }\n }\n\n // ── Enable submit ──\n submitBtn.disabled = false;\n submitBtn.textContent = 'Connect';\n\n // ── Auto-resume polling if already registered but not authorized ──\n if (config.isConfigured()) {\n (async () => {\n try {\n const client = await getTransport();\n const result = await client.registerDisplay();\n if (result.code === 'READY') {\n window.location.href = './index.html';\n } else {\n // Not authorized — go straight to polling\n startPolling(config.displayName);\n }\n } catch (e) {\n // Connection failed, show form\n console.log('[Setup] Auto-check failed, showing form');\n }\n })();\n }\n "],"names":["form","errorEl","submitBtn","phaseSetup","phaseWaiting","countdownEl","waitingNameEl","btnBack","successFlash","hwKey","config","pollTimer","countdownTimer","pollSeconds","transport","getTransport","rest","RestClient","XmdsClient","showPhase","phase","showError","msg","hideError","startCountdown","remaining","showSuccess","checkAuthorization","result","error","startPolling","displayName","stopPolling","tryAutoAuthorize","cmsAddress","hardwareKey","clientId","clientSecret","api","CmsApiClient","display","cmsKey","backupHardwareKey","client","key","req","db","tx","e"],"mappings":"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"}
@@ -1,16 +0,0 @@
1
- import{f as m,c as f}from"./cms-api-Ce7EVg5h.js";function p(y){const t=[];for(const e of y.querySelectorAll(":scope > criteria"))t.push({metric:e.getAttribute("metric")||"",condition:e.getAttribute("condition")||"",type:e.getAttribute("type")||"string",value:e.textContent||""});return t}function A(y){const e=new DOMParser().parseFromString(y,"text/xml"),s={default:null,layouts:[],campaigns:[],overlays:[],actions:[],commands:[],dataConnectors:[]},a=e.querySelector("default");a&&(s.default=a.getAttribute("file"));for(const r of e.querySelectorAll("campaign")){const o={id:r.getAttribute("id"),priority:parseInt(r.getAttribute("priority")||"0"),fromdt:r.getAttribute("fromdt"),todt:r.getAttribute("todt"),scheduleid:r.getAttribute("scheduleid"),layouts:[]};for(const l of r.querySelectorAll("layout")){const c=l.getAttribute("file");o.layouts.push({id:String(c),file:c,fromdt:l.getAttribute("fromdt")||o.fromdt,todt:l.getAttribute("todt")||o.todt,scheduleid:o.scheduleid,priority:o.priority,campaignId:o.id,maxPlaysPerHour:parseInt(l.getAttribute("maxPlaysPerHour")||"0"),isGeoAware:l.getAttribute("isGeoAware")==="1",geoLocation:l.getAttribute("geoLocation")||"",syncEvent:l.getAttribute("syncEvent")==="1",shareOfVoice:parseInt(l.getAttribute("shareOfVoice")||"0"),criteria:p(l)})}s.campaigns.push(o)}for(const r of e.querySelectorAll("schedule > layout")){const o=r.getAttribute("file");s.layouts.push({id:String(o),file:o,fromdt:r.getAttribute("fromdt"),todt:r.getAttribute("todt"),scheduleid:r.getAttribute("scheduleid"),priority:parseInt(r.getAttribute("priority")||"0"),campaignId:null,maxPlaysPerHour:parseInt(r.getAttribute("maxPlaysPerHour")||"0"),isGeoAware:r.getAttribute("isGeoAware")==="1",geoLocation:r.getAttribute("geoLocation")||"",syncEvent:r.getAttribute("syncEvent")==="1",shareOfVoice:parseInt(r.getAttribute("shareOfVoice")||"0"),criteria:p(r)})}const i=e.querySelector("overlays");if(i)for(const r of i.querySelectorAll("overlay")){const o=r.getAttribute("file");s.overlays.push({id:String(o),duration:parseInt(r.getAttribute("duration")||"60"),file:o,fromDt:r.getAttribute("fromdt"),toDt:r.getAttribute("todt"),priority:parseInt(r.getAttribute("priority")||"0"),scheduleId:r.getAttribute("scheduleid"),isGeoAware:r.getAttribute("isGeoAware")==="1",geoLocation:r.getAttribute("geoLocation")||"",syncEvent:r.getAttribute("syncEvent")==="1",maxPlaysPerHour:parseInt(r.getAttribute("maxPlaysPerHour")||"0"),criteria:p(r)})}const n=e.querySelector("actions");if(n)for(const r of n.querySelectorAll("action"))s.actions.push({actionType:r.getAttribute("actionType")||"",triggerCode:r.getAttribute("triggerCode")||"",layoutCode:r.getAttribute("layoutCode")||"",commandCode:r.getAttribute("commandCode")||"",duration:parseInt(r.getAttribute("duration")||"0"),fromDt:r.getAttribute("fromdt"),toDt:r.getAttribute("todt"),priority:parseInt(r.getAttribute("priority")||"0"),scheduleId:r.getAttribute("scheduleid"),isGeoAware:r.getAttribute("isGeoAware")==="1",geoLocation:r.getAttribute("geoLocation")||""});for(const r of e.querySelectorAll("schedule > command"))s.commands.push({code:r.getAttribute("command")||"",date:r.getAttribute("date")||""});for(const r of e.querySelectorAll("dataconnector"))s.dataConnectors.push({id:r.getAttribute("id")||"",dataConnectorId:r.getAttribute("dataConnectorId")||"",dataKey:r.getAttribute("dataKey")||"",url:r.getAttribute("url")||"",updateInterval:parseInt(r.getAttribute("updateInterval")||"300",10)});return s}const d=f("REST");class w{constructor(t){this.config=t,this.schemaVersion=7,this.retryOptions=t.retryOptions||{maxRetries:2,baseDelayMs:2e3},this._etags=new Map,this._responseCache=new Map,d.info("Using REST transport")}getRestBaseUrl(){return(this.config.restApiUrl||`${this.config.cmsAddress}/pwa`).replace(/\/+$/,"")}async restGet(t,e={}){const s=new URL(`${this.getRestBaseUrl()}${t}`);s.searchParams.set("serverKey",this.config.cmsKey),s.searchParams.set("hardwareKey",this.config.hardwareKey),s.searchParams.set("v",String(this.schemaVersion));for(const[u,h]of Object.entries(e))s.searchParams.set(u,String(h));const a=t,i={},n=this._etags.get(a);n&&(i["If-None-Match"]=n),d.debug(`GET ${t}`,e);const r=await m(s.toString(),{method:"GET",headers:i},this.retryOptions);if(r.status===304){const u=this._responseCache.get(a);if(u)return d.debug(`${t} → 304 (using cache)`),u}if(!r.ok){const u=await r.text().catch(()=>"");throw new Error(`REST GET ${t} failed: ${r.status} ${r.statusText} ${u}`)}const o=r.headers.get("ETag");o&&this._etags.set(a,o);const l=r.headers.get("Content-Type")||"";let c;return l.includes("application/json")?c=await r.json():c=await r.text(),this._responseCache.set(a,c),c}async restSend(t,e,s={}){const a=new URL(`${this.getRestBaseUrl()}${e}`);a.searchParams.set("v",String(this.schemaVersion)),d.debug(`${t} ${e}`);const i=await m(a.toString(),{method:t,headers:{"Content-Type":"application/json"},body:JSON.stringify({serverKey:this.config.cmsKey,hardwareKey:this.config.hardwareKey,...s})},this.retryOptions);if(!i.ok){const r=await i.text().catch(()=>"");throw new Error(`REST ${t} ${e} failed: ${i.status} ${i.statusText} ${r}`)}return(i.headers.get("Content-Type")||"").includes("application/json")?await i.json():await i.text()}async registerDisplay(){const t=typeof navigator<"u"?`${navigator.platform} ${navigator.userAgent}`:"unknown",e=await this.restSend("POST","/register",{displayName:this.config.displayName,clientType:"chromeOS",clientVersion:"0.1.0",clientCode:1,operatingSystem:t,macAddress:this.config.macAddress||"n/a",xmrChannel:this.config.xmrChannel,xmrPubKey:""});return this._parseRegisterDisplayJson(e)}_parseRegisterDisplayJson(t){const e=t.display||t,s=e["@attributes"]||{},a=s.code||e.code,i=s.message||e.message||"";if(a!=="READY")return{code:a,message:i,settings:null};const n={};for(const[c,u]of Object.entries(e))c==="@attributes"||c==="commands"||c==="file"||(n[c]=typeof u=="object"?JSON.stringify(u):String(u));const r=s.checkRf||"",o=s.checkSchedule||"",l=e.syncGroup?{syncGroup:String(e.syncGroup),syncPublisherPort:parseInt(e.syncPublisherPort||"9590",10),syncSwitchDelay:parseInt(e.syncSwitchDelay||"750",10),syncVideoPauseDelay:parseInt(e.syncVideoPauseDelay||"100",10),isLead:String(e.syncGroup)==="lead"}:null;return{code:a,message:i,settings:n,checkRf:r,checkSchedule:o,syncConfig:l}}async requiredFiles(){const t=await this.restGet("/requiredFiles");return this._parseRequiredFilesJson(t)}_parseRequiredFilesJson(t){const e=[];let s=t.file||[];Array.isArray(s)||(s=[s]);for(const a of s){const i=a["@attributes"]||a,n=i.path||null;e.push({type:i.type||null,id:i.id||null,size:parseInt(i.size||"0"),md5:i.md5||null,download:i.download||null,path:n,code:i.code||null,layoutid:i.layoutid||null,regionid:i.regionid||null,mediaid:i.mediaid||null})}return e}async schedule(){const t=await this.restGet("/schedule");return A(t)}async getResource(t,e,s){return this.restGet("/getResource",{layoutId:String(t),regionId:String(e),mediaId:String(s)})}async notifyStatus(t){var e;if(typeof navigator<"u"&&((e=navigator.storage)!=null&&e.estimate))try{const s=await navigator.storage.estimate();t.availableSpace=s.quota-s.usage,t.totalSpace=s.quota}catch{}return!t.timeZone&&typeof Intl<"u"&&(t.timeZone=Intl.DateTimeFormat().resolvedOptions().timeZone),this.restSend("PUT","/status",{statusData:t})}async mediaInventory(t){const e=Array.isArray(t)?{inventoryItems:t}:{inventory:t};return this.restSend("POST","/mediaInventory",e)}async blackList(t,e,s){return d.warn(`BlackList not available via REST (${e}/${t}: ${s})`),!1}async submitLog(t){const e=Array.isArray(t)?{logs:t}:{logXml:t},s=await this.restSend("POST","/log",e);return(s==null?void 0:s.success)===!0}async submitScreenShot(t){const e=await this.restSend("POST","/screenshot",{screenshot:t});return(e==null?void 0:e.success)===!0}async submitStats(t){try{const e=Array.isArray(t)?{stats:t}:{statXml:t},s=await this.restSend("POST","/stats",e),a=(s==null?void 0:s.success)===!0;return d.info(`SubmitStats result: ${a}`),a}catch(e){throw d.error("SubmitStats failed:",e),e}}}const g=f("XMDS");class S{constructor(t){this.config=t,this.schemaVersion=5,this.retryOptions=t.retryOptions||{maxRetries:2,baseDelayMs:2e3}}buildEnvelope(t,e){const s=Object.entries(e).map(([a,i])=>{const n=String(i).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;");return`<${a} xsi:type="xsd:string">${n}</${a}>`}).join(`
2
- `);return`<?xml version="1.0" encoding="UTF-8"?>
3
- <soap:Envelope
4
- xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
5
- xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
6
- xmlns:tns="urn:xmds"
7
- xmlns:types="urn:xmds/encodedTypes"
8
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
9
- xmlns:xsd="http://www.w3.org/2001/XMLSchema">
10
- <soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
11
- <tns:${t}>
12
- ${s}
13
- </tns:${t}>
14
- </soap:Body>
15
- </soap:Envelope>`}rewriteXmdsUrl(t){var e;return typeof window<"u"&&((e=window.electronAPI)!=null&&e.isElectron||window.location.hostname==="localhost"&&window.location.port==="8765")?`/xmds-proxy?cms=${encodeURIComponent(t)}`:`${t}/xmds.php`}async call(t,e={}){const s=this.rewriteXmdsUrl(this.config.cmsAddress),a=`${s}${s.includes("?")?"&":"?"}v=${this.schemaVersion}`,i=this.buildEnvelope(t,e);g.debug(`${t}`,e),g.debug(`URL: ${a}`);const n=await m(a,{method:"POST",headers:{"Content-Type":"text/xml; charset=utf-8"},body:i},this.retryOptions);if(!n.ok)throw new Error(`XMDS ${t} failed: ${n.status} ${n.statusText}`);const r=await n.text();return this.parseResponse(r,t)}parseResponse(t,e){var l,c;const a=new DOMParser().parseFromString(t,"text/xml");let i=a.querySelector("Fault");if(i||(i=Array.from(a.querySelectorAll("*")).find(u=>u.localName==="Fault"||u.tagName.endsWith(":Fault"))),i){const u=((l=i.querySelector("faultstring"))==null?void 0:l.textContent)||((c=Array.from(i.querySelectorAll("*")).find(h=>h.localName==="faultstring"))==null?void 0:c.textContent)||"Unknown SOAP fault";throw new Error(`SOAP Fault: ${u}`)}const n=`${e}Response`;let r=a.querySelector(n);if(r||(r=Array.from(a.querySelectorAll("*")).find(u=>u.localName===n||u.tagName.endsWith(":"+n))),!r)throw new Error(`No ${n} element in SOAP response`);const o=r.firstElementChild;return o?o.textContent:null}async registerDisplay(){const t=`${navigator.platform} ${navigator.userAgent}`,e=await this.call("RegisterDisplay",{serverKey:this.config.cmsKey,hardwareKey:this.config.hardwareKey,displayName:this.config.displayName,clientType:"chromeOS",clientVersion:"0.1.0",clientCode:"1",operatingSystem:t,macAddress:this.config.macAddress||"n/a",xmrChannel:this.config.xmrChannel,xmrPubKey:""});return this.parseRegisterDisplayResponse(e)}parseRegisterDisplayResponse(t){const a=new DOMParser().parseFromString(t,"text/xml").querySelector("display");if(!a)throw new Error("Invalid RegisterDisplay response: no <display> element");const i=a.getAttribute("code"),n=a.getAttribute("message");if(i!=="READY")return{code:i,message:n,settings:null};const r={};for(const c of a.children)["commands","file"].includes(c.tagName.toLowerCase())||(r[c.tagName]=c.textContent);const o=a.getAttribute("checkRf")||"",l=a.getAttribute("checkSchedule")||"";return{code:i,message:n,settings:r,checkRf:o,checkSchedule:l}}async requiredFiles(){const t=await this.call("RequiredFiles",{serverKey:this.config.cmsKey,hardwareKey:this.config.hardwareKey});return this.parseRequiredFilesResponse(t)}parseRequiredFilesResponse(t){const s=new DOMParser().parseFromString(t,"text/xml"),a=[];for(const i of s.querySelectorAll("file"))a.push({type:i.getAttribute("type"),id:i.getAttribute("id"),size:parseInt(i.getAttribute("size")||"0"),md5:i.getAttribute("md5"),download:i.getAttribute("download"),path:i.getAttribute("path"),code:i.getAttribute("code"),layoutid:i.getAttribute("layoutid"),regionid:i.getAttribute("regionid"),mediaid:i.getAttribute("mediaid")});return a}async schedule(){const t=await this.call("Schedule",{serverKey:this.config.cmsKey,hardwareKey:this.config.hardwareKey});return A(t)}async getResource(t,e,s){return await this.call("GetResource",{serverKey:this.config.cmsKey,hardwareKey:this.config.hardwareKey,layoutId:String(t),regionId:String(e),mediaId:String(s)})}async notifyStatus(t){var e;if(typeof navigator<"u"&&((e=navigator.storage)!=null&&e.estimate))try{const s=await navigator.storage.estimate();t.availableSpace=s.quota-s.usage,t.totalSpace=s.quota}catch{}return!t.timeZone&&typeof Intl<"u"&&(t.timeZone=Intl.DateTimeFormat().resolvedOptions().timeZone),await this.call("NotifyStatus",{serverKey:this.config.cmsKey,hardwareKey:this.config.hardwareKey,status:JSON.stringify(t)})}async mediaInventory(t){return await this.call("MediaInventory",{serverKey:this.config.cmsKey,hardwareKey:this.config.hardwareKey,mediaInventory:t})}async blackList(t,e,s){try{const a=await this.call("BlackList",{serverKey:this.config.cmsKey,hardwareKey:this.config.hardwareKey,mediaId:String(t),type:e||"media",reason:s||"Failed to render"});return g.info(`BlackListed ${e}/${t}: ${s}`),a==="true"}catch(a){return g.warn("BlackList failed:",a),!1}}async submitLog(t){return await this.call("SubmitLog",{serverKey:this.config.cmsKey,hardwareKey:this.config.hardwareKey,logXml:t})==="true"}async submitScreenShot(t){return await this.call("SubmitScreenShot",{serverKey:this.config.cmsKey,hardwareKey:this.config.hardwareKey,screenShot:t})==="true"}async submitStats(t){try{const s=await this.call("SubmitStats",{serverKey:this.config.cmsKey,hardwareKey:this.config.hardwareKey,statXml:t})==="true";return g.info(`SubmitStats result: ${s}`),s}catch(e){throw g.error("SubmitStats failed:",e),e}}}export{w as R,S as X,A as p};
16
- //# sourceMappingURL=xmds-client-MaDHqpeL.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"xmds-client-MaDHqpeL.js","sources":["../../../xiboplayer/packages/xmds/src/schedule-parser.js","../../../xiboplayer/packages/xmds/src/rest-client.js","../../../xiboplayer/packages/xmds/src/xmds-client.js"],"sourcesContent":["/**\n * Shared schedule XML parser used by both RestClient and XmdsClient.\n *\n * Both transports return the same XML structure for the Schedule endpoint,\n * so the parsing logic lives here to avoid duplication.\n */\n\n/**\n * Parse criteria child elements from a layout/overlay element.\n * Criteria are conditions that must be met for the item to display.\n *\n * XML format: <criteria metric=\"dayOfWeek\" condition=\"equals\" type=\"string\">Monday</criteria>\n *\n * @param {Element} parentEl - Parent XML element containing <criteria> children\n * @returns {Array<{metric: string, condition: string, type: string, value: string}>}\n */\nfunction parseCriteria(parentEl) {\n const criteria = [];\n for (const criteriaEl of parentEl.querySelectorAll(':scope > criteria')) {\n criteria.push({\n metric: criteriaEl.getAttribute('metric') || '',\n condition: criteriaEl.getAttribute('condition') || '',\n type: criteriaEl.getAttribute('type') || 'string',\n value: criteriaEl.textContent || ''\n });\n }\n return criteria;\n}\n\n/**\n * Parse Schedule XML response into a normalized schedule object.\n *\n * @param {string} xml - Raw XML string from CMS schedule endpoint\n * @returns {Object} Parsed schedule with default, layouts, campaigns, overlays, actions, commands, dataConnectors\n */\nexport function parseScheduleResponse(xml) {\n const parser = new DOMParser();\n const doc = parser.parseFromString(xml, 'text/xml');\n\n const schedule = {\n default: null,\n layouts: [],\n campaigns: [],\n overlays: [],\n actions: [],\n commands: [],\n dataConnectors: []\n };\n\n const defaultEl = doc.querySelector('default');\n if (defaultEl) {\n schedule.default = defaultEl.getAttribute('file');\n }\n\n // Parse campaigns (groups of layouts with shared priority)\n for (const campaignEl of doc.querySelectorAll('campaign')) {\n const campaign = {\n id: campaignEl.getAttribute('id'),\n priority: parseInt(campaignEl.getAttribute('priority') || '0'),\n fromdt: campaignEl.getAttribute('fromdt'),\n todt: campaignEl.getAttribute('todt'),\n scheduleid: campaignEl.getAttribute('scheduleid'),\n layouts: []\n };\n\n // Parse layouts within this campaign\n for (const layoutEl of campaignEl.querySelectorAll('layout')) {\n const fileId = layoutEl.getAttribute('file');\n campaign.layouts.push({\n id: String(fileId), // Normalized string ID for consistent type usage\n file: fileId,\n // Layouts in campaigns inherit timing from campaign level\n fromdt: layoutEl.getAttribute('fromdt') || campaign.fromdt,\n todt: layoutEl.getAttribute('todt') || campaign.todt,\n scheduleid: campaign.scheduleid,\n priority: campaign.priority, // Priority at campaign level\n campaignId: campaign.id,\n maxPlaysPerHour: parseInt(layoutEl.getAttribute('maxPlaysPerHour') || '0'),\n isGeoAware: layoutEl.getAttribute('isGeoAware') === '1',\n geoLocation: layoutEl.getAttribute('geoLocation') || '',\n syncEvent: layoutEl.getAttribute('syncEvent') === '1',\n shareOfVoice: parseInt(layoutEl.getAttribute('shareOfVoice') || '0'),\n criteria: parseCriteria(layoutEl)\n });\n }\n\n schedule.campaigns.push(campaign);\n }\n\n // Parse standalone layouts (not in campaigns)\n for (const layoutEl of doc.querySelectorAll('schedule > layout')) {\n const fileId = layoutEl.getAttribute('file');\n schedule.layouts.push({\n id: String(fileId), // Normalized string ID for consistent type usage\n file: fileId,\n fromdt: layoutEl.getAttribute('fromdt'),\n todt: layoutEl.getAttribute('todt'),\n scheduleid: layoutEl.getAttribute('scheduleid'),\n priority: parseInt(layoutEl.getAttribute('priority') || '0'),\n campaignId: null, // Standalone layout\n maxPlaysPerHour: parseInt(layoutEl.getAttribute('maxPlaysPerHour') || '0'),\n isGeoAware: layoutEl.getAttribute('isGeoAware') === '1',\n geoLocation: layoutEl.getAttribute('geoLocation') || '',\n syncEvent: layoutEl.getAttribute('syncEvent') === '1',\n shareOfVoice: parseInt(layoutEl.getAttribute('shareOfVoice') || '0'),\n criteria: parseCriteria(layoutEl)\n });\n }\n\n // Parse overlay layouts (appear on top of main layouts)\n const overlaysContainer = doc.querySelector('overlays');\n if (overlaysContainer) {\n for (const overlayEl of overlaysContainer.querySelectorAll('overlay')) {\n const fileId = overlayEl.getAttribute('file');\n schedule.overlays.push({\n id: String(fileId), // Normalized string ID for consistent type usage\n duration: parseInt(overlayEl.getAttribute('duration') || '60'),\n file: fileId,\n fromDt: overlayEl.getAttribute('fromdt'),\n toDt: overlayEl.getAttribute('todt'),\n priority: parseInt(overlayEl.getAttribute('priority') || '0'),\n scheduleId: overlayEl.getAttribute('scheduleid'),\n isGeoAware: overlayEl.getAttribute('isGeoAware') === '1',\n geoLocation: overlayEl.getAttribute('geoLocation') || '',\n syncEvent: overlayEl.getAttribute('syncEvent') === '1',\n maxPlaysPerHour: parseInt(overlayEl.getAttribute('maxPlaysPerHour') || '0'),\n criteria: parseCriteria(overlayEl)\n });\n }\n }\n\n // Parse action events (scheduled triggers)\n const actionsContainer = doc.querySelector('actions');\n if (actionsContainer) {\n for (const actionEl of actionsContainer.querySelectorAll('action')) {\n schedule.actions.push({\n actionType: actionEl.getAttribute('actionType') || '',\n triggerCode: actionEl.getAttribute('triggerCode') || '',\n layoutCode: actionEl.getAttribute('layoutCode') || '',\n commandCode: actionEl.getAttribute('commandCode') || '',\n duration: parseInt(actionEl.getAttribute('duration') || '0'),\n fromDt: actionEl.getAttribute('fromdt'),\n toDt: actionEl.getAttribute('todt'),\n priority: parseInt(actionEl.getAttribute('priority') || '0'),\n scheduleId: actionEl.getAttribute('scheduleid'),\n isGeoAware: actionEl.getAttribute('isGeoAware') === '1',\n geoLocation: actionEl.getAttribute('geoLocation') || ''\n });\n }\n }\n\n // Parse server commands (remote control)\n for (const cmdEl of doc.querySelectorAll('schedule > command')) {\n schedule.commands.push({\n code: cmdEl.getAttribute('command') || '',\n date: cmdEl.getAttribute('date') || ''\n });\n }\n\n // Parse data connectors (real-time data sources for widgets)\n for (const dcEl of doc.querySelectorAll('dataconnector')) {\n schedule.dataConnectors.push({\n id: dcEl.getAttribute('id') || '',\n dataConnectorId: dcEl.getAttribute('dataConnectorId') || '',\n dataKey: dcEl.getAttribute('dataKey') || '',\n url: dcEl.getAttribute('url') || '',\n updateInterval: parseInt(dcEl.getAttribute('updateInterval') || '300', 10)\n });\n }\n\n return schedule;\n}\n","/**\n * REST transport client for Xibo CMS.\n *\n * Uses the /pwa REST API endpoints with JSON payloads and ETag caching.\n * Lighter than SOAP — ~30% smaller payloads, standard HTTP semantics.\n *\n * Protocol: https://github.com/linuxnow/xibo_players_docs\n */\nimport { createLogger, fetchWithRetry } from '@xiboplayer/utils';\nimport { parseScheduleResponse } from './schedule-parser.js';\n\nconst log = createLogger('REST');\n\nexport class RestClient {\n constructor(config) {\n this.config = config;\n this.schemaVersion = 7;\n this.retryOptions = config.retryOptions || { maxRetries: 2, baseDelayMs: 2000 };\n\n // ETag-based HTTP caching\n this._etags = new Map(); // endpoint → ETag string\n this._responseCache = new Map(); // endpoint → cached parsed response\n\n log.info('Using REST transport');\n }\n\n // ─── Transport helpers ──────────────────────────────────────────\n\n /**\n * Get the REST API base URL.\n * Falls back to /pwa path relative to the CMS address.\n */\n getRestBaseUrl() {\n const base = this.config.restApiUrl || `${this.config.cmsAddress}/pwa`;\n return base.replace(/\\/+$/, '');\n }\n\n /**\n * Make a REST GET request with optional ETag caching.\n * Returns the parsed JSON body, or cached data on 304.\n */\n async restGet(path, queryParams = {}) {\n const url = new URL(`${this.getRestBaseUrl()}${path}`);\n url.searchParams.set('serverKey', this.config.cmsKey);\n url.searchParams.set('hardwareKey', this.config.hardwareKey);\n url.searchParams.set('v', String(this.schemaVersion));\n for (const [key, value] of Object.entries(queryParams)) {\n url.searchParams.set(key, String(value));\n }\n\n const cacheKey = path;\n const headers = {};\n const cachedEtag = this._etags.get(cacheKey);\n if (cachedEtag) {\n headers['If-None-Match'] = cachedEtag;\n }\n\n log.debug(`GET ${path}`, queryParams);\n\n const response = await fetchWithRetry(url.toString(), {\n method: 'GET',\n headers,\n }, this.retryOptions);\n\n // 304 Not Modified — return cached response\n if (response.status === 304) {\n const cached = this._responseCache.get(cacheKey);\n if (cached) {\n log.debug(`${path} → 304 (using cache)`);\n return cached;\n }\n // Cache miss despite 304 — fall through to fetch fresh\n }\n\n if (!response.ok) {\n const errorBody = await response.text().catch(() => '');\n throw new Error(`REST GET ${path} failed: ${response.status} ${response.statusText} ${errorBody}`);\n }\n\n // Store ETag for future requests\n const etag = response.headers.get('ETag');\n if (etag) {\n this._etags.set(cacheKey, etag);\n }\n\n const contentType = response.headers.get('Content-Type') || '';\n let data;\n if (contentType.includes('application/json')) {\n data = await response.json();\n } else {\n // XML or HTML — return raw text\n data = await response.text();\n }\n\n // Cache parsed response for 304 reuse\n this._responseCache.set(cacheKey, data);\n return data;\n }\n\n /**\n * Make a REST POST/PUT request with JSON body.\n * Returns the parsed JSON response.\n */\n async restSend(method, path, body = {}) {\n const url = new URL(`${this.getRestBaseUrl()}${path}`);\n url.searchParams.set('v', String(this.schemaVersion));\n\n log.debug(`${method} ${path}`);\n\n const response = await fetchWithRetry(url.toString(), {\n method,\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n serverKey: this.config.cmsKey,\n hardwareKey: this.config.hardwareKey,\n ...body,\n }),\n }, this.retryOptions);\n\n if (!response.ok) {\n const errorBody = await response.text().catch(() => '');\n throw new Error(`REST ${method} ${path} failed: ${response.status} ${response.statusText} ${errorBody}`);\n }\n\n const contentType = response.headers.get('Content-Type') || '';\n if (contentType.includes('application/json')) {\n return await response.json();\n }\n return await response.text();\n }\n\n // ─── Public API ─────────────────────────────────────────────────\n\n /**\n * RegisterDisplay - authenticate and get settings\n * POST /register → JSON with display settings\n */\n async registerDisplay() {\n const os = typeof navigator !== 'undefined'\n ? `${navigator.platform} ${navigator.userAgent}`\n : 'unknown';\n\n const json = await this.restSend('POST', '/register', {\n displayName: this.config.displayName,\n clientType: 'chromeOS',\n clientVersion: '0.1.0',\n clientCode: 1,\n operatingSystem: os,\n macAddress: this.config.macAddress || 'n/a',\n xmrChannel: this.config.xmrChannel,\n xmrPubKey: '',\n });\n\n return this._parseRegisterDisplayJson(json);\n }\n\n /**\n * Parse REST JSON RegisterDisplay response into the same format as SOAP.\n */\n _parseRegisterDisplayJson(json) {\n // Handle both direct object and wrapped {display: ...} forms\n const display = json.display || json;\n const attrs = display['@attributes'] || {};\n const code = attrs.code || display.code;\n const message = attrs.message || display.message || '';\n\n if (code !== 'READY') {\n return { code, message, settings: null };\n }\n\n const settings = {};\n for (const [key, value] of Object.entries(display)) {\n if (key === '@attributes' || key === 'commands' || key === 'file') continue;\n settings[key] = typeof value === 'object' ? JSON.stringify(value) : String(value);\n }\n\n const checkRf = attrs.checkRf || '';\n const checkSchedule = attrs.checkSchedule || '';\n\n // Extract sync group config if present (multi-display sync coordination)\n // syncGroup: \"lead\" if this display is leader, or leader's LAN IP if follower\n const syncConfig = display.syncGroup ? {\n syncGroup: String(display.syncGroup),\n syncPublisherPort: parseInt(display.syncPublisherPort || '9590', 10),\n syncSwitchDelay: parseInt(display.syncSwitchDelay || '750', 10),\n syncVideoPauseDelay: parseInt(display.syncVideoPauseDelay || '100', 10),\n isLead: String(display.syncGroup) === 'lead',\n } : null;\n\n return { code, message, settings, checkRf, checkSchedule, syncConfig };\n }\n\n /**\n * RequiredFiles - get list of files to download\n * GET /requiredFiles → JSON file manifest (with ETag caching)\n */\n async requiredFiles() {\n const json = await this.restGet('/requiredFiles');\n return this._parseRequiredFilesJson(json);\n }\n\n /**\n * Parse REST JSON RequiredFiles into the same array format as SOAP.\n */\n _parseRequiredFilesJson(json) {\n const files = [];\n let fileList = json.file || [];\n\n // Normalize single item to array\n if (!Array.isArray(fileList)) {\n fileList = [fileList];\n }\n\n for (const f of fileList) {\n const attrs = f['@attributes'] || f;\n const path = attrs.path || null;\n files.push({\n type: attrs.type || null,\n id: attrs.id || null,\n size: parseInt(attrs.size || '0'),\n md5: attrs.md5 || null,\n download: attrs.download || null,\n path,\n code: attrs.code || null,\n layoutid: attrs.layoutid || null,\n regionid: attrs.regionid || null,\n mediaid: attrs.mediaid || null,\n });\n }\n\n return files;\n }\n\n /**\n * Schedule - get layout schedule\n * GET /schedule → XML (preserved for layout parser compatibility, with ETag caching)\n */\n async schedule() {\n const xml = await this.restGet('/schedule');\n return parseScheduleResponse(xml);\n }\n\n /**\n * GetResource - get rendered widget HTML\n * GET /getResource → HTML string\n */\n async getResource(layoutId, regionId, mediaId) {\n return this.restGet('/getResource', {\n layoutId: String(layoutId),\n regionId: String(regionId),\n mediaId: String(mediaId),\n });\n }\n\n /**\n * NotifyStatus - report current status\n * PUT /status → JSON acknowledgement\n * @param {Object} status - Status object with currentLayoutId, deviceName, etc.\n */\n async notifyStatus(status) {\n // Enrich with storage estimate if available\n if (typeof navigator !== 'undefined' && navigator.storage?.estimate) {\n try {\n const estimate = await navigator.storage.estimate();\n status.availableSpace = estimate.quota - estimate.usage;\n status.totalSpace = estimate.quota;\n } catch (_) { /* storage estimate not supported */ }\n }\n\n // Add timezone if not already provided\n if (!status.timeZone && typeof Intl !== 'undefined') {\n status.timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;\n }\n\n return this.restSend('PUT', '/status', {\n statusData: status,\n });\n }\n\n /**\n * MediaInventory - report downloaded files\n * POST /mediaInventory → JSON acknowledgement\n */\n async mediaInventory(inventoryXml) {\n // Accept array (JSON-native) or string (XML) — send under the right key\n const body = Array.isArray(inventoryXml)\n ? { inventoryItems: inventoryXml }\n : { inventory: inventoryXml };\n return this.restSend('POST', '/mediaInventory', body);\n }\n\n /**\n * BlackList - report broken media to CMS\n *\n * BlackList has no REST equivalent endpoint.\n * Log a warning and return false.\n */\n async blackList(mediaId, type, reason) {\n log.warn(`BlackList not available via REST (${type}/${mediaId}: ${reason})`);\n return false;\n }\n\n /**\n * SubmitLog - submit player logs to CMS\n * POST /log → JSON acknowledgement\n */\n async submitLog(logXml) {\n // Accept array (JSON-native) or string (XML) — send under the right key\n const body = Array.isArray(logXml) ? { logs: logXml } : { logXml };\n const result = await this.restSend('POST', '/log', body);\n return result?.success === true;\n }\n\n /**\n * SubmitScreenShot - submit screenshot to CMS\n * POST /screenshot → JSON acknowledgement\n */\n async submitScreenShot(base64Image) {\n const result = await this.restSend('POST', '/screenshot', {\n screenshot: base64Image,\n });\n return result?.success === true;\n }\n\n /**\n * SubmitStats - submit proof of play statistics\n * POST /stats → JSON acknowledgement\n */\n async submitStats(statsXml) {\n try {\n // Accept array (JSON-native) or string (XML) — send under the right key\n const body = Array.isArray(statsXml) ? { stats: statsXml } : { statXml: statsXml };\n const result = await this.restSend('POST', '/stats', body);\n const success = result?.success === true;\n log.info(`SubmitStats result: ${success}`);\n return success;\n } catch (error) {\n log.error('SubmitStats failed:', error);\n throw error;\n }\n }\n}\n","/**\n * XMDS SOAP transport client for Xibo CMS.\n *\n * Uses the traditional SOAP/XML endpoint (xmds.php) for full protocol\n * compatibility with all Xibo CMS versions.\n *\n * Protocol: https://github.com/linuxnow/xibo_players_docs\n */\nimport { createLogger, fetchWithRetry } from '@xiboplayer/utils';\nimport { parseScheduleResponse } from './schedule-parser.js';\n\nconst log = createLogger('XMDS');\n\nexport class XmdsClient {\n constructor(config) {\n this.config = config;\n this.schemaVersion = 5;\n this.retryOptions = config.retryOptions || { maxRetries: 2, baseDelayMs: 2000 };\n }\n\n // ─── SOAP transport helpers ─────────────────────────────────────\n\n /**\n * Build SOAP envelope for a given method and parameters\n */\n buildEnvelope(method, params) {\n const paramElements = Object.entries(params)\n .map(([key, value]) => {\n const escaped = String(value)\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;');\n return `<${key} xsi:type=\"xsd:string\">${escaped}</${key}>`;\n })\n .join('\\n ');\n\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<soap:Envelope\n xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"\n xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\"\n xmlns:tns=\"urn:xmds\"\n xmlns:types=\"urn:xmds/encodedTypes\"\n xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\n <soap:Body soap:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n <tns:${method}>\n ${paramElements}\n </tns:${method}>\n </soap:Body>\n</soap:Envelope>`;\n }\n\n /**\n * Rewrite XMDS URL for Electron proxy.\n * If running inside the Electron shell, use the local proxy to avoid CORS.\n * Detection: preload.js exposes window.electronAPI.isElectron = true,\n * or fallback to checking localhost:8765 (default Electron server port).\n */\n rewriteXmdsUrl(cmsUrl) {\n if (typeof window !== 'undefined' &&\n (window.electronAPI?.isElectron ||\n (window.location.hostname === 'localhost' && window.location.port === '8765'))) {\n const encodedCmsUrl = encodeURIComponent(cmsUrl);\n return `/xmds-proxy?cms=${encodedCmsUrl}`;\n }\n\n return `${cmsUrl}/xmds.php`;\n }\n\n /**\n * Call XMDS SOAP method\n */\n async call(method, params = {}) {\n const xmdsUrl = this.rewriteXmdsUrl(this.config.cmsAddress);\n const url = `${xmdsUrl}${xmdsUrl.includes('?') ? '&' : '?'}v=${this.schemaVersion}`;\n const body = this.buildEnvelope(method, params);\n\n log.debug(`${method}`, params);\n log.debug(`URL: ${url}`);\n\n const response = await fetchWithRetry(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'text/xml; charset=utf-8'\n },\n body\n }, this.retryOptions);\n\n if (!response.ok) {\n throw new Error(`XMDS ${method} failed: ${response.status} ${response.statusText}`);\n }\n\n const xml = await response.text();\n return this.parseResponse(xml, method);\n }\n\n /**\n * Parse SOAP response\n */\n parseResponse(xml, method) {\n const parser = new DOMParser();\n const doc = parser.parseFromString(xml, 'text/xml');\n\n // Check for SOAP fault (handle namespace prefix like soap:Fault)\n let fault = doc.querySelector('Fault');\n if (!fault) {\n fault = Array.from(doc.querySelectorAll('*')).find(\n el => el.localName === 'Fault' || el.tagName.endsWith(':Fault')\n );\n }\n if (fault) {\n const faultString = fault.querySelector('faultstring')?.textContent\n || Array.from(fault.querySelectorAll('*')).find(el => el.localName === 'faultstring')?.textContent\n || 'Unknown SOAP fault';\n throw new Error(`SOAP Fault: ${faultString}`);\n }\n\n // Extract response element (handle namespace prefixes like ns1:MethodResponse)\n const responseTag = `${method}Response`;\n let responseEl = doc.querySelector(responseTag);\n if (!responseEl) {\n responseEl = Array.from(doc.querySelectorAll('*')).find(\n el => el.localName === responseTag || el.tagName.endsWith(':' + responseTag)\n );\n }\n\n if (!responseEl) {\n throw new Error(`No ${responseTag} element in SOAP response`);\n }\n\n const returnEl = responseEl.firstElementChild;\n if (!returnEl) {\n return null;\n }\n\n return returnEl.textContent;\n }\n\n // ─── Public API ─────────────────────────────────────────────────\n\n /**\n * RegisterDisplay - authenticate and get settings\n */\n async registerDisplay() {\n const os = `${navigator.platform} ${navigator.userAgent}`;\n\n const xml = await this.call('RegisterDisplay', {\n serverKey: this.config.cmsKey,\n hardwareKey: this.config.hardwareKey,\n displayName: this.config.displayName,\n clientType: 'chromeOS',\n clientVersion: '0.1.0',\n clientCode: '1',\n operatingSystem: os,\n macAddress: this.config.macAddress || 'n/a',\n xmrChannel: this.config.xmrChannel,\n xmrPubKey: ''\n });\n\n return this.parseRegisterDisplayResponse(xml);\n }\n\n /**\n * Parse RegisterDisplay XML response\n */\n parseRegisterDisplayResponse(xml) {\n const parser = new DOMParser();\n const doc = parser.parseFromString(xml, 'text/xml');\n\n const display = doc.querySelector('display');\n if (!display) {\n throw new Error('Invalid RegisterDisplay response: no <display> element');\n }\n\n const code = display.getAttribute('code');\n const message = display.getAttribute('message');\n\n if (code !== 'READY') {\n return { code, message, settings: null };\n }\n\n const settings = {};\n for (const child of display.children) {\n if (!['commands', 'file'].includes(child.tagName.toLowerCase())) {\n settings[child.tagName] = child.textContent;\n }\n }\n\n const checkRf = display.getAttribute('checkRf') || '';\n const checkSchedule = display.getAttribute('checkSchedule') || '';\n\n return { code, message, settings, checkRf, checkSchedule };\n }\n\n /**\n * RequiredFiles - get list of files to download\n */\n async requiredFiles() {\n const xml = await this.call('RequiredFiles', {\n serverKey: this.config.cmsKey,\n hardwareKey: this.config.hardwareKey\n });\n\n return this.parseRequiredFilesResponse(xml);\n }\n\n /**\n * Parse RequiredFiles XML response\n */\n parseRequiredFilesResponse(xml) {\n const parser = new DOMParser();\n const doc = parser.parseFromString(xml, 'text/xml');\n\n const files = [];\n for (const fileEl of doc.querySelectorAll('file')) {\n files.push({\n type: fileEl.getAttribute('type'),\n id: fileEl.getAttribute('id'),\n size: parseInt(fileEl.getAttribute('size') || '0'),\n md5: fileEl.getAttribute('md5'),\n download: fileEl.getAttribute('download'),\n path: fileEl.getAttribute('path'),\n code: fileEl.getAttribute('code'),\n layoutid: fileEl.getAttribute('layoutid'),\n regionid: fileEl.getAttribute('regionid'),\n mediaid: fileEl.getAttribute('mediaid')\n });\n }\n\n return files;\n }\n\n /**\n * Schedule - get layout schedule\n */\n async schedule() {\n const xml = await this.call('Schedule', {\n serverKey: this.config.cmsKey,\n hardwareKey: this.config.hardwareKey\n });\n\n return parseScheduleResponse(xml);\n }\n\n /**\n * GetResource - get rendered widget HTML\n */\n async getResource(layoutId, regionId, mediaId) {\n const xml = await this.call('GetResource', {\n serverKey: this.config.cmsKey,\n hardwareKey: this.config.hardwareKey,\n layoutId: String(layoutId),\n regionId: String(regionId),\n mediaId: String(mediaId)\n });\n\n return xml;\n }\n\n /**\n * NotifyStatus - report current status\n * @param {Object} status - Status object with currentLayoutId, deviceName, etc.\n */\n async notifyStatus(status) {\n // Enrich with storage estimate if available\n if (typeof navigator !== 'undefined' && navigator.storage?.estimate) {\n try {\n const estimate = await navigator.storage.estimate();\n status.availableSpace = estimate.quota - estimate.usage;\n status.totalSpace = estimate.quota;\n } catch (_) { /* storage estimate not supported */ }\n }\n\n // Add timezone if not already provided\n if (!status.timeZone && typeof Intl !== 'undefined') {\n status.timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;\n }\n\n return await this.call('NotifyStatus', {\n serverKey: this.config.cmsKey,\n hardwareKey: this.config.hardwareKey,\n status: JSON.stringify(status)\n });\n }\n\n /**\n * MediaInventory - report downloaded files\n */\n async mediaInventory(inventoryXml) {\n return await this.call('MediaInventory', {\n serverKey: this.config.cmsKey,\n hardwareKey: this.config.hardwareKey,\n mediaInventory: inventoryXml\n });\n }\n\n /**\n * BlackList - report broken media to CMS\n * @param {string} mediaId - The media file ID\n * @param {string} type - File type ('media' or 'layout')\n * @param {string} reason - Reason for blacklisting\n * @returns {Promise<boolean>}\n */\n async blackList(mediaId, type, reason) {\n try {\n const xml = await this.call('BlackList', {\n serverKey: this.config.cmsKey,\n hardwareKey: this.config.hardwareKey,\n mediaId: String(mediaId),\n type: type || 'media',\n reason: reason || 'Failed to render'\n });\n log.info(`BlackListed ${type}/${mediaId}: ${reason}`);\n return xml === 'true';\n } catch (error) {\n log.warn('BlackList failed:', error);\n return false;\n }\n }\n\n /**\n * SubmitLog - submit player logs to CMS for remote debugging\n * @param {string} logXml - XML string containing log entries\n * @returns {Promise<boolean>} - true if logs were successfully submitted\n */\n async submitLog(logXml) {\n const xml = await this.call('SubmitLog', {\n serverKey: this.config.cmsKey,\n hardwareKey: this.config.hardwareKey,\n logXml: logXml\n });\n\n return xml === 'true';\n }\n\n /**\n * SubmitScreenShot - submit screenshot to CMS for display verification\n * @param {string} base64Image - Base64-encoded PNG image data\n * @returns {Promise<boolean>} - true if screenshot was successfully submitted\n */\n async submitScreenShot(base64Image) {\n const xml = await this.call('SubmitScreenShot', {\n serverKey: this.config.cmsKey,\n hardwareKey: this.config.hardwareKey,\n screenShot: base64Image\n });\n\n return xml === 'true';\n }\n\n /**\n * SubmitStats - submit proof of play statistics\n * @param {string} statsXml - XML-encoded stats string\n * @returns {Promise<boolean>} - true if stats were successfully submitted\n */\n async submitStats(statsXml) {\n try {\n const xml = await this.call('SubmitStats', {\n serverKey: this.config.cmsKey,\n hardwareKey: this.config.hardwareKey,\n statXml: statsXml\n });\n\n const success = xml === 'true';\n log.info(`SubmitStats result: ${success}`);\n return success;\n } catch (error) {\n log.error('SubmitStats failed:', error);\n throw error;\n }\n }\n}\n"],"names":["parseCriteria","parentEl","criteria","criteriaEl","parseScheduleResponse","xml","doc","schedule","defaultEl","campaignEl","campaign","layoutEl","fileId","overlaysContainer","overlayEl","actionsContainer","actionEl","cmdEl","dcEl","log","createLogger","RestClient","config","path","queryParams","url","key","value","cacheKey","headers","cachedEtag","response","fetchWithRetry","cached","errorBody","etag","contentType","data","method","body","os","json","display","attrs","code","message","settings","checkRf","checkSchedule","syncConfig","files","fileList","f","layoutId","regionId","mediaId","status","_a","estimate","inventoryXml","type","reason","logXml","result","base64Image","statsXml","success","error","XmdsClient","params","paramElements","escaped","cmsUrl","xmdsUrl","fault","el","faultString","_b","responseTag","responseEl","returnEl","child","fileEl"],"mappings":"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"}
package/dist/index.html DELETED
@@ -1,130 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Xibo Player</title>
7
- <style>
8
- * {
9
- margin: 0;
10
- padding: 0;
11
- box-sizing: border-box;
12
- }
13
-
14
- body {
15
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
16
- background: #000;
17
- color: #fff;
18
- overflow: hidden;
19
- }
20
-
21
- #player-container {
22
- width: 100vw;
23
- height: 100vh;
24
- position: relative;
25
- overflow: hidden;
26
- }
27
-
28
- #overlay {
29
- position: fixed;
30
- top: 0;
31
- left: 0;
32
- right: 0;
33
- background: rgba(0, 0, 0, 0.7);
34
- padding: 10px 20px;
35
- display: flex;
36
- justify-content: space-between;
37
- align-items: center;
38
- font-size: 12px;
39
- z-index: 9999;
40
- opacity: 0;
41
- transition: opacity 0.3s;
42
- }
43
-
44
- #overlay.visible {
45
- opacity: 1;
46
- }
47
-
48
- #config-info {
49
- color: #4CAF50;
50
- }
51
-
52
- #status {
53
- color: #fff;
54
- }
55
-
56
- .status-error {
57
- color: #f44336 !important;
58
- }
59
-
60
- .status-info {
61
- color: #2196F3 !important;
62
- }
63
-
64
- /* Hide overlay by default - show only on hover */
65
- #overlay {
66
- display: none;
67
- }
68
-
69
- body:hover #overlay {
70
- display: flex;
71
- opacity: 1;
72
- }
73
-
74
- /* Layout styles */
75
- .xibo-layout {
76
- width: 100%;
77
- height: 100%;
78
- }
79
-
80
- .xibo-region {
81
- position: absolute;
82
- overflow: hidden;
83
- }
84
-
85
- .xibo-widget {
86
- width: 100%;
87
- height: 100%;
88
- }
89
- </style>
90
- <script type="module" crossorigin src="./assets/main-BUvkpHsV.js"></script>
91
- <link rel="modulepreload" crossorigin href="./assets/modulepreload-polyfill-B5Qt9EMX.js">
92
- <link rel="modulepreload" crossorigin href="./assets/cms-api-Ce7EVg5h.js">
93
- <link rel="modulepreload" crossorigin href="./assets/cache-proxy-CrlayfSe.js">
94
- </head>
95
- <body>
96
- <!-- Status overlay -->
97
- <div id="overlay">
98
- <div id="config-info">Initializing...</div>
99
- <div id="status">Loading player...</div>
100
- </div>
101
-
102
- <!-- Player rendering container -->
103
- <div id="player-container"></div>
104
-
105
- <!-- Check for configuration before loading player -->
106
- <script>
107
- // TEMP: Force debug level for testing (shows video controls, verbose logging)
108
- // Remove this line when debugging is no longer needed
109
- localStorage.setItem('xibo_log_level', 'DEBUG');
110
-
111
- // Check if player is configured
112
- const params = new URLSearchParams(window.location.search);
113
- const hasUrlConfig = params.has('cmsAddress') && params.has('cmsKey');
114
- const hasStoredConfig = localStorage.getItem('xibo_config');
115
-
116
- console.log('[Player] Has URL config:', hasUrlConfig);
117
- console.log('[Player] Has stored config:', !!hasStoredConfig);
118
-
119
- if (!hasUrlConfig && !hasStoredConfig) {
120
- // Not configured, redirect to setup
121
- console.log('[Player] Not configured, redirecting to setup...');
122
- window.location.href = './setup.html';
123
- } else {
124
- console.log('[Player] Configuration found, loading player...');
125
- }
126
- </script>
127
-
128
- <!-- Main player script -->
129
- </body>
130
- </html>