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
@@ -412,6 +412,8 @@ function createHlsAdPlayer(contentVideo, options) {
412
412
  var adHls;
413
413
  var adContainerEl;
414
414
  var currentAd;
415
+ var podAds = [];
416
+ var podIndex = 0;
415
417
  var sessionId;
416
418
  var preloadedAds = /* @__PURE__ */ new Map();
417
419
  var preloadingAds = /* @__PURE__ */ new Map();
@@ -576,14 +578,14 @@ function createHlsAdPlayer(contentVideo, options) {
576
578
  error: []
577
579
  };
578
580
  }
579
- function extractTrackingUrls(xmlDoc) {
581
+ function extractTrackingUrls(scope) {
580
582
  var trackingUrls = createEmptyTrackingUrls();
581
- xmlDoc.querySelectorAll("Impression").forEach(function(el) {
583
+ scope.querySelectorAll("Impression").forEach(function(el) {
582
584
  var _el_textContent;
583
585
  var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
584
586
  if (url) trackingUrls.impression.push(url);
585
587
  });
586
- xmlDoc.querySelectorAll("Tracking").forEach(function(el) {
588
+ scope.querySelectorAll("Tracking").forEach(function(el) {
587
589
  var _el_textContent;
588
590
  var event = el.getAttribute("event");
589
591
  var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
@@ -594,7 +596,7 @@ function createHlsAdPlayer(contentVideo, options) {
594
596
  }
595
597
  }
596
598
  });
597
- xmlDoc.querySelectorAll("Error").forEach(function(el) {
599
+ scope.querySelectorAll("Error").forEach(function(el) {
598
600
  var _el_textContent;
599
601
  var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
600
602
  if (url) trackingUrls.error.push(url);
@@ -704,6 +706,75 @@ function createHlsAdPlayer(contentVideo, options) {
704
706
  };
705
707
  }
706
708
  }
709
+ function parseAdElement(adElement) {
710
+ try {
711
+ var _adElement_querySelector, _adElement_querySelector_textContent, _adElement_querySelector1, _adElement_querySelector_textContent1, _adElement_querySelector2, _adElement_querySelector3;
712
+ var adId = adElement.getAttribute("id") || "unknown";
713
+ var title = ((_adElement_querySelector = adElement.querySelector("AdTitle")) === null || _adElement_querySelector === void 0 ? void 0 : _adElement_querySelector.textContent) || "Ad";
714
+ 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();
715
+ 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();
716
+ if (wrapperUri) {
717
+ return {
718
+ type: "wrapper",
719
+ vastAdTagUri: wrapperUri,
720
+ trackingUrls: extractTrackingUrls(adElement),
721
+ clickThrough: clickThrough
722
+ };
723
+ }
724
+ var isNoAdAvailable = adId === "empty" || title.toLowerCase().includes("no ad available") || title.toLowerCase() === "no ad available";
725
+ var durationText = ((_adElement_querySelector3 = adElement.querySelector("Duration")) === null || _adElement_querySelector3 === void 0 ? void 0 : _adElement_querySelector3.textContent) || "00:00:30";
726
+ var durationParts = durationText.split(":");
727
+ var duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseInt(durationParts[2] || "0", 10);
728
+ var mediaFileElements = adElement.querySelectorAll("MediaFile");
729
+ var mediaFiles = [];
730
+ mediaFileElements.forEach(function(mf) {
731
+ var _mf_textContent;
732
+ var type = mf.getAttribute("type") || "";
733
+ var url = ((_mf_textContent = mf.textContent) === null || _mf_textContent === void 0 ? void 0 : _mf_textContent.trim()) || "";
734
+ var width = mf.getAttribute("width") || "";
735
+ var height = mf.getAttribute("height") || "";
736
+ if (!url) return;
737
+ var bitrateAttr = mf.getAttribute("bitrate");
738
+ var bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;
739
+ var mediaFile = {
740
+ url: url,
741
+ type: type,
742
+ width: parseInt(width || "1920", 10),
743
+ height: parseInt(height || "1080", 10),
744
+ bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : void 0
745
+ };
746
+ if (isHlsMediaFile(mediaFile) || isProgressiveMediaFile(mediaFile)) {
747
+ mediaFiles.push(mediaFile);
748
+ }
749
+ });
750
+ if (mediaFiles.length === 0) {
751
+ if (isNoAdAvailable) {
752
+ console.warn("[HlsAdPlayer] Pod <Ad> indicates no ad available");
753
+ } else {
754
+ console.warn("[HlsAdPlayer] No supported media files in pod <Ad>");
755
+ }
756
+ return {
757
+ type: "empty"
758
+ };
759
+ }
760
+ return {
761
+ type: "inline",
762
+ ad: {
763
+ id: adId,
764
+ title: title,
765
+ duration: duration,
766
+ mediaFiles: mediaFiles,
767
+ trackingUrls: extractTrackingUrls(adElement),
768
+ clickThrough: clickThrough
769
+ }
770
+ };
771
+ } catch (error) {
772
+ console.error("[HlsAdPlayer] Error parsing pod <Ad> element:", error);
773
+ return {
774
+ type: "empty"
775
+ };
776
+ }
777
+ }
707
778
  function fetchVastXml(vastTagUrl) {
708
779
  return _async_to_generator(function() {
709
780
  var response;
@@ -780,6 +851,146 @@ function createHlsAdPlayer(contentVideo, options) {
780
851
  });
781
852
  }).apply(this, arguments);
782
853
  }
854
+ function fetchAndParsePod(vastTagUrl) {
855
+ return _async_to_generator(function() {
856
+ var vastXml, parser, xmlDoc, adElements, ads, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, adElement, parsed, resolved, error, err;
857
+ return _ts_generator(this, function(_state) {
858
+ switch(_state.label){
859
+ case 0:
860
+ return [
861
+ 4,
862
+ fetchVastXml(vastTagUrl)
863
+ ];
864
+ case 1:
865
+ vastXml = _state.sent();
866
+ console.log("[HlsAdPlayer] Pod VAST XML received");
867
+ parser = new DOMParser();
868
+ xmlDoc = parser.parseFromString(vastXml, "text/xml");
869
+ if (xmlDoc.querySelector("parsererror")) {
870
+ console.error("[HlsAdPlayer] Pod VAST XML parsing error (malformed)");
871
+ return [
872
+ 2,
873
+ []
874
+ ];
875
+ }
876
+ adElements = Array.from(xmlDoc.querySelectorAll("Ad"));
877
+ if (adElements.length === 0) {
878
+ console.warn("[HlsAdPlayer] No <Ad> elements found in pod VAST response");
879
+ return [
880
+ 2,
881
+ []
882
+ ];
883
+ }
884
+ adElements.sort(function(a, b) {
885
+ var aSeq = parseInt(a.getAttribute("sequence") || "", 10);
886
+ var bSeq = parseInt(b.getAttribute("sequence") || "", 10);
887
+ var aVal = Number.isFinite(aSeq) ? aSeq : Number.MAX_SAFE_INTEGER;
888
+ var bVal = Number.isFinite(bSeq) ? bSeq : Number.MAX_SAFE_INTEGER;
889
+ return aVal - bVal;
890
+ });
891
+ ads = [];
892
+ _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
893
+ _state.label = 2;
894
+ case 2:
895
+ _state.trys.push([
896
+ 2,
897
+ 10,
898
+ 11,
899
+ 12
900
+ ]);
901
+ _iterator = adElements[Symbol.iterator]();
902
+ _state.label = 3;
903
+ case 3:
904
+ if (!!(_iteratorNormalCompletion = (_step = _iterator.next()).done)) return [
905
+ 3,
906
+ 9
907
+ ];
908
+ adElement = _step.value;
909
+ parsed = parseAdElement(adElement);
910
+ if (!(parsed.type === "inline")) return [
911
+ 3,
912
+ 4
913
+ ];
914
+ ads.push(parsed.ad);
915
+ return [
916
+ 3,
917
+ 8
918
+ ];
919
+ case 4:
920
+ if (!(parsed.type === "wrapper")) return [
921
+ 3,
922
+ 8
923
+ ];
924
+ _state.label = 5;
925
+ case 5:
926
+ _state.trys.push([
927
+ 5,
928
+ 7,
929
+ ,
930
+ 8
931
+ ]);
932
+ return [
933
+ 4,
934
+ fetchAndParseVastAd(parsed.vastAdTagUri, 1, parsed.trackingUrls)
935
+ ];
936
+ case 6:
937
+ resolved = _state.sent();
938
+ if (resolved) {
939
+ ads.push(resolved);
940
+ }
941
+ return [
942
+ 3,
943
+ 8
944
+ ];
945
+ case 7:
946
+ error = _state.sent();
947
+ console.warn("[HlsAdPlayer] Failed to resolve wrapper <Ad> in pod:", error);
948
+ return [
949
+ 3,
950
+ 8
951
+ ];
952
+ case 8:
953
+ _iteratorNormalCompletion = true;
954
+ return [
955
+ 3,
956
+ 3
957
+ ];
958
+ case 9:
959
+ return [
960
+ 3,
961
+ 12
962
+ ];
963
+ case 10:
964
+ err = _state.sent();
965
+ _didIteratorError = true;
966
+ _iteratorError = err;
967
+ return [
968
+ 3,
969
+ 12
970
+ ];
971
+ case 11:
972
+ try {
973
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
974
+ _iterator.return();
975
+ }
976
+ } finally{
977
+ if (_didIteratorError) {
978
+ throw _iteratorError;
979
+ }
980
+ }
981
+ return [
982
+ 7
983
+ ];
984
+ case 12:
985
+ console.log("[HlsAdPlayer] Parsed ".concat(ads.length, " ad(s) from pod VAST response"));
986
+ return [
987
+ 2,
988
+ ads
989
+ ];
990
+ }
991
+ });
992
+ })();
993
+ }
783
994
  function createAdVideoElement() {
784
995
  var video = document.createElement("video");
785
996
  video.style.position = "absolute";
@@ -824,6 +1035,9 @@ function createHlsAdPlayer(contentVideo, options) {
824
1035
  trackingFired.complete = true;
825
1036
  fireTrackingPixels(currentAd.trackingUrls.complete);
826
1037
  console.log("[HlsAdPlayer] Ad completed");
1038
+ if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1039
+ return;
1040
+ }
827
1041
  handleAdComplete();
828
1042
  });
829
1043
  adVideoElement.addEventListener("error", function(e) {
@@ -832,6 +1046,9 @@ function createHlsAdPlayer(contentVideo, options) {
832
1046
  if (currentAd) {
833
1047
  fireTrackingPixels(currentAd.trackingUrls.error);
834
1048
  }
1049
+ if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1050
+ return;
1051
+ }
835
1052
  handleAdError();
836
1053
  });
837
1054
  adVideoElement.addEventListener("volumechange", function() {
@@ -860,6 +1077,94 @@ function createHlsAdPlayer(contentVideo, options) {
860
1077
  delete contentVideo.dataset.stormcloudAdPlaying;
861
1078
  }
862
1079
  }
1080
+ function resetQuartileTracking(preserveImpression) {
1081
+ trackingFired = {
1082
+ impression: preserveImpression ? trackingFired.impression : false,
1083
+ start: false,
1084
+ firstQuartile: false,
1085
+ midpoint: false,
1086
+ thirdQuartile: false,
1087
+ complete: false
1088
+ };
1089
+ }
1090
+ function loadCurrentAdMedia() {
1091
+ if (!adVideoElement || !currentAd) {
1092
+ throw new Error("No ad video element or ad to load");
1093
+ }
1094
+ var mediaFile = selectBestMediaFile(currentAd.mediaFiles);
1095
+ if (!mediaFile) {
1096
+ throw new Error("No media file available for ad");
1097
+ }
1098
+ var isHlsAd = isHlsMediaFile(mediaFile);
1099
+ console.log("[HlsAdPlayer] Loading ".concat(isHlsAd ? "HLS" : "progressive", " ad (pod ").concat(podIndex + 1, "/").concat(podAds.length || 1, ") from: ").concat(mediaFile.url));
1100
+ if (isHlsAd && import_hls.default.isSupported()) {
1101
+ if (adHls) {
1102
+ adHls.destroy();
1103
+ }
1104
+ adHls = new import_hls.default({
1105
+ enableWorker: true,
1106
+ lowLatencyMode: false
1107
+ });
1108
+ adHls.loadSource(mediaFile.url);
1109
+ adHls.attachMedia(adVideoElement);
1110
+ adHls.on(import_hls.default.Events.MANIFEST_PARSED, function() {
1111
+ console.log("[HlsAdPlayer] HLS manifest parsed, starting playback");
1112
+ adVideoElement.play().catch(function(error) {
1113
+ console.error("[HlsAdPlayer] Error starting ad playback:", error);
1114
+ handleAdError();
1115
+ });
1116
+ });
1117
+ adHls.on(import_hls.default.Events.ERROR, function(_event, data) {
1118
+ console.error("[HlsAdPlayer] HLS error:", data);
1119
+ if (data.fatal) {
1120
+ handleAdError();
1121
+ }
1122
+ });
1123
+ } else if (isHlsAd && adVideoElement.canPlayType("application/vnd.apple.mpegurl")) {
1124
+ adVideoElement.src = mediaFile.url;
1125
+ adVideoElement.play().catch(function(error) {
1126
+ console.error("[HlsAdPlayer] Error starting ad playback:", error);
1127
+ handleAdError();
1128
+ });
1129
+ } else if (!isHlsAd && isProgressiveMediaFile(mediaFile)) {
1130
+ if (adHls) {
1131
+ adHls.destroy();
1132
+ adHls = void 0;
1133
+ }
1134
+ adVideoElement.src = mediaFile.url;
1135
+ adVideoElement.load();
1136
+ adVideoElement.play().catch(function(error) {
1137
+ console.error("[HlsAdPlayer] Error starting progressive ad playback:", error);
1138
+ handleAdError();
1139
+ });
1140
+ } else {
1141
+ throw new Error("Unsupported ad media file type: ".concat(mediaFile.type));
1142
+ }
1143
+ }
1144
+ function advanceToNextPodAd() {
1145
+ if (podIndex >= podAds.length - 1) {
1146
+ return false;
1147
+ }
1148
+ podIndex++;
1149
+ currentAd = podAds[podIndex];
1150
+ resetQuartileTracking(false);
1151
+ if (currentAd) {
1152
+ fireTrackingPixels(currentAd.trackingUrls.impression);
1153
+ trackingFired.impression = true;
1154
+ console.log("[HlsAdPlayer] Advancing to next pod ad (".concat(podIndex + 1, "/").concat(podAds.length, "): ").concat(currentAd.title, ", duration: ").concat(currentAd.duration, "s"));
1155
+ }
1156
+ try {
1157
+ loadCurrentAdMedia();
1158
+ emit("pod_ad_started", {
1159
+ index: podIndex,
1160
+ total: podAds.length
1161
+ });
1162
+ return true;
1163
+ } catch (error) {
1164
+ console.error("[HlsAdPlayer] Failed to load next pod ad:", error);
1165
+ return false;
1166
+ }
1167
+ }
863
1168
  function handleAdComplete() {
864
1169
  console.log("[HlsAdPlayer] Handling ad completion");
865
1170
  adPlaying = false;
@@ -913,7 +1218,7 @@ function createHlsAdPlayer(contentVideo, options) {
913
1218
  },
914
1219
  requestAds: function requestAds(vastTagUrl) {
915
1220
  return _async_to_generator(function() {
916
- var ad, error;
1221
+ var ads, preloaded, error;
917
1222
  return _ts_generator(this, function(_state) {
918
1223
  switch(_state.label){
919
1224
  case 0:
@@ -934,12 +1239,18 @@ function createHlsAdPlayer(contentVideo, options) {
934
1239
  6
935
1240
  ]);
936
1241
  sessionId = generateSessionId();
1242
+ ads = [];
937
1243
  if (!preloadedAds.has(vastTagUrl)) return [
938
1244
  3,
939
1245
  2
940
1246
  ];
941
- ad = preloadedAds.get(vastTagUrl);
1247
+ preloaded = preloadedAds.get(vastTagUrl);
942
1248
  preloadedAds.delete(vastTagUrl);
1249
+ if (preloaded) {
1250
+ ads = [
1251
+ preloaded
1252
+ ];
1253
+ }
943
1254
  console.log("[HlsAdPlayer] Using preloaded VAST response:", vastTagUrl);
944
1255
  return [
945
1256
  3,
@@ -948,13 +1259,13 @@ function createHlsAdPlayer(contentVideo, options) {
948
1259
  case 2:
949
1260
  return [
950
1261
  4,
951
- fetchAndParseVastAd(vastTagUrl)
1262
+ fetchAndParsePod(vastTagUrl)
952
1263
  ];
953
1264
  case 3:
954
- ad = _state.sent();
1265
+ ads = _state.sent();
955
1266
  _state.label = 4;
956
1267
  case 4:
957
- if (!ad) {
1268
+ if (!ads.length) {
958
1269
  console.warn("[HlsAdPlayer] No ads available from VAST response");
959
1270
  emit("ad_error");
960
1271
  return [
@@ -962,10 +1273,14 @@ function createHlsAdPlayer(contentVideo, options) {
962
1273
  Promise.reject(new Error("No ads available from VAST response"))
963
1274
  ];
964
1275
  }
965
- currentAd = ad;
966
- console.log("[HlsAdPlayer] Ad parsed: ".concat(ad.title, ", duration: ").concat(ad.duration, "s"));
967
- fireTrackingPixels(ad.trackingUrls.impression);
968
- trackingFired.impression = true;
1276
+ podAds = ads;
1277
+ podIndex = 0;
1278
+ currentAd = ads[0];
1279
+ 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"));
1280
+ if (currentAd) {
1281
+ fireTrackingPixels(currentAd.trackingUrls.impression);
1282
+ trackingFired.impression = true;
1283
+ }
969
1284
  return [
970
1285
  2,
971
1286
  Promise.resolve()
@@ -988,7 +1303,7 @@ function createHlsAdPlayer(contentVideo, options) {
988
1303
  },
989
1304
  play: function play() {
990
1305
  return _async_to_generator(function() {
991
- var contentVolume, mediaFile, isHlsAd;
1306
+ var contentVolume;
992
1307
  return _ts_generator(this, function(_state) {
993
1308
  if (!currentAd) {
994
1309
  console.warn("[HlsAdPlayer] Cannot play: No ad loaded (no ads available)");
@@ -1004,14 +1319,7 @@ function createHlsAdPlayer(contentVideo, options) {
1004
1319
  adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.appendChild(adVideoElement);
1005
1320
  setupAdEventListeners();
1006
1321
  }
1007
- trackingFired = {
1008
- impression: trackingFired.impression,
1009
- start: false,
1010
- firstQuartile: false,
1011
- midpoint: false,
1012
- thirdQuartile: false,
1013
- complete: false
1014
- };
1322
+ resetQuartileTracking(true);
1015
1323
  contentVolume = contentVideo.volume;
1016
1324
  originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1017
1325
  if (!(options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds)) {
@@ -1029,60 +1337,12 @@ function createHlsAdPlayer(contentVideo, options) {
1029
1337
  adVideoElement.muted = originalMutedState;
1030
1338
  console.log("[HlsAdPlayer] Set ad video volume to ".concat(adVideoElement.volume, ", muted: ").concat(adVideoElement.muted, ", originalMutedState: ").concat(originalMutedState, ", contentVolume: ").concat(contentVolume));
1031
1339
  }
1032
- mediaFile = selectBestMediaFile(currentAd.mediaFiles);
1033
- if (!mediaFile) {
1034
- throw new Error("No media file available for ad");
1035
- }
1036
1340
  if (adContainerEl) {
1037
1341
  adContainerEl.style.display = "flex";
1038
1342
  adContainerEl.style.pointerEvents = "auto";
1039
1343
  }
1040
1344
  emit("content_pause");
1041
- isHlsAd = isHlsMediaFile(mediaFile);
1042
- console.log("[HlsAdPlayer] Loading ".concat(isHlsAd ? "HLS" : "progressive", " ad from: ").concat(mediaFile.url));
1043
- if (isHlsAd && import_hls.default.isSupported()) {
1044
- if (adHls) {
1045
- adHls.destroy();
1046
- }
1047
- adHls = new import_hls.default({
1048
- enableWorker: true,
1049
- lowLatencyMode: false
1050
- });
1051
- adHls.loadSource(mediaFile.url);
1052
- adHls.attachMedia(adVideoElement);
1053
- adHls.on(import_hls.default.Events.MANIFEST_PARSED, function() {
1054
- console.log("[HlsAdPlayer] HLS manifest parsed, starting playback");
1055
- adVideoElement.play().catch(function(error) {
1056
- console.error("[HlsAdPlayer] Error starting ad playback:", error);
1057
- handleAdError();
1058
- });
1059
- });
1060
- adHls.on(import_hls.default.Events.ERROR, function(event, data) {
1061
- console.error("[HlsAdPlayer] HLS error:", data);
1062
- if (data.fatal) {
1063
- handleAdError();
1064
- }
1065
- });
1066
- } else if (isHlsAd && adVideoElement.canPlayType("application/vnd.apple.mpegurl")) {
1067
- adVideoElement.src = mediaFile.url;
1068
- adVideoElement.play().catch(function(error) {
1069
- console.error("[HlsAdPlayer] Error starting ad playback:", error);
1070
- handleAdError();
1071
- });
1072
- } else if (!isHlsAd && isProgressiveMediaFile(mediaFile)) {
1073
- if (adHls) {
1074
- adHls.destroy();
1075
- adHls = void 0;
1076
- }
1077
- adVideoElement.src = mediaFile.url;
1078
- adVideoElement.load();
1079
- adVideoElement.play().catch(function(error) {
1080
- console.error("[HlsAdPlayer] Error starting progressive ad playback:", error);
1081
- handleAdError();
1082
- });
1083
- } else {
1084
- throw new Error("Unsupported ad media file type: ".concat(mediaFile.type));
1085
- }
1345
+ loadCurrentAdMedia();
1086
1346
  return [
1087
1347
  2,
1088
1348
  Promise.resolve()
@@ -1157,6 +1417,8 @@ function createHlsAdPlayer(contentVideo, options) {
1157
1417
  adVideoElement.src = "";
1158
1418
  }
1159
1419
  currentAd = void 0;
1420
+ podAds = [];
1421
+ podIndex = 0;
1160
1422
  return [
1161
1423
  2
1162
1424
  ];
@@ -1206,6 +1468,8 @@ function createHlsAdPlayer(contentVideo, options) {
1206
1468
  }
1207
1469
  adContainerEl = void 0;
1208
1470
  currentAd = void 0;
1471
+ podAds = [];
1472
+ podIndex = 0;
1209
1473
  listeners.clear();
1210
1474
  preloadedAds.clear();
1211
1475
  preloadingAds.clear();
@@ -1297,6 +1561,14 @@ function createHlsAdPlayer(contentVideo, options) {
1297
1561
  },
1298
1562
  getLoadedAdId: function getLoadedAdId() {
1299
1563
  return currentAd === null || currentAd === void 0 ? void 0 : currentAd.id;
1564
+ },
1565
+ getPodAdCount: function getPodAdCount() {
1566
+ return podAds.length;
1567
+ },
1568
+ getPodTotalDurationMs: function getPodTotalDurationMs() {
1569
+ return podAds.reduce(function(total, ad) {
1570
+ return total + (ad.duration > 0 ? ad.duration * 1e3 : 0);
1571
+ }, 0);
1300
1572
  }
1301
1573
  };
1302
1574
  }
@@ -3125,7 +3397,20 @@ function applyVastMacros(baseUrl, ctx) {
3125
3397
  if (ctx.pod != null) {
3126
3398
  params.set("pod", String(ctx.pod));
3127
3399
  }
3128
- if (ctx.adPosition != null) {
3400
+ var optimizedPodMode = ctx.podMaxAds != null || ctx.podMinDurationMs != null || ctx.podMaxDurationMs != null;
3401
+ if (optimizedPodMode) {
3402
+ params.delete("ppos");
3403
+ params.delete("lip");
3404
+ if (ctx.podMinDurationMs != null) {
3405
+ params.set("pmnd", String(Math.max(0, Math.round(ctx.podMinDurationMs))));
3406
+ }
3407
+ if (ctx.podMaxDurationMs != null) {
3408
+ params.set("pmxd", String(Math.max(0, Math.round(ctx.podMaxDurationMs))));
3409
+ }
3410
+ if (ctx.podMaxAds != null) {
3411
+ params.set("pmad", String(Math.max(1, Math.round(ctx.podMaxAds))));
3412
+ }
3413
+ } else if (ctx.adPosition != null) {
3129
3414
  params.set("ppos", String(ctx.adPosition));
3130
3415
  }
3131
3416
  var requestUrl = ctx.contentUrl || ctx.pageUrl;
@@ -4467,6 +4752,7 @@ var AdConfigManager = /*#__PURE__*/ function() {
4467
4752
  this.podAssignedByPrefetch = false;
4468
4753
  this.adRequestPositionInBreak = 0;
4469
4754
  this.lastHeartbeatTime = 0;
4755
+ this.defaultPodMaxAds = 6;
4470
4756
  this.config = config;
4471
4757
  this.video = video;
4472
4758
  }
@@ -4922,6 +5208,52 @@ var AdConfigManager = /*#__PURE__*/ function() {
4922
5208
  return urls;
4923
5209
  }
4924
5210
  },
5211
+ {
5212
+ key: "resolvePodParams",
5213
+ value: function resolvePodParams(breakDurationMs) {
5214
+ var maxDurationMs = breakDurationMs != null && breakDurationMs > 0 ? breakDurationMs : this.config.podMaxDurationMs;
5215
+ var maxAds = this.config.podMaxAds && this.config.podMaxAds > 0 ? this.config.podMaxAds : this.apiNumberAds && this.apiNumberAds > 0 ? this.apiNumberAds : this.defaultPodMaxAds;
5216
+ var minDurationMs = this.config.podExactDuration && maxDurationMs != null ? maxDurationMs : 0;
5217
+ return {
5218
+ maxAds: maxAds,
5219
+ minDurationMs: minDurationMs,
5220
+ maxDurationMs: maxDurationMs
5221
+ };
5222
+ }
5223
+ },
5224
+ {
5225
+ key: "generatePodVastUrl",
5226
+ value: function generatePodVastUrl(baseUrl, podParams, adPlayer, palNonce, inAdBreak) {
5227
+ var _podParams_maxDurationMs;
5228
+ var adWillPlayMuted = inAdBreak ? adPlayer.getOriginalMutedState() : this.video.muted;
5229
+ var envSignals = resolveVastEnvironmentSignals(!!this.config.ctvAdRequest);
5230
+ var urlWithMacros = applyVastMacros(baseUrl, {
5231
+ correlator: generateCorrelator(),
5232
+ streamCorrelator: this.streamCorrelator,
5233
+ pod: this.podCounter > 0 ? this.podCounter : void 0,
5234
+ podMaxAds: podParams.maxAds,
5235
+ podMinDurationMs: podParams.minDurationMs,
5236
+ podMaxDurationMs: podParams.maxDurationMs,
5237
+ isCtv: envSignals.isCtv,
5238
+ contentUrl: envSignals.contentUrl,
5239
+ pageUrl: !envSignals.isCtv && typeof window !== "undefined" ? window.location.href : void 0,
5240
+ adWillPlayMuted: adWillPlayMuted,
5241
+ adWillAutoPlay: !!this.config.autoplay,
5242
+ appId: envSignals.appId,
5243
+ appName: envSignals.appName,
5244
+ sessionId: envSignals.sessionId,
5245
+ deviceId: envSignals.deviceId,
5246
+ deviceIdType: envSignals.deviceIdType,
5247
+ limitAdTracking: envSignals.limitAdTracking,
5248
+ deviceTypeHint: envSignals.deviceTypeHint,
5249
+ adTest: this.config.adTest,
5250
+ consent: this.consentSignals
5251
+ });
5252
+ var finalUrl = palNonce.injectNonce(urlWithMacros);
5253
+ 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);
5254
+ return finalUrl;
5255
+ }
5256
+ },
4925
5257
  {
4926
5258
  // --- Tracking ---
4927
5259
  key: "initializeTracking",
@@ -5227,6 +5559,13 @@ var AdTimingService = /*#__PURE__*/ function() {
5227
5559
  this.lastAdRequestTime = Date.now();
5228
5560
  }
5229
5561
  },
5562
+ {
5563
+ key: "notePodAdStarted",
5564
+ value: function notePodAdStarted() {
5565
+ this.currentAdIndex++;
5566
+ this.totalAdsInBreak = this.currentAdIndex;
5567
+ }
5568
+ },
5230
5569
  {
5231
5570
  key: "getRemainingAdMs",
5232
5571
  value: function getRemainingAdMs() {
@@ -6735,13 +7074,26 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
6735
7074
  }
6736
7075
  },
6737
7076
  {
6738
- // ───────────────────────────────────────────────────────────────
7077
+ key: "optimizedPodsEnabled",
7078
+ get: // ───────────────────────────────────────────────────────────────
6739
7079
  // IMA event listeners
6740
7080
  // ───────────────────────────────────────────────────────────────
7081
+ function get() {
7082
+ return !!this.host.config.optimizedPods;
7083
+ }
7084
+ },
7085
+ {
6741
7086
  key: "attachImaEventListeners",
6742
7087
  value: function attachImaEventListeners() {
6743
7088
  var _this = this;
6744
7089
  var adPlayer = this.host.getAdPlayer();
7090
+ adPlayer.on("pod_ad_started", function(payload) {
7091
+ _this.timing.notePodAdStarted();
7092
+ if (_this.debug) {
7093
+ var _ref;
7094
+ 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 : "?"));
7095
+ }
7096
+ });
6745
7097
  adPlayer.on("all_ads_completed", function() {
6746
7098
  sendAdImpressionTracking(_this.host.config.licenseKey, {
6747
7099
  source: "hls",
@@ -6899,7 +7251,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
6899
7251
  // ───────────────────────────────────────────────────────────────
6900
7252
  function handleAdStart(_marker) {
6901
7253
  return _async_to_generator(function() {
6902
- var scheduled, tags, baseVastUrl, adBreakDurationMs, mode, currentMuted, currentVolume, firstAdUrl, usePreloadedAd, preloadedController, preloaded, firstAdUrlArray, adPlayer, preservedMuted, preservedVolume, adVolume, adPlayer1, adVolume1, error, fallbackPreloaded, ap, adVolume2, fallbackError;
7254
+ 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;
6903
7255
  return _ts_generator(this, function(_state) {
6904
7256
  switch(_state.label){
6905
7257
  case 0:
@@ -6946,6 +7298,26 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
6946
7298
  if (this.timing.expectedAdBreakDurationMs == null && adBreakDurationMs != null) {
6947
7299
  this.timing.expectedAdBreakDurationMs = adBreakDurationMs;
6948
7300
  }
7301
+ if (!this.optimizedPodsEnabled) return [
7302
+ 3,
7303
+ 2
7304
+ ];
7305
+ return [
7306
+ 4,
7307
+ this.startOptimizedPod(baseVastUrl, adBreakDurationMs, currentMuted, currentVolume)
7308
+ ];
7309
+ case 1:
7310
+ podPlayed = _state.sent();
7311
+ if (podPlayed) {
7312
+ return [
7313
+ 2
7314
+ ];
7315
+ }
7316
+ if (this.debug) {
7317
+ console.log("[POD] Optimized pod unavailable, falling back to sequential single-ad path");
7318
+ }
7319
+ _state.label = 2;
7320
+ case 2:
6949
7321
  usePreloadedAd = false;
6950
7322
  preloaded = this.preloadPool.getPreloadedAd();
6951
7323
  if (preloaded) {
@@ -6987,21 +7359,21 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
6987
7359
  if (this.debug) {
6988
7360
  console.log("[CONTINUOUS-FETCH] First VAST URL:", firstAdUrl);
6989
7361
  }
6990
- _state.label = 1;
6991
- case 1:
7362
+ _state.label = 3;
7363
+ case 3:
6992
7364
  _state.trys.push([
6993
- 1,
6994
- 12,
7365
+ 3,
7366
+ 14,
6995
7367
  ,
6996
- 20
7368
+ 22
6997
7369
  ]);
6998
7370
  if (!(usePreloadedAd && preloadedController)) return [
6999
7371
  3,
7000
- 5
7372
+ 7
7001
7373
  ];
7002
7374
  if (!!this.timing.ensureLoadedAdFitsBudget(preloadedController)) return [
7003
7375
  3,
7004
- 3
7376
+ 5
7005
7377
  ];
7006
7378
  this.timing.rejectLoadedAdForDuration(preloadedController);
7007
7379
  this.startContinuousFetching(baseVastUrl);
@@ -7009,12 +7381,12 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7009
7381
  4,
7010
7382
  this.tryNextAvailableAdWithRateLimit()
7011
7383
  ];
7012
- case 2:
7384
+ case 4:
7013
7385
  _state.sent();
7014
7386
  return [
7015
7387
  2
7016
7388
  ];
7017
- case 3:
7389
+ case 5:
7018
7390
  adPlayer = this.host.getAdPlayer();
7019
7391
  preservedMuted = adPlayer.getOriginalMutedState();
7020
7392
  preservedVolume = adPlayer.getOriginalVolume();
@@ -7039,7 +7411,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7039
7411
  4,
7040
7412
  preloadedController.play()
7041
7413
  ];
7042
- case 4:
7414
+ case 6:
7043
7415
  _state.sent();
7044
7416
  this.timing.markAdStarted();
7045
7417
  if (this.timing.expectedAdBreakDurationMs != null && this.timing.getAdBreakEndWallClockMs() == null) {
@@ -7049,22 +7421,22 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7049
7421
  preloadedController.setAdVolume(adVolume);
7050
7422
  return [
7051
7423
  3,
7052
- 11
7424
+ 13
7053
7425
  ];
7054
- case 5:
7426
+ case 7:
7055
7427
  adPlayer1 = this.host.getAdPlayer();
7056
7428
  return [
7057
7429
  4,
7058
7430
  this.timing.enforceGlobalRateLimit()
7059
7431
  ];
7060
- case 6:
7432
+ case 8:
7061
7433
  _state.sent();
7062
7434
  this.timing.lastAdRequestTime = Date.now();
7063
7435
  return [
7064
7436
  4,
7065
7437
  adPlayer1.requestAds(firstAdUrl)
7066
7438
  ];
7067
- case 7:
7439
+ case 9:
7068
7440
  _state.sent();
7069
7441
  sendAdLoadedTracking(this.host.config.licenseKey, {
7070
7442
  source: "hls",
@@ -7076,7 +7448,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7076
7448
  }
7077
7449
  if (!!this.timing.ensureLoadedAdFitsBudget(adPlayer1)) return [
7078
7450
  3,
7079
- 9
7451
+ 11
7080
7452
  ];
7081
7453
  this.timing.rejectLoadedAdForDuration(adPlayer1);
7082
7454
  this.recreateAdController();
@@ -7085,12 +7457,12 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7085
7457
  4,
7086
7458
  this.tryNextAvailableAdWithRateLimit()
7087
7459
  ];
7088
- case 8:
7460
+ case 10:
7089
7461
  _state.sent();
7090
7462
  return [
7091
7463
  2
7092
7464
  ];
7093
- case 9:
7465
+ case 11:
7094
7466
  this.timing.consecutiveFailures = 0;
7095
7467
  this.startContinuousFetching(baseVastUrl);
7096
7468
  if (!this.preloadPool.active) {
@@ -7100,7 +7472,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7100
7472
  4,
7101
7473
  adPlayer1.play()
7102
7474
  ];
7103
- case 10:
7475
+ case 12:
7104
7476
  _state.sent();
7105
7477
  this.timing.markAdStarted();
7106
7478
  if (this.timing.expectedAdBreakDurationMs != null && this.timing.getAdBreakEndWallClockMs() == null) {
@@ -7108,40 +7480,40 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7108
7480
  }
7109
7481
  adVolume1 = currentMuted ? 0 : currentVolume;
7110
7482
  adPlayer1.setAdVolume(adVolume1);
7111
- _state.label = 11;
7112
- case 11:
7483
+ _state.label = 13;
7484
+ case 13:
7113
7485
  return [
7114
7486
  3,
7115
- 20
7487
+ 22
7116
7488
  ];
7117
- case 12:
7489
+ case 14:
7118
7490
  error = _state.sent();
7119
7491
  if (this.debug) {
7120
7492
  console.warn("[CONTINUOUS-FETCH] First ad request failed:", error);
7121
7493
  }
7122
7494
  if (!!usePreloadedAd) return [
7123
7495
  3,
7124
- 18
7496
+ 20
7125
7497
  ];
7126
7498
  fallbackPreloaded = this.preloadPool.getPreloadedAd();
7127
7499
  if (!fallbackPreloaded) return [
7128
7500
  3,
7129
- 18
7501
+ 20
7130
7502
  ];
7131
7503
  if (this.debug) {
7132
7504
  console.log("[CONTINUOUS-FETCH] First ad failed, using preloaded fallback");
7133
7505
  }
7134
- _state.label = 13;
7135
- case 13:
7506
+ _state.label = 15;
7507
+ case 15:
7136
7508
  _state.trys.push([
7137
- 13,
7138
- 17,
7509
+ 15,
7510
+ 19,
7139
7511
  ,
7140
- 18
7512
+ 20
7141
7513
  ]);
7142
7514
  if (!!this.timing.ensureLoadedAdFitsBudget(fallbackPreloaded.adController)) return [
7143
7515
  3,
7144
- 15
7516
+ 17
7145
7517
  ];
7146
7518
  this.timing.rejectLoadedAdForDuration(fallbackPreloaded.adController);
7147
7519
  this.startContinuousFetching(baseVastUrl);
@@ -7149,12 +7521,12 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7149
7521
  4,
7150
7522
  this.tryNextAvailableAdWithRateLimit()
7151
7523
  ];
7152
- case 14:
7524
+ case 16:
7153
7525
  _state.sent();
7154
7526
  return [
7155
7527
  2
7156
7528
  ];
7157
- case 15:
7529
+ case 17:
7158
7530
  this.swapToPreloadedAdPlayer(fallbackPreloaded.adController);
7159
7531
  this.timing.consecutiveFailures = 0;
7160
7532
  this.startContinuousFetching(baseVastUrl);
@@ -7167,7 +7539,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7167
7539
  4,
7168
7540
  ap.play()
7169
7541
  ];
7170
- case 16:
7542
+ case 18:
7171
7543
  _state.sent();
7172
7544
  this.timing.markAdStarted();
7173
7545
  if (this.timing.expectedAdBreakDurationMs != null && this.timing.getAdBreakEndWallClockMs() == null) {
@@ -7178,16 +7550,16 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7178
7550
  return [
7179
7551
  2
7180
7552
  ];
7181
- case 17:
7553
+ case 19:
7182
7554
  fallbackError = _state.sent();
7183
7555
  if (this.debug) {
7184
7556
  console.warn("[CONTINUOUS-FETCH] Preloaded fallback also failed:", fallbackError);
7185
7557
  }
7186
7558
  return [
7187
7559
  3,
7188
- 18
7560
+ 20
7189
7561
  ];
7190
- case 18:
7562
+ case 20:
7191
7563
  if (this.timing.isTemporaryAdError(error)) {
7192
7564
  this.timing.temporaryFailureUrls.set(firstAdUrl, Date.now());
7193
7565
  if (this.debug) {
@@ -7205,13 +7577,137 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7205
7577
  4,
7206
7578
  this.tryNextAvailableAdWithRateLimit()
7207
7579
  ];
7208
- case 19:
7580
+ case 21:
7209
7581
  _state.sent();
7210
7582
  return [
7211
7583
  3,
7212
- 20
7584
+ 22
7213
7585
  ];
7214
- case 20:
7586
+ case 22:
7587
+ return [
7588
+ 2
7589
+ ];
7590
+ }
7591
+ });
7592
+ }).call(this);
7593
+ }
7594
+ },
7595
+ {
7596
+ key: "startOptimizedPod",
7597
+ value: // ───────────────────────────────────────────────────────────────
7598
+ // Optimized pod (single multi-ad request)
7599
+ // ───────────────────────────────────────────────────────────────
7600
+ function startOptimizedPod(baseVastUrl, breakDurationMs, currentMuted, currentVolume) {
7601
+ return _async_to_generator(function() {
7602
+ var podUrl, adPlayer, requestToken, _ref, _adPlayer_getPodAdCount, podCount, error;
7603
+ return _ts_generator(this, function(_state) {
7604
+ switch(_state.label){
7605
+ case 0:
7606
+ if (this.pendingAdBreak && this.pendingAdBreak.vastUrls.length > 0) {
7607
+ podUrl = this.pendingAdBreak.vastUrls[0];
7608
+ this.clearPendingAdBreak();
7609
+ } else {
7610
+ podUrl = this.host.generatePodVastUrl(baseVastUrl, breakDurationMs);
7611
+ }
7612
+ if (!podUrl) {
7613
+ return [
7614
+ 2,
7615
+ false
7616
+ ];
7617
+ }
7618
+ this.continuousFetchingActive = false;
7619
+ this.recreateAdController();
7620
+ adPlayer = this.host.getAdPlayer();
7621
+ requestToken = ++this.timing.adRequestTokenCounter;
7622
+ this.timing.activeAdRequestToken = requestToken;
7623
+ this.timing.startAdRequestWatchdog(requestToken);
7624
+ _state.label = 1;
7625
+ case 1:
7626
+ _state.trys.push([
7627
+ 1,
7628
+ 5,
7629
+ ,
7630
+ 6
7631
+ ]);
7632
+ return [
7633
+ 4,
7634
+ this.timing.enforceGlobalRateLimit()
7635
+ ];
7636
+ case 2:
7637
+ _state.sent();
7638
+ this.timing.lastAdRequestTime = Date.now();
7639
+ return [
7640
+ 4,
7641
+ adPlayer.requestAds(podUrl)
7642
+ ];
7643
+ case 3:
7644
+ _state.sent();
7645
+ this.timing.clearAdRequestWatchdog();
7646
+ if (this.timing.activeAdRequestToken !== requestToken) {
7647
+ return [
7648
+ 2,
7649
+ true
7650
+ ];
7651
+ }
7652
+ podCount = (_ref = (_adPlayer_getPodAdCount = adPlayer.getPodAdCount) === null || _adPlayer_getPodAdCount === void 0 ? void 0 : _adPlayer_getPodAdCount.call(adPlayer)) !== null && _ref !== void 0 ? _ref : 1;
7653
+ if (podCount < 1) {
7654
+ return [
7655
+ 2,
7656
+ false
7657
+ ];
7658
+ }
7659
+ if (this.debug) {
7660
+ 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"));
7661
+ }
7662
+ sendAdLoadedTracking(this.host.config.licenseKey, {
7663
+ source: "hls",
7664
+ vastUrl: podUrl,
7665
+ timestamp: /* @__PURE__ */ new Date().toISOString()
7666
+ }, this.analyticsContext).catch(function() {});
7667
+ this.timing.startAdFailsafeTimer(requestToken);
7668
+ return [
7669
+ 4,
7670
+ adPlayer.play()
7671
+ ];
7672
+ case 4:
7673
+ _state.sent();
7674
+ this.timing.markAdStarted();
7675
+ if (this.timing.expectedAdBreakDurationMs != null && this.timing.getAdBreakEndWallClockMs() == null) {
7676
+ this.timing.scheduleAdStopAtBreakBoundary();
7677
+ }
7678
+ adPlayer.setAdVolume(currentMuted ? 0 : currentVolume);
7679
+ this.timing.consecutiveFailures = 0;
7680
+ if (podCount === 1) {
7681
+ this.continuousFetchingActive = true;
7682
+ this.startContinuousFetching(baseVastUrl);
7683
+ if (!this.preloadPool.active) {
7684
+ this.preloadPool.startPreloadPool(baseVastUrl, []);
7685
+ }
7686
+ }
7687
+ return [
7688
+ 2,
7689
+ true
7690
+ ];
7691
+ case 5:
7692
+ error = _state.sent();
7693
+ this.timing.clearAdRequestWatchdog();
7694
+ this.timing.clearAdFailsafeTimer();
7695
+ if (this.timing.activeAdRequestToken === requestToken) {
7696
+ this.timing.activeAdRequestToken = null;
7697
+ }
7698
+ if (this.debug) {
7699
+ console.warn("[POD] Optimized pod request/play failed:", error);
7700
+ }
7701
+ if (this.timing.isTemporaryAdError(error)) {
7702
+ this.timing.temporaryFailureUrls.set(podUrl, Date.now());
7703
+ }
7704
+ this.continuousFetchingActive = true;
7705
+ this.recreateAdController();
7706
+ return [
7707
+ 2,
7708
+ false
7709
+ ];
7710
+ case 6:
7215
7711
  return [
7216
7712
  2
7217
7713
  ];
@@ -8293,6 +8789,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8293
8789
  },
8294
8790
  generateVastUrls: function generateVastUrls(base, count) {
8295
8791
  return _this.generateVastUrls(base, count);
8792
+ },
8793
+ generatePodVastUrl: function generatePodVastUrl(base, breakDurationMs) {
8794
+ return _this.generatePodVastUrl(base, breakDurationMs);
8296
8795
  }
8297
8796
  }, this.timing, this.preloadPool, this.adConfig, this.cueManager, this.placeholder);
8298
8797
  }
@@ -8325,6 +8824,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8325
8824
  return this.adConfig.generateVastUrlsWithCorrelators(baseUrl, count, this.adPlayer, this.palNonce, this.adBreak.inAdBreak);
8326
8825
  }
8327
8826
  },
8827
+ {
8828
+ key: "generatePodVastUrl",
8829
+ value: function generatePodVastUrl(baseUrl, breakDurationMs) {
8830
+ var podParams = this.adConfig.resolvePodParams(breakDurationMs);
8831
+ return this.adConfig.generatePodVastUrl(baseUrl, podParams, this.adPlayer, this.palNonce, this.adBreak.inAdBreak);
8832
+ }
8833
+ },
8328
8834
  {
8329
8835
  key: "load",
8330
8836
  value: // ───────────────────────────────────────────────────────────────
@@ -8713,7 +9219,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8713
9219
  }
8714
9220
  this.adConfig.beginNewAdPod();
8715
9221
  this.adConfig.podAssignedByPrefetch = true;
8716
- var generatedUrls = this.generateVastUrls(baseVastUrl, 1);
9222
+ var optimizedPods = !!this.config.optimizedPods;
9223
+ var breakDurationMs = marker.durationSeconds != null ? marker.durationSeconds * 1e3 : void 0;
9224
+ var generatedUrls = optimizedPods ? [
9225
+ this.generatePodVastUrl(baseVastUrl, breakDurationMs)
9226
+ ] : this.generateVastUrls(baseVastUrl, 1);
8717
9227
  this.adBreak.pendingAdBreak = _object_spread_props(_object_spread({
8718
9228
  marker: marker
8719
9229
  }, fragmentSn !== void 0 ? {
@@ -8735,7 +9245,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8735
9245
  }, detectPayload), buildAnalyticsContext(this.config)).catch(function() {});
8736
9246
  if (this.debug) {
8737
9247
  console.log("[PREFETCH] Starting ad prefetch for upcoming ad break");
8738
- console.log("[PREFETCH] Pre-generated ".concat(generatedUrls.length, " VAST URLs"));
9248
+ console.log("[PREFETCH] Pre-generated ".concat(generatedUrls.length, " ").concat(optimizedPods ? "pod" : "VAST", " URL(s)"));
9249
+ }
9250
+ if (optimizedPods) {
9251
+ if (this.debug) {
9252
+ console.log("[PREFETCH] Optimized pods enabled - skipping single-ad preload pool");
9253
+ }
9254
+ return;
8739
9255
  }
8740
9256
  this.preloadPool.startPreloadPool(baseVastUrl, generatedUrls.slice(0, 1), false);
8741
9257
  }