stormcloud-video-player 0.8.25 → 0.8.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/stormcloud-vp.min.js +1 -1
  2. package/lib/index.cjs +631 -115
  3. package/lib/index.cjs.map +1 -1
  4. package/lib/index.d.cts +7 -0
  5. package/lib/index.d.ts +7 -0
  6. package/lib/index.js +631 -115
  7. package/lib/index.js.map +1 -1
  8. package/lib/player/AdBreakOrchestrator.cjs +198 -41
  9. package/lib/player/AdBreakOrchestrator.cjs.map +1 -1
  10. package/lib/player/AdBreakOrchestrator.d.cts +4 -1
  11. package/lib/player/AdConfigManager.cjs +61 -1
  12. package/lib/player/AdConfigManager.cjs.map +1 -1
  13. package/lib/player/AdConfigManager.d.cts +12 -1
  14. package/lib/player/AdPreloadPool.d.cts +1 -1
  15. package/lib/player/AdTimingService.cjs +7 -0
  16. package/lib/player/AdTimingService.cjs.map +1 -1
  17. package/lib/player/AdTimingService.d.cts +2 -1
  18. package/lib/player/HlsEngine.d.cts +1 -1
  19. package/lib/player/PlayerControls.d.cts +1 -1
  20. package/lib/player/Scte35CueManager.d.cts +1 -1
  21. package/lib/player/Scte35Parser.d.cts +1 -1
  22. package/lib/player/StormcloudVideoPlayer.cjs +631 -115
  23. package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
  24. package/lib/player/StormcloudVideoPlayer.d.cts +2 -1
  25. package/lib/player/playerTypes.d.cts +1 -1
  26. package/lib/players/HlsPlayer.cjs +631 -115
  27. package/lib/players/HlsPlayer.cjs.map +1 -1
  28. package/lib/players/HlsPlayer.d.cts +1 -1
  29. package/lib/players/index.cjs +631 -115
  30. package/lib/players/index.cjs.map +1 -1
  31. package/lib/sdk/hlsAdPlayer.cjs +343 -71
  32. package/lib/sdk/hlsAdPlayer.cjs.map +1 -1
  33. package/lib/sdk/hlsAdPlayer.d.cts +1 -1
  34. package/lib/{types-Bz4aRmzc.d.cts → types-Xgz2_W1C.d.cts} +6 -0
  35. package/lib/ui/StormcloudVideoPlayer.cjs +631 -115
  36. package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
  37. package/lib/ui/StormcloudVideoPlayer.d.cts +1 -1
  38. package/lib/utils/tracking.d.cts +1 -1
  39. package/lib/utils/vastMacros.cjs +14 -1
  40. package/lib/utils/vastMacros.cjs.map +1 -1
  41. package/lib/utils/vastMacros.d.cts +3 -0
  42. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -382,6 +382,8 @@ function createHlsAdPlayer(contentVideo, options) {
382
382
  var adHls;
383
383
  var adContainerEl;
384
384
  var currentAd;
385
+ var podAds = [];
386
+ var podIndex = 0;
385
387
  var sessionId;
386
388
  var preloadedAds = /* @__PURE__ */ new Map();
387
389
  var preloadingAds = /* @__PURE__ */ new Map();
@@ -546,14 +548,14 @@ function createHlsAdPlayer(contentVideo, options) {
546
548
  error: []
547
549
  };
548
550
  }
