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,5 +1,5 @@
1
1
  import { Component } from 'react';
2
- import { S as StormcloudVideoPlayerConfig } from '../types-C23mJ_hh.cjs';
2
+ import { S as StormcloudVideoPlayerConfig } from '../types-Vj55FghO.cjs';
3
3
 
4
4
  interface HlsPlayerProps extends StormcloudVideoPlayerConfig {
5
5
  onMount?: (player: any) => void;
@@ -742,7 +742,7 @@ function createImaController(video, options) {
742
742
  adVideo.style.height = "100%";
743
743
  adVideo.style.objectFit = "contain";
744
744
  adVideo.style.backgroundColor = "transparent";
745
- adVideo.style.zIndex = "15";
745
+ adVideo.style.zIndex = "2";
746
746
  adVideo.playsInline = true;
747
747
  adVideo.volume = originalVolume;
748
748
  adVideo.muted = originalMutedState;
@@ -1035,7 +1035,7 @@ function createImaController(video, options) {
1035
1035
  container.style.alignItems = "center";
1036
1036
  container.style.justifyContent = "center";
1037
1037
  container.style.pointerEvents = "none";
1038
- container.style.zIndex = "10";
1038
+ container.style.zIndex = "30";
1039
1039
  container.style.backgroundColor = "#000";
1040
1040
  container.style.transition = "opacity 0.3s ease-in-out";
1041
1041
  container.style.opacity = "0";
@@ -1150,7 +1150,7 @@ function createImaController(video, options) {
1150
1150
  container.style.alignItems = "center";
1151
1151
  container.style.justifyContent = "center";
1152
1152
  container.style.pointerEvents = "none";
1153
- container.style.zIndex = "10";
1153
+ container.style.zIndex = "30";
1154
1154
  container.style.backgroundColor = "transparent";
1155
1155
  container.style.transition = "opacity 0.3s ease-in-out, background-color 0.3s ease-in-out";
1156
1156
  container.style.opacity = "0";
@@ -2065,7 +2065,7 @@ function createHlsAdPlayer(contentVideo, options) {
2065
2065
  container.style.alignItems = "center";
2066
2066
  container.style.justifyContent = "center";
2067
2067
  container.style.pointerEvents = "none";
2068
- container.style.zIndex = "10";
2068
+ container.style.zIndex = "30";
2069
2069
  container.style.backgroundColor = "#000";
2070
2070
  (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
2071
2071
  adContainerEl = container;
@@ -3289,6 +3289,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3289
3289
  this.inAdBreak = false;
3290
3290
  this.ptsDriftEmaMs = 0;
3291
3291
  this.adPodQueue = [];
3292
+ this.vmapBreaks = [];
3293
+ this.consumedVmapBreakIds = /* @__PURE__ */ new Set();
3292
3294
  this.lastHeartbeatTime = 0;
3293
3295
  this.currentAdIndex = 0;
3294
3296
  this.totalAdsInBreak = 0;
@@ -3843,13 +3845,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3843
3845
  _this.activeAdRequestToken = null;
3844
3846
  _this.showAds = true;
3845
3847
  _this.resetGamNoFillCounter();
3846
- if (_this.inAdBreak && _this.expectedAdBreakDurationMs != null) {
3847
- if (_this.adStopTimerId == null) {
3848
- _this.currentAdBreakStartWallClockMs = Date.now();
3849
- _this.scheduleAdStopCountdown(_this.expectedAdBreakDurationMs);
3850
- if (_this.config.debugAdTiming) {
3851
- console.log("[StormcloudVideoPlayer] Starting ad break timer on content_pause (first ad starting)");
3852
- }
3848
+ if (_this.inAdBreak && _this.expectedAdBreakDurationMs != null && _this.adStopTimerId == null) {
3849
+ _this.scheduleAdStopCountdown(_this.getRemainingAdMs());
3850
+ if (_this.config.debugAdTiming) {
3851
+ console.log("[StormcloudVideoPlayer] Starting ad break timer on content_pause (first ad starting)");
3853
3852
  }
3854
3853
  }
3855
3854
  var currentMuted = _this.video.muted;
@@ -3912,6 +3911,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3912
3911
  this.ima.showPlaceholder();
3913
3912
  this.isShowingPlaceholder = true;
3914
3913
  }
3914
+ var preservedMutedState = this.ima.getOriginalMutedState();
3915
+ var preservedVolumeState = this.ima.getOriginalVolume();
3915
3916
  if (this.ima) {
3916
3917
  try {
3917
3918
  this.ima.destroy();
@@ -3926,7 +3927,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3926
3927
  var continueLiveStreamDuringAds = this.shouldContinueLiveStreamDuringAds();
3927
3928
  this.ima = this.createAdPlayer(continueLiveStreamDuringAds);
3928
3929
  this.ima.initialize();
3929
- this.ima.updateOriginalMutedState(this.video.muted, this.video.volume);
3930
+ this.ima.updateOriginalMutedState(preservedMutedState, preservedVolumeState);
3930
3931
  this.attachImaEventListeners();
3931
3932
  if (shouldShowPlaceholder) {
3932
3933
  this.showPlaceholderLayer();
@@ -4242,12 +4243,17 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4242
4243
  }
4243
4244
  }
4244
4245
  if (this.inAdBreak) {
4245
- if (this.expectedAdBreakDurationMs == null && marker.durationSeconds != null) {
4246
- this.expectedAdBreakDurationMs = marker.durationSeconds * 1e3;
4247
- if (this.config.debugAdTiming) {
4248
- console.log("[StormcloudVideoPlayer] Updated ad break duration from subsequent marker: ".concat(this.expectedAdBreakDurationMs, "ms"));
4246
+ if (marker.durationSeconds != null) {
4247
+ var newDurationMs = marker.durationSeconds * 1e3;
4248
+ if (this.expectedAdBreakDurationMs == null || newDurationMs > this.expectedAdBreakDurationMs) {
4249
+ this.expectedAdBreakDurationMs = newDurationMs;
4250
+ var elapsedMs = this.currentAdBreakStartWallClockMs != null ? Date.now() - this.currentAdBreakStartWallClockMs : 0;
4251
+ var remainingMs = Math.max(0, newDurationMs - elapsedMs);
4252
+ this.scheduleAdStopCountdown(remainingMs);
4253
+ if (this.config.debugAdTiming) {
4254
+ console.log("[StormcloudVideoPlayer] Updated ad break duration from subsequent marker: ".concat(newDurationMs, "ms, remaining: ").concat(remainingMs, "ms"));
4255
+ }
4249
4256
  }
4250
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
4251
4257
  }
4252
4258
  return;
4253
4259
  }
@@ -4323,9 +4329,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4323
4329
  this.expectedAdBreakDurationMs = marker.durationSeconds * 1e3;
4324
4330
  }
4325
4331
  if (this.expectedAdBreakDurationMs != null && this.currentAdBreakStartWallClockMs != null) {
4326
- var elapsedMs = Date.now() - this.currentAdBreakStartWallClockMs;
4327
- var remainingMs = Math.max(0, this.expectedAdBreakDurationMs - elapsedMs);
4328
- this.scheduleAdStopCountdown(remainingMs);
4332
+ var elapsedMs1 = Date.now() - this.currentAdBreakStartWallClockMs;
4333
+ var remainingMs1 = Math.max(0, this.expectedAdBreakDurationMs - elapsedMs1);
4334
+ this.scheduleAdStopCountdown(remainingMs1);
4329
4335
  }
4330
4336
  if (!this.ima.isAdPlaying() && this.activeAdRequestToken === null && this.adRequestQueue.length > 0) {
4331
4337
  this.tryNextAvailableAdWithRateLimit();
@@ -4617,6 +4623,18 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4617
4623
  return _ts_generator(this, function(_state) {
4618
4624
  switch(_state.label){
4619
4625
  case 0:
4626
+ if (!this.config.vmapUrl) return [
4627
+ 3,
4628
+ 2
4629
+ ];
4630
+ return [
4631
+ 4,
4632
+ this.fetchAndParseVmap(this.config.vmapUrl)
4633
+ ];
4634
+ case 1:
4635
+ _state.sent();
4636
+ _state.label = 2;
4637
+ case 2:
4620
4638
  vastMode = this.config.vastMode || "default";
4621
4639
  if (this.config.debugAdTiming) {
4622
4640
  console.log("[StormcloudVideoPlayer] VAST mode:", vastMode);
@@ -4662,7 +4680,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4662
4680
  headers: headers
4663
4681
  })
4664
4682
  ];
4665
- case 1:
4683
+ case 3:
4666
4684
  response = _state.sent();
4667
4685
  if (!response.ok) {
4668
4686
  if (this.config.debugAdTiming) {
@@ -4676,7 +4694,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4676
4694
  4,
4677
4695
  response.json()
4678
4696
  ];
4679
- case 2:
4697
+ case 4:
4680
4698
  data = _state.sent();
4681
4699
  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;
4682
4700
  if (imaPayload) {
@@ -4704,6 +4722,171 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4704
4722
  }).call(this);
4705
4723
  }
4706
4724
  },
4725
+ {
4726
+ key: "fetchAndParseVmap",
4727
+ value: function fetchAndParseVmap(vmapUrl) {
4728
+ return _async_to_generator(function() {
4729
+ var response, vmapXml, error;
4730
+ return _ts_generator(this, function(_state) {
4731
+ switch(_state.label){
4732
+ case 0:
4733
+ if (!vmapUrl.trim()) {
4734
+ return [
4735
+ 2
4736
+ ];
4737
+ }
4738
+ _state.label = 1;
4739
+ case 1:
4740
+ _state.trys.push([
4741
+ 1,
4742
+ 4,
4743
+ ,
4744
+ 5
4745
+ ]);
4746
+ return [
4747
+ 4,
4748
+ fetch(vmapUrl)
4749
+ ];
4750
+ case 2:
4751
+ response = _state.sent();
4752
+ if (!response.ok) {
4753
+ throw new Error("Failed to fetch VMAP (".concat(response.status, ")"));
4754
+ }
4755
+ return [
4756
+ 4,
4757
+ response.text()
4758
+ ];
4759
+ case 3:
4760
+ vmapXml = _state.sent();
4761
+ this.vmapBreaks = this.parseVmapToBreaks(vmapXml);
4762
+ this.consumedVmapBreakIds.clear();
4763
+ if (this.config.debugAdTiming) {
4764
+ console.log("[StormcloudVideoPlayer] Loaded ".concat(this.vmapBreaks.length, " VMAP ad break(s) from:"), vmapUrl);
4765
+ }
4766
+ return [
4767
+ 3,
4768
+ 5
4769
+ ];
4770
+ case 4:
4771
+ error = _state.sent();
4772
+ this.vmapBreaks = [];
4773
+ this.consumedVmapBreakIds.clear();
4774
+ if (this.config.debugAdTiming) {
4775
+ console.warn("[StormcloudVideoPlayer] Failed to load VMAP:", error);
4776
+ }
4777
+ return [
4778
+ 3,
4779
+ 5
4780
+ ];
4781
+ case 5:
4782
+ return [
4783
+ 2
4784
+ ];
4785
+ }
4786
+ });
4787
+ }).call(this);
4788
+ }
4789
+ },
4790
+ {
4791
+ key: "parseVmapToBreaks",
4792
+ value: function parseVmapToBreaks(vmapXml) {
4793
+ var _this = this;
4794
+ if (typeof DOMParser === "undefined") {
4795
+ return [];
4796
+ }
4797
+ var doc = new DOMParser().parseFromString(vmapXml, "application/xml");
4798
+ if (doc.querySelector("parsererror")) {
4799
+ if (this.config.debugAdTiming) {
4800
+ console.warn("[StormcloudVideoPlayer] Invalid VMAP XML received");
4801
+ }
4802
+ return [];
4803
+ }
4804
+ var adBreakNodes = Array.from(doc.querySelectorAll("AdBreak, vmap\\:AdBreak"));
4805
+ var parsed = [];
4806
+ adBreakNodes.forEach(function(node, index) {
4807
+ var timeOffsetRaw = (node.getAttribute("timeOffset") || "").trim();
4808
+ var startTimeMs = _this.parseVmapTimeOffsetToMs(timeOffsetRaw);
4809
+ if (startTimeMs == null) {
4810
+ return;
4811
+ }
4812
+ var adTagNode = node.querySelector("AdTagURI, vmap\\:AdTagURI");
4813
+ var adTagUrl = ((adTagNode === null || adTagNode === void 0 ? void 0 : adTagNode.textContent) || "").trim();
4814
+ if (!adTagUrl) {
4815
+ return;
4816
+ }
4817
+ var breakId = node.getAttribute("breakId") || "vmap-break-".concat(index, "-").concat(timeOffsetRaw || "unknown");
4818
+ parsed.push({
4819
+ id: breakId,
4820
+ startTimeMs: startTimeMs,
4821
+ vastTagUrl: adTagUrl
4822
+ });
4823
+ });
4824
+ parsed.sort(function(a, b) {
4825
+ var aStart = a.startTimeMs < 0 ? Number.MAX_SAFE_INTEGER : a.startTimeMs;
4826
+ var bStart = b.startTimeMs < 0 ? Number.MAX_SAFE_INTEGER : b.startTimeMs;
4827
+ return aStart - bStart;
4828
+ });
4829
+ return parsed;
4830
+ }
4831
+ },
4832
+ {
4833
+ key: "parseVmapTimeOffsetToMs",
4834
+ value: function parseVmapTimeOffsetToMs(timeOffset) {
4835
+ if (!timeOffset) {
4836
+ return void 0;
4837
+ }
4838
+ var normalized = timeOffset.trim().toLowerCase();
4839
+ if (normalized === "start") {
4840
+ return 0;
4841
+ }
4842
+ if (normalized === "end") {
4843
+ return -1;
4844
+ }
4845
+ var hms = timeOffset.match(/^(\d{1,2}):(\d{2}):(\d{2})(?:\.(\d{1,3}))?$/);
4846
+ if (hms) {
4847
+ 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;
4848
+ var hours = Number(hh);
4849
+ var minutes = Number(mm);
4850
+ var seconds = Number(ss);
4851
+ var millis = Number(ms.padEnd(3, "0").slice(0, 3));
4852
+ return (hours * 3600 + minutes * 60 + seconds) * 1e3 + millis;
4853
+ }
4854
+ var percent = timeOffset.match(/^(\d+(?:\.\d+)?)%$/);
4855
+ if (percent) {
4856
+ var ratio = Number(percent[1]) / 100;
4857
+ var durationSec = this.video.duration;
4858
+ if (Number.isFinite(durationSec) && durationSec > 0) {
4859
+ return Math.floor(durationSec * 1e3 * ratio);
4860
+ }
4861
+ return void 0;
4862
+ }
4863
+ return void 0;
4864
+ }
4865
+ },
4866
+ {
4867
+ key: "getAdBreakKey",
4868
+ value: function getAdBreakKey(adBreak) {
4869
+ if (adBreak.id) {
4870
+ return adBreak.id;
4871
+ }
4872
+ return "".concat(adBreak.startTimeMs, "-").concat(adBreak.vastTagUrl || "");
4873
+ }
4874
+ },
4875
+ {
4876
+ key: "resolveBreakStartMs",
4877
+ value: function resolveBreakStartMs(adBreak) {
4878
+ if (adBreak.startTimeMs >= 0) {
4879
+ return adBreak.startTimeMs;
4880
+ }
4881
+ if (adBreak.startTimeMs === -1) {
4882
+ var durationSec = this.video.duration;
4883
+ if (Number.isFinite(durationSec) && durationSec > 0) {
4884
+ return Math.floor(durationSec * 1e3);
4885
+ }
4886
+ }
4887
+ return void 0;
4888
+ }
4889
+ },
4707
4890
  {
4708
4891
  key: "getCurrentAdIndex",
4709
4892
  value: function getCurrentAdIndex() {
@@ -4716,6 +4899,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4716
4899
  return this.totalAdsInBreak;
4717
4900
  }
4718
4901
  },
4902
+ {
4903
+ key: "getAdRemainingMs",
4904
+ value: function getAdRemainingMs() {
4905
+ return this.getRemainingAdMs();
4906
+ }
4907
+ },
4719
4908
  {
4720
4909
  key: "generateVastUrlsWithCorrelators",
4721
4910
  value: function generateVastUrlsWithCorrelators(baseUrl, count) {
@@ -4794,10 +4983,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4794
4983
  var scheduled = this.findCurrentOrNextBreak(this.video.currentTime * 1e3);
4795
4984
  var tags = this.selectVastTagsForBreak(scheduled);
4796
4985
  var baseVastUrl;
4797
- if (this.apiVastTagUrl) {
4798
- baseVastUrl = this.apiVastTagUrl;
4799
- } else if (tags && tags.length > 0 && tags[0]) {
4986
+ if (tags && tags.length > 0 && tags[0]) {
4800
4987
  baseVastUrl = tags[0];
4988
+ } else if (this.apiVastTagUrl) {
4989
+ baseVastUrl = this.apiVastTagUrl;
4801
4990
  } else {
4802
4991
  if (this.config.debugAdTiming) {
4803
4992
  console.warn("[StormcloudVideoPlayer] No VAST URL available for prefetch");
@@ -5247,11 +5436,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5247
5436
  switch(_state.label){
5248
5437
  case 0:
5249
5438
  scheduled = this.findCurrentOrNextBreak(this.video.currentTime * 1e3);
5439
+ if (scheduled) {
5440
+ this.consumedVmapBreakIds.add(this.getAdBreakKey(scheduled));
5441
+ }
5250
5442
  tags = this.selectVastTagsForBreak(scheduled);
5251
- if (this.apiVastTagUrl) {
5252
- baseVastUrl = this.apiVastTagUrl;
5253
- } else if (tags && tags.length > 0 && tags[0]) {
5443
+ if (tags && tags.length > 0 && tags[0]) {
5254
5444
  baseVastUrl = tags[0];
5445
+ } else if (this.apiVastTagUrl) {
5446
+ baseVastUrl = this.apiVastTagUrl;
5255
5447
  } else {
5256
5448
  this.clearPendingAdBreak();
5257
5449
  return [
@@ -5365,9 +5557,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5365
5557
  ];
5366
5558
  case 2:
5367
5559
  _state.sent();
5368
- if (this.expectedAdBreakDurationMs != null) {
5369
- this.currentAdBreakStartWallClockMs = Date.now();
5370
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
5560
+ if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
5561
+ this.scheduleAdStopCountdown(this.getRemainingAdMs());
5371
5562
  }
5372
5563
  adVolume = currentMuted ? 0 : currentVolume;
5373
5564
  this.ima.setAdVolume(adVolume);
@@ -5408,9 +5599,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5408
5599
  ];
5409
5600
  case 6:
5410
5601
  _state.sent();
5411
- if (this.expectedAdBreakDurationMs != null) {
5412
- this.currentAdBreakStartWallClockMs = Date.now();
5413
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
5602
+ if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
5603
+ this.scheduleAdStopCountdown(this.getRemainingAdMs());
5414
5604
  }
5415
5605
  adVolume1 = currentMuted ? 0 : currentVolume;
5416
5606
  this.ima.setAdVolume(adVolume1);
@@ -5464,9 +5654,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5464
5654
  ];
5465
5655
  case 10:
5466
5656
  _state.sent();
5467
- if (this.expectedAdBreakDurationMs != null) {
5468
- this.currentAdBreakStartWallClockMs = Date.now();
5469
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
5657
+ if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
5658
+ this.scheduleAdStopCountdown(this.getRemainingAdMs());
5470
5659
  }
5471
5660
  adVolume2 = currentMuted ? 0 : currentVolume;
5472
5661
  this.ima.setAdVolume(adVolume2);
@@ -5817,8 +6006,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5817
6006
  case 2:
5818
6007
  _state.sent();
5819
6008
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
5820
- this.currentAdBreakStartWallClockMs = Date.now();
5821
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
6009
+ this.scheduleAdStopCountdown(this.getRemainingAdMs());
5822
6010
  }
5823
6011
  currentMuted = this.video.muted;
5824
6012
  currentVolume = this.video.volume;
@@ -6130,15 +6318,22 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6130
6318
  {
6131
6319
  key: "findCurrentOrNextBreak",
6132
6320
  value: function findCurrentOrNextBreak(nowMs) {
6133
- var schedule = [];
6321
+ var schedule = this.vmapBreaks;
6134
6322
  var candidate;
6135
6323
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
6136
6324
  try {
6137
6325
  for(var _iterator = schedule[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
6138
6326
  var b = _step.value;
6139
- var _this_config_driftToleranceMs;
6327
+ var _this_config_driftToleranceMs, _this_resolveBreakStartMs;
6328
+ if (this.consumedVmapBreakIds.has(this.getAdBreakKey(b))) {
6329
+ continue;
6330
+ }
6331
+ var breakStartMs = this.resolveBreakStartMs(b);
6332
+ if (breakStartMs == null) {
6333
+ continue;
6334
+ }
6140
6335
  var tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
6141
- if (b.startTimeMs <= nowMs + tol && (candidate == null || b.startTimeMs > (candidate.startTimeMs || 0))) {
6336
+ if (breakStartMs <= nowMs + tol && (candidate == null || breakStartMs > ((_this_resolveBreakStartMs = this.resolveBreakStartMs(candidate)) !== null && _this_resolveBreakStartMs !== void 0 ? _this_resolveBreakStartMs : 0))) {
6142
6337
  candidate = b;
6143
6338
  }
6144
6339
  }
@@ -6162,11 +6357,16 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6162
6357
  {
6163
6358
  key: "onTimeUpdate",
6164
6359
  value: function onTimeUpdate(currentTimeSec) {
6165
- if (this.ima.isAdPlaying()) return;
6360
+ var _this = this;
6361
+ if (this.ima.isAdPlaying() || this.inAdBreak) return;
6166
6362
  var nowMs = currentTimeSec * 1e3;
6167
6363
  var breakToPlay = this.findBreakForTime(nowMs);
6168
6364
  if (breakToPlay) {
6169
- this.handleMidAdJoin(breakToPlay, nowMs);
6365
+ void this.handleMidAdJoin(breakToPlay, nowMs).catch(function(error) {
6366
+ if (_this.config.debugAdTiming) {
6367
+ console.warn("[StormcloudVideoPlayer] Mid-roll VMAP join failed gracefully:", error);
6368
+ }
6369
+ });
6170
6370
  }
6171
6371
  }
6172
6372
  },
@@ -6174,40 +6374,76 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6174
6374
  key: "handleMidAdJoin",
6175
6375
  value: function handleMidAdJoin(adBreak, nowMs) {
6176
6376
  return _async_to_generator(function() {
6177
- var _adBreak_durationMs, durationMs, endMs, remainingMs, tags, first, rest;
6377
+ var _adBreak_durationMs, _this_config_driftToleranceMs, key, breakStartMs, durationMs, endMs, tol, inWindow, remainingMs, tags, first, rest, error;
6178
6378
  return _ts_generator(this, function(_state) {
6179
6379
  switch(_state.label){
6180
6380
  case 0:
6381
+ key = this.getAdBreakKey(adBreak);
6382
+ if (this.consumedVmapBreakIds.has(key)) {
6383
+ return [
6384
+ 2
6385
+ ];
6386
+ }
6387
+ breakStartMs = this.resolveBreakStartMs(adBreak);
6388
+ if (breakStartMs == null) {
6389
+ return [
6390
+ 2
6391
+ ];
6392
+ }
6181
6393
  durationMs = (_adBreak_durationMs = adBreak.durationMs) !== null && _adBreak_durationMs !== void 0 ? _adBreak_durationMs : 0;
6182
- endMs = adBreak.startTimeMs + durationMs;
6183
- if (!(durationMs > 0 && nowMs > adBreak.startTimeMs && nowMs < endMs)) return [
6394
+ endMs = breakStartMs + durationMs;
6395
+ tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
6396
+ inWindow = durationMs > 0 ? nowMs > breakStartMs && nowMs < endMs : nowMs + tol >= breakStartMs;
6397
+ if (!inWindow) return [
6184
6398
  3,
6185
- 2
6399
+ 4
6186
6400
  ];
6187
- remainingMs = endMs - nowMs;
6401
+ this.consumedVmapBreakIds.add(key);
6402
+ remainingMs = durationMs > 0 ? Math.max(0, endMs - nowMs) : 0;
6188
6403
  tags = this.selectVastTagsForBreak(adBreak) || (this.apiVastTagUrl ? [
6189
6404
  this.apiVastTagUrl
6190
6405
  ] : void 0);
6191
6406
  if (!(tags && tags.length > 0)) return [
6192
6407
  3,
6193
- 2
6408
+ 4
6194
6409
  ];
6195
6410
  first = tags[0];
6196
6411
  rest = tags.slice(1);
6197
6412
  this.adPodQueue = rest;
6198
6413
  this.ima.updateOriginalMutedState(this.video.muted, this.video.volume);
6414
+ _state.label = 1;
6415
+ case 1:
6416
+ _state.trys.push([
6417
+ 1,
6418
+ 3,
6419
+ ,
6420
+ 4
6421
+ ]);
6199
6422
  return [
6200
6423
  4,
6201
6424
  this.playSingleAd(first)
6202
6425
  ];
6203
- case 1:
6426
+ case 2:
6204
6427
  _state.sent();
6205
6428
  this.inAdBreak = true;
6206
6429
  this.expectedAdBreakDurationMs = remainingMs;
6207
6430
  this.currentAdBreakStartWallClockMs = Date.now();
6208
6431
  this.scheduleAdStopCountdown(remainingMs);
6209
- _state.label = 2;
6210
- case 2:
6432
+ return [
6433
+ 3,
6434
+ 4
6435
+ ];
6436
+ case 3:
6437
+ error = _state.sent();
6438
+ this.adPodQueue = [];
6439
+ if (this.config.debugAdTiming) {
6440
+ console.warn("[StormcloudVideoPlayer] Mid-roll VMAP ad request failed:", error);
6441
+ }
6442
+ return [
6443
+ 3,
6444
+ 4
6445
+ ];
6446
+ case 4:
6211
6447
  return [
6212
6448
  2
6213
6449
  ];
@@ -6523,8 +6759,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6523
6759
  case 5:
6524
6760
  _state.sent();
6525
6761
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
6526
- this.currentAdBreakStartWallClockMs = Date.now();
6527
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
6762
+ this.scheduleAdStopCountdown(this.getRemainingAdMs());
6528
6763
  }
6529
6764
  currentMuted = this.video.muted;
6530
6765
  currentVolume = this.video.volume;
@@ -6574,8 +6809,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6574
6809
  case 8:
6575
6810
  _state.sent();
6576
6811
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
6577
- this.currentAdBreakStartWallClockMs = Date.now();
6578
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
6812
+ this.scheduleAdStopCountdown(this.getRemainingAdMs());
6579
6813
  }
6580
6814
  currentMuted1 = this.video.muted;
6581
6815
  currentVolume1 = this.video.volume;
@@ -6913,13 +7147,22 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6913
7147
  {
6914
7148
  key: "findBreakForTime",
6915
7149
  value: function findBreakForTime(nowMs) {
6916
- var schedule = [];
7150
+ var _this_config_driftToleranceMs;
7151
+ var schedule = this.vmapBreaks;
7152
+ var tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
6917
7153
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
6918
7154
  try {
6919
7155
  for(var _iterator = schedule[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
6920
7156
  var b = _step.value;
6921
- var end = (b.startTimeMs || 0) + (b.durationMs || 0);
6922
- if (nowMs >= (b.startTimeMs || 0) && (b.durationMs ? nowMs < end : true)) {
7157
+ if (this.consumedVmapBreakIds.has(this.getAdBreakKey(b))) {
7158
+ continue;
7159
+ }
7160
+ var breakStartMs = this.resolveBreakStartMs(b);
7161
+ if (breakStartMs == null) {
7162
+ continue;
7163
+ }
7164
+ var end = breakStartMs + (b.durationMs || 0);
7165
+ if (nowMs >= breakStartMs && (b.durationMs ? nowMs < end : nowMs <= breakStartMs + tol)) {
6923
7166
  return b;
6924
7167
  }
6925
7168
  }