stormcloud-video-player 0.8.24 → 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 (44) hide show
  1. package/dist/stormcloud-vp.min.js +1 -1
  2. package/lib/index.cjs +669 -126
  3. package/lib/index.cjs.map +1 -1
  4. package/lib/index.d.cts +10 -1
  5. package/lib/index.d.ts +10 -1
  6. package/lib/index.js +666 -127
  7. package/lib/index.js.map +1 -1
  8. package/lib/player/AdBreakOrchestrator.cjs +228 -48
  9. package/lib/player/AdBreakOrchestrator.cjs.map +1 -1
  10. package/lib/player/AdBreakOrchestrator.d.cts +5 -1
  11. package/lib/player/AdConfigManager.cjs +81 -4
  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 +665 -126
  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 +665 -126
  27. package/lib/players/HlsPlayer.cjs.map +1 -1
  28. package/lib/players/HlsPlayer.d.cts +1 -1
  29. package/lib/players/index.cjs +665 -126
  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-DNiBmPKK.d.cts → types-Xgz2_W1C.d.cts} +7 -0
  35. package/lib/ui/StormcloudVideoPlayer.cjs +665 -126
  36. package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
  37. package/lib/ui/StormcloudVideoPlayer.d.cts +1 -1
  38. package/lib/utils/tracking.cjs +22 -1
  39. package/lib/utils/tracking.cjs.map +1 -1
  40. package/lib/utils/tracking.d.cts +3 -2
  41. package/lib/utils/vastMacros.cjs +14 -1
  42. package/lib/utils/vastMacros.cjs.map +1 -1
  43. package/lib/utils/vastMacros.d.cts +3 -0
  44. package/package.json +1 -1
@@ -398,6 +398,8 @@ function createHlsAdPlayer(contentVideo, options) {
398
398
  var adHls;
399
399
  var adContainerEl;
400
400
  var currentAd;
401
+ var podAds = [];
402
+ var podIndex = 0;
401
403
  var sessionId;
402
404
  var preloadedAds = /* @__PURE__ */ new Map();
403
405
  var preloadingAds = /* @__PURE__ */ new Map();
@@ -562,14 +564,14 @@ function createHlsAdPlayer(contentVideo, options) {
562
564
  error: []
563
565
  };
564
566
  }