549
- function extractTrackingUrls(xmlDoc) {
551
+ function extractTrackingUrls(scope) {
550
552
  var trackingUrls = createEmptyTrackingUrls();
551
- xmlDoc.querySelectorAll("Impression").forEach(function(el) {
553
+ scope.querySelectorAll("Impression").forEach(function(el) {
552
554
  var _el_textContent;
553
555
  var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
554
556
  if (url) trackingUrls.impression.push(url);
555
557
  });
556
- xmlDoc.querySelectorAll("Tracking").forEach(function(el) {
558
+ scope.querySelectorAll("Tracking").forEach(function(el) {
557
559
  var _el_textContent;
558
560
  var event = el.getAttribute("event");
559
561
  var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
@@ -564,7 +566,7 @@ function createHlsAdPlayer(contentVideo, options) {
564
566
  }
565
567
  }
566
568
  });
567
- xmlDoc.querySelectorAll("Error").forEach(function(el) {
569
+ scope.querySelectorAll("Error").forEach(function(el) {
568
570
  var _el_textContent;
569
571
  var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
570
572
  if (url) trackingUrls.error.push(url);
@@ -674,6 +676,75 @@ function createHlsAdPlayer(contentVideo, options) {
674
676
  };
675
677
  }
676
678
  }
679
+ function parseAdElement(adElement) {
680
+ try {
681
+ var _adElement_querySelector, _adElement_querySelector_textContent, _adElement_querySelector1, _adElement_querySelector_textContent1, _adElement_querySelector2, _adElement_querySelector3;
682
+ var adId = adElement.getAttribute("id") || "unknown";
683
+ var title = ((_adElement_querySelector = adElement.querySelector("AdTitle")) === null || _adElement_querySelector === void 0 ? void 0 : _adElement_querySelector.textContent) || "Ad";
684
+ var clickThrough = (_adElement_querySelector1 = adElement.querySelector("ClickThrough")) === null || _adElement_querySelector1 === void 0 ? void 0 : (_adElement_querySelector_textContent = _adElement_querySelector1.textContent) === null || _adElement_querySelector_textContent === void 0 ? void 0 : _adElement_querySelector_textContent.trim();
685
+ var wrapperUri = (_adElement_querySelector2 = adElement.querySelector("VASTAdTagURI")) === null || _adElement_querySelector2 === void 0 ? void 0 : (_adElement_querySelector_textContent1 = _adElement_querySelector2.textContent) === null || _adElement_querySelector_textContent1 === void 0 ? void 0 : _adElement_querySelector_textContent1.trim();
686
+ if (wrapperUri) {
687
+ return {
688
+ type: "wrapper",
689
+ vastAdTagUri: wrapperUri,
690
+ trackingUrls: extractTrackingUrls(adElement),
691
+ clickThrough: clickThrough
692
+ };
693
+ }
694
+ var isNoAdAvailable = adId === "empty" || title.toLowerCase().includes("no ad available") || title.toLowerCase() === "no ad available";
695
+ var durationText = ((_adElement_querySelector3 = adElement.querySelector("Duration")) === null || _adElement_querySelector3 === void 0 ? void 0 : _adElement_querySelector3.textContent) || "00:00:30";
696
+ var durationParts = durationText.split(":");
697
+ var duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseInt(durationParts[2] || "0", 10);
698
+ var mediaFileElements = adElement.querySelectorAll("MediaFile");
699
+ var mediaFiles = [];
700
+ mediaFileElements.forEach(function(mf) {
701
+ var _mf_textContent;
702
+ var type = mf.getAttribute("type") || "";
703
+ var url = ((_mf_textContent = mf.textContent) === null || _mf_textContent === void 0 ? void 0 : _mf_textContent.trim()) || "";
704
+ var width = mf.getAttribute("width") || "";
705
+ var height = mf.getAttribute("height") || "";
706
+ if (!url) return;
707
+ var bitrateAttr = mf.getAttribute("bitrate");
708
+ var bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;
709
+ var mediaFile = {
710
+ url: url,
711
+ type: type,
712
+ width: parseInt(width || "1920", 10),
713
+ height: parseInt(height || "1080", 10),
714
+ bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : void 0
715
+ };
716
+ if (isHlsMediaFile(mediaFile) || isProgressiveMediaFile(mediaFile)) {
717
+ mediaFiles.push(mediaFile);
718
+ }
719
+ });
720
+ if (mediaFiles.length === 0) {
721
+ if (isNoAdAvailable) {
722
+ console.warn("[HlsAdPlayer] Pod <Ad> indicates no ad available");
723
+ } else {
724
+ console.warn("[HlsAdPlayer] No supported media files in pod <Ad>");
725
+ }
726
+ return {
727
+ type: "empty"
728
+ };
729
+ }
730
+ return {
731
+ type: "inline",
732
+ ad: {
733
+ id: adId,
734
+ title: title,
735
+ duration: duration,
736
+ mediaFiles: mediaFiles,
737
+ trackingUrls: extractTrackingUrls(adElement),
738
+ clickThrough: clickThrough
739
+ }
740
+ };
741
+ } catch (error) {
742
+ console.error("[HlsAdPlayer] Error parsing pod <Ad> element:", error);
743
+ return {
744
+ type: "empty"
745
+ };
746
+ }
747
+ }
677
748
  function fetchVastXml(vastTagUrl) {
678
749
  return _async_to_generator(function() {
679
750
  var response;
@@ -750,6 +821,146 @@ function createHlsAdPlayer(contentVideo, options) {
750
821
  });
751
822
  }).apply(this, arguments);
752
823
  }
824
+ function fetchAndParsePod(vastTagUrl) {
825
+ return _async_to_generator(function() {
826
+ var vastXml, parser, xmlDoc, adElements, ads, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, adElement, parsed, resolved, error, err;
827
+ return _ts_generator(this, function(_state) {
828
+ switch(_state.label){
829
+ case 0:
830
+ return [
831
+ 4,
832
+ fetchVastXml(vastTagUrl)
833
+ ];
834
+ case 1:
835
+ vastXml = _state.sent();
836
+ console.log("[HlsAdPlayer] Pod VAST XML received");
837
+ parser = new DOMParser();
838
+ xmlDoc = parser.parseFromString(vastXml, "text/xml");
839
+ if (xmlDoc.querySelector("parsererror")) {
840
+ console.error("[HlsAdPlayer] Pod VAST XML parsing error (malformed)");
841
+ return [
842
+ 2,
843
+ []
844
+ ];
845
+ }
846
+ adElements = Array.from(xmlDoc.querySelectorAll("Ad"));
847
+ if (adElements.length === 0) {
848
+ console.warn("[HlsAdPlayer] No <Ad> elements found in pod VAST response");
849
+ return [
850
+ 2,
851
+ []
852
+ ];
853
+ }
854
+ adElements.sort(function(a, b) {
855
+ var aSeq = parseInt(a.getAttribute("sequence") || "", 10);
856
+ var bSeq = parseInt(b.getAttribute("sequence") || "", 10);
857
+ var aVal = Number.isFinite(aSeq) ? aSeq : Number.MAX_SAFE_INTEGER;
858
+ var bVal = Number.isFinite(bSeq) ? bSeq : Number.MAX_SAFE_INTEGER;
859
+ return aVal - bVal;
860
+ });
861
+ ads = [];
862
+ _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
863
+ _state.label = 2;
864
+ case 2:
865
+ _state.trys.push([
866
+ 2,
867
+ 10,
868
+ 11,
869
+ 12
870
+ ]);
871
+ _iterator = adElements[Symbol.iterator]();
872
+ _state.label = 3;
873
+ case 3:
874
+ if (!!(_iteratorNormalCompletion = (_step = _iterator.next()).done)) return [
875
+ 3,
876
+ 9
877
+ ];
878
+ adElement = _step.value;
879
+ parsed = parseAdElement(adElement);
880
+ if (!(parsed.type === "inline")) return [
881
+ 3,
882
+ 4
883
+ ];
884
+ ads.push(parsed.ad);
885
+ return [
886
+ 3,
887
+ 8
888
+ ];
889
+ case 4:
890
+ if (!(parsed.type === "wrapper")) return [
891
+ 3,
892
+ 8
893
+ ];
894
+ _state.label = 5;
895
+ case 5:
896
+ _state.trys.push([
897
+ 5,
898
+ 7,
899
+ ,
900
+ 8
901
+ ]);
902
+ return [
903
+ 4,
904
+ fetchAndParseVastAd(parsed.vastAdTagUri, 1, parsed.trackingUrls)
905
+ ];
906
+ case 6:
907
+ resolved = _state.sent();
908
+ if (resolved) {
909
+ ads.push(resolved);
910
+ }
911
+ return [
912
+ 3,
913
+ 8
914
+ ];
915
+ case 7:
916
+ error = _state.sent();
917
+ console.warn("[HlsAdPlayer] Failed to resolve wrapper <Ad> in pod:", error);
918
+ return [
919
+ 3,
920
+ 8
921
+ ];
922
+ case 8:
923
+ _iteratorNormalCompletion = true;
924
+ return [
925
+ 3,
926
+ 3
927
+ ];
928
+ case 9:
929
+ return [
930
+ 3,
931
+ 12
932
+ ];
933
+ case 10:
934
+ err = _state.sent();
935
+ _didIteratorError = true;
936
+ _iteratorError = err;
937
+ return [
938
+ 3,
939
+ 12
940
+ ];
941
+ case 11:
942
+ try {
943
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
944
+ _iterator.return();
945
+ }
946
+ } finally{
947
+ if (_didIteratorError) {
948
+ throw _iteratorError;
949
+ }
950
+ }
951
+ return [
952
+ 7
953
+ ];
954
+ case 12:
955
+ console.log("[HlsAdPlayer] Parsed ".concat(ads.length, " ad(s) from pod VAST response"));
956
+ return [
957
+ 2,
958
+ ads
959
+ ];
960
+ }
961
+ });
962
+ })();
963
+ }
753
964
  function createAdVideoElement() {
754
965
  var video = document.createElement("video");
755
966
  video.style.position = "absolute";
@@ -794,6 +1005,9 @@ function createHlsAdPlayer(contentVideo, options) {
794
1005
  trackingFired.complete = true;
795
1006
  fireTrackingPixels(currentAd.trackingUrls.complete);
796
1007
  console.log("[HlsAdPlayer] Ad completed");
1008
+ if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1009
+ return;
1010
+ }
797
1011
  handleAdComplete();
798
1012
  });
799
1013
  adVideoElement.addEventListener("error", function(e) {
@@ -802,6 +1016,9 @@ function createHlsAdPlayer(contentVideo, options) {
802
1016
  if (currentAd) {
803
1017
  fireTrackingPixels(currentAd.trackingUrls.error);
804
1018
  }
1019
+ if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1020
+ return;
1021
+ }
805
1022
  handleAdError();
806
1023
  });
807
1024
  adVideoElement.addEventListener("volumechange", function() {
@@ -830,6 +1047,94 @@ function createHlsAdPlayer(contentVideo, options) {
830
1047
  delete contentVideo.dataset.stormcloudAdPlaying;
831
1048
  }
832
1049
  }
1050
+ function resetQuartileTracking(preserveImpression) {
1051
+ trackingFired = {
1052
+ impression: preserveImpression ? trackingFired.impression : false,
1053
+ start: false,
1054
+ firstQuartile: false,
1055
+ midpoint: false,
1056
+ thirdQuartile: false,
1057
+ complete: false
1058
+ };
1059
+ }
1060
+ function loadCurrentAdMedia() {
1061
+ if (!adVideoElement || !currentAd) {
1062
+ throw new Error("No ad video element or ad to load");
1063
+ }
1064
+ var mediaFile = selectBestMediaFile(currentAd.mediaFiles);
1065
+ if (!mediaFile) {
1066
+ throw new Error("No media file available for ad");
1067
+ }
1068
+ var isHlsAd = isHlsMediaFile(mediaFile);
1069
+ console.log("[HlsAdPlayer] Loading ".concat(isHlsAd ? "HLS" : "progressive", " ad (pod ").concat(podIndex + 1, "/").concat(podAds.length || 1, ") from: ").concat(mediaFile.url));
1070
+ if (isHlsAd && Hls.isSupported()) {
1071
+ if (adHls) {
1072
+ adHls.destroy();
1073
+ }
1074
+ adHls = new Hls({
1075
+ enableWorker: true,
1076
+ lowLatencyMode: false
1077
+ });
1078
+ adHls.loadSource(mediaFile.url);
1079
+ adHls.attachMedia(adVideoElement);
1080
+ adHls.on(Hls.Events.MANIFEST_PARSED, function() {
1081
+ console.log("[HlsAdPlayer] HLS manifest parsed, starting playback");
1082
+ adVideoElement.play().catch(function(error) {
1083
+ console.error("[HlsAdPlayer] Error starting ad playback:", error);
1084
+ handleAdError();
1085
+ });
1086
+ });
1087
+ adHls.on(Hls.Events.ERROR, function(_event, data) {
1088
+ console.error("[HlsAdPlayer] HLS error:", data);
1089
+ if (data.fatal) {
1090
+ handleAdError();
1091
+ }
1092
+ });
1093
+ } else if (isHlsAd && adVideoElement.canPlayType("application/vnd.apple.mpegurl")) {
1094
+ adVideoElement.src = mediaFile.url;
1095
+ adVideoElement.play().catch(function(error) {
1096
+ console.error("[HlsAdPlayer] Error starting ad playback:", error);
1097
+ handleAdError();
1098
+ });
1099
+ } else if (!isHlsAd && isProgressiveMediaFile(mediaFile)) {
1100
+ if (adHls) {
1101
+ adHls.destroy();
1102
+ adHls = void 0;
1103
+ }
1104
+ adVideoElement.src = mediaFile.url;
1105
+ adVideoElement.load();
1106
+ adVideoElement.play().catch(function(error) {
1107
+ console.error("[HlsAdPlayer] Error starting progressive ad playback:", error);
1108
+ handleAdError();
1109
+ });
1110
+ } else {
1111
+ throw new Error("Unsupported ad media file type: ".concat(mediaFile.type));
1112
+ }
1113
+ }
1114
+ function advanceToNextPodAd() {
1115
+ if (podIndex >= podAds.length - 1) {
1116
+ return false;
1117
+ }
1118
+ podIndex++;
1119
+ currentAd = podAds[podIndex];
1120
+ resetQuartileTracking(false);
1121
+ if (currentAd) {
1122
+ fireTrackingPixels(currentAd.trackingUrls.impression);
1123
+ trackingFired.impression = true;
1124
+ console.log("[HlsAdPlayer] Advancing to next pod ad (".concat(podIndex + 1, "/").concat(podAds.length, "): ").concat(currentAd.title, ", duration: ").concat(currentAd.duration, "s"));
1125
+ }
1126
+ try {
1127
+ loadCurrentAdMedia();
1128
+ emit("pod_ad_started", {
1129
+ index: podIndex,
1130
+ total: podAds.length
1131
+ });
1132
+ return true;
1133
+ } catch (error) {
1134
+ console.error("[HlsAdPlayer] Failed to load next pod ad:", error);
1135
+ return false;
1136
+ }
1137
+ }
833
1138
  function handleAdComplete() {
834
1139
  console.log("[HlsAdPlayer] Handling ad completion");
835
1140
  adPlaying = false;
@@ -883,7 +1188,7 @@ function createHlsAdPlayer(contentVideo, options) {
883
1188
  },
884
1189
  requestAds: function requestAds(vastTagUrl) {
885
1190
  return _async_to_generator(function() {
886
- var ad, error;
1191
+ var ads, preloaded, error;
887
1192
  return _ts_generator(this, function(_state) {
888
1193
  switch(_state.label){
889
1194
  case 0:
@@ -904,12 +1209,18 @@ function createHlsAdPlayer(contentVideo, options) {
904
1209
  6
905
1210
  ]);
906
1211
  sessionId = generateSessionId();
1212
+ ads = [];
907
1213
  if (!preloadedAds.has(vastTagUrl)) return [
908
1214
  3,
909
1215
  2
910
1216
  ];
911
- ad = preloadedAds.get(vastTagUrl);
1217
+ preloaded = preloadedAds.get(vastTagUrl);
912
1218
  preloadedAds.delete(vastTagUrl);
1219
+ if (preloaded) {
1220
+ ads = [
1221
+ preloaded
1222
+ ];
1223
+ }
913
1224
  console.log("[HlsAdPlayer] Using preloaded VAST response:", vastTagUrl);
914
1225
  return [
915
1226
  3,
@@ -918,13 +1229,13 @@ function createHlsAdPlayer(contentVideo, options) {
918
1229
  case 2:
919
1230
  return [
920
1231
  4,
921
- fetchAndParseVastAd(vastTagUrl)
1232
+ fetchAndParsePod(vastTagUrl)
922
1233
  ];
923
1234
  case 3:
924
- ad = _state.sent();
1235
+ ads = _state.sent();
925
1236
  _state.label = 4;
926
1237
  case 4:
927
- if (!ad) {
1238
+ if (!ads.length) {
928
1239
  console.warn("[HlsAdPlayer] No ads available from VAST response");
929
1240
  emit("ad_error");
930
1241
  return [
@@ -932,10 +1243,14 @@ function createHlsAdPlayer(contentVideo, options) {
932
1243
  Promise.reject(new Error("No ads available from VAST response"))
933
1244
  ];
934
1245
  }
935
- currentAd = ad;
936
- console.log("[HlsAdPlayer] Ad parsed: ".concat(ad.title, ", duration: ").concat(ad.duration, "s"));
937
- fireTrackingPixels(ad.trackingUrls.impression);
938
- trackingFired.impression = true;
1246
+ podAds = ads;
1247
+ podIndex = 0;
1248
+ currentAd = ads[0];
1249
+ console.log("[HlsAdPlayer] Pod parsed: ".concat(ads.length, ' ad(s), first="').concat(currentAd === null || currentAd === void 0 ? void 0 : currentAd.title, '", duration=').concat(currentAd === null || currentAd === void 0 ? void 0 : currentAd.duration, "s"));
1250
+ if (currentAd) {
1251
+ fireTrackingPixels(currentAd.trackingUrls.impression);
1252
+ trackingFired.impression = true;
1253
+ }
939
1254
  return [
940
1255
  2,
941
1256
  Promise.resolve()
@@ -958,7 +1273,7 @@ function createHlsAdPlayer(contentVideo, options) {
958
1273
  },
959
1274
  play: function play() {
960
1275
  return _async_to_generator(function() {
961
- var contentVolume, mediaFile, isHlsAd;
1276
+ var contentVolume;
962
1277
  return _ts_generator(this, function(_state) {
963
1278
  if (!currentAd) {
964
1279
  console.warn("[HlsAdPlayer] Cannot play: No ad loaded (no ads available)");
@@ -974,14 +1289,7 @@ function createHlsAdPlayer(contentVideo, options) {
974
1289
  adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.appendChild(adVideoElement);
975
1290
  setupAdEventListeners();
976
1291
  }
977
- trackingFired = {
978
- impression: trackingFired.impression,
979
- start: false,
980
- firstQuartile: false,
981
- midpoint: false,
982
- thirdQuartile: false,
983
- complete: false
984
- };
1292
+ resetQuartileTracking(true);
985
1293
  contentVolume = contentVideo.volume;
986
1294
  originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
987
1295
  if (!(options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds)) {
@@ -999,60 +1307,12 @@ function createHlsAdPlayer(contentVideo, options) {
999
1307
  adVideoElement.muted = originalMutedState;
1000
1308
  console.log("[HlsAdPlayer] Set ad video volume to ".concat(adVideoElement.volume, ", muted: ").concat(adVideoElement.muted, ", originalMutedState: ").concat(originalMutedState, ", contentVolume: ").concat(contentVolume));
1001
1309
  }
1002
- mediaFile = selectBestMediaFile(currentAd.mediaFiles);
1003
- if (!mediaFile) {
1004
- throw new Error("No media file available for ad");
1005
- }
1006
1310
  if (adContainerEl) {
1007
1311
  adContainerEl.style.display = "flex";
1008
1312
  adContainerEl.style.pointerEvents = "auto";
1009
1313
  }
1010
1314
  emit("content_pause");
1011
- isHlsAd = isHlsMediaFile(mediaFile);
1012
- console.log("[HlsAdPlayer] Loading ".concat(isHlsAd ? "HLS" : "progressive", " ad from: ").concat(mediaFile.url));
1013
- if (isHlsAd && Hls.isSupported()) {
1014
- if (adHls) {
1015
- adHls.destroy();
1016
- }
1017
- adHls = new Hls({
1018
- enableWorker: true,
1019
- lowLatencyMode: false
1020
- });
1021
- adHls.loadSource(mediaFile.url);
1022
- adHls.attachMedia(adVideoElement);
1023
- adHls.on(Hls.Events.MANIFEST_PARSED, function() {
1024
- console.log("[HlsAdPlayer] HLS manifest parsed, starting playback");
1025
- adVideoElement.play().catch(function(error) {
1026
- console.error("[HlsAdPlayer] Error starting ad playback:", error);
1027
- handleAdError();
1028
- });
1029
- });
1030
- adHls.on(Hls.Events.ERROR, function(event, data) {
1031
- console.error("[HlsAdPlayer] HLS error:", data);
1032
- if (data.fatal) {
1033
- handleAdError();
1034
- }
1035
- });
1036
- } else if (isHlsAd && adVideoElement.canPlayType("application/vnd.apple.mpegurl")) {
1037
- adVideoElement.src = mediaFile.url;
1038
- adVideoElement.play().catch(function(error) {
1039
- console.error("[HlsAdPlayer] Error starting ad playback:", error);
1040
- handleAdError();
1041
- });
1042
- } else if (!isHlsAd && isProgressiveMediaFile(mediaFile)) {
1043
- if (adHls) {
1044
- adHls.destroy();
1045
- adHls = void 0;
1046
- }
1047
- adVideoElement.src = mediaFile.url;
1048
- adVideoElement.load();
1049
- adVideoElement.play().catch(function(error) {
1050
- console.error("[HlsAdPlayer] Error starting progressive ad playback:", error);
1051
- handleAdError();
1052
- });
1053
- } else {
1054
- throw new Error("Unsupported ad media file type: ".concat(mediaFile.type));
1055
- }
1315
+ loadCurrentAdMedia();
1056
1316
  return [
1057
1317
  2,
1058
1318
  Promise.resolve()
@@ -1127,6 +1387,8 @@ function createHlsAdPlayer(contentVideo, options) {
1127
1387
  adVideoElement.src = "";
1128
1388
  }
1129
1389
  currentAd = void 0;
1390
+ podAds = [];
1391
+ podIndex = 0;
1130
1392
  return [
1131
1393
  2
1132
1394
  ];
@@ -1176,6 +1438,8 @@ function createHlsAdPlayer(contentVideo, options) {
1176
1438
  }
1177
1439
  adContainerEl = void 0;
1178
1440
  currentAd = void 0;
1441
+ podAds = [];
1442
+ podIndex = 0;
1179
1443
  listeners.clear();
1180
1444
  preloadedAds.clear();
1181
1445
  preloadingAds.clear();
@@ -1267,6 +1531,14 @@ function createHlsAdPlayer(contentVideo, options) {
1267
1531
  },
1268
1532
  getLoadedAdId: function getLoadedAdId() {
1269
1533
  return currentAd === null || currentAd === void 0 ? void 0 : currentAd.id;
1534
+ },
1535
+ getPodAdCount: function getPodAdCount() {
1536
+ return podAds.length;
1537
+ },
1538
+ getPodTotalDurationMs: function getPodTotalDurationMs() {
1539
+ return podAds.reduce(function(total, ad) {
1540
+ return total + (ad.duration > 0 ? ad.duration * 1e3 : 0);
1541
+ }, 0);
1270
1542
  }
1271
1543
  };
1272
1544
  }
@@ -3121,7 +3393,20 @@ function applyVastMacros(baseUrl, ctx) {
3121
3393
  if (ctx.pod != null) {
3122
3394
  params.set("pod", String(ctx.pod));
3123
3395
  }
3124
- if (ctx.adPosition != null) {
3396
+ var optimizedPodMode = ctx.podMaxAds != null || ctx.podMinDurationMs != null || ctx.podMaxDurationMs != null;
3397
+ if (optimizedPodMode) {
3398
+ params.delete("ppos");
3399
+ params.delete("lip");
3400
+ if (ctx.podMinDurationMs != null) {
3401
+ params.set("pmnd", String(Math.max(0, Math.round(ctx.podMinDurationMs))));
3402
+ }
3403
+ if (ctx.podMaxDurationMs != null) {
3404
+ params.set("pmxd", String(Math.max(0, Math.round(ctx.podMaxDurationMs))));
3405
+ }
3406
+ if (ctx.podMaxAds != null) {
3407
+ params.set("pmad", String(Math.max(1, Math.round(ctx.podMaxAds))));
3408
+ }
3409
+ } else if (ctx.adPosition != null) {
3125
3410
  params.set("ppos", String(ctx.adPosition));
3126
3411
  }
3127
3412
  var requestUrl = ctx.contentUrl || ctx.pageUrl;
@@ -4489,6 +4774,7 @@ var AdConfigManager = /*#__PURE__*/ function() {
4489
4774
  this.podAssignedByPrefetch = false;
4490
4775
  this.adRequestPositionInBreak = 0;
4491
4776
  this.lastHeartbeatTime = 0;
4777
+ this.defaultPodMaxAds = 6;
4492
4778
  this.config = config;
4493
4779
  this.video = video;
4494
4780
  }
@@ -4944,6 +5230,52 @@ var AdConfigManager = /*#__PURE__*/ function() {
4944
5230
  return urls;
4945
5231
  }
4946
5232
  },
5233
+ {
5234
+ key: "resolvePodParams",
5235
+ value: function resolvePodParams(breakDurationMs) {
5236
+ var maxDurationMs = breakDurationMs != null && breakDurationMs > 0 ? breakDurationMs : this.config.podMaxDurationMs;
5237
+ var maxAds = this.config.podMaxAds && this.config.podMaxAds > 0 ? this.config.podMaxAds : this.apiNumberAds && this.apiNumberAds > 0 ? this.apiNumberAds : this.defaultPodMaxAds;
5238
+ var minDurationMs = this.config.podExactDuration && maxDurationMs != null ? maxDurationMs : 0;
5239
+ return {
5240
+ maxAds: maxAds,
5241
+ minDurationMs: minDurationMs,
5242
+ maxDurationMs: maxDurationMs
5243
+ };
5244
+ }
5245
+ },
5246
+ {
5247
+ key: "generatePodVastUrl",
5248
+ value: function generatePodVastUrl(baseUrl, podParams, adPlayer, palNonce, inAdBreak) {
5249
+ var _podParams_maxDurationMs;
5250
+ var adWillPlayMuted = inAdBreak ? adPlayer.getOriginalMutedState() : this.video.muted;
5251
+ var envSignals = resolveVastEnvironmentSignals(!!this.config.ctvAdRequest);
5252
+ var urlWithMacros = applyVastMacros(baseUrl, {
5253
+ correlator: generateCorrelator(),
5254
+ streamCorrelator: this.streamCorrelator,
5255
+ pod: this.podCounter > 0 ? this.podCounter : void 0,
5256
+ podMaxAds: podParams.maxAds,
5257
+ podMinDurationMs: podParams.minDurationMs,
5258
+ podMaxDurationMs: podParams.maxDurationMs,
5259
+ isCtv: envSignals.isCtv,
5260
+ contentUrl: envSignals.contentUrl,
5261
+ pageUrl: !envSignals.isCtv && typeof window !== "undefined" ? window.location.href : void 0,
5262
+ adWillPlayMuted: adWillPlayMuted,
5263
+ adWillAutoPlay: !!this.config.autoplay,
5264
+ appId: envSignals.appId,
5265
+ appName: envSignals.appName,
5266
+ sessionId: envSignals.sessionId,
5267
+ deviceId: envSignals.deviceId,
5268
+ deviceIdType: envSignals.deviceIdType,
5269
+ limitAdTracking: envSignals.limitAdTracking,
5270
+ deviceTypeHint: envSignals.deviceTypeHint,
5271
+ adTest: this.config.adTest,
5272
+ consent: this.consentSignals
5273
+ });
5274
+ var finalUrl = palNonce.injectNonce(urlWithMacros);
5275
+ console.log("[StormcloudVideoPlayer] Resolved optimized-pod request URL (pod=".concat(this.podCounter, ", pmad=").concat(podParams.maxAds, ", pmnd=").concat(podParams.minDurationMs, ", pmxd=").concat((_podParams_maxDurationMs = podParams.maxDurationMs) !== null && _podParams_maxDurationMs !== void 0 ? _podParams_maxDurationMs : "?", "):"), finalUrl);
5276
+ return finalUrl;
5277
+ }
5278
+ },
4947
5279
  {
4948
5280
  // --- Tracking ---
4949
5281
  key: "initializeTracking",
@@ -5250,6 +5582,13 @@ var AdTimingService = /*#__PURE__*/ function() {
5250
5582
  this.lastAdRequestTime = Date.now();
5251
5583
  }
5252
5584
  },
5585
+ {
5586
+ key: "notePodAdStarted",
5587
+ value: function notePodAdStarted() {
5588
+ this.currentAdIndex++;
5589
+ this.totalAdsInBreak = this.currentAdIndex;
5590
+ }
5591
+ },
5253
5592
  {
5254
5593
  key: "getRemainingAdMs",
5255
5594
  value: function getRemainingAdMs() {
@@ -6762,13 +7101,26 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
6762
7101
  }
6763
7102
  },
6764
7103
  {
6765
- // ───────────────────────────────────────────────────────────────
7104
+ key: "optimizedPodsEnabled",
7105
+ get: // ───────────────────────────────────────────────────────────────
6766
7106
  // IMA event listeners
6767
7107
  // ───────────────────────────────────────────────────────────────
7108
+ function get() {
7109
+ return !!this.host.config.optimizedPods;
7110
+ }
7111
+ },
7112
+ {
6768
7113
  key: "attachImaEventListeners",
6769
7114
  value: function attachImaEventListeners() {
6770
7115
  var _this = this;
6771
7116
  var adPlayer = this.host.getAdPlayer();
7117
+ adPlayer.on("pod_ad_started", function(payload) {
7118
+ _this.timing.notePodAdStarted();
7119
+ if (_this.debug) {
7120
+ var _ref;
7121
+ console.log("[POD] Playing pod ad ".concat((payload === null || payload === void 0 ? void 0 : payload.index) != null ? payload.index + 1 : "?", "/").concat((_ref = payload === null || payload === void 0 ? void 0 : payload.total) !== null && _ref !== void 0 ? _ref : "?"));
7122
+ }
7123
+ });
6772
7124
  adPlayer.on("all_ads_completed", function() {
6773
7125
  sendAdImpressionTracking(_this.host.config.licenseKey, {
6774
7126
  source: "hls",
@@ -6926,7 +7278,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
6926
7278
  // ───────────────────────────────────────────────────────────────
6927
7279
  function handleAdStart(_marker) {
6928
7280
  return _async_to_generator(function() {
6929
- var scheduled, tags, baseVastUrl, adBreakDurationMs, mode, currentMuted, currentVolume, firstAdUrl, usePreloadedAd, preloadedController, preloaded, firstAdUrlArray, adPlayer, preservedMuted, preservedVolume, adVolume, adPlayer1, adVolume1, error, fallbackPreloaded, ap, adVolume2, fallbackError;
7281
+ var scheduled, tags, baseVastUrl, adBreakDurationMs, mode, currentMuted, currentVolume, podPlayed, firstAdUrl, usePreloadedAd, preloadedController, preloaded, firstAdUrlArray, adPlayer, preservedMuted, preservedVolume, adVolume, adPlayer1, adVolume1, error, fallbackPreloaded, ap, adVolume2, fallbackError;
6930
7282
  return _ts_generator(this, function(_state) {
6931
7283
  switch(_state.label){
6932
7284
  case 0:
@@ -6973,6 +7325,26 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
6973
7325
  if (this.timing.expectedAdBreakDurationMs == null && adBreakDurationMs != null) {
6974
7326
  this.timing.expectedAdBreakDurationMs = adBreakDurationMs;
6975
7327
  }
7328
+ if (!this.optimizedPodsEnabled) return [
7329
+ 3,
7330
+ 2
7331
+ ];
7332
+ return [
7333
+ 4,
7334
+ this.startOptimizedPod(baseVastUrl, adBreakDurationMs, currentMuted, currentVolume)
7335
+ ];
7336
+ case 1:
7337
+ podPlayed = _state.sent();
7338
+ if (podPlayed) {
7339
+ return [
7340
+ 2
7341
+ ];
7342
+ }
7343
+ if (this.debug) {
7344
+ console.log("[POD] Optimized pod unavailable, falling back to sequential single-ad path");
7345
+ }
7346
+ _state.label = 2;
7347
+ case 2:
6976
7348
  usePreloadedAd = false;
6977
7349
  preloaded = this.preloadPool.getPreloadedAd();
6978
7350
  if (preloaded) {
@@ -7014,21 +7386,21 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7014
7386
  if (this.debug) {
7015
7387
  console.log("[CONTINUOUS-FETCH] First VAST URL:", firstAdUrl);
7016
7388
  }
7017
- _state.label = 1;
7018
- case 1:
7389
+ _state.label = 3;
7390
+ case 3:
7019
7391
  _state.trys.push([
7020
- 1,
7021
- 12,
7392
+ 3,
7393
+ 14,
7022
7394
  ,
7023
- 20
7395
+ 22
7024
7396
  ]);
7025
7397
  if (!(usePreloadedAd && preloadedController)) return [
7026
7398
  3,
7027
- 5
7399
+ 7
7028
7400
  ];
7029
7401
  if (!!this.timing.ensureLoadedAdFitsBudget(preloadedController)) return [
7030
7402
  3,
7031
- 3
7403
+ 5
7032
7404
  ];
7033
7405
  this.timing.rejectLoadedAdForDuration(preloadedController);
7034
7406
  this.startContinuousFetching(baseVastUrl);
@@ -7036,12 +7408,12 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7036
7408
  4,
7037
7409
  this.tryNextAvailableAdWithRateLimit()
7038
7410
  ];
7039
- case 2:
7411
+ case 4:
7040
7412
  _state.sent();
7041
7413
  return [
7042
7414
  2
7043
7415
  ];
7044
- case 3:
7416
+ case 5:
7045
7417
  adPlayer = this.host.getAdPlayer();
7046
7418
  preservedMuted = adPlayer.getOriginalMutedState();
7047
7419
  preservedVolume = adPlayer.getOriginalVolume();
@@ -7066,7 +7438,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7066
7438
  4,
7067
7439
  preloadedController.play()
7068
7440
  ];
7069
- case 4:
7441
+ case 6:
7070
7442
  _state.sent();
7071
7443
  this.timing.markAdStarted();
7072
7444
  if (this.timing.expectedAdBreakDurationMs != null && this.timing.getAdBreakEndWallClockMs() == null) {
@@ -7076,22 +7448,22 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7076
7448
  preloadedController.setAdVolume(adVolume);
7077
7449
  return [
7078
7450
  3,
7079
- 11
7451
+ 13
7080
7452
  ];
7081
- case 5:
7453
+ case 7:
7082
7454
  adPlayer1 = this.host.getAdPlayer();
7083
7455
  return [
7084
7456
  4,
7085
7457
  this.timing.enforceGlobalRateLimit()
7086
7458
  ];
7087
- case 6:
7459
+ case 8:
7088
7460
  _state.sent();
7089
7461
  this.timing.lastAdRequestTime = Date.now();
7090
7462
  return [
7091
7463
  4,
7092
7464
  adPlayer1.requestAds(firstAdUrl)
7093
7465
  ];
7094
- case 7:
7466
+ case 9:
7095
7467
  _state.sent();
7096
7468
  sendAdLoadedTracking(this.host.config.licenseKey, {
7097
7469
  source: "hls",
@@ -7103,7 +7475,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7103
7475
  }
7104
7476
  if (!!this.timing.ensureLoadedAdFitsBudget(adPlayer1)) return [
7105
7477
  3,
7106
- 9
7478
+ 11
7107
7479
  ];
7108
7480
  this.timing.rejectLoadedAdForDuration(adPlayer1);
7109
7481
  this.recreateAdController();
@@ -7112,12 +7484,12 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7112
7484
  4,
7113
7485
  this.tryNextAvailableAdWithRateLimit()
7114
7486
  ];
7115
- case 8:
7487
+ case 10:
7116
7488
  _state.sent();
7117
7489
  return [
7118
7490
  2
7119
7491
  ];
7120
- case 9:
7492
+ case 11:
7121
7493
  this.timing.consecutiveFailures = 0;
7122
7494
  this.startContinuousFetching(baseVastUrl);
7123
7495
  if (!this.preloadPool.active) {
@@ -7127,7 +7499,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7127
7499
  4,
7128
7500
  adPlayer1.play()
7129
7501
  ];
7130
- case 10:
7502
+ case 12:
7131
7503
  _state.sent();
7132
7504
  this.timing.markAdStarted();
7133
7505
  if (this.timing.expectedAdBreakDurationMs != null && this.timing.getAdBreakEndWallClockMs() == null) {
@@ -7135,40 +7507,40 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7135
7507
  }
7136
7508
  adVolume1 = currentMuted ? 0 : currentVolume;
7137
7509
  adPlayer1.setAdVolume(adVolume1);
7138
- _state.label = 11;
7139
- case 11:
7510
+ _state.label = 13;
7511
+ case 13:
7140
7512
  return [
7141
7513
  3,
7142
- 20
7514
+ 22
7143
7515
  ];
7144
- case 12:
7516
+ case 14:
7145
7517
  error = _state.sent();
7146
7518
  if (this.debug) {
7147
7519
  console.warn("[CONTINUOUS-FETCH] First ad request failed:", error);
7148
7520
  }
7149
7521
  if (!!usePreloadedAd) return [
7150
7522
  3,
7151
- 18
7523
+ 20
7152
7524
  ];
7153
7525
  fallbackPreloaded = this.preloadPool.getPreloadedAd();
7154
7526
  if (!fallbackPreloaded) return [
7155
7527
  3,
7156
- 18
7528
+ 20
7157
7529
  ];
7158
7530
  if (this.debug) {
7159
7531
  console.log("[CONTINUOUS-FETCH] First ad failed, using preloaded fallback");
7160
7532
  }
7161
- _state.label = 13;
7162
- case 13:
7533
+ _state.label = 15;
7534
+ case 15:
7163
7535
  _state.trys.push([
7164
- 13,
7165
- 17,
7536
+ 15,
7537
+ 19,
7166
7538
  ,
7167
- 18
7539
+ 20
7168
7540
  ]);
7169
7541
  if (!!this.timing.ensureLoadedAdFitsBudget(fallbackPreloaded.adController)) return [
7170
7542
  3,
7171
- 15
7543
+ 17
7172
7544
  ];
7173
7545
  this.timing.rejectLoadedAdForDuration(fallbackPreloaded.adController);
7174
7546
  this.startContinuousFetching(baseVastUrl);
@@ -7176,12 +7548,12 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7176
7548
  4,
7177
7549
  this.tryNextAvailableAdWithRateLimit()
7178
7550
  ];
7179
- case 14:
7551
+ case 16:
7180
7552
  _state.sent();
7181
7553
  return [
7182
7554
  2
7183
7555
  ];
7184
- case 15:
7556
+ case 17:
7185
7557
  this.swapToPreloadedAdPlayer(fallbackPreloaded.adController);
7186
7558
  this.timing.consecutiveFailures = 0;
7187
7559
  this.startContinuousFetching(baseVastUrl);
@@ -7194,7 +7566,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7194
7566
  4,
7195
7567
  ap.play()
7196
7568
  ];
7197
- case 16:
7569
+ case 18:
7198
7570
  _state.sent();
7199
7571
  this.timing.markAdStarted();
7200
7572
  if (this.timing.expectedAdBreakDurationMs != null && this.timing.getAdBreakEndWallClockMs() == null) {
@@ -7205,16 +7577,16 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7205
7577
  return [
7206
7578
  2
7207
7579
  ];
7208
- case 17:
7580
+ case 19:
7209
7581
  fallbackError = _state.sent();
7210
7582
  if (this.debug) {
7211
7583
  console.warn("[CONTINUOUS-FETCH] Preloaded fallback also failed:", fallbackError);
7212
7584
  }
7213
7585
  return [
7214
7586
  3,
7215
- 18
7587
+ 20
7216
7588
  ];
7217
- case 18:
7589
+ case 20:
7218
7590
  if (this.timing.isTemporaryAdError(error)) {
7219
7591
  this.timing.temporaryFailureUrls.set(firstAdUrl, Date.now());
7220
7592
  if (this.debug) {
@@ -7232,13 +7604,137 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7232
7604
  4,
7233
7605
  this.tryNextAvailableAdWithRateLimit()
7234
7606
  ];
7235
- case 19:
7607
+ case 21:
7236
7608
  _state.sent();
7237
7609
  return [
7238
7610
  3,
7239
- 20
7611
+ 22
7240
7612
  ];
7241
- case 20:
7613
+ case 22:
7614
+ return [
7615
+ 2
7616
+ ];
7617
+ }
7618
+ });
7619
+ }).call(this);
7620
+ }
7621
+ },
7622
+ {
7623
+ key: "startOptimizedPod",
7624
+ value: // ───────────────────────────────────────────────────────────────
7625
+ // Optimized pod (single multi-ad request)
7626
+ // ───────────────────────────────────────────────────────────────
7627
+ function startOptimizedPod(baseVastUrl, breakDurationMs, currentMuted, currentVolume) {
7628
+ return _async_to_generator(function() {
7629
+ var podUrl, adPlayer, requestToken, _ref, _adPlayer_getPodAdCount, podCount, error;
7630
+ return _ts_generator(this, function(_state) {
7631
+ switch(_state.label){
7632
+ case 0:
7633
+ if (this.pendingAdBreak && this.pendingAdBreak.vastUrls.length > 0) {
7634
+ podUrl = this.pendingAdBreak.vastUrls[0];
7635
+ this.clearPendingAdBreak();
7636
+ } else {
7637
+ podUrl = this.host.generatePodVastUrl(baseVastUrl, breakDurationMs);
7638
+ }
7639
+ if (!podUrl) {
7640
+ return [
7641
+ 2,
7642
+ false
7643
+ ];
7644
+ }
7645
+ this.continuousFetchingActive = false;
7646
+ this.recreateAdController();
7647
+ adPlayer = this.host.getAdPlayer();
7648
+ requestToken = ++this.timing.adRequestTokenCounter;
7649
+ this.timing.activeAdRequestToken = requestToken;
7650
+ this.timing.startAdRequestWatchdog(requestToken);
7651
+ _state.label = 1;
7652
+ case 1:
7653
+ _state.trys.push([
7654
+ 1,
7655
+ 5,
7656
+ ,
7657
+ 6
7658
+ ]);
7659
+ return [
7660
+ 4,
7661
+ this.timing.enforceGlobalRateLimit()
7662
+ ];
7663
+ case 2:
7664
+ _state.sent();
7665
+ this.timing.lastAdRequestTime = Date.now();
7666
+ return [
7667
+ 4,
7668
+ adPlayer.requestAds(podUrl)
7669
+ ];
7670
+ case 3:
7671
+ _state.sent();
7672
+ this.timing.clearAdRequestWatchdog();
7673
+ if (this.timing.activeAdRequestToken !== requestToken) {
7674
+ return [
7675
+ 2,
7676
+ true
7677
+ ];
7678
+ }
7679
+ podCount = (_ref = (_adPlayer_getPodAdCount = adPlayer.getPodAdCount) === null || _adPlayer_getPodAdCount === void 0 ? void 0 : _adPlayer_getPodAdCount.call(adPlayer)) !== null && _ref !== void 0 ? _ref : 1;
7680
+ if (podCount < 1) {
7681
+ return [
7682
+ 2,
7683
+ false
7684
+ ];
7685
+ }
7686
+ if (this.debug) {
7687
+ console.log(podCount === 1 ? "[POD] Response contained a single ad; playing it and enabling sequential top-up" : "[POD] Optimized pod returned ".concat(podCount, " ads; playing pod in one controller"));
7688
+ }
7689
+ sendAdLoadedTracking(this.host.config.licenseKey, {
7690
+ source: "hls",
7691
+ vastUrl: podUrl,
7692
+ timestamp: /* @__PURE__ */ new Date().toISOString()
7693
+ }, this.analyticsContext).catch(function() {});
7694
+ this.timing.startAdFailsafeTimer(requestToken);
7695
+ return [
7696
+ 4,
7697
+ adPlayer.play()
7698
+ ];
7699
+ case 4:
7700
+ _state.sent();
7701
+ this.timing.markAdStarted();
7702
+ if (this.timing.expectedAdBreakDurationMs != null && this.timing.getAdBreakEndWallClockMs() == null) {
7703
+ this.timing.scheduleAdStopAtBreakBoundary();
7704
+ }
7705
+ adPlayer.setAdVolume(currentMuted ? 0 : currentVolume);
7706
+ this.timing.consecutiveFailures = 0;
7707
+ if (podCount === 1) {
7708
+ this.continuousFetchingActive = true;
7709
+ this.startContinuousFetching(baseVastUrl);
7710
+ if (!this.preloadPool.active) {
7711
+ this.preloadPool.startPreloadPool(baseVastUrl, []);
7712
+ }
7713
+ }
7714
+ return [
7715
+ 2,
7716
+ true
7717
+ ];
7718
+ case 5:
7719
+ error = _state.sent();
7720
+ this.timing.clearAdRequestWatchdog();
7721
+ this.timing.clearAdFailsafeTimer();
7722
+ if (this.timing.activeAdRequestToken === requestToken) {
7723
+ this.timing.activeAdRequestToken = null;
7724
+ }
7725
+ if (this.debug) {
7726
+ console.warn("[POD] Optimized pod request/play failed:", error);
7727
+ }
7728
+ if (this.timing.isTemporaryAdError(error)) {
7729
+ this.timing.temporaryFailureUrls.set(podUrl, Date.now());
7730
+ }
7731
+ this.continuousFetchingActive = true;
7732
+ this.recreateAdController();
7733
+ return [
7734
+ 2,
7735
+ false
7736
+ ];
7737
+ case 6:
7242
7738
  return [
7243
7739
  2
7244
7740
  ];
@@ -8321,6 +8817,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8321
8817
  },
8322
8818
  generateVastUrls: function generateVastUrls(base, count) {
8323
8819
  return _this.generateVastUrls(base, count);
8820
+ },
8821
+ generatePodVastUrl: function generatePodVastUrl(base, breakDurationMs) {
8822
+ return _this.generatePodVastUrl(base, breakDurationMs);
8324
8823
  }
8325
8824
  }, this.timing, this.preloadPool, this.adConfig, this.cueManager, this.placeholder);
8326
8825
  }
@@ -8353,6 +8852,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8353
8852
  return this.adConfig.generateVastUrlsWithCorrelators(baseUrl, count, this.adPlayer, this.palNonce, this.adBreak.inAdBreak);
8354
8853
  }
8355
8854
  },
8855
+ {
8856
+ key: "generatePodVastUrl",
8857
+ value: function generatePodVastUrl(baseUrl, breakDurationMs) {
8858
+ var podParams = this.adConfig.resolvePodParams(breakDurationMs);
8859
+ return this.adConfig.generatePodVastUrl(baseUrl, podParams, this.adPlayer, this.palNonce, this.adBreak.inAdBreak);
8860
+ }
8861
+ },
8356
8862
  {
8357
8863
  key: "load",
8358
8864
  value: // ───────────────────────────────────────────────────────────────
@@ -8741,7 +9247,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8741
9247
  }
8742
9248
  this.adConfig.beginNewAdPod();
8743
9249
  this.adConfig.podAssignedByPrefetch = true;
8744
- var generatedUrls = this.generateVastUrls(baseVastUrl, 1);
9250
+ var optimizedPods = !!this.config.optimizedPods;
9251
+ var breakDurationMs = marker.durationSeconds != null ? marker.durationSeconds * 1e3 : void 0;
9252
+ var generatedUrls = optimizedPods ? [
9253
+ this.generatePodVastUrl(baseVastUrl, breakDurationMs)
9254
+ ] : this.generateVastUrls(baseVastUrl, 1);
8745
9255
  this.adBreak.pendingAdBreak = _object_spread_props(_object_spread({
8746
9256
  marker: marker
8747
9257
  }, fragmentSn !== void 0 ? {
@@ -8763,7 +9273,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8763
9273
  }, detectPayload), buildAnalyticsContext(this.config)).catch(function() {});
8764
9274
  if (this.debug) {
8765
9275
  console.log("[PREFETCH] Starting ad prefetch for upcoming ad break");
8766
- console.log("[PREFETCH] Pre-generated ".concat(generatedUrls.length, " VAST URLs"));
9276
+ console.log("[PREFETCH] Pre-generated ".concat(generatedUrls.length, " ").concat(optimizedPods ? "pod" : "VAST", " URL(s)"));
9277
+ }
9278
+ if (optimizedPods) {
9279
+ if (this.debug) {
9280
+ console.log("[PREFETCH] Optimized pods enabled - skipping single-ad preload pool");
9281
+ }
9282
+ return;
8767
9283
  }
8768
9284
  this.preloadPool.startPreloadPool(baseVastUrl, generatedUrls.slice(0, 1), false);
8769
9285
  }