@xiboplayer/schedule 0.7.3 → 0.7.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xiboplayer/schedule",
3
- "version": "0.7.3",
3
+ "version": "0.7.4",
4
4
  "description": "Complete scheduling solution: campaigns, dayparting, interrupts, and overlays",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
@@ -12,7 +12,7 @@
12
12
  "./overlays": "./src/overlays.js"
13
13
  },
14
14
  "dependencies": {
15
- "@xiboplayer/utils": "0.7.3"
15
+ "@xiboplayer/utils": "0.7.4"
16
16
  },
17
17
  "devDependencies": {
18
18
  "vitest": "^2.1.9"
package/src/overlays.js CHANGED
@@ -111,23 +111,29 @@ export class OverlayScheduler {
111
111
  }
112
112
 
113
113
  /**
114
- * Check if overlay is within its time window
114
+ * Check if overlay is within its time window.
115
+ * Delegates to ScheduleManager.isTimeActive() which handles both
116
+ * simple date ranges and recurring schedule dayparting.
117
+ * Falls back to basic date-range check if no scheduleManager is set.
118
+ *
115
119
  * @param {Object} overlay - Overlay object
116
120
  * @param {Date} now - Current time
117
121
  * @returns {boolean}
118
122
  */
119
123
  isTimeActive(overlay, now) {
120
- const from = (overlay.fromdt || overlay.fromDt) ? new Date(overlay.fromdt || overlay.fromDt) : null;
121
- const to = (overlay.todt || overlay.toDt) ? new Date(overlay.todt || overlay.toDt) : null;
122
-
123
- // Check time bounds
124
- if (from && now < from) {
125
- return false;
126
- }
127
- if (to && now > to) {
128
- return false;
124
+ if (this.scheduleManager) {
125
+ // Normalize fromDt fromdt for ScheduleManager compatibility
126
+ const normalized = { ...overlay };
127
+ if (!normalized.fromdt && normalized.fromDt) normalized.fromdt = normalized.fromDt;
128
+ if (!normalized.todt && normalized.toDt) normalized.todt = normalized.toDt;
129
+ return this.scheduleManager.isTimeActive(normalized, now);
129
130
  }
130
131
 
132
+ // Fallback: basic date-range check (no scheduleManager available)
133
+ const from = (overlay.fromdt || overlay.fromDt) ? new Date(overlay.fromdt || overlay.fromDt) : null;
134
+ const to = (overlay.todt || overlay.toDt) ? new Date(overlay.todt || overlay.toDt) : null;
135
+ if (from && now < from) return false;
136
+ if (to && now > to) return false;
131
137
  return true;
132
138
  }
133
139
 
@@ -162,6 +162,13 @@ describe('OverlayScheduler', () => {
162
162
  it('filters by geo-fence when isGeoAware', () => {
163
163
  const mockScheduleManager = {
164
164
  isWithinGeoFence: () => false,
165
+ isTimeActive: (item, now) => {
166
+ const from = item.fromdt ? new Date(item.fromdt) : null;
167
+ const to = item.todt ? new Date(item.todt) : null;
168
+ if (from && now < from) return false;
169
+ if (to && now > to) return false;
170
+ return true;
171
+ },
165
172
  };
166
173
  scheduler.setScheduleManager(mockScheduleManager);
167
174
 
package/src/schedule.js CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  import { createLogger } from '@xiboplayer/utils';
8
8
  import { evaluateCriteria } from './criteria.js';
9
- import { buildScheduleQueue, parseLayoutFile } from './timeline.js';
9
+ import { buildScheduleQueue, canSimulatedPlay, parseLayoutFile } from './timeline.js';
10
10
 
11
11
  const log = createLogger('Schedule');
12
12
 
@@ -531,41 +531,8 @@ export class ScheduleManager {
531
531
  * @returns {boolean} True if layout can play, false if exceeded limit
532
532
  */
533
533
  canPlayLayout(layoutId, maxPlaysPerHour) {
534
- // If maxPlaysPerHour is 0 or undefined, unlimited plays
535
- if (!maxPlaysPerHour || maxPlaysPerHour === 0) {
536
- return true;
537
- }
538
-
539
- const now = Date.now();
540
- const oneHourAgo = now - (60 * 60 * 1000);
541
-
542
- // Get play history for this layout
543
534
  const history = this.playHistory.get(layoutId) || [];
544
-
545
- // Filter to plays within the last hour
546
- const playsInLastHour = history.filter(timestamp => timestamp > oneHourAgo);
547
-
548
- // Check 1: Total plays in last hour must be under limit
549
- if (playsInLastHour.length >= maxPlaysPerHour) {
550
- log.info(`Layout ${layoutId} has reached max plays per hour (${playsInLastHour.length}/${maxPlaysPerHour})`);
551
- return false;
552
- }
553
-
554
- // Check 2: Minimum gap between plays for even distribution
555
- // e.g., 3/hour → 1 every 20 min, 6/hour → 1 every 10 min
556
- if (playsInLastHour.length > 0) {
557
- const minGapMs = (60 * 60 * 1000) / maxPlaysPerHour;
558
- const lastPlayTime = Math.max(...playsInLastHour);
559
- const elapsed = now - lastPlayTime;
560
-
561
- if (elapsed < minGapMs) {
562
- const remainingMin = ((minGapMs - elapsed) / 60000).toFixed(1);
563
- log.info(`Layout ${layoutId} spacing: next play in ${remainingMin} min (${playsInLastHour.length}/${maxPlaysPerHour} plays, ${Math.round(minGapMs/60000)} min gap)`);
564
- return false;
565
- }
566
- }
567
-
568
- return true;
535
+ return canSimulatedPlay(history, maxPlaysPerHour, Date.now());
569
536
  }
570
537
 
571
538
  /**
package/src/timeline.js CHANGED
@@ -112,7 +112,7 @@ function arraysEqual(a, b) {
112
112
  * @param {number} timeMs - Current simulated time in ms
113
113
  * @returns {boolean}
114
114
  */
115
- function canSimulatedPlay(history, maxPlaysPerHour, timeMs) {
115
+ export function canSimulatedPlay(history, maxPlaysPerHour, timeMs) {
116
116
  if (!maxPlaysPerHour || maxPlaysPerHour === 0) return true;
117
117
 
118
118
  const oneHourAgo = timeMs - 3600000;