565
- function extractTrackingUrls(xmlDoc) {
567
+ function extractTrackingUrls(scope) {
566
568
  var trackingUrls = createEmptyTrackingUrls();
567
- xmlDoc.querySelectorAll("Impression").forEach(function(el) {
569
+ scope.querySelectorAll("Impression").forEach(function(el) {
568
570
  var _el_textContent;
569
571
  var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
570
572
  if (url) trackingUrls.impression.push(url);
571
573
  });
572
- xmlDoc.querySelectorAll("Tracking").forEach(function(el) {
574
+ scope.querySelectorAll("Tracking").forEach(function(el) {
573
575
  var _el_textContent;
574
576
  var event = el.getAttribute("event");
575
577
  var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
@@ -580,7 +582,7 @@ function createHlsAdPlayer(contentVideo, options) {
580
582
  }
581
583
  }
582
584
  });
583
- xmlDoc.querySelectorAll("Error").forEach(function(el) {
585
+ scope.querySelectorAll("Error").forEach(function(el) {
584
586
  var _el_textContent;
585
587
  var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
586
588
  if (url) trackingUrls.error.push(url);
@@ -690,6 +692,75 @@ function createHlsAdPlayer(contentVideo, options) {
690
692
  };
691
693
  }
692
694
  }
695
+ function parseAdElement(adElement) {
696
+ try {
697
+ var _adElement_querySelector, _adElement_querySelector_textContent, _adElement_querySelector1, _adElement_querySelector_textContent1, _adElement_querySelector2, _adElement_querySelector3;
698
+ var adId = adElement.getAttribute("id") || "unknown";
699
+ var title = ((_adElement_querySelector = adElement.querySelector("AdTitle")) === null || _adElement_querySelector === void 0 ? void 0 : _adElement_querySelector.textContent) || "Ad";
700
+ 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();
701
+ 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();
702
+ if (wrapperUri) {
703
+ return {
704
+ type: "wrapper",
705
+ vastAdTagUri: wrapperUri,
706
+ trackingUrls: extractTrackingUrls(adElement),
707
+ clickThrough: clickThrough
708
+ };
709
+ }
710
+ var isNoAdAvailable = adId === "empty" || title.toLowerCase().includes("no ad available") || title.toLowerCase() === "no ad available";
711
+ var durationText = ((_adElement_querySelector3 = adElement.querySelector("Duration")) === null || _adElement_querySelector3 === void 0 ? void 0 : _adElement_querySelector3.textContent) || "00:00:30";
712
+ var durationParts = durationText.split(":");
713
+ var duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseInt(durationParts[2] || "0", 10);
714
+ var mediaFileElements = adElement.querySelectorAll("MediaFile");
715
+ var mediaFiles = [];
716
+ mediaFileElements.forEach(function(mf) {
717
+ var _mf_textContent;
718
+ var type = mf.getAttribute("type") || "";
719
+ var url = ((_mf_textContent = mf.textContent) === null || _mf_textContent === void 0 ? void 0 : _mf_textContent.trim()) || "";
720
+ var width = mf.getAttribute("width") || "";
721
+ var height = mf.getAttribute("height") || "";
722
+ if (!url) return;
723
+ var bitrateAttr = mf.getAttribute("bitrate");
724
+ var bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;
725
+ var mediaFile = {
726
+ url: url,
727
+ type: type,
728
+ width: parseInt(width || "1920", 10),
729
+ height: parseInt(height || "1080", 10),
730
+ bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : void 0
731
+ };
732
+ if (isHlsMediaFile(mediaFile) || isProgressiveMediaFile(mediaFile)) {
733
+ mediaFiles.push(mediaFile);
734
+ }
735
+ });
736
+ if (mediaFiles.length === 0) {
737
+ if (isNoAdAvailable) {
738
+ console.warn("[HlsAdPlayer] Pod <Ad> indicates no ad available");
739
+ } else {
740
+ console.warn("[HlsAdPlayer] No supported media files in pod <Ad>");
741
+ }
742
+ return {
743
+ type: "empty"
744
+ };
745
+ }
746
+ return {
747
+ type: "inline",
748
+ ad: {
749
+ id: adId,
750
+ title: title,
751
+ duration: duration,
752
+ mediaFiles: mediaFiles,
753
+ trackingUrls: extractTrackingUrls(adElement),
754
+ clickThrough: clickThrough
755
+ }
756
+ };
757
+ } catch (error) {
758
+ console.error("[HlsAdPlayer] Error parsing pod <Ad> element:", error);
759
+ return {
760
+ type: "empty"
761
+ };
762
+ }
763
+ }
693
764
  function fetchVastXml(vastTagUrl) {
694
765
  return _async_to_generator(function() {
695
766
  var response;
@@ -766,6 +837,146 @@ function createHlsAdPlayer(contentVideo, options) {
766
837
  });
767
838
  }).apply(this, arguments);
768
839
  }
840
+ function fetchAndParsePod(vastTagUrl) {
841
+ return _async_to_generator(function() {
842
+ var vastXml, parser, xmlDoc, adElements, ads, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, adElement, parsed, resolved, error, err;
843
+ return _ts_generator(this, function(_state) {
844
+ switch(_state.label){
845
+ case 0:
846
+ return [
847
+ 4,
848
+ fetchVastXml(vastTagUrl)
849
+ ];
850
+ case 1:
851
+ vastXml = _state.sent();
852
+ console.log("[HlsAdPlayer] Pod VAST XML received");
853
+ parser = new DOMParser();
854
+ xmlDoc = parser.parseFromString(vastXml, "text/xml");
855
+ if (xmlDoc.querySelector("parsererror")) {
856
+ console.error("[HlsAdPlayer] Pod VAST XML parsing error (malformed)");
857
+ return [
858
+ 2,
859
+ []
860
+ ];
861
+ }
862
+ adElements = Array.from(xmlDoc.querySelectorAll("Ad"));
863
+ if (adElements.length === 0) {
864
+ console.warn("[HlsAdPlayer] No <Ad> elements found in pod VAST response");
865
+ return [
866
+ 2,
867
+ []
868
+ ];
869
+ }
870
+ adElements.sort(function(a, b) {
871
+ var aSeq = parseInt(a.getAttribute("sequence") || "", 10);
872
+ var bSeq = parseInt(b.getAttribute("sequence") || "", 10);
873
+ var aVal = Number.isFinite(aSeq) ? aSeq : Number.MAX_SAFE_INTEGER;
874
+ var bVal = Number.isFinite(bSeq) ? bSeq : Number.MAX_SAFE_INTEGER;
875
+ return aVal - bVal;
876
+ });
877
+ ads = [];
878
+ _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
879
+ _state.label = 2;
880
+ case 2:
881
+ _state.trys.push([
882
+ 2,
883
+ 10,
884
+ 11,
885
+ 12
886
+ ]);
887
+ _iterator = adElements[Symbol.iterator]();
888
+ _state.label = 3;
889
+ case 3:
890
+ if (!!(_iteratorNormalCompletion = (_step = _iterator.next()).done)) return [
891
+ 3,
892
+ 9
893
+ ];
894
+ adElement = _step.value;
895
+ parsed = parseAdElement(adElement);
896
+ if (!(parsed.type === "inline")) return [
897
+ 3,
898
+ 4
899
+ ];
900
+ ads.push(parsed.ad);
901
+ return [
902
+ 3,
903
+ 8
904
+ ];
905
+ case 4:
906
+ if (!(parsed.type === "wrapper")) return [
907
+ 3,
908
+ 8
909
+ ];
910
+ _state.label = 5;
911
+ case 5:
912
+ _state.trys.push([
913
+ 5,
914
+ 7,
915
+ ,
916
+ 8
917
+ ]);
918
+ return [
919
+ 4,
920
+ fetchAndParseVastAd(parsed.vastAdTagUri, 1, parsed.trackingUrls)
921
+ ];
922
+ case 6:
923
+ resolved = _state.sent();
924
+ if (resolved) {
925
+ ads.push(resolved);
926
+ }
927
+ return [
928
+ 3,
929
+ 8
930
+ ];
931
+ case 7:
932
+ error = _state.sent();
933
+ console.warn("[HlsAdPlayer] Failed to resolve wrapper <Ad> in pod:", error);
934
+ return [
935
+ 3,
936
+ 8
937
+ ];
938
+ case 8:
939
+ _iteratorNormalCompletion = true;
940
+ return [
941
+ 3,
942
+ 3
943
+ ];
944
+ case 9:
945
+ return [
946
+ 3,
947
+ 12
948
+ ];
949
+ case 10:
950
+ err = _state.sent();
951
+ _didIteratorError = true;
952
+ _iteratorError = err;
953
+ return [
954
+ 3,
955
+ 12
956
+ ];
957
+ case 11:
958
+ try {
959
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
960
+ _iterator.return();
961
+ }
962
+ } finally{
963
+ if (_didIteratorError) {
964
+ throw _iteratorError;
965
+ }
966
+ }
967
+ return [
968
+ 7
969
+ ];
970
+ case 12:
971
+ console.log("[HlsAdPlayer] Parsed ".concat(ads.length, " ad(s) from pod VAST response"));
972
+ return [
973
+ 2,
974
+ ads
975
+ ];
976
+ }
977
+ });
978
+ })();
979
+ }
769
980
  function createAdVideoElement() {
770
981
  var video = document.createElement("video");
771
982
  video.style.position = "absolute";
@@ -810,6 +1021,9 @@ function createHlsAdPlayer(contentVideo, options) {
810
1021
  trackingFired.complete = true;
811
1022
  fireTrackingPixels(currentAd.trackingUrls.complete);
812
1023
  console.log("[HlsAdPlayer] Ad completed");
1024
+ if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1025
+ return;
1026
+ }
813
1027
  handleAdComplete();
814
1028
  });
815
1029
  adVideoElement.addEventListener("error", function(e) {
@@ -818,6 +1032,9 @@ function createHlsAdPlayer(contentVideo, options) {
818
1032
  if (currentAd) {
819
1033
  fireTrackingPixels(currentAd.trackingUrls.error);
820
1034
  }
1035
+ if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1036
+ return;
1037
+ }
821
1038
  handleAdError();
822
1039
  });
823
1040
  adVideoElement.addEventListener("volumechange", function() {
@@ -846,6 +1063,94 @@ function createHlsAdPlayer(contentVideo, options) {
846
1063
  delete contentVideo.dataset.stormcloudAdPlaying;
847
1064
  }
848
1065
  }
1066
+ function resetQuartileTracking(preserveImpression) {
1067
+ trackingFired = {
1068
+ impression: preserveImpression ? trackingFired.impression : false,
1069
+ start: false,
1070
+ firstQuartile: false,
1071
+ midpoint: false,
1072
+ thirdQuartile: false,
1073
+ complete: false
1074
+ };
1075
+ }
1076
+ function loadCurrentAdMedia() {
1077
+ if (!adVideoElement || !currentAd) {
1078
+ throw new Error("No ad video element or ad to load");
1079
+ }
1080
+ var mediaFile = selectBestMediaFile(currentAd.mediaFiles);
1081
+ if (!mediaFile) {
1082
+ throw new Error("No media file available for ad");
1083
+ }
1084
+ var isHlsAd = isHlsMediaFile(mediaFile);
1085
+ console.log("[HlsAdPlayer] Loading ".concat(isHlsAd ? "HLS" : "progressive", " ad (pod ").concat(podIndex + 1, "/").concat(podAds.length || 1, ") from: ").concat(mediaFile.url));
1086
+ if (isHlsAd && import_hls.default.isSupported()) {
1087
+ if (adHls) {
1088
+ adHls.destroy();
1089
+ }
1090
+ adHls = new import_hls.default({
1091
+ enableWorker: true,
1092
+ lowLatencyMode: false
1093
+ });
1094
+ adHls.loadSource(mediaFile.url);
1095
+ adHls.attachMedia(adVideoElement);
1096
+ adHls.on(import_hls.default.Events.MANIFEST_PARSED, function() {
1097
+ console.log("[HlsAdPlayer] HLS manifest parsed, starting playback");
1098
+ adVideoElement.play().catch(function(error) {
1099
+ console.error("[HlsAdPlayer] Error starting ad playback:", error);
1100
+ handleAdError();
1101
+ });
1102
+ });
1103
+ adHls.on(import_hls.default.Events.ERROR, function(_event, data) {
1104
+ console.error("[HlsAdPlayer] HLS error:", data);
1105
+ if (data.fatal) {
1106
+ handleAdError();
1107
+ }
1108
+ });
1109
+ } else if (isHlsAd && adVideoElement.canPlayType("application/vnd.apple.mpegurl")) {
1110
+ adVideoElement.src = mediaFile.url;
1111
+ adVideoElement.play().catch(function(error) {
1112
+ console.error("[HlsAdPlayer] Error starting ad playback:", error);
1113
+ handleAdError();
1114
+ });
1115
+ } else if (!isHlsAd && isProgressiveMediaFile(mediaFile)) {
1116
+ if (adHls) {
1117
+ adHls.destroy();
1118
+ adHls = void 0;
1119
+ }
1120
+ adVideoElement.src = mediaFile.url;
1121
+ adVideoElement.load();
1122
+ adVideoElement.play().catch(function(error) {
1123
+ console.error("[HlsAdPlayer] Error starting progressive ad playback:", error);
1124
+ handleAdError();
1125
+ });
1126
+ } else {
1127
+ throw new Error("Unsupported ad media file type: ".concat(mediaFile.type));
1128
+ }
1129
+ }
1130
+ function advanceToNextPodAd() {
1131
+ if (podIndex >= podAds.length - 1) {
1132
+ return false;
1133
+ }
1134
+ podIndex++;
1135
+ currentAd = podAds[podIndex];
1136
+ resetQuartileTracking(false);
1137
+ if (currentAd) {
1138
+ fireTrackingPixels(currentAd.trackingUrls.impression);
1139
+ trackingFired.impression = true;
1140
+ console.log("[HlsAdPlayer] Advancing to next pod ad (".concat(podIndex + 1, "/").concat(podAds.length, "): ").concat(currentAd.title, ", duration: ").concat(currentAd.duration, "s"));
1141
+ }
1142
+ try {
1143
+ loadCurrentAdMedia();
1144
+ emit("pod_ad_started", {
1145
+ index: podIndex,
1146
+ total: podAds.length
1147
+ });
1148
+ return true;
1149
+ } catch (error) {
1150
+ console.error("[HlsAdPlayer] Failed to load next pod ad:", error);
1151
+ return false;
1152
+ }
1153
+ }
849
1154
  function handleAdComplete() {
850
1155
  console.log("[HlsAdPlayer] Handling ad completion");
851
1156
  adPlaying = false;
@@ -899,7 +1204,7 @@ function createHlsAdPlayer(contentVideo, options) {
899
1204
  },
900
1205
  requestAds: function requestAds(vastTagUrl) {
901
1206
  return _async_to_generator(function() {
902
- var ad, error;
1207
+ var ads, preloaded, error;
903
1208
  return _ts_generator(this, function(_state) {
904
1209
  switch(_state.label){
905
1210
  case 0:
@@ -920,12 +1225,18 @@ function createHlsAdPlayer(contentVideo, options) {
920
1225
  6
921
1226
  ]);
922
1227
  sessionId = generateSessionId();
1228
+ ads = [];
923
1229
  if (!preloadedAds.has(vastTagUrl)) return [
924
1230
  3,
925
1231
  2
926
1232
  ];
927
- ad = preloadedAds.get(vastTagUrl);
1233
+ preloaded = preloadedAds.get(vastTagUrl);
928
1234
  preloadedAds.delete(vastTagUrl);
1235
+ if (preloaded) {
1236
+ ads = [
1237
+ preloaded
1238
+ ];
1239
+ }
929
1240
  console.log("[HlsAdPlayer] Using preloaded VAST response:", vastTagUrl);
930
1241
  return [
931
1242
  3,
@@ -934,13 +1245,13 @@ function createHlsAdPlayer(contentVideo, options) {
934
1245
  case 2:
935
1246
  return [
936
1247
  4,
937
- fetchAndParseVastAd(vastTagUrl)
1248
+ fetchAndParsePod(vastTagUrl)
938
1249
  ];
939
1250
  case 3:
940
- ad = _state.sent();
1251
+ ads = _state.sent();
941
1252
  _state.label = 4;
942
1253
  case 4:
943
- if (!ad) {
1254
+ if (!ads.length) {
944
1255
  console.warn("[HlsAdPlayer] No ads available from VAST response");
945
1256
  emit("ad_error");
946
1257
  return [
@@ -948,10 +1259,14 @@ function createHlsAdPlayer(contentVideo, options) {
948
1259
  Promise.reject(new Error("No ads available from VAST response"))
949
1260
  ];
950
1261
  }
951
- currentAd = ad;
952
- console.log("[HlsAdPlayer] Ad parsed: ".concat(ad.title, ", duration: ").concat(ad.duration, "s"));
953
- fireTrackingPixels(ad.trackingUrls.impression);
954
- trackingFired.impression = true;
1262
+ podAds = ads;
1263
+ podIndex = 0;
1264
+ currentAd = ads[0];
1265
+ 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"));
1266
+ if (currentAd) {
1267
+ fireTrackingPixels(currentAd.trackingUrls.impression);
1268
+ trackingFired.impression = true;
1269
+ }
955
1270
  return [
956
1271
  2,
957
1272
  Promise.resolve()
@@ -974,7 +1289,7 @@ function createHlsAdPlayer(contentVideo, options) {
974
1289
  },
975
1290
  play: function play() {
976
1291
  return _async_to_generator(function() {
977
- var contentVolume, mediaFile, isHlsAd;
1292
+ var contentVolume;
978
1293
  return _ts_generator(this, function(_state) {
979
1294
  if (!currentAd) {
980
1295
  console.warn("[HlsAdPlayer] Cannot play: No ad loaded (no ads available)");
@@ -990,14 +1305,7 @@ function createHlsAdPlayer(contentVideo, options) {
990
1305
  adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.appendChild(adVideoElement);
991
1306
  setupAdEventListeners();
992
1307
  }
993
- trackingFired = {
994
- impression: trackingFired.impression,
995
- start: false,
996
- firstQuartile: false,
997
- midpoint: false,
998
- thirdQuartile: false,
999
- complete: false
1000
- };
1308
+ resetQuartileTracking(true);
1001
1309
  contentVolume = contentVideo.volume;
1002
1310
  originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1003
1311
  if (!(options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds)) {
@@ -1015,60 +1323,12 @@ function createHlsAdPlayer(contentVideo, options) {
1015
1323
  adVideoElement.muted = originalMutedState;
1016
1324
  console.log("[HlsAdPlayer] Set ad video volume to ".concat(adVideoElement.volume, ", muted: ").concat(adVideoElement.muted, ", originalMutedState: ").concat(originalMutedState, ", contentVolume: ").concat(contentVolume));
1017
1325
  }
1018
- mediaFile = selectBestMediaFile(currentAd.mediaFiles);
1019
- if (!mediaFile) {
1020
- throw new Error("No media file available for ad");
1021
- }
1022
1326
  if (adContainerEl) {
1023
1327
  adContainerEl.style.display = "flex";
1024
1328
  adContainerEl.style.pointerEvents = "auto";
1025
1329
  }
1026
1330
  emit("content_pause");
1027
- isHlsAd = isHlsMediaFile(mediaFile);
1028
- console.log("[HlsAdPlayer] Loading ".concat(isHlsAd ? "HLS" : "progressive", " ad from: ").concat(mediaFile.url));
1029
- if (isHlsAd && import_hls.default.isSupported()) {
1030
- if (adHls) {
1031
- adHls.destroy();
1032
- }
1033
- adHls = new import_hls.default({
1034
- enableWorker: true,
1035
- lowLatencyMode: false
1036
- });
1037
- adHls.loadSource(mediaFile.url);
1038
- adHls.attachMedia(adVideoElement);
1039
- adHls.on(import_hls.default.Events.MANIFEST_PARSED, function() {
1040
- console.log("[HlsAdPlayer] HLS manifest parsed, starting playback");
1041
- adVideoElement.play().catch(function(error) {
1042
- console.error("[HlsAdPlayer] Error starting ad playback:", error);
1043
- handleAdError();
1044
- });
1045
- });
1046
- adHls.on(import_hls.default.Events.ERROR, function(event, data) {
1047
- console.error("[HlsAdPlayer] HLS error:", data);
1048
- if (data.fatal) {
1049
- handleAdError();
1050
- }
1051
- });
1052
- } else if (isHlsAd && adVideoElement.canPlayType("application/vnd.apple.mpegurl")) {
1053
- adVideoElement.src = mediaFile.url;
1054
- adVideoElement.play().catch(function(error) {
1055
- console.error("[HlsAdPlayer] Error starting ad playback:", error);
1056
- handleAdError();
1057
- });
1058
- } else if (!isHlsAd && isProgressiveMediaFile(mediaFile)) {
1059
- if (adHls) {
1060
- adHls.destroy();
1061
- adHls = void 0;
1062
- }
1063
- adVideoElement.src = mediaFile.url;
1064
- adVideoElement.load();
1065
- adVideoElement.play().catch(function(error) {
1066
- console.error("[HlsAdPlayer] Error starting progressive ad playback:", error);
1067
- handleAdError();
1068
- });
1069
- } else {
1070
- throw new Error("Unsupported ad media file type: ".concat(mediaFile.type));
1071
- }
1331
+ loadCurrentAdMedia();
1072
1332
  return [
1073
1333
  2,
1074
1334
  Promise.resolve()
@@ -1143,6 +1403,8 @@ function createHlsAdPlayer(contentVideo, options) {
1143
1403
  adVideoElement.src = "";
1144
1404
  }
1145
1405
  currentAd = void 0;
1406
+ podAds = [];
1407
+ podIndex = 0;
1146
1408
  return [
1147
1409
  2
1148
1410
  ];
@@ -1192,6 +1454,8 @@ function createHlsAdPlayer(contentVideo, options) {
1192
1454
  }
1193
1455
  adContainerEl = void 0;
1194
1456
  currentAd = void 0;
1457
+ podAds = [];
1458
+ podIndex = 0;
1195
1459
  listeners.clear();
1196
1460
  preloadedAds.clear();
1197
1461
  preloadingAds.clear();
@@ -1283,6 +1547,14 @@ function createHlsAdPlayer(contentVideo, options) {
1283
1547
  },
1284
1548
  getLoadedAdId: function getLoadedAdId() {
1285
1549
  return currentAd === null || currentAd === void 0 ? void 0 : currentAd.id;
1550
+ },
1551
+ getPodAdCount: function getPodAdCount() {
1552
+ return podAds.length;
1553
+ },
1554
+ getPodTotalDurationMs: function getPodTotalDurationMs() {
1555
+ return podAds.reduce(function(total, ad) {
1556
+ return total + (ad.duration > 0 ? ad.duration * 1e3 : 0);
1557
+ }, 0);
1286
1558
  }
1287
1559
  };
1288
1560
  }
@@ -1982,6 +2254,16 @@ function normalizeBoolean(value) {
1982
2254
  }
1983
2255
  // src/utils/tracking.ts
1984
2256
  var cachedBrowserId = null;
2257
+ function buildAnalyticsContext(config) {
2258
+ var context = {};
2259
+ if (config.debugAdTiming) {
2260
+ context.debugAdTiming = true;
2261
+ }
2262
+ if (config.isLiveStream !== void 0) {
2263
+ context.inputStreamType = config.isLiveStream ? "live" : "vod";
2264
+ }
2265
+ return context;
2266
+ }
1985
2267
  function getClientInfo() {
1986
2268
  var _screen, _screen1, _screen2, _screen3, _screen_orientation, _screen4, _screen5, _window, _window1, _window_screen_orientation, _window_screen, _navigator_languages;
1987
2269
  var ua = navigator.userAgent;
@@ -2240,19 +2522,26 @@ function canPublish(licenseKey) {
2240
2522
  }
2241
2523
  function buildPlayerMetricEvent() {
2242
2524
  return _async_to_generator(function() {
2243
- var context, flags, _flags_captureAt, _flags_adLoaded, _flags_adDetect, clientInfo, playerId, captureAt;
2525
+ var context, flags, _flags_captureAt, _flags_adLoaded, _flags_adDetect, clientInfo, debugAdTiming, playerId, captureAt;
2244
2526
  var _arguments = arguments;
2245
2527
  return _ts_generator(this, function(_state) {
2246
2528
  switch(_state.label){
2247
2529
  case 0:
2248
2530
  context = _arguments.length > 0 && _arguments[0] !== void 0 ? _arguments[0] : {}, flags = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {};
2249
2531
  clientInfo = getClientInfo();
2532
+ debugAdTiming = !!context.debugAdTiming;
2533
+ if (debugAdTiming) {
2534
+ console.log("[StormcloudVideoPlayer] clientInfo: ", JSON.stringify(clientInfo, null, 2));
2535
+ }
2250
2536
  return [
2251
2537
  4,
2252
2538
  getBrowserID(clientInfo)
2253
2539
  ];
2254
2540
  case 1:
2255
2541
  playerId = _state.sent();
2542
+ if (debugAdTiming) {
2543
+ console.log("[StormcloudVideoPlayer] playerId: ", playerId);
2544
+ }
2256
2545
  captureAt = (_flags_captureAt = flags.captureAt) !== null && _flags_captureAt !== void 0 ? _flags_captureAt : /* @__PURE__ */ new Date().toISOString();
2257
2546
  return [
2258
2547
  2,
@@ -3094,7 +3383,20 @@ function applyVastMacros(baseUrl, ctx) {
3094
3383
  if (ctx.pod != null) {
3095
3384
  params.set("pod", String(ctx.pod));
3096
3385
  }
3097
- if (ctx.adPosition != null) {
3386
+ var optimizedPodMode = ctx.podMaxAds != null || ctx.podMinDurationMs != null || ctx.podMaxDurationMs != null;
3387
+ if (optimizedPodMode) {
3388
+ params.delete("ppos");
3389
+ params.delete("lip");
3390
+ if (ctx.podMinDurationMs != null) {
3391
+ params.set("pmnd", String(Math.max(0, Math.round(ctx.podMinDurationMs))));
3392
+ }
3393
+ if (ctx.podMaxDurationMs != null) {
3394
+ params.set("pmxd", String(Math.max(0, Math.round(ctx.podMaxDurationMs))));
3395
+ }
3396
+ if (ctx.podMaxAds != null) {
3397
+ params.set("pmad", String(Math.max(1, Math.round(ctx.podMaxAds))));
3398
+ }
3399
+ } else if (ctx.adPosition != null) {
3098
3400
  params.set("ppos", String(ctx.adPosition));
3099
3401
  }
3100
3402
  var requestUrl = ctx.contentUrl || ctx.pageUrl;
@@ -4436,6 +4738,7 @@ var AdConfigManager = /*#__PURE__*/ function() {
4436
4738
  this.podAssignedByPrefetch = false;
4437
4739
  this.adRequestPositionInBreak = 0;
4438
4740
  this.lastHeartbeatTime = 0;
4741
+ this.defaultPodMaxAds = 6;
4439
4742
  this.config = config;
4440
4743
  this.video = video;
4441
4744
  }
@@ -4891,12 +5194,58 @@ var AdConfigManager = /*#__PURE__*/ function() {
4891
5194
  return urls;
4892
5195
  }
4893
5196
  },
5197
+ {
5198
+ key: "resolvePodParams",
5199
+ value: function resolvePodParams(breakDurationMs) {
5200
+ var maxDurationMs = breakDurationMs != null && breakDurationMs > 0 ? breakDurationMs : this.config.podMaxDurationMs;
5201
+ var maxAds = this.config.podMaxAds && this.config.podMaxAds > 0 ? this.config.podMaxAds : this.apiNumberAds && this.apiNumberAds > 0 ? this.apiNumberAds : this.defaultPodMaxAds;
5202
+ var minDurationMs = this.config.podExactDuration && maxDurationMs != null ? maxDurationMs : 0;
5203
+ return {
5204
+ maxAds: maxAds,
5205
+ minDurationMs: minDurationMs,
5206
+ maxDurationMs: maxDurationMs
5207
+ };
5208
+ }
5209
+ },
5210
+ {
5211
+ key: "generatePodVastUrl",
5212
+ value: function generatePodVastUrl(baseUrl, podParams, adPlayer, palNonce, inAdBreak) {
5213
+ var _podParams_maxDurationMs;
5214
+ var adWillPlayMuted = inAdBreak ? adPlayer.getOriginalMutedState() : this.video.muted;
5215
+ var envSignals = resolveVastEnvironmentSignals(!!this.config.ctvAdRequest);
5216
+ var urlWithMacros = applyVastMacros(baseUrl, {
5217
+ correlator: generateCorrelator(),
5218
+ streamCorrelator: this.streamCorrelator,
5219
+ pod: this.podCounter > 0 ? this.podCounter : void 0,
5220
+ podMaxAds: podParams.maxAds,
5221
+ podMinDurationMs: podParams.minDurationMs,
5222
+ podMaxDurationMs: podParams.maxDurationMs,
5223
+ isCtv: envSignals.isCtv,
5224
+ contentUrl: envSignals.contentUrl,
5225
+ pageUrl: !envSignals.isCtv && typeof window !== "undefined" ? window.location.href : void 0,
5226
+ adWillPlayMuted: adWillPlayMuted,
5227
+ adWillAutoPlay: !!this.config.autoplay,
5228
+ appId: envSignals.appId,
5229
+ appName: envSignals.appName,
5230
+ sessionId: envSignals.sessionId,
5231
+ deviceId: envSignals.deviceId,
5232
+ deviceIdType: envSignals.deviceIdType,
5233
+ limitAdTracking: envSignals.limitAdTracking,
5234
+ deviceTypeHint: envSignals.deviceTypeHint,
5235
+ adTest: this.config.adTest,
5236
+ consent: this.consentSignals
5237
+ });
5238
+ var finalUrl = palNonce.injectNonce(urlWithMacros);
5239
+ 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);
5240
+ return finalUrl;
5241
+ }
5242
+ },
4894
5243
  {
4895
5244
  // --- Tracking ---
4896
5245
  key: "initializeTracking",
4897
5246
  value: function initializeTracking() {
4898
5247
  var _this = this;
4899
- sendInitialTracking(this.config.licenseKey).then(function() {
5248
+ sendInitialTracking(this.config.licenseKey, buildAnalyticsContext(this.config)).then(function() {
4900
5249
  _this.heartbeatInterval = window.setInterval(function() {
4901
5250
  _this.sendHeartbeatIfNeeded();
4902
5251
  }, 5e3);
@@ -4917,7 +5266,7 @@ var AdConfigManager = /*#__PURE__*/ function() {
4917
5266
  var now = Date.now();
4918
5267
  if (!this.lastHeartbeatTime || now - this.lastHeartbeatTime > 3e4) {
4919
5268
  this.lastHeartbeatTime = now;
4920
- sendHeartbeat(this.config.licenseKey).catch(function(error) {
5269
+ sendHeartbeat(this.config.licenseKey, buildAnalyticsContext(this.config)).catch(function(error) {
4921
5270
  if (_this.debug) {
4922
5271
  console.warn("[StormcloudVideoPlayer] Failed to send heartbeat:", error);
4923
5272
  }
@@ -5196,6 +5545,13 @@ var AdTimingService = /*#__PURE__*/ function() {
5196
5545
  this.lastAdRequestTime = Date.now();
5197
5546
  }
5198
5547
  },
5548
+ {
5549
+ key: "notePodAdStarted",
5550
+ value: function notePodAdStarted() {
5551
+ this.currentAdIndex++;
5552
+ this.totalAdsInBreak = this.currentAdIndex;
5553
+ }
5554
+ },
5199
5555
  {
5200
5556
  key: "getRemainingAdMs",
5201
5557
  value: function getRemainingAdMs() {
@@ -6698,19 +7054,38 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
6698
7054
  }
6699
7055
  },
6700
7056
  {
6701
- // ───────────────────────────────────────────────────────────────
7057
+ key: "analyticsContext",
7058
+ get: function get() {
7059
+ return buildAnalyticsContext(this.host.config);
7060
+ }
7061
+ },
7062
+ {
7063
+ key: "optimizedPodsEnabled",
7064
+ get: // ───────────────────────────────────────────────────────────────
6702
7065
  // IMA event listeners
6703
7066
  // ───────────────────────────────────────────────────────────────
7067
+ function get() {
7068
+ return !!this.host.config.optimizedPods;
7069
+ }
7070
+ },
7071
+ {
6704
7072
  key: "attachImaEventListeners",
6705
7073
  value: function attachImaEventListeners() {
6706
7074
  var _this = this;
6707
7075
  var adPlayer = this.host.getAdPlayer();
7076
+ adPlayer.on("pod_ad_started", function(payload) {
7077
+ _this.timing.notePodAdStarted();
7078
+ if (_this.debug) {
7079
+ var _ref;
7080
+ 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 : "?"));
7081
+ }
7082
+ });
6708
7083
  adPlayer.on("all_ads_completed", function() {
6709
7084
  sendAdImpressionTracking(_this.host.config.licenseKey, {
6710
7085
  source: "hls",
6711
7086
  adIndex: _this.timing.currentAdIndex,
6712
7087
  timestamp: /* @__PURE__ */ new Date().toISOString()
6713
- }).catch(function() {});
7088
+ }, _this.analyticsContext).catch(function() {});
6714
7089
  _this.timing.recordPlayedAdDuration(_this.host.getAdPlayer());
6715
7090
  var remaining = _this.timing.getRemainingAdMs();
6716
7091
  _this.timing.consecutiveFailures = 0;
@@ -6772,7 +7147,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
6772
7147
  source: "hls",
6773
7148
  adIndex: _this.timing.currentAdIndex,
6774
7149
  timestamp: /* @__PURE__ */ new Date().toISOString()
6775
- }).catch(function() {});
7150
+ }, _this.analyticsContext).catch(function() {});
6776
7151
  if (!_this.host.video.muted) {
6777
7152
  _this.host.video.muted = true;
6778
7153
  if (_this.debug) {
@@ -6862,7 +7237,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
6862
7237
  // ───────────────────────────────────────────────────────────────
6863
7238
  function handleAdStart(_marker) {
6864
7239
  return _async_to_generator(function() {
6865
- var scheduled, tags, baseVastUrl, adBreakDurationMs, mode, currentMuted, currentVolume, firstAdUrl, usePreloadedAd, preloadedController, preloaded, firstAdUrlArray, adPlayer, preservedMuted, preservedVolume, adVolume, adPlayer1, adVolume1, error, fallbackPreloaded, ap, adVolume2, fallbackError;
7240
+ 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;
6866
7241
  return _ts_generator(this, function(_state) {
6867
7242
  switch(_state.label){
6868
7243
  case 0:
@@ -6909,6 +7284,26 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
6909
7284
  if (this.timing.expectedAdBreakDurationMs == null && adBreakDurationMs != null) {
6910
7285
  this.timing.expectedAdBreakDurationMs = adBreakDurationMs;
6911
7286
  }
7287
+ if (!this.optimizedPodsEnabled) return [
7288
+ 3,
7289
+ 2
7290
+ ];
7291
+ return [
7292
+ 4,
7293
+ this.startOptimizedPod(baseVastUrl, adBreakDurationMs, currentMuted, currentVolume)
7294
+ ];
7295
+ case 1:
7296
+ podPlayed = _state.sent();
7297
+ if (podPlayed) {
7298
+ return [
7299
+ 2
7300
+ ];
7301
+ }
7302
+ if (this.debug) {
7303
+ console.log("[POD] Optimized pod unavailable, falling back to sequential single-ad path");
7304
+ }
7305
+ _state.label = 2;
7306
+ case 2:
6912
7307
  usePreloadedAd = false;
6913
7308
  preloaded = this.preloadPool.getPreloadedAd();
6914
7309
  if (preloaded) {
@@ -6919,7 +7314,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
6919
7314
  source: "hls",
6920
7315
  vastUrl: firstAdUrl,
6921
7316
  timestamp: /* @__PURE__ */ new Date().toISOString()
6922
- }).catch(function() {});
7317
+ }, this.analyticsContext).catch(function() {});
6923
7318
  if (this.debug) {
6924
7319
  console.log("[CONTINUOUS-FETCH] Using preloaded ad from pool (preloaded in advance, ready immediately!)");
6925
7320
  }
@@ -6950,21 +7345,21 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
6950
7345
  if (this.debug) {
6951
7346
  console.log("[CONTINUOUS-FETCH] First VAST URL:", firstAdUrl);
6952
7347
  }
6953
- _state.label = 1;
6954
- case 1:
7348
+ _state.label = 3;
7349
+ case 3:
6955
7350
  _state.trys.push([
6956
- 1,
6957
- 12,
7351
+ 3,
7352
+ 14,
6958
7353
  ,
6959
- 20
7354
+ 22
6960
7355
  ]);
6961
7356
  if (!(usePreloadedAd && preloadedController)) return [
6962
7357
  3,
6963
- 5
7358
+ 7
6964
7359
  ];
6965
7360
  if (!!this.timing.ensureLoadedAdFitsBudget(preloadedController)) return [
6966
7361
  3,
6967
- 3
7362
+ 5
6968
7363
  ];
6969
7364
  this.timing.rejectLoadedAdForDuration(preloadedController);
6970
7365
  this.startContinuousFetching(baseVastUrl);
@@ -6972,12 +7367,12 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
6972
7367
  4,
6973
7368
  this.tryNextAvailableAdWithRateLimit()
6974
7369
  ];
6975
- case 2:
7370
+ case 4:
6976
7371
  _state.sent();
6977
7372
  return [
6978
7373
  2
6979
7374
  ];
6980
- case 3:
7375
+ case 5:
6981
7376
  adPlayer = this.host.getAdPlayer();
6982
7377
  preservedMuted = adPlayer.getOriginalMutedState();
6983
7378
  preservedVolume = adPlayer.getOriginalVolume();
@@ -7002,7 +7397,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7002
7397
  4,
7003
7398
  preloadedController.play()
7004
7399
  ];
7005
- case 4:
7400
+ case 6:
7006
7401
  _state.sent();
7007
7402
  this.timing.markAdStarted();
7008
7403
  if (this.timing.expectedAdBreakDurationMs != null && this.timing.getAdBreakEndWallClockMs() == null) {
@@ -7012,34 +7407,34 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7012
7407
  preloadedController.setAdVolume(adVolume);
7013
7408
  return [
7014
7409
  3,
7015
- 11
7410
+ 13
7016
7411
  ];
7017
- case 5:
7412
+ case 7:
7018
7413
  adPlayer1 = this.host.getAdPlayer();
7019
7414
  return [
7020
7415
  4,
7021
7416
  this.timing.enforceGlobalRateLimit()
7022
7417
  ];
7023
- case 6:
7418
+ case 8:
7024
7419
  _state.sent();
7025
7420
  this.timing.lastAdRequestTime = Date.now();
7026
7421
  return [
7027
7422
  4,
7028
7423
  adPlayer1.requestAds(firstAdUrl)
7029
7424
  ];
7030
- case 7:
7425
+ case 9:
7031
7426
  _state.sent();
7032
7427
  sendAdLoadedTracking(this.host.config.licenseKey, {
7033
7428
  source: "hls",
7034
7429
  vastUrl: firstAdUrl,
7035
7430
  timestamp: /* @__PURE__ */ new Date().toISOString()
7036
- }).catch(function() {});
7431
+ }, this.analyticsContext).catch(function() {});
7037
7432
  if (this.debug) {
7038
7433
  console.log("[CONTINUOUS-FETCH] First ad request successful, starting playback");
7039
7434
  }
7040
7435
  if (!!this.timing.ensureLoadedAdFitsBudget(adPlayer1)) return [
7041
7436
  3,
7042
- 9
7437
+ 11
7043
7438
  ];
7044
7439
  this.timing.rejectLoadedAdForDuration(adPlayer1);
7045
7440
  this.recreateAdController();
@@ -7048,12 +7443,12 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7048
7443
  4,
7049
7444
  this.tryNextAvailableAdWithRateLimit()
7050
7445
  ];
7051
- case 8:
7446
+ case 10:
7052
7447
  _state.sent();
7053
7448
  return [
7054
7449
  2
7055
7450
  ];
7056
- case 9:
7451
+ case 11:
7057
7452
  this.timing.consecutiveFailures = 0;
7058
7453
  this.startContinuousFetching(baseVastUrl);
7059
7454
  if (!this.preloadPool.active) {
@@ -7063,7 +7458,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7063
7458
  4,
7064
7459
  adPlayer1.play()
7065
7460
  ];
7066
- case 10:
7461
+ case 12:
7067
7462
  _state.sent();
7068
7463
  this.timing.markAdStarted();
7069
7464
  if (this.timing.expectedAdBreakDurationMs != null && this.timing.getAdBreakEndWallClockMs() == null) {
@@ -7071,40 +7466,40 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7071
7466
  }
7072
7467
  adVolume1 = currentMuted ? 0 : currentVolume;
7073
7468
  adPlayer1.setAdVolume(adVolume1);
7074
- _state.label = 11;
7075
- case 11:
7469
+ _state.label = 13;
7470
+ case 13:
7076
7471
  return [
7077
7472
  3,
7078
- 20
7473
+ 22
7079
7474
  ];
7080
- case 12:
7475
+ case 14:
7081
7476
  error = _state.sent();
7082
7477
  if (this.debug) {
7083
7478
  console.warn("[CONTINUOUS-FETCH] First ad request failed:", error);
7084
7479
  }
7085
7480
  if (!!usePreloadedAd) return [
7086
7481
  3,
7087
- 18
7482
+ 20
7088
7483
  ];
7089
7484
  fallbackPreloaded = this.preloadPool.getPreloadedAd();
7090
7485
  if (!fallbackPreloaded) return [
7091
7486
  3,
7092
- 18
7487
+ 20
7093
7488
  ];
7094
7489
  if (this.debug) {
7095
7490
  console.log("[CONTINUOUS-FETCH] First ad failed, using preloaded fallback");
7096
7491
  }
7097
- _state.label = 13;
7098
- case 13:
7492
+ _state.label = 15;
7493
+ case 15:
7099
7494
  _state.trys.push([
7100
- 13,
7101
- 17,
7495
+ 15,
7496
+ 19,
7102
7497
  ,
7103
- 18
7498
+ 20
7104
7499
  ]);
7105
7500
  if (!!this.timing.ensureLoadedAdFitsBudget(fallbackPreloaded.adController)) return [
7106
7501
  3,
7107
- 15
7502
+ 17
7108
7503
  ];
7109
7504
  this.timing.rejectLoadedAdForDuration(fallbackPreloaded.adController);
7110
7505
  this.startContinuousFetching(baseVastUrl);
@@ -7112,12 +7507,12 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7112
7507
  4,
7113
7508
  this.tryNextAvailableAdWithRateLimit()
7114
7509
  ];
7115
- case 14:
7510
+ case 16:
7116
7511
  _state.sent();
7117
7512
  return [
7118
7513
  2
7119
7514
  ];
7120
- case 15:
7515
+ case 17:
7121
7516
  this.swapToPreloadedAdPlayer(fallbackPreloaded.adController);
7122
7517
  this.timing.consecutiveFailures = 0;
7123
7518
  this.startContinuousFetching(baseVastUrl);
@@ -7130,7 +7525,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7130
7525
  4,
7131
7526
  ap.play()
7132
7527
  ];
7133
- case 16:
7528
+ case 18:
7134
7529
  _state.sent();
7135
7530
  this.timing.markAdStarted();
7136
7531
  if (this.timing.expectedAdBreakDurationMs != null && this.timing.getAdBreakEndWallClockMs() == null) {
@@ -7141,16 +7536,16 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7141
7536
  return [
7142
7537
  2
7143
7538
  ];
7144
- case 17:
7539
+ case 19:
7145
7540
  fallbackError = _state.sent();
7146
7541
  if (this.debug) {
7147
7542
  console.warn("[CONTINUOUS-FETCH] Preloaded fallback also failed:", fallbackError);
7148
7543
  }
7149
7544
  return [
7150
7545
  3,
7151
- 18
7546
+ 20
7152
7547
  ];
7153
- case 18:
7548
+ case 20:
7154
7549
  if (this.timing.isTemporaryAdError(error)) {
7155
7550
  this.timing.temporaryFailureUrls.set(firstAdUrl, Date.now());
7156
7551
  if (this.debug) {
@@ -7168,13 +7563,137 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7168
7563
  4,
7169
7564
  this.tryNextAvailableAdWithRateLimit()
7170
7565
  ];
7171
- case 19:
7566
+ case 21:
7172
7567
  _state.sent();
7173
7568
  return [
7174
7569
  3,
7175
- 20
7570
+ 22
7176
7571
  ];
7177
- case 20:
7572
+ case 22:
7573
+ return [
7574
+ 2
7575
+ ];
7576
+ }
7577
+ });
7578
+ }).call(this);
7579
+ }
7580
+ },
7581
+ {
7582
+ key: "startOptimizedPod",
7583
+ value: // ───────────────────────────────────────────────────────────────
7584
+ // Optimized pod (single multi-ad request)
7585
+ // ───────────────────────────────────────────────────────────────
7586
+ function startOptimizedPod(baseVastUrl, breakDurationMs, currentMuted, currentVolume) {
7587
+ return _async_to_generator(function() {
7588
+ var podUrl, adPlayer, requestToken, _ref, _adPlayer_getPodAdCount, podCount, error;
7589
+ return _ts_generator(this, function(_state) {
7590
+ switch(_state.label){
7591
+ case 0:
7592
+ if (this.pendingAdBreak && this.pendingAdBreak.vastUrls.length > 0) {
7593
+ podUrl = this.pendingAdBreak.vastUrls[0];
7594
+ this.clearPendingAdBreak();
7595
+ } else {
7596
+ podUrl = this.host.generatePodVastUrl(baseVastUrl, breakDurationMs);
7597
+ }
7598
+ if (!podUrl) {
7599
+ return [
7600
+ 2,
7601
+ false
7602
+ ];
7603
+ }
7604
+ this.continuousFetchingActive = false;
7605
+ this.recreateAdController();
7606
+ adPlayer = this.host.getAdPlayer();
7607
+ requestToken = ++this.timing.adRequestTokenCounter;
7608
+ this.timing.activeAdRequestToken = requestToken;
7609
+ this.timing.startAdRequestWatchdog(requestToken);
7610
+ _state.label = 1;
7611
+ case 1:
7612
+ _state.trys.push([
7613
+ 1,
7614
+ 5,
7615
+ ,
7616
+ 6
7617
+ ]);
7618
+ return [
7619
+ 4,
7620
+ this.timing.enforceGlobalRateLimit()
7621
+ ];
7622
+ case 2:
7623
+ _state.sent();
7624
+ this.timing.lastAdRequestTime = Date.now();
7625
+ return [
7626
+ 4,
7627
+ adPlayer.requestAds(podUrl)
7628
+ ];
7629
+ case 3:
7630
+ _state.sent();
7631
+ this.timing.clearAdRequestWatchdog();
7632
+ if (this.timing.activeAdRequestToken !== requestToken) {
7633
+ return [
7634
+ 2,
7635
+ true
7636
+ ];
7637
+ }
7638
+ podCount = (_ref = (_adPlayer_getPodAdCount = adPlayer.getPodAdCount) === null || _adPlayer_getPodAdCount === void 0 ? void 0 : _adPlayer_getPodAdCount.call(adPlayer)) !== null && _ref !== void 0 ? _ref : 1;
7639
+ if (podCount < 1) {
7640
+ return [
7641
+ 2,
7642
+ false
7643
+ ];
7644
+ }
7645
+ if (this.debug) {
7646
+ 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"));
7647
+ }
7648
+ sendAdLoadedTracking(this.host.config.licenseKey, {
7649
+ source: "hls",
7650
+ vastUrl: podUrl,
7651
+ timestamp: /* @__PURE__ */ new Date().toISOString()
7652
+ }, this.analyticsContext).catch(function() {});
7653
+ this.timing.startAdFailsafeTimer(requestToken);
7654
+ return [
7655
+ 4,
7656
+ adPlayer.play()
7657
+ ];
7658
+ case 4:
7659
+ _state.sent();
7660
+ this.timing.markAdStarted();
7661
+ if (this.timing.expectedAdBreakDurationMs != null && this.timing.getAdBreakEndWallClockMs() == null) {
7662
+ this.timing.scheduleAdStopAtBreakBoundary();
7663
+ }
7664
+ adPlayer.setAdVolume(currentMuted ? 0 : currentVolume);
7665
+ this.timing.consecutiveFailures = 0;
7666
+ if (podCount === 1) {
7667
+ this.continuousFetchingActive = true;
7668
+ this.startContinuousFetching(baseVastUrl);
7669
+ if (!this.preloadPool.active) {
7670
+ this.preloadPool.startPreloadPool(baseVastUrl, []);
7671
+ }
7672
+ }
7673
+ return [
7674
+ 2,
7675
+ true
7676
+ ];
7677
+ case 5:
7678
+ error = _state.sent();
7679
+ this.timing.clearAdRequestWatchdog();
7680
+ this.timing.clearAdFailsafeTimer();
7681
+ if (this.timing.activeAdRequestToken === requestToken) {
7682
+ this.timing.activeAdRequestToken = null;
7683
+ }
7684
+ if (this.debug) {
7685
+ console.warn("[POD] Optimized pod request/play failed:", error);
7686
+ }
7687
+ if (this.timing.isTemporaryAdError(error)) {
7688
+ this.timing.temporaryFailureUrls.set(podUrl, Date.now());
7689
+ }
7690
+ this.continuousFetchingActive = true;
7691
+ this.recreateAdController();
7692
+ return [
7693
+ 2,
7694
+ false
7695
+ ];
7696
+ case 6:
7178
7697
  return [
7179
7698
  2
7180
7699
  ];
@@ -7497,7 +8016,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7497
8016
  source: "hls",
7498
8017
  vastUrl: preloaded.vastUrl,
7499
8018
  timestamp: /* @__PURE__ */ new Date().toISOString()
7500
- }).catch(function() {});
8019
+ }, this.analyticsContext).catch(function() {});
7501
8020
  _state.label = 1;
7502
8021
  case 1:
7503
8022
  _state.trys.push([
@@ -7730,7 +8249,7 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7730
8249
  source: "hls",
7731
8250
  vastUrl: vastTagUrl,
7732
8251
  timestamp: /* @__PURE__ */ new Date().toISOString()
7733
- }).catch(function() {});
8252
+ }, this.analyticsContext).catch(function() {});
7734
8253
  this.timing.clearAdRequestWatchdog();
7735
8254
  if (this.timing.activeAdRequestToken !== requestToken) return [
7736
8255
  2
@@ -8256,6 +8775,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8256
8775
  },
8257
8776
  generateVastUrls: function generateVastUrls(base, count) {
8258
8777
  return _this.generateVastUrls(base, count);
8778
+ },
8779
+ generatePodVastUrl: function generatePodVastUrl(base, breakDurationMs) {
8780
+ return _this.generatePodVastUrl(base, breakDurationMs);
8259
8781
  }
8260
8782
  }, this.timing, this.preloadPool, this.adConfig, this.cueManager, this.placeholder);
8261
8783
  }
@@ -8288,6 +8810,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8288
8810
  return this.adConfig.generateVastUrlsWithCorrelators(baseUrl, count, this.adPlayer, this.palNonce, this.adBreak.inAdBreak);
8289
8811
  }
8290
8812
  },
8813
+ {
8814
+ key: "generatePodVastUrl",
8815
+ value: function generatePodVastUrl(baseUrl, breakDurationMs) {
8816
+ var podParams = this.adConfig.resolvePodParams(breakDurationMs);
8817
+ return this.adConfig.generatePodVastUrl(baseUrl, podParams, this.adPlayer, this.palNonce, this.adBreak.inAdBreak);
8818
+ }
8819
+ },
8291
8820
  {
8292
8821
  key: "load",
8293
8822
  value: // ───────────────────────────────────────────────────────────────
@@ -8522,7 +9051,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8522
9051
  sendAdDetectTracking(this.config.licenseKey, _object_spread({
8523
9052
  source: "scte35",
8524
9053
  timestamp: /* @__PURE__ */ new Date().toISOString()
8525
- }, detectPayload)).catch(function() {});
9054
+ }, detectPayload), buildAnalyticsContext(this.config)).catch(function() {});
8526
9055
  }
8527
9056
  var hasPrefetchedAds = this.adBreak.pendingAdBreak && this.adBreak.pendingAdBreak.vastUrls.length > 0;
8528
9057
  var durationMs = marker.durationSeconds != null ? marker.durationSeconds * 1e3 : ((_this_adBreak_pendingAdBreak = this.adBreak.pendingAdBreak) === null || _this_adBreak_pendingAdBreak === void 0 ? void 0 : _this_adBreak_pendingAdBreak.marker.durationSeconds) != null ? this.adBreak.pendingAdBreak.marker.durationSeconds * 1e3 : void 0;
@@ -8676,7 +9205,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8676
9205
  }
8677
9206
  this.adConfig.beginNewAdPod();
8678
9207
  this.adConfig.podAssignedByPrefetch = true;
8679
- var generatedUrls = this.generateVastUrls(baseVastUrl, 1);
9208
+ var optimizedPods = !!this.config.optimizedPods;
9209
+ var breakDurationMs = marker.durationSeconds != null ? marker.durationSeconds * 1e3 : void 0;
9210
+ var generatedUrls = optimizedPods ? [
9211
+ this.generatePodVastUrl(baseVastUrl, breakDurationMs)
9212
+ ] : this.generateVastUrls(baseVastUrl, 1);
8680
9213
  this.adBreak.pendingAdBreak = _object_spread_props(_object_spread({
8681
9214
  marker: marker
8682
9215
  }, fragmentSn !== void 0 ? {
@@ -8695,10 +9228,16 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8695
9228
  sendAdDetectTracking(this.config.licenseKey, _object_spread({
8696
9229
  source: "scte35",
8697
9230
  timestamp: /* @__PURE__ */ new Date().toISOString()
8698
- }, detectPayload)).catch(function() {});
9231
+ }, detectPayload), buildAnalyticsContext(this.config)).catch(function() {});
8699
9232
  if (this.debug) {
8700
9233
  console.log("[PREFETCH] Starting ad prefetch for upcoming ad break");
8701
- console.log("[PREFETCH] Pre-generated ".concat(generatedUrls.length, " VAST URLs"));
9234
+ console.log("[PREFETCH] Pre-generated ".concat(generatedUrls.length, " ").concat(optimizedPods ? "pod" : "VAST", " URL(s)"));
9235
+ }
9236
+ if (optimizedPods) {
9237
+ if (this.debug) {
9238
+ console.log("[PREFETCH] Optimized pods enabled - skipping single-ad preload pool");
9239
+ }
9240
+ return;
8702
9241
  }
8703
9242
  this.preloadPool.startPreloadPool(baseVastUrl, generatedUrls.slice(0, 1), false);
8704
9243
  }