@xiboplayer/schedule 0.1.0

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/docs/README.md ADDED
@@ -0,0 +1,102 @@
1
+ # @xiboplayer/schedule Documentation
2
+
3
+ **Campaign scheduling, dayparting, and priority logic.**
4
+
5
+ ## Overview
6
+
7
+ The `@xiboplayer/schedule` package provides:
8
+
9
+ - **Campaign scheduler** - Multi-campaign priority handling
10
+ - **Dayparting** - Time-based scheduling
11
+ - **Geo-scheduling** - Location-based campaigns
12
+ - **Interrupt campaigns** - High-priority content
13
+ - **Default fallback** - Graceful degradation
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install @xiboplayer/schedule
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ ```javascript
24
+ import { Scheduler } from '@xiboplayer/schedule';
25
+
26
+ const scheduler = new Scheduler({
27
+ campaigns: campaignData,
28
+ timezone: 'America/New_York'
29
+ });
30
+
31
+ // Get current layout
32
+ const layout = scheduler.getCurrentLayout();
33
+
34
+ // Check next scheduled event
35
+ const nextEvent = scheduler.getNextEvent();
36
+ ```
37
+
38
+ ## Features
39
+
40
+ ### Campaign Priority
41
+
42
+ Campaigns ordered by priority (1 = highest):
43
+ 1. Interrupt campaigns (override all)
44
+ 2. Normal campaigns (scheduled)
45
+ 3. Default layout (fallback)
46
+
47
+ ### Dayparting
48
+
49
+ Time-based scheduling:
50
+ ```javascript
51
+ {
52
+ dayOfWeek: [1, 2, 3, 4, 5], // Mon-Fri
53
+ startTime: '08:00',
54
+ endTime: '18:00'
55
+ }
56
+ ```
57
+
58
+ ### Geo-Scheduling
59
+
60
+ Location-based content:
61
+ ```javascript
62
+ {
63
+ geofence: {
64
+ latitude: 40.7128,
65
+ longitude: -74.0060,
66
+ radius: 1000 // meters
67
+ }
68
+ }
69
+ ```
70
+
71
+ ## API Reference
72
+
73
+ ### Scheduler
74
+
75
+ ```javascript
76
+ class Scheduler {
77
+ constructor(options)
78
+ getCurrentLayout()
79
+ getNextEvent()
80
+ setLocation(lat, lon)
81
+ on(event, callback)
82
+ }
83
+ ```
84
+
85
+ ### Events
86
+
87
+ - `schedule:change` - Active schedule changed
88
+ - `campaign:start` - Campaign started
89
+ - `campaign:end` - Campaign ended
90
+
91
+ ## Dependencies
92
+
93
+ - `@xiboplayer/utils` - Logger, EventEmitter
94
+
95
+ ## Related Packages
96
+
97
+ - [@xiboplayer/core](../../core/docs/) - Player orchestration
98
+
99
+ ---
100
+
101
+ **Package Version**: 1.0.0
102
+ **Last Updated**: 2026-02-10
@@ -0,0 +1,600 @@
1
+ # Xibo Campaigns and Priority System
2
+
3
+ **Last Updated:** 2026-01-30
4
+
5
+ ## Overview
6
+
7
+ This document explains how Xibo's campaign and priority system works across all three player implementations (Electron, PWA, and Arexibo). Understanding this system is crucial for proper schedule configuration and layout management.
8
+
9
+ ---
10
+
11
+ ## What Are Campaigns?
12
+
13
+ **Campaigns** are a Xibo scheduling feature that groups related layouts together as a single schedulable unit.
14
+
15
+ ### Key Concepts
16
+
17
+ - **Campaign** = A collection of layouts with shared scheduling attributes
18
+ - **Priority Level** = Applied at the campaign level (not individual layouts)
19
+ - **Layout Cycling** = All layouts within a campaign cycle in sequence
20
+ - **Competition** = Campaigns compete with each other and standalone layouts based on priority
21
+
22
+ ### Why Use Campaigns?
23
+
24
+ Campaigns solve the problem of managing related content that should play together:
25
+
26
+ **Without Campaigns:**
27
+ - Schedule 10 individual breakfast menu layouts
28
+ - Each needs identical time windows and priorities
29
+ - Changes require updating 10 separate schedule entries
30
+
31
+ **With Campaigns:**
32
+ - Group 10 breakfast layouts into a "Breakfast Menu" campaign
33
+ - Schedule the campaign once with shared priority and time window
34
+ - Changes affect all layouts at once
35
+
36
+ ---
37
+
38
+ ## Priority System Explained
39
+
40
+ ### How Priority Works
41
+
42
+ Priority determines which layouts (or campaigns) play when multiple schedules overlap.
43
+
44
+ #### Priority Rules
45
+
46
+ 1. **Higher Number Wins**: Priority 10 beats priority 5
47
+ 2. **Campaign-Level Priority**: All layouts in a campaign inherit the campaign's priority
48
+ 3. **Same Priority = All Play**: Multiple items with the same priority all display (cycling)
49
+ 4. **No Priority = Priority 0**: Default priority if not specified
50
+
51
+ #### Priority Range
52
+
53
+ - **Type**: Integer (positive or negative)
54
+ - **Common Range**: 0-100
55
+ - **Special Values**:
56
+ - `0`: Default/lowest priority (normal content)
57
+ - `10`: Standard scheduled content
58
+ - `100`: Urgent/interrupt content (alerts, emergencies)
59
+
60
+ ---
61
+
62
+ ## XML Schedule Format
63
+
64
+ ### Campaign Structure
65
+
66
+ ```xml
67
+ <schedule>
68
+ <!-- Default layout (fallback when nothing scheduled) -->
69
+ <default file="1" />
70
+
71
+ <!-- Campaign: Group of layouts with shared attributes -->
72
+ <campaign id="10" priority="10" fromdt="2026-01-30 08:00:00" todt="2026-01-30 17:00:00">
73
+ <layout file="100" />
74
+ <layout file="101" />
75
+ <layout file="102" />
76
+ </campaign>
77
+
78
+ <!-- Standalone layout (not in a campaign) -->
79
+ <layout file="200" priority="5" fromdt="2026-01-30 00:00:00" todt="2026-01-30 23:59:59" />
80
+ </schedule>
81
+ ```
82
+
83
+ ### Campaign Attributes
84
+
85
+ | Attribute | Description | Required | Example |
86
+ |-----------|-------------|----------|---------|
87
+ | `id` | Unique campaign identifier | Yes | `id="10"` |
88
+ | `priority` | Priority level (integer) | No (default: 0) | `priority="10"` |
89
+ | `fromdt` | Start date/time | Yes | `fromdt="2026-01-30 08:00:00"` |
90
+ | `todt` | End date/time | Yes | `todt="2026-01-30 17:00:00"` |
91
+ | `scheduleid` | CMS schedule ID | No | `scheduleid="123"` |
92
+
93
+ ### Standalone Layout Attributes
94
+
95
+ | Attribute | Description | Required | Example |
96
+ |-----------|-------------|----------|---------|
97
+ | `file` | Layout ID | Yes | `file="200"` |
98
+ | `priority` | Priority level (integer) | No (default: 0) | `priority="5"` |
99
+ | `fromdt` | Start date/time | Yes | `fromdt="2026-01-30 00:00:00"` |
100
+ | `todt` | End date/time | Yes | `todt="2026-01-30 23:59:59"` |
101
+ | `scheduleid` | CMS schedule ID | No | `scheduleid="456"` |
102
+
103
+ ---
104
+
105
+ ## Priority Resolution Examples
106
+
107
+ ### Example 1: Campaign Beats Standalone
108
+
109
+ **Schedule:**
110
+ ```xml
111
+ <campaign id="1" priority="10" fromdt="2026-01-30 08:00:00" todt="2026-01-30 17:00:00">
112
+ <layout file="100" />
113
+ <layout file="101" />
114
+ </campaign>
115
+ <layout file="200" priority="5" fromdt="2026-01-30 00:00:00" todt="2026-01-30 23:59:59" />
116
+ ```
117
+
118
+ **At 12:00 PM (both active):**
119
+ - Campaign priority: 10
120
+ - Standalone priority: 5
121
+ - **Result**: Displays layouts 100, 101 (campaign wins)
122
+
123
+ ---
124
+
125
+ ### Example 2: Multiple Same-Priority Campaigns
126
+
127
+ **Schedule:**
128
+ ```xml
129
+ <campaign id="1" priority="10" fromdt="2026-01-30 08:00:00" todt="2026-01-30 17:00:00">
130
+ <layout file="100" />
131
+ <layout file="101" />
132
+ </campaign>
133
+ <campaign id="2" priority="10" fromdt="2026-01-30 08:00:00" todt="2026-01-30 17:00:00">
134
+ <layout file="200" />
135
+ <layout file="201" />
136
+ </campaign>
137
+ ```
138
+
139
+ **At 12:00 PM (both active):**
140
+ - Both campaigns at priority 10
141
+ - **Result**: Displays layouts 100, 101, 200, 201 (all layouts cycle)
142
+
143
+ ---
144
+
145
+ ### Example 3: Mixed Campaigns and Standalone
146
+
147
+ **Schedule:**
148
+ ```xml
149
+ <campaign id="1" priority="10" fromdt="2026-01-30 08:00:00" todt="2026-01-30 17:00:00">
150
+ <layout file="100" />
151
+ <layout file="101" />
152
+ </campaign>
153
+ <layout file="200" priority="10" fromdt="2026-01-30 08:00:00" todt="2026-01-30 17:00:00" />
154
+ <layout file="300" priority="5" fromdt="2026-01-30 00:00:00" todt="2026-01-30 23:59:59" />
155
+ ```
156
+
157
+ **At 12:00 PM:**
158
+ - Campaign 1: priority 10 (layouts 100, 101)
159
+ - Standalone 200: priority 10
160
+ - Standalone 300: priority 5
161
+ - **Result**: Displays layouts 100, 101, 200 (priority 10 wins, all shown)
162
+
163
+ ---
164
+
165
+ ### Example 4: Time Window Filtering
166
+
167
+ **Schedule:**
168
+ ```xml
169
+ <campaign id="1" priority="10" fromdt="2026-01-30 08:00:00" todt="2026-01-30 12:00:00">
170
+ <layout file="100" /> <!-- Morning campaign -->
171
+ </campaign>
172
+ <campaign id="2" priority="10" fromdt="2026-01-30 12:00:01" todt="2026-01-30 17:00:00">
173
+ <layout file="200" /> <!-- Afternoon campaign -->
174
+ </campaign>
175
+ ```
176
+
177
+ **At 10:00 AM:**
178
+ - Campaign 1 active (08:00-12:00)
179
+ - **Result**: Displays layout 100
180
+
181
+ **At 2:00 PM:**
182
+ - Campaign 2 active (12:00-17:00)
183
+ - **Result**: Displays layout 200
184
+
185
+ ---
186
+
187
+ ### Example 5: Interrupt Content
188
+
189
+ **Schedule:**
190
+ ```xml
191
+ <campaign id="1" priority="10" fromdt="2026-01-30 00:00:00" todt="2026-01-30 23:59:59">
192
+ <layout file="100" /> <!-- Regular content -->
193
+ </campaign>
194
+ <layout file="999" priority="100" fromdt="2026-01-30 14:00:00" todt="2026-01-30 14:15:00" />
195
+ ```
196
+
197
+ **At 1:00 PM:**
198
+ - Campaign 1 active (priority 10)
199
+ - **Result**: Displays layout 100
200
+
201
+ **At 2:05 PM:**
202
+ - Campaign 1 still active (priority 10)
203
+ - Emergency layout 999 active (priority 100)
204
+ - **Result**: Displays layout 999 (interrupt content overrides)
205
+
206
+ **At 2:20 PM:**
207
+ - Campaign 1 active (priority 10)
208
+ - Emergency layout 999 expired
209
+ - **Result**: Displays layout 100 (resumes normal content)
210
+
211
+ ---
212
+
213
+ ## Real-World Use Cases
214
+
215
+ ### Restaurant Menu Board
216
+
217
+ **Scenario:** Different menus for breakfast, lunch, dinner
218
+
219
+ ```xml
220
+ <schedule>
221
+ <default file="1" /> <!-- "We're Closed" layout -->
222
+
223
+ <!-- Breakfast: Mon-Fri 6am-11am -->
224
+ <campaign id="10" priority="10" fromdt="2026-01-30 06:00:00" todt="2026-01-30 11:00:00">
225
+ <layout file="100" /> <!-- Breakfast Page 1 -->
226
+ <layout file="101" /> <!-- Breakfast Page 2 -->
227
+ <layout file="102" /> <!-- Breakfast Specials -->
228
+ </campaign>
229
+
230
+ <!-- Lunch: Mon-Fri 11am-3pm -->
231
+ <campaign id="11" priority="10" fromdt="2026-01-30 11:00:00" todt="2026-01-30 15:00:00">
232
+ <layout file="200" /> <!-- Lunch Menu -->
233
+ <layout file="201" /> <!-- Daily Specials -->
234
+ </campaign>
235
+
236
+ <!-- Dinner: Mon-Fri 3pm-10pm -->
237
+ <campaign id="12" priority="10" fromdt="2026-01-30 15:00:00" todt="2026-01-30 22:00:00">
238
+ <layout file="300" /> <!-- Dinner Menu -->
239
+ <layout file="301" /> <!-- Wine List -->
240
+ </campaign>
241
+
242
+ <!-- Special Promotion: Overrides all (emergency interrupt) -->
243
+ <layout file="999" priority="100" fromdt="2026-01-30 17:00:00" todt="2026-01-30 18:00:00" />
244
+ </schedule>
245
+ ```
246
+
247
+ **Timeline:**
248
+ - **6:00 AM - 11:00 AM**: Breakfast campaign (layouts 100, 101, 102 cycle)
249
+ - **11:00 AM - 3:00 PM**: Lunch campaign (layouts 200, 201 cycle)
250
+ - **3:00 PM - 10:00 PM**: Dinner campaign (layouts 300, 301 cycle)
251
+ - **5:00 PM - 6:00 PM**: Happy hour promotion (layout 999 interrupts dinner campaign)
252
+ - **All other times**: Default "We're Closed" layout
253
+
254
+ ---
255
+
256
+ ### Retail Store Displays
257
+
258
+ **Scenario:** Regular content + promotional overrides
259
+
260
+ ```xml
261
+ <schedule>
262
+ <default file="1" /> <!-- Store logo/hours -->
263
+
264
+ <!-- Regular store content (low priority) -->
265
+ <campaign id="1" priority="5" fromdt="2026-01-30 00:00:00" todt="2026-01-31 00:00:00">
266
+ <layout file="100" /> <!-- Product showcase 1 -->
267
+ <layout file="101" /> <!-- Product showcase 2 -->
268
+ <layout file="102" /> <!-- Brand story -->
269
+ </campaign>
270
+
271
+ <!-- Tuesday sale (higher priority, overrides regular) -->
272
+ <campaign id="2" priority="10" fromdt="2026-01-30 09:00:00" todt="2026-01-30 21:00:00">
273
+ <layout file="200" /> <!-- Sale announcement -->
274
+ <layout file="201" /> <!-- Featured deals -->
275
+ </campaign>
276
+
277
+ <!-- Flash sale announcement (highest priority, interrupts everything) -->
278
+ <layout file="999" priority="100" fromdt="2026-01-30 12:00:00" todt="2026-01-30 13:00:00" />
279
+ </schedule>
280
+ ```
281
+
282
+ **Timeline:**
283
+ - **12:00 AM - 9:00 AM**: Regular content (layouts 100, 101, 102)
284
+ - **9:00 AM - 12:00 PM**: Tuesday sale (layouts 200, 201 override regular)
285
+ - **12:00 PM - 1:00 PM**: Flash sale (layout 999 interrupts Tuesday sale)
286
+ - **1:00 PM - 9:00 PM**: Tuesday sale resumes (layouts 200, 201)
287
+ - **9:00 PM - 12:00 AM**: Regular content resumes (layouts 100, 101, 102)
288
+
289
+ ---
290
+
291
+ ### Corporate Lobby
292
+
293
+ **Scenario:** News + scheduled events
294
+
295
+ ```xml
296
+ <schedule>
297
+ <default file="1" /> <!-- Company logo -->
298
+
299
+ <!-- Always-on company news (low priority) -->
300
+ <campaign id="1" priority="5" fromdt="2026-01-30 08:00:00" todt="2026-01-30 18:00:00">
301
+ <layout file="100" /> <!-- News feed -->
302
+ <layout file="101" /> <!-- Employee spotlights -->
303
+ <layout file="102" /> <!-- Company metrics -->
304
+ </campaign>
305
+
306
+ <!-- Weekly all-hands meeting (interrupts news) -->
307
+ <layout file="200" priority="50" fromdt="2026-01-30 14:00:00" todt="2026-01-30 15:00:00" />
308
+
309
+ <!-- Emergency alert (highest priority) -->
310
+ <layout file="999" priority="100" fromdt="2026-01-30 10:00:00" todt="2026-01-30 10:15:00" />
311
+ </schedule>
312
+ ```
313
+
314
+ **Timeline:**
315
+ - **8:00 AM - 2:00 PM**: Company news (layouts 100, 101, 102 cycle)
316
+ - **10:00 AM - 10:15 AM**: Emergency alert (layout 999 interrupts news)
317
+ - **2:00 PM - 3:00 PM**: All-hands meeting (layout 200 overrides news)
318
+ - **3:00 PM - 6:00 PM**: Company news resumes
319
+
320
+ ---
321
+
322
+ ## Implementation Status
323
+
324
+ ### Feature Parity Matrix
325
+
326
+ | Feature | Electron | PWA | Arexibo | Status |
327
+ |---------|----------|-----|---------|--------|
328
+ | Campaign XML parsing | ✅ | ✅ | ✅ | Complete |
329
+ | Campaign-level priority | ✅ | ✅ | ✅ | Complete |
330
+ | Layout cycling within campaign | ✅ | ✅ | ✅ | Complete |
331
+ | Mixed campaigns + standalone | ✅ | ✅ | ✅ | Complete |
332
+ | Time window filtering | ✅ | ✅ | ✅ | Complete |
333
+ | Multiple same-priority campaigns | ✅ | ✅ | ✅ | Complete |
334
+ | Backward compatibility | ✅ | ✅ | ✅ | Complete |
335
+
336
+ ### Implementation Details
337
+
338
+ #### PWA Core
339
+ - **Branch**: `feature/pwa-campaigns`
340
+ - **Files**: `packages/core/src/xmds.js`, `packages/core/src/schedule.js`
341
+ - **Tests**: 6 comprehensive test cases
342
+ - **Status**: Ready for merge
343
+
344
+ #### Arexibo
345
+ - **Branch**: `feature/arx-dayparting` (includes campaigns)
346
+ - **Files**: `src/schedule.rs`
347
+ - **Tests**: 9 campaign-specific tests
348
+ - **Status**: Ready for merge
349
+
350
+ #### Electron
351
+ - **Status**: Already implemented (baseline reference)
352
+
353
+ ---
354
+
355
+ ## Technical Details
356
+
357
+ ### Scheduling Algorithm
358
+
359
+ All three players use the same priority resolution algorithm:
360
+
361
+ ```
362
+ function getCurrentLayouts(currentDateTime):
363
+ 1. Filter all schedule items (campaigns + standalone) by time window
364
+ → Keep only items where: fromdt <= now <= todt
365
+
366
+ 2. Find maximum priority among active items
367
+ → maxPriority = max(item.priority for all active items)
368
+
369
+ 3. Select all items matching maximum priority
370
+ → winners = items where priority == maxPriority
371
+
372
+ 4. Collect layouts from winning items
373
+ → For campaigns: add all layouts in campaign
374
+ → For standalone: add the layout
375
+
376
+ 5. Return collected layouts
377
+ → If no layouts: return default layout
378
+ ```
379
+
380
+ ### Layout Cycling
381
+
382
+ When multiple layouts are selected, they cycle with:
383
+
384
+ 1. **Duration**: Each layout's configured duration (from layout definition)
385
+ 2. **Order**: Maintains XML order within campaigns
386
+ 3. **Seamless**: Transitions between layouts based on player settings
387
+ 4. **Repeat**: Cycles indefinitely until schedule changes
388
+
389
+ ---
390
+
391
+ ## Configuration Best Practices
392
+
393
+ ### Priority Guidelines
394
+
395
+ **Recommended Priority Tiers:**
396
+
397
+ | Priority Range | Use Case | Example |
398
+ |----------------|----------|---------|
399
+ | 0 | Default/fallback content | Idle screens, logos |
400
+ | 1-5 | Low-priority background content | Generic ads, filler content |
401
+ | 10 | Standard scheduled content | Normal operations, menus |
402
+ | 20-50 | Important scheduled content | Special events, meetings |
403
+ | 75-90 | High-priority overrides | Alerts, announcements |
404
+ | 100+ | Emergency interrupts | Fire alarms, emergencies |
405
+
406
+ ### Time Window Guidelines
407
+
408
+ 1. **No Gaps**: Ensure continuous coverage with default layout fallback
409
+ 2. **No Overlaps**: Use priority to handle intentional overlaps
410
+ 3. **Timezone Aware**: All times in player's local timezone
411
+ 4. **Boundary Handling**: End time is inclusive (todt="17:00:00" includes 17:00)
412
+
413
+ ### Campaign Organization
414
+
415
+ **Good Campaign Structure:**
416
+ ```xml
417
+ <!-- Logical grouping: Related content together -->
418
+ <campaign id="morning" priority="10" fromdt="..." todt="...">
419
+ <layout file="100" /> <!-- Morning welcome -->
420
+ <layout file="101" /> <!-- Morning news -->
421
+ <layout file="102" /> <!-- Morning schedule -->
422
+ </campaign>
423
+ ```
424
+
425
+ **Poor Campaign Structure:**
426
+ ```xml
427
+ <!-- Unrelated content mixed together -->
428
+ <campaign id="random" priority="10" fromdt="..." todt="...">
429
+ <layout file="100" /> <!-- Welcome screen -->
430
+ <layout file="999" /> <!-- Emergency alert -->
431
+ <layout file="200" /> <!-- Lunch menu -->
432
+ </campaign>
433
+ ```
434
+
435
+ ---
436
+
437
+ ## Troubleshooting
438
+
439
+ ### Common Issues
440
+
441
+ #### Issue: "Lower priority content showing instead of higher"
442
+
443
+ **Cause**: Time window mismatch
444
+
445
+ **Check:**
446
+ 1. Verify both items are active at current time
447
+ 2. Check system clock on player
448
+ 3. Confirm timezone matches schedule
449
+
450
+ #### Issue: "Campaign layouts not cycling"
451
+
452
+ **Cause**: Empty campaign or single layout
453
+
454
+ **Check:**
455
+ 1. Verify campaign has multiple layouts in XML
456
+ 2. Check layout durations are set correctly
457
+ 3. Ensure layouts are valid and downloaded
458
+
459
+ #### Issue: "All layouts showing at once instead of cycling"
460
+
461
+ **Cause**: Player misconfiguration (not a campaign issue)
462
+
463
+ **Check:**
464
+ 1. Player cycling settings
465
+ 2. Region configuration
466
+ 3. Xibo player version compatibility
467
+
468
+ #### Issue: "Standalone layout never shows"
469
+
470
+ **Cause**: Another item always has higher priority
471
+
472
+ **Check:**
473
+ 1. Compare priorities of all schedule items
474
+ 2. Verify time windows don't overlap with higher priority items
475
+ 3. Add default layout as fallback
476
+
477
+ ---
478
+
479
+ ## Migration from Non-Campaign Schedules
480
+
481
+ ### Converting Standalone Layouts to Campaigns
482
+
483
+ **Before (Standalone):**
484
+ ```xml
485
+ <layout file="100" priority="10" fromdt="2026-01-30 08:00:00" todt="2026-01-30 17:00:00" />
486
+ <layout file="101" priority="10" fromdt="2026-01-30 08:00:00" todt="2026-01-30 17:00:00" />
487
+ <layout file="102" priority="10" fromdt="2026-01-30 08:00:00" todt="2026-01-30 17:00:00" />
488
+ ```
489
+
490
+ **After (Campaign):**
491
+ ```xml
492
+ <campaign id="1" priority="10" fromdt="2026-01-30 08:00:00" todt="2026-01-30 17:00:00">
493
+ <layout file="100" />
494
+ <layout file="101" />
495
+ <layout file="102" />
496
+ </campaign>
497
+ ```
498
+
499
+ **Benefits:**
500
+ - ✅ Single schedule entry instead of three
501
+ - ✅ Guaranteed same priority and time window
502
+ - ✅ Easier to update all layouts at once
503
+
504
+ ### Backward Compatibility
505
+
506
+ All players maintain full backward compatibility:
507
+
508
+ - ✅ Old schedules without campaigns continue working
509
+ - ✅ Mixed old + new schedules supported
510
+ - ✅ No breaking changes to existing functionality
511
+
512
+ ---
513
+
514
+ ## References
515
+
516
+ ### Xibo CMS Documentation
517
+ - [Xibo Manual - Scheduling](https://xibosignage.com/manual/en/scheduling.html)
518
+ - [Xibo Manual - Campaigns](https://xibosignage.com/manual/en/media_module_campaigns.html)
519
+
520
+ ### Implementation Branches
521
+ - **PWA**: `feature/pwa-campaigns` in [xibo_players repo](https://github.com/linuxnow/xibo_players)
522
+ - **Arexibo**: `feature/arx-dayparting` in [arexibo repo](https://github.com/linuxnow/arexibo)
523
+
524
+ ### Related Documentation
525
+ - `TRANSITIONS.md` - Layout transition effects
526
+ - `DAYPARTING.md` - Recurring schedule patterns
527
+ - `XIBO_FEATURE_COMPARISON.md` - Cross-player feature matrix
528
+
529
+ ---
530
+
531
+ ## Appendix: Complete Example
532
+
533
+ ### Multi-Day Restaurant Schedule
534
+
535
+ ```xml
536
+ <schedule>
537
+ <!-- Fallback: Closed -->
538
+ <default file="1" />
539
+
540
+ <!-- Monday-Friday Breakfast (6am-11am) -->
541
+ <campaign id="weekday_breakfast" priority="10"
542
+ fromdt="2026-01-27 06:00:00" todt="2026-01-27 11:00:00">
543
+ <layout file="100" />
544
+ <layout file="101" />
545
+ <layout file="102" />
546
+ </campaign>
547
+
548
+ <!-- Monday-Friday Lunch (11am-3pm) -->
549
+ <campaign id="weekday_lunch" priority="10"
550
+ fromdt="2026-01-27 11:00:00" todt="2026-01-27 15:00:00">
551
+ <layout file="200" />
552
+ <layout file="201" />
553
+ </campaign>
554
+
555
+ <!-- Monday-Friday Dinner (3pm-10pm) -->
556
+ <campaign id="weekday_dinner" priority="10"
557
+ fromdt="2026-01-27 15:00:00" todt="2026-01-27 22:00:00">
558
+ <layout file="300" />
559
+ <layout file="301" />
560
+ </campaign>
561
+
562
+ <!-- Weekend Brunch (9am-3pm) -->
563
+ <campaign id="weekend_brunch" priority="10"
564
+ fromdt="2026-02-01 09:00:00" todt="2026-02-01 15:00:00">
565
+ <layout file="400" />
566
+ <layout file="401" />
567
+ <layout file="402" />
568
+ </campaign>
569
+
570
+ <!-- Weekend Dinner (3pm-10pm) -->
571
+ <campaign id="weekend_dinner" priority="10"
572
+ fromdt="2026-02-01 15:00:00" todt="2026-02-01 22:00:00">
573
+ <layout file="500" />
574
+ <layout file="501" />
575
+ </campaign>
576
+
577
+ <!-- Special: Valentine's Day Override -->
578
+ <campaign id="valentines" priority="50"
579
+ fromdt="2026-02-14 15:00:00" todt="2026-02-14 22:00:00">
580
+ <layout file="600" /> <!-- Valentine's Special Menu -->
581
+ <layout file="601" /> <!-- Valentine's Desserts -->
582
+ </campaign>
583
+
584
+ <!-- Emergency: Power Outage Notice -->
585
+ <layout file="999" priority="100"
586
+ fromdt="2026-01-30 18:00:00" todt="2026-01-30 19:00:00" />
587
+ </schedule>
588
+ ```
589
+
590
+ This schedule demonstrates:
591
+ - ✅ Multiple campaigns for different meal times
592
+ - ✅ Weekday vs weekend content separation
593
+ - ✅ Special event overrides (Valentine's Day)
594
+ - ✅ Emergency interrupt capability
595
+ - ✅ Proper priority tier usage
596
+ - ✅ Comprehensive time coverage with fallback
597
+
598
+ ---
599
+
600
+ **End of Document**