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
@@ -520,15 +520,147 @@ function logBrowserInfo() {
520
520
  userAgent: navigator.userAgent
521
521
  }));
522
522
  }
523
+ // src/utils/vastTrackingMacros.ts
524
+ var VAST_MACRO_PATTERN = /\[([A-Z][A-Z0-9_]*)\]/g;
525
+ var CACHEBUSTING_ALIASES = /\[CACHEBUSTER\]|\[cachebuster\]|\[timestamp\]|\[random\]|\[INSERT_RANDOM_NUMBER\]|%%CACHEBUSTER%%|%%CACHEBUST%%|\$\{CACHEBUSTER\}|\$\{CACHEBUSTING\}|\{cachebuster\}|\{random\}/g;
526
+ var KNOWN_VAST_MACROS = /* @__PURE__ */ new Set([
527
+ "ADCATEGORIES",
528
+ "ADCOUNT",
529
+ "ADPLAYHEAD",
530
+ "ADSERVINGID",
531
+ "ADTYPE",
532
+ "APIFRAMEWORKS",
533
+ "APPBUNDLE",
534
+ "ASSETURI",
535
+ "BLOCKEDADCATEGORIES",
536
+ "BREAKMAXADLENGTH",
537
+ "BREAKMAXADS",
538
+ "BREAKMAXDURATION",
539
+ "BREAKMINADLENGTH",
540
+ "BREAKPOSITION",
541
+ "CACHEBUSTING",
542
+ "CLICKPOS",
543
+ "CLICKTYPE",
544
+ "CLIENTUA",
545
+ "CONTENTID",
546
+ "CONTENTPLAYHEAD",
547
+ "CONTENTURI",
548
+ "DEVICEIP",
549
+ "DEVICEUA",
550
+ "DOMAIN",
551
+ "ERRORCODE",
552
+ "EXTENSIONS",
553
+ "GDPRCONSENT",
554
+ "IFA",
555
+ "IFATYPE",
556
+ "INVENTORYSTATE",
557
+ "LATLONG",
558
+ "LIMITADTRACKING",
559
+ "MEDIAMIME",
560
+ "MEDIAPLAYHEAD",
561
+ "OMIDPARTNER",
562
+ "PAGEURL",
563
+ "PLACEMENTTYPE",
564
+ "PLAYERCAPABILITIES",
565
+ "PLAYERSIZE",
566
+ "PLAYERSTATE",
567
+ "PODSEQUENCE",
568
+ "REGULATIONS",
569
+ "SERVERSIDE",
570
+ "SERVERUA",
571
+ "TIMESTAMP",
572
+ "TRANSACTIONID",
573
+ "UNIVERSALADID",
574
+ "VASTVERSIONS",
575
+ "VERIFICATIONVENDORS"
576
+ ]);
577
+ function generateCachebuster() {
578
+ return String(Math.floor(Math.random() * 9e7) + 1e7);
579
+ }
580
+ function formatPlayhead(seconds) {
581
+ if (seconds == null || !Number.isFinite(seconds) || seconds < 0) {
582
+ return void 0;
583
+ }
584
+ var total = Math.floor(seconds);
585
+ var hh = String(Math.floor(total / 3600)).padStart(2, "0");
586
+ var mm = String(Math.floor(total % 3600 / 60)).padStart(2, "0");
587
+ var ss = String(total % 60).padStart(2, "0");
588
+ var ms = String(Math.floor((seconds - total) * 1e3)).padStart(3, "0");
589
+ return "".concat(hh, ":").concat(mm, ":").concat(ss, ".").concat(ms);
590
+ }
591
+ function resolveMacroValues(ctx) {
592
+ var values = /* @__PURE__ */ new Map();
593
+ var set = function set(key, value) {
594
+ if (value != null && value !== "") values.set(key, value);
595
+ };
596
+ var adPlayhead = formatPlayhead(ctx.adPlayheadSeconds);
597
+ set("ADPLAYHEAD", adPlayhead);
598
+ set("MEDIAPLAYHEAD", adPlayhead);
599
+ set("CONTENTPLAYHEAD", formatPlayhead(ctx.contentPlayheadSeconds));
600
+ set("ASSETURI", ctx.assetUri);
601
+ set("MEDIAMIME", ctx.mediaMime);
602
+ set("TIMESTAMP", (/* @__PURE__ */ new Date()).toISOString());
603
+ set("SERVERSIDE", "0");
604
+ if (ctx.errorCode != null && ctx.errorCode !== "") {
605
+ set("ERRORCODE", String(ctx.errorCode));
606
+ }
607
+ if (ctx.playerWidth != null && ctx.playerHeight != null) {
608
+ set("PLAYERSIZE", "".concat(Math.round(ctx.playerWidth), ",").concat(Math.round(ctx.playerHeight)));
609
+ }
610
+ set("IFA", ctx.deviceId);
611
+ set("IFATYPE", ctx.deviceIdType);
612
+ if (ctx.limitAdTracking != null) {
613
+ set("LIMITADTRACKING", ctx.limitAdTracking ? "1" : "0");
614
+ }
615
+ set("PAGEURL", ctx.pageUrl);
616
+ if (ctx.pageUrl) {
617
+ try {
618
+ set("DOMAIN", new URL(ctx.pageUrl).hostname);
619
+ } catch (unused) {}
620
+ }
621
+ set("CLIENTUA", ctx.clientUa);
622
+ set("DEVICEUA", ctx.clientUa);
623
+ if (ctx.podSequence != null) {
624
+ set("PODSEQUENCE", String(ctx.podSequence));
625
+ }
626
+ return values;
627
+ }
628
+ function substituteVastTrackingMacros(url) {
629
+ var ctx = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
630
+ if (!url) return url;
631
+ var values = resolveMacroValues(ctx);
632
+ return url.replace(CACHEBUSTING_ALIASES, function() {
633
+ return generateCachebuster();
634
+ }).replace(VAST_MACRO_PATTERN, function(match, name) {
635
+ if (name === "CACHEBUSTING") return generateCachebuster();
636
+ var value = values.get(name);
637
+ if (value != null) return encodeURIComponent(value);
638
+ return KNOWN_VAST_MACROS.has(name) ? "" : match;
639
+ });
640
+ }
523
641
  // src/sdk/hlsAdPlayer.ts
