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.
package/lib/index.js CHANGED
@@ -705,7 +705,7 @@ function createImaController(video, options) {
705
705
  adVideo.style.height = "100%";
706
706
  adVideo.style.objectFit = "contain";
707
707
  adVideo.style.backgroundColor = "transparent";
708
- adVideo.style.zIndex = "15";
708
+ adVideo.style.zIndex = "2";
709
709
  adVideo.playsInline = true;
710
710
  adVideo.volume = originalVolume;
711
711
  adVideo.muted = originalMutedState;
@@ -998,7 +998,7 @@ function createImaController(video, options) {
998
998
  container.style.alignItems = "center";
999
999
  container.style.justifyContent = "center";
1000
1000
  container.style.pointerEvents = "none";
1001
- container.style.zIndex = "10";
1001
+ container.style.zIndex = "30";
1002
1002
  container.style.backgroundColor = "#000";
1003
1003
  container.style.transition = "opacity 0.3s ease-in-out";
1004
1004
  container.style.opacity = "0";
@@ -1113,7 +1113,7 @@ function createImaController(video, options) {
1113
1113
  container.style.alignItems = "center";
1114
1114
  container.style.justifyContent = "center";
1115
1115
  container.style.pointerEvents = "none";
1116
- container.style.zIndex = "10";
1116
+ container.style.zIndex = "30";
1117
1117
  container.style.backgroundColor = "transparent";
1118
1118
  container.style.transition = "opacity 0.3s ease-in-out, background-color 0.3s ease-in-out";
1119
1119
  container.style.opacity = "0";
@@ -2028,7 +2028,7 @@ function createHlsAdPlayer(contentVideo, options) {
2028
2028
  container.style.alignItems = "center";
2029
2029
  container.style.justifyContent = "center";
2030
2030
  container.style.pointerEvents = "none";
2031
- container.style.zIndex = "10";
2031
+ container.style.zIndex = "30";
2032
2032
  container.style.backgroundColor = "#000";
2033
2033
  (_contentVideo_parentElement = contentVideo.parentElement) === null || _contentVideo_parentElement === void 0 ? void 0 : _contentVideo_parentElement.appendChild(container);
2034
2034
  adContainerEl = container;
@@ -3255,6 +3255,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3255
3255
  this.inAdBreak = false;
3256
3256
  this.ptsDriftEmaMs = 0;
3257
3257
  this.adPodQueue = [];
3258
+ this.vmapBreaks = [];
3259
+ this.consumedVmapBreakIds = /* @__PURE__ */ new Set();
3258
3260
  this.lastHeartbeatTime = 0;
3259
3261
  this.currentAdIndex = 0;
3260
3262
  this.totalAdsInBreak = 0;
@@ -3809,13 +3811,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3809
3811
  _this.activeAdRequestToken = null;
3810
3812
  _this.showAds = true;
3811
3813
  _this.resetGamNoFillCounter();
3812
- if (_this.inAdBreak && _this.expectedAdBreakDurationMs != null) {
3813
- if (_this.adStopTimerId == null) {
3814
- _this.currentAdBreakStartWallClockMs = Date.now();
3815
- _this.scheduleAdStopCountdown(_this.expectedAdBreakDurationMs);
3816
- if (_this.config.debugAdTiming) {
3817
- console.log("[StormcloudVideoPlayer] Starting ad break timer on content_pause (first ad starting)");
3818
- }
3814
+ if (_this.inAdBreak && _this.expectedAdBreakDurationMs != null && _this.adStopTimerId == null) {
3815
+ _this.scheduleAdStopCountdown(_this.getRemainingAdMs());
3816
+ if (_this.config.debugAdTiming) {
3817
+ console.log("[StormcloudVideoPlayer] Starting ad break timer on content_pause (first ad starting)");
3819
3818
  }
3820
3819
  }
3821
3820
  var currentMuted = _this.video.muted;
@@ -3878,6 +3877,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3878
3877
  this.ima.showPlaceholder();
3879
3878
  this.isShowingPlaceholder = true;
3880
3879
  }
3880
+ var preservedMutedState = this.ima.getOriginalMutedState();
3881
+ var preservedVolumeState = this.ima.getOriginalVolume();
3881
3882
  if (this.ima) {
3882
3883
  try {
3883
3884
  this.ima.destroy();
@@ -3892,7 +3893,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3892
3893
  var continueLiveStreamDuringAds = this.shouldContinueLiveStreamDuringAds();
3893
3894
  this.ima = this.createAdPlayer(continueLiveStreamDuringAds);
3894
3895
  this.ima.initialize();
3895
- this.ima.updateOriginalMutedState(this.video.muted, this.video.volume);
3896
+ this.ima.updateOriginalMutedState(preservedMutedState, preservedVolumeState);
3896
3897
  this.attachImaEventListeners();
3897
3898
  if (shouldShowPlaceholder) {
3898
3899
  this.showPlaceholderLayer();
@@ -4208,12 +4209,17 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4208
4209
  }
4209
4210
  }
4210
4211
  if (this.inAdBreak) {
4211
- if (this.expectedAdBreakDurationMs == null && marker.durationSeconds != null) {
4212
- this.expectedAdBreakDurationMs = marker.durationSeconds * 1e3;
4213
- if (this.config.debugAdTiming) {
4214
- console.log("[StormcloudVideoPlayer] Updated ad break duration from subsequent marker: ".concat(this.expectedAdBreakDurationMs, "ms"));
4212
+ if (marker.durationSeconds != null) {
4213
+ var newDurationMs = marker.durationSeconds * 1e3;
4214
+ if (this.expectedAdBreakDurationMs == null || newDurationMs > this.expectedAdBreakDurationMs) {
4215
+ this.expectedAdBreakDurationMs = newDurationMs;
4216
+ var elapsedMs = this.currentAdBreakStartWallClockMs != null ? Date.now() - this.currentAdBreakStartWallClockMs : 0;
4217
+ var remainingMs = Math.max(0, newDurationMs - elapsedMs);
4218
+ this.scheduleAdStopCountdown(remainingMs);
4219
+ if (this.config.debugAdTiming) {
4220
+ console.log("[StormcloudVideoPlayer] Updated ad break duration from subsequent marker: ".concat(newDurationMs, "ms, remaining: ").concat(remainingMs, "ms"));
4221
+ }
4215
4222
  }
4216
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
4217
4223
  }
4218
4224
  return;
4219
4225
  }
@@ -4289,9 +4295,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4289
4295
  this.expectedAdBreakDurationMs = marker.durationSeconds * 1e3;
4290
4296
  }
4291
4297
  if (this.expectedAdBreakDurationMs != null && this.currentAdBreakStartWallClockMs != null) {
4292
- var elapsedMs = Date.now() - this.currentAdBreakStartWallClockMs;
4293
- var remainingMs = Math.max(0, this.expectedAdBreakDurationMs - elapsedMs);
4294
- this.scheduleAdStopCountdown(remainingMs);
4298
+ var elapsedMs1 = Date.now() - this.currentAdBreakStartWallClockMs;
4299
+ var remainingMs1 = Math.max(0, this.expectedAdBreakDurationMs - elapsedMs1);
4300
+ this.scheduleAdStopCountdown(remainingMs1);
4295
4301
  }
4296
4302
  if (!this.ima.isAdPlaying() && this.activeAdRequestToken === null && this.adRequestQueue.length > 0) {
4297
4303
  this.tryNextAvailableAdWithRateLimit();
@@ -4583,6 +4589,18 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4583
4589
  return _ts_generator(this, function(_state) {
4584
4590
  switch(_state.label){
4585
4591
  case 0:
4592
+ if (!this.config.vmapUrl) return [
4593
+ 3,
4594
+ 2
4595
+ ];
4596
+ return [
4597
+ 4,
4598
+ this.fetchAndParseVmap(this.config.vmapUrl)
4599
+ ];
4600
+ case 1:
4601
+ _state.sent();
4602
+ _state.label = 2;
4603
+ case 2:
4586
4604
  vastMode = this.config.vastMode || "default";
4587
4605
  if (this.config.debugAdTiming) {
4588
4606
  console.log("[StormcloudVideoPlayer] VAST mode:", vastMode);
@@ -4628,7 +4646,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4628
4646
  headers: headers
4629
4647
  })
4630
4648
  ];
4631
- case 1:
4649
+ case 3:
4632
4650
  response = _state.sent();
4633
4651
  if (!response.ok) {
4634
4652
  if (this.config.debugAdTiming) {
@@ -4642,7 +4660,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4642
4660
  4,
4643
4661
  response.json()
4644
4662
  ];
4645
- case 2:
4663
+ case 4:
4646
4664
  data = _state.sent();
4647
4665
  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;
4648
4666
  if (imaPayload) {
@@ -4670,6 +4688,171 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4670
4688
  }).call(this);
4671
4689
  }
4672
4690
  },
4691
+ {
4692
+ key: "fetchAndParseVmap",
4693
+ value: function fetchAndParseVmap(vmapUrl) {
4694
+ return _async_to_generator(function() {
4695
+ var response, vmapXml, error;
4696
+ return _ts_generator(this, function(_state) {
4697
+ switch(_state.label){
4698
+ case 0:
4699
+ if (!vmapUrl.trim()) {
4700
+ return [
4701
+ 2
4702
+ ];
4703
+ }
4704
+ _state.label = 1;
4705
+ case 1:
4706
+ _state.trys.push([
4707
+ 1,
4708
+ 4,
4709
+ ,
4710
+ 5
4711
+ ]);
4712
+ return [
4713
+ 4,
4714
+ fetch(vmapUrl)
4715
+ ];
4716
+ case 2:
4717
+ response = _state.sent();
4718
+ if (!response.ok) {
4719
+ throw new Error("Failed to fetch VMAP (".concat(response.status, ")"));
4720
+ }
4721
+ return [
4722
+ 4,
4723
+ response.text()
4724
+ ];
4725
+ case 3:
4726
+ vmapXml = _state.sent();
4727
+ this.vmapBreaks = this.parseVmapToBreaks(vmapXml);
4728
+ this.consumedVmapBreakIds.clear();
4729
+ if (this.config.debugAdTiming) {
4730
+ console.log("[StormcloudVideoPlayer] Loaded ".concat(this.vmapBreaks.length, " VMAP ad break(s) from:"), vmapUrl);
4731
+ }
4732
+ return [
4733
+ 3,
4734
+ 5
4735
+ ];
4736
+ case 4:
4737
+ error = _state.sent();
4738
+ this.vmapBreaks = [];
4739
+ this.consumedVmapBreakIds.clear();
4740
+ if (this.config.debugAdTiming) {
4741
+ console.warn("[StormcloudVideoPlayer] Failed to load VMAP:", error);
4742
+ }
4743
+ return [
4744
+ 3,
4745
+ 5
4746
+ ];
4747
+ case 5:
4748
+ return [
4749
+ 2
4750
+ ];
4751
+ }
4752
+ });
4753
+ }).call(this);
4754
+ }
4755
+ },
4756
+ {
4757
+ key: "parseVmapToBreaks",
4758
+ value: function parseVmapToBreaks(vmapXml) {
4759
+ var _this = this;
4760
+ if (typeof DOMParser === "undefined") {
4761
+ return [];
4762
+ }
4763
+ var doc = new DOMParser().parseFromString(vmapXml, "application/xml");
4764
+ if (doc.querySelector("parsererror")) {
4765
+ if (this.config.debugAdTiming) {
4766
+ console.warn("[StormcloudVideoPlayer] Invalid VMAP XML received");
4767
+ }
4768
+ return [];
4769
+ }
4770
+ var adBreakNodes = Array.from(doc.querySelectorAll("AdBreak, vmap\\:AdBreak"));
4771
+ var parsed = [];
4772
+ adBreakNodes.forEach(function(node, index) {
4773
+ var timeOffsetRaw = (node.getAttribute("timeOffset") || "").trim();
4774
+ var startTimeMs = _this.parseVmapTimeOffsetToMs(timeOffsetRaw);
4775
+ if (startTimeMs == null) {
4776
+ return;
4777
+ }
4778
+ var adTagNode = node.querySelector("AdTagURI, vmap\\:AdTagURI");
4779
+ var adTagUrl = ((adTagNode === null || adTagNode === void 0 ? void 0 : adTagNode.textContent) || "").trim();
4780
+ if (!adTagUrl) {
4781
+ return;
4782
+ }
4783
+ var breakId = node.getAttribute("breakId") || "vmap-break-".concat(index, "-").concat(timeOffsetRaw || "unknown");
4784
+ parsed.push({
4785
+ id: breakId,
4786
+ startTimeMs: startTimeMs,
4787
+ vastTagUrl: adTagUrl
4788
+ });
4789
+ });
4790
+ parsed.sort(function(a, b) {
4791
+ var aStart = a.startTimeMs < 0 ? Number.MAX_SAFE_INTEGER : a.startTimeMs;
4792
+ var bStart = b.startTimeMs < 0 ? Number.MAX_SAFE_INTEGER : b.startTimeMs;
4793
+ return aStart - bStart;
4794
+ });
4795
+ return parsed;
4796
+ }
4797
+ },
4798
+ {
4799
+ key: "parseVmapTimeOffsetToMs",
4800
+ value: function parseVmapTimeOffsetToMs(timeOffset) {
4801
+ if (!timeOffset) {
4802
+ return void 0;
4803
+ }
4804
+ var normalized = timeOffset.trim().toLowerCase();
4805
+ if (normalized === "start") {
4806
+ return 0;
4807
+ }
4808
+ if (normalized === "end") {
4809
+ return -1;
4810
+ }
4811
+ var hms = timeOffset.match(/^(\d{1,2}):(\d{2}):(\d{2})(?:\.(\d{1,3}))?$/);
4812
+ if (hms) {
4813
+ 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;
4814
+ var hours = Number(hh);
4815
+ var minutes = Number(mm);
4816
+ var seconds = Number(ss);
4817
+ var millis = Number(ms.padEnd(3, "0").slice(0, 3));
4818
+ return (hours * 3600 + minutes * 60 + seconds) * 1e3 + millis;
4819
+ }
4820
+ var percent = timeOffset.match(/^(\d+(?:\.\d+)?)%$/);
4821
+ if (percent) {
4822
+ var ratio = Number(percent[1]) / 100;
4823
+ var durationSec = this.video.duration;
4824
+ if (Number.isFinite(durationSec) && durationSec > 0) {
4825
+ return Math.floor(durationSec * 1e3 * ratio);
4826
+ }
4827
+ return void 0;
4828
+ }
4829
+ return void 0;
4830
+ }
4831
+ },
4832
+ {
4833
+ key: "getAdBreakKey",
4834
+ value: function getAdBreakKey(adBreak) {
4835
+ if (adBreak.id) {
4836
+ return adBreak.id;
4837
+ }
4838
+ return "".concat(adBreak.startTimeMs, "-").concat(adBreak.vastTagUrl || "");
4839
+ }
4840
+ },
4841
+ {
4842
+ key: "resolveBreakStartMs",
4843
+ value: function resolveBreakStartMs(adBreak) {
4844
+ if (adBreak.startTimeMs >= 0) {
4845
+ return adBreak.startTimeMs;
4846
+ }
4847
+ if (adBreak.startTimeMs === -1) {
4848
+ var durationSec = this.video.duration;
4849
+ if (Number.isFinite(durationSec) && durationSec > 0) {
4850
+ return Math.floor(durationSec * 1e3);
4851
+ }
4852
+ }
4853
+ return void 0;
4854
+ }
4855
+ },
4673
4856
  {
4674
4857
  key: "getCurrentAdIndex",
4675
4858
  value: function getCurrentAdIndex() {
@@ -4682,6 +4865,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4682
4865
  return this.totalAdsInBreak;
4683
4866
  }
4684
4867
  },
4868
+ {
4869
+ key: "getAdRemainingMs",
4870
+ value: function getAdRemainingMs() {
4871
+ return this.getRemainingAdMs();
4872
+ }
4873
+ },
4685
4874
  {
4686
4875
  key: "generateVastUrlsWithCorrelators",
4687
4876
  value: function generateVastUrlsWithCorrelators(baseUrl, count) {
@@ -4760,10 +4949,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4760
4949
  var scheduled = this.findCurrentOrNextBreak(this.video.currentTime * 1e3);
4761
4950
  var tags = this.selectVastTagsForBreak(scheduled);
4762
4951
  var baseVastUrl;
4763
- if (this.apiVastTagUrl) {
4764
- baseVastUrl = this.apiVastTagUrl;
4765
- } else if (tags && tags.length > 0 && tags[0]) {
4952
+ if (tags && tags.length > 0 && tags[0]) {
4766
4953
  baseVastUrl = tags[0];
4954
+ } else if (this.apiVastTagUrl) {
4955
+ baseVastUrl = this.apiVastTagUrl;
4767
4956
  } else {
4768
4957
  if (this.config.debugAdTiming) {
4769
4958
  console.warn("[StormcloudVideoPlayer] No VAST URL available for prefetch");
@@ -5213,11 +5402,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5213
5402
  switch(_state.label){
5214
5403
  case 0:
5215
5404
  scheduled = this.findCurrentOrNextBreak(this.video.currentTime * 1e3);
5405
+ if (scheduled) {
5406
+ this.consumedVmapBreakIds.add(this.getAdBreakKey(scheduled));
5407
+ }
5216
5408
  tags = this.selectVastTagsForBreak(scheduled);
5217
- if (this.apiVastTagUrl) {
5218
- baseVastUrl = this.apiVastTagUrl;
5219
- } else if (tags && tags.length > 0 && tags[0]) {
5409
+ if (tags && tags.length > 0 && tags[0]) {
5220
5410
  baseVastUrl = tags[0];
5411
+ } else if (this.apiVastTagUrl) {
5412
+ baseVastUrl = this.apiVastTagUrl;
5221
5413
  } else {
5222
5414
  this.clearPendingAdBreak();
5223
5415
  return [
@@ -5331,9 +5523,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5331
5523
  ];
5332
5524
  case 2:
5333
5525
  _state.sent();
5334
- if (this.expectedAdBreakDurationMs != null) {
5335
- this.currentAdBreakStartWallClockMs = Date.now();
5336
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
5526
+ if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
5527
+ this.scheduleAdStopCountdown(this.getRemainingAdMs());
5337
5528
  }
5338
5529
  adVolume = currentMuted ? 0 : currentVolume;
5339
5530
  this.ima.setAdVolume(adVolume);
@@ -5374,9 +5565,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5374
5565
  ];
5375
5566
  case 6:
5376
5567
  _state.sent();
5377
- if (this.expectedAdBreakDurationMs != null) {
5378
- this.currentAdBreakStartWallClockMs = Date.now();
5379
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
5568
+ if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
5569
+ this.scheduleAdStopCountdown(this.getRemainingAdMs());
5380
5570
  }
5381
5571
  adVolume1 = currentMuted ? 0 : currentVolume;
5382
5572
  this.ima.setAdVolume(adVolume1);
@@ -5430,9 +5620,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5430
5620
  ];
5431
5621
  case 10:
5432
5622
  _state.sent();
5433
- if (this.expectedAdBreakDurationMs != null) {
5434
- this.currentAdBreakStartWallClockMs = Date.now();
5435
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
5623
+ if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
5624
+ this.scheduleAdStopCountdown(this.getRemainingAdMs());
5436
5625
  }
5437
5626
  adVolume2 = currentMuted ? 0 : currentVolume;
5438
5627
  this.ima.setAdVolume(adVolume2);
@@ -5783,8 +5972,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5783
5972
  case 2:
5784
5973
  _state.sent();
5785
5974
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
5786
- this.currentAdBreakStartWallClockMs = Date.now();
5787
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
5975
+ this.scheduleAdStopCountdown(this.getRemainingAdMs());
5788
5976
  }
5789
5977
  currentMuted = this.video.muted;
5790
5978
  currentVolume = this.video.volume;
@@ -6096,15 +6284,22 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6096
6284
  {
6097
6285
  key: "findCurrentOrNextBreak",
6098
6286
  value: function findCurrentOrNextBreak(nowMs) {
6099
- var schedule = [];
6287
+ var schedule = this.vmapBreaks;
6100
6288
  var candidate;
6101
6289
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
6102
6290
  try {
6103
6291
  for(var _iterator = schedule[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
6104
6292
  var b = _step.value;
6105
- var _this_config_driftToleranceMs;
6293
+ var _this_config_driftToleranceMs, _this_resolveBreakStartMs;
6294
+ if (this.consumedVmapBreakIds.has(this.getAdBreakKey(b))) {
6295
+ continue;
6296
+ }
6297
+ var breakStartMs = this.resolveBreakStartMs(b);
6298
+ if (breakStartMs == null) {
6299
+ continue;
6300
+ }
6106
6301
  var tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
6107
- if (b.startTimeMs <= nowMs + tol && (candidate == null || b.startTimeMs > (candidate.startTimeMs || 0))) {
6302
+ if (breakStartMs <= nowMs + tol && (candidate == null || breakStartMs > ((_this_resolveBreakStartMs = this.resolveBreakStartMs(candidate)) !== null && _this_resolveBreakStartMs !== void 0 ? _this_resolveBreakStartMs : 0))) {
6108
6303
  candidate = b;
6109
6304
  }
6110
6305
  }
@@ -6128,11 +6323,16 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6128
6323
  {
6129
6324
  key: "onTimeUpdate",
6130
6325
  value: function onTimeUpdate(currentTimeSec) {
6131
- if (this.ima.isAdPlaying()) return;
6326
+ var _this = this;
6327
+ if (this.ima.isAdPlaying() || this.inAdBreak) return;
6132
6328
  var nowMs = currentTimeSec * 1e3;
6133
6329
  var breakToPlay = this.findBreakForTime(nowMs);
6134
6330
  if (breakToPlay) {
6135
- this.handleMidAdJoin(breakToPlay, nowMs);
6331
+ void this.handleMidAdJoin(breakToPlay, nowMs).catch(function(error) {
6332
+ if (_this.config.debugAdTiming) {
6333
+ console.warn("[StormcloudVideoPlayer] Mid-roll VMAP join failed gracefully:", error);
6334
+ }
6335
+ });
6136
6336
  }
6137
6337
  }
6138
6338
  },
@@ -6140,40 +6340,76 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6140
6340
  key: "handleMidAdJoin",
6141
6341
  value: function handleMidAdJoin(adBreak, nowMs) {
6142
6342
  return _async_to_generator(function() {
6143
- var _adBreak_durationMs, durationMs, endMs, remainingMs, tags, first, rest;
6343
+ var _adBreak_durationMs, _this_config_driftToleranceMs, key, breakStartMs, durationMs, endMs, tol, inWindow, remainingMs, tags, first, rest, error;
6144
6344
  return _ts_generator(this, function(_state) {
6145
6345
  switch(_state.label){
6146
6346
  case 0:
6347
+ key = this.getAdBreakKey(adBreak);
6348
+ if (this.consumedVmapBreakIds.has(key)) {
6349
+ return [
6350
+ 2
6351
+ ];
6352
+ }
6353
+ breakStartMs = this.resolveBreakStartMs(adBreak);
6354
+ if (breakStartMs == null) {
6355
+ return [
6356
+ 2
6357
+ ];
6358
+ }
6147
6359
  durationMs = (_adBreak_durationMs = adBreak.durationMs) !== null && _adBreak_durationMs !== void 0 ? _adBreak_durationMs : 0;
6148
- endMs = adBreak.startTimeMs + durationMs;
6149
- if (!(durationMs > 0 && nowMs > adBreak.startTimeMs && nowMs < endMs)) return [
6360
+ endMs = breakStartMs + durationMs;
6361
+ tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
6362
+ inWindow = durationMs > 0 ? nowMs > breakStartMs && nowMs < endMs : nowMs + tol >= breakStartMs;
6363
+ if (!inWindow) return [
6150
6364
  3,
6151
- 2
6365
+ 4
6152
6366
  ];
6153
- remainingMs = endMs - nowMs;
6367
+ this.consumedVmapBreakIds.add(key);
6368
+ remainingMs = durationMs > 0 ? Math.max(0, endMs - nowMs) : 0;
6154
6369
  tags = this.selectVastTagsForBreak(adBreak) || (this.apiVastTagUrl ? [
6155
6370
  this.apiVastTagUrl
6156
6371
  ] : void 0);
6157
6372
  if (!(tags && tags.length > 0)) return [
6158
6373
  3,
6159
- 2
6374
+ 4
6160
6375
  ];
6161
6376
  first = tags[0];
6162
6377
  rest = tags.slice(1);
6163
6378
  this.adPodQueue = rest;
6164
6379
  this.ima.updateOriginalMutedState(this.video.muted, this.video.volume);
6380
+ _state.label = 1;
6381
+ case 1:
6382
+ _state.trys.push([
6383
+ 1,
6384
+ 3,
6385
+ ,
6386
+ 4
6387
+ ]);
6165
6388
  return [
6166
6389
  4,
6167
6390
  this.playSingleAd(first)
6168
6391
  ];
6169
- case 1:
6392
+ case 2:
6170
6393
  _state.sent();
6171
6394
  this.inAdBreak = true;
6172
6395
  this.expectedAdBreakDurationMs = remainingMs;
6173
6396
  this.currentAdBreakStartWallClockMs = Date.now();
6174
6397
  this.scheduleAdStopCountdown(remainingMs);
6175
- _state.label = 2;
6176
- case 2:
6398
+ return [
6399
+ 3,
6400
+ 4
6401
+ ];
6402
+ case 3:
6403
+ error = _state.sent();
6404
+ this.adPodQueue = [];
6405
+ if (this.config.debugAdTiming) {
6406
+ console.warn("[StormcloudVideoPlayer] Mid-roll VMAP ad request failed:", error);
6407
+ }
6408
+ return [
6409
+ 3,
6410
+ 4
6411
+ ];
6412
+ case 4:
6177
6413
  return [
6178
6414
  2
6179
6415
  ];
@@ -6489,8 +6725,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6489
6725
  case 5:
6490
6726
  _state.sent();
6491
6727
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
6492
- this.currentAdBreakStartWallClockMs = Date.now();
6493
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
6728
+ this.scheduleAdStopCountdown(this.getRemainingAdMs());
6494
6729
  }
6495
6730
  currentMuted = this.video.muted;
6496
6731
  currentVolume = this.video.volume;
@@ -6540,8 +6775,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6540
6775
  case 8:
6541
6776
  _state.sent();
6542
6777
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
6543
- this.currentAdBreakStartWallClockMs = Date.now();
6544
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
6778
+ this.scheduleAdStopCountdown(this.getRemainingAdMs());
6545
6779
  }
6546
6780
  currentMuted1 = this.video.muted;
6547
6781
  currentVolume1 = this.video.volume;
@@ -6879,13 +7113,22 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6879
7113
  {
6880
7114
  key: "findBreakForTime",
6881
7115
  value: function findBreakForTime(nowMs) {
6882
- var schedule = [];
7116
+ var _this_config_driftToleranceMs;
7117
+ var schedule = this.vmapBreaks;
7118
+ var tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
6883
7119
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
6884
7120
  try {
6885
7121
  for(var _iterator = schedule[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
6886
7122
  var b = _step.value;
6887
- var end = (b.startTimeMs || 0) + (b.durationMs || 0);
6888
- if (nowMs >= (b.startTimeMs || 0) && (b.durationMs ? nowMs < end : true)) {
7123
+ if (this.consumedVmapBreakIds.has(this.getAdBreakKey(b))) {
7124
+ continue;
7125
+ }
7126
+ var breakStartMs = this.resolveBreakStartMs(b);
7127
+ if (breakStartMs == null) {
7128
+ continue;
7129
+ }
7130
+ var end = breakStartMs + (b.durationMs || 0);
7131
+ if (nowMs >= breakStartMs && (b.durationMs ? nowMs < end : nowMs <= breakStartMs + tol)) {
6889
7132
  return b;
6890
7133
  }
6891
7134
  }
@@ -7111,19 +7354,21 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7111
7354
  return StormcloudVideoPlayer;
7112
7355
  }();
7113
7356
  // src/ui/StormcloudVideoPlayer.tsx
7114
- import { FaPlay, FaPause, FaVolumeUp, FaVolumeMute, FaVolumeDown, FaExpand, FaCompress, FaSpinner } from "react-icons/fa";
7357
+ import { FaPlay, FaPause, FaVolumeUp, FaVolumeMute, FaVolumeDown, FaExpand, FaCompress } from "react-icons/fa";
7115
7358
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7116
7359
  var CRITICAL_PROPS = [
7117
7360
  "src",
7118
7361
  "allowNativeHls",
7119
7362
  "licenseKey",
7363
+ "vmapUrl",
7120
7364
  "lowLatencyMode",
7121
7365
  "driftToleranceMs",
7122
7366
  "vastMode"
7123
7367
  ];
7124
7368
  var CONTROLS_HIDE_DELAY = 3e3;
7369
+ var DEFAULT_PLAYER_ASPECT_RATIO = 16 / 9;
7125
7370
  var StormcloudVideoPlayerComponent = React.memo(function(props) {
7126
- var src = props.src, autoplay = props.autoplay, muted = props.muted, lowLatencyMode = props.lowLatencyMode, allowNativeHls = props.allowNativeHls, driftToleranceMs = props.driftToleranceMs, immediateManifestAds = props.immediateManifestAds, debugAdTiming = props.debugAdTiming, showCustomControls = props.showCustomControls, hideLoadingIndicator = props.hideLoadingIndicator, onVolumeToggle = props.onVolumeToggle, onFullscreenToggle = props.onFullscreenToggle, onControlClick = props.onControlClick, onReady = props.onReady, wrapperClassName = props.wrapperClassName, wrapperStyle = props.wrapperStyle, className = props.className, style = props.style, controls = props.controls, playsInline = props.playsInline, preload = props.preload, poster = props.poster, children = props.children, licenseKey = props.licenseKey, vastMode = props.vastMode, vastTagUrl = props.vastTagUrl, adPlayerType = props.adPlayerType, minSegmentsBeforePlay = props.minSegmentsBeforePlay, restVideoAttrs = _object_without_properties(props, [
7371
+ var src = props.src, autoplay = props.autoplay, muted = props.muted, lowLatencyMode = props.lowLatencyMode, allowNativeHls = props.allowNativeHls, driftToleranceMs = props.driftToleranceMs, immediateManifestAds = props.immediateManifestAds, debugAdTiming = props.debugAdTiming, showCustomControls = props.showCustomControls, hideLoadingIndicator = props.hideLoadingIndicator, onVolumeToggle = props.onVolumeToggle, onFullscreenToggle = props.onFullscreenToggle, onControlClick = props.onControlClick, onReady = props.onReady, wrapperClassName = props.wrapperClassName, wrapperStyle = props.wrapperStyle, className = props.className, style = props.style, controls = props.controls, playsInline = props.playsInline, preload = props.preload, poster = props.poster, children = props.children, licenseKey = props.licenseKey, vastMode = props.vastMode, vastTagUrl = props.vastTagUrl, vmapUrl = props.vmapUrl, adPlayerType = props.adPlayerType, minSegmentsBeforePlay = props.minSegmentsBeforePlay, restVideoAttrs = _object_without_properties(props, [
7127
7372
  "src",
7128
7373
  "autoplay",
7129
7374
  "muted",
@@ -7150,6 +7395,7 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
7150
7395
  "licenseKey",
7151
7396
  "vastMode",
7152
7397
  "vastTagUrl",
7398
+ "vmapUrl",
7153
7399
  "adPlayerType",
7154
7400
  "minSegmentsBeforePlay"
7155
7401
  ]);
@@ -7161,7 +7407,8 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
7161
7407
  var _React_useState = _sliced_to_array(React.useState({
7162
7408
  showAds: false,
7163
7409
  currentIndex: 0,
7164
- totalAds: 0
7410
+ totalAds: 0,
7411
+ remainingSeconds: 0
7165
7412
  }), 2), adStatus = _React_useState[0], setAdStatus = _React_useState[1];
7166
7413
  var _React_useState1 = _sliced_to_array(React.useState(true), 2), shouldShowNativeControls = _React_useState1[0], setShouldShowNativeControls = _React_useState1[1];
7167
7414
  var _React_useState2 = _sliced_to_array(React.useState(false), 2), isMuted = _React_useState2[0], setIsMuted = _React_useState2[1];
@@ -7180,6 +7427,7 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
7180
7427
  var _React_useState15 = _sliced_to_array(React.useState(true), 2), controlsVisible = _React_useState15[0], setControlsVisible = _React_useState15[1];
7181
7428
  var _React_useState16 = _sliced_to_array(React.useState(typeof window !== "undefined" ? window.innerWidth : 1920), 2), viewportWidth = _React_useState16[0], setViewportWidth = _React_useState16[1];
7182
7429
  var _React_useState17 = _sliced_to_array(React.useState(typeof window !== "undefined" ? window.innerHeight > window.innerWidth : false), 2), isPortrait = _React_useState17[0], setIsPortrait = _React_useState17[1];
7430
+ var _React_useState18 = _sliced_to_array(React.useState(DEFAULT_PLAYER_ASPECT_RATIO), 2), playerAspectRatio = _React_useState18[0], setPlayerAspectRatio = _React_useState18[1];
7183
7431
  var getResponsiveScale = function getResponsiveScale() {
7184
7432
  if (viewportWidth < 480) return 0.7;
7185
7433
  if (viewportWidth < 768) return 0.8;
@@ -7289,6 +7537,7 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
7289
7537
  src,
7290
7538
  allowNativeHls,
7291
7539
  licenseKey,
7540
+ vmapUrl,
7292
7541
  lowLatencyMode,
7293
7542
  driftToleranceMs,
7294
7543
  vastMode
@@ -7331,6 +7580,7 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
7331
7580
  if (licenseKey !== void 0) cfg.licenseKey = licenseKey;
7332
7581
  if (vastMode !== void 0) cfg.vastMode = vastMode;
7333
7582
  if (vastTagUrl !== void 0) cfg.vastTagUrl = vastTagUrl;
7583
+ if (vmapUrl !== void 0) cfg.vmapUrl = vmapUrl;
7334
7584
  if (adPlayerType !== void 0) cfg.adPlayerType = adPlayerType;
7335
7585
  if (minSegmentsBeforePlay !== void 0) cfg.minSegmentsBeforePlay = minSegmentsBeforePlay;
7336
7586
  var player = new StormcloudVideoPlayer(cfg);
@@ -7382,15 +7632,18 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
7382
7632
  var showAds = showAdsFromMethod || showAdsFromAttribute;
7383
7633
  var currentIndex = playerRef.current.getCurrentAdIndex();
7384
7634
  var totalAds = playerRef.current.getTotalAdsInBreak();
7635
+ var remainingMs = playerRef.current.getAdRemainingMs();
7636
+ var remainingSeconds = showAds ? Math.max(0, Math.ceil(remainingMs / 1e3)) : 0;
7385
7637
  setAdStatus(function(prev) {
7386
- if (prev.showAds !== showAds || prev.currentIndex !== currentIndex || prev.totalAds !== totalAds) {
7638
+ if (prev.showAds !== showAds || prev.currentIndex !== currentIndex || prev.totalAds !== totalAds || prev.remainingSeconds !== remainingSeconds) {
7387
7639
  if (showAds && !prev.showAds) {
7388
7640
  setShowCenterPlay(false);
7389
7641
  }
7390
7642
  return {
7391
7643
  showAds: showAds,
7392
7644
  currentIndex: currentIndex,
7393
- totalAds: totalAds
7645
+ totalAds: totalAds,
7646
+ remainingSeconds: remainingSeconds
7394
7647
  };
7395
7648
  }
7396
7649
  return prev;
@@ -7448,8 +7701,11 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
7448
7701
  useEffect(function() {
7449
7702
  if (!videoRef.current) return;
7450
7703
  var handleLoadedMetadata = function handleLoadedMetadata() {
7451
- if (videoRef.current) {
7452
- var video2 = videoRef.current;
7704
+ var video2 = videoRef.current;
7705
+ if (video2) {
7706
+ if (video2.videoWidth > 0 && video2.videoHeight > 0) {
7707
+ setPlayerAspectRatio(video2.videoWidth / video2.videoHeight);
7708
+ }
7453
7709
  void video2.offsetHeight;
7454
7710
  }
7455
7711
  if (debugAdTiming) {
@@ -7565,6 +7821,11 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
7565
7821
  }, [
7566
7822
  debugAdTiming
7567
7823
  ]);
7824
+ useEffect(function() {
7825
+ setPlayerAspectRatio(DEFAULT_PLAYER_ASPECT_RATIO);
7826
+ }, [
7827
+ src
7828
+ ]);
7568
7829
  useEffect(function() {
7569
7830
  return function() {
7570
7831
  if (controlsTimerRef.current) {
@@ -7577,7 +7838,7 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
7577
7838
  return /* @__PURE__ */ jsxs(Fragment, {
7578
7839
  children: [
7579
7840
  /* @__PURE__ */ jsx("style", {
7580
- children: "\n @keyframes sc-spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n @keyframes sc-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.6; }\n }\n @keyframes sc-fade-in {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n }\n .sc-wrapper:fullscreen,\n .sc-wrapper:has(*:fullscreen) {\n border-radius: 0 !important;\n box-shadow: none !important;\n width: 100vw !important;\n height: 100vh !important;\n max-width: 100vw !important;\n max-height: 100vh !important;\n position: fixed !important;\n top: 0 !important;\n left: 0 !important;\n z-index: 999999 !important;\n background: #000 !important;\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n }\n .sc-ctrl-btn {\n background: none;\n border: none;\n color: #fff;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n padding: 8px;\n transition: background 0.15s ease, opacity 0.15s ease;\n opacity: 0.9;\n }\n .sc-ctrl-btn:hover {\n opacity: 1;\n background: rgba(255, 255, 255, 0.1);\n }\n .sc-ctrl-btn:active {\n opacity: 0.7;\n }\n .sc-controls-bar {\n transition: opacity 0.35s ease, transform 0.35s ease;\n }\n .sc-progress-track:hover .sc-progress-thumb {\n transform: translate(-50%, -50%) scale(1) !important;\n }\n .sc-loading-hidden .sc-loading-indicator {\n display: none !important;\n }\n "
7841
+ children: "\n @keyframes sc-spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n @keyframes sc-loading-glow {\n 0%, 100% { opacity: 0.85; transform: scale(1); }\n 50% { opacity: 1; transform: scale(1.05); }\n }\n @keyframes sc-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.6; }\n }\n @keyframes sc-fade-in {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n }\n .sc-wrapper:fullscreen,\n .sc-wrapper:has(*:fullscreen) {\n border-radius: 0 !important;\n box-shadow: none !important;\n width: 100vw !important;\n height: 100vh !important;\n max-width: 100vw !important;\n max-height: 100vh !important;\n position: fixed !important;\n top: 0 !important;\n left: 0 !important;\n z-index: 999999 !important;\n background: #000 !important;\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n }\n .sc-ctrl-btn {\n background: none;\n border: none;\n color: #fff;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n padding: 8px;\n transition: background 0.15s ease, opacity 0.15s ease;\n opacity: 0.9;\n }\n .sc-ctrl-btn:hover {\n opacity: 1;\n background: rgba(255, 255, 255, 0.1);\n }\n .sc-ctrl-btn:active {\n opacity: 0.7;\n }\n .sc-controls-bar {\n transition: opacity 0.35s ease, transform 0.35s ease;\n }\n .sc-progress-track:hover .sc-progress-thumb {\n transform: translate(-50%, -50%) scale(1) !important;\n }\n .sc-loading-hidden .sc-loading-indicator {\n display: none !important;\n }\n "
7581
7842
  }),
7582
7843
  /* @__PURE__ */ jsxs("div", {
7583
7844
  ref: wrapperRef,
@@ -7595,6 +7856,7 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
7595
7856
  width: isFullscreen ? "100vw" : "100%",
7596
7857
  height: isFullscreen ? "100vh" : "auto",
7597
7858
  minHeight: isFullscreen ? "100vh" : "auto",
7859
+ aspectRatio: isFullscreen ? void 0 : playerAspectRatio,
7598
7860
  maxWidth: isFullscreen ? "100vw" : "100%",
7599
7861
  maxHeight: isFullscreen ? "100vh" : "none",
7600
7862
  zIndex: isFullscreen ? 999999 : void 0,
@@ -7609,7 +7871,7 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
7609
7871
  style: _object_spread({
7610
7872
  display: "block",
7611
7873
  width: "100%",
7612
- height: isFullscreen ? "100%" : "auto",
7874
+ height: "100%",
7613
7875
  maxWidth: "100%",
7614
7876
  maxHeight: isFullscreen ? "100%" : "none",
7615
7877
  objectFit: isFullscreen ? "cover" : "contain",
@@ -7623,18 +7885,44 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
7623
7885
  }, restVideoAttrs), {
7624
7886
  children: children
7625
7887
  })),
7626
- (isLoading || isBuffering) && !hideLoadingIndicator && /* @__PURE__ */ jsx(FaSpinner, {
7888
+ (isLoading || isBuffering) && !hideLoadingIndicator && /* @__PURE__ */ jsxs("div", {
7627
7889
  className: "sc-loading-indicator",
7628
- size: 40,
7629
- color: "rgba(255, 255, 255, 0.85)",
7630
7890
  style: {
7631
7891
  position: "absolute",
7632
- top: "calc(50% - 20px)",
7633
- left: "calc(50% - 20px)",
7892
+ top: "50%",
7893
+ left: "50%",
7894
+ transform: "translate(-50%, -50%)",
7634
7895
  zIndex: 20,
7635
- animation: "sc-spin 0.9s linear infinite",
7636
- filter: "drop-shadow(0 2px 8px rgba(0, 0, 0, 0.6))"
7637
- }
7896
+ width: "".concat(Math.max(34, 38 * responsiveScale), "px"),
7897
+ height: "".concat(Math.max(34, 38 * responsiveScale), "px"),
7898
+ display: "flex",
7899
+ alignItems: "center",
7900
+ justifyContent: "center",
7901
+ animation: "sc-loading-glow 1.4s ease-in-out infinite",
7902
+ filter: "drop-shadow(0 6px 14px rgba(0, 0, 0, 0.55))"
7903
+ },
7904
+ children: [
7905
+ /* @__PURE__ */ jsx("div", {
7906
+ style: {
7907
+ position: "absolute",
7908
+ inset: 0,
7909
+ borderRadius: "50%",
7910
+ border: "3px solid rgba(255, 255, 255, 0.25)",
7911
+ borderTopColor: "#ff0000",
7912
+ borderRightColor: "rgba(255, 255, 255, 0.85)",
7913
+ animation: "sc-spin 0.8s linear infinite"
7914
+ }
7915
+ }),
7916
+ /* @__PURE__ */ jsx("div", {
7917
+ style: {
7918
+ width: "7px",
7919
+ height: "7px",
7920
+ borderRadius: "50%",
7921
+ background: "#ff0000",
7922
+ boxShadow: "0 0 10px rgba(255, 0, 0, 0.65)"
7923
+ }
7924
+ })
7925
+ ]
7638
7926
  }),
7639
7927
  showLicenseWarning && /* @__PURE__ */ jsxs("div", {
7640
7928
  style: {
@@ -7678,6 +7966,48 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
7678
7966
  })
7679
7967
  ]
7680
7968
  }),
7969
+ adStatus.showAds && /* @__PURE__ */ jsxs("div", {
7970
+ style: {
7971
+ position: "absolute",
7972
+ top: "".concat(12 * responsiveScale, "px"),
7973
+ left: "".concat(12 * responsiveScale, "px"),
7974
+ zIndex: 50,
7975
+ display: "flex",
7976
+ alignItems: "center",
7977
+ gap: "8px",
7978
+ pointerEvents: "none",
7979
+ animation: "sc-fade-in 0.3s ease"
7980
+ },
7981
+ children: [
7982
+ /* @__PURE__ */ jsx("div", {
7983
+ style: {
7984
+ background: "rgba(234, 179, 8, 0.95)",
7985
+ color: "#111",
7986
+ padding: "".concat(4 * responsiveScale, "px ").concat(12 * responsiveScale, "px"),
7987
+ borderRadius: "6px",
7988
+ fontSize: "".concat(11 * responsiveScale, "px"),
7989
+ fontWeight: 700,
7990
+ letterSpacing: "0.08em",
7991
+ textTransform: "uppercase",
7992
+ boxShadow: "0 2px 12px rgba(234, 179, 8, 0.35)"
7993
+ },
7994
+ children: "Ad"
7995
+ }),
7996
+ /* @__PURE__ */ jsx("div", {
7997
+ style: {
7998
+ background: "rgba(0, 0, 0, 0.58)",
7999
+ color: "rgba(255, 255, 255, 0.92)",
8000
+ padding: "".concat(4 * responsiveScale, "px ").concat(10 * responsiveScale, "px"),
8001
+ borderRadius: "6px",
8002
+ fontSize: "".concat(11 * responsiveScale, "px"),
8003
+ fontWeight: 600,
8004
+ border: "1px solid rgba(255, 255, 255, 0.1)",
8005
+ boxShadow: "0 2px 10px rgba(0, 0, 0, 0.25)"
8006
+ },
8007
+ children: "".concat(Math.max(1, adStatus.currentIndex), " of ").concat(Math.max(Math.max(1, adStatus.currentIndex), adStatus.totalAds))
8008
+ })
8009
+ ]
8010
+ }),
7681
8011
  showCenterPlay && !isLoading && !isBuffering && !showLicenseWarning && !adStatus.showAds && /* @__PURE__ */ jsx("div", {
7682
8012
  onClick: handleCenterPlayClick,
7683
8013
  style: {
@@ -7817,7 +8147,8 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
7817
8147
  /* @__PURE__ */ jsxs("div", {
7818
8148
  style: {
7819
8149
  display: "flex",
7820
- alignItems: "center"
8150
+ alignItems: "center",
8151
+ paddingRight: "".concat(6 * responsiveScale, "px")
7821
8152
  },
7822
8153
  onMouseEnter: function onMouseEnter() {
7823
8154
  return setShowVolumeSlider(true);
@@ -7846,13 +8177,13 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
7846
8177
  }),
7847
8178
  /* @__PURE__ */ jsx("div", {
7848
8179
  style: {
7849
- width: showVolumeSlider ? "".concat(62 * responsiveScale, "px") : "0px",
8180
+ width: showVolumeSlider ? "".concat(68 * responsiveScale, "px") : "0px",
7850
8181
  overflow: "hidden",
7851
8182
  transition: "width 0.2s cubic-bezier(0.4, 0, 0.2, 1)",
7852
8183
  display: "flex",
7853
8184
  alignItems: "center",
7854
- paddingLeft: showVolumeSlider ? "2px" : "0",
7855
- paddingRight: showVolumeSlider ? "4px" : "0"
8185
+ paddingLeft: showVolumeSlider ? "".concat(3 * responsiveScale, "px") : "0",
8186
+ paddingRight: showVolumeSlider ? "".concat(8 * responsiveScale, "px") : "0"
7856
8187
  },
7857
8188
  children: /* @__PURE__ */ jsxs("div", {
7858
8189
  style: {
@@ -8099,7 +8430,8 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
8099
8430
  alignItems: "center",
8100
8431
  background: "rgba(0, 0, 0, 0.6)",
8101
8432
  borderRadius: "".concat(18 * responsiveScale, "px"),
8102
- padding: "2px"
8433
+ padding: "2px",
8434
+ paddingRight: "".concat(8 * responsiveScale, "px")
8103
8435
  },
8104
8436
  onMouseEnter: function onMouseEnter() {
8105
8437
  return setShowVolumeSlider(true);
@@ -8128,13 +8460,13 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
8128
8460
  }),
8129
8461
  /* @__PURE__ */ jsx("div", {
8130
8462
  style: {
8131
- width: showVolumeSlider ? "".concat(62 * responsiveScale, "px") : "0px",
8463
+ width: showVolumeSlider ? "".concat(68 * responsiveScale, "px") : "0px",
8132
8464
  overflow: "hidden",
8133
8465
  transition: "width 0.2s cubic-bezier(0.4, 0, 0.2, 1)",
8134
8466
  display: "flex",
8135
8467
  alignItems: "center",
8136
- paddingLeft: showVolumeSlider ? "2px" : "0",
8137
- paddingRight: showVolumeSlider ? "6px" : "0"
8468
+ paddingLeft: showVolumeSlider ? "".concat(3 * responsiveScale, "px") : "0",
8469
+ paddingRight: showVolumeSlider ? "".concat(10 * responsiveScale, "px") : "0"
8138
8470
  },
8139
8471
  children: /* @__PURE__ */ jsxs("div", {
8140
8472
  style: {
@@ -8370,6 +8702,7 @@ var defaultProps = {
8370
8702
  showCustomControls: false,
8371
8703
  hideLoadingIndicator: false,
8372
8704
  licenseKey: "",
8705
+ vmapUrl: "",
8373
8706
  adFailsafeTimeoutMs: 1e4,
8374
8707
  minSegmentsBeforePlay: 2,
8375
8708
  onStart: noop,
@@ -9316,6 +9649,7 @@ var SUPPORTED_PROPS = [
9316
9649
  "debugAdTiming",
9317
9650
  "showCustomControls",
9318
9651
  "licenseKey",
9652
+ "vmapUrl",
9319
9653
  "adFailsafeTimeoutMs",
9320
9654
  "minSegmentsBeforePlay",
9321
9655
  "onReady",