@xibosignage/xibo-layout-renderer 1.0.24 → 1.0.26

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.
@@ -706,6 +706,7 @@ var XiboLayoutRenderer = (function (exports) {
706
706
  return Promise.resolve([]);
707
707
  },
708
708
  removeLayout: function removeLayout() {},
709
+ discardLayout: function discardLayout() {},
709
710
  getXlf: function getXlf() {
710
711
  return '';
711
712
  },
@@ -716,6 +717,13 @@ var XiboLayoutRenderer = (function (exports) {
716
717
  html: null
717
718
  };
718
719
 
720
+ var MediaState = {
721
+ IDLE: 'idle',
722
+ PLAYING: 'playing',
723
+ ENDED: 'ended',
724
+ CANCELLED: 'cancelled'
725
+ };
726
+
719
727
  var initialRegion = {
720
728
  complete: false,
721
729
  containerName: '',
@@ -764,56 +772,6 @@ var XiboLayoutRenderer = (function (exports) {
764
772
  xlr: {}
765
773
  };
766
774
 
767
- var MediaState = {
768
- IDLE: 'idle',
769
- PLAYING: 'playing',
770
- ENDED: 'ended',
771
- CANCELLED: 'cancelled'
772
- };
773
- var initialMedia = {
774
- attachedAudio: false,
775
- checkIframeStatus: false,
776
- containerName: '',
777
- divHeight: 0,
778
- divWidth: 0,
779
- duration: 0,
780
- emitter: {},
781
- enableStat: false,
782
- fileId: '',
783
- finished: false,
784
- html: null,
785
- id: '',
786
- idCounter: 0,
787
- iframe: null,
788
- iframeName: '',
789
- index: 0,
790
- loadIframeOnRun: false,
791
- loop: false,
792
- mediaId: '',
793
- mediaType: '',
794
- muted: false,
795
- options: {},
796
- player: undefined,
797
- ready: true,
798
- region: initialRegion,
799
- render: 'html',
800
- run: function run() {},
801
- schemaVersion: '1',
802
- singlePlay: false,
803
- state: MediaState.IDLE,
804
- stop: function stop() {
805
- return Promise.resolve();
806
- },
807
- tempSrc: '',
808
- timeoutId: setTimeout(function () {}, 0),
809
- type: '',
810
- uri: '',
811
- url: null,
812
- useDuration: Boolean(0),
813
- xml: null,
814
- mediaTimer: undefined
815
- };
816
-
817
775
  var OverlayLayoutManager = /*#__PURE__*/function () {
818
776
  function OverlayLayoutManager() {
819
777
  _classCallCheck(this, OverlayLayoutManager);
@@ -834,31 +792,37 @@ var XiboLayoutRenderer = (function (exports) {
834
792
  case 0:
835
793
  _context2.next = 2;
836
794
  return Promise.all(list.map( /*#__PURE__*/function () {
837
- var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(item) {
838
- var inputOverlay, overlayLayout, $overlay;
795
+ var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(item, index) {
796
+ var _item$index;
797
+ var inputOverlay, overlayLayout, $overlay, _overlayLayout$zIndex;
839
798
  return _regeneratorRuntime().wrap(function _callee$(_context) {
840
799
  while (1) switch (_context.prev = _context.next) {
841
800
  case 0:
842
801
  inputOverlay = {};
843
802
  inputOverlay = _objectSpread2(_objectSpread2({}, inputOverlay), item);
844
- inputOverlay.index = item.index;
803
+ inputOverlay.index = (_item$index = item.index) !== null && _item$index !== void 0 ? _item$index : index;
845
804
  _context.next = 5;
846
805
  return _this.parent.prepareLayoutXlf(_objectSpread2(_objectSpread2({}, initialLayout), inputOverlay));
847
806
  case 5:
848
807
  overlayLayout = _context.sent;
808
+ console.debug('<> XLR.debug OverlayLayoutManager::parseOverlays prepared overlay layout', {
809
+ overlayLayout: overlayLayout,
810
+ inputOverlay: inputOverlay
811
+ });
849
812
  // Hide all overlays first
850
813
  $overlay = document.querySelector("#".concat(overlayLayout.containerName, "[data-sequence=\"").concat(overlayLayout.index, "\"]"));
851
814
  if ($overlay !== null) {
852
- $overlay.style.setProperty('display', 'none');
815
+ $overlay.style.setProperty('visibility', 'hidden');
816
+ $overlay.style.setProperty('z-index', "".concat((_overlayLayout$zIndex = overlayLayout.zIndex) !== null && _overlayLayout$zIndex !== void 0 ? _overlayLayout$zIndex : -999));
853
817
  }
854
818
  return _context.abrupt("return", overlayLayout);
855
- case 9:
819
+ case 10:
856
820
  case "end":
857
821
  return _context.stop();
858
822
  }
859
823
  }, _callee);
860
824
  }));
861
- return function (_x2) {
825
+ return function (_x2, _x3) {
862
826
  return _ref.apply(this, arguments);
863
827
  };
864
828
  }()));
@@ -987,7 +951,7 @@ var XiboLayoutRenderer = (function (exports) {
987
951
  }
988
952
  }, _callee3, this, [[12, 21, 24, 27]]);
989
953
  }));
990
- function prepareOverlayLayouts(_x3, _x4) {
954
+ function prepareOverlayLayouts(_x4, _x5) {
991
955
  return _prepareOverlayLayouts.apply(this, arguments);
992
956
  }
993
957
  return prepareOverlayLayouts;
@@ -998,7 +962,8 @@ var XiboLayoutRenderer = (function (exports) {
998
962
  var _this$parent$currentL;
999
963
  if (this.overlays.length === 0) return;
1000
964
  if (this.parent && (_this$parent$currentL = this.parent.currentLayout) !== null && _this$parent$currentL !== void 0 && _this$parent$currentL.isInterrupt()) {
1001
- this.container.style.setProperty('display', 'none');
965
+ this.container.style.setProperty('visibility', 'hidden');
966
+ this.container.style.setProperty('z-index', '-999');
1002
967
  return;
1003
968
  }
1004
969
  this.overlays.forEach(function (overlay) {
@@ -1016,21 +981,25 @@ var XiboLayoutRenderer = (function (exports) {
1016
981
  while (1) switch (_context5.prev = _context5.next) {
1017
982
  case 0:
1018
983
  overlayHtml = document.querySelector("#".concat(overlay.containerName, "[data-sequence=\"").concat(overlay.index, "\"]"));
984
+ console.debug('<> XLR.debug OverlayLayoutManager::stopOverlays', {
985
+ overlay: overlay,
986
+ overlayHtml: overlayHtml
987
+ });
1019
988
  if (!(overlayHtml !== null)) {
1020
- _context5.next = 5;
989
+ _context5.next = 6;
1021
990
  break;
1022
991
  }
1023
- _context5.next = 4;
992
+ _context5.next = 5;
1024
993
  return overlay.finishAllRegions();
1025
- case 4:
1026
- overlay.emitter.emit('end', overlay);
1027
994
  case 5:
995
+ overlay.emitter.emit('end', overlay);
996
+ case 6:
1028
997
  case "end":
1029
998
  return _context5.stop();
1030
999
  }
1031
1000
  }, _callee4);
1032
1001
  }));
1033
- return function (_x5) {
1002
+ return function (_x6) {
1034
1003
  return _ref2.apply(this, arguments);
1035
1004
  };
1036
1005
  }());
@@ -1099,6 +1068,7 @@ var XiboLayoutRenderer = (function (exports) {
1099
1068
  isLayoutInDOM: function isLayoutInDOM(containerName, layoutId) {
1100
1069
  return false;
1101
1070
  },
1071
+ cleanupOrphanedLayouts: function cleanupOrphanedLayouts(_keepCurrent, _keepNext) {},
1102
1072
  isSspEnabled: false,
1103
1073
  isUpdatingLoop: false,
1104
1074
  isUpdatingOverlays: false,
@@ -72519,6 +72489,10 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
72519
72489
  function composeVideoSource($media, media) {
72520
72490
  // const videoSrc = await preloadMediaBlob(media.url as string, media.mediaType as MediaTypes);
72521
72491
  var vidType = videoFileType(getFileExt(media.uri));
72492
+ if (!vidType) {
72493
+ console.warn("XLR >> VideoMedia: Unsupported video type for media ".concat(media.id, " with uri ").concat(media.uri));
72494
+ return $media;
72495
+ }
72522
72496
  // Only add one source per type
72523
72497
  if ($media.querySelectorAll("source[type=\"".concat(vidType, "\"]")).length === 0) {
72524
72498
  var $videoSource = document.createElement('source');
@@ -72545,8 +72519,38 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
72545
72519
  };
72546
72520
  var reportToPlayerPlatform = [exports.ConsumerPlatform.CHROMEOS, exports.ConsumerPlatform.ELECTRON];
72547
72521
  function VideoMedia(media, xlr) {
72522
+ var stopped = false;
72548
72523
  var mediaId = getMediaId(media);
72524
+ // ── Stall watchdog (closure-level so stop() can cancel it) ───────────────
72525
+ // 'waiting' and 'stalled' fire when the browser stops receiving data.
72526
+ // Unlike codec or source errors they do NOT fire the 'error' event, so
72527
+ // without a watchdog the video silently freezes for its entire duration.
72528
+ var stallWatchdog;
72529
+ var STALL_TIMEOUT_MS = 10000;
72530
+ var clearStallWatchdog = function clearStallWatchdog() {
72531
+ if (stallWatchdog !== undefined) {
72532
+ clearTimeout(stallWatchdog);
72533
+ stallWatchdog = undefined;
72534
+ }
72535
+ };
72536
+ // ─────────────────────────────────────────────────────────────────────────
72537
+ // ── Unified error → report → stop helper (closure-level) ─────────────────
72538
+ // Used by both the 'error' event and the play Promise catch.
72539
+ // playerReportFault only fires for platforms that report faults (Electron,
72540
+ // ChromeOS). All other platforms just advance to the next media via stop().
72541
+ var reportAndStop = function reportAndStop(reason, code) {
72542
+ if (stopped) return;
72543
+ if (reportToPlayerPlatform.includes(xlr.config.platform)) {
72544
+ playerReportFault(reason, media, code).then(function () {
72545
+ return videoPlayer.stop();
72546
+ });
72547
+ } else {
72548
+ videoPlayer.stop();
72549
+ }
72550
+ };
72551
+ // ─────────────────────────────────────────────────────────────────────────
72549
72552
  var videoPlayer = {
72553
+ player: undefined,
72550
72554
  duration: 0,
72551
72555
  init: function init() {
72552
72556
  var _this = this;
@@ -72554,9 +72558,37 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
72554
72558
  videoPlayer.duration = media.duration;
72555
72559
  var vjsPlayer = videojs(mediaId);
72556
72560
  if (vjsPlayer) {
72557
- vjsPlayer.on('loadstart', function () {
72558
- console.debug("??? XLR.debug >> VideoMedia: ".concat(capitalizeStr(media.mediaType), " for media > ").concat(media.id, " has started loading data . . ."));
72559
- });
72561
+ videoPlayer.player = vjsPlayer;
72562
+ // ── Early source check ────────────────────────────────────────────────
72563
+ // Two-step check before video.js tries to load anything:
72564
+ // 1. Is the file extension one we map to a MIME type?
72565
+ // 2. Can the browser actually play that MIME type?
72566
+ // Failing either step skips the media immediately so video.js
72567
+ // never renders its "No compatible source" error overlay.
72568
+ var vidType = videoFileType(getFileExt(media.uri));
72569
+ if (!vidType) {
72570
+ console.warn("XLR >> VideoMedia: unrecognised file extension for media ".concat(media.id, " (uri: ").concat(media.uri, ")"));
72571
+ reportAndStop("Unsupported video file extension for media ".concat(media.id), exports.FaultCodes.FaultVideoSource);
72572
+ return;
72573
+ }
72574
+ if (document.createElement('video').canPlayType(vidType) === '') {
72575
+ console.warn("XLR >> VideoMedia: browser cannot play type \"".concat(vidType, "\" for media ").concat(media.id));
72576
+ reportAndStop("Browser cannot play video type \"".concat(vidType, "\" for media ").concat(media.id), exports.FaultCodes.FaultVideoSource);
72577
+ return;
72578
+ }
72579
+ // ─────────────────────────────────────────────────────────────────────
72580
+ var armStallWatchdog = function armStallWatchdog() {
72581
+ clearStallWatchdog();
72582
+ stallWatchdog = setTimeout(function () {
72583
+ if (stopped) return;
72584
+ console.warn("XLR >> VideoMedia: stall timeout on media ".concat(media.id));
72585
+ reportAndStop('Video stall timeout', exports.FaultCodes.FaultVideoUnexpected);
72586
+ }, STALL_TIMEOUT_MS);
72587
+ };
72588
+ vjsPlayer.on('waiting', armStallWatchdog);
72589
+ vjsPlayer.on('stalled', armStallWatchdog);
72590
+ vjsPlayer.on('playing', clearStallWatchdog);
72591
+ vjsPlayer.on('ended', clearStallWatchdog);
72560
72592
  vjsPlayer.on('loadedmetadata', function () {
72561
72593
  if (media.duration === 0) {
72562
72594
  videoPlayer.duration = vjsPlayer.duration();
@@ -72627,34 +72659,20 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
72627
72659
  }, 5000);
72628
72660
  })]).then(function () {
72629
72661
  console.debug("??? XLR.debug >> VideoMedia: ".concat(capitalizeStr(media.mediaType), " for media > ").concat(media.id, " : Autoplay started"));
72630
- })["catch"]( /*#__PURE__*/function () {
72631
- var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(error) {
72632
- return _regeneratorRuntime().wrap(function _callee2$(_context2) {
72633
- while (1) switch (_context2.prev = _context2.next) {
72634
- case 0:
72635
- if (error === 'Timeout') {
72636
- console.debug("??? XLR.debug >> VideoMedia: ".concat(capitalizeStr(media.mediaType), " for media > ").concat(media.id, " : Promise not resolved within 5 seconds. Move to next media"));
72637
- _this.stop();
72638
- } else {
72639
- console.debug("??? XLR.debug >> VideoMedia: ".concat(capitalizeStr(media.mediaType), " for media > ").concat(media.id, " : Autoplay error: ").concat(error));
72640
- if (reportToPlayerPlatform.includes(xlr.config.platform)) {
72641
- playerReportFault('Media autoplay error', media).then(function () {
72642
- _this.stop();
72643
- });
72644
- }
72645
- }
72646
- case 1:
72647
- case "end":
72648
- return _context2.stop();
72649
- }
72650
- }, _callee2);
72651
- }));
72652
- return function (_x) {
72653
- return _ref2.apply(this, arguments);
72654
- };
72655
- }());
72662
+ })["catch"](function (error) {
72663
+ if (stopped) return;
72664
+ if (error === 'Timeout') {
72665
+ console.debug("??? XLR.debug >> VideoMedia: ".concat(capitalizeStr(media.mediaType), " for media > ").concat(media.id, " : Promise not resolved within 5 seconds. Move to next media"));
72666
+ // Timeout is a scheduling issue, not a media fault — just advance
72667
+ videoPlayer.stop();
72668
+ } else {
72669
+ console.debug("??? XLR.debug >> VideoMedia: ".concat(capitalizeStr(media.mediaType), " for media > ").concat(media.id, " : Autoplay error: ").concat(error));
72670
+ reportAndStop('Media autoplay error', exports.FaultCodes.FaultVideoUnexpected);
72671
+ }
72672
+ });
72656
72673
  // Optional: Reset the flag automatically when a new video loads or the source changes
72657
72674
  vjsPlayer.on('loadstart', function () {
72675
+ console.debug("??? XLR.debug >> VideoMedia: ".concat(capitalizeStr(media.mediaType), " for media > ").concat(media.id, " has started loading data . . ."));
72658
72676
  triggerTimeUpdate = false;
72659
72677
  });
72660
72678
  if (media.duration === 0) {
@@ -72667,13 +72685,9 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
72667
72685
  if (mediaDuration !== undefined && currentTime !== undefined) {
72668
72686
  remainingTimeMs = (mediaDuration - currentTime) * 1000;
72669
72687
  }
72670
- if (regionHasMultipleMedia && remainingTimeMs === 0 && !triggerTimeUpdate) {
72671
- // We don't have data yet and we must immediately prepare next media
72672
- media.region.prepareNextMedia();
72673
- } else if (regionHasMultipleMedia && remainingTimeMs <= preloadBufferTimeMs && !triggerTimeUpdate) {
72688
+ if (regionHasMultipleMedia && !triggerTimeUpdate && (remainingTimeMs === 0 || remainingTimeMs <= preloadBufferTimeMs)) {
72674
72689
  // Check if remaining time is less than preloadBufferTimeMs and the action hasn't been triggered yet
72675
72690
  console.log('Less than preloadBufferTimeMs remaining! Do something now.');
72676
- // Prepare next media in region
72677
72691
  media.region.prepareNextMedia();
72678
72692
  triggerTimeUpdate = true; // Set the flag to prevent re-triggering
72679
72693
  }
@@ -72685,33 +72699,16 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
72685
72699
  }
72686
72700
  }
72687
72701
  });
72688
- vjsPlayer.on('error', /*#__PURE__*/function () {
72689
- var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3(err) {
72690
- return _regeneratorRuntime().wrap(function _callee3$(_context3) {
72691
- while (1) switch (_context3.prev = _context3.next) {
72692
- case 0:
72693
- console.debug("??? XLR.debug >> VideoMedia: Media Error: ".concat(capitalizeStr(media.mediaType), " for media > ").concat(media.id));
72694
- if (reportToPlayerPlatform.includes(xlr.config.platform)) {
72695
- playerReportFault('Video file source not supported', media).then(function () {
72696
- _this.stop();
72697
- });
72698
- } else {
72699
- // End media after 5 seconds
72700
- setTimeout(function () {
72701
- console.debug("??? XLR.debug >> VideoMedia: ".concat(capitalizeStr(media.mediaType), " for media > ").concat(media.id, " has ended . . ."));
72702
- _this.stop();
72703
- }, 5000);
72704
- }
72705
- case 2:
72706
- case "end":
72707
- return _context3.stop();
72708
- }
72709
- }, _callee3);
72710
- }));
72711
- return function (_x2) {
72712
- return _ref3.apply(this, arguments);
72713
- };
72714
- }());
72702
+ vjsPlayer.on('error', function () {
72703
+ if (stopped) return;
72704
+ clearStallWatchdog();
72705
+ // Extract the actual MediaError so the fault message is
72706
+ // meaningful: code 2 = network, 3 = decode, 4 = not supported.
72707
+ var vjsError = vjsPlayer.error();
72708
+ var reason = vjsError ? "Video error (code ".concat(vjsError.code, "): ").concat(vjsError.message) : 'Unknown video error';
72709
+ console.warn("XLR >> VideoMedia: error on media ".concat(media.id), vjsError);
72710
+ reportAndStop(reason, exports.FaultCodes.FaultVideoUnexpected);
72711
+ });
72715
72712
  if (media.duration === 0) {
72716
72713
  vjsPlayer.on('ended', function () {
72717
72714
  console.debug("??? XLR.debug >> VideoMedia: onended: ".concat(capitalizeStr(media.mediaType), " for media > ").concat(media.id, " has ended playing . . ."));
@@ -72721,26 +72718,37 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
72721
72718
  }
72722
72719
  },
72723
72720
  stop: function stop() {
72721
+ var _videoPlayer$player;
72724
72722
  var disposeOnly = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
72725
- var vjsPlayer = media.player;
72723
+ clearStallWatchdog();
72724
+ // videoPlayer.player is where init() stores the vjs instance;
72725
+ // media.player is a legacy path kept for backward compat but is
72726
+ // no longer set by init(), so always prefer videoPlayer.player.
72727
+ var vjsPlayer = (_videoPlayer$player = videoPlayer.player) !== null && _videoPlayer$player !== void 0 ? _videoPlayer$player : media.player;
72726
72728
  console.debug('??? XLR.debug >> VideoMedia::stop', {
72727
72729
  vjsPlayer: vjsPlayer,
72728
- isDisposed: vjsPlayer === null || vjsPlayer === void 0 ? void 0 : vjsPlayer.isDisposed_,
72729
- el: vjsPlayer === null || vjsPlayer === void 0 ? void 0 : vjsPlayer.el_
72730
+ isDisposed: vjsPlayer === null || vjsPlayer === void 0 ? void 0 : vjsPlayer.isDisposed(),
72731
+ el: vjsPlayer === null || vjsPlayer === void 0 ? void 0 : vjsPlayer.el()
72730
72732
  });
72731
72733
  // Expire the media and dispose the video
72732
- if (vjsPlayer !== undefined && !vjsPlayer.isDisposed_) {
72734
+ if (vjsPlayer !== undefined && !vjsPlayer.isDisposed()) {
72733
72735
  if (!disposeOnly) {
72734
72736
  media.emitter.emit('end', media);
72735
72737
  }
72736
72738
  vjsPlayer.dispose();
72737
72739
  // Clear up media player
72740
+ videoPlayer.player = undefined;
72738
72741
  media.player = undefined;
72742
+ media.html = null;
72739
72743
  } else {
72744
+ videoPlayer.player = undefined;
72740
72745
  media.player = undefined;
72741
72746
  media.html = null;
72742
- media.emitter.emit('end', media);
72747
+ if (!disposeOnly) {
72748
+ media.emitter.emit('end', media);
72749
+ }
72743
72750
  }
72751
+ stopped = true;
72744
72752
  },
72745
72753
  play: function play() {
72746
72754
  var _this2 = this;
@@ -72748,9 +72756,9 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
72748
72756
  if (vjsPlayer !== undefined) {
72749
72757
  var _vjsPlayer$play;
72750
72758
  (_vjsPlayer$play = vjsPlayer.play()) === null || _vjsPlayer$play === void 0 || _vjsPlayer$play["catch"]( /*#__PURE__*/function () {
72751
- var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4(error) {
72752
- return _regeneratorRuntime().wrap(function _callee4$(_context4) {
72753
- while (1) switch (_context4.prev = _context4.next) {
72759
+ var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(error) {
72760
+ return _regeneratorRuntime().wrap(function _callee2$(_context2) {
72761
+ while (1) switch (_context2.prev = _context2.next) {
72754
72762
  case 0:
72755
72763
  if (error === 'Timeout') {
72756
72764
  console.debug("??? XLR.debug >> VideoMedia: ".concat(capitalizeStr(media.mediaType), " for media > ").concat(media.id, " : Promise not resolved within 5 seconds. Move to next media"));
@@ -72765,12 +72773,12 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
72765
72773
  }
72766
72774
  case 1:
72767
72775
  case "end":
72768
- return _context4.stop();
72776
+ return _context2.stop();
72769
72777
  }
72770
- }, _callee4);
72778
+ }, _callee2);
72771
72779
  }));
72772
- return function (_x3) {
72773
- return _ref4.apply(this, arguments);
72780
+ return function (_x) {
72781
+ return _ref2.apply(this, arguments);
72774
72782
  };
72775
72783
  }());
72776
72784
  }
@@ -73182,11 +73190,11 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
73182
73190
  return _getDataBlob.apply(this, arguments);
73183
73191
  }
73184
73192
  function _getDataBlob() {
73185
- _getDataBlob = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3(src, jwtToken) {
73186
- return _regeneratorRuntime().wrap(function _callee3$(_context3) {
73187
- while (1) switch (_context3.prev = _context3.next) {
73193
+ _getDataBlob = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(src, jwtToken) {
73194
+ return _regeneratorRuntime().wrap(function _callee2$(_context2) {
73195
+ while (1) switch (_context2.prev = _context2.next) {
73188
73196
  case 0:
73189
- return _context3.abrupt("return", fetch(src, {
73197
+ return _context2.abrupt("return", fetch(src, {
73190
73198
  method: 'GET',
73191
73199
  headers: {
73192
73200
  'X-PREVIEW-JWT': jwtToken || ''
@@ -73205,9 +73213,9 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
73205
73213
  }));
73206
73214
  case 1:
73207
73215
  case "end":
73208
- return _context3.stop();
73216
+ return _context2.stop();
73209
73217
  }
73210
- }, _callee3);
73218
+ }, _callee2);
73211
73219
  }));
73212
73220
  return _getDataBlob.apply(this, arguments);
73213
73221
  }
@@ -73215,12 +73223,12 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
73215
73223
  return _preloadMediaBlob.apply(this, arguments);
73216
73224
  }
73217
73225
  function _preloadMediaBlob() {
73218
- _preloadMediaBlob = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4(src, type, jwtToken) {
73226
+ _preloadMediaBlob = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3(src, type, jwtToken) {
73219
73227
  var res, blob, data;
73220
- return _regeneratorRuntime().wrap(function _callee4$(_context4) {
73221
- while (1) switch (_context4.prev = _context4.next) {
73228
+ return _regeneratorRuntime().wrap(function _callee3$(_context3) {
73229
+ while (1) switch (_context3.prev = _context3.next) {
73222
73230
  case 0:
73223
- _context4.next = 2;
73231
+ _context3.next = 2;
73224
73232
  return fetch(src, {
73225
73233
  method: 'GET',
73226
73234
  headers: {
@@ -73228,45 +73236,45 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
73228
73236
  }
73229
73237
  });
73230
73238
  case 2:
73231
- res = _context4.sent;
73239
+ res = _context3.sent;
73232
73240
  blob = new Blob();
73233
73241
  if (!(type === 'image')) {
73234
- _context4.next = 8;
73242
+ _context3.next = 8;
73235
73243
  break;
73236
73244
  }
73237
73245
  blob = new Blob();
73238
- _context4.next = 19;
73246
+ _context3.next = 19;
73239
73247
  break;
73240
73248
  case 8:
73241
73249
  if (!(type === 'video')) {
73242
- _context4.next = 14;
73250
+ _context3.next = 14;
73243
73251
  break;
73244
73252
  }
73245
- _context4.next = 11;
73253
+ _context3.next = 11;
73246
73254
  return res.blob();
73247
73255
  case 11:
73248
- blob = _context4.sent;
73249
- _context4.next = 19;
73256
+ blob = _context3.sent;
73257
+ _context3.next = 19;
73250
73258
  break;
73251
73259
  case 14:
73252
73260
  if (!(type === 'audio')) {
73253
- _context4.next = 19;
73261
+ _context3.next = 19;
73254
73262
  break;
73255
73263
  }
73256
- _context4.next = 17;
73264
+ _context3.next = 17;
73257
73265
  return res.arrayBuffer();
73258
73266
  case 17:
73259
- data = _context4.sent;
73267
+ data = _context3.sent;
73260
73268
  blob = new Blob([data], {
73261
73269
  type: audioFileType(getFileExt(src))
73262
73270
  });
73263
73271
  case 19:
73264
- return _context4.abrupt("return", URL.createObjectURL(blob));
73272
+ return _context3.abrupt("return", URL.createObjectURL(blob));
73265
73273
  case 20:
73266
73274
  case "end":
73267
- return _context4.stop();
73275
+ return _context3.stop();
73268
73276
  }
73269
- }, _callee4);
73277
+ }, _callee3);
73270
73278
  }));
73271
73279
  return _preloadMediaBlob.apply(this, arguments);
73272
73280
  }
@@ -73274,11 +73282,11 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
73274
73282
  return _fetchJSON.apply(this, arguments);
73275
73283
  }
73276
73284
  function _fetchJSON() {
73277
- _fetchJSON = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5(url, jwtToken) {
73278
- return _regeneratorRuntime().wrap(function _callee5$(_context5) {
73279
- while (1) switch (_context5.prev = _context5.next) {
73285
+ _fetchJSON = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4(url, jwtToken) {
73286
+ return _regeneratorRuntime().wrap(function _callee4$(_context4) {
73287
+ while (1) switch (_context4.prev = _context4.next) {
73280
73288
  case 0:
73281
- return _context5.abrupt("return", fetch(url, {
73289
+ return _context4.abrupt("return", fetch(url, {
73282
73290
  method: 'GET',
73283
73291
  headers: {
73284
73292
  'X-PREVIEW-JWT': jwtToken || ''
@@ -73290,9 +73298,9 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
73290
73298
  }));
73291
73299
  case 1:
73292
73300
  case "end":
73293
- return _context5.stop();
73301
+ return _context4.stop();
73294
73302
  }
73295
- }, _callee5);
73303
+ }, _callee4);
73296
73304
  }));
73297
73305
  return _fetchJSON.apply(this, arguments);
73298
73306
  }
@@ -73300,11 +73308,11 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
73300
73308
  return _fetchText.apply(this, arguments);
73301
73309
  }
73302
73310
  function _fetchText() {
73303
- _fetchText = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee6(url, jwtToken) {
73304
- return _regeneratorRuntime().wrap(function _callee6$(_context6) {
73305
- while (1) switch (_context6.prev = _context6.next) {
73311
+ _fetchText = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5(url, jwtToken) {
73312
+ return _regeneratorRuntime().wrap(function _callee5$(_context5) {
73313
+ while (1) switch (_context5.prev = _context5.next) {
73306
73314
  case 0:
73307
- return _context6.abrupt("return", fetch(url, {
73315
+ return _context5.abrupt("return", fetch(url, {
73308
73316
  method: 'GET',
73309
73317
  headers: {
73310
73318
  'X-PREVIEW-JWT': jwtToken || ''
@@ -73323,9 +73331,9 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
73323
73331
  }));
73324
73332
  case 1:
73325
73333
  case "end":
73326
- return _context6.stop();
73334
+ return _context5.stop();
73327
73335
  }
73328
- }, _callee6);
73336
+ }, _callee5);
73329
73337
  }));
73330
73338
  return _fetchText.apply(this, arguments);
73331
73339
  }
@@ -73442,6 +73450,32 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
73442
73450
  var today = new Date();
73443
73451
  return new Date(today.setHours(24 * numDays || 1)).toJSON();
73444
73452
  }
73453
+ /**
73454
+ * Check whether a media item is currently within its valid date window.
73455
+ * Returns true when the media should be shown, false when it should be skipped.
73456
+ *
73457
+ * Rules:
73458
+ * - Empty / invalid fromDt → treat as "no start restriction"
73459
+ * - Empty / invalid toDt → treat as "no expiry"
73460
+ * - now < fromDt → not yet active → skip
73461
+ * - now > toDt → expired → skip
73462
+ */
73463
+ function isMediaActive(fromDt, toDt) {
73464
+ var now = Date.now();
73465
+ if (fromDt) {
73466
+ var from = new Date(fromDt).getTime();
73467
+ if (!isNaN(from) && now < from) {
73468
+ return false;
73469
+ }
73470
+ }
73471
+ if (toDt) {
73472
+ var to = new Date(toDt).getTime();
73473
+ if (!isNaN(to) && now > to) {
73474
+ return false;
73475
+ }
73476
+ }
73477
+ return true;
73478
+ }
73445
73479
  /**
73446
73480
  * Check if given layout exists in the loop using layoutId
73447
73481
  * @param layouts Schedule loop unique layouts (uniqueLayouts)
@@ -73650,7 +73684,7 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
73650
73684
  var $layout = region.layout.html;
73651
73685
  var layoutSelector = '#' + region.layout.containerName + '[data-sequence="' + region.layout.index + '"]';
73652
73686
  var $layoutWithIndex = document.querySelector(layoutSelector);
73653
- var $region = document.querySelector('#' + region.containerName);
73687
+ var $region = region.html;
73654
73688
  var mediaInRegion = $region === null || $region === void 0 ? void 0 : $region.querySelector('.' + mediaId);
73655
73689
  console.debug('??? XLR.debug >> [Generators::prepareVideoMedia]', {
73656
73690
  layoutSelector: layoutSelector,
@@ -73669,7 +73703,7 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
73669
73703
  media.html = createMediaElement(media);
73670
73704
  }
73671
73705
  // Append fresh copy of the media into the region
73672
- $region !== null && $region.appendChild(media.html);
73706
+ region.html.appendChild(media.html);
73673
73707
  var isMediaInDOM = document.body.contains(media.html);
73674
73708
  console.debug('??? XLR.debug >> [Generators::prepareVideoMedia]', {
73675
73709
  isMediaInDOM: isMediaInDOM,
@@ -73678,29 +73712,9 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
73678
73712
  });
73679
73713
  // Initialize video.js
73680
73714
  media.player = videojs(mediaId, _objectSpread2(_objectSpread2({}, defaultVjsOpts), {}, {
73681
- errorDisplay: region.xlr.config.platform !== exports.ConsumerPlatform.CHROMEOS,
73715
+ errorDisplay: !reportToPlayerPlatform.includes(region.xlr.config.platform),
73682
73716
  loop: media.loop
73683
73717
  }));
73684
- media.player.on('error', /*#__PURE__*/function () {
73685
- var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(err) {
73686
- return _regeneratorRuntime().wrap(function _callee2$(_context2) {
73687
- while (1) switch (_context2.prev = _context2.next) {
73688
- case 0:
73689
- if (media.region.xlr.config.platform === exports.ConsumerPlatform.CHROMEOS) {
73690
- playerReportFault('Video file not supported', media).then(function () {
73691
- media.emitter.emit('end', media);
73692
- });
73693
- }
73694
- case 1:
73695
- case "end":
73696
- return _context2.stop();
73697
- }
73698
- }, _callee2);
73699
- }));
73700
- return function (_x10) {
73701
- return _ref3.apply(this, arguments);
73702
- };
73703
- }());
73704
73718
  media.player.el().style.setProperty('visibility', 'hidden');
73705
73719
  media.player.el().style.setProperty('opacity', '0');
73706
73720
  media.player.el().style.setProperty('z-index', '-99');
@@ -73715,9 +73729,9 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
73715
73729
  if (mediaInRegion) {
73716
73730
  mediaInRegion.remove();
73717
73731
  }
73718
- // Append media to its region
73719
- var $region = document.querySelector('#' + region.containerName);
73720
- $region !== null && $region.appendChild(media.html);
73732
+ // Append media to its region using the direct reference to avoid
73733
+ // global querySelector finding a same-named region in another layout
73734
+ region.html.appendChild(media.html);
73721
73735
  }
73722
73736
  function prepareAudioMedia(media, region) {
73723
73737
  var mediaId = getMediaId(media);
@@ -73730,9 +73744,8 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
73730
73744
  if (mediaInRegion) {
73731
73745
  mediaInRegion.remove();
73732
73746
  }
73733
- // Append media to its region
73734
- var $region = document.querySelector('#' + region.containerName);
73735
- $region !== null && $region.appendChild(media.html);
73747
+ // Append media to its region using the direct reference
73748
+ region.html.appendChild(media.html);
73736
73749
  }
73737
73750
  function prepareHtmlMedia(media, region) {
73738
73751
  // Set state as false ( for now )
@@ -73752,60 +73765,102 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
73752
73765
  media.html.innerHTML = '';
73753
73766
  media.html.appendChild(media.iframe);
73754
73767
  if (!mediaInRegion) {
73755
- // Add fresh copy of the media into the region
73756
- var _$region = document.querySelector('#' + region.containerName);
73757
- _$region !== null && _$region.appendChild(media.html);
73768
+ // Add fresh copy of the media into the region using the direct reference
73769
+ region.html.appendChild(media.html);
73758
73770
  media.ready = true;
73759
73771
  }
73760
73772
  }
73761
73773
  }
73762
- function playerReportFault(_x11, _x12) {
73774
+ exports.FaultCodes = void 0;
73775
+ (function (FaultCodes) {
73776
+ FaultCodes[FaultCodes["FaultVideoSource"] = 2001] = "FaultVideoSource";
73777
+ FaultCodes[FaultCodes["FaultVideoUnexpected"] = 2099] = "FaultVideoUnexpected";
73778
+ })(exports.FaultCodes || (exports.FaultCodes = {}));
73779
+ function playerReportFault(_x10, _x11) {
73763
73780
  return _playerReportFault.apply(this, arguments);
73764
73781
  }
73765
73782
  function _playerReportFault() {
73766
- _playerReportFault = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee7(msg, media) {
73767
- var playerSW, hasSW;
73768
- return _regeneratorRuntime().wrap(function _callee7$(_context7) {
73769
- while (1) switch (_context7.prev = _context7.next) {
73783
+ _playerReportFault = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee6(msg, media) {
73784
+ var code,
73785
+ platform,
73786
+ playerSW,
73787
+ hasSW,
73788
+ mediaFault,
73789
+ channel,
73790
+ _args6 = arguments;
73791
+ return _regeneratorRuntime().wrap(function _callee6$(_context6) {
73792
+ while (1) switch (_context6.prev = _context6.next) {
73770
73793
  case 0:
73794
+ code = _args6.length > 2 && _args6[2] !== undefined ? _args6[2] : exports.FaultCodes.FaultVideoUnexpected;
73771
73795
  // Immediately expire media and report a fault
73796
+ platform = media.region.xlr.config.platform;
73772
73797
  playerSW = PwaSW();
73773
- _context7.next = 3;
73798
+ _context6.next = 5;
73774
73799
  return playerSW.getSW();
73775
- case 3:
73776
- hasSW = _context7.sent;
73777
- if (hasSW) {
73778
- playerSW.postMsg({
73779
- type: 'MEDIA_FAULT',
73780
- code: 5002,
73781
- reason: msg,
73800
+ case 5:
73801
+ hasSW = _context6.sent;
73802
+ mediaFault = {
73803
+ type: 'MEDIA_FAULT',
73804
+ code: code,
73805
+ reason: msg,
73806
+ mediaId: media.id,
73807
+ regionId: media.region.id,
73808
+ layoutId: media.region.layout.id,
73809
+ date: format(new Date(), 'yyyy-MM-dd HH:mm:ss'),
73810
+ // Temporary setting
73811
+ expires: format(new Date(setExpiry(1)), 'yyyy-MM-dd HH:mm:ss')
73812
+ };
73813
+ console.debug('playerReportFault >> Reporting media fault', {
73814
+ mediaFault: mediaFault,
73815
+ platform: platform,
73816
+ hasSW: hasSW
73817
+ });
73818
+ if (!(platform === exports.ConsumerPlatform.CHROMEOS && hasSW)) {
73819
+ _context6.next = 12;
73820
+ break;
73821
+ }
73822
+ return _context6.abrupt("return", playerSW.postMsg(mediaFault).then(function () {
73823
+ // We try to prepare next media if we have more than 1 media
73824
+ if (media.region.totalMediaObjects > 1) {
73825
+ media.region.prepareNextMedia();
73826
+ }
73827
+ })["finally"](function () {
73828
+ // Stopping media as we have reported the error as fault
73829
+ console.debug('??? XLR.debug >> VideoMedia - Done reporting media fault', {
73782
73830
  mediaId: media.id,
73783
- regionId: media.region.id,
73784
- layoutId: media.region.layout.id,
73785
- date: format(new Date(), 'yyyy-MM-dd HH:mm:ss'),
73786
- // Temporary setting
73787
- expires: format(new Date(setExpiry(1)), 'yyyy-MM-dd HH:mm:ss')
73788
- }).then(function () {
73789
- // We try to prepare next media if we have more than 1 media
73790
- if (media.region.totalMediaObjects > 1) {
73791
- media.region.prepareNextMedia();
73792
- }
73793
- })["finally"](function () {
73794
- // Stopping media as we have reported the error as fault
73795
- console.debug('??? XLR.debug >> VideoMedia - Done reporting media fault', {
73796
- mediaId: media.id,
73797
- regionItems: media.region.totalMediaObjects
73798
- });
73831
+ regionItems: media.region.totalMediaObjects
73799
73832
  });
73833
+ }));
73834
+ case 12:
73835
+ if (!(platform === exports.ConsumerPlatform.ELECTRON)) {
73836
+ _context6.next = 17;
73837
+ break;
73800
73838
  }
73801
- case 5:
73839
+ // Create a broadcast channel to report media fault to the main process
73840
+ channel = new BroadcastChannel('player-faults-bc');
73841
+ channel.postMessage(mediaFault);
73842
+ console.debug('playerReportFault >> Electron platform - posted media fault to channel', {
73843
+ mediaFault: mediaFault
73844
+ });
73845
+ // channel.close();
73846
+ return _context6.abrupt("return", Promise.resolve());
73847
+ case 17:
73848
+ return _context6.abrupt("return", Promise.resolve());
73849
+ case 18:
73802
73850
  case "end":
73803
- return _context7.stop();
73851
+ return _context6.stop();
73804
73852
  }
73805
- }, _callee7);
73853
+ }, _callee6);
73806
73854
  }));
73807
73855
  return _playerReportFault.apply(this, arguments);
73808
73856
  }
73857
+ function setLayoutIndex(layout, layoutIndex) {
73858
+ if (!layout || layout.id === null) {
73859
+ return;
73860
+ }
73861
+ layout.index = layoutIndex;
73862
+ return layout;
73863
+ }
73809
73864
 
73810
73865
  const urlAlphabet =
73811
73866
  'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict';
@@ -73823,7 +73878,7 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
73823
73878
  function AudioMedia(media) {
73824
73879
  var audioMediaObject = {
73825
73880
  init: function init() {
73826
- var $audioMedia = document.getElementById(getMediaId(media));
73881
+ var $audioMedia = media.html;
73827
73882
  var $playBtn = null;
73828
73883
  if ($audioMedia) {
73829
73884
  $audioMedia.onloadstart = function () {
@@ -73886,6 +73941,8 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
73886
73941
  _this$xml3,
73887
73942
  _this$xml4,
73888
73943
  _this$xml5,
73944
+ _this$xml6,
73945
+ _this$xml7,
73889
73946
  _this = this;
73890
73947
  _classCallCheck(this, Media);
73891
73948
  _defineProperty(this, "attachedAudio", false);
@@ -73898,6 +73955,7 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
73898
73955
  _defineProperty(this, "enableStat", false);
73899
73956
  _defineProperty(this, "fileId", '');
73900
73957
  _defineProperty(this, "finished", false);
73958
+ _defineProperty(this, "fromDt", '');
73901
73959
  _defineProperty(this, "html", null);
73902
73960
  _defineProperty(this, "id", '');
73903
73961
  _defineProperty(this, "idCounter", 0);
@@ -73919,6 +73977,7 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
73919
73977
  _defineProperty(this, "state", MediaState.IDLE);
73920
73978
  _defineProperty(this, "tempSrc", '');
73921
73979
  _defineProperty(this, "timeoutId", setTimeout(function () {}, 0));
73980
+ _defineProperty(this, "toDt", '');
73922
73981
  _defineProperty(this, "type", '');
73923
73982
  _defineProperty(this, "uri", '');
73924
73983
  _defineProperty(this, "url", null);
@@ -73945,12 +74004,14 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
73945
74004
  this.duration = parseInt((_this$xml4 = this.xml) === null || _this$xml4 === void 0 ? void 0 : _this$xml4.getAttribute('duration')) || 0;
73946
74005
  this.enableStat = Boolean(((_this$xml5 = this.xml) === null || _this$xml5 === void 0 ? void 0 : _this$xml5.getAttribute('enableStat')) || false);
73947
74006
  this.hasCommandExecuted = false;
74007
+ this.fromDt = ((_this$xml6 = this.xml) === null || _this$xml6 === void 0 ? void 0 : _this$xml6.getAttribute('fromDt')) || '';
74008
+ this.toDt = ((_this$xml7 = this.xml) === null || _this$xml7 === void 0 ? void 0 : _this$xml7.getAttribute('toDt')) || '';
73948
74009
  this.on('start', function (media) {
73949
74010
  if (media.state === MediaState.PLAYING) return;
73950
74011
  media.state = MediaState.PLAYING;
73951
74012
  if (media.mediaType === 'video') {
73952
- var videoMedia = VideoMedia(media, _this.xlr);
73953
- videoMedia.init();
74013
+ media.videoHandler = VideoMedia(media, _this.xlr);
74014
+ media.videoHandler.init();
73954
74015
  if (media.duration > 0) {
73955
74016
  _this.startMediaTimer(media);
73956
74017
  }
@@ -74077,8 +74138,8 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
74077
74138
  if (media.mediaType === 'video') {
74078
74139
  // Dispose the video media
74079
74140
  console.debug("??? XLR.debug >> VideoMedia::stop - ".concat(capitalizeStr(media.mediaType), " for media > ").concat(media.id, " has ended playing . . ."));
74080
- if (media.player !== undefined) {
74081
- VideoMedia(media, _this2.xlr).stop(true);
74141
+ if (media.videoHandler !== undefined) {
74142
+ media.videoHandler.stop(true);
74082
74143
  }
74083
74144
  }
74084
74145
  }
@@ -74093,8 +74154,8 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
74093
74154
  }, {
74094
74155
  key: "init",
74095
74156
  value: function init() {
74096
- var _this$xml6;
74097
- var mediaOptions = (_this$xml6 = this.xml) === null || _this$xml6 === void 0 ? void 0 : _this$xml6.getElementsByTagName('options');
74157
+ var _this$xml8;
74158
+ var mediaOptions = (_this$xml8 = this.xml) === null || _this$xml8 === void 0 ? void 0 : _this$xml8.getElementsByTagName('options');
74098
74159
  if (mediaOptions) {
74099
74160
  for (var _i = 0, _Array$from = Array.from(mediaOptions); _i < _Array$from.length; _i++) {
74100
74161
  var _options = _Array$from[_i];
@@ -74149,6 +74210,10 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
74149
74210
  }
74150
74211
  } else if (this.xlr.config.platform === exports.ConsumerPlatform.ELECTRON) {
74151
74212
  tmpUrl = composeResourceUrlByPlatform(this.xlr.config, resourceUrlParams);
74213
+ // this is an SSP Layout
74214
+ if (this.region.layout.layoutId === -1) {
74215
+ tmpUrl = this.uri;
74216
+ }
74152
74217
  }
74153
74218
  this.url = tmpUrl;
74154
74219
  // Loop if media has loop, or if region has loop and a single media
@@ -74191,8 +74256,8 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
74191
74256
  mediaType: _this3.mediaType,
74192
74257
  containerName: _this3.containerName
74193
74258
  });
74194
- var $region = document.querySelector('#' + _this3.region.containerName);
74195
- var $media = $region !== null && $region.querySelector('.' + mediaId);
74259
+ var $region = _this3.region.html;
74260
+ var $media = $region.querySelector('.' + mediaId);
74196
74261
  if (!$media) {
74197
74262
  $media = getNewMedia();
74198
74263
  }
@@ -74256,13 +74321,13 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
74256
74321
  }
74257
74322
  };
74258
74323
  var getNewMedia = function getNewMedia() {
74259
- var $region = document.getElementById("".concat(_this3.region.containerName));
74324
+ var $region = _this3.region.html;
74260
74325
  // This function is for checking whether
74261
74326
  // the region still has to show a media item
74262
74327
  // when another region is not finished yet
74263
74328
  if (_this3.region.complete && !_this3.region.layout.allEnded) {
74264
74329
  // Add currentMedia to the region
74265
- $region && $region.insertBefore(_this3.html, $region.lastElementChild);
74330
+ $region.insertBefore(_this3.html, $region.lastElementChild);
74266
74331
  return _this3.html;
74267
74332
  }
74268
74333
  return null;
@@ -74273,23 +74338,18 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
74273
74338
  key: "stop",
74274
74339
  value: function () {
74275
74340
  var _stop = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
74276
- var $media;
74277
74341
  return _regeneratorRuntime().wrap(function _callee$(_context) {
74278
74342
  while (1) switch (_context.prev = _context.next) {
74279
74343
  case 0:
74280
- $media = document.getElementById(getMediaId({
74281
- mediaType: this.mediaType,
74282
- containerName: this.containerName
74283
- }));
74284
- if ($media) {
74285
- $media.style.display = 'none';
74286
- $media.remove();
74344
+ if (this.html) {
74345
+ this.html.style.display = 'none';
74346
+ this.html.remove();
74287
74347
  }
74288
74348
  // Release blob URLs for image media to prevent memory leaks on long-running signage
74289
74349
  if (this.mediaType === 'image' && this.url) {
74290
74350
  BlobLoader.release(this.url);
74291
74351
  }
74292
- case 3:
74352
+ case 2:
74293
74353
  case "end":
74294
74354
  return _context.stop();
74295
74355
  }
@@ -74462,18 +74522,30 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
74462
74522
  this.html = $region;
74463
74523
  /* Parse region media objects */
74464
74524
  var regionMediaItems = Array.from(this.xml.getElementsByTagName('media'));
74465
- this.totalMediaObjects = regionMediaItems.length;
74466
74525
  $layout && $layout.appendChild(this.html);
74467
74526
  Array.from(regionMediaItems).forEach( /*#__PURE__*/function () {
74468
74527
  var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(mediaXml, indx) {
74469
- var mediaObj;
74528
+ var fromDt, toDt, mediaObj;
74470
74529
  return _regeneratorRuntime().wrap(function _callee$(_context) {
74471
74530
  while (1) switch (_context.prev = _context.next) {
74472
74531
  case 0:
74532
+ fromDt = mediaXml.getAttribute('fromDt') || '';
74533
+ toDt = mediaXml.getAttribute('toDt') || '';
74534
+ if (isMediaActive(fromDt, toDt)) {
74535
+ _context.next = 5;
74536
+ break;
74537
+ }
74538
+ console.debug('??? XLR.debug >> Region::prepareRegion - skipping expired/inactive media', {
74539
+ mediaId: mediaXml.getAttribute('id'),
74540
+ fromDt: fromDt,
74541
+ toDt: toDt
74542
+ });
74543
+ return _context.abrupt("return");
74544
+ case 5:
74473
74545
  mediaObj = new Media(_this, (mediaXml === null || mediaXml === void 0 ? void 0 : mediaXml.getAttribute('id')) || '', mediaXml, _this.options, _this.xlr);
74474
74546
  mediaObj.index = indx;
74475
74547
  _this.mediaObjects.push(mediaObj);
74476
- case 3:
74548
+ case 8:
74477
74549
  case "end":
74478
74550
  return _context.stop();
74479
74551
  }
@@ -74483,6 +74555,7 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
74483
74555
  return _ref.apply(this, arguments);
74484
74556
  };
74485
74557
  }());
74558
+ this.totalMediaObjects = this.mediaObjects.length;
74486
74559
  console.debug('??? XLR.debug >> Region - done looping through media', {
74487
74560
  mediaObjects: this.mediaObjects
74488
74561
  });
@@ -74538,6 +74611,23 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
74538
74611
  key: "prepareNextMedia",
74539
74612
  value: function prepareNextMedia() {
74540
74613
  var nextMediaIndex = (this.currentMediaIndex + 1) % this.totalMediaObjects;
74614
+ // Skip over any media items that are no longer within their active date window
74615
+ var skippedCount = 0;
74616
+ while (skippedCount < this.totalMediaObjects) {
74617
+ var candidate = this.mediaObjects[nextMediaIndex];
74618
+ if (isMediaActive(candidate.fromDt, candidate.toDt)) {
74619
+ break;
74620
+ }
74621
+ skippedCount++;
74622
+ nextMediaIndex = (nextMediaIndex + 1) % this.totalMediaObjects;
74623
+ }
74624
+ // Nothing to pre-load when:
74625
+ // - every item is expired, OR
74626
+ // - the only active item is the one currently playing (skip loop wrapped back to it)
74627
+ if (skippedCount >= this.totalMediaObjects || nextMediaIndex === this.currentMediaIndex) {
74628
+ console.debug('<><> XLR.debug >> [Region::prepareNextMedia()] - no active next media to preload');
74629
+ return;
74630
+ }
74541
74631
  var nextMedia = this.mediaObjects[nextMediaIndex];
74542
74632
  console.debug('<><> XLR.debug >> [Media] - [Region::prepareNextMedia()] - Preparing next media', {
74543
74633
  currentMediaIndex: this.currentMediaIndex,
@@ -74578,9 +74668,21 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
74578
74668
  }, {
74579
74669
  key: "run",
74580
74670
  value: function run() {
74671
+ var _this$currMedia, _this$oldMedia2;
74581
74672
  console.debug('??? XLR.debug >> Region Called Region::run > ', this.id);
74582
74673
  // Reset region states
74583
74674
  this.reset();
74675
+ // All media were filtered out (all expired/inactive before this run started)
74676
+ if (this.mediaObjects.length === 0) {
74677
+ console.debug('??? XLR.debug >> Region::run - no active media, finishing region', this.id);
74678
+ this.finished();
74679
+ return;
74680
+ }
74681
+ console.debug('??? XLR.debug >> Region Called Region::run - after reset > ', {
74682
+ regionId: this.id,
74683
+ currMedia: (_this$currMedia = this.currMedia) === null || _this$currMedia === void 0 ? void 0 : _this$currMedia.containerName,
74684
+ oldMedia: (_this$oldMedia2 = this.oldMedia) === null || _this$oldMedia2 === void 0 ? void 0 : _this$oldMedia2.containerName
74685
+ });
74584
74686
  if (this.currMedia) {
74585
74687
  this.transitionNodes(this.oldMedia, this.currMedia);
74586
74688
  }
@@ -74629,6 +74731,7 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
74629
74731
  // Hide oldMedia
74630
74732
  if (oldMedia) {
74631
74733
  var $layout = document.querySelector("#".concat(_this2.layout.containerName, "[data-sequence=\"").concat(_this2.layout.index, "\"]"));
74734
+ if (!$layout) return;
74632
74735
  var $region = $layout.querySelector('#' + _this2.containerName);
74633
74736
  var $oldMedia = $region ? $region.querySelector('.' + getMediaId(oldMedia)) : null;
74634
74737
  if ($oldMedia) {
@@ -74649,7 +74752,7 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
74649
74752
  $videoWrapper.style.setProperty('visibility', 'hidden');
74650
74753
  $videoWrapper.style.setProperty('z-index', '-999');
74651
74754
  $videoWrapper.style.setProperty('opacity', '0');
74652
- if (oldMedia.player && oldMedia.videoHandler) {
74755
+ if (oldMedia.videoHandler) {
74653
74756
  oldMedia.videoHandler.stop(true);
74654
74757
  }
74655
74758
  }
@@ -74709,13 +74812,13 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
74709
74812
  }, {
74710
74813
  key: "playNextMedia",
74711
74814
  value: function playNextMedia() {
74712
- var _this$oldMedia2, _this$currMedia, _this$nxtMedia, _this$currMedia2, _this$currMedia3, _this$currMedia4, _this$currMedia5, _this$currMedia6, _this$oldMedia3, _this$currMedia7, _this$nxtMedia2;
74815
+ var _this$oldMedia3, _this$currMedia2, _this$nxtMedia, _this$currMedia3, _this$currMedia4, _this$currMedia5, _this$currMedia6, _this$oldMedia4, _this$currMedia7, _this$nxtMedia2;
74713
74816
  console.debug('??? XLR.debug Region playing next media', {
74714
74817
  regionId: this.id,
74715
74818
  currentMediaIndex: this.currentMediaIndex,
74716
74819
  mediaItemsLn: this.mediaObjects.length,
74717
- oldMedia: (_this$oldMedia2 = this.oldMedia) === null || _this$oldMedia2 === void 0 ? void 0 : _this$oldMedia2.containerName,
74718
- currMedia: (_this$currMedia = this.currMedia) === null || _this$currMedia === void 0 ? void 0 : _this$currMedia.containerName,
74820
+ oldMedia: (_this$oldMedia3 = this.oldMedia) === null || _this$oldMedia3 === void 0 ? void 0 : _this$oldMedia3.containerName,
74821
+ currMedia: (_this$currMedia2 = this.currMedia) === null || _this$currMedia2 === void 0 ? void 0 : _this$currMedia2.containerName,
74719
74822
  nxtMedia: (_this$nxtMedia = this.nxtMedia) === null || _this$nxtMedia === void 0 ? void 0 : _this$nxtMedia.containerName
74720
74823
  });
74721
74824
  /* The current media has finished running */
@@ -74725,33 +74828,20 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
74725
74828
  });
74726
74829
  return;
74727
74830
  }
74728
- // Are we in a playlist, and has the playlist completed a full cycle?
74729
- var isLastMediaInPlaylist = this.currentMediaIndex === this.mediaObjects.length - 1 && this.mediaObjects.length > 1;
74730
- // If yes, enable shell command widgets again (if any), so they execute on the next playlist cycle
74731
- if (isLastMediaInPlaylist) {
74732
- this.mediaObjects.forEach(function (media) {
74733
- if (media.mediaType === 'shellcommand') {
74734
- // reset per-playlist-cycle execution state
74735
- media.hasCommandExecuted = false;
74736
- }
74737
- });
74738
- }
74739
- if (!this.layout.isOverlay && this.currentMediaIndex === this.mediaObjects.length - 1) {
74740
- this.finished();
74741
- if (this.layout.allEnded) {
74742
- console.debug('??? XLR.debug >> Region - playNextMedia - layout all ended');
74743
- return;
74744
- }
74745
- }
74831
+ // Snapshot the index of the media that just ended so we can detect
74832
+ // cycle completion after the skip loop runs.
74833
+ var origIndex = this.currentMediaIndex;
74746
74834
  // When the region has completed and when currentMedia is html
74747
74835
  // Then, preserve the currentMedia state
74748
- if (this.complete && ((_this$currMedia2 = this.currMedia) === null || _this$currMedia2 === void 0 ? void 0 : _this$currMedia2.render) === 'html') {
74836
+ if (this.complete && ((_this$currMedia3 = this.currMedia) === null || _this$currMedia3 === void 0 ? void 0 : _this$currMedia3.render) === 'html') {
74749
74837
  return;
74750
74838
  }
74751
74839
  // When the region has completed and mediaObjects.length = 1
74752
- // and curMedia.loop = false, then put the media on
74753
- // its current state
74754
- if (this.complete && this.mediaObjects.length === 1 && ((_this$currMedia3 = this.currMedia) === null || _this$currMedia3 === void 0 ? void 0 : _this$currMedia3.render) !== 'html' && (((_this$currMedia4 = this.currMedia) === null || _this$currMedia4 === void 0 ? void 0 : _this$currMedia4.mediaType) === 'image' || ((_this$currMedia5 = this.currMedia) === null || _this$currMedia5 === void 0 ? void 0 : _this$currMedia5.mediaType) === 'video') && !((_this$currMedia6 = this.currMedia) !== null && _this$currMedia6 !== void 0 && _this$currMedia6.loop)) {
74840
+ // and render is not html, preserve the current media state without
74841
+ // calling transitionNodes (which would remove the media from DOM for 1s).
74842
+ // Do NOT restart the media timer here the layout will end naturally when
74843
+ // regionExpired() detects all regions complete on the next cycle.
74844
+ if (this.complete && this.mediaObjects.length === 1 && ((_this$currMedia4 = this.currMedia) === null || _this$currMedia4 === void 0 ? void 0 : _this$currMedia4.render) !== 'html' && (((_this$currMedia5 = this.currMedia) === null || _this$currMedia5 === void 0 ? void 0 : _this$currMedia5.mediaType) === 'image' || ((_this$currMedia6 = this.currMedia) === null || _this$currMedia6 === void 0 ? void 0 : _this$currMedia6.mediaType) === 'video')) {
74755
74845
  return;
74756
74846
  }
74757
74847
  if (this.currMedia) {
@@ -74759,17 +74849,51 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
74759
74849
  } else {
74760
74850
  this.oldMedia = undefined;
74761
74851
  }
74762
- this.currentMediaIndex = (this.currentMediaIndex + 1) % this.totalMediaObjects;
74852
+ this.currentMediaIndex = (origIndex + 1) % this.totalMediaObjects;
74763
74853
  this.currMedia = this.mediaObjects[this.currentMediaIndex];
74854
+ // Skip media items that are no longer within their active date window
74855
+ var skippedCount = 0;
74856
+ while (this.currMedia && !isMediaActive(this.currMedia.fromDt, this.currMedia.toDt)) {
74857
+ skippedCount++;
74858
+ if (skippedCount >= this.totalMediaObjects) {
74859
+ // Every item in the playlist has expired; finish this region
74860
+ console.debug('??? XLR.debug >> Region::playNextMedia - all media expired, finishing region', this.id);
74861
+ this.finished();
74862
+ return;
74863
+ }
74864
+ this.currentMediaIndex = (this.currentMediaIndex + 1) % this.totalMediaObjects;
74865
+ this.currMedia = this.mediaObjects[this.currentMediaIndex];
74866
+ }
74764
74867
  this.nxtMedia = this.mediaObjects[(this.currentMediaIndex + 1) % this.totalMediaObjects];
74868
+ // A full playlist cycle has been traversed when the total advancement
74869
+ // (the initial +1 step plus any skips over expired items) reaches or
74870
+ // crosses the end of the array.
74871
+ var crossedEnd = origIndex + 1 + skippedCount >= this.totalMediaObjects;
74872
+ // Re-enable shell command widgets at the end of each full cycle so they
74873
+ // execute again on the next pass.
74874
+ if (crossedEnd && this.mediaObjects.length > 1) {
74875
+ this.mediaObjects.forEach(function (media) {
74876
+ if (media.mediaType === 'shellcommand') {
74877
+ // reset per-playlist-cycle execution state
74878
+ media.hasCommandExecuted = false;
74879
+ }
74880
+ });
74881
+ }
74765
74882
  console.debug('??? XLR.debug >> End Region::playNextMedia > execute transitionNodes', {
74766
74883
  regionId: this.id,
74767
74884
  currentMediaIndex: this.currentMediaIndex,
74768
74885
  mediaItemsLn: this.mediaObjects.length,
74769
- oldMedia: (_this$oldMedia3 = this.oldMedia) === null || _this$oldMedia3 === void 0 ? void 0 : _this$oldMedia3.containerName,
74886
+ oldMedia: (_this$oldMedia4 = this.oldMedia) === null || _this$oldMedia4 === void 0 ? void 0 : _this$oldMedia4.containerName,
74770
74887
  currMedia: (_this$currMedia7 = this.currMedia) === null || _this$currMedia7 === void 0 ? void 0 : _this$currMedia7.containerName,
74771
74888
  nxtMedia: (_this$nxtMedia2 = this.nxtMedia) === null || _this$nxtMedia2 === void 0 ? void 0 : _this$nxtMedia2.containerName
74772
74889
  });
74890
+ if (!this.layout.isOverlay && crossedEnd) {
74891
+ this.finished();
74892
+ if (this.layout.allEnded) {
74893
+ console.debug('??? XLR.debug >> Region - playNextMedia - layout all ended');
74894
+ return;
74895
+ }
74896
+ }
74773
74897
  this.transitionNodes(this.oldMedia, this.currMedia);
74774
74898
  }
74775
74899
  }, {
@@ -74798,8 +74922,7 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
74798
74922
  }, {
74799
74923
  key: "exitTransition",
74800
74924
  value: function exitTransition() {
74801
- /* TODO: Actually implement region exit transitions */
74802
- document.getElementById("".concat(this.containerName));
74925
+ /* TODO: Actually implement region exit transitions using this.html */
74803
74926
  console.debug('Called Region::exitTransition ', this.id);
74804
74927
  this.exitTransitionComplete();
74805
74928
  }
@@ -74981,10 +75104,16 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
74981
75104
  }, {
74982
75105
  key: "openLayoutInNewTab",
74983
75106
  value: function openLayoutInNewTab(layoutCode, options) {
74984
- if (confirm(this.translations.navigateToLayout.replace('[layoutTag]', layoutCode))) {
74985
- var url = options.layoutPreviewUrl.replace('[layoutCode]', layoutCode) + '?findByCode=1';
74986
- window.open(url, '_blank');
74987
- }
75107
+ var url = options.layoutPreviewUrl.replace('[layoutCode]', layoutCode) + '?findByCode=1';
75108
+ // Send a postMessage to the parent frame so the CMS can handle the confirmation
75109
+ // and navigation (confirm() is blocked in sandboxed iframes without allow-modals).
75110
+ window.parent.postMessage({
75111
+ type: 'xlr:navLayout',
75112
+ layoutCode: layoutCode,
75113
+ url: url
75114
+ }, '*');
75115
+ // Also emit via the XLR event system for non-iframe consumers.
75116
+ this.parent.xlr.emitter.emit('navLayout', layoutCode, url);
74988
75117
  }
74989
75118
  }, {
74990
75119
  key: "openLayoutInPlayer",
@@ -75093,7 +75222,7 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
75093
75222
  if (dataset.source === 'region') {
75094
75223
  // Try to find the region
75095
75224
  if (regionObj.id === dataset.sourceid) {
75096
- $sourceObj = document.getElementById(regionObj.containerName);
75225
+ $sourceObj = regionObj.html;
75097
75226
  break;
75098
75227
  }
75099
75228
  } else if (dataset.source === 'widget') {
@@ -75102,7 +75231,7 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
75102
75231
  for (var _i2 = 0, _mediaObjects = mediaObjects; _i2 < _mediaObjects.length; _i2++) {
75103
75232
  var mediaObject = _mediaObjects[_i2];
75104
75233
  if (mediaObject.id === dataset.sourceid) {
75105
- $sourceObj = document.getElementById(mediaObject.containerName);
75234
+ $sourceObj = mediaObject.html;
75106
75235
  break;
75107
75236
  }
75108
75237
  }
@@ -75367,7 +75496,11 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
75367
75496
  this.on('start', function (layout) {
75368
75497
  layout.done = false;
75369
75498
  layout.state = exports.ELayoutState.RUNNING;
75370
- console.debug('>>>> XLR.debug Layout start emitted > Layout ID > ', layout.id);
75499
+ console.debug('>>>> XLR.debug Layout start emitted > Layout > ', {
75500
+ layoutId: layout.id,
75501
+ layoutIndex: layout.index,
75502
+ layoutState: layout.state
75503
+ });
75371
75504
  // Check if stats are enabled for the layout
75372
75505
  if (layout.enableStat) {
75373
75506
  _this.statsBC.postMessage({
@@ -75388,12 +75521,21 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
75388
75521
  while (1) switch (_context2.prev = _context2.next) {
75389
75522
  case 0:
75390
75523
  if (!(layout.state === exports.ELayoutState.CANCELLED)) {
75391
- _context2.next = 2;
75524
+ _context2.next = 3;
75392
75525
  break;
75393
75526
  }
75527
+ console.debug('>>>> XLR.debug Layout end emitted but layout is already cancelled > Layout ID > ', {
75528
+ layoutId: layout.id,
75529
+ layoutIndex: layout.index,
75530
+ layoutState: layout.state
75531
+ });
75394
75532
  return _context2.abrupt("return");
75395
- case 2:
75396
- console.debug('>>>> XLR.debug Ending layout with ID of > ', layout.layoutId);
75533
+ case 3:
75534
+ console.debug('>>>> XLR.debug Ending layout', {
75535
+ layoutId: layout.id,
75536
+ layoutIndex: layout.index,
75537
+ layoutState: layout.state
75538
+ });
75397
75539
  /* Remove layout that has ended */
75398
75540
  $layout = document.querySelector("#".concat(layout.containerName, "[data-sequence=\"").concat(layout.index, "\"]")); // Only update layout.state when last state === RUNNING
75399
75541
  if (layout.state === exports.ELayoutState.RUNNING) {
@@ -75401,8 +75543,13 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
75401
75543
  layout.state = exports.ELayoutState.PLAYED;
75402
75544
  }
75403
75545
  layout.done = true;
75404
- console.debug({
75405
- $layout: $layout
75546
+ console.debug('>>> XLR.debug Layout end emitted > Layout ID > ', {
75547
+ $layout: $layout,
75548
+ layoutId: layout.id,
75549
+ layoutIndex: layout.index,
75550
+ layoutState: layout.state,
75551
+ isOverlay: layout.isOverlay,
75552
+ isInterrupt: layout.isInterrupt()
75406
75553
  });
75407
75554
  if ($layout !== null) {
75408
75555
  $layout.style.setProperty('visibility', 'hidden');
@@ -75427,9 +75574,9 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
75427
75574
  }
75428
75575
  // Emit layout end event
75429
75576
  console.debug('>>>>> XLR.debug Awaited XLR::emitSync > End - Calling layoutEnd event');
75430
- _context2.next = 12;
75577
+ _context2.next = 13;
75431
75578
  return layout.xlr.emitSync('layoutEnd', layout);
75432
- case 12:
75579
+ case 13:
75433
75580
  if (_this.xlr.config.platform !== exports.ConsumerPlatform.CMS && layout.inLoop) {
75434
75581
  // Transition next layout to current layout and prepare next layout if exist
75435
75582
  _this.xlr.prepareLayouts().then( /*#__PURE__*/function () {
@@ -75459,7 +75606,7 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
75459
75606
  };
75460
75607
  }());
75461
75608
  }
75462
- case 13:
75609
+ case 14:
75463
75610
  case "end":
75464
75611
  return _context2.stop();
75465
75612
  }
@@ -75472,6 +75619,34 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
75472
75619
  this.on('cancelled', function (layout) {
75473
75620
  console.debug('>>>>> XLR.debug / Layout cancelled > Layout ID > ', layout.id);
75474
75621
  layout.state = exports.ELayoutState.CANCELLED;
75622
+ layout.inLoop = false;
75623
+ // Dispose video handlers immediately so their stall watchdogs and error
75624
+ // callbacks can't fire against a layout whose DOM is about to be removed.
75625
+ var _iterator = _createForOfIteratorHelper(layout.regions),
75626
+ _step;
75627
+ try {
75628
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
75629
+ var region = _step.value;
75630
+ var _iterator2 = _createForOfIteratorHelper(region.mediaObjects),
75631
+ _step2;
75632
+ try {
75633
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
75634
+ var media = _step2.value;
75635
+ if (media.videoHandler) {
75636
+ media.videoHandler.stop(true);
75637
+ }
75638
+ }
75639
+ } catch (err) {
75640
+ _iterator2.e(err);
75641
+ } finally {
75642
+ _iterator2.f();
75643
+ }
75644
+ }
75645
+ } catch (err) {
75646
+ _iterator.e(err);
75647
+ } finally {
75648
+ _iterator.f();
75649
+ }
75475
75650
  });
75476
75651
  }
75477
75652
  return _createClass(Layout, [{
@@ -75613,6 +75788,14 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
75613
75788
  if ($splashScreen) {
75614
75789
  $splashScreen.style.display = 'none';
75615
75790
  }
75791
+ // Check if $layoutContainer is still in the DOM before trying to play regions, as the layout may have been removed while waiting for a long-running region to finish.
75792
+ console.debug('??? XLR.debug >> Layout::run() - Checking if layout container is still in the DOM before playing regions...', {
75793
+ layoutId: this.id,
75794
+ layoutContainerExists: !!$layoutContainer,
75795
+ $layoutContainer: $layoutContainer,
75796
+ layoutIndex: this.index,
75797
+ shouldParse: false
75798
+ });
75616
75799
  if ($layoutContainer) {
75617
75800
  $layoutContainer.style.setProperty('visibility', 'visible');
75618
75801
  $layoutContainer.style.setProperty('opacity', '1');
@@ -75643,19 +75826,19 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
75643
75826
  key: "regionExpired",
75644
75827
  value: function regionExpired() {
75645
75828
  this.allExpired = true;
75646
- var _iterator = _createForOfIteratorHelper(this.regions),
75647
- _step;
75829
+ var _iterator3 = _createForOfIteratorHelper(this.regions),
75830
+ _step3;
75648
75831
  try {
75649
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
75650
- var layoutRegion = _step.value;
75832
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
75833
+ var layoutRegion = _step3.value;
75651
75834
  if (!layoutRegion.complete) {
75652
75835
  this.allExpired = false;
75653
75836
  }
75654
75837
  }
75655
75838
  } catch (err) {
75656
- _iterator.e(err);
75839
+ _iterator3.e(err);
75657
75840
  } finally {
75658
- _iterator.f();
75841
+ _iterator3.f();
75659
75842
  }
75660
75843
  if (this.allExpired) {
75661
75844
  this.end();
@@ -75666,17 +75849,17 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
75666
75849
  value: function end() {
75667
75850
  console.debug('Executing Layout::end and Calling Region::end ', this);
75668
75851
  /* Ask the layout to gracefully stop running now */
75669
- var _iterator2 = _createForOfIteratorHelper(this.regions),
75670
- _step2;
75852
+ var _iterator4 = _createForOfIteratorHelper(this.regions),
75853
+ _step4;
75671
75854
  try {
75672
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
75673
- var layoutRegion = _step2.value;
75855
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
75856
+ var layoutRegion = _step4.value;
75674
75857
  layoutRegion.end();
75675
75858
  }
75676
75859
  } catch (err) {
75677
- _iterator2.e(err);
75860
+ _iterator4.e(err);
75678
75861
  } finally {
75679
- _iterator2.f();
75862
+ _iterator4.f();
75680
75863
  }
75681
75864
  }
75682
75865
  }, {
@@ -75689,7 +75872,11 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
75689
75872
  }
75690
75873
  }
75691
75874
  if (this.allEnded) {
75692
- console.debug('starting to end layout . . .');
75875
+ console.debug('starting to end layout . . .', {
75876
+ layoutId: this.layoutId,
75877
+ layoutIndex: this.index,
75878
+ layoutState: this.state
75879
+ });
75693
75880
  if (this.xlr.config.platform === exports.ConsumerPlatform.CMS) {
75694
75881
  var $end = document.getElementById('play_ended');
75695
75882
  var $preview = document.getElementById('screen_container');
@@ -75788,6 +75975,42 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
75788
75975
  (_$layout$parentElemen2 = $layout.parentElement) === null || _$layout$parentElemen2 === void 0 || _$layout$parentElemen2.removeChild($layout);
75789
75976
  }
75790
75977
  }
75978
+ }, {
75979
+ key: "discardLayout",
75980
+ value: function discardLayout() {
75981
+ var caller = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : exports.LayoutPlaybackType.NEXT;
75982
+ // Dispose any video.js players that were initialized during prepareVideoMedia
75983
+ // but never played. The isDisposed() guard makes this safe to call on
75984
+ // layouts that were fully played as well.
75985
+ var _iterator5 = _createForOfIteratorHelper(this.regions),
75986
+ _step5;
75987
+ try {
75988
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
75989
+ var region = _step5.value;
75990
+ var _iterator6 = _createForOfIteratorHelper(region.mediaObjects),
75991
+ _step6;
75992
+ try {
75993
+ for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
75994
+ var media = _step6.value;
75995
+ if (media.player && !media.player.isDisposed()) {
75996
+ media.player.dispose();
75997
+ media.player = undefined;
75998
+ media.html = null;
75999
+ }
76000
+ }
76001
+ } catch (err) {
76002
+ _iterator6.e(err);
76003
+ } finally {
76004
+ _iterator6.f();
76005
+ }
76006
+ }
76007
+ } catch (err) {
76008
+ _iterator5.e(err);
76009
+ } finally {
76010
+ _iterator5.f();
76011
+ }
76012
+ this.removeLayout(caller);
76013
+ }
75791
76014
  }, {
75792
76015
  key: "getXlf",
75793
76016
  value: function getXlf() {
@@ -76030,6 +76253,7 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76030
76253
  }());
76031
76254
  xlrObject.on('updateLoop', /*#__PURE__*/function () {
76032
76255
  var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3(inputLayouts) {
76256
+ var _xlrObject$currentLay;
76033
76257
  return _regeneratorRuntime().wrap(function _callee3$(_context3) {
76034
76258
  while (1) switch (_context3.prev = _context3.next) {
76035
76259
  case 0:
@@ -76038,7 +76262,17 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76038
76262
  return xlrObject.updateLoop(inputLayouts);
76039
76263
  case 3:
76040
76264
  xlrObject.isUpdatingLoop = false;
76041
- case 4:
76265
+ // If the running layout finished while isUpdatingLoop was true, the
76266
+ // layout end-handler bailed out of prepareLayouts() early and the
76267
+ // subsequent playLayouts() call saw currentLayout.done === true and
76268
+ // skipped run() — leaving a black screen. Catch up now that the flag
76269
+ // is clear.
76270
+ if ((_xlrObject$currentLay = xlrObject.currentLayout) !== null && _xlrObject$currentLay !== void 0 && _xlrObject$currentLay.done) {
76271
+ xlrObject.prepareLayouts().then(function (xlr) {
76272
+ return xlrObject.playLayouts(xlr);
76273
+ });
76274
+ }
76275
+ case 5:
76042
76276
  case "end":
76043
76277
  return _context3.stop();
76044
76278
  }
@@ -76068,40 +76302,35 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76068
76302
  return _ref4.apply(this, arguments);
76069
76303
  };
76070
76304
  }());
76071
- /**
76072
- * Asynchronous event emitter. Extended nanoevents event emitter.
76073
- *
76074
- * NOTE: Known limitation — nanoevents emit() is synchronous.
76075
- * Any async event handlers registered via .on() are fire-and-forget;
76076
- * emitSync does NOT await them. The returned Promise resolves
76077
- * immediately after handlers are invoked, not after they complete.
76078
- *
76079
- * @param eventName
76080
- * @param args
76081
- */
76082
- xlrObject.emitSync = function (eventName) {
76083
- for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
76084
- args[_key - 1] = arguments[_key];
76085
- }
76086
- return new Promise( /*#__PURE__*/function () {
76087
- var _ref5 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5(resolve) {
76088
- var _xlrObject$emitter;
76089
- return _regeneratorRuntime().wrap(function _callee5$(_context5) {
76090
- while (1) switch (_context5.prev = _context5.next) {
76091
- case 0:
76092
- (_xlrObject$emitter = xlrObject.emitter).emit.apply(_xlrObject$emitter, [eventName].concat(args));
76093
- resolve();
76094
- case 2:
76095
- case "end":
76096
- return _context5.stop();
76097
- }
76098
- }, _callee5);
76099
- }));
76100
- return function (_x4) {
76101
- return _ref5.apply(this, arguments);
76102
- };
76103
- }());
76104
- };
76305
+ xlrObject.emitSync = /*#__PURE__*/function () {
76306
+ var _ref5 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5(eventName) {
76307
+ var _xlrObject$emitter$ev;
76308
+ var _len,
76309
+ args,
76310
+ _key,
76311
+ handlers,
76312
+ _args5 = arguments;
76313
+ return _regeneratorRuntime().wrap(function _callee5$(_context5) {
76314
+ while (1) switch (_context5.prev = _context5.next) {
76315
+ case 0:
76316
+ for (_len = _args5.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
76317
+ args[_key - 1] = _args5[_key];
76318
+ }
76319
+ handlers = (_xlrObject$emitter$ev = xlrObject.emitter.events[eventName]) !== null && _xlrObject$emitter$ev !== void 0 ? _xlrObject$emitter$ev : [];
76320
+ _context5.next = 4;
76321
+ return Promise.all(handlers.map(function (handler) {
76322
+ return handler.apply(void 0, args);
76323
+ }));
76324
+ case 4:
76325
+ case "end":
76326
+ return _context5.stop();
76327
+ }
76328
+ }, _callee5);
76329
+ }));
76330
+ return function (_x4) {
76331
+ return _ref5.apply(this, arguments);
76332
+ };
76333
+ }();
76105
76334
  xlrObject.bootstrap = function () {
76106
76335
  // Place to set configurations and initialize required props
76107
76336
  var self = this;
@@ -76136,13 +76365,22 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76136
76365
  if ($splashScreen && $splashScreen.style.display === 'block') {
76137
76366
  $splashScreen === null || $splashScreen === void 0 || $splashScreen.hide();
76138
76367
  }
76368
+ console.debug('>>>> XLR.debug XLR::playLayouts > currentLayout', {
76369
+ layoutId: xlr.currentLayout.layoutId,
76370
+ layoutIndex: xlr.currentLayout.index,
76371
+ layoutState: xlr.currentLayout.state
76372
+ });
76139
76373
  if (!xlr.currentLayout.done) {
76140
- console.log('>>>> XLR.debug XLR::playSchedules > Running currentLayout', xlr.currentLayout);
76141
- xlr.currentLayout.run();
76142
76374
  // Hide overlays when current layout is interrupt
76143
76375
  if (xlr.currentLayout.isInterrupt()) {
76144
76376
  xlrObject.overlayLayoutManager.stopOverlays();
76145
76377
  }
76378
+ console.debug('>>>> XLR.debug XLR::playLayouts > Running currentLayout', {
76379
+ layoutId: xlr.currentLayout.layoutId,
76380
+ layoutIndex: xlr.currentLayout.index,
76381
+ layoutState: xlr.currentLayout.state
76382
+ });
76383
+ xlr.currentLayout.run();
76146
76384
  }
76147
76385
  } else {
76148
76386
  // Show splash screen
@@ -76219,7 +76457,7 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76219
76457
  _context7.next = 10;
76220
76458
  return _overlay.finishAllRegions();
76221
76459
  case 10:
76222
- _overlay.removeLayout();
76460
+ _overlay.removeLayout(exports.LayoutPlaybackType.OVERLAY);
76223
76461
  case 11:
76224
76462
  _context7.next = 14;
76225
76463
  break;
@@ -76285,6 +76523,31 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76285
76523
  var $layout = document.querySelector("#".concat(containerName, "[data-sequence=\"").concat(layoutIndex, "\"]"));
76286
76524
  return $layout !== null;
76287
76525
  };
76526
+ // Scans screen_container for non-overlay layout divs and removes any that
76527
+ // are not the current or next active layout. Prevents DOM accumulation when
76528
+ // prepareLayouts() races with updateLoop and multiple same-layoutId elements
76529
+ // end up in screen_container (e.g. transitioning from a 1-layout loop where
76530
+ // two elements exist for the same layout to a multi-layout schedule).
76531
+ // keepCurrent / keepNext:
76532
+ // undefined → fall back to this.currentLayout / this.nextLayout
76533
+ // null → keep nothing for that slot (explicit "no layout to preserve")
76534
+ // ILayout → keep exactly that instance
76535
+ xlrObject.cleanupOrphanedLayouts = function (keepCurrent, keepNext) {
76536
+ var $screen = document.getElementById('screen_container');
76537
+ if (!$screen) return;
76538
+ var current = keepCurrent !== undefined ? keepCurrent : this.currentLayout;
76539
+ var next = keepNext !== undefined ? keepNext : this.nextLayout;
76540
+ Array.from($screen.querySelectorAll(':scope > div:not(.is-overlay)')).forEach(function (el) {
76541
+ var div = el;
76542
+ var isCurrentLayout = current && div.id === current.containerName && div.dataset.sequence === String(current.index);
76543
+ var isNextLayout = next && div.id === next.containerName && div.dataset.sequence === String(next.index);
76544
+ if (!isCurrentLayout && !isNextLayout) {
76545
+ var _div$parentElement;
76546
+ console.debug('XLR::cleanupOrphanedLayouts - removing orphaned layout element', div.id);
76547
+ (_div$parentElement = div.parentElement) === null || _div$parentElement === void 0 || _div$parentElement.removeChild(div);
76548
+ }
76549
+ });
76550
+ };
76288
76551
  xlrObject.updateLoop = /*#__PURE__*/function () {
76289
76552
  var _ref10 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee11(inputLayouts) {
76290
76553
  var _this$currentLayout,
@@ -76331,11 +76594,11 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76331
76594
  };
76332
76595
  }();
76333
76596
  if (isCurrentLayoutValid) {
76334
- _context11.next = 54;
76597
+ _context11.next = 55;
76335
76598
  break;
76336
76599
  }
76337
76600
  if (!playback.hasDefaultOnly) {
76338
- _context11.next = 33;
76601
+ _context11.next = 34;
76339
76602
  break;
76340
76603
  }
76341
76604
  if (!(this.currentLayout && playback.currentLayout && this.currentLayout.layoutId !== playback.currentLayout.layoutId)) {
@@ -76348,82 +76611,102 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76348
76611
  case 19:
76349
76612
  this.currentLayout.removeLayout();
76350
76613
  case 20:
76351
- _context11.next = 22;
76614
+ // Discard old nextLayout before replacing it — same as the
76615
+ // other two branches do, otherwise the prepared DOM element
76616
+ // and any video.js players are orphaned.
76617
+ if (this.nextLayout && this.isLayoutInDOM(this.nextLayout.containerName, this.nextLayout.index)) {
76618
+ this.nextLayout.discardLayout(exports.LayoutPlaybackType.NEXT);
76619
+ }
76620
+ _context11.next = 23;
76352
76621
  return this.prepareLayoutXlf(playback.currentLayout);
76353
- case 22:
76622
+ case 23:
76354
76623
  this.currentLayout = _context11.sent;
76355
76624
  this.currentLayoutId = this.currentLayout.layoutId;
76356
76625
  _context11.t0 = this;
76357
- _context11.next = 27;
76626
+ _context11.next = 28;
76358
76627
  return this.prepareLayoutXlf(playback.nextLayout);
76359
- case 27:
76628
+ case 28:
76360
76629
  _context11.t1 = _context11.sent;
76361
- _context11.next = 30;
76630
+ _context11.next = 31;
76362
76631
  return _context11.t0.prepareForSsp.call(_context11.t0, _context11.t1);
76363
- case 30:
76632
+ case 31:
76364
76633
  this.nextLayout = _context11.sent;
76365
- _context11.next = 50;
76634
+ _context11.next = 51;
76366
76635
  break;
76367
- case 33:
76636
+ case 34:
76368
76637
  if (!(this.currentLayout && this.isLayoutInDOM(this.currentLayout.containerName, this.currentLayout.index))) {
76369
- _context11.next = 38;
76638
+ _context11.next = 39;
76370
76639
  break;
76371
76640
  }
76372
76641
  this.currentLayout.inLoop = false;
76373
- _context11.next = 37;
76642
+ _context11.next = 38;
76374
76643
  return this.currentLayout.finishAllRegions();
76375
- case 37:
76376
- this.currentLayout.removeLayout();
76377
76644
  case 38:
76645
+ this.currentLayout.removeLayout();
76646
+ case 39:
76378
76647
  if (this.nextLayout && this.isLayoutInDOM(this.nextLayout.containerName, this.nextLayout.index)) {
76379
- this.nextLayout.removeLayout();
76648
+ this.nextLayout.discardLayout(exports.LayoutPlaybackType.NEXT);
76380
76649
  }
76381
76650
  if (!playback.currentLayout) {
76382
- _context11.next = 42;
76651
+ _context11.next = 43;
76383
76652
  break;
76384
76653
  }
76385
- _context11.next = 42;
76654
+ _context11.next = 43;
76386
76655
  return prepareNewCurrentLayout();
76387
- case 42:
76656
+ case 43:
76388
76657
  if (!playback.nextLayout) {
76389
- _context11.next = 50;
76658
+ _context11.next = 51;
76390
76659
  break;
76391
76660
  }
76392
76661
  _context11.t2 = this;
76393
- _context11.next = 46;
76662
+ _context11.next = 47;
76394
76663
  return this.prepareLayoutXlf(playback.nextLayout);
76395
- case 46:
76664
+ case 47:
76396
76665
  _context11.t3 = _context11.sent;
76397
- _context11.next = 49;
76666
+ _context11.next = 50;
76398
76667
  return _context11.t2.prepareForSsp.call(_context11.t2, _context11.t3);
76399
- case 49:
76400
- this.nextLayout = _context11.sent;
76401
76668
  case 50:
76402
- _context11.next = 52;
76669
+ this.nextLayout = _context11.sent;
76670
+ case 51:
76671
+ _context11.next = 53;
76403
76672
  return this.playSchedules(this);
76404
- case 52:
76673
+ case 53:
76405
76674
  _context11.next = 67;
76406
76675
  break;
76407
- case 54:
76676
+ case 55:
76408
76677
  // Remove next layout if it is in the DOM
76409
76678
  if (this.nextLayout && this.isLayoutInDOM(this.nextLayout.containerName, this.nextLayout.index)) {
76410
- this.nextLayout.removeLayout();
76679
+ this.nextLayout.discardLayout(exports.LayoutPlaybackType.NEXT);
76411
76680
  }
76412
- // Prepare new current layout
76681
+ // Purge any other orphaned layouts from screen_container that belong
76682
+ // to the old single-layout loop. When there was only one layout in the
76683
+ // loop, prepareLayouts() kept two DOM elements alive (current + next,
76684
+ // both the same layoutId but different containerNames). On a schedule
76685
+ // change the this.nextLayout check above only discards the element
76686
+ // currently referenced by this.nextLayout, but concurrent
76687
+ // prepareLayouts() calls can leave earlier same-layoutId elements
76688
+ // behind.
76689
+ // Pass null (not undefined) for keepNext: undefined would fall back to
76690
+ // this.nextLayout which may still reference the just-discarded layout
76691
+ // or — if isLayoutInDOM returned false and discardLayout was skipped —
76692
+ // the orphan itself, causing cleanupOrphanedLayouts to preserve it.
76693
+ // null means "no next to keep"; we are about to prepare a fresh one.
76694
+ this.cleanupOrphanedLayouts(this.currentLayout, null);
76695
+ // The current layout is still valid and running — do NOT replace the
76696
+ // live currentLayout object. Only refresh the queued nextLayout so
76697
+ // that when the running layout finishes it transitions to the correct
76698
+ // position in the updated loop. Using playback.currentLayout (the
76699
+ // slot that follows the running layout in the new queue) as the new
76700
+ // nextLayout keeps the cycle in order; the slot after that will be
76701
+ // prepared by the normal prepareLayouts() call at transition time.
76413
76702
  if (!playback.currentLayout) {
76414
- _context11.next = 58;
76415
- break;
76416
- }
76417
- _context11.next = 58;
76418
- return prepareNewCurrentLayout();
76419
- case 58:
76420
- if (!playback.nextLayout) {
76421
76703
  _context11.next = 66;
76422
76704
  break;
76423
76705
  }
76706
+ this.currentLayoutIndex = playback.currentLayoutIndex;
76424
76707
  _context11.t4 = this;
76425
76708
  _context11.next = 62;
76426
- return this.prepareLayoutXlf(playback.nextLayout);
76709
+ return this.prepareLayoutXlf(playback.currentLayout);
76427
76710
  case 62:
76428
76711
  _context11.t5 = _context11.sent;
76429
76712
  _context11.next = 65;
@@ -76490,8 +76773,10 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76490
76773
  var tempNextLayoutIndex = getLayoutIndexByLayoutId(this.inputLayouts, this.nextLayout.layoutId);
76491
76774
  _currentLayoutIndex = tempNextLayoutIndex !== null && tempNextLayoutIndex !== void 0 ? tempNextLayoutIndex : 0;
76492
76775
  _currentLayout = this.getLayout(this.inputLayouts[tempNextLayoutIndex !== null && tempNextLayoutIndex !== void 0 ? tempNextLayoutIndex : 0]);
76776
+ _currentLayout = setLayoutIndex(_currentLayout, _currentLayoutIndex);
76493
76777
  } else {
76494
76778
  _currentLayout = this.getLayout(this.inputLayouts[0]);
76779
+ _currentLayout = setLayoutIndex(_currentLayout, 0);
76495
76780
  }
76496
76781
  if (this.inputLayouts.length > 1) {
76497
76782
  if (_currentLayoutIndex + 1 > this.inputLayouts.length - 1) {
@@ -76500,6 +76785,7 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76500
76785
  _nextLayoutIndex = _currentLayoutIndex + 1;
76501
76786
  }
76502
76787
  _nextLayout = this.getLayout(this.inputLayouts[_nextLayoutIndex]);
76788
+ _nextLayout = setLayoutIndex(_nextLayout, _nextLayoutIndex);
76503
76789
  } else {
76504
76790
  _nextLayout = _currentLayout;
76505
76791
  }
@@ -76512,20 +76798,38 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76512
76798
  if (_currentLayout) {
76513
76799
  _currentLayoutIndex = _currentLayout.index;
76514
76800
  }
76801
+ _currentLayout = setLayoutIndex(_currentLayout, _currentLayoutIndex);
76515
76802
  _nextLayoutIndex = 0;
76516
76803
  _nextLayout = this.getLayout(this.inputLayouts[_nextLayoutIndex]);
76804
+ _nextLayout = setLayoutIndex(_nextLayout, _nextLayoutIndex);
76517
76805
  }
76518
76806
  } else {
76519
76807
  _currentLayoutIndex = this.nextLayout.index > this.inputLayouts.length - 1 ? 0 : this.nextLayout.index;
76520
76808
  _currentLayout = this.getLayout(this.inputLayouts[_currentLayoutIndex]);
76809
+ _currentLayout = setLayoutIndex(_currentLayout, _currentLayoutIndex);
76521
76810
  _nextLayoutIndex = _currentLayoutIndex + 1 > this.inputLayouts.length - 1 ? 0 : _currentLayoutIndex + 1;
76522
76811
  _nextLayout = this.getLayout(this.inputLayouts[_nextLayoutIndex]);
76812
+ _nextLayout = setLayoutIndex(_nextLayout, _nextLayoutIndex);
76523
76813
  }
76524
76814
  } else {
76815
+ var _this$currentLayout4, _this$currentLayout5;
76525
76816
  _currentLayout = this.nextLayout;
76526
76817
  _currentLayoutIndex = _currentLayout.index;
76818
+ // updateLoop can re-queue the same index that is currently
76819
+ // playing (e.g. it fires while nextLayout.index === currentLayout.index).
76820
+ // When that layout then ends, the catch-up prepareLayouts() would
76821
+ // replay the same slot instead of advancing. Detect this by checking
76822
+ // whether the queued next-to-current is at the same index as the
76823
+ // layout that just finished, and advance past it so the following
76824
+ // slot (e.g. an SSP that now has an ad) becomes current instead.
76825
+ if (this.inputLayouts.length > 1 && (_this$currentLayout4 = this.currentLayout) !== null && _this$currentLayout4 !== void 0 && _this$currentLayout4.done && _currentLayoutIndex === ((_this$currentLayout5 = this.currentLayout) === null || _this$currentLayout5 === void 0 ? void 0 : _this$currentLayout5.index)) {
76826
+ _currentLayoutIndex = (_currentLayoutIndex + 1) % this.inputLayouts.length;
76827
+ _currentLayout = this.getLayout(this.inputLayouts[_currentLayoutIndex]);
76828
+ _currentLayout = setLayoutIndex(_currentLayout, _currentLayoutIndex);
76829
+ }
76527
76830
  _nextLayoutIndex = (_currentLayoutIndex + 1) % this.inputLayouts.length;
76528
76831
  _nextLayout = this.getLayout(this.inputLayouts[_nextLayoutIndex]);
76832
+ _nextLayout = setLayoutIndex(_nextLayout, _nextLayoutIndex);
76529
76833
  }
76530
76834
  }
76531
76835
  }
@@ -76533,17 +76837,22 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76533
76837
  // Initial run: set both currentLayout and nextLayout
76534
76838
  if (hasLayout) {
76535
76839
  _currentLayout = this.getLayout(this.inputLayouts[_currentLayoutIndex]);
76840
+ _currentLayout = setLayoutIndex(_currentLayout, _currentLayoutIndex);
76536
76841
  if (this.inputLayouts.length > 1) {
76537
76842
  _nextLayout = this.getLayout(this.inputLayouts[_nextLayoutIndex]);
76843
+ _nextLayout = setLayoutIndex(_nextLayout, _nextLayoutIndex);
76538
76844
  } else {
76539
76845
  _nextLayout = this.getLayout(this.inputLayouts[0]);
76846
+ _nextLayout = setLayoutIndex(_nextLayout, 0);
76540
76847
  }
76541
76848
  }
76542
76849
  }
76543
76850
  if (_currentLayout === undefined && _nextLayout === undefined) {
76544
76851
  if (_hasDefaultOnly) {
76545
76852
  _currentLayout = this.getLayout(this.inputLayouts[0]);
76853
+ _currentLayout = setLayoutIndex(_currentLayout, 0);
76546
76854
  _nextLayout = this.getLayout(this.inputLayouts[0]);
76855
+ _nextLayout = setLayoutIndex(_nextLayout, 0);
76547
76856
  }
76548
76857
  }
76549
76858
  if (_currentLayout !== undefined && _nextLayout !== undefined) {
@@ -76573,10 +76882,19 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76573
76882
  var activeLayout = inputLayout;
76574
76883
  if (isCMS) {
76575
76884
  activeLayout.index = 0;
76885
+ // id stays null without this — setLayoutIndex returns undefined for CMS layouts
76886
+ if (activeLayout.id == null) {
76887
+ activeLayout.id = activeLayout.layoutId;
76888
+ }
76576
76889
  } else {
76577
76890
  activeLayout = _objectSpread2({}, this.uniqueLayouts[inputLayout.layoutId]);
76578
76891
  }
76579
76892
  _layout = _objectSpread2(_objectSpread2({}, _layout), activeLayout);
76893
+ console.debug('XLR::getLayout > activeLayout from uniqueLayouts', {
76894
+ activeLayout: activeLayout,
76895
+ inputLayout: inputLayout,
76896
+ uniqueLayouts: this.uniqueLayouts
76897
+ });
76580
76898
  // Must set index/sequence from schedule loop
76581
76899
  _layout.index = activeLayout.index;
76582
76900
  }
@@ -76598,7 +76916,7 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76598
76916
  };
76599
76917
  xlrObject.prepareLayouts = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee14() {
76600
76918
  var _layoutPlayback$curre, _layoutPlayback$curre2;
76601
- var self, layoutPlayback, currentLayoutXlf, nextLayoutXlf, layouts;
76919
+ var self, layoutPlayback, currentLayoutXlf, wasCurrentReused, nextLayoutXlf, layouts;
76602
76920
  return _regeneratorRuntime().wrap(function _callee14$(_context14) {
76603
76921
  while (1) switch (_context14.prev = _context14.next) {
76604
76922
  case 0:
@@ -76621,7 +76939,12 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76621
76939
  shouldParse: false
76622
76940
  });
76623
76941
  self.currentLayoutId = (_layoutPlayback$curre = layoutPlayback.currentLayout) === null || _layoutPlayback$curre === void 0 ? void 0 : _layoutPlayback$curre.layoutId;
76624
- if (!((_layoutPlayback$curre2 = layoutPlayback.currentLayout) !== null && _layoutPlayback$curre2 !== void 0 && _layoutPlayback$curre2.layoutNode)) {
76942
+ // Only reuse the existing Layout instance if it is fully healthy
76943
+ // a done=true instance was removed from the DOM (e.g. an SSP slot that
76944
+ // had no ad), and an empty-XLF instance has no regions so it can never
76945
+ // advance the cycle. In either case re-prepare from scratch so we get
76946
+ // a fresh request (which may now have a valid ad / XLF).
76947
+ if (!((_layoutPlayback$curre2 = layoutPlayback.currentLayout) !== null && _layoutPlayback$curre2 !== void 0 && _layoutPlayback$curre2.layoutNode && !layoutPlayback.currentLayout.done && layoutPlayback.currentLayout.xlfString !== '')) {
76625
76948
  _context14.next = 12;
76626
76949
  break;
76627
76950
  }
@@ -76635,27 +76958,40 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76635
76958
  _context14.t0 = _context14.sent;
76636
76959
  case 15:
76637
76960
  currentLayoutXlf = _context14.t0;
76638
- _context14.next = 18;
76961
+ // True when the same object was returned (reused); false when a fresh
76962
+ // Layout was constructed by prepareLayoutXlf above.
76963
+ wasCurrentReused = currentLayoutXlf === layoutPlayback.currentLayout;
76964
+ _context14.next = 19;
76639
76965
  return self.prepareLayoutXlf(layoutPlayback.nextLayout);
76640
- case 18:
76966
+ case 19:
76641
76967
  nextLayoutXlf = _context14.sent;
76642
76968
  _context14.t1 = Promise;
76643
76969
  _context14.t2 = currentLayoutXlf;
76644
- _context14.next = 23;
76970
+ _context14.next = 24;
76645
76971
  return self.prepareForSsp(nextLayoutXlf);
76646
- case 23:
76972
+ case 24:
76647
76973
  _context14.t3 = _context14.sent;
76648
76974
  _context14.t4 = [_context14.t2, _context14.t3];
76649
- _context14.next = 27;
76975
+ _context14.next = 28;
76650
76976
  return _context14.t1.all.call(_context14.t1, _context14.t4);
76651
- case 27:
76977
+ case 28:
76652
76978
  layouts = _context14.sent;
76653
- // Return early when layout loop is updating
76654
- if (self.isUpdatingLoop) {
76655
- if (layoutPlayback.nextLayout && nextLayoutXlf && this.isLayoutInDOM(nextLayoutXlf.containerName, nextLayoutXlf.index)) {
76656
- nextLayoutXlf.removeLayout();
76657
- }
76979
+ if (!(self.isUpdatingLoop || layouts[0].done)) {
76980
+ _context14.next = 33;
76981
+ break;
76982
+ }
76983
+ // If currentLayout was freshly prepared (not reused from nextLayout),
76984
+ // its DOM element was just appended — discard it now so it does not
76985
+ // accumulate in screen_container. Also disposes any video.js players
76986
+ // that were initialized during prepareVideoMedia but never played.
76987
+ if (!wasCurrentReused && this.isLayoutInDOM(currentLayoutXlf.containerName, currentLayoutXlf.index)) {
76988
+ currentLayoutXlf.discardLayout(exports.LayoutPlaybackType.NEXT);
76989
+ }
76990
+ if (layoutPlayback.nextLayout && nextLayoutXlf && this.isLayoutInDOM(nextLayoutXlf.containerName, nextLayoutXlf.index)) {
76991
+ nextLayoutXlf.discardLayout(exports.LayoutPlaybackType.NEXT);
76658
76992
  }
76993
+ return _context14.abrupt("return", Promise.resolve(self));
76994
+ case 33:
76659
76995
  console.debug('>>>>> XLR.debug prepared layout XLF', layouts);
76660
76996
  return _context14.abrupt("return", new Promise( /*#__PURE__*/function () {
76661
76997
  var _ref14 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee13(resolve) {
@@ -76672,8 +77008,15 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76672
77008
  self.currentLayout = self.layouts.current;
76673
77009
  self.currentLayoutId = self.currentLayout.layoutId;
76674
77010
  self.nextLayout = self.layouts.next;
77011
+ // Evict any orphaned layout DOM elements that aren't the current
77012
+ // or next layout. Concurrent prepareLayouts() calls can each append
77013
+ // a freshly-prepared nextLayout to screen_container and then
77014
+ // overwrite this.nextLayout, leaving earlier elements behind.
77015
+ // Calling this here — with explicit references — ensures every
77016
+ // completed prepare cycle leaves the DOM in a clean state.
77017
+ self.cleanupOrphanedLayouts(self.currentLayout, self.nextLayout);
76675
77018
  resolve(xlrObject);
76676
- case 8:
77019
+ case 9:
76677
77020
  case "end":
76678
77021
  return _context13.stop();
76679
77022
  }
@@ -76683,7 +77026,7 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76683
77026
  return _ref14.apply(this, arguments);
76684
77027
  };
76685
77028
  }()));
76686
- case 31:
77029
+ case 35:
76687
77030
  case "end":
76688
77031
  return _context14.stop();
76689
77032
  }
@@ -76711,34 +77054,38 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76711
77054
  newOptions.xlfUrl = inputLayout.path;
76712
77055
  }
76713
77056
  if (!(inputLayout && inputLayout.layoutNode === undefined)) {
76714
- _context15.next = 21;
77057
+ _context15.next = 22;
76715
77058
  break;
76716
77059
  }
76717
77060
  if (!(inputLayout.layoutId === -1)) {
76718
- _context15.next = 14;
77061
+ _context15.next = 15;
76719
77062
  break;
76720
77063
  }
76721
77064
  _context15.next = 10;
76722
77065
  return self.emitSync('adRequest', inputLayout.index);
76723
77066
  case 10:
76724
77067
  sspInputLayout = self.inputLayouts[inputLayout.index];
77068
+ console.debug('XLR::prepareLayoutXlf > SSP input layout', {
77069
+ sspInputLayout: sspInputLayout,
77070
+ inputLayout: inputLayout
77071
+ });
76725
77072
  // @ts-ignore
76726
- layoutXlf = ((_sspInputLayout = sspInputLayout) === null || _sspInputLayout === void 0 ? void 0 : _sspInputLayout.getXlf()) || '';
76727
- _context15.next = 17;
77073
+ layoutXlf = typeof ((_sspInputLayout = sspInputLayout) === null || _sspInputLayout === void 0 ? void 0 : _sspInputLayout.getXlf) === 'function' ? sspInputLayout.getXlf() : '';
77074
+ _context15.next = 18;
76728
77075
  break;
76729
- case 14:
76730
- _context15.next = 16;
77076
+ case 15:
77077
+ _context15.next = 17;
76731
77078
  return getXlf(newOptions);
76732
- case 16:
76733
- layoutXlf = _context15.sent;
76734
77079
  case 17:
77080
+ layoutXlf = _context15.sent;
77081
+ case 18:
76735
77082
  parser = new window.DOMParser();
76736
77083
  layoutXlfNode = parser.parseFromString(layoutXlf, 'text/xml');
76737
- _context15.next = 22;
77084
+ _context15.next = 23;
76738
77085
  break;
76739
- case 21:
76740
- layoutXlfNode = inputLayout && inputLayout.layoutNode;
76741
77086
  case 22:
77087
+ layoutXlfNode = inputLayout && inputLayout.layoutNode;
77088
+ case 23:
76742
77089
  isOverlayLayout = !!(inputLayout !== null && inputLayout !== void 0 && inputLayout.isOverlay);
76743
77090
  return _context15.abrupt("return", new Promise(function (resolve) {
76744
77091
  var _inputLayout$ad;
@@ -76763,13 +77110,22 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76763
77110
  xlrLayoutObj.duration = sspInputLayout.duration || 0;
76764
77111
  xlrLayoutObj.ad = sspInputLayout.ad;
76765
77112
  }
77113
+ var xlrLayout;
76766
77114
  if (isOverlayLayout) {
76767
- resolve(new OverlayLayout(xlrLayoutObj, newOptions, self, layoutXlfNode));
77115
+ xlrLayout = new OverlayLayout(xlrLayoutObj, newOptions, self, layoutXlfNode);
76768
77116
  } else {
76769
- resolve(new Layout(xlrLayoutObj, newOptions, self, layoutXlfNode));
77117
+ xlrLayout = new Layout(xlrLayoutObj, newOptions, self, layoutXlfNode);
77118
+ }
77119
+ // Advance the shared counter so the next prepareLayoutXlf() call
77120
+ // starts from where this layout left off — prevents every layout
77121
+ // instance from reusing idCounter=1 and colliding on the same
77122
+ // containerName / DOM element.
77123
+ if (props.options) {
77124
+ props.options.idCounter = newOptions.idCounter;
76770
77125
  }
77126
+ resolve(xlrLayout);
76771
77127
  }));
76772
- case 24:
77128
+ case 25:
76773
77129
  case "end":
76774
77130
  return _context15.stop();
76775
77131
  }
@@ -76781,45 +77137,49 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76781
77137
  }();
76782
77138
  xlrObject.prepareForSsp = /*#__PURE__*/function () {
76783
77139
  var _ref16 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee16(nextLayout) {
76784
- var self, _nextLayout, nextIndex, inputLayout, nextLayoutObj;
77140
+ var self, _nextLayout, iterations, maxIterations, nextIndex, inputLayout, nextLayoutObj;
76785
77141
  return _regeneratorRuntime().wrap(function _callee16$(_context16) {
76786
77142
  while (1) switch (_context16.prev = _context16.next) {
76787
77143
  case 0:
76788
77144
  self = this;
76789
77145
  _nextLayout = nextLayout;
76790
- case 2:
76791
- if (!(_nextLayout && _nextLayout.xlfString === '')) {
76792
- _context16.next = 16;
76793
- break;
76794
- }
76795
- // Remove skipped layout
76796
- _nextLayout.removeLayout();
76797
- // Get next valid layout
76798
- // We will skip next layout that has no valid xlf
76799
- nextIndex = _nextLayout.index + 1;
76800
- if (!(nextIndex >= self.inputLayouts.length)) {
76801
- _context16.next = 7;
77146
+ iterations = 0;
77147
+ maxIterations = self.inputLayouts.length;
77148
+ case 4:
77149
+ if (!(_nextLayout && _nextLayout.xlfString === '' && iterations < maxIterations)) {
77150
+ _context16.next = 20;
76802
77151
  break;
76803
77152
  }
76804
- return _context16.abrupt("break", 16);
76805
- case 7:
77153
+ // Remove the empty slot's DOM element before skipping past it
77154
+ _nextLayout.removeLayout(exports.LayoutPlaybackType.NEXT);
77155
+ iterations++;
77156
+ // Advance to the next slot, wrapping around so a trailing SSP slot
77157
+ // with no ad does not strand the queue at the end of the array.
77158
+ nextIndex = (_nextLayout.index + 1) % self.inputLayouts.length;
76806
77159
  inputLayout = self.inputLayouts[nextIndex];
76807
77160
  if (inputLayout) {
76808
- _context16.next = 10;
77161
+ _context16.next = 11;
76809
77162
  break;
76810
77163
  }
76811
- return _context16.abrupt("break", 16);
76812
- case 10:
77164
+ return _context16.abrupt("break", 20);
77165
+ case 11:
76813
77166
  nextLayoutObj = self.getLayout(inputLayout);
76814
- _context16.next = 13;
77167
+ nextLayoutObj = setLayoutIndex(nextLayoutObj, nextIndex);
77168
+ if (nextLayoutObj) {
77169
+ _context16.next = 15;
77170
+ break;
77171
+ }
77172
+ return _context16.abrupt("break", 20);
77173
+ case 15:
77174
+ _context16.next = 17;
76815
77175
  return self.prepareLayoutXlf(nextLayoutObj);
76816
- case 13:
77176
+ case 17:
76817
77177
  _nextLayout = _context16.sent;
76818
- _context16.next = 2;
77178
+ _context16.next = 4;
76819
77179
  break;
76820
- case 16:
77180
+ case 20:
76821
77181
  return _context16.abrupt("return", _nextLayout);
76822
- case 17:
77182
+ case 21:
76823
77183
  case "end":
76824
77184
  return _context16.stop();
76825
77185
  }
@@ -76831,7 +77191,7 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76831
77191
  }();
76832
77192
  xlrObject.gotoPrevLayout = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee18() {
76833
77193
  var _this4 = this;
76834
- var _currentLayoutIndex, _assumedPrevIndex, _this$currentLayout4;
77194
+ var _currentLayoutIndex, _assumedPrevIndex, _this$currentLayout6;
76835
77195
  return _regeneratorRuntime().wrap(function _callee18$(_context18) {
76836
77196
  while (1) switch (_context18.prev = _context18.next) {
76837
77197
  case 0:
@@ -76854,7 +77214,7 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76854
77214
  break;
76855
77215
  }
76856
77216
  _context18.next = 8;
76857
- return (_this$currentLayout4 = this.currentLayout) === null || _this$currentLayout4 === void 0 ? void 0 : _this$currentLayout4.finishAllRegions();
77217
+ return (_this$currentLayout6 = this.currentLayout) === null || _this$currentLayout6 === void 0 ? void 0 : _this$currentLayout6.finishAllRegions();
76858
77218
  case 8:
76859
77219
  // and set the previous layout as current layout
76860
77220
  this.currentLayoutIndex = _assumedPrevIndex;
@@ -76882,7 +77242,7 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76882
77242
  }, _callee18, this);
76883
77243
  }));
76884
77244
  xlrObject.gotoNextLayout = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee19() {
76885
- var _xlrObject$currentLay;
77245
+ var _xlrObject$currentLay2;
76886
77246
  return _regeneratorRuntime().wrap(function _callee19$(_context19) {
76887
77247
  while (1) switch (_context19.prev = _context19.next) {
76888
77248
  case 0:
@@ -76892,7 +77252,7 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76892
77252
  shouldParse: false
76893
77253
  });
76894
77254
  _context19.next = 3;
76895
- return (_xlrObject$currentLay = xlrObject.currentLayout) === null || _xlrObject$currentLay === void 0 ? void 0 : _xlrObject$currentLay.finishAllRegions();
77255
+ return (_xlrObject$currentLay2 = xlrObject.currentLayout) === null || _xlrObject$currentLay2 === void 0 ? void 0 : _xlrObject$currentLay2.finishAllRegions();
76896
77256
  case 3:
76897
77257
  case "end":
76898
77258
  return _context19.stop();
@@ -76904,6 +77264,11 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76904
77264
  if (layout !== null) {
76905
77265
  layout.index = xlrInputLayout.index;
76906
77266
  }
77267
+ console.debug('XLR::updateInputLayout', {
77268
+ layoutIndex: layoutIndex,
77269
+ layout: layout,
77270
+ xlrInputLayout: xlrInputLayout
77271
+ });
76907
77272
  this.inputLayouts[layoutIndex] = layout || xlrInputLayout;
76908
77273
  };
76909
77274
  xlrObject.bootstrap();
@@ -76947,11 +77312,11 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76947
77312
  exports.hasSspLayout = hasSspLayout;
76948
77313
  exports.initRenderingDOM = initRenderingDOM;
76949
77314
  exports.initialLayout = initialLayout;
76950
- exports.initialMedia = initialMedia;
76951
77315
  exports.initialRegion = initialRegion;
76952
77316
  exports.initialXlr = initialXlr;
76953
77317
  exports.isEmpty = isEmpty;
76954
77318
  exports.isLayoutValid = isLayoutValid;
77319
+ exports.isMediaActive = isMediaActive;
76955
77320
  exports.nextId = nextId;
76956
77321
  exports.playerReportFault = playerReportFault;
76957
77322
  exports.preloadMediaBlob = preloadMediaBlob;
@@ -76959,6 +77324,7 @@ ${segmentInfoString(segmentInfo)}`); // If there's an init segment associated wi
76959
77324
  exports.prepareHtmlMedia = prepareHtmlMedia;
76960
77325
  exports.prepareImageMedia = prepareImageMedia;
76961
77326
  exports.prepareVideoMedia = prepareVideoMedia;
77327
+ exports.reportToPlayerPlatform = reportToPlayerPlatform;
76962
77328
  exports.setExpiry = setExpiry;
76963
77329
  exports.transitionElement = transitionElement;
76964
77330
  exports.videoFileType = videoFileType;