524
642
  var MAX_VAST_WRAPPER_DEPTH = 5;
643
+ var BEACON_TIMEOUT_MS = 3e4;
644
+ var inFlightBeacons = /* @__PURE__ */ new Set();
645
+ var VAST_ERROR_MEDIA_DISPLAY = 405;
646
+ function toVastMediaErrorCode(error) {
647
+ switch(error === null || error === void 0 ? void 0 : error.code){
648
+ case 1:
649
+ return 400;
650
+ case 2:
651
+ return 401;
652
+ case 4:
653
+ return 403;
654
+ default:
655
+ return VAST_ERROR_MEDIA_DISPLAY;
656
+ }
657
+ }
525
658
  function createHlsAdPlayer(contentVideo, options) {
526
659
  var _contentVideo_AD_VIDEO_PROP, _contentVideo_AD_CONTAINER_PROP;
527
660
  var adPlaying = false;
528
661
  var originalMutedState = false;
529
662
  var originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));
530
663
  var listeners = /* @__PURE__ */ new Map();
531
- var licenseKey = options === null || options === void 0 ? void 0 : options.licenseKey;
532
664
  var mainHlsInstance = options === null || options === void 0 ? void 0 : options.mainHlsInstance;
533
665
  var AD_CONTAINER_PROP = "__stormcloudAdContainer";
534
666
  var AD_VIDEO_PROP = "__stormcloudAdVideo";
