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
@@ -448,6 +448,8 @@ function createHlsAdPlayer(contentVideo, options) {
448
448
  var adHls;
449
449
  var adContainerEl;
450
450
  var currentAd;
451
+ var podAds = [];
452
+ var podIndex = 0;
451
453
  var sessionId;
452
454
  var preloadedAds = /* @__PURE__ */ new Map();
453
455
  var preloadingAds = /* @__PURE__ */ new Map();
@@ -612,14 +614,14 @@ function createHlsAdPlayer(contentVideo, options) {
612
614
  error: []
613
615
  };
614
616
  }
615
- function extractTrackingUrls(xmlDoc) {
617
+ function extractTrackingUrls(scope) {
616
618
  var trackingUrls = createEmptyTrackingUrls();
617
- xmlDoc.querySelectorAll("Impression").forEach(function(el) {
619
+ scope.querySelectorAll("Impression").forEach(function(el) {
618
620
  var _el_textContent;
619
621
  var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
620
622
  if (url) trackingUrls.impression.push(url);
621
623
  });
622
- xmlDoc.querySelectorAll("Tracking").forEach(function(el) {
624
+ scope.querySelectorAll("Tracking").forEach(function(el) {
623
625
  var _el_textContent;
624
626
  var event = el.getAttribute("event");
625
627
  var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
@@ -630,7 +632,7 @@ function createHlsAdPlayer(contentVideo, options) {
630
632
  }
631
633
  }
632
634
  });
633
- xmlDoc.querySelectorAll("Error").forEach(function(el) {
635
+ scope.querySelectorAll("Error").forEach(function(el) {
634
636
  var _el_textContent;
635
637
  var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
636
638
  if (url) trackingUrls.error.push(url);
@@ -740,6 +742,75 @@ function createHlsAdPlayer(contentVideo, options) {
740
742
  };
741
743
  }
742
744
  }
745
+ function parseAdElement(adElement) {
746
+ try {
747
+ var _adElement_querySelector, _adElement_querySelector_textContent, _adElement_querySelector1, _adElement_querySelector_textContent1, _adElement_querySelector2, _adElement_querySelector3;
748
+ var adId = adElement.getAttribute("id") || "unknown";
749
+ var title = ((_adElement_querySelector = adElement.querySelector("AdTitle")) === null || _adElement_querySelector === void 0 ? void 0 : _adElement_querySelector.textContent) || "Ad";
750
+ 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();
751
+ 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();
752
+ if (wrapperUri) {
753
+ return {
754
+ type: "wrapper",
755
+ vastAdTagUri: wrapperUri,
756
+ trackingUrls: extractTrackingUrls(adElement),
757
+ clickThrough: clickThrough
758
+ };
759
+ }
760
+ var isNoAdAvailable = adId === "empty" || title.toLowerCase().includes("no ad available") || title.toLowerCase() === "no ad available";
761
+ var durationText = ((_adElement_querySelector3 = adElement.querySelector("Duration")) === null || _adElement_querySelector3 === void 0 ? void 0 : _adElement_querySelector3.textContent) || "00:00:30";
762
+ var durationParts = durationText.split(":");
763
+ var duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseInt(durationParts[2] || "0", 10);
764
+ var mediaFileElements = adElement.querySelectorAll("MediaFile");
765
+ var mediaFiles = [];
766
+ mediaFileElements.forEach(function(mf) {
767
+ var _mf_textContent;
768
+ var type = mf.getAttribute("type") || "";
769
+ var url = ((_mf_textContent = mf.textContent) === null || _mf_textContent === void 0 ? void 0 : _mf_textContent.trim()) || "";
770
+ var width = mf.getAttribute("width") || "";
771
+ var height = mf.getAttribute("height") || "";
772
+ if (!url) return;
773
+ var bitrateAttr = mf.getAttribute("bitrate");
774
+ var bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;
775
+ var mediaFile = {
776
+ url: url,
777
+ type: type,
778
+ width: parseInt(width || "1920", 10),
779
+ height: parseInt(height || "1080", 10),
780
+ bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : void 0
781
+ };
782
+ if (isHlsMediaFile(mediaFile) || isProgressiveMediaFile(mediaFile)) {
783
+ mediaFiles.push(mediaFile);
784
+ }
785
+ });
786
+ if (mediaFiles.length === 0) {
787
+ if (isNoAdAvailable) {
788
+ console.warn("[HlsAdPlayer] Pod <Ad> indicates no ad available");
789
+ } else {
790
+ console.warn("[HlsAdPlayer] No supported media files in pod <Ad>");
791
+ }
792
+ return {
793
+ type: "empty"
794
+ };
795
+ }
796
+ return {
797
+ type: "inline",
798
+ ad: {
799
+ id: adId,
800
+ title: title,
801
+ duration: duration,
802
+ mediaFiles: mediaFiles,
803
+ trackingUrls: extractTrackingUrls(adElement),
804
+ clickThrough: clickThrough
805
+ }
806
+ };
807
+ } catch (error) {
808
+ console.error("[HlsAdPlayer] Error parsing pod <Ad> element:", error);
809
+ return {
810
+ type: "empty"
811
+ };
812
+ }
813
+ }
743
814
  function fetchVastXml(vastTagUrl) {
744
815
  return _async_to_generator(function() {
745
816
  var response;
@@ -816,6 +887,146 @@ function createHlsAdPlayer(contentVideo, options) {
816
887
  });
817
888
  }).apply(this, arguments);
818
889
  }
890
+ function fetchAndParsePod(vastTagUrl) {
891
+ return _async_to_generator(function() {
892
+ var vastXml, parser, xmlDoc, adElements, ads, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, adElement, parsed, resolved, error, err;
893
+ return _ts_generator(this, function(_state) {
894
+ switch(_state.label){
895
+ case 0:
896
+ return [
897
+ 4,
898
+ fetchVastXml(vastTagUrl)
899
+ ];
900
+ case 1:
901
+ vastXml = _state.sent();
902
+ console.log("[HlsAdPlayer] Pod VAST XML received");
903
+ parser = new DOMParser();
904
+ xmlDoc = parser.parseFromString(vastXml, "text/xml");
905
+ if (xmlDoc.querySelector("parsererror")) {
906
+ console.error("[HlsAdPlayer] Pod VAST XML parsing error (malformed)");
907
+ return [
908
+ 2,
909
+ []
910
+ ];
911
+ }
912
+ adElements = Array.from(xmlDoc.querySelectorAll("Ad"));
913
+ if (adElements.length === 0) {
914
+ console.warn("[HlsAdPlayer] No <Ad> elements found in pod VAST response");
915
+ return [
916
+ 2,
917
+ []
918
+ ];
919
+ }
920
+ adElements.sort(function(a, b) {
921
+ var aSeq = parseInt(a.getAttribute("sequence") || "", 10);
922
+ var bSeq = parseInt(b.getAttribute("sequence") || "", 10);
923
+ var aVal = Number.isFinite(aSeq) ? aSeq : Number.MAX_SAFE_INTEGER;
924
+ var bVal = Number.isFinite(bSeq) ? bSeq : Number.MAX_SAFE_INTEGER;
925
+ return aVal - bVal;
926
+ });
927
+ ads = [];
928
+ _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
929
+ _state.label = 2;
930
+ case 2:
931
+ _state.trys.push([
932
+ 2,
933
+ 10,
934
+ 11,
935
+ 12
936
+ ]);
937
+ _iterator = adElements[Symbol.iterator]();
938
+ _state.label = 3;
939
+ case 3:
940
+ if (!!(_iteratorNormalCompletion = (_step = _iterator.next()).done)) return [
941
+ 3,
942
+ 9
943
+ ];
944
+ adElement = _step.value;
945
+ parsed = parseAdElement(adElement);
946
+ if (!(parsed.type === "inline")) return [
947
+ 3,
948
+ 4
949
+ ];
950
+ ads.push(parsed.ad);
951
+ return [
952
+ 3,
953
+ 8
954
+ ];
955
+ case 4:
956
+ if (!(parsed.type === "wrapper")) return [
957
+ 3,
958
+ 8
959
+ ];
960
+ _state.label = 5;
961
+ case 5:
962
+ _state.trys.push([
963
+ 5,
964
+ 7,
965
+ ,
966
+ 8
967
+ ]);
968
+ return [
969
+ 4,
970
+ fetchAndParseVastAd(parsed.vastAdTagUri, 1, parsed.trackingUrls)
971
+ ];
972
+ case 6:
973
+ resolved = _state.sent();
974
+ if (resolved) {
975
+ ads.push(resolved);
976
+ }
977
+ return [
978
+ 3,
979
+ 8
980
+ ];
981
+ case 7:
982
+ error = _state.sent();
983
+ console.warn("[HlsAdPlayer] Failed to resolve wrapper <Ad> in pod:", error);
984
+ return [
985
+ 3,
986
+ 8
987
+ ];
988
+ case 8:
989
+ _iteratorNormalCompletion = true;
990
+ return [
991
+ 3,
992
+ 3
993
+ ];
994
+ case 9:
995
+ return [
996
+ 3,
997
+ 12
998
+ ];
999
+ case 10:
1000
+ err = _state.sent();
1001
+ _didIteratorError = true;
1002
+ _iteratorError = err;
1003
+ return [
1004
+ 3,
1005
+ 12
1006
+ ];
1007
+ case 11:
1008
+ try {
1009
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1010
+ _iterator.return();
1011
+ }
1012
+ } finally{
1013
+ if (_didIteratorError) {
1014
+ throw _iteratorError;
1015
+ }
1016
+ }
1017
+ return [
1018
+ 7
1019
+ ];
1020
+ case 12:
1021
+ console.log("[HlsAdPlayer] Parsed ".concat(ads.length, " ad(s) from pod VAST response"));
1022
+ return [
1023
+ 2,
1024
+ ads
1025
+ ];
1026
+ }
1027
+ });
1028
+ })();
1029
+ }
819
1030
  function createAdVideoElement() {
820
1031
  var video = document.createElement("video");
821
1032
  video.style.position = "absolute";
@@ -860,6 +1071,9 @@ function createHlsAdPlayer(contentVideo, options) {
860
1071
  trackingFired.complete = true;
861
1072
  fireTrackingPixels(currentAd.trackingUrls.complete);
862
1073
  console.log("[HlsAdPlayer] Ad completed");
1074
+ if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1075
+ return;
1076
+ }
863
1077
  handleAdComplete();
864
1078
  });
865
1079
  adVideoElement.addEventListener("error", function(e) {
@@ -868,6 +1082,9 @@ function createHlsAdPlayer(contentVideo, options) {
868
1082
  if (currentAd) {
869
1083
  fireTrackingPixels(currentAd.trackingUrls.error);
870
1084
  }
1085
+ if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1086
+ return;
1087
+ }
871
1088
  handleAdError();
872
1089
  });
873
1090
  adVideoElement.addEventListener("volumechange", function() {
@@ -896,6 +1113,94 @@ function createHlsAdPlayer(contentVideo, options) {
896
1113
  delete contentVideo.dataset.stormcloudAdPlaying;
897
1114
  }
898
1115
  }
1116
+ function resetQuartileTracking(preserveImpression) {
1117
+ trackingFired = {
1118
+ impression: preserveImpression ? trackingFired.impression : false,
1119
+ start: false,
1120
+ firstQuartile: false,
1121
+ midpoint: false,
1122
+ thirdQuartile: false,
1123
+ complete: false
1124
+ };
1125
+ }
1126
+ function loadCurrentAdMedia() {
1127
+ if (!adVideoElement || !currentAd) {
1128
+ throw new Error("No ad video element or ad to load");
1129
+ }
1130
+ var mediaFile = selectBestMediaFile(currentAd.mediaFiles);
1131
+ if (!mediaFile) {
1132
+ throw new Error("No media file available for ad");
1133
+ }
1134
+ var isHlsAd = isHlsMediaFile(mediaFile);
1135
+ console.log("[HlsAdPlayer] Loading ".concat(isHlsAd ? "HLS" : "progressive", " ad (pod ").concat(podIndex + 1, "/").concat(podAds.length || 1, ") from: ").concat(mediaFile.url));
1136
+ if (isHlsAd && import_hls.default.isSupported()) {
1137
+ if (adHls) {
1138
+ adHls.destroy();
1139
+ }
1140
+ adHls = new import_hls.default({
1141
+ enableWorker: true,
1142
+ lowLatencyMode: false
1143
+ });
1144
+ adHls.loadSource(mediaFile.url);
1145
+ adHls.attachMedia(adVideoElement);
1146
+ adHls.on(import_hls.default.Events.MANIFEST_PARSED, function() {
1147
+ console.log("[HlsAdPlayer] HLS manifest parsed, starting playback");
1148
+ adVideoElement.play().catch(function(error) {
1149
+ console.error("[HlsAdPlayer] Error starting ad playback:", error);
1150
+ handleAdError();
1151
+ });
1152
+ });
1153
+ adHls.on(import_hls.default.Events.ERROR, function(_event, data) {
1154
+ console.error("[HlsAdPlayer] HLS error:", data);
1155
+ if (data.fatal) {
1156
+ handleAdError();
1157
+ }
1158
+ });
1159
+ } else if (isHlsAd && adVideoElement.canPlayType("application/vnd.apple.mpegurl")) {
1160
+ adVideoElement.src = mediaFile.url;
1161
+ adVideoElement.play().catch(function(error) {
1162
+ console.error("[HlsAdPlayer] Error starting ad playback:", error);
1163
+ handleAdError();
1164
+ });
1165
+ } else if (!isHlsAd && isProgressiveMediaFile(mediaFile)) {
1166
+ if (adHls) {
1167
+ adHls.destroy();
1168
+ adHls = void 0;
1169
+ }
1170
+ adVideoElement.src = mediaFile.url;
1171
+ adVideoElement.load();
1172
+ adVideoElement.play().catch(function(error) {
1173
+ console.error("[HlsAdPlayer] Error starting progressive ad playback:", error);
1174
+ handleAdError();
1175
+ });
1176
+ } else {
1177
+ throw new Error("Unsupported ad media file type: ".concat(mediaFile.type));
1178
+ }
1179
+ }
1180
+ function advanceToNextPodAd() {
1181
+ if (podIndex >= podAds.length - 1) {
1182
+ return false;
1183
+ }
1184
+ podIndex++;
1185
+ currentAd = podAds[podIndex];
1186
+ resetQuartileTracking(false);
1187
+ if (currentAd) {
1188
+ fireTrackingPixels(currentAd.trackingUrls.impression);
1189
+ trackingFired.impression = true;
1190
+ console.log("[HlsAdPlayer] Advancing to next pod ad (".concat(podIndex + 1, "/").concat(podAds.length, "): ").concat(currentAd.title, ", duration: ").concat(currentAd.duration, "s"));
1191
+ }
1192
+ try {
1193
+ loadCurrentAdMedia();
1194
+ emit("pod_ad_started", {
1195
+ index: podIndex,
1196
+ total: podAds.length
1197
+ });
1198
+ return true;
1199
+ } catch (error) {
1200
+ console.error("[HlsAdPlayer] Failed to load next pod ad:", error);
1201
+ return false;
1202
+ }
1203
+ }
899
1204
  function handleAdComplete() {
900
1205
  console.log("[HlsAdPlayer] Handling ad completion");
901
1206
  adPlaying = false;
@@ -949,7 +1254,7 @@ function createHlsAdPlayer(contentVideo, options) {
949
1254
  },
950
1255
  requestAds: function requestAds(vastTagUrl) {
951
1256
  return _async_to_generator(function() {
952
- var ad, error;
1257
+ var ads, preloaded, error;
953
1258
  return _ts_generator(this, function(_state) {
954
1259
  switch(_state.label){
955
1260
  case 0:
@@ -970,12 +1275,18 @@ function createHlsAdPlayer(contentVideo, options) {
970
1275
  6
971
1276
  ]);
972
1277
  sessionId = generateSessionId();
1278
+ ads = [];
973
1279
  if (!preloadedAds.has(vastTagUrl)) return [
974
1280
  3,
975
1281
  2
976
1282
  ];
977
- ad = preloadedAds.get(vastTagUrl);
1283
+ preloaded = preloadedAds.get(vastTagUrl);
978
1284
  preloadedAds.delete(vastTagUrl);
1285
+ if (preloaded) {
1286
+ ads = [
1287
+ preloaded
1288
+ ];
1289
+ }
979
1290
  console.log("[HlsAdPlayer] Using preloaded VAST response:", vastTagUrl);
980
1291
  return [
981
1292
  3,
@@ -984,13 +1295,13 @@ function createHlsAdPlayer(contentVideo, options) {
984
1295
  case 2:
985
1296
  return [
986
1297
  4,
987
- fetchAndParseVastAd(vastTagUrl)
1298
+ fetchAndParsePod(vastTagUrl)
988
1299
  ];
989
1300
  case 3:
990
- ad = _state.sent();
1301
+ ads = _state.sent();
991
1302
  _state.label = 4;
992
1303
  case 4:
993
- if (!ad) {
1304
+ if (!ads.length) {
994
1305
  console.warn("[HlsAdPlayer] No ads available from VAST response");
995
1306
  emit("ad_error");
996
1307
  return [
@@ -998,10 +1309,14 @@ function createHlsAdPlayer(contentVideo, options) {
998
1309
  Promise.reject(new Error("No ads available from VAST response"))
999
1310
  ];
1000
1311
  }
1001
- currentAd = ad;
1002
- console.log("[HlsAdPlayer] Ad parsed: ".concat(ad.title, ", duration: ").concat(ad.duration, "s"));
1003
- fireTrackingPixels(ad.trackingUrls.impression);
1004
- trackingFired.impression = true;
1312
+ podAds = ads;
1313
+ podIndex = 0;
1314
+ currentAd = ads[0];
1315
+ 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"));
1316
+ if (currentAd) {
1317
+ fireTrackingPixels(currentAd.trackingUrls.impression);
1318
+ trackingFired.impression = true;
1319
+ }
1005
1320
  return [
1006
1321
  2,
1007
1322
  Promise.resolve()
@@ -1024,7 +1339,7 @@ function createHlsAdPlayer(contentVideo, options) {
1024
1339
  },
1025
1340
  play: function play() {
1026
1341
  return _async_to_generator(function() {
1027
- var contentVolume, mediaFile, isHlsAd;
1342
+ var contentVolume;
1028
1343
  return _ts_generator(this, function(_state) {
1029
1344
  if (!currentAd) {
1030
1345
  console.warn("[HlsAdPlayer] Cannot play: No ad loaded (no ads available)");
@@ -1040,14 +1355,7 @@ function createHlsAdPlayer(contentVideo, options) {
1040
1355
  adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.appendChild(adVideoElement);
1041
1356
  setupAdEventListeners();
1042
1357
  }
1043
- trackingFired = {
1044
- impression: trackingFired.impression,
1045
- start: false,
1046
- firstQuartile: false,
1047
- midpoint: false,
1048
- thirdQuartile: false,
1049
- complete: false
1050
- };
1358
+ resetQuartileTracking(true);
1051
1359
  contentVolume = contentVideo.volume;
1052
1360
  originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1053
1361
  if (!(options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds)) {
@@ -1065,60 +1373,12 @@ function createHlsAdPlayer(contentVideo, options) {
1065
1373
  adVideoElement.muted = originalMutedState;
1066
1374
  console.log("[HlsAdPlayer] Set ad video volume to ".concat(adVideoElement.volume, ", muted: ").concat(adVideoElement.muted, ", originalMutedState: ").concat(originalMutedState, ", contentVolume: ").concat(contentVolume));
1067
1375
  }
1068
- mediaFile = selectBestMediaFile(currentAd.mediaFiles);
1069
- if (!mediaFile) {
1070
- throw new Error("No media file available for ad");
1071
- }
1072
1376
  if (adContainerEl) {
1073
1377
  adContainerEl.style.display = "flex";
1074
1378
  adContainerEl.style.pointerEvents = "auto";
1075
1379
  }
1076
1380
  emit("content_pause");
1077
- isHlsAd = isHlsMediaFile(mediaFile);
1078
- console.log("[HlsAdPlayer] Loading ".concat(isHlsAd ? "HLS" : "progressive", " ad from: ").concat(mediaFile.url));
1079
- if (isHlsAd && import_hls.default.isSupported()) {
1080
- if (adHls) {
1081
- adHls.destroy();
1082
- }
1083
- adHls = new import_hls.default({
1084
- enableWorker: true,
1085
- lowLatencyMode: false
1086
- });
1087
- adHls.loadSource(mediaFile.url);
1088
- adHls.attachMedia(adVideoElement);
1089
- adHls.on(import_hls.default.Events.MANIFEST_PARSED, function() {
1090
- console.log("[HlsAdPlayer] HLS manifest parsed, starting playback");
1091
- adVideoElement.play().catch(function(error) {
1092
- console.error("[HlsAdPlayer] Error starting ad playback:", error);
1093
- handleAdError();
1094
- });
1095
- });
1096
- adHls.on(import_hls.default.Events.ERROR, function(event, data) {
1097
- console.error("[HlsAdPlayer] HLS error:", data);
1098
- if (data.fatal) {
1099
- handleAdError();
1100
- }
1101
- });
1102
- } else if (isHlsAd && adVideoElement.canPlayType("application/vnd.apple.mpegurl")) {
1103
- adVideoElement.src = mediaFile.url;
1104
- adVideoElement.play().catch(function(error) {
1105
- console.error("[HlsAdPlayer] Error starting ad playback:", error);
1106
- handleAdError();
1107
- });
1108
- } else if (!isHlsAd && isProgressiveMediaFile(mediaFile)) {
1109
- if (adHls) {
1110
- adHls.destroy();
1111
- adHls = void 0;
1112
- }
1113
- adVideoElement.src = mediaFile.url;
1114
- adVideoElement.load();
1115
- adVideoElement.play().catch(function(error) {
1116
- console.error("[HlsAdPlayer] Error starting progressive ad playback:", error);
1117
- handleAdError();
1118
- });
1119
- } else {
1120
- throw new Error("Unsupported ad media file type: ".concat(mediaFile.type));
1121
- }
1381
+ loadCurrentAdMedia();
1122
1382
  return [
1123
1383
  2,
1124
1384
  Promise.resolve()
@@ -1193,6 +1453,8 @@ function createHlsAdPlayer(contentVideo, options) {
1193
1453
  adVideoElement.src = "";
1194
1454
  }
1195
1455
  currentAd = void 0;
1456
+ podAds = [];
1457
+ podIndex = 0;
1196
1458
  return [
1197
1459
  2
1198
1460
  ];
@@ -1242,6 +1504,8 @@ function createHlsAdPlayer(contentVideo, options) {
1242
1504
  }
1243
1505
  adContainerEl = void 0;
1244
1506
  currentAd = void 0;
1507
+ podAds = [];
1508
+ podIndex = 0;
1245
1509
  listeners.clear();
1246
1510
  preloadedAds.clear();
1247
1511
  preloadingAds.clear();
@@ -1333,6 +1597,14 @@ function createHlsAdPlayer(contentVideo, options) {
1333
1597
  },
1334
1598
  getLoadedAdId: function getLoadedAdId() {
1335
1599
  return currentAd === null || currentAd === void 0 ? void 0 : currentAd.id;
1600
+ },
1601
+ getPodAdCount: function getPodAdCount() {
1602
+ return podAds.length;
1603
+ },
1604
+ getPodTotalDurationMs: function getPodTotalDurationMs() {
1605
+ return podAds.reduce(function(total, ad) {
1606
+ return total + (ad.duration > 0 ? ad.duration * 1e3 : 0);
1607
+ }, 0);
1336
1608
  }
1337
1609
  };
1338
1610
  }
@@ -3161,7 +3433,20 @@ function applyVastMacros(baseUrl, ctx) {
3161
3433
  if (ctx.pod != null) {
3162
3434
  params.set("pod", String(ctx.pod));
3163
3435
  }
3164
- if (ctx.adPosition != null) {
3436
+ var optimizedPodMode = ctx.podMaxAds != null || ctx.podMinDurationMs != null || ctx.podMaxDurationMs != null;
3437
+ if (optimizedPodMode) {
3438
+ params.delete("ppos");
3439
+ params.delete("lip");
3440
+ if (ctx.podMinDurationMs != null) {
3441
+ params.set("pmnd", String(Math.max(0, Math.round(ctx.podMinDurationMs))));
3442
+ }
3443
+ if (ctx.podMaxDurationMs != null) {
3444
+ params.set("pmxd", String(Math.max(0, Math.round(ctx.podMaxDurationMs))));
3445
+ }
3446
+ if (ctx.podMaxAds != null) {
3447
+ params.set("pmad", String(Math.max(1, Math.round(ctx.podMaxAds))));
3448
+ }
3449
+ } else if (ctx.adPosition != null) {
3165
3450
  params.set("ppos", String(ctx.adPosition));
3166
3451
  }
3167
3452
  var requestUrl = ctx.contentUrl || ctx.pageUrl;
@@ -4503,6 +4788,7 @@ var AdConfigManager = /*#__PURE__*/ function() {
4503
4788
  this.podAssignedByPrefetch = false;
4504
4789
  this.adRequestPositionInBreak = 0;
4505
4790
  this.lastHeartbeatTime = 0;
4791
+ this.defaultPodMaxAds = 6;
4506
4792
  this.config = config;
4507
4793
  this.video = video;
4508
4794
  }
@@ -4958,6 +5244,52 @@ var AdConfigManager = /*#__PURE__*/ function() {
4958
5244
  return urls;
4959
5245
  }
4960
5246
  },
5247
+ {
5248
+ key: "resolvePodParams",
5249
+ value: function resolvePodParams(breakDurationMs) {
5250
+ var maxDurationMs = breakDurationMs != null && breakDurationMs > 0 ? breakDurationMs : this.config.podMaxDurationMs;
5251
+ var maxAds = this.config.podMaxAds && this.config.podMaxAds > 0 ? this.config.podMaxAds : this.apiNumberAds && this.apiNumberAds > 0 ? this.apiNumberAds : this.defaultPodMaxAds;
5252
+ var minDurationMs = this.config.podExactDuration && maxDurationMs != null ? maxDurationMs : 0;
5253
+ return {
5254
+ maxAds: maxAds,
5255
+ minDurationMs: minDurationMs,
5256
+ maxDurationMs: maxDurationMs
5257
+ };
5258
+ }
5259
+ },
5260
+ {
5261
+ key: "generatePodVastUrl",
5262
+ value: function generatePodVastUrl(baseUrl, podParams, adPlayer, palNonce, inAdBreak) {
5263
+ var _podParams_maxDurationMs;
5264
+ var adWillPlayMuted = inAdBreak ? adPlayer.getOriginalMutedState() : this.video.muted;
5265
+ var envSignals = resolveVastEnvironmentSignals(!!this.config.ctvAdRequest);
5266
+ var urlWithMacros = applyVastMacros(baseUrl, {
5267
+ correlator: generateCorrelator(),
5268
+ streamCorrelator: this.streamCorrelator,
5269
+ pod: this.podCounter > 0 ? this.podCounter : void 0,
5270
+ podMaxAds: podParams.maxAds,
5271
+ podMinDurationMs: podParams.minDurationMs,
5272
+ podMaxDurationMs: podParams.maxDurationMs,
5273
+ isCtv: envSignals.isCtv,
5274
+ contentUrl: envSignals.contentUrl,
5275
+ pageUrl: !envSignals.isCtv && typeof window !== "undefined" ? window.location.href : void 0,
5276
+ adWillPlayMuted: adWillPlayMuted,
5277
+ adWillAutoPlay: !!this.config.autoplay,
5278
+ appId: envSignals.appId,
5279
+ appName: envSignals.appName,
5280
+ sessionId: envSignals.sessionId,
5281
+ deviceId: envSignals.deviceId,
5282
+ deviceIdType: envSignals.deviceIdType,
5283
+ limitAdTracking: envSignals.limitAdTracking,
5284
+ deviceTypeHint: envSignals.deviceTypeHint,
5285
+ adTest: this.config.adTest,
5286
+ consent: this.consentSignals
5287
+ });
5288
+ var finalUrl = palNonce.injectNonce(urlWithMacros);
5289
+ 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);
5290
+ return finalUrl;
5291
+ }
5292
+ },
4961
5293
  {
4962
5294
  // --- Tracking ---
4963
5295
  key: "initializeTracking",
@@ -5263,6 +5595,13 @@ var AdTimingService = /*#__PURE__*/ function() {
5263
5595
  this.lastAdRequestTime = Date.now();
5264
5596
  }
5265
5597
  },
5598
+ {
5599
+ key: "notePodAdStarted",
5600
+ value: function notePodAdStarted() {
5601
+ this.currentAdIndex++;
5602
+ this.totalAdsInBreak = this.currentAdIndex;
5603
+ }
5604
+ },
5266
5605
  {
5267
5606
  key: "getRemainingAdMs",
5268
5607
  value: function getRemainingAdMs() {
@@ -6771,13 +7110,26 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
6771
7110
  }
6772
7111
  },
6773
7112
  {
6774
- // ───────────────────────────────────────────────────────────────
7113
+ key: "optimizedPodsEnabled",
7114
+ get: // ───────────────────────────────────────────────────────────────
6775
7115
  // IMA event listeners
6776
7116
  // ───────────────────────────────────────────────────────────────
7117
+ function get() {
7118
+ return !!this.host.config.optimizedPods;
7119
+ }
7120
+ },
7121
+ {
6777
7122
  key: "attachImaEventListeners",
6778
7123
  value: function attachImaEventListeners() {
6779
7124
  var _this = this;
6780
7125
  var adPlayer = this.host.getAdPlayer();
7126
+ adPlayer.on("pod_ad_started", function(payload) {
7127
+ _this.timing.notePodAdStarted();
7128
+ if (_this.debug) {
7129
+ var _ref;
7130
+ 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 : "?"));
7131
+ }
7132
+ });
6781
7133
  adPlayer.on("all_ads_completed", function() {
6782
7134
  sendAdImpressionTracking(_this.host.config.licenseKey, {
6783
7135
  source: "hls",
@@ -6935,7 +7287,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
6935
7287
  // ───────────────────────────────────────────────────────────────
6936
7288
  function handleAdStart(_marker) {
6937
7289
  return _async_to_generator(function() {
6938
- var scheduled, tags, baseVastUrl, adBreakDurationMs, mode, currentMuted, currentVolume, firstAdUrl, usePreloadedAd, preloadedController, preloaded, firstAdUrlArray, adPlayer, preservedMuted, preservedVolume, adVolume, adPlayer1, adVolume1, error, fallbackPreloaded, ap, adVolume2, fallbackError;
7290
+ 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;
6939
7291
  return _ts_generator(this, function(_state) {
6940
7292
  switch(_state.label){
6941
7293
  case 0:
@@ -6982,6 +7334,26 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
6982
7334
  if (this.timing.expectedAdBreakDurationMs == null && adBreakDurationMs != null) {
6983
7335
  this.timing.expectedAdBreakDurationMs = adBreakDurationMs;
6984
7336
  }
7337
+ if (!this.optimizedPodsEnabled) return [
7338
+ 3,
7339
+ 2
7340
+ ];
7341
+ return [
7342
+ 4,
7343
+ this.startOptimizedPod(baseVastUrl, adBreakDurationMs, currentMuted, currentVolume)
7344
+ ];
7345
+ case 1:
7346
+ podPlayed = _state.sent();
7347
+ if (podPlayed) {
7348
+ return [
7349
+ 2
7350
+ ];
7351
+ }
7352
+ if (this.debug) {
7353
+ console.log("[POD] Optimized pod unavailable, falling back to sequential single-ad path");
7354
+ }
7355
+ _state.label = 2;
7356
+ case 2:
6985
7357
  usePreloadedAd = false;
6986
7358
  preloaded = this.preloadPool.getPreloadedAd();
6987
7359
  if (preloaded) {
@@ -7023,21 +7395,21 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7023
7395
  if (this.debug) {
7024
7396
  console.log("[CONTINUOUS-FETCH] First VAST URL:", firstAdUrl);
7025
7397
  }
7026
- _state.label = 1;
7027
- case 1:
7398
+ _state.label = 3;
7399
+ case 3:
7028
7400
  _state.trys.push([
7029
- 1,
7030
- 12,
7401
+ 3,
7402
+ 14,
7031
7403
  ,
7032
- 20
7404
+ 22
7033
7405
  ]);
7034
7406
  if (!(usePreloadedAd && preloadedController)) return [
7035
7407
  3,
7036
- 5
7408
+ 7
7037
7409
  ];
7038
7410
  if (!!this.timing.ensureLoadedAdFitsBudget(preloadedController)) return [
7039
7411
  3,
7040
- 3
7412
+ 5
7041
7413
  ];
7042
7414
  this.timing.rejectLoadedAdForDuration(preloadedController);
7043
7415
  this.startContinuousFetching(baseVastUrl);
@@ -7045,12 +7417,12 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7045
7417
  4,
7046
7418
  this.tryNextAvailableAdWithRateLimit()
7047
7419
  ];
7048
- case 2:
7420
+ case 4:
7049
7421
  _state.sent();
7050
7422
  return [
7051
7423
  2
7052
7424
  ];
7053
- case 3:
7425
+ case 5:
7054
7426
  adPlayer = this.host.getAdPlayer();
7055
7427
  preservedMuted = adPlayer.getOriginalMutedState();
7056
7428
  preservedVolume = adPlayer.getOriginalVolume();
@@ -7075,7 +7447,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7075
7447
  4,
7076
7448
  preloadedController.play()
7077
7449
  ];
7078
- case 4:
7450
+ case 6:
7079
7451
  _state.sent();
7080
7452
  this.timing.markAdStarted();
7081
7453
  if (this.timing.expectedAdBreakDurationMs != null && this.timing.getAdBreakEndWallClockMs() == null) {
@@ -7085,22 +7457,22 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7085
7457
  preloadedController.setAdVolume(adVolume);
7086
7458
  return [
7087
7459
  3,
7088
- 11
7460
+ 13
7089
7461
  ];
7090
- case 5:
7462
+ case 7:
7091
7463
  adPlayer1 = this.host.getAdPlayer();
7092
7464
  return [
7093
7465
  4,
7094
7466
  this.timing.enforceGlobalRateLimit()
7095
7467
  ];
7096
- case 6:
7468
+ case 8:
7097
7469
  _state.sent();
7098
7470
  this.timing.lastAdRequestTime = Date.now();
7099
7471
  return [
7100
7472
  4,
7101
7473
  adPlayer1.requestAds(firstAdUrl)
7102
7474
  ];
7103
- case 7:
7475
+ case 9:
7104
7476
  _state.sent();
7105
7477
  sendAdLoadedTracking(this.host.config.licenseKey, {
7106
7478
  source: "hls",
@@ -7112,7 +7484,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7112
7484
  }
7113
7485
  if (!!this.timing.ensureLoadedAdFitsBudget(adPlayer1)) return [
7114
7486
  3,
7115
- 9
7487
+ 11
7116
7488
  ];
7117
7489
  this.timing.rejectLoadedAdForDuration(adPlayer1);
7118
7490
  this.recreateAdController();
@@ -7121,12 +7493,12 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7121
7493
  4,
7122
7494
  this.tryNextAvailableAdWithRateLimit()
7123
7495
  ];
7124
- case 8:
7496
+ case 10:
7125
7497
  _state.sent();
7126
7498
  return [
7127
7499
  2
7128
7500
  ];
7129
- case 9:
7501
+ case 11:
7130
7502
  this.timing.consecutiveFailures = 0;
7131
7503
  this.startContinuousFetching(baseVastUrl);
7132
7504
  if (!this.preloadPool.active) {
@@ -7136,7 +7508,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7136
7508
  4,
7137
7509
  adPlayer1.play()
7138
7510
  ];
7139
- case 10:
7511
+ case 12:
7140
7512
  _state.sent();
7141
7513
  this.timing.markAdStarted();
7142
7514
  if (this.timing.expectedAdBreakDurationMs != null && this.timing.getAdBreakEndWallClockMs() == null) {
@@ -7144,40 +7516,40 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7144
7516
  }
7145
7517
  adVolume1 = currentMuted ? 0 : currentVolume;
7146
7518
  adPlayer1.setAdVolume(adVolume1);
7147
- _state.label = 11;
7148
- case 11:
7519
+ _state.label = 13;
7520
+ case 13:
7149
7521
  return [
7150
7522
  3,
7151
- 20
7523
+ 22
7152
7524
  ];
7153
- case 12:
7525
+ case 14:
7154
7526
  error = _state.sent();
7155
7527
  if (this.debug) {
7156
7528
  console.warn("[CONTINUOUS-FETCH] First ad request failed:", error);
7157
7529
  }
7158
7530
  if (!!usePreloadedAd) return [
7159
7531
  3,
7160
- 18
7532
+ 20
7161
7533
  ];
7162
7534
  fallbackPreloaded = this.preloadPool.getPreloadedAd();
7163
7535
  if (!fallbackPreloaded) return [
7164
7536
  3,
7165
- 18
7537
+ 20
7166
7538
  ];
7167
7539
  if (this.debug) {
7168
7540
  console.log("[CONTINUOUS-FETCH] First ad failed, using preloaded fallback");
7169
7541
  }
7170
- _state.label = 13;
7171
- case 13:
7542
+ _state.label = 15;
7543
+ case 15:
7172
7544
  _state.trys.push([
7173
- 13,
7174
- 17,
7545
+ 15,
7546
+ 19,
7175
7547
  ,
7176
- 18
7548
+ 20
7177
7549
  ]);
7178
7550
  if (!!this.timing.ensureLoadedAdFitsBudget(fallbackPreloaded.adController)) return [
7179
7551
  3,
7180
- 15
7552
+ 17
7181
7553
  ];
7182
7554
  this.timing.rejectLoadedAdForDuration(fallbackPreloaded.adController);
7183
7555
  this.startContinuousFetching(baseVastUrl);
@@ -7185,12 +7557,12 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7185
7557
  4,
7186
7558
  this.tryNextAvailableAdWithRateLimit()
7187
7559
  ];
7188
- case 14:
7560
+ case 16:
7189
7561
  _state.sent();
7190
7562
  return [
7191
7563
  2
7192
7564
  ];
7193
- case 15:
7565
+ case 17:
7194
7566
  this.swapToPreloadedAdPlayer(fallbackPreloaded.adController);
7195
7567
  this.timing.consecutiveFailures = 0;
7196
7568
  this.startContinuousFetching(baseVastUrl);
@@ -7203,7 +7575,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7203
7575
  4,
7204
7576
  ap.play()
7205
7577
  ];
7206
- case 16:
7578
+ case 18:
7207
7579
  _state.sent();
7208
7580
  this.timing.markAdStarted();
7209
7581
  if (this.timing.expectedAdBreakDurationMs != null && this.timing.getAdBreakEndWallClockMs() == null) {
@@ -7214,16 +7586,16 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7214
7586
  return [
7215
7587
  2
7216
7588
  ];
7217
- case 17:
7589
+ case 19:
7218
7590
  fallbackError = _state.sent();
7219
7591
  if (this.debug) {
7220
7592
  console.warn("[CONTINUOUS-FETCH] Preloaded fallback also failed:", fallbackError);
7221
7593
  }
7222
7594
  return [
7223
7595
  3,
7224
- 18
7596
+ 20
7225
7597
  ];
7226
- case 18:
7598
+ case 20:
7227
7599
  if (this.timing.isTemporaryAdError(error)) {
7228
7600
  this.timing.temporaryFailureUrls.set(firstAdUrl, Date.now());
7229
7601
  if (this.debug) {
@@ -7241,13 +7613,137 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7241
7613
  4,
7242
7614
  this.tryNextAvailableAdWithRateLimit()
7243
7615
  ];
7244
- case 19:
7616
+ case 21:
7245
7617
  _state.sent();
7246
7618
  return [
7247
7619
  3,
7248
- 20
7620
+ 22
7249
7621
  ];
7250
- case 20:
7622
+ case 22:
7623
+ return [
7624
+ 2
7625
+ ];
7626
+ }
7627
+ });
7628
+ }).call(this);
7629
+ }
7630
+ },
7631
+ {
7632
+ key: "startOptimizedPod",
7633
+ value: // ───────────────────────────────────────────────────────────────
7634
+ // Optimized pod (single multi-ad request)
7635
+ // ───────────────────────────────────────────────────────────────
7636
+ function startOptimizedPod(baseVastUrl, breakDurationMs, currentMuted, currentVolume) {
7637
+ return _async_to_generator(function() {
7638
+ var podUrl, adPlayer, requestToken, _ref, _adPlayer_getPodAdCount, podCount, error;
7639
+ return _ts_generator(this, function(_state) {
7640
+ switch(_state.label){
7641
+ case 0:
7642
+ if (this.pendingAdBreak && this.pendingAdBreak.vastUrls.length > 0) {
7643
+ podUrl = this.pendingAdBreak.vastUrls[0];
7644
+ this.clearPendingAdBreak();
7645
+ } else {
7646
+ podUrl = this.host.generatePodVastUrl(baseVastUrl, breakDurationMs);
7647
+ }
7648
+ if (!podUrl) {
7649
+ return [
7650
+ 2,
7651
+ false
7652
+ ];
7653
+ }
7654
+ this.continuousFetchingActive = false;
7655
+ this.recreateAdController();
7656
+ adPlayer = this.host.getAdPlayer();
7657
+ requestToken = ++this.timing.adRequestTokenCounter;
7658
+ this.timing.activeAdRequestToken = requestToken;
7659
+ this.timing.startAdRequestWatchdog(requestToken);
7660
+ _state.label = 1;
7661
+ case 1:
7662
+ _state.trys.push([
7663
+ 1,
7664
+ 5,
7665
+ ,
7666
+ 6
7667
+ ]);
7668
+ return [
7669
+ 4,
7670
+ this.timing.enforceGlobalRateLimit()
7671
+ ];
7672
+ case 2:
7673
+ _state.sent();
7674
+ this.timing.lastAdRequestTime = Date.now();
7675
+ return [
7676
+ 4,
7677
+ adPlayer.requestAds(podUrl)
7678
+ ];
7679
+ case 3:
7680
+ _state.sent();
7681
+ this.timing.clearAdRequestWatchdog();
7682
+ if (this.timing.activeAdRequestToken !== requestToken) {
7683
+ return [
7684
+ 2,
7685
+ true
7686
+ ];
7687
+ }
7688
+ podCount = (_ref = (_adPlayer_getPodAdCount = adPlayer.getPodAdCount) === null || _adPlayer_getPodAdCount === void 0 ? void 0 : _adPlayer_getPodAdCount.call(adPlayer)) !== null && _ref !== void 0 ? _ref : 1;
7689
+ if (podCount < 1) {
7690
+ return [
7691
+ 2,
7692
+ false
7693
+ ];
7694
+ }
7695
+ if (this.debug) {
7696
+ 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"));
7697
+ }
7698
+ sendAdLoadedTracking(this.host.config.licenseKey, {
7699
+ source: "hls",
7700
+ vastUrl: podUrl,
7701
+ timestamp: /* @__PURE__ */ new Date().toISOString()
7702
+ }, this.analyticsContext).catch(function() {});
7703
+ this.timing.startAdFailsafeTimer(requestToken);
7704
+ return [
7705
+ 4,
7706
+ adPlayer.play()
7707
+ ];
7708
+ case 4:
7709
+ _state.sent();
7710
+ this.timing.markAdStarted();
7711
+ if (this.timing.expectedAdBreakDurationMs != null && this.timing.getAdBreakEndWallClockMs() == null) {
7712
+ this.timing.scheduleAdStopAtBreakBoundary();
7713
+ }
7714
+ adPlayer.setAdVolume(currentMuted ? 0 : currentVolume);
7715
+ this.timing.consecutiveFailures = 0;
7716
+ if (podCount === 1) {
7717
+ this.continuousFetchingActive = true;
7718
+ this.startContinuousFetching(baseVastUrl);
7719
+ if (!this.preloadPool.active) {
7720
+ this.preloadPool.startPreloadPool(baseVastUrl, []);
7721
+ }
7722
+ }
7723
+ return [
7724
+ 2,
7725
+ true
7726
+ ];
7727
+ case 5:
7728
+ error = _state.sent();
7729
+ this.timing.clearAdRequestWatchdog();
7730
+ this.timing.clearAdFailsafeTimer();
7731
+ if (this.timing.activeAdRequestToken === requestToken) {
7732
+ this.timing.activeAdRequestToken = null;
7733
+ }
7734
+ if (this.debug) {
7735
+ console.warn("[POD] Optimized pod request/play failed:", error);
7736
+ }
7737
+ if (this.timing.isTemporaryAdError(error)) {
7738
+ this.timing.temporaryFailureUrls.set(podUrl, Date.now());
7739
+ }
7740
+ this.continuousFetchingActive = true;
7741
+ this.recreateAdController();
7742
+ return [
7743
+ 2,
7744
+ false
7745
+ ];
7746
+ case 6:
7251
7747
  return [
7252
7748
  2
7253
7749
  ];
@@ -8329,6 +8825,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8329
8825
  },
8330
8826
  generateVastUrls: function generateVastUrls(base, count) {
8331
8827
  return _this.generateVastUrls(base, count);
8828
+ },
8829
+ generatePodVastUrl: function generatePodVastUrl(base, breakDurationMs) {
8830
+ return _this.generatePodVastUrl(base, breakDurationMs);
8332
8831
  }
8333
8832
  }, this.timing, this.preloadPool, this.adConfig, this.cueManager, this.placeholder);
8334
8833
  }
@@ -8361,6 +8860,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8361
8860
  return this.adConfig.generateVastUrlsWithCorrelators(baseUrl, count, this.adPlayer, this.palNonce, this.adBreak.inAdBreak);
8362
8861
  }
8363
8862
  },
8863
+ {
8864
+ key: "generatePodVastUrl",
8865
+ value: function generatePodVastUrl(baseUrl, breakDurationMs) {
8866
+ var podParams = this.adConfig.resolvePodParams(breakDurationMs);
8867
+ return this.adConfig.generatePodVastUrl(baseUrl, podParams, this.adPlayer, this.palNonce, this.adBreak.inAdBreak);
8868
+ }
8869
+ },
8364
8870
  {
8365
8871
  key: "load",
8366
8872
  value: // ───────────────────────────────────────────────────────────────
@@ -8749,7 +9255,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8749
9255
  }
8750
9256
  this.adConfig.beginNewAdPod();
8751
9257
  this.adConfig.podAssignedByPrefetch = true;
8752
- var generatedUrls = this.generateVastUrls(baseVastUrl, 1);
9258
+ var optimizedPods = !!this.config.optimizedPods;
9259
+ var breakDurationMs = marker.durationSeconds != null ? marker.durationSeconds * 1e3 : void 0;
9260
+ var generatedUrls = optimizedPods ? [
9261
+ this.generatePodVastUrl(baseVastUrl, breakDurationMs)
9262
+ ] : this.generateVastUrls(baseVastUrl, 1);
8753
9263
  this.adBreak.pendingAdBreak = _object_spread_props(_object_spread({
8754
9264
  marker: marker
8755
9265
  }, fragmentSn !== void 0 ? {
@@ -8771,7 +9281,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8771
9281
  }, detectPayload), buildAnalyticsContext(this.config)).catch(function() {});
8772
9282
  if (this.debug) {
8773
9283
  console.log("[PREFETCH] Starting ad prefetch for upcoming ad break");
8774
- console.log("[PREFETCH] Pre-generated ".concat(generatedUrls.length, " VAST URLs"));
9284
+ console.log("[PREFETCH] Pre-generated ".concat(generatedUrls.length, " ").concat(optimizedPods ? "pod" : "VAST", " URL(s)"));
9285
+ }
9286
+ if (optimizedPods) {
9287
+ if (this.debug) {
9288
+ console.log("[PREFETCH] Optimized pods enabled - skipping single-ad preload pool");
9289
+ }
9290
+ return;
8775
9291
  }
8776
9292
  this.preloadPool.startPreloadPool(baseVastUrl, generatedUrls.slice(0, 1), false);
8777
9293
  }