stormcloud-video-player 0.8.55 → 0.8.56

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 (56) hide show
  1. package/dist/stormcloud-vp.min.js +2 -2
  2. package/lib/index.cjs +222 -82
  3. package/lib/index.cjs.map +1 -1
  4. package/lib/index.d.cts +0 -1
  5. package/lib/index.d.ts +0 -1
  6. package/lib/index.js +222 -82
  7. package/lib/index.js.map +1 -1
  8. package/lib/player/AdBreakOrchestrator.cjs +27 -29
  9. package/lib/player/AdBreakOrchestrator.cjs.map +1 -1
  10. package/lib/player/AdBreakOrchestrator.d.cts +1 -1
  11. package/lib/player/AdConfigManager.cjs +3 -14
  12. package/lib/player/AdConfigManager.cjs.map +1 -1
  13. package/lib/player/AdConfigManager.d.cts +1 -1
  14. package/lib/player/AdTimingService.d.cts +1 -1
  15. package/lib/player/HlsEngine.cjs.map +1 -1
  16. package/lib/player/HlsEngine.d.cts +1 -1
  17. package/lib/player/PlaceholderLayer.cjs.map +1 -1
  18. package/lib/player/PlayerControls.cjs.map +1 -1
  19. package/lib/player/PlayerControls.d.cts +1 -1
  20. package/lib/player/Scte35CueManager.cjs.map +1 -1
  21. package/lib/player/Scte35CueManager.d.cts +1 -1
  22. package/lib/player/Scte35Parser.cjs.map +1 -1
  23. package/lib/player/Scte35Parser.d.cts +1 -1
  24. package/lib/player/StormcloudVideoPlayer.cjs +222 -82
  25. package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
  26. package/lib/player/StormcloudVideoPlayer.d.cts +1 -1
  27. package/lib/player/playerTypes.cjs.map +1 -1
  28. package/lib/player/playerTypes.d.cts +1 -1
  29. package/lib/players/HlsPlayer.cjs +222 -82
  30. package/lib/players/HlsPlayer.cjs.map +1 -1
  31. package/lib/players/HlsPlayer.d.cts +1 -1
  32. package/lib/players/index.cjs +222 -82
  33. package/lib/players/index.cjs.map +1 -1
  34. package/lib/sdk/hlsAdPlayer.cjs +194 -52
  35. package/lib/sdk/hlsAdPlayer.cjs.map +1 -1
  36. package/lib/sdk/hlsAdPlayer.d.cts +1 -1
  37. package/lib/{types-DpbgEvSH.d.cts → types-cTqIKw_D.d.cts} +0 -1
  38. package/lib/ui/StormcloudVideoPlayer.cjs +222 -82
  39. package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
  40. package/lib/ui/StormcloudVideoPlayer.d.cts +1 -1
  41. package/lib/utils/browserCompat.cjs.map +1 -1
  42. package/lib/utils/ctvVastSignals.cjs.map +1 -1
  43. package/lib/utils/devUrl.cjs.map +1 -1
  44. package/lib/utils/mqttClient.cjs.map +1 -1
  45. package/lib/utils/polyfills.cjs.map +1 -1
  46. package/lib/utils/tracking.cjs +7 -19
  47. package/lib/utils/tracking.cjs.map +1 -1
  48. package/lib/utils/tracking.d.cts +1 -1
  49. package/lib/utils/vastEnvironmentSignals.cjs +0 -4
  50. package/lib/utils/vastEnvironmentSignals.cjs.map +1 -1
  51. package/lib/utils/vastEnvironmentSignals.d.cts +1 -2
  52. package/lib/utils/vastMacros.cjs.map +1 -1
  53. package/lib/utils/vastTrackingMacros.cjs +185 -0
  54. package/lib/utils/vastTrackingMacros.cjs.map +1 -0
  55. package/lib/utils/vastTrackingMacros.d.cts +19 -0
  56. package/package.json +1 -1