@@ -539,10 +671,9 @@ function createHlsAdPlayer(contentVideo, options) {
539
671
  var adContainerEl = (_contentVideo_AD_CONTAINER_PROP = contentVideo[AD_CONTAINER_PROP]) !== null && _contentVideo_AD_CONTAINER_PROP !== void 0 ? _contentVideo_AD_CONTAINER_PROP : void 0;
540
672
  var adEventHandlers = [];
541
673
  var currentAd;
542
- var currentAdMediaUrl;
674
+ var currentAdMediaFile;
543
675
  var podAds = [];
544
676
  var podIndex = 0;
545
- var sessionId;
546
677
  var preloadedAds = /* @__PURE__ */ new Map();
547
678
  var preloadingAds = /* @__PURE__ */ new Map();
548
679
  var destroyed = false;
@@ -592,21 +723,47 @@ function createHlsAdPlayer(contentVideo, options) {
592
723
  }
593
724
  }
594
725
  }
595
- function generateSessionId() {
596
- return "session-".concat(Date.now(), "-").concat(Math.random().toString(36).substr(2, 9));
726
+ function buildTrackingMacroContext(errorCode) {
727
+ var context = {
728
+ adPlayheadSeconds: adVideoElement === null || adVideoElement === void 0 ? void 0 : adVideoElement.currentTime,
729
+ contentPlayheadSeconds: contentVideo.currentTime,
730
+ assetUri: currentAdMediaFile === null || currentAdMediaFile === void 0 ? void 0 : currentAdMediaFile.url,
731
+ mediaMime: currentAdMediaFile === null || currentAdMediaFile === void 0 ? void 0 : currentAdMediaFile.type,
732
+ playerWidth: (adVideoElement === null || adVideoElement === void 0 ? void 0 : adVideoElement.clientWidth) || (adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.clientWidth),
733
+ playerHeight: (adVideoElement === null || adVideoElement === void 0 ? void 0 : adVideoElement.clientHeight) || (adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.clientHeight)
734
+ };
735
+ if (errorCode != null) {
736
+ context.errorCode = errorCode;
737
+ }
738
+ if (typeof navigator !== "undefined" && navigator.userAgent) {
739
+ context.clientUa = navigator.userAgent;
740
+ }
741
+ if (typeof location !== "undefined" && location.href) {
742
+ context.pageUrl = location.href;
743
+ }
744
+ if (podAds.length > 0) {
745
+ context.podSequence = podIndex + 1;
746
+ }
747
+ return context;
597
748
  }
598
- function fireTrackingPixels(urls) {
749
+ function fireTrackingPixels(urls, options2) {
599
750
  if (!urls || urls.length === 0) return;
751
+ var macroContext = buildTrackingMacroContext(options2 === null || options2 === void 0 ? void 0 : options2.errorCode);
600
752
  urls.forEach(function(url) {
601
753
  try {
602
- var trackingUrl = url;
603
- if (sessionId) {
604
- trackingUrl = "".concat(trackingUrl).concat(trackingUrl.includes("?") ? "&" : "?", "session_id=").concat(sessionId);
605
- }
606
- if (licenseKey) {
607
- trackingUrl = "".concat(trackingUrl).concat(trackingUrl.includes("?") ? "&" : "?", "license_key=").concat(licenseKey);
608
- }
754
+ var trackingUrl = substituteVastTrackingMacros(url, macroContext);
609
755
  var img = new Image(1, 1);
756
+ inFlightBeacons.add(img);
757
+ var timeoutId;
758
+ var release = function release() {
759
+ if (timeoutId !== void 0) clearTimeout(timeoutId);
760
+ img.onload = null;
761
+ img.onerror = null;
762
+ inFlightBeacons.delete(img);
763
+ };
764
+ img.onload = release;
765
+ img.onerror = release;
766
+ timeoutId = setTimeout(release, BEACON_TIMEOUT_MS);
610
767
  img.src = trackingUrl;
611
768
  console.log("[HlsAdPlayer] Fired tracking pixel: ".concat(trackingUrl));
612
769
  } catch (error) {
@@ -1245,7 +1402,9 @@ function createHlsAdPlayer(contentVideo, options) {
1245
1402
  if (!adPlaying) return;
1246
1403
  console.error("[HlsAdPlayer] Ad video error:", e);
1247
1404
  if (currentAd) {
1248
- fireTrackingPixels(currentAd.trackingUrls.error);
1405
+ fireTrackingPixels(currentAd.trackingUrls.error, {
1406
+ errorCode: toVastMediaErrorCode(adVideoElement === null || adVideoElement === void 0 ? void 0 : adVideoElement.error)
1407
+ });
1249
1408
  }
1250
1409
  if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1251
1410
  return;
@@ -1357,9 +1516,9 @@ function createHlsAdPlayer(contentVideo, options) {
1357
1516
  delete contentVideo.dataset.stormcloudAdPlaying;
1358
1517
  }
1359
1518
  }
1360
- function resetQuartileTracking() {
1519
+ function resetQuartileTracking(preserveImpression) {
1361
1520
  trackingFired = {
1362
- impression: false,
1521
+ impression: preserveImpression ? trackingFired.impression : false,
1363
1522
  start: false,
1364
1523
  firstQuartile: false,
1365
1524
  midpoint: false,
@@ -1367,27 +1526,6 @@ function createHlsAdPlayer(contentVideo, options) {
1367
1526
  complete: false
1368
1527
  };
1369
1528
  }
1370
- function markCreativeRendered(reason) {
1371
- if (!currentAd || trackingFired.impression) return;
1372
- trackingFired.impression = true;
1373
- fireTrackingPixels(currentAd.trackingUrls.impression);
1374
- console.log("[HlsAdPlayer] Impression (pod ".concat(podIndex + 1, "/").concat(podAds.length || 1, ", reason: ").concat(reason, "): ").concat(currentAd.title));
1375
- emit("ad_impression", {
1376
- adId: currentAd.id,
1377
- title: currentAd.title,
1378
- durationSeconds: currentAd.duration,
1379
- mediaUrl: currentAdMediaUrl,
1380
- podIndex: podIndex,
1381
- podSize: podAds.length || 1,
1382
- reason: reason
1383
- });
1384
- }
1385
- function canDetectBlackFrames() {
1386
- if (!adVideoElement) return false;
1387
- if (requiresMediaPipelineResetAfterAds()) return false;
1388
- if (isRvfcSupported(adVideoElement)) return true;
1389
- return getDecodedVideoFrameCount(adVideoElement) !== void 0;
1390
- }
1391
1529
  function isRvfcSupported(video) {
1392
1530
  return typeof video.requestVideoFrameCallback === "function";
1393
1531
  }
@@ -1450,7 +1588,7 @@ function createHlsAdPlayer(contentVideo, options) {
1450
1588
  if (!mediaFile) {
1451
1589
  throw new Error("No media file available for ad");
1452
1590
  }
1453
- currentAdMediaUrl = mediaFile.url;
1591
+ currentAdMediaFile = mediaFile;
1454
1592
  var isHlsAd = isHlsMediaFile(mediaFile);
1455
1593
  console.log("[HlsAdPlayer] Loading ".concat(isHlsAd ? "HLS" : "progressive", " ad (pod ").concat(podIndex + 1, "/").concat(podAds.length || 1, ") from: ").concat(mediaFile.url));
1456
1594
  if (isHlsAd && import_hls.default.isSupported()) {
@@ -1494,9 +1632,11 @@ function createHlsAdPlayer(contentVideo, options) {
1494
1632
  }
1495
1633
  podIndex++;
1496
1634
  currentAd = podAds[podIndex];
1497
- currentAdMediaUrl = void 0;
1498
- resetQuartileTracking();
1635
+ currentAdMediaFile = void 0;
1636
+ resetQuartileTracking(false);
1499
1637
  if (currentAd) {
1638
+ fireTrackingPixels(currentAd.trackingUrls.impression);
1639
+ trackingFired.impression = true;
1500
1640
  console.log("[HlsAdPlayer] Advancing to next pod ad (".concat(podIndex + 1, "/").concat(podAds.length, "): ").concat(currentAd.title, ", duration: ").concat(currentAd.duration, "s"));
1501
1641
  }
1502
1642
  clearStallWatchdog();
@@ -1535,7 +1675,9 @@ function createHlsAdPlayer(contentVideo, options) {
1535
1675
  console.warn("[HlsAdPlayer] Ad playback stalled (no progress) - recovering to avoid a blank frame");
1536
1676
  clearStallWatchdog();
1537
1677
  if (currentAd) {
1538
- fireTrackingPixels(currentAd.trackingUrls.error);
1678
+ fireTrackingPixels(currentAd.trackingUrls.error, {
1679
+ errorCode: VAST_ERROR_MEDIA_DISPLAY
1680
+ });
1539
1681
  }
1540
1682
  if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1541
1683
  return;
@@ -1591,7 +1733,6 @@ function createHlsAdPlayer(contentVideo, options) {
1591
1733
  if (!adPlaying) return;
1592
1734
  sawDecodedVideoFrame = true;
1593
1735
  markRvfcReliable();
1594
- markCreativeRendered("first_presented_frame");
1595
1736
  };
1596
1737
  try {
1597
1738
  videoFrameCallbackHandle = rvfc.call(adVideoElement, onPresentedFrame);
@@ -1604,7 +1745,9 @@ function createHlsAdPlayer(contentVideo, options) {
1604
1745
  console.warn("[HlsAdPlayer] Ad audio is advancing but no video frames decoded (black screen) - skipping this creative");
1605
1746
  clearStallWatchdog();
1606
1747
  if (currentAd) {
1607
- fireTrackingPixels(currentAd.trackingUrls.error);
1748
+ fireTrackingPixels(currentAd.trackingUrls.error, {
1749
+ errorCode: VAST_ERROR_MEDIA_DISPLAY
1750
+ });
1608
1751
  }
1609
1752
  if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1610
1753
  return;
@@ -1626,7 +1769,6 @@ function createHlsAdPlayer(contentVideo, options) {
1626
1769
  if (decodedFrames !== void 0 && decodedFrames > 0) {
1627
1770
  sawDecodedVideoFrame = true;
1628
1771
  markFrameCounterReliable();
1629
- markCreativeRendered("decoded_frames");
1630
1772
  } else if (adVideoElement.currentTime >= BLACKFRAME_MIN_PLAYBACK_S) {
1631
1773
  var timeAdvancing = adVideoElement.currentTime > lastAdProgressPosition + 0.05;
1632
1774
  if (isRvfcSupported(adVideoElement) && timeAdvancing && isRvfcReliable()) {
@@ -1639,9 +1781,6 @@ function createHlsAdPlayer(contentVideo, options) {
1639
1781
  }
1640
1782
  }
1641
1783
  }
1642
- if (!trackingFired.impression && !adVideoElement.paused && adVideoElement.currentTime >= BLACKFRAME_MIN_PLAYBACK_S && (sawDecodedVideoFrame || !canDetectBlackFrames())) {
1643
- markCreativeRendered(sawDecodedVideoFrame ? "decoded_frames" : "sustained_playback");
1644
- }
1645
1784
  if (adVideoElement.currentTime > lastAdProgressPosition + 0.05) {
1646
1785
  noteAdProgress();
1647
1786
  return;
@@ -1742,7 +1881,6 @@ function createHlsAdPlayer(contentVideo, options) {
1742
1881
  ,
1743
1882
  6
1744
1883
  ]);
1745
- sessionId = generateSessionId();
1746
1884
  ads = [];
1747
1885
  if (!preloadedAds.has(vastTagUrl)) return [
1748
1886
  3,
@@ -1780,9 +1918,12 @@ function createHlsAdPlayer(contentVideo, options) {
1780
1918
  podAds = ads;
1781
1919
  podIndex = 0;
1782
1920
  currentAd = ads[0];
1783
- currentAdMediaUrl = void 0;
1784
- resetQuartileTracking();
1921
+ currentAdMediaFile = void 0;
1785
1922
  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"));
1923
+ if (currentAd) {
1924
+ fireTrackingPixels(currentAd.trackingUrls.impression);
1925
+ trackingFired.impression = true;
1926
+ }
1786
1927
  return [
1787
1928
  2,
1788
1929
  Promise.resolve()
@@ -1822,7 +1963,7 @@ function createHlsAdPlayer(contentVideo, options) {
1822
1963
  contentVideo[AD_VIDEO_PROP] = adVideoElement;
1823
1964
  }
1824
1965
  setupAdEventListeners();
1825
- resetQuartileTracking();
1966
+ resetQuartileTracking(true);
1826
1967
  contentVolume = contentVideo.volume;
1827
1968
  originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1828
1969
  if (!(options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds)) {
@@ -1912,7 +2053,7 @@ function createHlsAdPlayer(contentVideo, options) {
1912
2053
  }
1913
2054
  }
1914
2055
  currentAd = void 0;
1915
- currentAdMediaUrl = void 0;
2056
+ currentAdMediaFile = void 0;
1916
2057
  podAds = [];
1917
2058
  podIndex = 0;
1918
2059
  return [
@@ -1953,6 +2094,7 @@ function createHlsAdPlayer(contentVideo, options) {
1953
2094
  teardownAdEventListeners();
1954
2095
  releaseAdDecoder();
1955
2096
  currentAd = void 0;
2097
+ currentAdMediaFile = void 0;
1956
2098
  podAds = [];
1957
2099
  podIndex = 0;
1958
2100
  listeners.clear();
@@ -3246,19 +3388,8 @@ function buildPlayerMetricEvent() {
3246
3388
  }).apply(this, arguments);
3247
3389
  }
3248
3390
  function publishTracking(licenseKey, channel, body) {
3249
- var debug = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : false;
3250
3391
  ensureMQTTClient();
3251
- var topic = buildPlayerTopic(licenseKey, channel);
3252
- var published = publishMQTT(topic, body);
3253
- if (debug) {
3254
- console.log("[StormcloudVideoPlayer] publishTracking:", JSON.stringify({
3255
- licenseKey: licenseKey,
3256
- channel: channel,
3257
- topic: topic,
3258
- body: body,
3259
- published: published
3260
- }, null, 2));
3261
- }
3392
+ publishMQTT(buildPlayerTopic(licenseKey, channel), body);
3262
3393
  }
3263
3394
  function sendInitialTracking(_0) {
3264
3395
  return _async_to_generator(function(licenseKey) {
@@ -3292,7 +3423,7 @@ function sendInitialTracking(_0) {
3292
3423
  events: [
3293
3424
  metricEvent
3294
3425
  ]
3295
- }, !!context.debugAdTiming);
3426
+ });
3296
3427
  return [
3297
3428
  3,
3298
3429
  4
@@ -3402,7 +3533,7 @@ function sendAdLoadedTracking(_0, _1) {
3402
3533
  }
3403
3534
  function sendAdImpressionTracking(_0, _1) {
3404
3535
  return _async_to_generator(function(licenseKey, adImpressionInfo) {
3405
- var context, _adImpressionInfo_adUrl, metricEvent, error;
3536
+ var context, metricEvent, error;
3406
3537
  var _arguments = arguments;
3407
3538
  return _ts_generator(this, function(_state) {
3408
3539
  switch(_state.label){
@@ -3427,18 +3558,17 @@ function sendAdImpressionTracking(_0, _1) {
3427
3558
  ];
3428
3559
  case 2:
3429
3560
  metricEvent = _state.sent();
3430
- publishTracking(licenseKey, "heartbeat", metricEvent, !!context.debugAdTiming);
3561
+ publishTracking(licenseKey, "heartbeat", metricEvent);
3431
3562
  publishTracking(licenseKey, "impressions", {
3432
3563
  events: [
3433
3564
  {
3434
- event_id: createUuid(),
3435
3565
  player_id: metricEvent.player_id,
3436
3566
  ad_played_count: 1,
3437
- ad_url: (_adImpressionInfo_adUrl = adImpressionInfo.adUrl) !== null && _adImpressionInfo_adUrl !== void 0 ? _adImpressionInfo_adUrl : adImpressionInfo.adId,
3567
+ ad_url: adImpressionInfo.adUrl,
3438
3568
  capture_at: adImpressionInfo.timestamp
3439
3569
  }
3440
3570
  ]
3441
- }, !!context.debugAdTiming);
3571
+ });
3442
3572
  return [
3443
3573
  3,
3444
3574
  4
@@ -3483,7 +3613,7 @@ function sendHeartbeat(_0) {
3483
3613
  ];
3484
3614
  case 2:
3485
3615
  heartbeatData = _state.sent();
3486
- publishTracking(licenseKey, "heartbeat", heartbeatData, !!context.debugAdTiming);
3616
+ publishTracking(licenseKey, "heartbeat", heartbeatData);
3487
3617
  return [
3488
3618
  3,
3489
3619
  4
@@ -7277,22 +7407,27 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7277
7407
  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 : "?"));
7278
7408
  }
7279
7409
  });
7280
- adPlayer.on("ad_impression", function(payload) {
7281
- var impressionInfo = {
7410
+ adPlayer.on("all_ads_completed", function() {
7411
+ sendAdImpressionTracking(_this.host.config.licenseKey, {
7282
7412
  source: "hls",
7283
7413
  adIndex: _this.timing.currentAdIndex,
7284
7414
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
7285
- };
7286
- if (payload === null || payload === void 0 ? void 0 : payload.adId) impressionInfo.adId = payload.adId;
7287
- if (payload === null || payload === void 0 ? void 0 : payload.mediaUrl) impressionInfo.adUrl = payload.mediaUrl;
7288
- if ((payload === null || payload === void 0 ? void 0 : payload.durationSeconds) != null) {
7289
- impressionInfo.durationSeconds = payload.durationSeconds;
7415
+ }, _this.analyticsContext).catch(function() {});
7416
+ _this.timing.recordPlayedAdDuration(_this.host.getAdPlayer());
7417
+ var remaining = _this.timing.getRemainingAdMs();
7418
+ _this.timing.consecutiveFailures = 0;
7419
+ if (_this.debug) {
7420
+ console.log("[StormcloudVideoPlayer] all_ads_completed event received - remaining=".concat(remaining, "ms, queued ads=").concat(_this.adRequestQueue.length), _this.adRequestQueue.length > 0 ? {
7421
+ queuedUrls: _to_consumable_array(_this.adRequestQueue)
7422
+ } : {});
7290
7423
  }
7291
- sendAdImpressionTracking(_this.host.config.licenseKey, impressionInfo, _this.analyticsContext).catch(function(error) {
7292
- if (_this.debug) {
7293
- console.warn("[AdBreakOrchestrator] Failed to send ad impression tracking:", error);
7424
+ if (_this.inAdBreak) {
7425
+ if (_this.timing.hasTimeToStartAnotherAd()) {
7426
+ _this.tryNextAvailableAdWithRateLimit();
7427
+ } else {
7428
+ _this.handleAdPodComplete();
7294
7429
  }
7295
- });
7430
+ }
7296
7431
  });
7297
7432
  adPlayer.on("ad_error", function(errorPayload) {
7298
7433
  var errorMessage = "Ad playback failed";
@@ -7335,6 +7470,11 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7335
7470
  }
7336
7471
  });
7337
7472
  adPlayer.on("content_resume", function() {
7473
+ sendAdImpressionTracking(_this.host.config.licenseKey, {
7474
+ source: "hls",
7475
+ adIndex: _this.timing.currentAdIndex,
7476
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
7477
+ }, _this.analyticsContext).catch(function() {});
7338
7478
  if (!_this.host.video.muted) {
7339
7479
  _this.host.video.muted = true;
7340
7480
  if (_this.debug) {