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.
@@ -1,4 +1,4 @@
1
- import { S as StormcloudVideoPlayerConfig } from '../types-C23mJ_hh.cjs';
1
+ import { S as StormcloudVideoPlayerConfig } from '../types-Vj55FghO.cjs';
2
2
 
3
3
  declare class StormcloudVideoPlayer {
4
4
  private readonly video;
@@ -16,6 +16,8 @@ declare class StormcloudVideoPlayer {
16
16
  private adPodQueue;
17
17
  private apiVastTagUrl;
18
18
  private apiNumberAds;
19
+ private vmapBreaks;
20
+ private consumedVmapBreakIds;
19
21
  private lastHeartbeatTime;
20
22
  private heartbeatInterval;
21
23
  private currentAdIndex;
@@ -87,8 +89,14 @@ declare class StormcloudVideoPlayer {
87
89
  private initializeTracking;
88
90
  private sendHeartbeatIfNeeded;
89
91
  private fetchAdConfiguration;
92
+ private fetchAndParseVmap;
93
+ private parseVmapToBreaks;
94
+ private parseVmapTimeOffsetToMs;
95
+ private getAdBreakKey;
96
+ private resolveBreakStartMs;
90
97
  getCurrentAdIndex(): number;
91
98
  getTotalAdsInBreak(): number;
99
+ getAdRemainingMs(): number;
92
100
  private generateVastUrlsWithCorrelators;
93
101
  isAdPlaying(): boolean;
94
102
  isShowingAds(): boolean;
@@ -706,7 +706,7 @@ function createImaController(video, options) {
706
706
  adVideo.style.height = "100%";
707
707
  adVideo.style.objectFit = "contain";
708
708
  adVideo.style.backgroundColor = "transparent";
709
- adVideo.style.zIndex = "15";
709
+ adVideo.style.zIndex = "2";
710
710
  adVideo.playsInline = true;
711
711
  adVideo.volume = originalVolume;
712
712
  adVideo.muted = originalMutedState;
@@ -999,7 +999,7 @@ function createImaController(video, options) {
999
999
  container.style.alignItems = "center";
1000
1000
  container.style.justifyContent = "center";
1001
1001
  container.style.pointerEvents = "none";
1002
- container.style.zIndex = "10";
1002
+ container.style.zIndex = "30";
1003
1003
  container.style.backgroundColor = "#000";
1004
1004
  container.style.transition = "opacity 0.3s ease-in-out";
1005
1005
  container.style.opacity = "0";
@@ -1114,7 +1114,7 @@ function createImaController(video, options) {
1114
1114
  container.style.alignItems = "center";
1115
1115
  container.style.justifyContent = "center";
1116
1116
  container.style.pointerEvents = "none";
1117
- container.style.zIndex = "10";
1117
+ container.style.zIndex = "30";
1118
1118
  container.style.backgroundColor = "transparent";
1119
1119
  container.style.transition = "opacity 0.3s ease-in-out, background-color 0.3s ease-in-out";
1120
1120
  container.style.opacity = "0";
@@ -2029,7 +2029,7 @@ function createHlsAdPlayer(contentVideo, options) {
2029
2029
  container.style.alignItems = "center";
2030
2030
  container.style.justifyContent = "center";
2031
2031
  container.style.pointerEvents = "none";
2032
- container.style.zIndex = "10";
2032
+ container.style.zIndex = "30";
2033
2033
  container.style.backgroundColor = "#000";
2034
2034
  (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
2035
2035
  adContainerEl = container;
@@ -3253,6 +3253,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3253
3253
  this.inAdBreak = false;
3254
3254
  this.ptsDriftEmaMs = 0;
3255
3255
  this.adPodQueue = [];
3256
+ this.vmapBreaks = [];
3257
+ this.consumedVmapBreakIds = /* @__PURE__ */ new Set();
3256
3258
  this.lastHeartbeatTime = 0;
3257
3259
  this.currentAdIndex = 0;
3258
3260
  this.totalAdsInBreak = 0;
@@ -3807,13 +3809,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3807
3809
  _this.activeAdRequestToken = null;
3808
3810
  _this.showAds = true;
3809
3811
  _this.resetGamNoFillCounter();
3810
- if (_this.inAdBreak && _this.expectedAdBreakDurationMs != null) {
3811
- if (_this.adStopTimerId == null) {
3812
- _this.currentAdBreakStartWallClockMs = Date.now();
3813
- _this.scheduleAdStopCountdown(_this.expectedAdBreakDurationMs);
3814
- if (_this.config.debugAdTiming) {
3815
- console.log("[StormcloudVideoPlayer] Starting ad break timer on content_pause (first ad starting)");
3816
- }
3812
+ if (_this.inAdBreak && _this.expectedAdBreakDurationMs != null && _this.adStopTimerId == null) {
3813
+ _this.scheduleAdStopCountdown(_this.getRemainingAdMs());
3814
+ if (_this.config.debugAdTiming) {
3815
+ console.log("[StormcloudVideoPlayer] Starting ad break timer on content_pause (first ad starting)");
3817
3816
  }
3818
3817
  }
3819
3818
  var currentMuted = _this.video.muted;
@@ -3876,6 +3875,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3876
3875
  this.ima.showPlaceholder();
3877
3876
  this.isShowingPlaceholder = true;
3878
3877
  }
3878
+ var preservedMutedState = this.ima.getOriginalMutedState();
3879
+ var preservedVolumeState = this.ima.getOriginalVolume();
3879
3880
  if (this.ima) {
3880
3881
  try {
3881
3882
  this.ima.destroy();
@@ -3890,7 +3891,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3890
3891
  var continueLiveStreamDuringAds = this.shouldContinueLiveStreamDuringAds();
3891
3892
  this.ima = this.createAdPlayer(continueLiveStreamDuringAds);
3892
3893
  this.ima.initialize();
3893
- this.ima.updateOriginalMutedState(this.video.muted, this.video.volume);
3894
+ this.ima.updateOriginalMutedState(preservedMutedState, preservedVolumeState);
3894
3895
  this.attachImaEventListeners();
3895
3896
  if (shouldShowPlaceholder) {
3896
3897
  this.showPlaceholderLayer();
@@ -4206,12 +4207,17 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4206
4207
  }
4207
4208
  }
4208
4209
  if (this.inAdBreak) {
4209
- if (this.expectedAdBreakDurationMs == null && marker.durationSeconds != null) {
4210
- this.expectedAdBreakDurationMs = marker.durationSeconds * 1e3;
4211
- if (this.config.debugAdTiming) {
4212
- console.log("[StormcloudVideoPlayer] Updated ad break duration from subsequent marker: ".concat(this.expectedAdBreakDurationMs, "ms"));
4210
+ if (marker.durationSeconds != null) {
4211
+ var newDurationMs = marker.durationSeconds * 1e3;
4212
+ if (this.expectedAdBreakDurationMs == null || newDurationMs > this.expectedAdBreakDurationMs) {
4213
+ this.expectedAdBreakDurationMs = newDurationMs;
4214
+ var elapsedMs = this.currentAdBreakStartWallClockMs != null ? Date.now() - this.currentAdBreakStartWallClockMs : 0;
4215
+ var remainingMs = Math.max(0, newDurationMs - elapsedMs);
4216
+ this.scheduleAdStopCountdown(remainingMs);
4217
+ if (this.config.debugAdTiming) {
4218
+ console.log("[StormcloudVideoPlayer] Updated ad break duration from subsequent marker: ".concat(newDurationMs, "ms, remaining: ").concat(remainingMs, "ms"));
4219
+ }
4213
4220
  }
4214
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
4215
4221
  }
4216
4222
  return;
4217
4223
  }
@@ -4287,9 +4293,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4287
4293
  this.expectedAdBreakDurationMs = marker.durationSeconds * 1e3;
4288
4294
  }
4289
4295
  if (this.expectedAdBreakDurationMs != null && this.currentAdBreakStartWallClockMs != null) {
4290
- var elapsedMs = Date.now() - this.currentAdBreakStartWallClockMs;
4291
- var remainingMs = Math.max(0, this.expectedAdBreakDurationMs - elapsedMs);
4292
- this.scheduleAdStopCountdown(remainingMs);
4296
+ var elapsedMs1 = Date.now() - this.currentAdBreakStartWallClockMs;
4297
+ var remainingMs1 = Math.max(0, this.expectedAdBreakDurationMs - elapsedMs1);
4298
+ this.scheduleAdStopCountdown(remainingMs1);
4293
4299
  }
4294
4300
  if (!this.ima.isAdPlaying() && this.activeAdRequestToken === null && this.adRequestQueue.length > 0) {
4295
4301
  this.tryNextAvailableAdWithRateLimit();
@@ -4581,6 +4587,18 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4581
4587
  return _ts_generator(this, function(_state) {
4582
4588
  switch(_state.label){
4583
4589
  case 0:
4590
+ if (!this.config.vmapUrl) return [
4591
+ 3,
4592
+ 2
4593
+ ];
4594
+ return [
4595
+ 4,
4596
+ this.fetchAndParseVmap(this.config.vmapUrl)
4597
+ ];
4598
+ case 1:
4599
+ _state.sent();
4600
+ _state.label = 2;
4601
+ case 2:
4584
4602
  vastMode = this.config.vastMode || "default";
4585
4603
  if (this.config.debugAdTiming) {
4586
4604
  console.log("[StormcloudVideoPlayer] VAST mode:", vastMode);
@@ -4626,7 +4644,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4626
4644
  headers: headers
4627
4645
  })
4628
4646
  ];
4629
- case 1:
4647
+ case 3:
4630
4648
  response = _state.sent();
4631
4649
  if (!response.ok) {
4632
4650
  if (this.config.debugAdTiming) {
@@ -4640,7 +4658,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4640
4658
  4,
4641
4659
  response.json()
4642
4660
  ];
4643
- case 2:
4661
+ case 4:
4644
4662
  data = _state.sent();
4645
4663
  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;
4646
4664
  if (imaPayload) {
@@ -4668,6 +4686,171 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4668
4686
  }).call(this);
4669
4687
  }
4670
4688
  },
4689
+ {
4690
+ key: "fetchAndParseVmap",
4691
+ value: function fetchAndParseVmap(vmapUrl) {
4692
+ return _async_to_generator(function() {
4693
+ var response, vmapXml, error;
4694
+ return _ts_generator(this, function(_state) {
4695
+ switch(_state.label){
4696
+ case 0:
4697
+ if (!vmapUrl.trim()) {
4698
+ return [
4699
+ 2
4700
+ ];
4701
+ }
4702
+ _state.label = 1;
4703
+ case 1:
4704
+ _state.trys.push([
4705
+ 1,
4706
+ 4,
4707
+ ,
4708
+ 5
4709
+ ]);
4710
+ return [
4711
+ 4,
4712
+ fetch(vmapUrl)
4713
+ ];
4714
+ case 2:
4715
+ response = _state.sent();
4716
+ if (!response.ok) {
4717
+ throw new Error("Failed to fetch VMAP (".concat(response.status, ")"));
4718
+ }
4719
+ return [
4720
+ 4,
4721
+ response.text()
4722
+ ];
4723
+ case 3:
4724
+ vmapXml = _state.sent();
4725
+ this.vmapBreaks = this.parseVmapToBreaks(vmapXml);
4726
+ this.consumedVmapBreakIds.clear();
4727
+ if (this.config.debugAdTiming) {
4728
+ console.log("[StormcloudVideoPlayer] Loaded ".concat(this.vmapBreaks.length, " VMAP ad break(s) from:"), vmapUrl);
4729
+ }
4730
+ return [
4731
+ 3,
4732
+ 5
4733
+ ];
4734
+ case 4:
4735
+ error = _state.sent();
4736
+ this.vmapBreaks = [];
4737
+ this.consumedVmapBreakIds.clear();
4738
+ if (this.config.debugAdTiming) {
4739
+ console.warn("[StormcloudVideoPlayer] Failed to load VMAP:", error);
4740
+ }
4741
+ return [
4742
+ 3,
4743
+ 5
4744
+ ];
4745
+ case 5:
4746
+ return [
4747
+ 2
4748
+ ];
4749
+ }
4750
+ });
4751
+ }).call(this);
4752
+ }
4753
+ },
4754
+ {
4755
+ key: "parseVmapToBreaks",
4756
+ value: function parseVmapToBreaks(vmapXml) {
4757
+ var _this = this;
4758
+ if (typeof DOMParser === "undefined") {
4759
+ return [];
4760
+ }
4761
+ var doc = new DOMParser().parseFromString(vmapXml, "application/xml");
4762
+ if (doc.querySelector("parsererror")) {
4763
+ if (this.config.debugAdTiming) {
4764
+ console.warn("[StormcloudVideoPlayer] Invalid VMAP XML received");
4765
+ }
4766
+ return [];
4767
+ }
4768
+ var adBreakNodes = Array.from(doc.querySelectorAll("AdBreak, vmap\\:AdBreak"));
4769
+ var parsed = [];
4770
+ adBreakNodes.forEach(function(node, index) {
4771
+ var timeOffsetRaw = (node.getAttribute("timeOffset") || "").trim();
4772
+ var startTimeMs = _this.parseVmapTimeOffsetToMs(timeOffsetRaw);
4773
+ if (startTimeMs == null) {
4774
+ return;
4775
+ }
4776
+ var adTagNode = node.querySelector("AdTagURI, vmap\\:AdTagURI");
4777
+ var adTagUrl = ((adTagNode === null || adTagNode === void 0 ? void 0 : adTagNode.textContent) || "").trim();
4778
+ if (!adTagUrl) {
4779
+ return;
4780
+ }
4781
+ var breakId = node.getAttribute("breakId") || "vmap-break-".concat(index, "-").concat(timeOffsetRaw || "unknown");
4782
+ parsed.push({
4783
+ id: breakId,
4784
+ startTimeMs: startTimeMs,
4785
+ vastTagUrl: adTagUrl
4786
+ });
4787
+ });
4788
+ parsed.sort(function(a, b) {
4789
+ var aStart = a.startTimeMs < 0 ? Number.MAX_SAFE_INTEGER : a.startTimeMs;
4790
+ var bStart = b.startTimeMs < 0 ? Number.MAX_SAFE_INTEGER : b.startTimeMs;
4791
+ return aStart - bStart;
4792
+ });
4793
+ return parsed;
4794
+ }
4795
+ },
4796
+ {
4797
+ key: "parseVmapTimeOffsetToMs",
4798
+ value: function parseVmapTimeOffsetToMs(timeOffset) {
4799
+ if (!timeOffset) {
4800
+ return void 0;
4801
+ }
4802
+ var normalized = timeOffset.trim().toLowerCase();
4803
+ if (normalized === "start") {
4804
+ return 0;
4805
+ }
4806
+ if (normalized === "end") {
4807
+ return -1;
4808
+ }
4809
+ var hms = timeOffset.match(/^(\d{1,2}):(\d{2}):(\d{2})(?:\.(\d{1,3}))?$/);
4810
+ if (hms) {
4811
+ 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;
4812
+ var hours = Number(hh);
4813
+ var minutes = Number(mm);
4814
+ var seconds = Number(ss);
4815
+ var millis = Number(ms.padEnd(3, "0").slice(0, 3));
4816
+ return (hours * 3600 + minutes * 60 + seconds) * 1e3 + millis;
4817
+ }
4818
+ var percent = timeOffset.match(/^(\d+(?:\.\d+)?)%$/);
4819
+ if (percent) {
4820
+ var ratio = Number(percent[1]) / 100;
4821
+ var durationSec = this.video.duration;
4822
+ if (Number.isFinite(durationSec) && durationSec > 0) {
4823
+ return Math.floor(durationSec * 1e3 * ratio);
4824
+ }
4825
+ return void 0;
4826
+ }
4827
+ return void 0;
4828
+ }
4829
+ },
4830
+ {
4831
+ key: "getAdBreakKey",
4832
+ value: function getAdBreakKey(adBreak) {
4833
+ if (adBreak.id) {
4834
+ return adBreak.id;
4835
+ }
4836
+ return "".concat(adBreak.startTimeMs, "-").concat(adBreak.vastTagUrl || "");
4837
+ }
4838
+ },
4839
+ {
4840
+ key: "resolveBreakStartMs",
4841
+ value: function resolveBreakStartMs(adBreak) {
4842
+ if (adBreak.startTimeMs >= 0) {
4843
+ return adBreak.startTimeMs;
4844
+ }
4845
+ if (adBreak.startTimeMs === -1) {
4846
+ var durationSec = this.video.duration;
4847
+ if (Number.isFinite(durationSec) && durationSec > 0) {
4848
+ return Math.floor(durationSec * 1e3);
4849
+ }
4850
+ }
4851
+ return void 0;
4852
+ }
4853
+ },
4671
4854
  {
4672
4855
  key: "getCurrentAdIndex",
4673
4856
  value: function getCurrentAdIndex() {
@@ -4680,6 +4863,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4680
4863
  return this.totalAdsInBreak;
4681
4864
  }
4682
4865
  },
4866
+ {
4867
+ key: "getAdRemainingMs",
4868
+ value: function getAdRemainingMs() {
4869
+ return this.getRemainingAdMs();
4870
+ }
4871
+ },
4683
4872
  {
4684
4873
  key: "generateVastUrlsWithCorrelators",
4685
4874
  value: function generateVastUrlsWithCorrelators(baseUrl, count) {
@@ -4758,10 +4947,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4758
4947
  var scheduled = this.findCurrentOrNextBreak(this.video.currentTime * 1e3);
4759
4948
  var tags = this.selectVastTagsForBreak(scheduled);
4760
4949
  var baseVastUrl;
4761
- if (this.apiVastTagUrl) {
4762
- baseVastUrl = this.apiVastTagUrl;
4763
- } else if (tags && tags.length > 0 && tags[0]) {
4950
+ if (tags && tags.length > 0 && tags[0]) {
4764
4951
  baseVastUrl = tags[0];
4952
+ } else if (this.apiVastTagUrl) {
4953
+ baseVastUrl = this.apiVastTagUrl;
4765
4954
  } else {
4766
4955
  if (this.config.debugAdTiming) {
4767
4956
  console.warn("[StormcloudVideoPlayer] No VAST URL available for prefetch");
@@ -5211,11 +5400,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5211
5400
  switch(_state.label){
5212
5401
  case 0:
5213
5402
  scheduled = this.findCurrentOrNextBreak(this.video.currentTime * 1e3);
5403
+ if (scheduled) {
5404
+ this.consumedVmapBreakIds.add(this.getAdBreakKey(scheduled));
5405
+ }
5214
5406
  tags = this.selectVastTagsForBreak(scheduled);
5215
- if (this.apiVastTagUrl) {
5216
- baseVastUrl = this.apiVastTagUrl;
5217
- } else if (tags && tags.length > 0 && tags[0]) {
5407
+ if (tags && tags.length > 0 && tags[0]) {
5218
5408
  baseVastUrl = tags[0];
5409
+ } else if (this.apiVastTagUrl) {
5410
+ baseVastUrl = this.apiVastTagUrl;
5219
5411
  } else {
5220
5412
  this.clearPendingAdBreak();
5221
5413
  return [
@@ -5329,9 +5521,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5329
5521
  ];
5330
5522
  case 2:
5331
5523
  _state.sent();
5332
- if (this.expectedAdBreakDurationMs != null) {
5333
- this.currentAdBreakStartWallClockMs = Date.now();
5334
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
5524
+ if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
5525
+ this.scheduleAdStopCountdown(this.getRemainingAdMs());
5335
5526
  }
5336
5527
  adVolume = currentMuted ? 0 : currentVolume;
5337
5528
  this.ima.setAdVolume(adVolume);
@@ -5372,9 +5563,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5372
5563
  ];
5373
5564
  case 6:
5374
5565
  _state.sent();
5375
- if (this.expectedAdBreakDurationMs != null) {
5376
- this.currentAdBreakStartWallClockMs = Date.now();
5377
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
5566
+ if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
5567
+ this.scheduleAdStopCountdown(this.getRemainingAdMs());
5378
5568
  }
5379
5569
  adVolume1 = currentMuted ? 0 : currentVolume;
5380
5570
  this.ima.setAdVolume(adVolume1);
@@ -5428,9 +5618,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5428
5618
  ];
5429
5619
  case 10:
5430
5620
  _state.sent();
5431
- if (this.expectedAdBreakDurationMs != null) {
5432
- this.currentAdBreakStartWallClockMs = Date.now();
5433
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
5621
+ if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
5622
+ this.scheduleAdStopCountdown(this.getRemainingAdMs());
5434
5623
  }
5435
5624
  adVolume2 = currentMuted ? 0 : currentVolume;
5436
5625
  this.ima.setAdVolume(adVolume2);
@@ -5781,8 +5970,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5781
5970
  case 2:
5782
5971
  _state.sent();
5783
5972
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
5784
- this.currentAdBreakStartWallClockMs = Date.now();
5785
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
5973
+ this.scheduleAdStopCountdown(this.getRemainingAdMs());
5786
5974
  }
5787
5975
  currentMuted = this.video.muted;
5788
5976
  currentVolume = this.video.volume;
@@ -6094,15 +6282,22 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6094
6282
  {
6095
6283
  key: "findCurrentOrNextBreak",
6096
6284
  value: function findCurrentOrNextBreak(nowMs) {
6097
- var schedule = [];
6285
+ var schedule = this.vmapBreaks;
6098
6286
  var candidate;
6099
6287
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
6100
6288
  try {
6101
6289
  for(var _iterator = schedule[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
6102
6290
  var b = _step.value;
6103
- var _this_config_driftToleranceMs;
6291
+ var _this_config_driftToleranceMs, _this_resolveBreakStartMs;
6292
+ if (this.consumedVmapBreakIds.has(this.getAdBreakKey(b))) {
6293
+ continue;
6294
+ }
6295
+ var breakStartMs = this.resolveBreakStartMs(b);
6296
+ if (breakStartMs == null) {
6297
+ continue;
6298
+ }
6104
6299
  var tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
6105
- if (b.startTimeMs <= nowMs + tol && (candidate == null || b.startTimeMs > (candidate.startTimeMs || 0))) {
6300
+ if (breakStartMs <= nowMs + tol && (candidate == null || breakStartMs > ((_this_resolveBreakStartMs = this.resolveBreakStartMs(candidate)) !== null && _this_resolveBreakStartMs !== void 0 ? _this_resolveBreakStartMs : 0))) {
6106
6301
  candidate = b;
6107
6302
  }
6108
6303
  }
@@ -6126,11 +6321,16 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6126
6321
  {
6127
6322
  key: "onTimeUpdate",
6128
6323
  value: function onTimeUpdate(currentTimeSec) {
6129
- if (this.ima.isAdPlaying()) return;
6324
+ var _this = this;
6325
+ if (this.ima.isAdPlaying() || this.inAdBreak) return;
6130
6326
  var nowMs = currentTimeSec * 1e3;
6131
6327
  var breakToPlay = this.findBreakForTime(nowMs);
6132
6328
  if (breakToPlay) {
6133
- this.handleMidAdJoin(breakToPlay, nowMs);
6329
+ void this.handleMidAdJoin(breakToPlay, nowMs).catch(function(error) {
6330
+ if (_this.config.debugAdTiming) {
6331
+ console.warn("[StormcloudVideoPlayer] Mid-roll VMAP join failed gracefully:", error);
6332
+ }
6333
+ });
6134
6334
  }
6135
6335
  }
6136
6336
  },
@@ -6138,40 +6338,76 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6138
6338
  key: "handleMidAdJoin",
6139
6339
  value: function handleMidAdJoin(adBreak, nowMs) {
6140
6340
  return _async_to_generator(function() {
6141
- var _adBreak_durationMs, durationMs, endMs, remainingMs, tags, first, rest;
6341
+ var _adBreak_durationMs, _this_config_driftToleranceMs, key, breakStartMs, durationMs, endMs, tol, inWindow, remainingMs, tags, first, rest, error;
6142
6342
  return _ts_generator(this, function(_state) {
6143
6343
  switch(_state.label){
6144
6344
  case 0:
6345
+ key = this.getAdBreakKey(adBreak);
6346
+ if (this.consumedVmapBreakIds.has(key)) {
6347
+ return [
6348
+ 2
6349
+ ];
6350
+ }
6351
+ breakStartMs = this.resolveBreakStartMs(adBreak);
6352
+ if (breakStartMs == null) {
6353
+ return [
6354
+ 2
6355
+ ];
6356
+ }
6145
6357
  durationMs = (_adBreak_durationMs = adBreak.durationMs) !== null && _adBreak_durationMs !== void 0 ? _adBreak_durationMs : 0;
6146
- endMs = adBreak.startTimeMs + durationMs;
6147
- if (!(durationMs > 0 && nowMs > adBreak.startTimeMs && nowMs < endMs)) return [
6358
+ endMs = breakStartMs + durationMs;
6359
+ tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
6360
+ inWindow = durationMs > 0 ? nowMs > breakStartMs && nowMs < endMs : nowMs + tol >= breakStartMs;
6361
+ if (!inWindow) return [
6148
6362
  3,
6149
- 2
6363
+ 4
6150
6364
  ];
6151
- remainingMs = endMs - nowMs;
6365
+ this.consumedVmapBreakIds.add(key);
6366
+ remainingMs = durationMs > 0 ? Math.max(0, endMs - nowMs) : 0;
6152
6367
  tags = this.selectVastTagsForBreak(adBreak) || (this.apiVastTagUrl ? [
6153
6368
  this.apiVastTagUrl
6154
6369
  ] : void 0);
6155
6370
  if (!(tags && tags.length > 0)) return [
6156
6371
  3,
6157
- 2
6372
+ 4
6158
6373
  ];
6159
6374
  first = tags[0];
6160
6375
  rest = tags.slice(1);
6161
6376
  this.adPodQueue = rest;
6162
6377
  this.ima.updateOriginalMutedState(this.video.muted, this.video.volume);
6378
+ _state.label = 1;
6379
+ case 1:
6380
+ _state.trys.push([
6381
+ 1,
6382
+ 3,
6383
+ ,
6384
+ 4
6385
+ ]);
6163
6386
  return [
6164
6387
  4,
6165
6388
  this.playSingleAd(first)
6166
6389
  ];
6167
- case 1:
6390
+ case 2:
6168
6391
  _state.sent();
6169
6392
  this.inAdBreak = true;
6170
6393
  this.expectedAdBreakDurationMs = remainingMs;
6171
6394
  this.currentAdBreakStartWallClockMs = Date.now();
6172
6395
  this.scheduleAdStopCountdown(remainingMs);
6173
- _state.label = 2;
6174
- case 2:
6396
+ return [
6397
+ 3,
6398
+ 4
6399
+ ];
6400
+ case 3:
6401
+ error = _state.sent();
6402
+ this.adPodQueue = [];
6403
+ if (this.config.debugAdTiming) {
6404
+ console.warn("[StormcloudVideoPlayer] Mid-roll VMAP ad request failed:", error);
6405
+ }
6406
+ return [
6407
+ 3,
6408
+ 4
6409
+ ];
6410
+ case 4:
6175
6411
  return [
6176
6412
  2
6177
6413
  ];
@@ -6487,8 +6723,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6487
6723
  case 5:
6488
6724
  _state.sent();
6489
6725
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
6490
- this.currentAdBreakStartWallClockMs = Date.now();
6491
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
6726
+ this.scheduleAdStopCountdown(this.getRemainingAdMs());
6492
6727
  }
6493
6728
  currentMuted = this.video.muted;
6494
6729
  currentVolume = this.video.volume;
@@ -6538,8 +6773,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6538
6773
  case 8:
6539
6774
  _state.sent();
6540
6775
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
6541
- this.currentAdBreakStartWallClockMs = Date.now();
6542
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
6776
+ this.scheduleAdStopCountdown(this.getRemainingAdMs());
6543
6777
  }
6544
6778
  currentMuted1 = this.video.muted;
6545
6779
  currentVolume1 = this.video.volume;
@@ -6877,13 +7111,22 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6877
7111
  {
6878
7112
  key: "findBreakForTime",
6879
7113
  value: function findBreakForTime(nowMs) {
6880
- var schedule = [];
7114
+ var _this_config_driftToleranceMs;
7115
+ var schedule = this.vmapBreaks;
7116
+ var tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
6881
7117
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
6882
7118
  try {
6883
7119
  for(var _iterator = schedule[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
6884
7120
  var b = _step.value;
6885
- var end = (b.startTimeMs || 0) + (b.durationMs || 0);
6886
- if (nowMs >= (b.startTimeMs || 0) && (b.durationMs ? nowMs < end : true)) {
7121
+ if (this.consumedVmapBreakIds.has(this.getAdBreakKey(b))) {
7122
+ continue;
7123
+ }
7124
+ var breakStartMs = this.resolveBreakStartMs(b);
7125
+ if (breakStartMs == null) {
7126
+ continue;
7127
+ }
7128
+ var end = breakStartMs + (b.durationMs || 0);
7129
+ if (nowMs >= breakStartMs && (b.durationMs ? nowMs < end : nowMs <= breakStartMs + tol)) {
6887
7130
  return b;
6888
7131
  }
6889
7132
  }