@raydiant/playlist-window-manager 0.21.1 → 0.21.3

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.
@@ -1,1017 +0,0 @@
1
- "use strict";
2
- var __extends = (this && this.__extends) || (function () {
3
- var extendStatics = function (d, b) {
4
- extendStatics = Object.setPrototypeOf ||
5
- ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
- function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
7
- return extendStatics(d, b);
8
- };
9
- return function (d, b) {
10
- if (typeof b !== "function" && b !== null)
11
- throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
12
- extendStatics(d, b);
13
- function __() { this.constructor = d; }
14
- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15
- };
16
- })();
17
- var __assign = (this && this.__assign) || function () {
18
- __assign = Object.assign || function(t) {
19
- for (var s, i = 1, n = arguments.length; i < n; i++) {
20
- s = arguments[i];
21
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
22
- t[p] = s[p];
23
- }
24
- return t;
25
- };
26
- return __assign.apply(this, arguments);
27
- };
28
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
29
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
30
- return new (P || (P = Promise))(function (resolve, reject) {
31
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
32
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
33
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
34
- step((generator = generator.apply(thisArg, _arguments || [])).next());
35
- });
36
- };
37
- var __generator = (this && this.__generator) || function (thisArg, body) {
38
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
39
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
40
- function verb(n) { return function (v) { return step([n, v]); }; }
41
- function step(op) {
42
- if (f) throw new TypeError("Generator is already executing.");
43
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
44
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
45
- if (y = 0, t) op = [op[0] & 2, t.value];
46
- switch (op[0]) {
47
- case 0: case 1: t = op; break;
48
- case 4: _.label++; return { value: op[1], done: false };
49
- case 5: _.label++; y = op[1]; op = [0]; continue;
50
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
51
- default:
52
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
53
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
54
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
55
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
56
- if (t[2]) _.ops.pop();
57
- _.trys.pop(); continue;
58
- }
59
- op = body.call(thisArg, _);
60
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
61
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
62
- }
63
- };
64
- var __importDefault = (this && this.__importDefault) || function (mod) {
65
- return (mod && mod.__esModule) ? mod : { "default": mod };
66
- };
67
- Object.defineProperty(exports, "__esModule", { value: true });
68
- var uuid_1 = require("uuid");
69
- var eventemitter3_1 = __importDefault(require("eventemitter3"));
70
- var PresentationWindow_1 = __importDefault(require("./PresentationWindow"));
71
- var WindowUnresponsiveError_1 = __importDefault(require("./WindowUnresponsiveError"));
72
- var WindowTimeoutError_1 = __importDefault(require("./WindowTimeoutError"));
73
- var WindowLoadError_1 = __importDefault(require("./WindowLoadError"));
74
- // Wait at least 3 seconds before restarting or moving onto the next window
75
- // to prevent log spam causing devices to become unresponsive.
76
- var minTimeBetweenCompletes = 3000;
77
- var PlaylistWindowManager = /** @class */ (function (_super) {
78
- __extends(PlaylistWindowManager, _super);
79
- function PlaylistWindowManager(options) {
80
- var _this = _super.call(this) || this;
81
- _this.options = options;
82
- _this.currentPresentation = null;
83
- _this.nextPresentation = null;
84
- _this.overrideNextPresentation = null;
85
- _this.currentWindow = null;
86
- _this.nextWindow = null;
87
- _this.hasPendingInterrupt = false;
88
- _this.ruleEngine = null;
89
- _this.state = null;
90
- _this.renderer = null;
91
- _this.restartCurrentWindowOnEnd = false;
92
- _this.shouldHardRestart = false;
93
- _this.currentWindowError = null;
94
- _this.interruptCheckTimeout = null;
95
- _this.currentPresentationCompleteTimeout = null;
96
- _this.lastCompleteAt = null;
97
- _this.forceMute = false;
98
- _this.isFocused = false;
99
- _this.workerState = {};
100
- _this.handleEnableInterruptLock = function () {
101
- var onEnableInterruptLock = _this.options.onEnableInterruptLock;
102
- if (onEnableInterruptLock) {
103
- onEnableInterruptLock();
104
- }
105
- };
106
- _this.handleDisableInterruptLock = function () {
107
- var onDisableInterruptLock = _this.options.onDisableInterruptLock;
108
- if (onDisableInterruptLock) {
109
- onDisableInterruptLock();
110
- }
111
- if (_this.hasPendingInterrupt) {
112
- _this.endCurrentPresentation();
113
- }
114
- };
115
- _this.handleAnalyticsEvent = function (event) {
116
- // Emit the event on the current window. Only the current window should
117
- // send analytics events since the next window is not visible.
118
- _this.emitCurrentWindowEvent('window_analytics_event', event);
119
- };
120
- _this.handleCurrentPresentationComplete = function () { return __awaiter(_this, void 0, void 0, function () {
121
- var logger, isThrottled, now, timeSinceLastComplete, delay, _a, next, preview, nextPreviewPresentationId;
122
- var _this = this;
123
- return __generator(this, function (_b) {
124
- switch (_b.label) {
125
- case 0:
126
- logger = this.options.logger;
127
- isThrottled = false;
128
- if (this.lastCompleteAt !== null) {
129
- now = new Date();
130
- timeSinceLastComplete = +now - +this.lastCompleteAt;
131
- if (timeSinceLastComplete < minTimeBetweenCompletes) {
132
- isThrottled = true;
133
- // Throttle presentation complete handler if we have not throttled already.
134
- if (this.currentPresentationCompleteTimeout === null) {
135
- delay = minTimeBetweenCompletes - timeSinceLastComplete + 1;
136
- logger.warn("Throttling presentation complete handler for ".concat(delay, "ms because it was called again in less than ").concat(minTimeBetweenCompletes, "ms"));
137
- this.currentPresentationCompleteTimeout = setTimeout(function () {
138
- _this.currentPresentationCompleteTimeout = null;
139
- _this.handleCurrentPresentationComplete();
140
- }, delay);
141
- }
142
- else {
143
- logger.warn("Skipping presentation complete because it is currently throttled");
144
- }
145
- }
146
- }
147
- // Don't run presentation complete handler when throttled.
148
- if (isThrottled) {
149
- return [2 /*return*/];
150
- }
151
- // Not throttled, update lastCompleteAt and run presentation complete handler.
152
- this.lastCompleteAt = new Date();
153
- // Emit presentation end events.
154
- if (this.currentWindowError) {
155
- this.emitCurrentWindowErrorEvent('window_end_error', this.currentWindowError);
156
- }
157
- else {
158
- this.emitCurrentWindowEvent('window_end_success');
159
- }
160
- // Clear current window error flag.
161
- this.currentWindowError = null;
162
- if (!(!this.isLocked() &&
163
- !this.restartCurrentWindowOnEnd &&
164
- this.currentWindow &&
165
- this.nextWindow)) return [3 /*break*/, 5];
166
- if (!this.nextWindow.isReady()) return [3 /*break*/, 2];
167
- return [4 /*yield*/, this.swapWindows()];
168
- case 1:
169
- _b.sent();
170
- return [3 /*break*/, 4];
171
- case 2:
172
- // The next window isn't ready yet, restart the current presentation.
173
- // restartCurrentWindow depends on this.shouldHardRestart
174
- return [4 /*yield*/, this.restartCurrentWindow()];
175
- case 3:
176
- // The next window isn't ready yet, restart the current presentation.
177
- // restartCurrentWindow depends on this.shouldHardRestart
178
- _b.sent();
179
- _b.label = 4;
180
- case 4: return [3 /*break*/, 12];
181
- case 5:
182
- if (!this.currentWindow) return [3 /*break*/, 9];
183
- _a = this.evalRuleEngine(), next = _a.next, preview = _a.preview;
184
- nextPreviewPresentationId = preview.presentationId;
185
- if (!!next.presentationId) return [3 /*break*/, 6];
186
- // If next.presentationId is null after evaluating the rule engine that means
187
- // nothing should be playing, remove the current window.
188
- this.removeCurrentWindow();
189
- return [3 /*break*/, 8];
190
- case 6:
191
- // Restart the current presentation when:
192
- // - There's only one presentation in the playlist (no preload)
193
- // - The playlist is locked or paused
194
- // - There is a still a presentation that should be
195
- // NOTE: restartCurrentWindow depends on this.shouldHardRestart
196
- return [4 /*yield*/, this.restartCurrentWindow()];
197
- case 7:
198
- // Restart the current presentation when:
199
- // - There's only one presentation in the playlist (no preload)
200
- // - The playlist is locked or paused
201
- // - There is a still a presentation that should be
202
- // NOTE: restartCurrentWindow depends on this.shouldHardRestart
203
- _b.sent();
204
- // Check to see if there is a presentation to preload. This can happen if
205
- // if state has changed since initial load (ie. publish).
206
- if (this.shouldPreload(nextPreviewPresentationId)) {
207
- this.nextPresentation = preview;
208
- this.preloadNextWindow();
209
- }
210
- _b.label = 8;
211
- case 8: return [3 /*break*/, 12];
212
- case 9:
213
- if (!this.nextWindow) return [3 /*break*/, 11];
214
- // There is no current window but there is a next window. Swap to the next window.
215
- // This can happen if updating the rule engine from an empty playlist to a non-empty playlist.
216
- return [4 /*yield*/, this.swapWindows()];
217
- case 10:
218
- // There is no current window but there is a next window. Swap to the next window.
219
- // This can happen if updating the rule engine from an empty playlist to a non-empty playlist.
220
- _b.sent();
221
- return [3 /*break*/, 12];
222
- case 11:
223
- logger.warn("Presentation complete received but there's no current window.");
224
- _b.label = 12;
225
- case 12:
226
- // Clear hard restart after running complete handler. This could be true when the current window errors
227
- // but if there's another presentation to move on to we won't restart it but we still need to clear it
228
- // so we don't hard restart the new current window when we shouldn't.
229
- this.shouldHardRestart = false;
230
- return [2 /*return*/];
231
- }
232
- });
233
- }); };
234
- _this.handleCurrentPresentationError = function (error) { return __awaiter(_this, void 0, void 0, function () {
235
- var logger, isWindowError;
236
- return __generator(this, function (_a) {
237
- logger = this.options.logger;
238
- logger.warn("Current presentation had an error, move to next presentation or hard restart current window");
239
- isWindowError = error instanceof WindowUnresponsiveError_1.default ||
240
- error instanceof WindowTimeoutError_1.default ||
241
- error instanceof WindowLoadError_1.default;
242
- if (isWindowError) {
243
- // Error is window error, hard restart the window if it's the only presentation in the playlist.
244
- this.shouldHardRestart = true;
245
- }
246
- // Flag the current presentation as having errored.
247
- this.currentWindowError = error;
248
- this.handleCurrentPresentationComplete();
249
- return [2 /*return*/];
250
- });
251
- }); };
252
- _this.handleNextPresentationError = function (error) { return __awaiter(_this, void 0, void 0, function () {
253
- var logger, preview, nextPreviewPresentationId;
254
- return __generator(this, function (_a) {
255
- switch (_a.label) {
256
- case 0:
257
- logger = this.options.logger;
258
- // Emit event that preload has failed.
259
- this.emitNextWindowErrorEvent('window_preload_error', error);
260
- logger.warn("Next presentation had an error, preload the next presentation");
261
- preview = this.evalRuleEngine().preview;
262
- nextPreviewPresentationId = preview.presentationId;
263
- if (!this.shouldPreload(nextPreviewPresentationId)) return [3 /*break*/, 2];
264
- // Remove the window before preloading a new one.
265
- return [4 /*yield*/, this.removeNextWindow()];
266
- case 1:
267
- // Remove the window before preloading a new one.
268
- _a.sent();
269
- // Calling removeNextWindow will set this.nextPresentation to null so we need to
270
- // set after but before preloadNextWindow.
271
- this.nextPresentation = preview;
272
- this.preloadNextWindow();
273
- return [3 /*break*/, 4];
274
- case 2: return [4 /*yield*/, this.removeNextWindow()];
275
- case 3:
276
- _a.sent();
277
- _a.label = 4;
278
- case 4: return [2 /*return*/];
279
- }
280
- });
281
- }); };
282
- _this.checkPreviewAction = function () { return __awaiter(_this, void 0, void 0, function () {
283
- var logger, preview;
284
- return __generator(this, function (_a) {
285
- switch (_a.label) {
286
- case 0:
287
- logger = this.options.logger;
288
- if (!this.ruleEngine) {
289
- return [2 /*return*/];
290
- }
291
- preview = this.ruleEngine.previewNext();
292
- if (!this.shouldPreload(preview.presentationId)) return [3 /*break*/, 3];
293
- logger.info("Preview check replacing preloaded presentation '".concat(this.nextPresentationId(), "' with new presentation '").concat(preview.presentationId, "'"));
294
- return [4 /*yield*/, this.removeNextWindow()];
295
- case 1:
296
- _a.sent();
297
- this.nextPresentation = preview;
298
- return [4 /*yield*/, this.preloadNextWindow()];
299
- case 2:
300
- _a.sent();
301
- _a.label = 3;
302
- case 3:
303
- if (preview.shouldInterrupt) {
304
- logger.info("Interrupting current presentation with '".concat(preview.presentationId, "'"));
305
- this.registerInterrupt();
306
- }
307
- return [2 /*return*/];
308
- }
309
- });
310
- }); };
311
- _this.ruleEngine = options.ruleEngine;
312
- _this.state = options.state;
313
- _this.bounds = options.bounds;
314
- _this.themeOverride = options.themeOverride;
315
- _this.forceMute = options.forceMute || false;
316
- return _this;
317
- }
318
- PlaylistWindowManager.prototype.currentPresentationId = function () {
319
- return this.currentPresentation
320
- ? this.currentPresentation.presentationId
321
- : null;
322
- };
323
- PlaylistWindowManager.prototype.nextPresentationId = function () {
324
- return this.nextPresentation ? this.nextPresentation.presentationId : null;
325
- };
326
- PlaylistWindowManager.prototype.load = function () {
327
- return __awaiter(this, void 0, void 0, function () {
328
- var _a, next, preview, nextPresentationId, nextPreviewPresentationId;
329
- return __generator(this, function (_b) {
330
- switch (_b.label) {
331
- case 0:
332
- if (!this.renderer) {
333
- throw new Error('Attempted to load playlist window manager with missing renderer');
334
- }
335
- _a = this.evalRuleEngine(), next = _a.next, preview = _a.preview;
336
- nextPresentationId = next.presentationId;
337
- nextPreviewPresentationId = preview.presentationId;
338
- // Resolve immediately if there if there is no presentation to play next.
339
- if (!nextPresentationId) {
340
- return [2 /*return*/];
341
- }
342
- // We need to set this.currentPresentation before calling shouldPreload in order
343
- // to avoid preloading the next presentation id if it's the same as the current.
344
- this.currentPresentation = next;
345
- if (!this.shouldPreload(nextPreviewPresentationId)) return [3 /*break*/, 1];
346
- this.nextPresentation = preview;
347
- this.preloadNextWindow();
348
- return [3 /*break*/, 3];
349
- case 1: return [4 /*yield*/, this.removeNextWindow()];
350
- case 2:
351
- _b.sent();
352
- _b.label = 3;
353
- case 3:
354
- // Load and wait for current window before playing.
355
- return [4 /*yield*/, this.loadCurrentWindow()];
356
- case 4:
357
- // Load and wait for current window before playing.
358
- _b.sent();
359
- return [2 /*return*/];
360
- }
361
- });
362
- });
363
- };
364
- PlaylistWindowManager.prototype.isEmpty = function () {
365
- if (!this.ruleEngine)
366
- return true;
367
- var preview = this.ruleEngine.previewNext();
368
- return !preview.presentationId;
369
- };
370
- PlaylistWindowManager.prototype.play = function () {
371
- this.restartCurrentWindowOnEnd = false;
372
- this.playCurrentWindow();
373
- this.startPreviewCheck();
374
- };
375
- PlaylistWindowManager.prototype.isPlaying = function () {
376
- if (!this.currentWindow) {
377
- return false;
378
- }
379
- return this.currentWindow.isPlaying();
380
- };
381
- PlaylistWindowManager.prototype.pause = function () {
382
- // Pausing a playlist means restarting the current window when it completes
383
- // instead of moving on to the next one.
384
- this.restartCurrentWindowOnEnd = true;
385
- this.pauseCurrentWindow();
386
- this.stopInterruptCheck();
387
- };
388
- PlaylistWindowManager.prototype.resume = function () {
389
- // Resuming a playlist will switch to the next window when the current window
390
- // completes. We don't want to fire 'play' because that could restart the window's
391
- // on complete timer.
392
- this.restartCurrentWindowOnEnd = false;
393
- this.resumeCurrentWindow();
394
- this.startPreviewCheck();
395
- };
396
- PlaylistWindowManager.prototype.blur = function () {
397
- // Use this method to stop creating windows that are focused. There is no renderer API for
398
- // blurring a window because Electron doesn't have a blur() method on BrowserWindows. If focus
399
- // should be switched to another PlaylistWindowManager call blur() and then show(true) on the other.
400
- this.isFocused = false;
401
- };
402
- PlaylistWindowManager.prototype.isPaused = function () {
403
- return this.restartCurrentWindowOnEnd;
404
- };
405
- PlaylistWindowManager.prototype.getRenderer = function () {
406
- return this.renderer;
407
- };
408
- PlaylistWindowManager.prototype.setRenderer = function (renderer) {
409
- this.renderer = renderer;
410
- };
411
- PlaylistWindowManager.prototype.getRuleEngine = function () {
412
- return this.ruleEngine;
413
- };
414
- PlaylistWindowManager.prototype.setRuleEngine = function (ruleEngine) {
415
- return __awaiter(this, void 0, void 0, function () {
416
- var _a, next, preview, nextPresentationId;
417
- return __generator(this, function (_b) {
418
- switch (_b.label) {
419
- case 0:
420
- this.ruleEngine = ruleEngine;
421
- _a = this.evalRuleEngine(false), next = _a.next, preview = _a.preview;
422
- nextPresentationId = next.presentationId;
423
- // If the window manager doesn't have a renderer, update the current and next
424
- // presentations but don't load any windows. This handles the case where the
425
- // window manager is created with an empty playlist and then has a non-empty
426
- // playlist is published to it.
427
- if (!this.renderer) {
428
- this.currentPresentation = next;
429
- this.nextPresentation = preview;
430
- return [2 /*return*/];
431
- }
432
- if (!!nextPresentationId) return [3 /*break*/, 3];
433
- this.currentPresentation = null;
434
- return [4 /*yield*/, this.removeCurrentWindow()];
435
- case 1:
436
- _b.sent();
437
- this.nextPresentation = null;
438
- return [4 /*yield*/, this.removeNextWindow()];
439
- case 2:
440
- _b.sent();
441
- return [2 /*return*/];
442
- case 3:
443
- // We've already evalulated the rule engine to get the new current presentation and the
444
- // new next presentation. The current next presentation is replaced with the new current
445
- // presentation. Since we've already evaluated the new next presentation above, we need to
446
- // prevent evaling the rule engine again when new current presentation completes by setting
447
- // this.overrideNextPresentationId. This fixes an issue where the second presentation in the
448
- // playlists is skipped after reinitializing.
449
- this.overrideNextPresentation = preview;
450
- // Assume the next window is no longer correct when swapping the rule engine.
451
- return [4 /*yield*/, this.removeNextWindow()];
452
- case 4:
453
- // Assume the next window is no longer correct when swapping the rule engine.
454
- _b.sent();
455
- // Load the new current presentation with the new rule engine.
456
- this.nextPresentation = next;
457
- return [4 /*yield*/, this.preloadNextWindow()];
458
- case 5:
459
- _b.sent();
460
- return [2 /*return*/];
461
- }
462
- });
463
- });
464
- };
465
- PlaylistWindowManager.prototype.getState = function () {
466
- return this.state;
467
- };
468
- PlaylistWindowManager.prototype.setState = function (state) {
469
- this.state = state;
470
- };
471
- // For setting dynamic tags data from workers and reevaluate rules for playlists
472
- // input: newRulesDataStoreObj: {'workers': {'ai': {'percentMales': 30}}}
473
- PlaylistWindowManager.prototype.reinitializeRuleEngineState = function (newRulesDataStoreObj) {
474
- var _this = this;
475
- var logger = this.options.logger;
476
- logger.debug('Dynamic Rule engine state change event received!');
477
- if (this.ruleEngine) {
478
- logger.debug("OLD Rule Data Store: ".concat(JSON.stringify(this.ruleEngine.state), " \n NEW Rule Data Store: ").concat(JSON.stringify(newRulesDataStoreObj)));
479
- this.ruleEngine.state.rulesDataStore = newRulesDataStoreObj;
480
- }
481
- else {
482
- logger.warn("No Rule engine found for reinitiazling the state!");
483
- return;
484
- }
485
- // re-evaluate the next presentations depending upon the new rule engine state
486
- var checkOverridePresentation = function () { return __awaiter(_this, void 0, void 0, function () {
487
- return __generator(this, function (_a) {
488
- if (this.ruleEngine) {
489
- this.checkPreviewAction();
490
- // calling reinitialize Rule engine state for inner playlist windows (for MZ)
491
- if (this.currentWindow) {
492
- this.currentWindow.reinitializePresentationWindowRuleEngineState(newRulesDataStoreObj);
493
- }
494
- if (this.nextWindow) {
495
- this.nextWindow.reinitializePresentationWindowRuleEngineState(newRulesDataStoreObj);
496
- }
497
- }
498
- return [2 /*return*/];
499
- });
500
- }); };
501
- checkOverridePresentation();
502
- };
503
- // Replace state and rule engine, and reinitialize the window manager.
504
- PlaylistWindowManager.prototype.reinitialize = function (state, ruleEngine, shouldInterruptPlayback) {
505
- return __awaiter(this, void 0, void 0, function () {
506
- return __generator(this, function (_a) {
507
- switch (_a.label) {
508
- case 0:
509
- this.setState(state);
510
- return [4 /*yield*/, this.setRuleEngine(ruleEngine)];
511
- case 1:
512
- _a.sent();
513
- if (shouldInterruptPlayback) {
514
- this.registerInterrupt();
515
- }
516
- return [2 /*return*/];
517
- }
518
- });
519
- });
520
- };
521
- PlaylistWindowManager.prototype.registerInterrupt = function () {
522
- if (!this.isLocked()) {
523
- this.endCurrentPresentation();
524
- }
525
- else {
526
- this.hasPendingInterrupt = true;
527
- }
528
- };
529
- PlaylistWindowManager.prototype.endCurrentPresentation = function () {
530
- this.handleCurrentPresentationComplete();
531
- };
532
- PlaylistWindowManager.prototype.destroy = function () {
533
- return __awaiter(this, void 0, void 0, function () {
534
- return __generator(this, function (_a) {
535
- switch (_a.label) {
536
- case 0:
537
- this.stopInterruptCheck();
538
- if (this.currentPresentationCompleteTimeout) {
539
- clearTimeout(this.currentPresentationCompleteTimeout);
540
- }
541
- return [4 /*yield*/, Promise.all([this.removeCurrentWindow(), this.removeNextWindow()])];
542
- case 1:
543
- _a.sent();
544
- return [2 /*return*/];
545
- }
546
- });
547
- });
548
- };
549
- PlaylistWindowManager.prototype.updateBounds = function (bounds) {
550
- this.bounds = bounds;
551
- if (this.currentWindow) {
552
- this.currentWindow.updateBounds(this.bounds);
553
- }
554
- if (this.nextWindow) {
555
- this.nextWindow.updateBounds(this.bounds);
556
- }
557
- };
558
- PlaylistWindowManager.prototype.getBounds = function () {
559
- return this.bounds;
560
- };
561
- PlaylistWindowManager.prototype.setThemeOverride = function (theme) {
562
- this.themeOverride = theme;
563
- var currentPresentationId = this.currentPresentationId();
564
- var nextPresentationId = this.nextPresentationId();
565
- if (this.currentWindow && currentPresentationId) {
566
- this.currentWindow.setTheme(this.getTheme(currentPresentationId));
567
- }
568
- if (this.nextWindow && nextPresentationId) {
569
- this.nextWindow.setTheme(this.getTheme(nextPresentationId));
570
- }
571
- };
572
- PlaylistWindowManager.prototype.getThemeOverride = function () {
573
- return this.themeOverride;
574
- };
575
- PlaylistWindowManager.prototype.setForceMute = function (forceMute) {
576
- this.forceMute = forceMute;
577
- if (this.currentWindow) {
578
- this.currentWindow.setForceMute(forceMute);
579
- }
580
- if (this.nextWindow) {
581
- this.nextWindow.setForceMute(forceMute);
582
- }
583
- };
584
- PlaylistWindowManager.prototype.getForceMute = function () {
585
- return this.forceMute;
586
- };
587
- PlaylistWindowManager.prototype.reload = function () {
588
- if (this.currentWindow) {
589
- this.currentWindow.reload();
590
- }
591
- if (this.nextWindow) {
592
- this.nextWindow.reload();
593
- }
594
- };
595
- PlaylistWindowManager.prototype.show = function (isFocused) {
596
- if (isFocused === void 0) { isFocused = true; }
597
- return __awaiter(this, void 0, void 0, function () {
598
- return __generator(this, function (_a) {
599
- if (this.currentWindow) {
600
- // Save the focused state so we know if preloaded windows should be
601
- // focused when swapped for the current.
602
- this.isFocused = isFocused;
603
- this.currentWindow.show(isFocused);
604
- }
605
- return [2 /*return*/];
606
- });
607
- });
608
- };
609
- PlaylistWindowManager.prototype.hide = function () {
610
- return __awaiter(this, void 0, void 0, function () {
611
- return __generator(this, function (_a) {
612
- if (this.currentWindow) {
613
- this.currentWindow.hide();
614
- }
615
- return [2 /*return*/];
616
- });
617
- });
618
- };
619
- PlaylistWindowManager.prototype.isReady = function () {
620
- if (!this.currentWindow) {
621
- return true;
622
- }
623
- return this.currentWindow.isReady();
624
- };
625
- PlaylistWindowManager.prototype.isLocked = function () {
626
- if (!this.currentWindow) {
627
- return false;
628
- }
629
- return this.currentWindow.isLocked();
630
- };
631
- PlaylistWindowManager.prototype.runWorkerSubscriptions = function (state) {
632
- // Persist worker state so new windows can be initialized with it.
633
- this.workerState = state;
634
- // Run worker subcriptions on the current window.
635
- if (this.currentWindow) {
636
- this.currentWindow.runWorkerSubscriptions(state);
637
- }
638
- // Run worker subscriptions on the next window.
639
- if (this.nextWindow) {
640
- this.nextWindow.runWorkerSubscriptions(state);
641
- }
642
- };
643
- PlaylistWindowManager.prototype.createWindow = function (pr) {
644
- var _a = this.options, readyTimeoutDurationSeconds = _a.readyTimeoutDurationSeconds, appRendererUrl = _a.appRendererUrl, backgroundColor = _a.backgroundColor, device = _a.device, logger = _a.logger, windowName = _a.windowName, parentWindowId = _a.parentWindowId, isPreview = _a.isPreview;
645
- if (!this.ruleEngine) {
646
- throw new Error('Attempted to create window but ruleEngine was not provided');
647
- }
648
- if (!this.state) {
649
- throw new Error('Attempted to create window but state was not provided');
650
- }
651
- if (!this.renderer) {
652
- throw new Error('Attempted to create window but renderer was not provided');
653
- }
654
- var presentationId = pr.presentationId;
655
- if (!presentationId) {
656
- throw new Error('Attempted to create window but presentationId is null');
657
- }
658
- var presentation = this.state.getPresentation(presentationId);
659
- var applicationVersion = this.state.getApplicationVersion(presentation.applicationDeploymentId);
660
- var windowId = (0, uuid_1.v4)();
661
- return new PresentationWindow_1.default({
662
- windowManager: this,
663
- renderer: this.renderer,
664
- logger: logger,
665
- windowId: windowId,
666
- windowName: windowName,
667
- parentWindowId: parentWindowId,
668
- presentation: presentation,
669
- applicationVersion: applicationVersion,
670
- device: device,
671
- playlistId: pr.playlistId,
672
- playlistName: this.ruleEngine.state.playlist(pr.playlistId).name,
673
- rule: pr.rule,
674
- publishedAt: this.state.getPublishedAt(),
675
- theme: this.getTheme(presentationId),
676
- forceMute: this.forceMute,
677
- readyTimeoutDurationSeconds: readyTimeoutDurationSeconds,
678
- appRendererUrl: appRendererUrl,
679
- bounds: this.bounds,
680
- backgroundColor: backgroundColor,
681
- playlistWindowManagerState: this.state,
682
- ruleEngineState: this.ruleEngine.state,
683
- globalRule: this.ruleEngine.globalRule,
684
- isPreview: isPreview,
685
- workerState: this.workerState
686
- });
687
- };
688
- PlaylistWindowManager.prototype.loadCurrentWindow = function () {
689
- return __awaiter(this, void 0, void 0, function () {
690
- var logger;
691
- return __generator(this, function (_a) {
692
- switch (_a.label) {
693
- case 0:
694
- logger = this.options.logger;
695
- if (!this.currentPresentation) {
696
- logger.warn("Attempted to load current window but currentPresentation not set");
697
- return [2 /*return*/];
698
- }
699
- this.currentWindow = this.createWindow(this.currentPresentation);
700
- this.currentWindow.onComplete(this.handleCurrentPresentationComplete);
701
- this.currentWindow.onError(this.handleCurrentPresentationError);
702
- this.currentWindow.onEnableInterruptLock(this.handleEnableInterruptLock);
703
- this.currentWindow.onDisableInterruptLock(this.handleDisableInterruptLock);
704
- this.currentWindow.onAnalyticsEvent(this.handleAnalyticsEvent);
705
- return [4 /*yield*/, this.currentWindow.load()];
706
- case 1:
707
- _a.sent();
708
- return [2 /*return*/];
709
- }
710
- });
711
- });
712
- };
713
- PlaylistWindowManager.prototype.shouldPreload = function (presentationId) {
714
- // Don't preload if there is no presentation.
715
- if (presentationId === null) {
716
- return false;
717
- }
718
- // Don't preload the next presentation if it's already preloaded. When the window manager
719
- // is first created it will eval the rule engine and set this.nextPresentationId but not
720
- // this.nextWindow.
721
- if (presentationId === this.nextPresentationId()) {
722
- return false;
723
- }
724
- // An optimization to avoid preloading the same presentation we are currenly playing.
725
- // When the current presentation completes we will play it again and then check for
726
- // a new presentation to preload.
727
- if (presentationId === this.currentPresentationId()) {
728
- return false;
729
- }
730
- return true;
731
- };
732
- PlaylistWindowManager.prototype.preloadNextWindow = function () {
733
- return __awaiter(this, void 0, void 0, function () {
734
- var logger;
735
- return __generator(this, function (_a) {
736
- switch (_a.label) {
737
- case 0:
738
- logger = this.options.logger;
739
- if (!this.nextPresentation) {
740
- logger.warn("Attempted to preload next window but nextPresentation not set");
741
- return [2 /*return*/];
742
- }
743
- this.nextWindow = this.createWindow(this.nextPresentation);
744
- this.nextWindow.onError(this.handleNextPresentationError);
745
- return [4 /*yield*/, this.nextWindow.load()];
746
- case 1:
747
- _a.sent();
748
- // If there is no current window and the next window successfully loaded, show the preloaded window.
749
- // NOTE: Apps that use raydiant-kit's onError handler will end up showing an error on screen anyways
750
- // because the onError method fires presentation_ready before sending the error. We should fix this
751
- // but would require updating raydiant-kit and then all apps.
752
- if (!this.currentWindow && !this.nextWindow.didError()) {
753
- this.handleCurrentPresentationComplete();
754
- }
755
- return [2 /*return*/];
756
- }
757
- });
758
- });
759
- };
760
- PlaylistWindowManager.prototype.playCurrentWindow = function () {
761
- var logger = this.options.logger;
762
- if (this.currentWindow) {
763
- this.currentWindow.play();
764
- this.emitCurrentWindowEvent('window_play');
765
- }
766
- else {
767
- logger.warn("Attempted to play current window but it doesn't exist");
768
- }
769
- };
770
- PlaylistWindowManager.prototype.pauseCurrentWindow = function () {
771
- var logger = this.options.logger;
772
- if (this.currentWindow) {
773
- this.currentWindow.pause();
774
- }
775
- else {
776
- logger.warn("Attempted to pause current window but it doesn't exist");
777
- }
778
- };
779
- PlaylistWindowManager.prototype.resumeCurrentWindow = function () {
780
- var logger = this.options.logger;
781
- if (this.currentWindow) {
782
- this.currentWindow.resume();
783
- }
784
- else {
785
- logger.warn("Attempted to resume current window but it doesn't exist");
786
- }
787
- };
788
- PlaylistWindowManager.prototype.restartCurrentWindow = function () {
789
- return __awaiter(this, void 0, void 0, function () {
790
- var logger;
791
- return __generator(this, function (_a) {
792
- switch (_a.label) {
793
- case 0:
794
- logger = this.options.logger;
795
- if (!this.currentWindow) return [3 /*break*/, 5];
796
- if (!this.shouldHardRestart) return [3 /*break*/, 3];
797
- logger.info("Restart current window with hard restart");
798
- return [4 /*yield*/, this.removeCurrentWindow()];
799
- case 1:
800
- _a.sent();
801
- return [4 /*yield*/, this.loadCurrentWindow()];
802
- case 2:
803
- _a.sent();
804
- this.currentWindow.show(this.isFocused);
805
- return [3 /*break*/, 4];
806
- case 3:
807
- logger.info("Restart current window");
808
- this.currentWindow.reset();
809
- _a.label = 4;
810
- case 4:
811
- this.playCurrentWindow();
812
- return [3 /*break*/, 6];
813
- case 5:
814
- logger.warn("Attempted to restart current window but it doesn't exist");
815
- _a.label = 6;
816
- case 6: return [2 /*return*/];
817
- }
818
- });
819
- });
820
- };
821
- PlaylistWindowManager.prototype.removeCurrentWindow = function () {
822
- return __awaiter(this, void 0, void 0, function () {
823
- return __generator(this, function (_a) {
824
- switch (_a.label) {
825
- case 0:
826
- if (!this.currentWindow) return [3 /*break*/, 2];
827
- return [4 /*yield*/, this.currentWindow.remove()];
828
- case 1:
829
- _a.sent();
830
- _a.label = 2;
831
- case 2:
832
- this.currentWindow = null;
833
- this.currentPresentation = null;
834
- return [2 /*return*/];
835
- }
836
- });
837
- });
838
- };
839
- PlaylistWindowManager.prototype.removeNextWindow = function () {
840
- return __awaiter(this, void 0, void 0, function () {
841
- return __generator(this, function (_a) {
842
- switch (_a.label) {
843
- case 0:
844
- if (!this.nextWindow) return [3 /*break*/, 2];
845
- return [4 /*yield*/, this.nextWindow.remove()];
846
- case 1:
847
- _a.sent();
848
- _a.label = 2;
849
- case 2:
850
- this.nextWindow = null;
851
- this.nextPresentation = null;
852
- return [2 /*return*/];
853
- }
854
- });
855
- });
856
- };
857
- PlaylistWindowManager.prototype.swapWindows = function () {
858
- return __awaiter(this, void 0, void 0, function () {
859
- var nextPreviewPresentationId, preview, result, shouldPreload;
860
- return __generator(this, function (_a) {
861
- switch (_a.label) {
862
- case 0:
863
- nextPreviewPresentationId = null;
864
- preview = null;
865
- if (this.overrideNextPresentation) {
866
- preview = this.overrideNextPresentation;
867
- nextPreviewPresentationId = this.overrideNextPresentation.presentationId;
868
- this.overrideNextPresentation = null;
869
- }
870
- else {
871
- result = this.evalRuleEngine();
872
- preview = result.preview;
873
- nextPreviewPresentationId = preview.presentationId;
874
- }
875
- // Set this.currentPresentationId before removing the current window to avoid timing issues with previewCheck
876
- // triggering during removeCurrentWindow. Current presentation id needs to be set to the next
877
- // presentation before calling shouldPreload().
878
- this.currentPresentation = this.nextPresentation;
879
- shouldPreload = this.shouldPreload(nextPreviewPresentationId);
880
- if (shouldPreload) {
881
- // Set this.nextPresentationId before removing the current window. This prevents
882
- // race conditions with previewCheck when using the window pool, where removeWindow
883
- // is async because we unload the window instead of destroying it.
884
- this.nextPresentation = preview;
885
- }
886
- // Clear the pending interrupt whenever we swap the current window for the next one.
887
- this.hasPendingInterrupt = false;
888
- // Next window is ready, show the next one, hide the current window, and
889
- // then remove the current window. Show the next window before hiding the
890
- // current to avoid flashes when rendering with BrowserWindows on device.
891
- if (this.nextWindow) {
892
- this.nextWindow.show(this.isFocused);
893
- }
894
- if (!this.currentWindow) return [3 /*break*/, 2];
895
- this.currentWindow.hide();
896
- return [4 /*yield*/, this.removeCurrentWindow()];
897
- case 1:
898
- _a.sent();
899
- _a.label = 2;
900
- case 2:
901
- // Swap windows.
902
- this.currentWindow = this.nextWindow;
903
- if (this.currentWindow) {
904
- this.currentWindow.onComplete(this.handleCurrentPresentationComplete);
905
- this.currentWindow.onError(this.handleCurrentPresentationError);
906
- this.currentWindow.onEnableInterruptLock(this.handleEnableInterruptLock);
907
- this.currentWindow.onDisableInterruptLock(this.handleDisableInterruptLock);
908
- this.currentWindow.onAnalyticsEvent(this.handleAnalyticsEvent);
909
- }
910
- // Play new current window.
911
- this.playCurrentWindow();
912
- // Preload the next presentation if there is one.
913
- if (shouldPreload) {
914
- this.preloadNextWindow();
915
- }
916
- else {
917
- // Set next window to null to reset preload state. We don't want to
918
- // remove the next window because it's the new current window.
919
- this.nextWindow = null;
920
- this.nextPresentation = null;
921
- }
922
- return [2 /*return*/];
923
- }
924
- });
925
- });
926
- };
927
- PlaylistWindowManager.prototype.evalRuleEngine = function (warnIfPreloadMismatch) {
928
- if (warnIfPreloadMismatch === void 0) { warnIfPreloadMismatch = true; }
929
- var logger = this.options.logger;
930
- if (!this.ruleEngine) {
931
- throw new Error('Attempted to eval rule engine but ruleEngine not provided');
932
- }
933
- var next = this.ruleEngine.next();
934
- var preview = this.ruleEngine.previewNext();
935
- var nextPresentationId = next.presentationId;
936
- if (this.nextPresentationId() !== null &&
937
- nextPresentationId !== this.nextPresentationId() &&
938
- warnIfPreloadMismatch) {
939
- // TODO: Handle the case when the next presentation isn't the preloaded window.
940
- // This can happen when we support dynamic rule engine state.
941
- logger.warn("The next presentation id '".concat(nextPresentationId, "' doesnt match preloaded presentation id '").concat(this.nextPresentationId(), "'"));
942
- }
943
- return { next: next, preview: preview };
944
- };
945
- PlaylistWindowManager.prototype.startPreviewCheck = function () {
946
- var _this = this;
947
- var checkPreview = function () { return __awaiter(_this, void 0, void 0, function () {
948
- var now, nextMinute, timeUntilNextMinute;
949
- return __generator(this, function (_a) {
950
- if (this.ruleEngine) {
951
- this.checkPreviewAction();
952
- }
953
- now = new Date();
954
- nextMinute = new Date();
955
- nextMinute.setMilliseconds(0);
956
- nextMinute.setSeconds(1);
957
- nextMinute.setMinutes(now.getMinutes() + 1);
958
- timeUntilNextMinute = +nextMinute - +now;
959
- this.interruptCheckTimeout = setTimeout(checkPreview, timeUntilNextMinute);
960
- return [2 /*return*/];
961
- });
962
- }); };
963
- checkPreview();
964
- };
965
- PlaylistWindowManager.prototype.stopInterruptCheck = function () {
966
- if (this.interruptCheckTimeout) {
967
- clearTimeout(this.interruptCheckTimeout);
968
- }
969
- };
970
- PlaylistWindowManager.prototype.getTheme = function (presentationId) {
971
- if (!this.state)
972
- return;
973
- var theme;
974
- var presentation = this.state.getPresentation(presentationId);
975
- if (this.themeOverride) {
976
- theme = this.themeOverride;
977
- }
978
- else if (presentation.themeId && this.state) {
979
- theme = this.state.getTheme(presentation.themeId);
980
- }
981
- return theme;
982
- };
983
- PlaylistWindowManager.prototype.emitWindowEvent = function (label, event, window, data) {
984
- var logger = this.options.logger;
985
- if (window) {
986
- this.emit(event, __assign(__assign({}, window.metadata()), { data: data }));
987
- }
988
- else {
989
- logger.warn("Attempted to emit ".concat(label, " window event but window not set"));
990
- }
991
- };
992
- PlaylistWindowManager.prototype.emitCurrentWindowEvent = function (event, data) {
993
- return this.emitWindowEvent('current', event, this.currentWindow, data);
994
- };
995
- PlaylistWindowManager.prototype.emitNextWindowEvent = function (event, data) {
996
- return this.emitWindowEvent('next', event, this.nextWindow, data);
997
- };
998
- PlaylistWindowManager.prototype.emitCurrentWindowErrorEvent = function (event, error) {
999
- return this.emitCurrentWindowEvent(event, {
1000
- errorMessage: this.getErrorMessage(error)
1001
- });
1002
- };
1003
- PlaylistWindowManager.prototype.emitNextWindowErrorEvent = function (event, error) {
1004
- return this.emitNextWindowEvent(event, {
1005
- errorMessage: this.getErrorMessage(error)
1006
- });
1007
- };
1008
- PlaylistWindowManager.prototype.getErrorMessage = function (error) {
1009
- if (typeof error === 'string')
1010
- return error;
1011
- if (error && typeof error === 'object' && error.message)
1012
- return error.message;
1013
- return '';
1014
- };
1015
- return PlaylistWindowManager;
1016
- }(eventemitter3_1.default));
1017
- exports.default = PlaylistWindowManager;