stormcloud-video-player 0.3.55 → 0.3.57

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.
@@ -654,7 +654,7 @@ function createImaController(video, options) {
654
654
  adVideo.style.height = "100%";
655
655
  adVideo.style.objectFit = "contain";
656
656
  adVideo.style.backgroundColor = "transparent";
657
- adVideo.style.zIndex = "15";
657
+ adVideo.style.zIndex = "2";
658
658
  adVideo.playsInline = true;
659
659
  adVideo.volume = originalVolume;
660
660
  adVideo.muted = originalMutedState;
@@ -947,7 +947,7 @@ function createImaController(video, options) {
947
947
  container.style.alignItems = "center";
948
948
  container.style.justifyContent = "center";
949
949
  container.style.pointerEvents = "none";
950
- container.style.zIndex = "10";
950
+ container.style.zIndex = "30";
951
951
  container.style.backgroundColor = "#000";
952
952
  container.style.transition = "opacity 0.3s ease-in-out";
953
953
  container.style.opacity = "0";
@@ -1062,7 +1062,7 @@ function createImaController(video, options) {
1062
1062
  container.style.alignItems = "center";
1063
1063
  container.style.justifyContent = "center";
1064
1064
  container.style.pointerEvents = "none";
1065
- container.style.zIndex = "10";
1065
+ container.style.zIndex = "30";
1066
1066
  container.style.backgroundColor = "transparent";
1067
1067
  container.style.transition = "opacity 0.3s ease-in-out, background-color 0.3s ease-in-out";
1068
1068
  container.style.opacity = "0";
@@ -1977,7 +1977,7 @@ function createHlsAdPlayer(contentVideo, options) {
1977
1977
  container.style.alignItems = "center";
1978
1978
  container.style.justifyContent = "center";
1979
1979
  container.style.pointerEvents = "none";
1980
- container.style.zIndex = "10";
1980
+ container.style.zIndex = "30";
1981
1981
  container.style.backgroundColor = "#000";
1982
1982
  (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
1983
1983
  adContainerEl = container;
@@ -3201,6 +3201,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3201
3201
  this.inAdBreak = false;
3202
3202
  this.ptsDriftEmaMs = 0;
3203
3203
  this.adPodQueue = [];
3204
+ this.vmapBreaks = [];
3205
+ this.consumedVmapBreakIds = /* @__PURE__ */ new Set();
3204
3206
  this.lastHeartbeatTime = 0;
3205
3207
  this.currentAdIndex = 0;
3206
3208
  this.totalAdsInBreak = 0;
@@ -3755,13 +3757,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3755
3757
  _this.activeAdRequestToken = null;
3756
3758
  _this.showAds = true;
3757
3759
  _this.resetGamNoFillCounter();
3758
- if (_this.inAdBreak && _this.expectedAdBreakDurationMs != null) {
3759
- if (_this.adStopTimerId == null) {
3760
- _this.currentAdBreakStartWallClockMs = Date.now();
3761
- _this.scheduleAdStopCountdown(_this.expectedAdBreakDurationMs);
3762
- if (_this.config.debugAdTiming) {
3763
- console.log("[StormcloudVideoPlayer] Starting ad break timer on content_pause (first ad starting)");
3764
- }
3760
+ if (_this.inAdBreak && _this.expectedAdBreakDurationMs != null && _this.adStopTimerId == null) {
3761
+ _this.scheduleAdStopCountdown(_this.getRemainingAdMs());
3762
+ if (_this.config.debugAdTiming) {
3763
+ console.log("[StormcloudVideoPlayer] Starting ad break timer on content_pause (first ad starting)");
3765
3764
  }
3766
3765
  }
3767
3766
  var currentMuted = _this.video.muted;
@@ -3824,6 +3823,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3824
3823
  this.ima.showPlaceholder();
3825
3824
  this.isShowingPlaceholder = true;
3826
3825
  }
3826
+ var preservedMutedState = this.ima.getOriginalMutedState();
3827
+ var preservedVolumeState = this.ima.getOriginalVolume();
3827
3828
  if (this.ima) {
3828
3829
  try {
3829
3830
  this.ima.destroy();
@@ -3838,7 +3839,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3838
3839
  var continueLiveStreamDuringAds = this.shouldContinueLiveStreamDuringAds();
3839
3840
  this.ima = this.createAdPlayer(continueLiveStreamDuringAds);
3840
3841
  this.ima.initialize();
3841
- this.ima.updateOriginalMutedState(this.video.muted, this.video.volume);
3842
+ this.ima.updateOriginalMutedState(preservedMutedState, preservedVolumeState);
3842
3843
  this.attachImaEventListeners();
3843
3844
  if (shouldShowPlaceholder) {
3844
3845
  this.showPlaceholderLayer();
@@ -4154,12 +4155,17 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4154
4155
  }
4155
4156
  }
4156
4157
  if (this.inAdBreak) {
4157
- if (this.expectedAdBreakDurationMs == null && marker.durationSeconds != null) {
4158
- this.expectedAdBreakDurationMs = marker.durationSeconds * 1e3;
4159
- if (this.config.debugAdTiming) {
4160
- console.log("[StormcloudVideoPlayer] Updated ad break duration from subsequent marker: ".concat(this.expectedAdBreakDurationMs, "ms"));
4158
+ if (marker.durationSeconds != null) {
4159
+ var newDurationMs = marker.durationSeconds * 1e3;
4160
+ if (this.expectedAdBreakDurationMs == null || newDurationMs > this.expectedAdBreakDurationMs) {
4161
+ this.expectedAdBreakDurationMs = newDurationMs;
4162
+ var elapsedMs = this.currentAdBreakStartWallClockMs != null ? Date.now() - this.currentAdBreakStartWallClockMs : 0;
4163
+ var remainingMs = Math.max(0, newDurationMs - elapsedMs);
4164
+ this.scheduleAdStopCountdown(remainingMs);
4165
+ if (this.config.debugAdTiming) {
4166
+ console.log("[StormcloudVideoPlayer] Updated ad break duration from subsequent marker: ".concat(newDurationMs, "ms, remaining: ").concat(remainingMs, "ms"));
4167
+ }
4161
4168
  }
4162
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
4163
4169
  }
4164
4170
  return;
4165
4171
  }
@@ -4235,9 +4241,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4235
4241
  this.expectedAdBreakDurationMs = marker.durationSeconds * 1e3;
4236
4242
  }
4237
4243
  if (this.expectedAdBreakDurationMs != null && this.currentAdBreakStartWallClockMs != null) {
4238
- var elapsedMs = Date.now() - this.currentAdBreakStartWallClockMs;
4239
- var remainingMs = Math.max(0, this.expectedAdBreakDurationMs - elapsedMs);
4240
- this.scheduleAdStopCountdown(remainingMs);
4244
+ var elapsedMs1 = Date.now() - this.currentAdBreakStartWallClockMs;
4245
+ var remainingMs1 = Math.max(0, this.expectedAdBreakDurationMs - elapsedMs1);
4246
+ this.scheduleAdStopCountdown(remainingMs1);
4241
4247
  }
4242
4248
  if (!this.ima.isAdPlaying() && this.activeAdRequestToken === null && this.adRequestQueue.length > 0) {
4243
4249
  this.tryNextAvailableAdWithRateLimit();
@@ -4529,6 +4535,18 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4529
4535
  return _ts_generator(this, function(_state) {
4530
4536
  switch(_state.label){
4531
4537
  case 0:
4538
+ if (!this.config.vmapUrl) return [
4539
+ 3,
4540
+ 2
4541
+ ];
4542
+ return [
4543
+ 4,
4544
+ this.fetchAndParseVmap(this.config.vmapUrl)
4545
+ ];
4546
+ case 1:
4547
+ _state.sent();
4548
+ _state.label = 2;
4549
+ case 2:
4532
4550
  vastMode = this.config.vastMode || "default";
4533
4551
  if (this.config.debugAdTiming) {
4534
4552
  console.log("[StormcloudVideoPlayer] VAST mode:", vastMode);
@@ -4574,7 +4592,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4574
4592
  headers: headers
4575
4593
  })
4576
4594
  ];
4577
- case 1:
4595
+ case 3:
4578
4596
  response = _state.sent();
4579
4597
  if (!response.ok) {
4580
4598
  if (this.config.debugAdTiming) {
@@ -4588,7 +4606,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4588
4606
  4,
4589
4607
  response.json()
4590
4608
  ];
4591
- case 2:
4609
+ case 4:
4592
4610
  data = _state.sent();
4593
4611
  imaPayload = (_data_response = data.response) === null || _data_response === void 0 ? void 0 : (_data_response_ima = _data_response.ima) === null || _data_response_ima === void 0 ? void 0 : (_data_response_ima_publisherdeskima = _data_response_ima["publisherdesk.ima"]) === null || _data_response_ima_publisherdeskima === void 0 ? void 0 : _data_response_ima_publisherdeskima.payload;
4594
4612
  if (imaPayload) {
@@ -4616,6 +4634,171 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4616
4634
  }).call(this);
4617
4635
  }
4618
4636
  },
4637
+ {
4638
+ key: "fetchAndParseVmap",
4639
+ value: function fetchAndParseVmap(vmapUrl) {
4640
+ return _async_to_generator(function() {
4641
+ var response, vmapXml, error;
4642
+ return _ts_generator(this, function(_state) {
4643
+ switch(_state.label){
4644
+ case 0:
4645
+ if (!vmapUrl.trim()) {
4646
+ return [
4647
+ 2
4648
+ ];
4649
+ }
4650
+ _state.label = 1;
4651
+ case 1:
4652
+ _state.trys.push([
4653
+ 1,
4654
+ 4,
4655
+ ,
4656
+ 5
4657
+ ]);
4658
+ return [
4659
+ 4,
4660
+ fetch(vmapUrl)
4661
+ ];
4662
+ case 2:
4663
+ response = _state.sent();
4664
+ if (!response.ok) {
4665
+ throw new Error("Failed to fetch VMAP (".concat(response.status, ")"));
4666
+ }
4667
+ return [
4668
+ 4,
4669
+ response.text()
4670
+ ];
4671
+ case 3:
4672
+ vmapXml = _state.sent();
4673
+ this.vmapBreaks = this.parseVmapToBreaks(vmapXml);
4674
+ this.consumedVmapBreakIds.clear();
4675
+ if (this.config.debugAdTiming) {
4676
+ console.log("[StormcloudVideoPlayer] Loaded ".concat(this.vmapBreaks.length, " VMAP ad break(s) from:"), vmapUrl);
4677
+ }
4678
+ return [
4679
+ 3,
4680
+ 5
4681
+ ];
4682
+ case 4:
4683
+ error = _state.sent();
4684
+ this.vmapBreaks = [];
4685
+ this.consumedVmapBreakIds.clear();
4686
+ if (this.config.debugAdTiming) {
4687
+ console.warn("[StormcloudVideoPlayer] Failed to load VMAP:", error);
4688
+ }
4689
+ return [
4690
+ 3,
4691
+ 5
4692
+ ];
4693
+ case 5:
4694
+ return [
4695
+ 2
4696
+ ];
4697
+ }
4698
+ });
4699
+ }).call(this);
4700
+ }
4701
+ },
4702
+ {
4703
+ key: "parseVmapToBreaks",
4704
+ value: function parseVmapToBreaks(vmapXml) {
4705
+ var _this = this;
4706
+ if (typeof DOMParser === "undefined") {
4707
+ return [];
4708
+ }
4709
+ var doc = new DOMParser().parseFromString(vmapXml, "application/xml");
4710
+ if (doc.querySelector("parsererror")) {
4711
+ if (this.config.debugAdTiming) {
4712
+ console.warn("[StormcloudVideoPlayer] Invalid VMAP XML received");
4713
+ }
4714
+ return [];
4715
+ }
4716
+ var adBreakNodes = Array.from(doc.querySelectorAll("AdBreak, vmap\\:AdBreak"));
4717
+ var parsed = [];
4718
+ adBreakNodes.forEach(function(node, index) {
4719
+ var timeOffsetRaw = (node.getAttribute("timeOffset") || "").trim();
4720
+ var startTimeMs = _this.parseVmapTimeOffsetToMs(timeOffsetRaw);
4721
+ if (startTimeMs == null) {
4722
+ return;
4723
+ }
4724
+ var adTagNode = node.querySelector("AdTagURI, vmap\\:AdTagURI");
4725
+ var adTagUrl = ((adTagNode === null || adTagNode === void 0 ? void 0 : adTagNode.textContent) || "").trim();
4726
+ if (!adTagUrl) {
4727
+ return;
4728
+ }
4729
+ var breakId = node.getAttribute("breakId") || "vmap-break-".concat(index, "-").concat(timeOffsetRaw || "unknown");
4730
+ parsed.push({
4731
+ id: breakId,
4732
+ startTimeMs: startTimeMs,
4733
+ vastTagUrl: adTagUrl
4734
+ });
4735
+ });
4736
+ parsed.sort(function(a, b) {
4737
+ var aStart = a.startTimeMs < 0 ? Number.MAX_SAFE_INTEGER : a.startTimeMs;
4738
+ var bStart = b.startTimeMs < 0 ? Number.MAX_SAFE_INTEGER : b.startTimeMs;
4739
+ return aStart - bStart;
4740
+ });
4741
+ return parsed;
4742
+ }
4743
+ },
4744
+ {
4745
+ key: "parseVmapTimeOffsetToMs",
4746
+ value: function parseVmapTimeOffsetToMs(timeOffset) {
4747
+ if (!timeOffset) {
4748
+ return void 0;
4749
+ }
4750
+ var normalized = timeOffset.trim().toLowerCase();
4751
+ if (normalized === "start") {
4752
+ return 0;
4753
+ }
4754
+ if (normalized === "end") {
4755
+ return -1;
4756
+ }
4757
+ var hms = timeOffset.match(/^(\d{1,2}):(\d{2}):(\d{2})(?:\.(\d{1,3}))?$/);
4758
+ if (hms) {
4759
+ var _hms = _sliced_to_array(hms, 5), hh = _hms[1], mm = _hms[2], ss = _hms[3], tmp = _hms[4], ms = tmp === void 0 ? "0" : tmp;
4760
+ var hours = Number(hh);
4761
+ var minutes = Number(mm);
4762
+ var seconds = Number(ss);
4763
+ var millis = Number(ms.padEnd(3, "0").slice(0, 3));
4764
+ return (hours * 3600 + minutes * 60 + seconds) * 1e3 + millis;
4765
+ }
4766
+ var percent = timeOffset.match(/^(\d+(?:\.\d+)?)%$/);
4767
+ if (percent) {
4768
+ var ratio = Number(percent[1]) / 100;
4769
+ var durationSec = this.video.duration;
4770
+ if (Number.isFinite(durationSec) && durationSec > 0) {
4771
+ return Math.floor(durationSec * 1e3 * ratio);
4772
+ }
4773
+ return void 0;
4774
+ }
4775
+ return void 0;
4776
+ }
4777
+ },
4778
+ {
4779
+ key: "getAdBreakKey",
4780
+ value: function getAdBreakKey(adBreak) {
4781
+ if (adBreak.id) {
4782
+ return adBreak.id;
4783
+ }
4784
+ return "".concat(adBreak.startTimeMs, "-").concat(adBreak.vastTagUrl || "");
4785
+ }
4786
+ },
4787
+ {
4788
+ key: "resolveBreakStartMs",
4789
+ value: function resolveBreakStartMs(adBreak) {
4790
+ if (adBreak.startTimeMs >= 0) {
4791
+ return adBreak.startTimeMs;
4792
+ }
4793
+ if (adBreak.startTimeMs === -1) {
4794
+ var durationSec = this.video.duration;
4795
+ if (Number.isFinite(durationSec) && durationSec > 0) {
4796
+ return Math.floor(durationSec * 1e3);
4797
+ }
4798
+ }
4799
+ return void 0;
4800
+ }
4801
+ },
4619
4802
  {
4620
4803
  key: "getCurrentAdIndex",
4621
4804
  value: function getCurrentAdIndex() {
@@ -4628,6 +4811,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4628
4811
  return this.totalAdsInBreak;
4629
4812
  }
4630
4813
  },
4814
+ {
4815
+ key: "getAdRemainingMs",
4816
+ value: function getAdRemainingMs() {
4817
+ return this.getRemainingAdMs();
4818
+ }
4819
+ },
4631
4820
  {
4632
4821
  key: "generateVastUrlsWithCorrelators",
4633
4822
  value: function generateVastUrlsWithCorrelators(baseUrl, count) {
@@ -4706,10 +4895,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4706
4895
  var scheduled = this.findCurrentOrNextBreak(this.video.currentTime * 1e3);
4707
4896
  var tags = this.selectVastTagsForBreak(scheduled);
4708
4897
  var baseVastUrl;
4709
- if (this.apiVastTagUrl) {
4710
- baseVastUrl = this.apiVastTagUrl;
4711
- } else if (tags && tags.length > 0 && tags[0]) {
4898
+ if (tags && tags.length > 0 && tags[0]) {
4712
4899
  baseVastUrl = tags[0];
4900
+ } else if (this.apiVastTagUrl) {
4901
+ baseVastUrl = this.apiVastTagUrl;
4713
4902
  } else {
4714
4903
  if (this.config.debugAdTiming) {
4715
4904
  console.warn("[StormcloudVideoPlayer] No VAST URL available for prefetch");
@@ -5159,11 +5348,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5159
5348
  switch(_state.label){
5160
5349
  case 0:
5161
5350
  scheduled = this.findCurrentOrNextBreak(this.video.currentTime * 1e3);
5351
+ if (scheduled) {
5352
+ this.consumedVmapBreakIds.add(this.getAdBreakKey(scheduled));
5353
+ }
5162
5354
  tags = this.selectVastTagsForBreak(scheduled);
5163
- if (this.apiVastTagUrl) {
5164
- baseVastUrl = this.apiVastTagUrl;
5165
- } else if (tags && tags.length > 0 && tags[0]) {
5355
+ if (tags && tags.length > 0 && tags[0]) {
5166
5356
  baseVastUrl = tags[0];
5357
+ } else if (this.apiVastTagUrl) {
5358
+ baseVastUrl = this.apiVastTagUrl;
5167
5359
  } else {
5168
5360
  this.clearPendingAdBreak();
5169
5361
  return [
@@ -5277,9 +5469,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5277
5469
  ];
5278
5470
  case 2:
5279
5471
  _state.sent();
5280
- if (this.expectedAdBreakDurationMs != null) {
5281
- this.currentAdBreakStartWallClockMs = Date.now();
5282
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
5472
+ if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
5473
+ this.scheduleAdStopCountdown(this.getRemainingAdMs());
5283
5474
  }
5284
5475
  adVolume = currentMuted ? 0 : currentVolume;
5285
5476
  this.ima.setAdVolume(adVolume);
@@ -5320,9 +5511,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5320
5511
  ];
5321
5512
  case 6:
5322
5513
  _state.sent();
5323
- if (this.expectedAdBreakDurationMs != null) {
5324
- this.currentAdBreakStartWallClockMs = Date.now();
5325
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
5514
+ if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
5515
+ this.scheduleAdStopCountdown(this.getRemainingAdMs());
5326
5516
  }
5327
5517
  adVolume1 = currentMuted ? 0 : currentVolume;
5328
5518
  this.ima.setAdVolume(adVolume1);
@@ -5376,9 +5566,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5376
5566
  ];
5377
5567
  case 10:
5378
5568
  _state.sent();
5379
- if (this.expectedAdBreakDurationMs != null) {
5380
- this.currentAdBreakStartWallClockMs = Date.now();
5381
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
5569
+ if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
5570
+ this.scheduleAdStopCountdown(this.getRemainingAdMs());
5382
5571
  }
5383
5572
  adVolume2 = currentMuted ? 0 : currentVolume;
5384
5573
  this.ima.setAdVolume(adVolume2);
@@ -5729,8 +5918,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5729
5918
  case 2:
5730
5919
  _state.sent();
5731
5920
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
5732
- this.currentAdBreakStartWallClockMs = Date.now();
5733
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
5921
+ this.scheduleAdStopCountdown(this.getRemainingAdMs());
5734
5922
  }
5735
5923
  currentMuted = this.video.muted;
5736
5924
  currentVolume = this.video.volume;
@@ -6042,15 +6230,22 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6042
6230
  {
6043
6231
  key: "findCurrentOrNextBreak",
6044
6232
  value: function findCurrentOrNextBreak(nowMs) {
6045
- var schedule = [];
6233
+ var schedule = this.vmapBreaks;
6046
6234
  var candidate;
6047
6235
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
6048
6236
  try {
6049
6237
  for(var _iterator = schedule[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
6050
6238
  var b = _step.value;
6051
- var _this_config_driftToleranceMs;
6239
+ var _this_config_driftToleranceMs, _this_resolveBreakStartMs;
6240
+ if (this.consumedVmapBreakIds.has(this.getAdBreakKey(b))) {
6241
+ continue;
6242
+ }
6243
+ var breakStartMs = this.resolveBreakStartMs(b);
6244
+ if (breakStartMs == null) {
6245
+ continue;
6246
+ }
6052
6247
  var tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
6053
- if (b.startTimeMs <= nowMs + tol && (candidate == null || b.startTimeMs > (candidate.startTimeMs || 0))) {
6248
+ if (breakStartMs <= nowMs + tol && (candidate == null || breakStartMs > ((_this_resolveBreakStartMs = this.resolveBreakStartMs(candidate)) !== null && _this_resolveBreakStartMs !== void 0 ? _this_resolveBreakStartMs : 0))) {
6054
6249
  candidate = b;
6055
6250
  }
6056
6251
  }
@@ -6074,11 +6269,16 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6074
6269
  {
6075
6270
  key: "onTimeUpdate",
6076
6271
  value: function onTimeUpdate(currentTimeSec) {
6077
- if (this.ima.isAdPlaying()) return;
6272
+ var _this = this;
6273
+ if (this.ima.isAdPlaying() || this.inAdBreak) return;
6078
6274
  var nowMs = currentTimeSec * 1e3;
6079
6275
  var breakToPlay = this.findBreakForTime(nowMs);
6080
6276
  if (breakToPlay) {
6081
- this.handleMidAdJoin(breakToPlay, nowMs);
6277
+ void this.handleMidAdJoin(breakToPlay, nowMs).catch(function(error) {
6278
+ if (_this.config.debugAdTiming) {
6279
+ console.warn("[StormcloudVideoPlayer] Mid-roll VMAP join failed gracefully:", error);
6280
+ }
6281
+ });
6082
6282
  }
6083
6283
  }
6084
6284
  },
@@ -6086,40 +6286,76 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6086
6286
  key: "handleMidAdJoin",
6087
6287
  value: function handleMidAdJoin(adBreak, nowMs) {
6088
6288
  return _async_to_generator(function() {
6089
- var _adBreak_durationMs, durationMs, endMs, remainingMs, tags, first, rest;
6289
+ var _adBreak_durationMs, _this_config_driftToleranceMs, key, breakStartMs, durationMs, endMs, tol, inWindow, remainingMs, tags, first, rest, error;
6090
6290
  return _ts_generator(this, function(_state) {
6091
6291
  switch(_state.label){
6092
6292
  case 0:
6293
+ key = this.getAdBreakKey(adBreak);
6294
+ if (this.consumedVmapBreakIds.has(key)) {
6295
+ return [
6296
+ 2
6297
+ ];
6298
+ }
6299
+ breakStartMs = this.resolveBreakStartMs(adBreak);
6300
+ if (breakStartMs == null) {
6301
+ return [
6302
+ 2
6303
+ ];
6304
+ }
6093
6305
  durationMs = (_adBreak_durationMs = adBreak.durationMs) !== null && _adBreak_durationMs !== void 0 ? _adBreak_durationMs : 0;
6094
- endMs = adBreak.startTimeMs + durationMs;
6095
- if (!(durationMs > 0 && nowMs > adBreak.startTimeMs && nowMs < endMs)) return [
6306
+ endMs = breakStartMs + durationMs;
6307
+ tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
6308
+ inWindow = durationMs > 0 ? nowMs > breakStartMs && nowMs < endMs : nowMs + tol >= breakStartMs;
6309
+ if (!inWindow) return [
6096
6310
  3,
6097
- 2
6311
+ 4
6098
6312
  ];
6099
- remainingMs = endMs - nowMs;
6313
+ this.consumedVmapBreakIds.add(key);
6314
+ remainingMs = durationMs > 0 ? Math.max(0, endMs - nowMs) : 0;
6100
6315
  tags = this.selectVastTagsForBreak(adBreak) || (this.apiVastTagUrl ? [
6101
6316
  this.apiVastTagUrl
6102
6317
  ] : void 0);
6103
6318
  if (!(tags && tags.length > 0)) return [
6104
6319
  3,
6105
- 2
6320
+ 4
6106
6321
  ];
6107
6322
  first = tags[0];
6108
6323
  rest = tags.slice(1);
6109
6324
  this.adPodQueue = rest;
6110
6325
  this.ima.updateOriginalMutedState(this.video.muted, this.video.volume);
6326
+ _state.label = 1;
6327
+ case 1:
6328
+ _state.trys.push([
6329
+ 1,
6330
+ 3,
6331
+ ,
6332
+ 4
6333
+ ]);
6111
6334
  return [
6112
6335
  4,
6113
6336
  this.playSingleAd(first)
6114
6337
  ];
6115
- case 1:
6338
+ case 2:
6116
6339
  _state.sent();
6117
6340
  this.inAdBreak = true;
6118
6341
  this.expectedAdBreakDurationMs = remainingMs;
6119
6342
  this.currentAdBreakStartWallClockMs = Date.now();
6120
6343
  this.scheduleAdStopCountdown(remainingMs);
6121
- _state.label = 2;
6122
- case 2:
6344
+ return [
6345
+ 3,
6346
+ 4
6347
+ ];
6348
+ case 3:
6349
+ error = _state.sent();
6350
+ this.adPodQueue = [];
6351
+ if (this.config.debugAdTiming) {
6352
+ console.warn("[StormcloudVideoPlayer] Mid-roll VMAP ad request failed:", error);
6353
+ }
6354
+ return [
6355
+ 3,
6356
+ 4
6357
+ ];
6358
+ case 4:
6123
6359
  return [
6124
6360
  2
6125
6361
  ];
@@ -6435,8 +6671,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6435
6671
  case 5:
6436
6672
  _state.sent();
6437
6673
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
6438
- this.currentAdBreakStartWallClockMs = Date.now();
6439
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
6674
+ this.scheduleAdStopCountdown(this.getRemainingAdMs());
6440
6675
  }
6441
6676
  currentMuted = this.video.muted;
6442
6677
  currentVolume = this.video.volume;
@@ -6486,8 +6721,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6486
6721
  case 8:
6487
6722
  _state.sent();
6488
6723
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
6489
- this.currentAdBreakStartWallClockMs = Date.now();
6490
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
6724
+ this.scheduleAdStopCountdown(this.getRemainingAdMs());
6491
6725
  }
6492
6726
  currentMuted1 = this.video.muted;
6493
6727
  currentVolume1 = this.video.volume;
@@ -6825,13 +7059,22 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6825
7059
  {
6826
7060
  key: "findBreakForTime",
6827
7061
  value: function findBreakForTime(nowMs) {
6828
- var schedule = [];
7062
+ var _this_config_driftToleranceMs;
7063
+ var schedule = this.vmapBreaks;
7064
+ var tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
6829
7065
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
6830
7066
  try {
6831
7067
  for(var _iterator = schedule[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
6832
7068
  var b = _step.value;
6833
- var end = (b.startTimeMs || 0) + (b.durationMs || 0);
6834
- if (nowMs >= (b.startTimeMs || 0) && (b.durationMs ? nowMs < end : true)) {
7069
+ if (this.consumedVmapBreakIds.has(this.getAdBreakKey(b))) {
7070
+ continue;
7071
+ }
7072
+ var breakStartMs = this.resolveBreakStartMs(b);
7073
+ if (breakStartMs == null) {
7074
+ continue;
7075
+ }
7076
+ var end = breakStartMs + (b.durationMs || 0);
7077
+ if (nowMs >= breakStartMs && (b.durationMs ? nowMs < end : nowMs <= breakStartMs + tol)) {
6835
7078
  return b;
6836
7079
  }
6837
7080
  }