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
@@ -361,6 +361,8 @@ function createHlsAdPlayer(contentVideo, options) {
361
361
  var adHls;
362
362
  var adContainerEl;
363
363
  var currentAd;
364
+ var podAds = [];
365
+ var podIndex = 0;
364
366
  var sessionId;
365
367
  var preloadedAds = /* @__PURE__ */ new Map();
366
368
  var preloadingAds = /* @__PURE__ */ new Map();
@@ -525,14 +527,14 @@ function createHlsAdPlayer(contentVideo, options) {
525
527
  error: []
526
528
  };
527
529
  }
528
- function extractTrackingUrls(xmlDoc) {
530
+ function extractTrackingUrls(scope) {
529
531
  var trackingUrls = createEmptyTrackingUrls();
530
- xmlDoc.querySelectorAll("Impression").forEach(function(el) {
532
+ scope.querySelectorAll("Impression").forEach(function(el) {
531
533
  var _el_textContent;
532
534
  var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
533
535
  if (url) trackingUrls.impression.push(url);
534
536
  });
535
- xmlDoc.querySelectorAll("Tracking").forEach(function(el) {
537
+ scope.querySelectorAll("Tracking").forEach(function(el) {
536
538
  var _el_textContent;
537
539
  var event = el.getAttribute("event");
538
540
  var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
@@ -543,7 +545,7 @@ function createHlsAdPlayer(contentVideo, options) {
543
545
  }
544
546
  }
545
547
  });
546
- xmlDoc.querySelectorAll("Error").forEach(function(el) {
548
+ scope.querySelectorAll("Error").forEach(function(el) {
547
549
  var _el_textContent;
548
550
  var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
549
551
  if (url) trackingUrls.error.push(url);
@@ -653,6 +655,75 @@ function createHlsAdPlayer(contentVideo, options) {
653
655
  };
654
656
  }
655
657
  }
658
+ function parseAdElement(adElement) {
659
+ try {
660
+ var _adElement_querySelector, _adElement_querySelector_textContent, _adElement_querySelector1, _adElement_querySelector_textContent1, _adElement_querySelector2, _adElement_querySelector3;
661
+ var adId = adElement.getAttribute("id") || "unknown";
662
+ var title = ((_adElement_querySelector = adElement.querySelector("AdTitle")) === null || _adElement_querySelector === void 0 ? void 0 : _adElement_querySelector.textContent) || "Ad";
663
+ 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();
664
+ 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();
665
+ if (wrapperUri) {
666
+ return {
667
+ type: "wrapper",
668
+ vastAdTagUri: wrapperUri,
669
+ trackingUrls: extractTrackingUrls(adElement),
670
+ clickThrough: clickThrough
671
+ };
672
+ }
673
+ var isNoAdAvailable = adId === "empty" || title.toLowerCase().includes("no ad available") || title.toLowerCase() === "no ad available";
674
+ var durationText = ((_adElement_querySelector3 = adElement.querySelector("Duration")) === null || _adElement_querySelector3 === void 0 ? void 0 : _adElement_querySelector3.textContent) || "00:00:30";
675
+ var durationParts = durationText.split(":");
676
+ var duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseInt(durationParts[2] || "0", 10);
677
+ var mediaFileElements = adElement.querySelectorAll("MediaFile");
678
+ var mediaFiles = [];
679
+ mediaFileElements.forEach(function(mf) {
680
+ var _mf_textContent;
681
+ var type = mf.getAttribute("type") || "";
682
+ var url = ((_mf_textContent = mf.textContent) === null || _mf_textContent === void 0 ? void 0 : _mf_textContent.trim()) || "";
683
+ var width = mf.getAttribute("width") || "";
684
+ var height = mf.getAttribute("height") || "";
685
+ if (!url) return;
686
+ var bitrateAttr = mf.getAttribute("bitrate");
687
+ var bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;
688
+ var mediaFile = {
689
+ url: url,
690
+ type: type,
691
+ width: parseInt(width || "1920", 10),
692
+ height: parseInt(height || "1080", 10),
693
+ bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : void 0
694
+ };
695
+ if (isHlsMediaFile(mediaFile) || isProgressiveMediaFile(mediaFile)) {
696
+ mediaFiles.push(mediaFile);
697
+ }
698
+ });
699
+ if (mediaFiles.length === 0) {
700
+ if (isNoAdAvailable) {
701
+ console.warn("[HlsAdPlayer] Pod <Ad> indicates no ad available");
702
+ } else {
703
+ console.warn("[HlsAdPlayer] No supported media files in pod <Ad>");
704
+ }
705
+ return {
706
+ type: "empty"
707
+ };
708
+ }
709
+ return {
710
+ type: "inline",
711
+ ad: {
712
+ id: adId,
713
+ title: title,
714
+ duration: duration,
715
+ mediaFiles: mediaFiles,
716
+ trackingUrls: extractTrackingUrls(adElement),
717
+ clickThrough: clickThrough
718
+ }
719
+ };
720
+ } catch (error) {
721
+ console.error("[HlsAdPlayer] Error parsing pod <Ad> element:", error);
722
+ return {
723
+ type: "empty"
724
+ };
725
+ }
726
+ }
656
727
  function fetchVastXml(vastTagUrl) {
657
728
  return _async_to_generator(function() {
658
729
  var response;
@@ -729,6 +800,146 @@ function createHlsAdPlayer(contentVideo, options) {
729
800
  });
730
801
  }).apply(this, arguments);
731
802
  }
803
+ function fetchAndParsePod(vastTagUrl) {
804
+ return _async_to_generator(function() {
805
+ var vastXml, parser, xmlDoc, adElements, ads, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, adElement, parsed, resolved, error, err;
806
+ return _ts_generator(this, function(_state) {
807
+ switch(_state.label){
808
+ case 0:
809
+ return [
810
+ 4,
811
+ fetchVastXml(vastTagUrl)
812
+ ];
813
+ case 1:
814
+ vastXml = _state.sent();
815
+ console.log("[HlsAdPlayer] Pod VAST XML received");
816
+ parser = new DOMParser();
817
+ xmlDoc = parser.parseFromString(vastXml, "text/xml");
818
+ if (xmlDoc.querySelector("parsererror")) {
819
+ console.error("[HlsAdPlayer] Pod VAST XML parsing error (malformed)");
820
+ return [
821
+ 2,
822
+ []
823
+ ];
824
+ }
825
+ adElements = Array.from(xmlDoc.querySelectorAll("Ad"));
826
+ if (adElements.length === 0) {
827
+ console.warn("[HlsAdPlayer] No <Ad> elements found in pod VAST response");
828
+ return [
829
+ 2,
830
+ []
831
+ ];
832
+ }
833
+ adElements.sort(function(a, b) {
834
+ var aSeq = parseInt(a.getAttribute("sequence") || "", 10);
835
+ var bSeq = parseInt(b.getAttribute("sequence") || "", 10);
836
+ var aVal = Number.isFinite(aSeq) ? aSeq : Number.MAX_SAFE_INTEGER;
837
+ var bVal = Number.isFinite(bSeq) ? bSeq : Number.MAX_SAFE_INTEGER;
838
+ return aVal - bVal;
839
+ });
840
+ ads = [];
841
+ _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
842
+ _state.label = 2;
843
+ case 2:
844
+ _state.trys.push([
845
+ 2,
846
+ 10,
847
+ 11,
848
+ 12
849
+ ]);
850
+ _iterator = adElements[Symbol.iterator]();
851
+ _state.label = 3;
852
+ case 3:
853
+ if (!!(_iteratorNormalCompletion = (_step = _iterator.next()).done)) return [
854
+ 3,
855
+ 9
856
+ ];
857
+ adElement = _step.value;
858
+ parsed = parseAdElement(adElement);
859
+ if (!(parsed.type === "inline")) return [
860
+ 3,
861
+ 4
862
+ ];
863
+ ads.push(parsed.ad);
864
+ return [
865
+ 3,
866
+ 8
867
+ ];
868
+ case 4:
869
+ if (!(parsed.type === "wrapper")) return [
870
+ 3,
871
+ 8
872
+ ];
873
+ _state.label = 5;
874
+ case 5:
875
+ _state.trys.push([
876
+ 5,
877
+ 7,
878
+ ,
879
+ 8
880
+ ]);
881
+ return [
882
+ 4,
883
+ fetchAndParseVastAd(parsed.vastAdTagUri, 1, parsed.trackingUrls)
884
+ ];
885
+ case 6:
886
+ resolved = _state.sent();
887
+ if (resolved) {
888
+ ads.push(resolved);
889
+ }
890
+ return [
891
+ 3,
892
+ 8
893
+ ];
894
+ case 7:
895
+ error = _state.sent();
896
+ console.warn("[HlsAdPlayer] Failed to resolve wrapper <Ad> in pod:", error);
897
+ return [
898
+ 3,
899
+ 8
900
+ ];
901
+ case 8:
902
+ _iteratorNormalCompletion = true;
903
+ return [
904
+ 3,
905
+ 3
906
+ ];
907
+ case 9:
908
+ return [
909
+ 3,
910
+ 12
911
+ ];
912
+ case 10:
913
+ err = _state.sent();
914
+ _didIteratorError = true;
915
+ _iteratorError = err;
916
+ return [
917
+ 3,
918
+ 12
919
+ ];
920
+ case 11:
921
+ try {
922
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
923
+ _iterator.return();
924
+ }
925
+ } finally{
926
+ if (_didIteratorError) {
927
+ throw _iteratorError;
928
+ }
929
+ }
930
+ return [
931
+ 7
932
+ ];
933
+ case 12:
934
+ console.log("[HlsAdPlayer] Parsed ".concat(ads.length, " ad(s) from pod VAST response"));
935
+ return [
936
+ 2,
937
+ ads
938
+ ];
939
+ }
940
+ });
941
+ })();
942
+ }
732
943
  function createAdVideoElement() {
733
944
  var video = document.createElement("video");
734
945
  video.style.position = "absolute";
@@ -773,6 +984,9 @@ function createHlsAdPlayer(contentVideo, options) {
773
984
  trackingFired.complete = true;
774
985
  fireTrackingPixels(currentAd.trackingUrls.complete);
775
986
  console.log("[HlsAdPlayer] Ad completed");
987
+ if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
988
+ return;
989
+ }
776
990
  handleAdComplete();
777
991
  });
778
992
  adVideoElement.addEventListener("error", function(e) {
@@ -781,6 +995,9 @@ function createHlsAdPlayer(contentVideo, options) {
781
995
  if (currentAd) {
782
996
  fireTrackingPixels(currentAd.trackingUrls.error);
783
997
  }
998
+ if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
999
+ return;
1000
+ }
784
1001
  handleAdError();
785
1002
  });
786
1003
  adVideoElement.addEventListener("volumechange", function() {
@@ -809,6 +1026,94 @@ function createHlsAdPlayer(contentVideo, options) {
809
1026
  delete contentVideo.dataset.stormcloudAdPlaying;
810
1027
  }
811
1028
  }
1029
+ function resetQuartileTracking(preserveImpression) {
1030
+ trackingFired = {
1031
+ impression: preserveImpression ? trackingFired.impression : false,
1032
+ start: false,
1033
+ firstQuartile: false,
1034
+ midpoint: false,
1035
+ thirdQuartile: false,
1036
+ complete: false
1037
+ };
1038
+ }
1039
+ function loadCurrentAdMedia() {
1040
+ if (!adVideoElement || !currentAd) {
1041
+ throw new Error("No ad video element or ad to load");
1042
+ }
1043
+ var mediaFile = selectBestMediaFile(currentAd.mediaFiles);
1044
+ if (!mediaFile) {
1045
+ throw new Error("No media file available for ad");
1046
+ }
1047
+ var isHlsAd = isHlsMediaFile(mediaFile);
1048
+ console.log("[HlsAdPlayer] Loading ".concat(isHlsAd ? "HLS" : "progressive", " ad (pod ").concat(podIndex + 1, "/").concat(podAds.length || 1, ") from: ").concat(mediaFile.url));
1049
+ if (isHlsAd && import_hls.default.isSupported()) {
1050
+ if (adHls) {
1051
+ adHls.destroy();
1052
+ }
1053
+ adHls = new import_hls.default({
1054
+ enableWorker: true,
1055
+ lowLatencyMode: false
1056
+ });
1057
+ adHls.loadSource(mediaFile.url);
1058
+ adHls.attachMedia(adVideoElement);
1059
+ adHls.on(import_hls.default.Events.MANIFEST_PARSED, function() {
1060
+ console.log("[HlsAdPlayer] HLS manifest parsed, starting playback");
1061
+ adVideoElement.play().catch(function(error) {
1062
+ console.error("[HlsAdPlayer] Error starting ad playback:", error);
1063
+ handleAdError();
1064
+ });
1065
+ });
1066
+ adHls.on(import_hls.default.Events.ERROR, function(_event, data) {
1067
+ console.error("[HlsAdPlayer] HLS error:", data);
1068
+ if (data.fatal) {
1069
+ handleAdError();
1070
+ }
1071
+ });
1072
+ } else if (isHlsAd && adVideoElement.canPlayType("application/vnd.apple.mpegurl")) {
1073
+ adVideoElement.src = mediaFile.url;
1074
+ adVideoElement.play().catch(function(error) {
1075
+ console.error("[HlsAdPlayer] Error starting ad playback:", error);
1076
+ handleAdError();
1077
+ });
1078
+ } else if (!isHlsAd && isProgressiveMediaFile(mediaFile)) {
1079
+ if (adHls) {
1080
+ adHls.destroy();
1081
+ adHls = void 0;
1082
+ }
1083
+ adVideoElement.src = mediaFile.url;
1084
+ adVideoElement.load();
1085
+ adVideoElement.play().catch(function(error) {
1086
+ console.error("[HlsAdPlayer] Error starting progressive ad playback:", error);
1087
+ handleAdError();
1088
+ });
1089
+ } else {
1090
+ throw new Error("Unsupported ad media file type: ".concat(mediaFile.type));
1091
+ }
1092
+ }
1093
+ function advanceToNextPodAd() {
1094
+ if (podIndex >= podAds.length - 1) {
1095
+ return false;
1096
+ }
1097
+ podIndex++;
1098
+ currentAd = podAds[podIndex];
1099
+ resetQuartileTracking(false);
1100
+ if (currentAd) {
1101
+ fireTrackingPixels(currentAd.trackingUrls.impression);
1102
+ trackingFired.impression = true;
1103
+ console.log("[HlsAdPlayer] Advancing to next pod ad (".concat(podIndex + 1, "/").concat(podAds.length, "): ").concat(currentAd.title, ", duration: ").concat(currentAd.duration, "s"));
1104
+ }
1105
+ try {
1106
+ loadCurrentAdMedia();
1107
+ emit("pod_ad_started", {
1108
+ index: podIndex,
1109
+ total: podAds.length
1110
+ });
1111
+ return true;
1112
+ } catch (error) {
1113
+ console.error("[HlsAdPlayer] Failed to load next pod ad:", error);
1114
+ return false;
1115
+ }
1116
+ }
812
1117
  function handleAdComplete() {
813
1118
  console.log("[HlsAdPlayer] Handling ad completion");
814
1119
  adPlaying = false;
@@ -862,7 +1167,7 @@ function createHlsAdPlayer(contentVideo, options) {
862
1167
  },
863
1168
  requestAds: function requestAds(vastTagUrl) {
864
1169
  return _async_to_generator(function() {
865
- var ad, error;
1170
+ var ads, preloaded, error;
866
1171
  return _ts_generator(this, function(_state) {
867
1172
  switch(_state.label){
868
1173
  case 0:
@@ -883,12 +1188,18 @@ function createHlsAdPlayer(contentVideo, options) {
883
1188
  6
884
1189
  ]);
885
1190
  sessionId = generateSessionId();
1191
+ ads = [];
886
1192
  if (!preloadedAds.has(vastTagUrl)) return [
887
1193
  3,
888
1194
  2
889
1195
  ];
890
- ad = preloadedAds.get(vastTagUrl);
1196
+ preloaded = preloadedAds.get(vastTagUrl);
891
1197
  preloadedAds.delete(vastTagUrl);
1198
+ if (preloaded) {
1199
+ ads = [
1200
+ preloaded
1201
+ ];
1202
+ }
892
1203
  console.log("[HlsAdPlayer] Using preloaded VAST response:", vastTagUrl);
893
1204
  return [
894
1205
  3,
@@ -897,13 +1208,13 @@ function createHlsAdPlayer(contentVideo, options) {
897
1208
  case 2:
898
1209
  return [
899
1210
  4,
900
- fetchAndParseVastAd(vastTagUrl)
1211
+ fetchAndParsePod(vastTagUrl)
901
1212
  ];
902
1213
  case 3:
903
- ad = _state.sent();
1214
+ ads = _state.sent();
904
1215
  _state.label = 4;
905
1216
  case 4:
906
- if (!ad) {
1217
+ if (!ads.length) {
907
1218
  console.warn("[HlsAdPlayer] No ads available from VAST response");
908
1219
  emit("ad_error");
909
1220
  return [
@@ -911,10 +1222,14 @@ function createHlsAdPlayer(contentVideo, options) {
911
1222
  Promise.reject(new Error("No ads available from VAST response"))
912
1223
  ];
913
1224
  }
914
- currentAd = ad;
915
- console.log("[HlsAdPlayer] Ad parsed: ".concat(ad.title, ", duration: ").concat(ad.duration, "s"));
916
- fireTrackingPixels(ad.trackingUrls.impression);
917
- trackingFired.impression = true;
1225
+ podAds = ads;
1226
+ podIndex = 0;
1227
+ currentAd = ads[0];
1228
+ 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"));
1229
+ if (currentAd) {
1230
+ fireTrackingPixels(currentAd.trackingUrls.impression);
1231
+ trackingFired.impression = true;
1232
+ }
918
1233
  return [
919
1234
  2,
920
1235
  Promise.resolve()
@@ -937,7 +1252,7 @@ function createHlsAdPlayer(contentVideo, options) {
937
1252
  },
938
1253
  play: function play() {
939
1254
  return _async_to_generator(function() {
940
- var contentVolume, mediaFile, isHlsAd;
1255
+ var contentVolume;
941
1256
  return _ts_generator(this, function(_state) {
942
1257
  if (!currentAd) {
943
1258
  console.warn("[HlsAdPlayer] Cannot play: No ad loaded (no ads available)");
@@ -953,14 +1268,7 @@ function createHlsAdPlayer(contentVideo, options) {
953
1268
  adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.appendChild(adVideoElement);
954
1269
  setupAdEventListeners();
955
1270
  }
956
- trackingFired = {
957
- impression: trackingFired.impression,
958
- start: false,
959
- firstQuartile: false,
960
- midpoint: false,
961
- thirdQuartile: false,
962
- complete: false
963
- };
1271
+ resetQuartileTracking(true);
964
1272
  contentVolume = contentVideo.volume;
965
1273
  originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
966
1274
  if (!(options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds)) {
@@ -978,60 +1286,12 @@ function createHlsAdPlayer(contentVideo, options) {
978
1286
  adVideoElement.muted = originalMutedState;
979
1287
  console.log("[HlsAdPlayer] Set ad video volume to ".concat(adVideoElement.volume, ", muted: ").concat(adVideoElement.muted, ", originalMutedState: ").concat(originalMutedState, ", contentVolume: ").concat(contentVolume));
980
1288
  }
981
- mediaFile = selectBestMediaFile(currentAd.mediaFiles);
982
- if (!mediaFile) {
983
- throw new Error("No media file available for ad");
984
- }
985
1289
  if (adContainerEl) {
986
1290
  adContainerEl.style.display = "flex";
987
1291
  adContainerEl.style.pointerEvents = "auto";
988
1292
  }
989
1293
  emit("content_pause");
990
- isHlsAd = isHlsMediaFile(mediaFile);
991
- console.log("[HlsAdPlayer] Loading ".concat(isHlsAd ? "HLS" : "progressive", " ad from: ").concat(mediaFile.url));
992
- if (isHlsAd && import_hls.default.isSupported()) {
993
- if (adHls) {
994
- adHls.destroy();
995
- }
996
- adHls = new import_hls.default({
997
- enableWorker: true,
998
- lowLatencyMode: false
999
- });
1000
- adHls.loadSource(mediaFile.url);
1001
- adHls.attachMedia(adVideoElement);
1002
- adHls.on(import_hls.default.Events.MANIFEST_PARSED, function() {
1003
- console.log("[HlsAdPlayer] HLS manifest parsed, starting playback");
1004
- adVideoElement.play().catch(function(error) {
1005
- console.error("[HlsAdPlayer] Error starting ad playback:", error);
1006
- handleAdError();
1007
- });
1008
- });
1009
- adHls.on(import_hls.default.Events.ERROR, function(event, data) {
1010
- console.error("[HlsAdPlayer] HLS error:", data);
1011
- if (data.fatal) {
1012
- handleAdError();
1013
- }
1014
- });
1015
- } else if (isHlsAd && adVideoElement.canPlayType("application/vnd.apple.mpegurl")) {
1016
- adVideoElement.src = mediaFile.url;
1017
- adVideoElement.play().catch(function(error) {
1018
- console.error("[HlsAdPlayer] Error starting ad playback:", error);
1019
- handleAdError();
1020
- });
1021
- } else if (!isHlsAd && isProgressiveMediaFile(mediaFile)) {
1022
- if (adHls) {
1023
- adHls.destroy();
1024
- adHls = void 0;
1025
- }
1026
- adVideoElement.src = mediaFile.url;
1027
- adVideoElement.load();
1028
- adVideoElement.play().catch(function(error) {
1029
- console.error("[HlsAdPlayer] Error starting progressive ad playback:", error);
1030
- handleAdError();
1031
- });
1032
- } else {
1033
- throw new Error("Unsupported ad media file type: ".concat(mediaFile.type));
1034
- }
1294
+ loadCurrentAdMedia();
1035
1295
  return [
1036
1296
  2,
1037
1297
  Promise.resolve()
@@ -1106,6 +1366,8 @@ function createHlsAdPlayer(contentVideo, options) {
1106
1366
  adVideoElement.src = "";
1107
1367
  }
1108
1368
  currentAd = void 0;
1369
+ podAds = [];
1370
+ podIndex = 0;
1109
1371
  return [
1110
1372
  2
1111
1373
  ];
@@ -1155,6 +1417,8 @@ function createHlsAdPlayer(contentVideo, options) {
1155
1417
  }
1156
1418
  adContainerEl = void 0;
1157
1419
  currentAd = void 0;
1420
+ podAds = [];
1421
+ podIndex = 0;
1158
1422
  listeners.clear();
1159
1423
  preloadedAds.clear();
1160
1424
  preloadingAds.clear();
@@ -1246,6 +1510,14 @@ function createHlsAdPlayer(contentVideo, options) {
1246
1510
  },
1247
1511
  getLoadedAdId: function getLoadedAdId() {
1248
1512
  return currentAd === null || currentAd === void 0 ? void 0 : currentAd.id;
1513
+ },
1514
+ getPodAdCount: function getPodAdCount() {
1515
+ return podAds.length;
1516
+ },
1517
+ getPodTotalDurationMs: function getPodTotalDurationMs() {
1518
+ return podAds.reduce(function(total, ad) {
1519
+ return total + (ad.duration > 0 ? ad.duration * 1e3 : 0);
1520
+ }, 0);
1249
1521
  }
1250
1522
  };
1251
1523
  }
@@ -3074,7 +3346,20 @@ function applyVastMacros(baseUrl, ctx) {
3074
3346
  if (ctx.pod != null) {
3075
3347
  params.set("pod", String(ctx.pod));
3076
3348
  }
3077
- if (ctx.adPosition != null) {
3349
+ var optimizedPodMode = ctx.podMaxAds != null || ctx.podMinDurationMs != null || ctx.podMaxDurationMs != null;
3350
+ if (optimizedPodMode) {
3351
+ params.delete("ppos");
3352
+ params.delete("lip");
3353
+ if (ctx.podMinDurationMs != null) {
3354
+ params.set("pmnd", String(Math.max(0, Math.round(ctx.podMinDurationMs))));
3355
+ }
3356
+ if (ctx.podMaxDurationMs != null) {
3357
+ params.set("pmxd", String(Math.max(0, Math.round(ctx.podMaxDurationMs))));
3358
+ }
3359
+ if (ctx.podMaxAds != null) {
3360
+ params.set("pmad", String(Math.max(1, Math.round(ctx.podMaxAds))));
3361
+ }
3362
+ } else if (ctx.adPosition != null) {
3078
3363
  params.set("ppos", String(ctx.adPosition));
3079
3364
  }
3080
3365
  var requestUrl = ctx.contentUrl || ctx.pageUrl;
@@ -4416,6 +4701,7 @@ var AdConfigManager = /*#__PURE__*/ function() {
4416
4701
  this.podAssignedByPrefetch = false;
4417
4702
  this.adRequestPositionInBreak = 0;
4418
4703
  this.lastHeartbeatTime = 0;
4704
+ this.defaultPodMaxAds = 6;
4419
4705
  this.config = config;
4420
4706
  this.video = video;
4421
4707
  }
@@ -4871,6 +5157,52 @@ var AdConfigManager = /*#__PURE__*/ function() {
4871
5157
  return urls;
4872
5158
  }
4873
5159
  },
5160
+ {
5161
+ key: "resolvePodParams",
5162
+ value: function resolvePodParams(breakDurationMs) {
5163
+ var maxDurationMs = breakDurationMs != null && breakDurationMs > 0 ? breakDurationMs : this.config.podMaxDurationMs;
5164
+ var maxAds = this.config.podMaxAds && this.config.podMaxAds > 0 ? this.config.podMaxAds : this.apiNumberAds && this.apiNumberAds > 0 ? this.apiNumberAds : this.defaultPodMaxAds;
5165
+ var minDurationMs = this.config.podExactDuration && maxDurationMs != null ? maxDurationMs : 0;
5166
+ return {
5167
+ maxAds: maxAds,
5168
+ minDurationMs: minDurationMs,
5169
+ maxDurationMs: maxDurationMs
5170
+ };
5171
+ }
5172
+ },
5173
+ {
5174
+ key: "generatePodVastUrl",
5175
+ value: function generatePodVastUrl(baseUrl, podParams, adPlayer, palNonce, inAdBreak) {
5176
+ var _podParams_maxDurationMs;
5177
+ var adWillPlayMuted = inAdBreak ? adPlayer.getOriginalMutedState() : this.video.muted;
5178
+ var envSignals = resolveVastEnvironmentSignals(!!this.config.ctvAdRequest);
5179
+ var urlWithMacros = applyVastMacros(baseUrl, {
5180
+ correlator: generateCorrelator(),
5181
+ streamCorrelator: this.streamCorrelator,
5182
+ pod: this.podCounter > 0 ? this.podCounter : void 0,
5183
+ podMaxAds: podParams.maxAds,
5184
+ podMinDurationMs: podParams.minDurationMs,
5185
+ podMaxDurationMs: podParams.maxDurationMs,
5186
+ isCtv: envSignals.isCtv,
5187
+ contentUrl: envSignals.contentUrl,
5188
+ pageUrl: !envSignals.isCtv && typeof window !== "undefined" ? window.location.href : void 0,
5189
+ adWillPlayMuted: adWillPlayMuted,
5190
+ adWillAutoPlay: !!this.config.autoplay,
5191
+ appId: envSignals.appId,
5192
+ appName: envSignals.appName,
5193
+ sessionId: envSignals.sessionId,
5194
+ deviceId: envSignals.deviceId,
5195
+ deviceIdType: envSignals.deviceIdType,
5196
+ limitAdTracking: envSignals.limitAdTracking,
5197
+ deviceTypeHint: envSignals.deviceTypeHint,
5198
+ adTest: this.config.adTest,
5199
+ consent: this.consentSignals
5200
+ });
5201
+ var finalUrl = palNonce.injectNonce(urlWithMacros);
5202
+ 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);
5203
+ return finalUrl;
5204
+ }
5205
+ },
4874
5206
  {
4875
5207
  // --- Tracking ---
4876
5208
  key: "initializeTracking",
@@ -5176,6 +5508,13 @@ var AdTimingService = /*#__PURE__*/ function() {
5176
5508
  this.lastAdRequestTime = Date.now();
5177
5509
  }
5178
5510
  },
5511
+ {
5512
+ key: "notePodAdStarted",
5513
+ value: function notePodAdStarted() {
5514
+ this.currentAdIndex++;
5515
+ this.totalAdsInBreak = this.currentAdIndex;
5516
+ }
5517
+ },
5179
5518
  {
5180
5519
  key: "getRemainingAdMs",
5181
5520
  value: function getRemainingAdMs() {
@@ -6684,13 +7023,26 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
6684
7023
  }
6685
7024
  },
6686
7025
  {
6687
- // ───────────────────────────────────────────────────────────────
7026
+ key: "optimizedPodsEnabled",
7027
+ get: // ───────────────────────────────────────────────────────────────
6688
7028
  // IMA event listeners
6689
7029
  // ───────────────────────────────────────────────────────────────
7030
+ function get() {
7031
+ return !!this.host.config.optimizedPods;
7032
+ }
7033
+ },
7034
+ {
6690
7035
  key: "attachImaEventListeners",
6691
7036
  value: function attachImaEventListeners() {
6692
7037
  var _this = this;
6693
7038
  var adPlayer = this.host.getAdPlayer();
7039
+ adPlayer.on("pod_ad_started", function(payload) {
7040
+ _this.timing.notePodAdStarted();
7041
+ if (_this.debug) {
7042
+ var _ref;
7043
+ 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 : "?"));
7044
+ }
7045
+ });
6694
7046
  adPlayer.on("all_ads_completed", function() {
6695
7047
  sendAdImpressionTracking(_this.host.config.licenseKey, {
6696
7048
  source: "hls",
@@ -6848,7 +7200,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
6848
7200
  // ───────────────────────────────────────────────────────────────
6849
7201
  function handleAdStart(_marker) {
6850
7202
  return _async_to_generator(function() {
6851
- var scheduled, tags, baseVastUrl, adBreakDurationMs, mode, currentMuted, currentVolume, firstAdUrl, usePreloadedAd, preloadedController, preloaded, firstAdUrlArray, adPlayer, preservedMuted, preservedVolume, adVolume, adPlayer1, adVolume1, error, fallbackPreloaded, ap, adVolume2, fallbackError;
7203
+ 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;
6852
7204
  return _ts_generator(this, function(_state) {
6853
7205
  switch(_state.label){
6854
7206
  case 0:
@@ -6895,6 +7247,26 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
6895
7247
  if (this.timing.expectedAdBreakDurationMs == null && adBreakDurationMs != null) {
6896
7248
  this.timing.expectedAdBreakDurationMs = adBreakDurationMs;
6897
7249
  }
7250
+ if (!this.optimizedPodsEnabled) return [
7251
+ 3,
7252
+ 2
7253
+ ];
7254
+ return [
7255
+ 4,
7256
+ this.startOptimizedPod(baseVastUrl, adBreakDurationMs, currentMuted, currentVolume)
7257
+ ];
7258
+ case 1:
7259
+ podPlayed = _state.sent();
7260
+ if (podPlayed) {
7261
+ return [
7262
+ 2
7263
+ ];
7264
+ }
7265
+ if (this.debug) {
7266
+ console.log("[POD] Optimized pod unavailable, falling back to sequential single-ad path");
7267
+ }
7268
+ _state.label = 2;
7269
+ case 2:
6898
7270
  usePreloadedAd = false;
6899
7271
  preloaded = this.preloadPool.getPreloadedAd();
6900
7272
  if (preloaded) {
@@ -6936,21 +7308,21 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
6936
7308
  if (this.debug) {
6937
7309
  console.log("[CONTINUOUS-FETCH] First VAST URL:", firstAdUrl);
6938
7310
  }
6939
- _state.label = 1;
6940
- case 1:
7311
+ _state.label = 3;
7312
+ case 3:
6941
7313
  _state.trys.push([
6942
- 1,
6943
- 12,
7314
+ 3,
7315
+ 14,
6944
7316
  ,
6945
- 20
7317
+ 22
6946
7318
  ]);
6947
7319
  if (!(usePreloadedAd && preloadedController)) return [
6948
7320
  3,
6949
- 5
7321
+ 7
6950
7322
  ];
6951
7323
  if (!!this.timing.ensureLoadedAdFitsBudget(preloadedController)) return [
6952
7324
  3,
6953
- 3
7325
+ 5
6954
7326
  ];
6955
7327
  this.timing.rejectLoadedAdForDuration(preloadedController);
6956
7328
  this.startContinuousFetching(baseVastUrl);
@@ -6958,12 +7330,12 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
6958
7330
  4,
6959
7331
  this.tryNextAvailableAdWithRateLimit()
6960
7332
  ];
6961
- case 2:
7333
+ case 4:
6962
7334
  _state.sent();
6963
7335
  return [
6964
7336
  2
6965
7337
  ];
6966
- case 3:
7338
+ case 5:
6967
7339
  adPlayer = this.host.getAdPlayer();
6968
7340
  preservedMuted = adPlayer.getOriginalMutedState();
6969
7341
  preservedVolume = adPlayer.getOriginalVolume();
@@ -6988,7 +7360,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
6988
7360
  4,
6989
7361
  preloadedController.play()
6990
7362
  ];
6991
- case 4:
7363
+ case 6:
6992
7364
  _state.sent();
6993
7365
  this.timing.markAdStarted();
6994
7366
  if (this.timing.expectedAdBreakDurationMs != null && this.timing.getAdBreakEndWallClockMs() == null) {
@@ -6998,22 +7370,22 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
6998
7370
  preloadedController.setAdVolume(adVolume);
6999
7371
  return [
7000
7372
  3,
7001
- 11
7373
+ 13
7002
7374
  ];
7003
- case 5:
7375
+ case 7:
7004
7376
  adPlayer1 = this.host.getAdPlayer();
7005
7377
  return [
7006
7378
  4,
7007
7379
  this.timing.enforceGlobalRateLimit()
7008
7380
  ];
7009
- case 6:
7381
+ case 8:
7010
7382
  _state.sent();
7011
7383
  this.timing.lastAdRequestTime = Date.now();
7012
7384
  return [
7013
7385
  4,
7014
7386
  adPlayer1.requestAds(firstAdUrl)
7015
7387
  ];
7016
- case 7:
7388
+ case 9:
7017
7389
  _state.sent();
7018
7390
  sendAdLoadedTracking(this.host.config.licenseKey, {
7019
7391
  source: "hls",
@@ -7025,7 +7397,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7025
7397
  }
7026
7398
  if (!!this.timing.ensureLoadedAdFitsBudget(adPlayer1)) return [
7027
7399
  3,
7028
- 9
7400
+ 11
7029
7401
  ];
7030
7402
  this.timing.rejectLoadedAdForDuration(adPlayer1);
7031
7403
  this.recreateAdController();
@@ -7034,12 +7406,12 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7034
7406
  4,
7035
7407
  this.tryNextAvailableAdWithRateLimit()
7036
7408
  ];
7037
- case 8:
7409
+ case 10:
7038
7410
  _state.sent();
7039
7411
  return [
7040
7412
  2
7041
7413
  ];
7042
- case 9:
7414
+ case 11:
7043
7415
  this.timing.consecutiveFailures = 0;
7044
7416
  this.startContinuousFetching(baseVastUrl);
7045
7417
  if (!this.preloadPool.active) {
@@ -7049,7 +7421,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7049
7421
  4,
7050
7422
  adPlayer1.play()
7051
7423
  ];
7052
- case 10:
7424
+ case 12:
7053
7425
  _state.sent();
7054
7426
  this.timing.markAdStarted();
7055
7427
  if (this.timing.expectedAdBreakDurationMs != null && this.timing.getAdBreakEndWallClockMs() == null) {
@@ -7057,40 +7429,40 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7057
7429
  }
7058
7430
  adVolume1 = currentMuted ? 0 : currentVolume;
7059
7431
  adPlayer1.setAdVolume(adVolume1);
7060
- _state.label = 11;
7061
- case 11:
7432
+ _state.label = 13;
7433
+ case 13:
7062
7434
  return [
7063
7435
  3,
7064
- 20
7436
+ 22
7065
7437
  ];
7066
- case 12:
7438
+ case 14:
7067
7439
  error = _state.sent();
7068
7440
  if (this.debug) {
7069
7441
  console.warn("[CONTINUOUS-FETCH] First ad request failed:", error);
7070
7442
  }
7071
7443
  if (!!usePreloadedAd) return [
7072
7444
  3,
7073
- 18
7445
+ 20
7074
7446
  ];
7075
7447
  fallbackPreloaded = this.preloadPool.getPreloadedAd();
7076
7448
  if (!fallbackPreloaded) return [
7077
7449
  3,
7078
- 18
7450
+ 20
7079
7451
  ];
7080
7452
  if (this.debug) {
7081
7453
  console.log("[CONTINUOUS-FETCH] First ad failed, using preloaded fallback");
7082
7454
  }
7083
- _state.label = 13;
7084
- case 13:
7455
+ _state.label = 15;
7456
+ case 15:
7085
7457
  _state.trys.push([
7086
- 13,
7087
- 17,
7458
+ 15,
7459
+ 19,
7088
7460
  ,
7089
- 18
7461
+ 20
7090
7462
  ]);
7091
7463
  if (!!this.timing.ensureLoadedAdFitsBudget(fallbackPreloaded.adController)) return [
7092
7464
  3,
7093
- 15
7465
+ 17
7094
7466
  ];
7095
7467
  this.timing.rejectLoadedAdForDuration(fallbackPreloaded.adController);
7096
7468
  this.startContinuousFetching(baseVastUrl);
@@ -7098,12 +7470,12 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7098
7470
  4,
7099
7471
  this.tryNextAvailableAdWithRateLimit()
7100
7472
  ];
7101
- case 14:
7473
+ case 16:
7102
7474
  _state.sent();
7103
7475
  return [
7104
7476
  2
7105
7477
  ];
7106
- case 15:
7478
+ case 17:
7107
7479
  this.swapToPreloadedAdPlayer(fallbackPreloaded.adController);
7108
7480
  this.timing.consecutiveFailures = 0;
7109
7481
  this.startContinuousFetching(baseVastUrl);
@@ -7116,7 +7488,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7116
7488
  4,
7117
7489
  ap.play()
7118
7490
  ];
7119
- case 16:
7491
+ case 18:
7120
7492
  _state.sent();
7121
7493
  this.timing.markAdStarted();
7122
7494
  if (this.timing.expectedAdBreakDurationMs != null && this.timing.getAdBreakEndWallClockMs() == null) {
@@ -7127,16 +7499,16 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7127
7499
  return [
7128
7500
  2
7129
7501
  ];
7130
- case 17:
7502
+ case 19:
7131
7503
  fallbackError = _state.sent();
7132
7504
  if (this.debug) {
7133
7505
  console.warn("[CONTINUOUS-FETCH] Preloaded fallback also failed:", fallbackError);
7134
7506
  }
7135
7507
  return [
7136
7508
  3,
7137
- 18
7509
+ 20
7138
7510
  ];
7139
- case 18:
7511
+ case 20:
7140
7512
  if (this.timing.isTemporaryAdError(error)) {
7141
7513
  this.timing.temporaryFailureUrls.set(firstAdUrl, Date.now());
7142
7514
  if (this.debug) {
@@ -7154,13 +7526,137 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7154
7526
  4,
7155
7527
  this.tryNextAvailableAdWithRateLimit()
7156
7528
  ];
7157
- case 19:
7529
+ case 21:
7158
7530
  _state.sent();
7159
7531
  return [
7160
7532
  3,
7161
- 20
7533
+ 22
7162
7534
  ];
7163
- case 20:
7535
+ case 22:
7536
+ return [
7537
+ 2
7538
+ ];
7539
+ }
7540
+ });
7541
+ }).call(this);
7542
+ }
7543
+ },
7544
+ {
7545
+ key: "startOptimizedPod",
7546
+ value: // ───────────────────────────────────────────────────────────────
7547
+ // Optimized pod (single multi-ad request)
7548
+ // ───────────────────────────────────────────────────────────────
7549
+ function startOptimizedPod(baseVastUrl, breakDurationMs, currentMuted, currentVolume) {
7550
+ return _async_to_generator(function() {
7551
+ var podUrl, adPlayer, requestToken, _ref, _adPlayer_getPodAdCount, podCount, error;
7552
+ return _ts_generator(this, function(_state) {
7553
+ switch(_state.label){
7554
+ case 0:
7555
+ if (this.pendingAdBreak && this.pendingAdBreak.vastUrls.length > 0) {
7556
+ podUrl = this.pendingAdBreak.vastUrls[0];
7557
+ this.clearPendingAdBreak();
7558
+ } else {
7559
+ podUrl = this.host.generatePodVastUrl(baseVastUrl, breakDurationMs);
7560
+ }
7561
+ if (!podUrl) {
7562
+ return [
7563
+ 2,
7564
+ false
7565
+ ];
7566
+ }
7567
+ this.continuousFetchingActive = false;
7568
+ this.recreateAdController();
7569
+ adPlayer = this.host.getAdPlayer();
7570
+ requestToken = ++this.timing.adRequestTokenCounter;
7571
+ this.timing.activeAdRequestToken = requestToken;
7572
+ this.timing.startAdRequestWatchdog(requestToken);
7573
+ _state.label = 1;
7574
+ case 1:
7575
+ _state.trys.push([
7576
+ 1,
7577
+ 5,
7578
+ ,
7579
+ 6
7580
+ ]);
7581
+ return [
7582
+ 4,
7583
+ this.timing.enforceGlobalRateLimit()
7584
+ ];
7585
+ case 2:
7586
+ _state.sent();
7587
+ this.timing.lastAdRequestTime = Date.now();
7588
+ return [
7589
+ 4,
7590
+ adPlayer.requestAds(podUrl)
7591
+ ];
7592
+ case 3:
7593
+ _state.sent();
7594
+ this.timing.clearAdRequestWatchdog();
7595
+ if (this.timing.activeAdRequestToken !== requestToken) {
7596
+ return [
7597
+ 2,
7598
+ true
7599
+ ];
7600
+ }
7601
+ podCount = (_ref = (_adPlayer_getPodAdCount = adPlayer.getPodAdCount) === null || _adPlayer_getPodAdCount === void 0 ? void 0 : _adPlayer_getPodAdCount.call(adPlayer)) !== null && _ref !== void 0 ? _ref : 1;
7602
+ if (podCount < 1) {
7603
+ return [
7604
+ 2,
7605
+ false
7606
+ ];
7607
+ }
7608
+ if (this.debug) {
7609
+ 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"));
7610
+ }
7611
+ sendAdLoadedTracking(this.host.config.licenseKey, {
7612
+ source: "hls",
7613
+ vastUrl: podUrl,
7614
+ timestamp: /* @__PURE__ */ new Date().toISOString()
7615
+ }, this.analyticsContext).catch(function() {});
7616
+ this.timing.startAdFailsafeTimer(requestToken);
7617
+ return [
7618
+ 4,
7619
+ adPlayer.play()
7620
+ ];
7621
+ case 4:
7622
+ _state.sent();
7623
+ this.timing.markAdStarted();
7624
+ if (this.timing.expectedAdBreakDurationMs != null && this.timing.getAdBreakEndWallClockMs() == null) {
7625
+ this.timing.scheduleAdStopAtBreakBoundary();
7626
+ }
7627
+ adPlayer.setAdVolume(currentMuted ? 0 : currentVolume);
7628
+ this.timing.consecutiveFailures = 0;
7629
+ if (podCount === 1) {
7630
+ this.continuousFetchingActive = true;
7631
+ this.startContinuousFetching(baseVastUrl);
7632
+ if (!this.preloadPool.active) {
7633
+ this.preloadPool.startPreloadPool(baseVastUrl, []);
7634
+ }
7635
+ }
7636
+ return [
7637
+ 2,
7638
+ true
7639
+ ];
7640
+ case 5:
7641
+ error = _state.sent();
7642
+ this.timing.clearAdRequestWatchdog();
7643
+ this.timing.clearAdFailsafeTimer();
7644
+ if (this.timing.activeAdRequestToken === requestToken) {
7645
+ this.timing.activeAdRequestToken = null;
7646
+ }
7647
+ if (this.debug) {
7648
+ console.warn("[POD] Optimized pod request/play failed:", error);
7649
+ }
7650
+ if (this.timing.isTemporaryAdError(error)) {
7651
+ this.timing.temporaryFailureUrls.set(podUrl, Date.now());
7652
+ }
7653
+ this.continuousFetchingActive = true;
7654
+ this.recreateAdController();
7655
+ return [
7656
+ 2,
7657
+ false
7658
+ ];
7659
+ case 6:
7164
7660
  return [
7165
7661
  2
7166
7662
  ];
@@ -8242,6 +8738,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8242
8738
  },
8243
8739
  generateVastUrls: function generateVastUrls(base, count) {
8244
8740
  return _this.generateVastUrls(base, count);
8741
+ },
8742
+ generatePodVastUrl: function generatePodVastUrl(base, breakDurationMs) {
8743
+ return _this.generatePodVastUrl(base, breakDurationMs);
8245
8744
  }
8246
8745
  }, this.timing, this.preloadPool, this.adConfig, this.cueManager, this.placeholder);
8247
8746
  }
@@ -8274,6 +8773,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8274
8773
  return this.adConfig.generateVastUrlsWithCorrelators(baseUrl, count, this.adPlayer, this.palNonce, this.adBreak.inAdBreak);
8275
8774
  }
8276
8775
  },
8776
+ {
8777
+ key: "generatePodVastUrl",
8778
+ value: function generatePodVastUrl(baseUrl, breakDurationMs) {
8779
+ var podParams = this.adConfig.resolvePodParams(breakDurationMs);
8780
+ return this.adConfig.generatePodVastUrl(baseUrl, podParams, this.adPlayer, this.palNonce, this.adBreak.inAdBreak);
8781
+ }
8782
+ },
8277
8783
  {
8278
8784
  key: "load",
8279
8785
  value: // ───────────────────────────────────────────────────────────────
@@ -8662,7 +9168,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8662
9168
  }
8663
9169
  this.adConfig.beginNewAdPod();
8664
9170
  this.adConfig.podAssignedByPrefetch = true;
8665
- var generatedUrls = this.generateVastUrls(baseVastUrl, 1);
9171
+ var optimizedPods = !!this.config.optimizedPods;
9172
+ var breakDurationMs = marker.durationSeconds != null ? marker.durationSeconds * 1e3 : void 0;
9173
+ var generatedUrls = optimizedPods ? [
9174
+ this.generatePodVastUrl(baseVastUrl, breakDurationMs)
9175
+ ] : this.generateVastUrls(baseVastUrl, 1);
8666
9176
  this.adBreak.pendingAdBreak = _object_spread_props(_object_spread({
8667
9177
  marker: marker
8668
9178
  }, fragmentSn !== void 0 ? {
@@ -8684,7 +9194,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8684
9194
  }, detectPayload), buildAnalyticsContext(this.config)).catch(function() {});
8685
9195
  if (this.debug) {
8686
9196
  console.log("[PREFETCH] Starting ad prefetch for upcoming ad break");
8687
- console.log("[PREFETCH] Pre-generated ".concat(generatedUrls.length, " VAST URLs"));
9197
+ console.log("[PREFETCH] Pre-generated ".concat(generatedUrls.length, " ").concat(optimizedPods ? "pod" : "VAST", " URL(s)"));
9198
+ }
9199
+ if (optimizedPods) {
9200
+ if (this.debug) {
9201
+ console.log("[PREFETCH] Optimized pods enabled - skipping single-ad preload pool");
9202
+ }
9203
+ return;
8688
9204
  }
8689
9205
  this.preloadPool.startPreloadPool(baseVastUrl, generatedUrls.slice(0, 1), false);
8690
9206
  }