@xiboplayer/pwa 0.5.13 → 0.5.14
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/{index-rMG3kuqV.js → index-Bcgq4p6v.js} +2 -2
- package/dist/assets/{index-rMG3kuqV.js.map → index-Bcgq4p6v.js.map} +1 -1
- package/dist/assets/index-BczIv3fg.js +2 -0
- package/dist/assets/{index-BzTeZiFu.js.map → index-BczIv3fg.js.map} +1 -1
- package/dist/assets/{index-dSvc2qBf.js → index-BeGa2zKC.js} +2 -2
- package/dist/assets/{index-dSvc2qBf.js.map → index-BeGa2zKC.js.map} +1 -1
- package/dist/assets/{index-B9S4-Tg6.js → index-COInxuZI.js} +2 -2
- package/dist/assets/{index-B9S4-Tg6.js.map → index-COInxuZI.js.map} +1 -1
- package/dist/assets/{index-BrJYfvV-.js → index-DAhOdNyB.js} +2 -2
- package/dist/assets/{index-BrJYfvV-.js.map → index-DAhOdNyB.js.map} +1 -1
- package/dist/assets/{index-RNYmTctp.js → index-DBYNSQLp.js} +2 -2
- package/dist/assets/{index-RNYmTctp.js.map → index-DBYNSQLp.js.map} +1 -1
- package/dist/assets/{index-DBeB6nHq.js → index-DgqUapYt.js} +2 -2
- package/dist/assets/{index-DBeB6nHq.js.map → index-DgqUapYt.js.map} +1 -1
- package/dist/assets/{index-DD2ZPwTV.js → index-FlRMd3Sh.js} +2 -2
- package/dist/assets/{index-DD2ZPwTV.js.map → index-FlRMd3Sh.js.map} +1 -1
- package/dist/assets/{index-B39PWpun.js → index-ZD5qisoE.js} +2 -2
- package/dist/assets/{index-B39PWpun.js.map → index-ZD5qisoE.js.map} +1 -1
- package/dist/assets/{main-BJ4a67Bs.js → main-DstA7-TG.js} +3 -3
- package/dist/assets/main-DstA7-TG.js.map +1 -0
- package/dist/assets/{setup-Cal-4t_7.js → setup-CKgHUoum.js} +2 -2
- package/dist/assets/{setup-Cal-4t_7.js.map → setup-CKgHUoum.js.map} +1 -1
- package/dist/index.html +12 -1
- package/dist/setup.html +1 -1
- package/dist/sw-pwa.js +1 -1
- package/package.json +13 -13
- package/dist/assets/index-BzTeZiFu.js +0 -2
- package/dist/assets/main-BJ4a67Bs.js.map +0 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{C as g,d as L,L as n,a as m,b as p,c as v,f as c,g as E,i as l,m as C,r as f,s as S,u as k}from"./cms-api-B3gEu-pj.js";import{E as x}from"./main-
|
|
2
|
-
//# sourceMappingURL=index-
|
|
1
|
+
import{C as g,d as L,L as n,a as m,b as p,c as v,f as c,g as E,i as l,m as C,r as f,s as S,u as k}from"./cms-api-B3gEu-pj.js";import{E as x}from"./main-DstA7-TG.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./widget-html-DvXXB6at.js";const e="0.5.14",s={version:e},t=s.version;export{g as CmsApiClient,L as CmsApiError,x as EventEmitter,n as LOG_LEVELS,t as VERSION,m as applyCmsLogLevel,p as config,v as createLogger,c as fetchWithRetry,E as getLogLevel,l as isDebug,C as mapCmsLogLevel,f as registerLogSink,S as setLogLevel,k as unregisterLogSink};
|
|
2
|
+
//# sourceMappingURL=index-Bcgq4p6v.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-
|
|
1
|
+
{"version":3,"file":"index-Bcgq4p6v.js","sources":["../../../utils/src/index.js"],"sourcesContent":["// @xiboplayer/utils - Shared utilities\nimport pkg from '../package.json' with { type: 'json' };\nexport const VERSION = pkg.version;\nexport { createLogger, setLogLevel, getLogLevel, isDebug, applyCmsLogLevel, mapCmsLogLevel, registerLogSink, unregisterLogSink, LOG_LEVELS } from './logger.js';\nexport { EventEmitter } from './event-emitter.js';\nexport { config } from './config.js';\nexport { fetchWithRetry } from './fetch-retry.js';\nexport { CmsApiClient, CmsApiError } from './cms-api.js';\n"],"names":["VERSION","pkg"],"mappings":"mRAEaA,EAAUC,EAAI"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{L as p,a as m,R as L}from"./main-DstA7-TG.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./cms-api-B3gEu-pj.js";import"./widget-html-DvXXB6at.js";const o="0.5.14",r={version:o},a=r.version;export{p as LayoutPool,m as LayoutTranslator,L as RendererLite,a as VERSION};
|
|
2
|
+
//# sourceMappingURL=index-BczIv3fg.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-
|
|
1
|
+
{"version":3,"file":"index-BczIv3fg.js","sources":["../../../renderer/src/index.js"],"sourcesContent":["// @xiboplayer/renderer - Layout rendering\nimport pkg from '../package.json' with { type: 'json' };\nexport const VERSION = pkg.version;\nexport { RendererLite } from './renderer-lite.js';\nexport { LayoutPool } from './layout-pool.js';\nexport { LayoutTranslator } from './layout.js';\n"],"names":["VERSION","pkg"],"mappings":"iMAEaA,EAAUC,EAAI"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{E as i}from"./main-
|
|
2
|
-
//# sourceMappingURL=index-
|
|
1
|
+
import{E as i}from"./main-DstA7-TG.js";import{D as m,P as g}from"./main-DstA7-TG.js";import"./cms-api-B3gEu-pj.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./widget-html-DvXXB6at.js";const r="0.5.14",a={version:r};class d extends i{constructor(){super(),this.currentLayoutId=null,this.currentScheduleId=null,this.displayName="",this.hardwareKey="",this.playerType="pwa",this.displayStatus="idle",this.screenWidth=0,this.screenHeight=0,this.lastCollectionTime=null,this.lastHeartbeat=null,this.isRegistered=!1}set(t,e){if(this[t]===e)return;const s=this[t];this[t]=e,this.emit("change",t,e,s)}toJSON(){return{currentLayoutId:this.currentLayoutId,currentScheduleId:this.currentScheduleId,displayName:this.displayName,hardwareKey:this.hardwareKey,playerType:this.playerType,displayStatus:this.displayStatus,screenWidth:this.screenWidth,screenHeight:this.screenHeight,lastCollectionTime:this.lastCollectionTime,lastHeartbeat:this.lastHeartbeat,isRegistered:this.isRegistered}}}const p=a.version;export{m as DataConnectorManager,g as PlayerCore,d as PlayerState,p as VERSION};
|
|
2
|
+
//# sourceMappingURL=index-BeGa2zKC.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-
|
|
1
|
+
{"version":3,"file":"index-BeGa2zKC.js","sources":["../../../core/src/state.js","../../../core/src/index.js"],"sourcesContent":["/**\n * Centralized player state\n *\n * Single source of truth for player status, dimensions, and display info.\n * Avoids scattered state across PlayerCore, renderer, and platform layer.\n */\n\nimport { EventEmitter } from '@xiboplayer/utils';\n\nexport class PlayerState extends EventEmitter {\n constructor() {\n super();\n this.currentLayoutId = null;\n this.currentScheduleId = null;\n this.displayName = '';\n this.hardwareKey = '';\n this.playerType = 'pwa';\n this.displayStatus = 'idle'; // idle | collecting | rendering | error\n this.screenWidth = 0;\n this.screenHeight = 0;\n this.lastCollectionTime = null;\n this.lastHeartbeat = null;\n this.isRegistered = false;\n }\n\n /**\n * Update a state property and emit change event\n */\n set(key, value) {\n if (this[key] === value) return;\n const old = this[key];\n this[key] = value;\n this.emit('change', key, value, old);\n }\n\n /**\n * Get snapshot of current state (for status reporting)\n */\n toJSON() {\n return {\n currentLayoutId: this.currentLayoutId,\n currentScheduleId: this.currentScheduleId,\n displayName: this.displayName,\n hardwareKey: this.hardwareKey,\n playerType: this.playerType,\n displayStatus: this.displayStatus,\n screenWidth: this.screenWidth,\n screenHeight: this.screenHeight,\n lastCollectionTime: this.lastCollectionTime,\n lastHeartbeat: this.lastHeartbeat,\n isRegistered: this.isRegistered\n };\n }\n}\n","// @xiboplayer/core - Player core orchestration\nimport pkg from '../package.json' with { type: 'json' };\nexport const VERSION = pkg.version;\nexport { PlayerCore } from './player-core.js';\nexport { PlayerState } from './state.js';\nexport { DataConnectorManager } from './data-connectors.js';\n"],"names":["PlayerState","EventEmitter","key","value","old","VERSION","pkg"],"mappings":"iOASO,MAAMA,UAAoBC,CAAa,CAC5C,aAAc,CACZ,MAAK,EACL,KAAK,gBAAkB,KACvB,KAAK,kBAAoB,KACzB,KAAK,YAAc,GACnB,KAAK,YAAc,GACnB,KAAK,WAAa,MAClB,KAAK,cAAgB,OACrB,KAAK,YAAc,EACnB,KAAK,aAAe,EACpB,KAAK,mBAAqB,KAC1B,KAAK,cAAgB,KACrB,KAAK,aAAe,EACtB,CAKA,IAAIC,EAAKC,EAAO,CACd,GAAI,KAAKD,CAAG,IAAMC,EAAO,OACzB,MAAMC,EAAM,KAAKF,CAAG,EACpB,KAAKA,CAAG,EAAIC,EACZ,KAAK,KAAK,SAAUD,EAAKC,EAAOC,CAAG,CACrC,CAKA,QAAS,CACP,MAAO,CACL,gBAAiB,KAAK,gBACtB,kBAAmB,KAAK,kBACxB,YAAa,KAAK,YAClB,YAAa,KAAK,YAClB,WAAY,KAAK,WACjB,cAAe,KAAK,cACpB,YAAa,KAAK,YAClB,aAAc,KAAK,aACnB,mBAAoB,KAAK,mBACzB,cAAe,KAAK,cACpB,aAAc,KAAK,YACzB,CACE,CACF,CCnDY,MAACC,EAAUC,EAAI"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{c as i}from"./cms-api-B3gEu-pj.js";import{E as o}from"./main-
|
|
2
|
-
//# sourceMappingURL=index-
|
|
1
|
+
import{c as i}from"./cms-api-B3gEu-pj.js";import{E as o}from"./main-DstA7-TG.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./widget-html-DvXXB6at.js";const a="0.5.14",l={version:a},r=i("DisplaySettings");class p extends o{constructor(){super(),this.settings={collectInterval:300,displayName:"Unknown Display",sizeX:1920,sizeY:1080,statsEnabled:!1,aggregationLevel:"Individual",logLevel:"error",xmrNetworkAddress:null,xmrWebSocketAddress:null,xmrCmsKey:null,preventSleep:!0,embeddedServerPort:9696,screenshotInterval:120,downloadStartWindow:null,downloadEndWindow:null,licenceCode:null,isSspEnabled:!1}}applySettings(e){if(!e)return r.warn("No settings provided"),{changed:[],settings:this.settings};const t=[],s=this.settings.collectInterval;return this.settings.collectInterval=this.parseCollectInterval(e.collectInterval||e.CollectInterval),this.settings.displayName=e.displayName||e.DisplayName||this.settings.displayName,this.settings.sizeX=parseInt(e.sizeX||e.SizeX||this.settings.sizeX),this.settings.sizeY=parseInt(e.sizeY||e.SizeY||this.settings.sizeY),this.settings.statsEnabled=this.parseBoolean(e.statsEnabled||e.StatsEnabled),this.settings.aggregationLevel=e.aggregationLevel||e.AggregationLevel||this.settings.aggregationLevel,this.settings.logLevel=e.logLevel||e.LogLevel||this.settings.logLevel,this.settings.xmrNetworkAddress=e.xmrNetworkAddress||e.XmrNetworkAddress||this.settings.xmrNetworkAddress,this.settings.xmrWebSocketAddress=e.xmrWebSocketAddress||e.XmrWebSocketAddress||this.settings.xmrWebSocketAddress,this.settings.xmrCmsKey=e.xmrCmsKey||e.XmrCmsKey||this.settings.xmrCmsKey,this.settings.preventSleep=this.parseBoolean(e.preventSleep||e.PreventSleep,!0),this.settings.embeddedServerPort=parseInt(e.embeddedServerPort||e.EmbeddedServerPort||this.settings.embeddedServerPort),this.settings.screenshotInterval=parseInt(e.screenshotInterval||e.ScreenshotInterval||this.settings.screenshotInterval),this.settings.downloadStartWindow=e.downloadStartWindow||e.DownloadStartWindow||this.settings.downloadStartWindow,this.settings.downloadEndWindow=e.downloadEndWindow||e.DownloadEndWindow||this.settings.downloadEndWindow,this.settings.licenceCode=e.licenceCode||e.LicenceCode||this.settings.licenceCode,this.settings.isSspEnabled=this.parseBoolean(e.isAdspaceEnabled||e.IsAdspaceEnabled),s!==this.settings.collectInterval&&(t.push("collectInterval"),this.emit("interval-changed",this.settings.collectInterval)),this.emit("settings-applied",this.settings,t),r.info("Applied settings:",{collectInterval:this.settings.collectInterval,displayName:this.settings.displayName,statsEnabled:this.settings.statsEnabled,changes:t}),{changed:t,settings:this.settings}}parseCollectInterval(e){const t=parseInt(e,10);return isNaN(t)||t<60?300:t>86400?86400:t}parseBoolean(e,t=!1){return e===!0||e===!1?e:e==="1"||e===1?!0:e==="0"||e===0?!1:t}getCollectInterval(){return this.settings.collectInterval}getDisplayName(){return this.settings.displayName}getDisplaySize(){return{width:this.settings.sizeX,height:this.settings.sizeY}}isStatsEnabled(){return this.settings.statsEnabled}getAllSettings(){return{...this.settings}}getSetting(e,t=null){return this.settings[e]!==void 0?this.settings[e]:t}isInDownloadWindow(){if(!this.settings.downloadStartWindow||!this.settings.downloadEndWindow)return!0;try{const e=new Date,t=e.getHours()*60+e.getMinutes(),s=this.parseTimeWindow(this.settings.downloadStartWindow),n=this.parseTimeWindow(this.settings.downloadEndWindow);return s>n?t>=s||t<n:t>=s&&t<n}catch(e){return r.warn("Failed to parse download window:",e),!0}}parseTimeWindow(e){if(!e||typeof e!="string")throw new Error("Invalid time window format");const t=e.split(":");if(t.length!==2)throw new Error("Invalid time window format (expected HH:MM)");const s=parseInt(t[0],10),n=parseInt(t[1],10);if(isNaN(s)||isNaN(n)||s<0||s>23||n<0||n>59)throw new Error("Invalid time window values");return s*60+n}getNextDownloadWindow(){if(!this.settings.downloadStartWindow||!this.settings.downloadEndWindow)return null;try{const e=new Date,t=e.getHours()*60+e.getMinutes(),s=this.parseTimeWindow(this.settings.downloadStartWindow),n=new Date(e);return t<s||n.setDate(n.getDate()+1),n.setHours(Math.floor(s/60),s%60,0,0),n}catch(e){return r.warn("Failed to calculate next download window:",e),null}}shouldTakeScreenshot(e){return e?(Date.now()-e.getTime())/1e3>=this.settings.screenshotInterval:!0}}const m=l.version;export{p as DisplaySettings,m as VERSION};
|
|
2
|
+
//# sourceMappingURL=index-COInxuZI.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-B9S4-Tg6.js","sources":["../../../settings/src/settings.js","../../../settings/src/index.js"],"sourcesContent":["/**\n * DisplaySettings - CMS display settings management\n *\n * Parses and applies configuration from RegisterDisplay response.\n * Based on upstream electron-player implementation.\n *\n * Architecture:\n * ┌─────────────────────────────────────────────────────┐\n * │ PlayerCore │\n * │ - Receives RegisterDisplay response │\n * │ - Passes to DisplaySettings.applySettings() │\n * └─────────────────────────────────────────────────────┘\n * ↓\n * ┌─────────────────────────────────────────────────────┐\n * │ DisplaySettings (this module) │\n * │ - Parse all CMS settings │\n * │ - Validate and normalize values │\n * │ - Apply collection interval │\n * │ - Check download windows │\n * │ - Handle screenshot requests │\n * │ - Emit events on changes │\n * └─────────────────────────────────────────────────────┘\n * ↓\n * ┌─────────────────────────────────────────────────────┐\n * │ Platform Layer (PWA/Electron/Mobile) │\n * │ - Listen for setting change events │\n * │ - Update UI with display name │\n * │ - Handle screenshot requests │\n * │ - Respect download windows │\n * └─────────────────────────────────────────────────────┘\n *\n * Usage:\n * const settings = new DisplaySettings();\n * settings.applySettings(regResult.settings);\n *\n * // Get settings\n * const collectInterval = settings.getCollectInterval();\n * const canDownload = settings.isInDownloadWindow();\n *\n * // Listen for changes\n * settings.on('interval-changed', (newInterval) => { ... });\n */\n\nimport { EventEmitter, createLogger } from '@xiboplayer/utils';\n\nconst log = createLogger('DisplaySettings');\n\nexport class DisplaySettings extends EventEmitter {\n constructor() {\n super();\n\n // Current settings (with defaults)\n this.settings = {\n // Collection\n collectInterval: 300, // seconds (5 minutes default)\n\n // Display info\n displayName: 'Unknown Display',\n sizeX: 1920,\n sizeY: 1080,\n\n // Stats\n statsEnabled: false,\n aggregationLevel: 'Individual', // or 'Aggregate'\n\n // Logging\n logLevel: 'error', // 'error', 'audit', 'info', 'debug'\n\n // XMR\n xmrNetworkAddress: null,\n xmrWebSocketAddress: null,\n xmrCmsKey: null,\n\n // Features\n preventSleep: true,\n embeddedServerPort: 9696,\n screenshotInterval: 120, // seconds\n\n // Download windows\n downloadStartWindow: null,\n downloadEndWindow: null,\n\n // License\n licenceCode: null,\n\n // SSP (ad space)\n isSspEnabled: false,\n };\n }\n\n /**\n * Apply settings from RegisterDisplay response\n * @param {Object} settings - Raw settings from CMS\n * @returns {Object} Applied settings with changes\n */\n applySettings(settings) {\n if (!settings) {\n log.warn('No settings provided');\n return { changed: [], settings: this.settings };\n }\n\n const changes = [];\n const oldInterval = this.settings.collectInterval;\n\n // Parse all settings with defaults\n // Handle both lowercase and CamelCase (uppercase first letter)\n this.settings.collectInterval = this.parseCollectInterval(settings.collectInterval || settings.CollectInterval);\n this.settings.displayName = settings.displayName || settings.DisplayName || this.settings.displayName;\n this.settings.sizeX = parseInt(settings.sizeX || settings.SizeX || this.settings.sizeX);\n this.settings.sizeY = parseInt(settings.sizeY || settings.SizeY || this.settings.sizeY);\n\n // Stats\n this.settings.statsEnabled = this.parseBoolean(settings.statsEnabled || settings.StatsEnabled);\n this.settings.aggregationLevel = settings.aggregationLevel || settings.AggregationLevel || this.settings.aggregationLevel;\n\n // Logging\n this.settings.logLevel = settings.logLevel || settings.LogLevel || this.settings.logLevel;\n\n // XMR\n this.settings.xmrNetworkAddress = settings.xmrNetworkAddress || settings.XmrNetworkAddress || this.settings.xmrNetworkAddress;\n this.settings.xmrWebSocketAddress = settings.xmrWebSocketAddress || settings.XmrWebSocketAddress || this.settings.xmrWebSocketAddress;\n this.settings.xmrCmsKey = settings.xmrCmsKey || settings.XmrCmsKey || this.settings.xmrCmsKey;\n\n // Features\n this.settings.preventSleep = this.parseBoolean(settings.preventSleep || settings.PreventSleep, true);\n this.settings.embeddedServerPort = parseInt(settings.embeddedServerPort || settings.EmbeddedServerPort || this.settings.embeddedServerPort);\n this.settings.screenshotInterval = parseInt(settings.screenshotInterval || settings.ScreenshotInterval || this.settings.screenshotInterval);\n\n // Download windows\n this.settings.downloadStartWindow = settings.downloadStartWindow || settings.DownloadStartWindow || this.settings.downloadStartWindow;\n this.settings.downloadEndWindow = settings.downloadEndWindow || settings.DownloadEndWindow || this.settings.downloadEndWindow;\n\n // License\n this.settings.licenceCode = settings.licenceCode || settings.LicenceCode || this.settings.licenceCode;\n\n // SSP\n this.settings.isSspEnabled = this.parseBoolean(settings.isAdspaceEnabled || settings.IsAdspaceEnabled);\n\n // Detect changes\n if (oldInterval !== this.settings.collectInterval) {\n changes.push('collectInterval');\n this.emit('interval-changed', this.settings.collectInterval);\n }\n\n // Emit generic settings-applied event\n this.emit('settings-applied', this.settings, changes);\n\n log.info('Applied settings:', {\n collectInterval: this.settings.collectInterval,\n displayName: this.settings.displayName,\n statsEnabled: this.settings.statsEnabled,\n changes\n });\n\n return { changed: changes, settings: this.settings };\n }\n\n /**\n * Parse collection interval (seconds)\n * @param {*} value - Raw value from CMS\n * @returns {number} Collection interval in seconds\n */\n parseCollectInterval(value) {\n const interval = parseInt(value, 10);\n\n // Validate range (minimum 60s, maximum 86400s = 24h)\n if (isNaN(interval) || interval < 60) {\n return 300; // 5 minutes default\n }\n\n if (interval > 86400) {\n return 86400; // 24 hours max\n }\n\n return interval;\n }\n\n /**\n * Parse boolean setting\n * @param {*} value - Raw value from CMS (string '1' or '0', or boolean)\n * @param {boolean} defaultValue - Default if not set\n * @returns {boolean}\n */\n parseBoolean(value, defaultValue = false) {\n if (value === true || value === false) {\n return value;\n }\n\n if (value === '1' || value === 1) {\n return true;\n }\n\n if (value === '0' || value === 0) {\n return false;\n }\n\n return defaultValue;\n }\n\n /**\n * Get collection interval in seconds\n * @returns {number}\n */\n getCollectInterval() {\n return this.settings.collectInterval;\n }\n\n /**\n * Get display name\n * @returns {string}\n */\n getDisplayName() {\n return this.settings.displayName;\n }\n\n /**\n * Get display size\n * @returns {{ width: number, height: number }}\n */\n getDisplaySize() {\n return {\n width: this.settings.sizeX,\n height: this.settings.sizeY\n };\n }\n\n /**\n * Check if stats are enabled\n * @returns {boolean}\n */\n isStatsEnabled() {\n return this.settings.statsEnabled;\n }\n\n /**\n * Get all settings\n * @returns {Object}\n */\n getAllSettings() {\n return { ...this.settings };\n }\n\n /**\n * Get a specific setting by key\n * @param {string} key - Setting key\n * @param {*} defaultValue - Default value if not set\n * @returns {*}\n */\n getSetting(key, defaultValue = null) {\n return this.settings[key] !== undefined ? this.settings[key] : defaultValue;\n }\n\n /**\n * Check if current time is within download window\n * @returns {boolean}\n */\n isInDownloadWindow() {\n // If no download window configured, always allow\n if (!this.settings.downloadStartWindow || !this.settings.downloadEndWindow) {\n return true;\n }\n\n try {\n const now = new Date();\n const currentTime = now.getHours() * 60 + now.getMinutes();\n\n const start = this.parseTimeWindow(this.settings.downloadStartWindow);\n const end = this.parseTimeWindow(this.settings.downloadEndWindow);\n\n // Handle overnight window (e.g., 22:00 - 06:00)\n if (start > end) {\n // Overnight: allow if AFTER start OR BEFORE end\n return currentTime >= start || currentTime < end;\n } else {\n // Same day: allow if AFTER start AND BEFORE end\n return currentTime >= start && currentTime < end;\n }\n } catch (error) {\n log.warn('Failed to parse download window:', error);\n return true; // Allow downloads if parsing fails\n }\n }\n\n /**\n * Parse time window string to minutes since midnight\n * @param {string} timeStr - Time string (e.g., \"14:30\", \"22:00\")\n * @returns {number} Minutes since midnight\n */\n parseTimeWindow(timeStr) {\n if (!timeStr || typeof timeStr !== 'string') {\n throw new Error('Invalid time window format');\n }\n\n const parts = timeStr.split(':');\n if (parts.length !== 2) {\n throw new Error('Invalid time window format (expected HH:MM)');\n }\n\n const hours = parseInt(parts[0], 10);\n const minutes = parseInt(parts[1], 10);\n\n if (isNaN(hours) || isNaN(minutes) || hours < 0 || hours > 23 || minutes < 0 || minutes > 59) {\n throw new Error('Invalid time window values');\n }\n\n return hours * 60 + minutes;\n }\n\n /**\n * Get next download window start time\n * @returns {Date|null} Next window start, or null if always allowed\n */\n getNextDownloadWindow() {\n if (!this.settings.downloadStartWindow || !this.settings.downloadEndWindow) {\n return null;\n }\n\n try {\n const now = new Date();\n const currentTime = now.getHours() * 60 + now.getMinutes();\n const start = this.parseTimeWindow(this.settings.downloadStartWindow);\n\n const nextWindow = new Date(now);\n\n if (currentTime < start) {\n // Window is later today\n nextWindow.setHours(Math.floor(start / 60), start % 60, 0, 0);\n } else {\n // Window is tomorrow\n nextWindow.setDate(nextWindow.getDate() + 1);\n nextWindow.setHours(Math.floor(start / 60), start % 60, 0, 0);\n }\n\n return nextWindow;\n } catch (error) {\n log.warn('Failed to calculate next download window:', error);\n return null;\n }\n }\n\n /**\n * Check if screenshot interval has elapsed\n * @param {Date} lastScreenshot - Last screenshot timestamp\n * @returns {boolean}\n */\n shouldTakeScreenshot(lastScreenshot) {\n if (!lastScreenshot) {\n return true;\n }\n\n const elapsed = (Date.now() - lastScreenshot.getTime()) / 1000;\n return elapsed >= this.settings.screenshotInterval;\n }\n}\n","// @xiboplayer/settings - CMS settings management\nimport pkg from '../package.json' with { type: 'json' };\nexport const VERSION = pkg.version;\n\n/**\n * Settings manager for Xibo Player\n * @module @xiboplayer/settings\n */\nexport { DisplaySettings } from './settings.js';\n"],"names":["log","createLogger","DisplaySettings","EventEmitter","settings","changes","oldInterval","value","interval","defaultValue","key","now","currentTime","start","end","error","timeStr","parts","hours","minutes","nextWindow","lastScreenshot","VERSION","pkg"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index-COInxuZI.js","sources":["../../../settings/src/settings.js","../../../settings/src/index.js"],"sourcesContent":["/**\n * DisplaySettings - CMS display settings management\n *\n * Parses and applies configuration from RegisterDisplay response.\n * Based on upstream electron-player implementation.\n *\n * Architecture:\n * ┌─────────────────────────────────────────────────────┐\n * │ PlayerCore │\n * │ - Receives RegisterDisplay response │\n * │ - Passes to DisplaySettings.applySettings() │\n * └─────────────────────────────────────────────────────┘\n * ↓\n * ┌─────────────────────────────────────────────────────┐\n * │ DisplaySettings (this module) │\n * │ - Parse all CMS settings │\n * │ - Validate and normalize values │\n * │ - Apply collection interval │\n * │ - Check download windows │\n * │ - Handle screenshot requests │\n * │ - Emit events on changes │\n * └─────────────────────────────────────────────────────┘\n * ↓\n * ┌─────────────────────────────────────────────────────┐\n * │ Platform Layer (PWA/Electron/Mobile) │\n * │ - Listen for setting change events │\n * │ - Update UI with display name │\n * │ - Handle screenshot requests │\n * │ - Respect download windows │\n * └─────────────────────────────────────────────────────┘\n *\n * Usage:\n * const settings = new DisplaySettings();\n * settings.applySettings(regResult.settings);\n *\n * // Get settings\n * const collectInterval = settings.getCollectInterval();\n * const canDownload = settings.isInDownloadWindow();\n *\n * // Listen for changes\n * settings.on('interval-changed', (newInterval) => { ... });\n */\n\nimport { EventEmitter, createLogger } from '@xiboplayer/utils';\n\nconst log = createLogger('DisplaySettings');\n\nexport class DisplaySettings extends EventEmitter {\n constructor() {\n super();\n\n // Current settings (with defaults)\n this.settings = {\n // Collection\n collectInterval: 300, // seconds (5 minutes default)\n\n // Display info\n displayName: 'Unknown Display',\n sizeX: 1920,\n sizeY: 1080,\n\n // Stats\n statsEnabled: false,\n aggregationLevel: 'Individual', // or 'Aggregate'\n\n // Logging\n logLevel: 'error', // 'error', 'audit', 'info', 'debug'\n\n // XMR\n xmrNetworkAddress: null,\n xmrWebSocketAddress: null,\n xmrCmsKey: null,\n\n // Features\n preventSleep: true,\n embeddedServerPort: 9696,\n screenshotInterval: 120, // seconds\n\n // Download windows\n downloadStartWindow: null,\n downloadEndWindow: null,\n\n // License\n licenceCode: null,\n\n // SSP (ad space)\n isSspEnabled: false,\n };\n }\n\n /**\n * Apply settings from RegisterDisplay response\n * @param {Object} settings - Raw settings from CMS\n * @returns {Object} Applied settings with changes\n */\n applySettings(settings) {\n if (!settings) {\n log.warn('No settings provided');\n return { changed: [], settings: this.settings };\n }\n\n const changes = [];\n const oldInterval = this.settings.collectInterval;\n\n // Parse all settings with defaults\n // Handle both lowercase and CamelCase (uppercase first letter)\n this.settings.collectInterval = this.parseCollectInterval(settings.collectInterval || settings.CollectInterval);\n this.settings.displayName = settings.displayName || settings.DisplayName || this.settings.displayName;\n this.settings.sizeX = parseInt(settings.sizeX || settings.SizeX || this.settings.sizeX);\n this.settings.sizeY = parseInt(settings.sizeY || settings.SizeY || this.settings.sizeY);\n\n // Stats\n this.settings.statsEnabled = this.parseBoolean(settings.statsEnabled || settings.StatsEnabled);\n this.settings.aggregationLevel = settings.aggregationLevel || settings.AggregationLevel || this.settings.aggregationLevel;\n\n // Logging\n this.settings.logLevel = settings.logLevel || settings.LogLevel || this.settings.logLevel;\n\n // XMR\n this.settings.xmrNetworkAddress = settings.xmrNetworkAddress || settings.XmrNetworkAddress || this.settings.xmrNetworkAddress;\n this.settings.xmrWebSocketAddress = settings.xmrWebSocketAddress || settings.XmrWebSocketAddress || this.settings.xmrWebSocketAddress;\n this.settings.xmrCmsKey = settings.xmrCmsKey || settings.XmrCmsKey || this.settings.xmrCmsKey;\n\n // Features\n this.settings.preventSleep = this.parseBoolean(settings.preventSleep || settings.PreventSleep, true);\n this.settings.embeddedServerPort = parseInt(settings.embeddedServerPort || settings.EmbeddedServerPort || this.settings.embeddedServerPort);\n this.settings.screenshotInterval = parseInt(settings.screenshotInterval || settings.ScreenshotInterval || this.settings.screenshotInterval);\n\n // Download windows\n this.settings.downloadStartWindow = settings.downloadStartWindow || settings.DownloadStartWindow || this.settings.downloadStartWindow;\n this.settings.downloadEndWindow = settings.downloadEndWindow || settings.DownloadEndWindow || this.settings.downloadEndWindow;\n\n // License\n this.settings.licenceCode = settings.licenceCode || settings.LicenceCode || this.settings.licenceCode;\n\n // SSP\n this.settings.isSspEnabled = this.parseBoolean(settings.isAdspaceEnabled || settings.IsAdspaceEnabled);\n\n // Detect changes\n if (oldInterval !== this.settings.collectInterval) {\n changes.push('collectInterval');\n this.emit('interval-changed', this.settings.collectInterval);\n }\n\n // Emit generic settings-applied event\n this.emit('settings-applied', this.settings, changes);\n\n log.info('Applied settings:', {\n collectInterval: this.settings.collectInterval,\n displayName: this.settings.displayName,\n statsEnabled: this.settings.statsEnabled,\n changes\n });\n\n return { changed: changes, settings: this.settings };\n }\n\n /**\n * Parse collection interval (seconds)\n * @param {*} value - Raw value from CMS\n * @returns {number} Collection interval in seconds\n */\n parseCollectInterval(value) {\n const interval = parseInt(value, 10);\n\n // Validate range (minimum 60s, maximum 86400s = 24h)\n if (isNaN(interval) || interval < 60) {\n return 300; // 5 minutes default\n }\n\n if (interval > 86400) {\n return 86400; // 24 hours max\n }\n\n return interval;\n }\n\n /**\n * Parse boolean setting\n * @param {*} value - Raw value from CMS (string '1' or '0', or boolean)\n * @param {boolean} defaultValue - Default if not set\n * @returns {boolean}\n */\n parseBoolean(value, defaultValue = false) {\n if (value === true || value === false) {\n return value;\n }\n\n if (value === '1' || value === 1) {\n return true;\n }\n\n if (value === '0' || value === 0) {\n return false;\n }\n\n return defaultValue;\n }\n\n /**\n * Get collection interval in seconds\n * @returns {number}\n */\n getCollectInterval() {\n return this.settings.collectInterval;\n }\n\n /**\n * Get display name\n * @returns {string}\n */\n getDisplayName() {\n return this.settings.displayName;\n }\n\n /**\n * Get display size\n * @returns {{ width: number, height: number }}\n */\n getDisplaySize() {\n return {\n width: this.settings.sizeX,\n height: this.settings.sizeY\n };\n }\n\n /**\n * Check if stats are enabled\n * @returns {boolean}\n */\n isStatsEnabled() {\n return this.settings.statsEnabled;\n }\n\n /**\n * Get all settings\n * @returns {Object}\n */\n getAllSettings() {\n return { ...this.settings };\n }\n\n /**\n * Get a specific setting by key\n * @param {string} key - Setting key\n * @param {*} defaultValue - Default value if not set\n * @returns {*}\n */\n getSetting(key, defaultValue = null) {\n return this.settings[key] !== undefined ? this.settings[key] : defaultValue;\n }\n\n /**\n * Check if current time is within download window\n * @returns {boolean}\n */\n isInDownloadWindow() {\n // If no download window configured, always allow\n if (!this.settings.downloadStartWindow || !this.settings.downloadEndWindow) {\n return true;\n }\n\n try {\n const now = new Date();\n const currentTime = now.getHours() * 60 + now.getMinutes();\n\n const start = this.parseTimeWindow(this.settings.downloadStartWindow);\n const end = this.parseTimeWindow(this.settings.downloadEndWindow);\n\n // Handle overnight window (e.g., 22:00 - 06:00)\n if (start > end) {\n // Overnight: allow if AFTER start OR BEFORE end\n return currentTime >= start || currentTime < end;\n } else {\n // Same day: allow if AFTER start AND BEFORE end\n return currentTime >= start && currentTime < end;\n }\n } catch (error) {\n log.warn('Failed to parse download window:', error);\n return true; // Allow downloads if parsing fails\n }\n }\n\n /**\n * Parse time window string to minutes since midnight\n * @param {string} timeStr - Time string (e.g., \"14:30\", \"22:00\")\n * @returns {number} Minutes since midnight\n */\n parseTimeWindow(timeStr) {\n if (!timeStr || typeof timeStr !== 'string') {\n throw new Error('Invalid time window format');\n }\n\n const parts = timeStr.split(':');\n if (parts.length !== 2) {\n throw new Error('Invalid time window format (expected HH:MM)');\n }\n\n const hours = parseInt(parts[0], 10);\n const minutes = parseInt(parts[1], 10);\n\n if (isNaN(hours) || isNaN(minutes) || hours < 0 || hours > 23 || minutes < 0 || minutes > 59) {\n throw new Error('Invalid time window values');\n }\n\n return hours * 60 + minutes;\n }\n\n /**\n * Get next download window start time\n * @returns {Date|null} Next window start, or null if always allowed\n */\n getNextDownloadWindow() {\n if (!this.settings.downloadStartWindow || !this.settings.downloadEndWindow) {\n return null;\n }\n\n try {\n const now = new Date();\n const currentTime = now.getHours() * 60 + now.getMinutes();\n const start = this.parseTimeWindow(this.settings.downloadStartWindow);\n\n const nextWindow = new Date(now);\n\n if (currentTime < start) {\n // Window is later today\n nextWindow.setHours(Math.floor(start / 60), start % 60, 0, 0);\n } else {\n // Window is tomorrow\n nextWindow.setDate(nextWindow.getDate() + 1);\n nextWindow.setHours(Math.floor(start / 60), start % 60, 0, 0);\n }\n\n return nextWindow;\n } catch (error) {\n log.warn('Failed to calculate next download window:', error);\n return null;\n }\n }\n\n /**\n * Check if screenshot interval has elapsed\n * @param {Date} lastScreenshot - Last screenshot timestamp\n * @returns {boolean}\n */\n shouldTakeScreenshot(lastScreenshot) {\n if (!lastScreenshot) {\n return true;\n }\n\n const elapsed = (Date.now() - lastScreenshot.getTime()) / 1000;\n return elapsed >= this.settings.screenshotInterval;\n }\n}\n","// @xiboplayer/settings - CMS settings management\nimport pkg from '../package.json' with { type: 'json' };\nexport const VERSION = pkg.version;\n\n/**\n * Settings manager for Xibo Player\n * @module @xiboplayer/settings\n */\nexport { DisplaySettings } from './settings.js';\n"],"names":["log","createLogger","DisplaySettings","EventEmitter","settings","changes","oldInterval","value","interval","defaultValue","key","now","currentTime","start","end","error","timeStr","parts","hours","minutes","nextWindow","lastScreenshot","VERSION","pkg"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{I as n,O as i,S as l,b as p,c as d,p as S,s as h}from"./main-
|
|
2
|
-
//# sourceMappingURL=index-
|
|
1
|
+
import{I as n,O as i,S as l,b as p,c as d,p as S,s as h}from"./main-DstA7-TG.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./cms-api-B3gEu-pj.js";import"./widget-html-DvXXB6at.js";const e="0.5.14",r={version:e},t=r.version;export{n as InterruptScheduler,i as OverlayScheduler,l as ScheduleManager,t as VERSION,p as buildScheduleQueue,d as calculateTimeline,S as parseLayoutDuration,h as scheduleManager};
|
|
2
|
+
//# sourceMappingURL=index-DAhOdNyB.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-
|
|
1
|
+
{"version":3,"file":"index-DAhOdNyB.js","sources":["../../../schedule/src/index.js"],"sourcesContent":["// @xiboplayer/schedule - Campaign scheduling and advanced features\n// Basic scheduling, interrupts, overlays, and dayparting\nimport pkg from '../package.json' with { type: 'json' };\nexport const VERSION = pkg.version;\n\n/**\n * Core schedule manager for basic scheduling and dayparting\n * @module @xiboplayer/schedule\n */\nexport { ScheduleManager, scheduleManager } from './schedule.js';\n\n/**\n * Interrupt scheduler for shareOfVoice layouts\n * @module @xiboplayer/schedule/interrupts\n */\nexport { InterruptScheduler } from './interrupts.js';\n\n/**\n * Overlay layout scheduler\n * @module @xiboplayer/schedule/overlays\n */\nexport { OverlayScheduler } from './overlays.js';\n\n/**\n * Offline timeline calculator — duration parser + timeline simulator\n * @module @xiboplayer/schedule/timeline\n */\nexport { calculateTimeline, parseLayoutDuration, buildScheduleQueue } from './timeline.js';\n"],"names":["VERSION","pkg"],"mappings":"6NAGaA,EAAUC,EAAI"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{C as t,b as i,D as l,a as c,F as d,L as g,S as p,d as C,c as h,i as x,t as D}from"./widget-html-DvXXB6at.js";import"./cms-api-B3gEu-pj.js";const a="0.5.
|
|
2
|
-
//# sourceMappingURL=index-
|
|
1
|
+
import{C as t,b as i,D as l,a as c,F as d,L as g,S as p,d as C,c as h,i as x,t as D}from"./widget-html-DvXXB6at.js";import"./cms-api-B3gEu-pj.js";const a="0.5.14",e={version:a},s=e.version;export{t as CacheAnalyzer,i as CacheManager,l as DownloadClient,c as DownloadManager,d as FileDownload,g as LayoutTaskBuilder,p as StoreClient,s as VERSION,C as cacheManager,h as cacheWidgetHtml,x as isUrlExpired,D as toProxyUrl};
|
|
2
|
+
//# sourceMappingURL=index-DBYNSQLp.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-
|
|
1
|
+
{"version":3,"file":"index-DBYNSQLp.js","sources":["../../../cache/src/index.js"],"sourcesContent":["// @xiboplayer/cache - Offline caching and downloads\nimport pkg from '../package.json' with { type: 'json' };\nexport const VERSION = pkg.version;\nexport { CacheManager, cacheManager } from './cache.js';\nexport { StoreClient } from './store-client.js';\nexport { DownloadClient } from './download-client.js';\nexport { DownloadManager, FileDownload, LayoutTaskBuilder, isUrlExpired, toProxyUrl } from './download-manager.js';\nexport { CacheAnalyzer } from './cache-analyzer.js';\nexport { cacheWidgetHtml } from './widget-html.js';\n"],"names":["VERSION","pkg"],"mappings":"iLAEaA,EAAUC,EAAI"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{R as p,X as i,p as a}from"./xmds-client-CX0t7Oes.js";import"./cms-api-B3gEu-pj.js";const s="0.5.
|
|
2
|
-
//# sourceMappingURL=index-
|
|
1
|
+
import{R as p,X as i,p as a}from"./xmds-client-CX0t7Oes.js";import"./cms-api-B3gEu-pj.js";const s="0.5.14",e={version:s},n=e.version;export{p as RestClient,n as VERSION,i as XmdsClient,a as parseScheduleResponse};
|
|
2
|
+
//# sourceMappingURL=index-DgqUapYt.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-
|
|
1
|
+
{"version":3,"file":"index-DgqUapYt.js","sources":["../../../xmds/src/index.js"],"sourcesContent":["// @xiboplayer/xmds - XMDS clients (REST and SOAP)\nimport pkg from '../package.json' with { type: 'json' };\nexport const VERSION = pkg.version;\nexport { RestClient } from './rest-client.js';\nexport { XmdsClient } from './xmds-client.js';\nexport { parseScheduleResponse } from './schedule-parser.js';\n"],"names":["VERSION","pkg"],"mappings":"yHAEaA,EAAUC,EAAI"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{c as w}from"./cms-api-B3gEu-pj.js";const m="0.5.
|
|
1
|
+
import{c as w}from"./cms-api-B3gEu-pj.js";const m="0.5.14",$={version:m},c=w("@xiboplayer/stats"),D="xibo-player-stats",v=1,b="stats";class L{constructor(){this.db=null,this.inProgressStats=new Map}async init(){if(this.db){c.debug("Stats collector already initialized");return}return new Promise((r,t)=>{if(typeof indexedDB>"u"){const e=new Error("IndexedDB not available");c.error("IndexedDB not available - stats will not be persisted"),t(e);return}const s=indexedDB.open(D,v);s.onerror=()=>{const e=new Error(`Failed to open IndexedDB: ${s.error}`);c.error("Failed to open stats database:",s.error),t(e)},s.onsuccess=()=>{this.db=s.result,c.info("Stats database initialized"),r()},s.onupgradeneeded=e=>{const n=e.target.result;n.objectStoreNames.contains(b)||(n.createObjectStore(b,{keyPath:"id",autoIncrement:!0}).createIndex("submitted","submitted",{unique:!1}),c.info("Stats store created"))}})}async startLayout(r,t,s){if(!this.db){c.warn("Stats database not initialized");return}if((s==null?void 0:s.enableStat)===!1){c.debug(`Stats disabled for layout ${r} (enableStat=false)`);return}const e=`layout-${r}`;if(this.inProgressStats.has(e)){const o=this.inProgressStats.get(e);o.end=new Date,o.duration=Math.floor((o.end-o.start)/1e3),await this._saveStatSplit(o),this.inProgressStats.delete(e),c.debug(`Layout ${r} replay - ended previous cycle (${o.duration}s)`)}const n={type:"layout",layoutId:r,scheduleId:t,start:new Date,end:null,duration:0,count:1,submitted:0};this.inProgressStats.set(e,n),c.debug(`Started tracking layout ${r} (schedule ${t})`)}async endLayout(r,t){if(!this.db){c.warn("Stats database not initialized");return}const s=`layout-${r}`,e=this.inProgressStats.get(s);if(!e){c.debug(`Layout ${r} not found in progress (may have been ended by replay)`);return}e.end=new Date,e.duration=Math.floor((e.end-e.start)/1e3);try{await this._saveStatSplit(e),this.inProgressStats.delete(s),c.debug(`Ended tracking layout ${r} (${e.duration}s)`)}catch(n){throw c.error(`Failed to save layout stat ${r}:`,n),n}}async startWidget(r,t,s,e,n){if(!this.db){c.warn("Stats database not initialized");return}if((n==null?void 0:n.enableStat)===!1){c.debug(`Stats disabled for widget ${r} (enableStat=false)`);return}const o=`media-${r}-${t}`;if(this.inProgressStats.has(o)){const d=this.inProgressStats.get(o);d.end=new Date,d.duration=Math.floor((d.end-d.start)/1e3),await this._saveStatSplit(d),this.inProgressStats.delete(o),c.debug(`Widget ${r} replay - ended previous cycle (${d.duration}s)`)}const a={type:"media",mediaId:r,widgetId:e||null,layoutId:t,scheduleId:s,start:new Date,end:null,duration:0,count:1,submitted:0};this.inProgressStats.set(o,a),c.debug(`Started tracking widget ${r} in layout ${t}`)}async endWidget(r,t,s){if(!this.db){c.warn("Stats database not initialized");return}const e=`media-${r}-${t}`,n=this.inProgressStats.get(e);if(!n){c.debug(`Widget ${r} not found in progress (expected during layout transitions)`);return}n.end=new Date,n.duration=Math.floor((n.end-n.start)/1e3);try{await this._saveStatSplit(n),this.inProgressStats.delete(e),c.debug(`Ended tracking widget ${r} (${n.duration}s)`)}catch(o){throw c.error(`Failed to save widget stat ${r}:`,o),o}}async recordEvent(r,t,s,e){if(!this.db){c.warn("Stats database not initialized");return}const n=new Date,o={type:"event",tag:r,layoutId:t,widgetId:s,scheduleId:e,start:n,end:n,duration:0,count:1,submitted:0};try{await this._saveStat(o),c.debug(`Recorded event '${r}' for widget ${s} in layout ${t}`)}catch(a){throw c.error(`Failed to record event '${r}':`,a),a}}async getStatsForSubmission(r=50){return this.db?new Promise((t,s)=>{const a=this.db.transaction([b],"readonly").objectStore(b).index("submitted").openCursor(IDBKeyRange.only(0)),d=[];a.onsuccess=u=>{const h=u.target.result;h&&d.length<r?(d.push(h.value),h.continue()):(c.debug(`Retrieved ${d.length} unsubmitted stats`),t(d))},a.onerror=()=>{c.error("Failed to retrieve stats:",a.error),s(new Error(`Failed to retrieve stats: ${a.error}`))}}):(c.warn("Stats database not initialized"),[])}async clearSubmittedStats(r){if(!this.db){c.warn("Stats database not initialized");return}if(!(!r||r.length===0))return new Promise((t,s)=>{const e=this.db.transaction([b],"readwrite"),n=e.objectStore(b);let o=0;r.forEach(a=>{if(a.id){const d=n.delete(a.id);d.onsuccess=()=>{o++},d.onerror=()=>{c.error(`Failed to delete stat ${a.id}:`,d.error)}}}),e.oncomplete=()=>{c.debug(`Deleted ${o} submitted stats`),t()},e.onerror=()=>{c.error("Failed to delete submitted stats:",e.error),s(new Error(`Failed to delete stats: ${e.error}`))}})}async getAggregatedStatsForSubmission(r=50){const t=await this.getStatsForSubmission(r);if(t.length===0)return[];const s=new Map;for(const e of t){const n=e.start instanceof Date?e.start.toISOString().slice(0,13):new Date(e.start).toISOString().slice(0,13),o=`${e.type}|${e.layoutId}|${e.mediaId||""}|${e.widgetId||""}|${e.tag||""}|${e.scheduleId}|${n}`;if(s.has(o)){const a=s.get(o);a.count+=e.count||1,a.duration+=e.duration||0;const d=e.start instanceof Date?e.start:new Date(e.start),u=e.end instanceof Date?e.end:new Date(e.end||e.start);d<a.start&&(a.start=d),u>a.end&&(a.end=u),a._rawIds.push(e.id)}else s.set(o,{...e,start:e.start instanceof Date?e.start:new Date(e.start),end:e.end instanceof Date?e.end:new Date(e.end||e.start),count:e.count||1,_rawIds:[e.id]})}return Array.from(s.values())}async getAllStats(){return this.db?new Promise((r,t)=>{const n=this.db.transaction([b],"readonly").objectStore(b).getAll();n.onsuccess=()=>{r(n.result)},n.onerror=()=>{c.error("Failed to get all stats:",n.error),t(new Error(`Failed to get all stats: ${n.error}`))}}):(c.warn("Stats database not initialized"),[])}async clearAllStats(){if(!this.db){c.warn("Stats database not initialized");return}return new Promise((r,t)=>{const n=this.db.transaction([b],"readwrite").objectStore(b).clear();n.onsuccess=()=>{c.debug("Cleared all stats"),this.inProgressStats.clear(),r()},n.onerror=()=>{c.error("Failed to clear all stats:",n.error),t(new Error(`Failed to clear stats: ${n.error}`))}})}async _saveStat(r){return new Promise((t,s)=>{const n=this.db.transaction([b],"readwrite").objectStore(b),o=n.add(r);o.onsuccess=()=>{t(o.result)},o.onerror=()=>{o.error.name==="QuotaExceededError"?(c.error("IndexedDB quota exceeded - cleaning old stats"),this._cleanOldStats().then(()=>{const a=n.add(r);a.onsuccess=()=>t(a.result),a.onerror=()=>s(a.error)}).catch(s)):s(o.error)}})}_splitAtHourBoundaries(r){const t=r.start,s=r.end;if(t.getFullYear()===s.getFullYear()&&t.getMonth()===s.getMonth()&&t.getDate()===s.getDate()&&t.getHours()===s.getHours())return[r];const e=[];let n=new Date(t.getTime());for(;n<s;){const o=new Date(n.getTime());o.setMinutes(0,0,0),o.setHours(o.getHours()+1);const a=o<s?o:s,d=Math.floor((a-n)/1e3);e.push({...r,start:new Date(n.getTime()),end:new Date(a.getTime()),duration:d,count:1}),n=a}return e}async _saveStatSplit(r){const t=this._splitAtHourBoundaries(r);for(const s of t)await this._saveStat(s)}async _cleanOldStats(){if(this.db)return new Promise((r,t)=>{const e=this.db.transaction([b],"readwrite").objectStore(b),o=e.index("submitted").openCursor(1),a=[];o.onsuccess=d=>{const u=d.target.result;u&&a.length<100?(a.push(u.value.id),u.continue()):(a.forEach(h=>{e.delete(h)}),c.info(`Cleaned ${a.length} old stats due to quota`),r())},o.onerror=()=>{c.error("Failed to clean old stats:",o.error),t(o.error)}})}}function E(i){return!i||i.length===0?"<stats></stats>":`<stats>
|
|
2
2
|
${i.map(t=>{const s=S(t.start),e=S(t.end||t.start),n=[`type="${f(t.type)}"`,`fromdt="${f(s)}"`,`todt="${f(e)}"`,`scheduleid="${t.scheduleId}"`,`layoutid="${t.layoutId}"`];return t.type==="media"&&(t.mediaId&&n.push(`mediaid="${t.mediaId}"`),t.widgetId&&n.push(`widgetid="${t.widgetId}"`)),t.type==="event"&&(t.tag&&n.push(`tag="${f(t.tag)}"`),t.widgetId&&n.push(`widgetid="${t.widgetId}"`)),n.push(`count="${t.count}"`),n.push(`duration="${t.duration}"`),` <stat ${n.join(" ")} />`}).join(`
|
|
3
3
|
`)}
|
|
4
4
|
</stats>`}function S(i){i instanceof Date||(i=new Date(i));const r=i.getFullYear(),t=String(i.getMonth()+1).padStart(2,"0"),s=String(i.getDate()).padStart(2,"0"),e=String(i.getHours()).padStart(2,"0"),n=String(i.getMinutes()).padStart(2,"0"),o=String(i.getSeconds()).padStart(2,"0");return`${r}-${t}-${s} ${e}:${n}:${o}`}function f(i){return typeof i!="string"?i:i.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}const l=w("@xiboplayer/stats"),F="xibo-player-logs",P=1,g="logs";class _{constructor(){this.db=null,this._reportedFaults=new Map}async init(){if(this.db){l.debug("Log reporter already initialized");return}return new Promise((r,t)=>{if(typeof indexedDB>"u"){const e=new Error("IndexedDB not available");l.error("IndexedDB not available - logs will not be persisted"),t(e);return}const s=indexedDB.open(F,P);s.onerror=()=>{const e=new Error(`Failed to open IndexedDB: ${s.error}`);l.error("Failed to open logs database:",s.error),t(e)},s.onsuccess=()=>{this.db=s.result,l.info("Logs database initialized"),r()},s.onupgradeneeded=e=>{const n=e.target.result;n.objectStoreNames.contains(g)||(n.createObjectStore(g,{keyPath:"id",autoIncrement:!0}).createIndex("submitted","submitted",{unique:!1}),l.info("Logs store created"))}})}async log(r,t,s="PLAYER",e=null){if(!this.db){console.warn("[LogReporter] Database not initialized, dropping log entry");return}["error","warning","audit","info","debug"].includes(r)||(r="info");const o={level:r,message:t,category:s,timestamp:new Date,submitted:0};e&&(e.alertType&&(o.alertType=e.alertType),e.eventType&&(o.eventType=e.eventType));try{await this._saveLog(o)}catch(a){throw console.error("[LogReporter] Failed to save log entry:",a),a}}async reportFault(r,t,s=3e5){const e=this._reportedFaults.get(r);e&&Date.now()-e<s||(this._reportedFaults.set(r,Date.now()),await this.log("error",t,"event",{alertType:"Player Fault",eventType:r}),l.info(`Fault reported: ${r} - ${t}`))}async getFaultsForSubmission(r=10){return this.db?new Promise((t,s)=>{const a=this.db.transaction([g],"readonly").objectStore(g).index("submitted").openCursor(IDBKeyRange.only(0)),d=[];a.onsuccess=u=>{const h=u.target.result;h&&d.length<r?(h.value.alertType==="Player Fault"&&d.push(h.value),h.continue()):t(d)},a.onerror=()=>{l.error("Failed to retrieve faults:",a.error),s(new Error(`Failed to retrieve faults: ${a.error}`))}}):[]}async error(r,t="PLAYER"){return this.log("error",r,t)}async audit(r,t="PLAYER"){return this.log("audit",r,t)}async info(r,t="PLAYER"){return this.log("info",r,t)}async debug(r,t="PLAYER"){return this.log("debug",r,t)}async getLogsForSubmission(r=50){return this.db?new Promise((t,s)=>{const a=this.db.transaction([g],"readonly").objectStore(g).index("submitted").openCursor(IDBKeyRange.only(0)),d=[];a.onsuccess=u=>{const h=u.target.result;h&&d.length<r?(d.push(h.value),h.continue()):(l.debug(`Retrieved ${d.length} unsubmitted logs (limit: ${r})`),t(d))},a.onerror=()=>{l.error("Failed to retrieve logs:",a.error),s(new Error(`Failed to retrieve logs: ${a.error}`))}}):(l.warn("Logs database not initialized"),[])}async _countUnsubmitted(){return new Promise(r=>{try{const n=this.db.transaction([g],"readonly").objectStore(g).index("submitted").count(IDBKeyRange.only(0));n.onsuccess=()=>r(n.result),n.onerror=()=>r(0)}catch{r(0)}})}async clearSubmittedLogs(r){if(!this.db){l.warn("Logs database not initialized");return}if(!(!r||r.length===0))return new Promise((t,s)=>{const e=this.db.transaction([g],"readwrite"),n=e.objectStore(g);let o=0;r.forEach(a=>{if(a.id){const d=n.delete(a.id);d.onsuccess=()=>{o++},d.onerror=()=>{l.error(`Failed to delete log ${a.id}:`,d.error)}}}),e.oncomplete=()=>{l.debug(`Deleted ${o} submitted logs`),t()},e.onerror=()=>{l.error("Failed to delete submitted logs:",e.error),s(new Error(`Failed to delete logs: ${e.error}`))}})}async getAllLogs(){return this.db?new Promise((r,t)=>{const n=this.db.transaction([g],"readonly").objectStore(g).getAll();n.onsuccess=()=>{r(n.result)},n.onerror=()=>{l.error("Failed to get all logs:",n.error),t(new Error(`Failed to get all logs: ${n.error}`))}}):(l.warn("Logs database not initialized"),[])}async clearAllLogs(){if(!this.db){l.warn("Logs database not initialized");return}return new Promise((r,t)=>{const n=this.db.transaction([g],"readwrite").objectStore(g).clear();n.onsuccess=()=>{l.debug("Cleared all logs"),r()},n.onerror=()=>{l.error("Failed to clear all logs:",n.error),t(new Error(`Failed to clear logs: ${n.error}`))}})}async _saveLog(r){return new Promise((t,s)=>{const n=this.db.transaction([g],"readwrite").objectStore(g),o=n.add(r);o.onsuccess=()=>{t(o.result)},o.onerror=()=>{o.error.name==="QuotaExceededError"?(console.warn("[LogReporter] IndexedDB quota exceeded - cleaning old logs"),this._cleanOldLogs().then(()=>{const a=n.add(r);a.onsuccess=()=>t(a.result),a.onerror=()=>s(a.error)}).catch(s)):s(o.error)}})}async _cleanOldLogs(){if(this.db)return new Promise((r,t)=>{const e=this.db.transaction([g],"readwrite").objectStore(g),o=e.index("submitted").openCursor(1),a=[];o.onsuccess=d=>{const u=d.target.result;u&&a.length<100?(a.push(u.value.id),u.continue()):(a.forEach(h=>{e.delete(h)}),console.log(`[LogReporter] Cleaned ${a.length} old logs due to quota`),r())},o.onerror=()=>{console.error("[LogReporter] Failed to clean old logs:",o.error),t(o.error)}})}}function R(i){return!i||i.length===0?"<logs></logs>":`<logs>
|
|
@@ -10,4 +10,4 @@ ${i.map(t=>{const s=y(t.timestamp),e=t.level==="error"||t.level==="audit"?t.leve
|
|
|
10
10
|
</log>`}).join(`
|
|
11
11
|
`)}
|
|
12
12
|
</logs>`}function q(i){return!i||i.length===0?"[]":JSON.stringify(i.map(r=>({code:r.eventType||"UNKNOWN",reason:r.message||"",date:y(r.timestamp),layoutId:r.scheduleId||0})))}function y(i){i instanceof Date||(i=new Date(i));const r=i.getFullYear(),t=String(i.getMonth()+1).padStart(2,"0"),s=String(i.getDate()).padStart(2,"0"),e=String(i.getHours()).padStart(2,"0"),n=String(i.getMinutes()).padStart(2,"0"),o=String(i.getSeconds()).padStart(2,"0");return`${r}-${t}-${s} ${e}:${n}:${o}`}function p(i){return typeof i!="string"?i:i.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}const T=$.version;export{_ as LogReporter,L as StatsCollector,T as VERSION,q as formatFaults,R as formatLogs,E as formatStats};
|
|
13
|
-
//# sourceMappingURL=index-
|
|
13
|
+
//# sourceMappingURL=index-FlRMd3Sh.js.map
|