package/lib/index.d.cts CHANGED
@@ -163,7 +163,6 @@ interface AdLoadedInfo {
163
163
  interface AdImpressionInfo {
164
164
  source: "vast" | "hls";
165
165
  adIndex: number;
166
- adId?: string;
167
166
  adUrl?: string;
168
167
  durationSeconds?: number;
169
168
  timestamp: string;
package/lib/index.d.ts CHANGED
@@ -163,7 +163,6 @@ interface AdLoadedInfo {
163
163
  interface AdImpressionInfo {
164
164
  source: "vast" | "hls";
165
165
  adIndex: number;
166
- adId?: string;
167
166
  adUrl?: string;
168
167
  durationSeconds?: number;
169
168
  timestamp: string;
package/lib/index.js CHANGED
@@ -560,15 +560,147 @@ function supportsFeature(feature) {
560
560
  return false;
561
561
  }
562
562
  }
563
+ // src/utils/vastTrackingMacros.ts
564
+ var VAST_MACRO_PATTERN = /\[([A-Z][A-Z0-9_]*)\]/g;
565
+ var CACHEBUSTING_ALIASES = /\[CACHEBUSTER\]|\[cachebuster\]|\[timestamp\]|\[random\]|\[INSERT_RANDOM_NUMBER\]|%%CACHEBUSTER%%|%%CACHEBUST%%|\$\{CACHEBUSTER\}|\$\{CACHEBUSTING\}|\{cachebuster\}|\{random\}/g;
566
+ var KNOWN_VAST_MACROS = /* @__PURE__ */ new Set([
567
+ "ADCATEGORIES",
568
+ "ADCOUNT",
569
+ "ADPLAYHEAD",
570
+ "ADSERVINGID",
571
+ "ADTYPE",
572
+ "APIFRAMEWORKS",
573
+ "APPBUNDLE",
574
+ "ASSETURI",
575
+ "BLOCKEDADCATEGORIES",
576
+ "BREAKMAXADLENGTH",
577
+ "BREAKMAXADS",
578
+ "BREAKMAXDURATION",
579
+ "BREAKMINADLENGTH",
580
+ "BREAKPOSITION",
581
+ "CACHEBUSTING",
582
+ "CLICKPOS",
583
+ "CLICKTYPE",
584
+ "CLIENTUA",
585
+ "CONTENTID",
586
+ "CONTENTPLAYHEAD",
587
+ "CONTENTURI",
588
+ "DEVICEIP",
589
+ "DEVICEUA",
590
+ "DOMAIN",
591
+ "ERRORCODE",
592
+ "EXTENSIONS",
593
+ "GDPRCONSENT",
594
+ "IFA",
595
+ "IFATYPE",
596
+ "INVENTORYSTATE",
597
+ "LATLONG",
598
+ "LIMITADTRACKING",
599
+ "MEDIAMIME",
600
+ "MEDIAPLAYHEAD",
601
+ "OMIDPARTNER",
602
+ "PAGEURL",
603
+ "PLACEMENTTYPE",
604
+ "PLAYERCAPABILITIES",
605
+ "PLAYERSIZE",
606
+ "PLAYERSTATE",
607
+ "PODSEQUENCE",
608
+ "REGULATIONS",
609
+ "SERVERSIDE",
610
+ "SERVERUA",
611
+ "TIMESTAMP",
612
+ "TRANSACTIONID",
613
+ "UNIVERSALADID",
614
+ "VASTVERSIONS",
615
+ "VERIFICATIONVENDORS"
616
+ ]);
617
+ function generateCachebuster() {
618
+ return String(Math.floor(Math.random() * 9e7) + 1e7);
619
+ }
620
+ function formatPlayhead(seconds) {
621
+ if (seconds == null || !Number.isFinite(seconds) || seconds < 0) {
622
+ return void 0;
623
+ }
624
+ var total = Math.floor(seconds);
625
+ var hh = String(Math.floor(total / 3600)).padStart(2, "0");
626
+ var mm = String(Math.floor(total % 3600 / 60)).padStart(2, "0");
627
+ var ss = String(total % 60).padStart(2, "0");
628
+ var ms = String(Math.floor((seconds - total) * 1e3)).padStart(3, "0");
629
+ return "".concat(hh, ":").concat(mm, ":").concat(ss, ".").concat(ms);
630
+ }
631
+ function resolveMacroValues(ctx) {
632
+ var values = /* @__PURE__ */ new Map();
633
+ var set = function set(key, value) {
634
+ if (value != null && value !== "") values.set(key, value);
635
+ };
636
+ var adPlayhead = formatPlayhead(ctx.adPlayheadSeconds);
637
+ set("ADPLAYHEAD", adPlayhead);
638
+ set("MEDIAPLAYHEAD", adPlayhead);
639
+ set("CONTENTPLAYHEAD", formatPlayhead(ctx.contentPlayheadSeconds));
640
+ set("ASSETURI", ctx.assetUri);
641
+ set("MEDIAMIME", ctx.mediaMime);
642
+ set("TIMESTAMP", (/* @__PURE__ */ new Date()).toISOString());
643
+ set("SERVERSIDE", "0");
644
+ if (ctx.errorCode != null && ctx.errorCode !== "") {
645
+ set("ERRORCODE", String(ctx.errorCode));
646
+ }
647
+ if (ctx.playerWidth != null && ctx.playerHeight != null) {
648
+ set("PLAYERSIZE", "".concat(Math.round(ctx.playerWidth), ",").concat(Math.round(ctx.playerHeight)));
649
+ }
650
+ set("IFA", ctx.deviceId);
651
+ set("IFATYPE", ctx.deviceIdType);
652
+ if (ctx.limitAdTracking != null) {
653
+ set("LIMITADTRACKING", ctx.limitAdTracking ? "1" : "0");
654
+ }
655
+ set("PAGEURL", ctx.pageUrl);
656
+ if (ctx.pageUrl) {
657
+ try {
658
+ set("DOMAIN", new URL(ctx.pageUrl).hostname);
659
+ } catch (unused) {}
660
+ }
661
+ set("CLIENTUA", ctx.clientUa);
662
+ set("DEVICEUA", ctx.clientUa);
663
+ if (ctx.podSequence != null) {
664
+ set("PODSEQUENCE", String(ctx.podSequence));
665
+ }
666
+ return values;
667
+ }
668
+ function substituteVastTrackingMacros(url) {
669
+ var ctx = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
670
+ if (!url) return url;
671
+ var values = resolveMacroValues(ctx);
672
+ return url.replace(CACHEBUSTING_ALIASES, function() {
673
+ return generateCachebuster();
674
+ }).replace(VAST_MACRO_PATTERN, function(match, name) {
675
+ if (name === "CACHEBUSTING") return generateCachebuster();
676
+ var value = values.get(name);
677
+ if (value != null) return encodeURIComponent(value);
678
+ return KNOWN_VAST_MACROS.has(name) ? "" : match;
679
+ });
680
+ }
563
681
  // src/sdk/hlsAdPlayer.ts
564
682
  var MAX_VAST_WRAPPER_DEPTH = 5;
683
+ var BEACON_TIMEOUT_MS = 3e4;
684
+ var inFlightBeacons = /* @__PURE__ */ new Set();
685
+ var VAST_ERROR_MEDIA_DISPLAY = 405;
686
+ function toVastMediaErrorCode(error) {
687
+ switch(error === null || error === void 0 ? void 0 : error.code){
688
+ case 1:
689
+ return 400;
690
+ case 2:
691
+ return 401;
692
+ case 4:
693
+ return 403;
694
+ default:
695
+ return VAST_ERROR_MEDIA_DISPLAY;
696
+ }
697
+ }
565
698
  function createHlsAdPlayer(contentVideo, options) {
566
699
  var _contentVideo_AD_VIDEO_PROP, _contentVideo_AD_CONTAINER_PROP;
567
700
  var adPlaying = false;
568
701
  var originalMutedState = false;
569
702
  var originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));
570
703
  var listeners = /* @__PURE__ */ new Map();
571
- var licenseKey = options === null || options === void 0 ? void 0 : options.licenseKey;
572
704
  var mainHlsInstance = options === null || options === void 0 ? void 0 : options.mainHlsInstance;
573
705
  var AD_CONTAINER_PROP = "__stormcloudAdContainer";
574
706
  var AD_VIDEO_PROP = "__stormcloudAdVideo";
@@ -579,10 +711,9 @@ function createHlsAdPlayer(contentVideo, options) {
579
711
  var adContainerEl = (_contentVideo_AD_CONTAINER_PROP = contentVideo[AD_CONTAINER_PROP]) !== null && _contentVideo_AD_CONTAINER_PROP !== void 0 ? _contentVideo_AD_CONTAINER_PROP : void 0;
580
712
  var adEventHandlers = [];
581
713
  var currentAd;
582
- var currentAdMediaUrl;
714
+ var currentAdMediaFile;
583
715
  var podAds = [];
584
716
  var podIndex = 0;
585
- var sessionId;
586
717
  var preloadedAds = /* @__PURE__ */ new Map();
587
718
  var preloadingAds = /* @__PURE__ */ new Map();
588
719
  var destroyed = false;
@@ -632,21 +763,47 @@ function createHlsAdPlayer(contentVideo, options) {
632
763
  }
633
764
  }
634
765
  }
635
- function generateSessionId() {
636
- return "session-".concat(Date.now(), "-").concat(Math.random().toString(36).substr(2, 9));
766
+ function buildTrackingMacroContext(errorCode) {
767
+ var context = {
768
+ adPlayheadSeconds: adVideoElement === null || adVideoElement === void 0 ? void 0 : adVideoElement.currentTime,
769
+ contentPlayheadSeconds: contentVideo.currentTime,
770
+ assetUri: currentAdMediaFile === null || currentAdMediaFile === void 0 ? void 0 : currentAdMediaFile.url,
771
+ mediaMime: currentAdMediaFile === null || currentAdMediaFile === void 0 ? void 0 : currentAdMediaFile.type,
772
+ playerWidth: (adVideoElement === null || adVideoElement === void 0 ? void 0 : adVideoElement.clientWidth) || (adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.clientWidth),
773
+ playerHeight: (adVideoElement === null || adVideoElement === void 0 ? void 0 : adVideoElement.clientHeight) || (adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.clientHeight)
774
+ };
775
+ if (errorCode != null) {
776
+ context.errorCode = errorCode;
777
+ }
778
+ if (typeof navigator !== "undefined" && navigator.userAgent) {
779
+ context.clientUa = navigator.userAgent;
780
+ }
781
+ if (typeof location !== "undefined" && location.href) {
782
+ context.pageUrl = location.href;
783
+ }
784
+ if (podAds.length > 0) {
785
+ context.podSequence = podIndex + 1;
786
+ }
787
+ return context;
637
788
  }
638
- function fireTrackingPixels(urls) {
789
+ function fireTrackingPixels(urls, options2) {
639
790
  if (!urls || urls.length === 0) return;
791
+ var macroContext = buildTrackingMacroContext(options2 === null || options2 === void 0 ? void 0 : options2.errorCode);
640
792
  urls.forEach(function(url) {
641
793
  try {
642
- var trackingUrl = url;
643
- if (sessionId) {
644
- trackingUrl = "".concat(trackingUrl).concat(trackingUrl.includes("?") ? "&" : "?", "session_id=").concat(sessionId);
645
- }
646
- if (licenseKey) {
647
- trackingUrl = "".concat(trackingUrl).concat(trackingUrl.includes("?") ? "&" : "?", "license_key=").concat(licenseKey);
648
- }
794
+ var trackingUrl = substituteVastTrackingMacros(url, macroContext);
649
795
  var img = new Image(1, 1);
796
+ inFlightBeacons.add(img);
797
+ var timeoutId;
798
+ var release = function release() {
799
+ if (timeoutId !== void 0) clearTimeout(timeoutId);
800
+ img.onload = null;
801
+ img.onerror = null;
802
+ inFlightBeacons.delete(img);
803
+ };
804
+ img.onload = release;
805
+ img.onerror = release;
806
+ timeoutId = setTimeout(release, BEACON_TIMEOUT_MS);
650
807
  img.src = trackingUrl;
651
808
  console.log("[HlsAdPlayer] Fired tracking pixel: ".concat(trackingUrl));
652
809
  } catch (error) {
@@ -1285,7 +1442,9 @@ function createHlsAdPlayer(contentVideo, options) {
1285
1442
  if (!adPlaying) return;
1286
1443
  console.error("[HlsAdPlayer] Ad video error:", e);
1287
1444
  if (currentAd) {
1288
- fireTrackingPixels(currentAd.trackingUrls.error);
1445
+ fireTrackingPixels(currentAd.trackingUrls.error, {
1446
+ errorCode: toVastMediaErrorCode(adVideoElement === null || adVideoElement === void 0 ? void 0 : adVideoElement.error)
1447
+ });
1289
1448
  }
1290
1449
  if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1291
1450
  return;
@@ -1397,9 +1556,9 @@ function createHlsAdPlayer(contentVideo, options) {
1397
1556
  delete contentVideo.dataset.stormcloudAdPlaying;
1398
1557
  }
1399
1558
  }
1400
- function resetQuartileTracking() {
1559
+ function resetQuartileTracking(preserveImpression) {
1401
1560
  trackingFired = {
1402
- impression: false,
1561
+ impression: preserveImpression ? trackingFired.impression : false,
1403
1562
  start: false,
1404
1563
  firstQuartile: false,
1405
1564
  midpoint: false,
@@ -1407,27 +1566,6 @@ function createHlsAdPlayer(contentVideo, options) {
1407
1566
  complete: false
1408
1567
  };
1409
1568
  }
1410
- function markCreativeRendered(reason) {
1411
- if (!currentAd || trackingFired.impression) return;
1412
- trackingFired.impression = true;
1413
- fireTrackingPixels(currentAd.trackingUrls.impression);
1414
- console.log("[HlsAdPlayer] Impression (pod ".concat(podIndex + 1, "/").concat(podAds.length || 1, ", reason: ").concat(reason, "): ").concat(currentAd.title));
1415
- emit("ad_impression", {
1416
- adId: currentAd.id,
1417
- title: currentAd.title,
1418
- durationSeconds: currentAd.duration,
1419
- mediaUrl: currentAdMediaUrl,
1420
- podIndex: podIndex,
1421
- podSize: podAds.length || 1,
1422
- reason: reason
1423
- });
1424
- }
1425
- function canDetectBlackFrames() {
1426
- if (!adVideoElement) return false;
1427
- if (requiresMediaPipelineResetAfterAds()) return false;
1428
- if (isRvfcSupported(adVideoElement)) return true;
1429
- return getDecodedVideoFrameCount(adVideoElement) !== void 0;
1430
- }
1431
1569
  function isRvfcSupported(video) {
1432
1570
  return typeof video.requestVideoFrameCallback === "function";
1433
1571
  }
@@ -1490,7 +1628,7 @@ function createHlsAdPlayer(contentVideo, options) {
1490
1628
  if (!mediaFile) {
1491
1629
  throw new Error("No media file available for ad");
1492
1630
  }
1493
- currentAdMediaUrl = mediaFile.url;
1631
+ currentAdMediaFile = mediaFile;
1494
1632
  var isHlsAd = isHlsMediaFile(mediaFile);
1495
1633
  console.log("[HlsAdPlayer] Loading ".concat(isHlsAd ? "HLS" : "progressive", " ad (pod ").concat(podIndex + 1, "/").concat(podAds.length || 1, ") from: ").concat(mediaFile.url));
1496
1634
  if (isHlsAd && Hls.isSupported()) {
@@ -1534,9 +1672,11 @@ function createHlsAdPlayer(contentVideo, options) {
1534
1672
  }
1535
1673
  podIndex++;
1536
1674
  currentAd = podAds[podIndex];
1537
- currentAdMediaUrl = void 0;
1538
- resetQuartileTracking();
1675
+ currentAdMediaFile = void 0;
1676
+ resetQuartileTracking(false);
1539
1677
  if (currentAd) {
1678
+ fireTrackingPixels(currentAd.trackingUrls.impression);
1679
+ trackingFired.impression = true;
1540
1680
  console.log("[HlsAdPlayer] Advancing to next pod ad (".concat(podIndex + 1, "/").concat(podAds.length, "): ").concat(currentAd.title, ", duration: ").concat(currentAd.duration, "s"));
1541
1681
  }
1542
1682
  clearStallWatchdog();
@@ -1575,7 +1715,9 @@ function createHlsAdPlayer(contentVideo, options) {
1575
1715
  console.warn("[HlsAdPlayer] Ad playback stalled (no progress) - recovering to avoid a blank frame");
1576
1716
  clearStallWatchdog();
1577
1717
  if (currentAd) {
1578
- fireTrackingPixels(currentAd.trackingUrls.error);
1718
+ fireTrackingPixels(currentAd.trackingUrls.error, {
1719
+ errorCode: VAST_ERROR_MEDIA_DISPLAY
1720
+ });
1579
1721
  }
1580
1722
  if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1581
1723
  return;
@@ -1631,7 +1773,6 @@ function createHlsAdPlayer(contentVideo, options) {
1631
1773
  if (!adPlaying) return;
1632
1774
  sawDecodedVideoFrame = true;
1633
1775
  markRvfcReliable();
1634
- markCreativeRendered("first_presented_frame");
1635
1776
  };
1636
1777
  try {
1637
1778
  videoFrameCallbackHandle = rvfc.call(adVideoElement, onPresentedFrame);
@@ -1644,7 +1785,9 @@ function createHlsAdPlayer(contentVideo, options) {
1644
1785
  console.warn("[HlsAdPlayer] Ad audio is advancing but no video frames decoded (black screen) - skipping this creative");
1645
1786
  clearStallWatchdog();
1646
1787
  if (currentAd) {
1647
- fireTrackingPixels(currentAd.trackingUrls.error);
1788
+ fireTrackingPixels(currentAd.trackingUrls.error, {
1789
+ errorCode: VAST_ERROR_MEDIA_DISPLAY
1790
+ });
1648
1791
  }
1649
1792
  if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1650
1793
  return;
@@ -1666,7 +1809,6 @@ function createHlsAdPlayer(contentVideo, options) {
1666
1809
  if (decodedFrames !== void 0 && decodedFrames > 0) {
1667
1810
  sawDecodedVideoFrame = true;
1668
1811
  markFrameCounterReliable();
1669
- markCreativeRendered("decoded_frames");
1670
1812
  } else if (adVideoElement.currentTime >= BLACKFRAME_MIN_PLAYBACK_S) {
1671
1813
  var timeAdvancing = adVideoElement.currentTime > lastAdProgressPosition + 0.05;
1672
1814
  if (isRvfcSupported(adVideoElement) && timeAdvancing && isRvfcReliable()) {
@@ -1679,9 +1821,6 @@ function createHlsAdPlayer(contentVideo, options) {
1679
1821
  }
1680
1822
  }
1681
1823
  }
1682
- if (!trackingFired.impression && !adVideoElement.paused && adVideoElement.currentTime >= BLACKFRAME_MIN_PLAYBACK_S && (sawDecodedVideoFrame || !canDetectBlackFrames())) {
1683
- markCreativeRendered(sawDecodedVideoFrame ? "decoded_frames" : "sustained_playback");
1684
- }
1685
1824
  if (adVideoElement.currentTime > lastAdProgressPosition + 0.05) {
1686
1825
  noteAdProgress();
1687
1826
  return;
@@ -1782,7 +1921,6 @@ function createHlsAdPlayer(contentVideo, options) {
1782
1921
  ,
1783
1922
  6
1784
1923
  ]);
1785
- sessionId = generateSessionId();
1786
1924
  ads = [];
1787
1925
  if (!preloadedAds.has(vastTagUrl)) return [
1788
1926
  3,
@@ -1820,9 +1958,12 @@ function createHlsAdPlayer(contentVideo, options) {
1820
1958
  podAds = ads;
1821
1959
  podIndex = 0;
1822
1960
  currentAd = ads[0];
1823
- currentAdMediaUrl = void 0;
1824
- resetQuartileTracking();
1961
+ currentAdMediaFile = void 0;
1825
1962
  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"));
1963
+ if (currentAd) {
1964
+ fireTrackingPixels(currentAd.trackingUrls.impression);
1965
+ trackingFired.impression = true;
1966
+ }
1826
1967
  return [
1827
1968
  2,
1828
1969
  Promise.resolve()
@@ -1862,7 +2003,7 @@ function createHlsAdPlayer(contentVideo, options) {
1862
2003
  contentVideo[AD_VIDEO_PROP] = adVideoElement;
1863
2004
  }
1864
2005
  setupAdEventListeners();
1865
- resetQuartileTracking();
2006
+ resetQuartileTracking(true);
1866
2007
  contentVolume = contentVideo.volume;
1867
2008
  originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1868
2009
  if (!(options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds)) {
@@ -1952,7 +2093,7 @@ function createHlsAdPlayer(contentVideo, options) {
1952
2093
  }
1953
2094
  }
1954
2095
  currentAd = void 0;
1955
- currentAdMediaUrl = void 0;
2096
+ currentAdMediaFile = void 0;
1956
2097
  podAds = [];
1957
2098
  podIndex = 0;
1958
2099
  return [
@@ -1993,6 +2134,7 @@ function createHlsAdPlayer(contentVideo, options) {
1993
2134
  teardownAdEventListeners();
1994
2135
  releaseAdDecoder();
1995
2136
  currentAd = void 0;
2137
+ currentAdMediaFile = void 0;
1996
2138
  podAds = [];
1997
2139
  podIndex = 0;
1998
2140
  listeners.clear();
@@ -3307,19 +3449,8 @@ function buildPlayerMetricEvent() {
3307
3449
  }).apply(this, arguments);
3308
3450
  }
3309
3451
  function publishTracking(licenseKey, channel, body) {
3310
- var debug = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : false;
3311
3452
  ensureMQTTClient();
3312
- var topic = buildPlayerTopic(licenseKey, channel);
3313
- var published = publishMQTT(topic, body);
3314
- if (debug) {
3315
- console.log("[StormcloudVideoPlayer] publishTracking:", JSON.stringify({
3316
- licenseKey: licenseKey,
3317
- channel: channel,
3318
- topic: topic,
3319
- body: body,
3320
- published: published
3321
- }, null, 2));
3322
- }
3453
+ publishMQTT(buildPlayerTopic(licenseKey, channel), body);
3323
3454
  }
3324
3455
  function sendInitialTracking(_0) {
3325
3456
  return _async_to_generator(function(licenseKey) {
@@ -3353,7 +3484,7 @@ function sendInitialTracking(_0) {
3353
3484
  events: [
3354
3485
  metricEvent
3355
3486
  ]
3356
- }, !!context.debugAdTiming);
3487
+ });
3357
3488
  return [
3358
3489
  3,
3359
3490
  4
@@ -3463,7 +3594,7 @@ function sendAdLoadedTracking(_0, _1) {
3463
3594
  }
3464
3595
  function sendAdImpressionTracking(_0, _1) {
3465
3596
  return _async_to_generator(function(licenseKey, adImpressionInfo) {
3466
- var context, _adImpressionInfo_adUrl, metricEvent, error;
3597
+ var context, metricEvent, error;
3467
3598
  var _arguments = arguments;
3468
3599
  return _ts_generator(this, function(_state) {
3469
3600
  switch(_state.label){
@@ -3488,18 +3619,17 @@ function sendAdImpressionTracking(_0, _1) {
3488
3619
  ];
3489
3620
  case 2:
3490
3621
  metricEvent = _state.sent();
3491
- publishTracking(licenseKey, "heartbeat", metricEvent, !!context.debugAdTiming);
3622
+ publishTracking(licenseKey, "heartbeat", metricEvent);
3492
3623
  publishTracking(licenseKey, "impressions", {
3493
3624
  events: [
3494
3625
  {
3495
- event_id: createUuid(),
3496
3626
  player_id: metricEvent.player_id,
3497
3627
  ad_played_count: 1,
3498
- ad_url: (_adImpressionInfo_adUrl = adImpressionInfo.adUrl) !== null && _adImpressionInfo_adUrl !== void 0 ? _adImpressionInfo_adUrl : adImpressionInfo.adId,
3628
+ ad_url: adImpressionInfo.adUrl,
3499
3629
  capture_at: adImpressionInfo.timestamp
3500
3630
  }
3501
3631
  ]
3502
- }, !!context.debugAdTiming);
3632
+ });
3503
3633
  return [
3504
3634
  3,
3505
3635
  4
@@ -3544,7 +3674,7 @@ function sendHeartbeat(_0) {
3544
3674
  ];
3545
3675
  case 2:
3546
3676
  heartbeatData = _state.sent();
3547
- publishTracking(licenseKey, "heartbeat", heartbeatData, !!context.debugAdTiming);
3677
+ publishTracking(licenseKey, "heartbeat", heartbeatData);
3548
3678
  return [
3549
3679
  3,
3550
3680
  4
@@ -7347,22 +7477,27 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7347
7477
  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 : "?"));
7348
7478
  }
7349
7479
  });
7350
- adPlayer.on("ad_impression", function(payload) {
7351
- var impressionInfo = {
7480
+ adPlayer.on("all_ads_completed", function() {
7481
+ sendAdImpressionTracking(_this.host.config.licenseKey, {
7352
7482
  source: "hls",
7353
7483
  adIndex: _this.timing.currentAdIndex,
7354
7484
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
7355
- };
7356
- if (payload === null || payload === void 0 ? void 0 : payload.adId) impressionInfo.adId = payload.adId;
7357
- if (payload === null || payload === void 0 ? void 0 : payload.mediaUrl) impressionInfo.adUrl = payload.mediaUrl;
7358
- if ((payload === null || payload === void 0 ? void 0 : payload.durationSeconds) != null) {
7359
- impressionInfo.durationSeconds = payload.durationSeconds;
7485
+ }, _this.analyticsContext).catch(function() {});
7486
+ _this.timing.recordPlayedAdDuration(_this.host.getAdPlayer());
7487
+ var remaining = _this.timing.getRemainingAdMs();
7488
+ _this.timing.consecutiveFailures = 0;
7489
+ if (_this.debug) {
7490
+ console.log("[StormcloudVideoPlayer] all_ads_completed event received - remaining=".concat(remaining, "ms, queued ads=").concat(_this.adRequestQueue.length), _this.adRequestQueue.length > 0 ? {
7491
+ queuedUrls: _to_consumable_array(_this.adRequestQueue)
7492
+ } : {});
7360
7493
  }
7361
- sendAdImpressionTracking(_this.host.config.licenseKey, impressionInfo, _this.analyticsContext).catch(function(error) {
7362
- if (_this.debug) {
7363
- console.warn("[AdBreakOrchestrator] Failed to send ad impression tracking:", error);
7494
+ if (_this.inAdBreak) {
7495
+ if (_this.timing.hasTimeToStartAnotherAd()) {
7496
+ _this.tryNextAvailableAdWithRateLimit();
7497
+ } else {
7498
+ _this.handleAdPodComplete();
7364
7499
  }
7365
- });
7500
+ }
7366
7501
  });
7367
7502
  adPlayer.on("ad_error", function(errorPayload) {
7368
7503
  var errorMessage = "Ad playback failed";
@@ -7405,6 +7540,11 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7405
7540
  }
7406
7541
  });
7407
7542
  adPlayer.on("content_resume", function() {
7543
+ sendAdImpressionTracking(_this.host.config.licenseKey, {
7544
+ source: "hls",
7545
+ adIndex: _this.timing.currentAdIndex,
7546
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
7547
+ }, _this.analyticsContext).catch(function() {});
7408
7548
  if (!_this.host.video.muted) {
7409
7549
  _this.host.video.muted = true;
7410
7550
  if (_this.debug) {