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
@@ -1,4 +1,4 @@
1
- import { a as StormcloudVideoPlayerConfig } from '../types-DpbgEvSH.cjs';
1
+ import { a as StormcloudVideoPlayerConfig } from '../types-cTqIKw_D.cjs';
2
2
 
3
3
  declare class StormcloudVideoPlayer {
4
4
  private readonly video;
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/ubuntu24-new/Dev/stormcloud-vp/lib/player/playerTypes.cjs"],"names":["__defProp","Object","defineProperty"],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mEACIA,QAAYC,EAAAA,IAAAA,KAAAA;oBAAAA,KAAAA,CAAAA,CAAAA,GAAAA,IAAAA;+BAAAA,GAAOC,CAAAA,CAAAA,IAAAA","sourcesContent":["\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/player/playerTypes.ts\nvar playerTypes_exports = {};\nmodule.exports = __toCommonJS(playerTypes_exports);\n"]}
1
+ {"version":3,"sources":["/home/ubuntu24-new/Dev/stormcloud-vp/lib/player/playerTypes.cjs"],"names":["__defProp","Object","defineProperty","__getOwnPropDesc","getOwnPropertyDescriptor","__getOwnPropNames","__hasOwnProp","prototype","hasOwnProperty","__copyProps","to","from","except"],"mappings":"AAAA;;;;;;;;;;;;;;;mEACIA,QAAYC,EAAAA,IAAAA,KAAAA;oBAAAA,KAAAA,KAAAA,IAAAA;+BAAAA,GAAOC,CAAAA,CAAAA,IAAAA;;oBAAAA,MAAc,MAAA,CAAA,CAAA,OAAA,iBAAA,MAAA,IAAA,KAAA,KAAA,UAAA;gBAAA;;;;;;;;;;;;;;;;;MACrC,EAAIC,EAAAA,QAAAA,CAAAA,OAAAA,qCAAAA,SAAAA,EAAmBF,GAAAA,MAAOG,YAAAA,OAAAA,KAAwB,IAAA,YAAA;cAClDC,kCAAAA,2BAAAA;;;;;;;gBACAC,IAAAA,CAAAA,OAAAA,CAAeL,KAAAA,EAAOM,EAAAA,CAAAA,IAAAA,EAAS,CAACC,KAAAA,QAAAA,CAAc,OAC9CC,UAAc,IAAA,KAAA;oBAAA,KAAA,CAAA,CAAA,GAACC,IAAD;+BAACA,GAAIC,CAAAA,CAAAA,IAAMC","sourcesContent":["\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/player/playerTypes.ts\nvar playerTypes_exports = {};\nmodule.exports = __toCommonJS(playerTypes_exports);\n"]}
@@ -1,4 +1,4 @@
1
- import { S as Scte35Marker } from '../types-DpbgEvSH.cjs';
1
+ import { S as Scte35Marker } from '../types-cTqIKw_D.cjs';
2
2
 
3
3
  type Scte35CueSource = "manifest" | "id3" | "ts";
4
4
  type Scte35CueReadiness = "early" | "playback";
@@ -567,15 +567,147 @@ function logBrowserInfo() {
567
567
  userAgent: navigator.userAgent
568
568
  }));
569
569
  }
570
+ // src/utils/vastTrackingMacros.ts
571
+ var VAST_MACRO_PATTERN = /\[([A-Z][A-Z0-9_]*)\]/g;
572
+ var CACHEBUSTING_ALIASES = /\[CACHEBUSTER\]|\[cachebuster\]|\[timestamp\]|\[random\]|\[INSERT_RANDOM_NUMBER\]|%%CACHEBUSTER%%|%%CACHEBUST%%|\$\{CACHEBUSTER\}|\$\{CACHEBUSTING\}|\{cachebuster\}|\{random\}/g;
573
+ var KNOWN_VAST_MACROS = /* @__PURE__ */ new Set([
574
+ "ADCATEGORIES",
575
+ "ADCOUNT",
576
+ "ADPLAYHEAD",
577
+ "ADSERVINGID",
578
+ "ADTYPE",
579
+ "APIFRAMEWORKS",
580
+ "APPBUNDLE",
581
+ "ASSETURI",
582
+ "BLOCKEDADCATEGORIES",
583
+ "BREAKMAXADLENGTH",
584
+ "BREAKMAXADS",
585
+ "BREAKMAXDURATION",
586
+ "BREAKMINADLENGTH",
587
+ "BREAKPOSITION",
588
+ "CACHEBUSTING",
589
+ "CLICKPOS",
590
+ "CLICKTYPE",
591
+ "CLIENTUA",
592
+ "CONTENTID",
593
+ "CONTENTPLAYHEAD",
594
+ "CONTENTURI",
595
+ "DEVICEIP",
596
+ "DEVICEUA",
597
+ "DOMAIN",
598
+ "ERRORCODE",
599
+ "EXTENSIONS",
600
+ "GDPRCONSENT",
601
+ "IFA",
602
+ "IFATYPE",
603
+ "INVENTORYSTATE",
604
+ "LATLONG",
605
+ "LIMITADTRACKING",
606
+ "MEDIAMIME",
607
+ "MEDIAPLAYHEAD",
608
+ "OMIDPARTNER",
609
+ "PAGEURL",
610
+ "PLACEMENTTYPE",
611
+ "PLAYERCAPABILITIES",
612
+ "PLAYERSIZE",
613
+ "PLAYERSTATE",
614
+ "PODSEQUENCE",
615
+ "REGULATIONS",
616
+ "SERVERSIDE",
617
+ "SERVERUA",
618
+ "TIMESTAMP",
619
+ "TRANSACTIONID",
620
+ "UNIVERSALADID",
621
+ "VASTVERSIONS",
622
+ "VERIFICATIONVENDORS"
623
+ ]);
624
+ function generateCachebuster() {
625
+ return String(Math.floor(Math.random() * 9e7) + 1e7);
626
+ }
627
+ function formatPlayhead(seconds) {
628
+ if (seconds == null || !Number.isFinite(seconds) || seconds < 0) {
629
+ return void 0;
630
+ }
631
+ var total = Math.floor(seconds);
632
+ var hh = String(Math.floor(total / 3600)).padStart(2, "0");
633
+ var mm = String(Math.floor(total % 3600 / 60)).padStart(2, "0");
634
+ var ss = String(total % 60).padStart(2, "0");
635
+ var ms = String(Math.floor((seconds - total) * 1e3)).padStart(3, "0");
636
+ return "".concat(hh, ":").concat(mm, ":").concat(ss, ".").concat(ms);
637
+ }
638
+ function resolveMacroValues(ctx) {
639
+ var values = /* @__PURE__ */ new Map();
640
+ var set = function set(key, value) {
641
+ if (value != null && value !== "") values.set(key, value);
642
+ };
643
+ var adPlayhead = formatPlayhead(ctx.adPlayheadSeconds);
644
+ set("ADPLAYHEAD", adPlayhead);
645
+ set("MEDIAPLAYHEAD", adPlayhead);
646
+ set("CONTENTPLAYHEAD", formatPlayhead(ctx.contentPlayheadSeconds));
647
+ set("ASSETURI", ctx.assetUri);
648
+ set("MEDIAMIME", ctx.mediaMime);
649
+ set("TIMESTAMP", (/* @__PURE__ */ new Date()).toISOString());
650
+ set("SERVERSIDE", "0");
651
+ if (ctx.errorCode != null && ctx.errorCode !== "") {
652
+ set("ERRORCODE", String(ctx.errorCode));
653
+ }
654
+ if (ctx.playerWidth != null && ctx.playerHeight != null) {
655
+ set("PLAYERSIZE", "".concat(Math.round(ctx.playerWidth), ",").concat(Math.round(ctx.playerHeight)));
656
+ }
657
+ set("IFA", ctx.deviceId);
658
+ set("IFATYPE", ctx.deviceIdType);
659
+ if (ctx.limitAdTracking != null) {
660
+ set("LIMITADTRACKING", ctx.limitAdTracking ? "1" : "0");
661
+ }
662
+ set("PAGEURL", ctx.pageUrl);
663
+ if (ctx.pageUrl) {
664
+ try {
665
+ set("DOMAIN", new URL(ctx.pageUrl).hostname);
666
+ } catch (unused) {}
667
+ }
668
+ set("CLIENTUA", ctx.clientUa);
669
+ set("DEVICEUA", ctx.clientUa);
670
+ if (ctx.podSequence != null) {
671
+ set("PODSEQUENCE", String(ctx.podSequence));
672
+ }
673
+ return values;
674
+ }
675
+ function substituteVastTrackingMacros(url) {
676
+ var ctx = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
677
+ if (!url) return url;
678
+ var values = resolveMacroValues(ctx);
679
+ return url.replace(CACHEBUSTING_ALIASES, function() {
680
+ return generateCachebuster();
681
+ }).replace(VAST_MACRO_PATTERN, function(match, name) {
682
+ if (name === "CACHEBUSTING") return generateCachebuster();
683
+ var value = values.get(name);
684
+ if (value != null) return encodeURIComponent(value);
685
+ return KNOWN_VAST_MACROS.has(name) ? "" : match;
686
+ });
687
+ }
570
688
  // src/sdk/hlsAdPlayer.ts
571
689
  var MAX_VAST_WRAPPER_DEPTH = 5;
690
+ var BEACON_TIMEOUT_MS = 3e4;
691
+ var inFlightBeacons = /* @__PURE__ */ new Set();
692
+ var VAST_ERROR_MEDIA_DISPLAY = 405;
693
+ function toVastMediaErrorCode(error) {
694
+ switch(error === null || error === void 0 ? void 0 : error.code){
695
+ case 1:
696
+ return 400;
697
+ case 2:
698
+ return 401;
699
+ case 4:
700
+ return 403;
701
+ default:
702
+ return VAST_ERROR_MEDIA_DISPLAY;
703
+ }
704
+ }
572
705
  function createHlsAdPlayer(contentVideo, options) {
573
706
  var _contentVideo_AD_VIDEO_PROP, _contentVideo_AD_CONTAINER_PROP;
574
707
  var adPlaying = false;
575
708
  var originalMutedState = false;
576
709
  var originalVolume = Math.max(0, Math.min(1, contentVideo.volume || 1));
577
710
  var listeners = /* @__PURE__ */ new Map();
578
- var licenseKey = options === null || options === void 0 ? void 0 : options.licenseKey;
579
711
  var mainHlsInstance = options === null || options === void 0 ? void 0 : options.mainHlsInstance;
580
712
  var AD_CONTAINER_PROP = "__stormcloudAdContainer";
581
713
  var AD_VIDEO_PROP = "__stormcloudAdVideo";
@@ -586,10 +718,9 @@ function createHlsAdPlayer(contentVideo, options) {
586
718
  var adContainerEl = (_contentVideo_AD_CONTAINER_PROP = contentVideo[AD_CONTAINER_PROP]) !== null && _contentVideo_AD_CONTAINER_PROP !== void 0 ? _contentVideo_AD_CONTAINER_PROP : void 0;
587
719
  var adEventHandlers = [];
588
720
  var currentAd;
589
- var currentAdMediaUrl;
721
+ var currentAdMediaFile;
590
722
  var podAds = [];
591
723
  var podIndex = 0;
592
- var sessionId;
593
724
  var preloadedAds = /* @__PURE__ */ new Map();
594
725
  var preloadingAds = /* @__PURE__ */ new Map();
595
726
  var destroyed = false;
@@ -639,21 +770,47 @@ function createHlsAdPlayer(contentVideo, options) {
639
770
  }
640
771
  }
641
772
  }
642
- function generateSessionId() {
643
- return "session-".concat(Date.now(), "-").concat(Math.random().toString(36).substr(2, 9));
773
+ function buildTrackingMacroContext(errorCode) {
774
+ var context = {
775
+ adPlayheadSeconds: adVideoElement === null || adVideoElement === void 0 ? void 0 : adVideoElement.currentTime,
776
+ contentPlayheadSeconds: contentVideo.currentTime,
777
+ assetUri: currentAdMediaFile === null || currentAdMediaFile === void 0 ? void 0 : currentAdMediaFile.url,
778
+ mediaMime: currentAdMediaFile === null || currentAdMediaFile === void 0 ? void 0 : currentAdMediaFile.type,
779
+ playerWidth: (adVideoElement === null || adVideoElement === void 0 ? void 0 : adVideoElement.clientWidth) || (adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.clientWidth),
780
+ playerHeight: (adVideoElement === null || adVideoElement === void 0 ? void 0 : adVideoElement.clientHeight) || (adContainerEl === null || adContainerEl === void 0 ? void 0 : adContainerEl.clientHeight)
781
+ };
782
+ if (errorCode != null) {
783
+ context.errorCode = errorCode;
784
+ }
785
+ if (typeof navigator !== "undefined" && navigator.userAgent) {
786
+ context.clientUa = navigator.userAgent;
787
+ }
788
+ if (typeof location !== "undefined" && location.href) {
789
+ context.pageUrl = location.href;
790
+ }
791
+ if (podAds.length > 0) {
792
+ context.podSequence = podIndex + 1;
793
+ }
794
+ return context;
644
795
  }
645
- function fireTrackingPixels(urls) {
796
+ function fireTrackingPixels(urls, options2) {
646
797
  if (!urls || urls.length === 0) return;
798
+ var macroContext = buildTrackingMacroContext(options2 === null || options2 === void 0 ? void 0 : options2.errorCode);
647
799
  urls.forEach(function(url) {
648
800
  try {
649
- var trackingUrl = url;
650
- if (sessionId) {
651
- trackingUrl = "".concat(trackingUrl).concat(trackingUrl.includes("?") ? "&" : "?", "session_id=").concat(sessionId);
652
- }
653
- if (licenseKey) {
654
- trackingUrl = "".concat(trackingUrl).concat(trackingUrl.includes("?") ? "&" : "?", "license_key=").concat(licenseKey);
655
- }
801
+ var trackingUrl = substituteVastTrackingMacros(url, macroContext);
656
802
  var img = new Image(1, 1);
803
+ inFlightBeacons.add(img);
804
+ var timeoutId;
805
+ var release = function release() {
806
+ if (timeoutId !== void 0) clearTimeout(timeoutId);
807
+ img.onload = null;
808
+ img.onerror = null;
809
+ inFlightBeacons.delete(img);
810
+ };
811
+ img.onload = release;
812
+ img.onerror = release;
813
+ timeoutId = setTimeout(release, BEACON_TIMEOUT_MS);
657
814
  img.src = trackingUrl;
658
815
  console.log("[HlsAdPlayer] Fired tracking pixel: ".concat(trackingUrl));
659
816
  } catch (error) {
@@ -1292,7 +1449,9 @@ function createHlsAdPlayer(contentVideo, options) {
1292
1449
  if (!adPlaying) return;
1293
1450
  console.error("[HlsAdPlayer] Ad video error:", e);
1294
1451
  if (currentAd) {
1295
- fireTrackingPixels(currentAd.trackingUrls.error);
1452
+ fireTrackingPixels(currentAd.trackingUrls.error, {
1453
+ errorCode: toVastMediaErrorCode(adVideoElement === null || adVideoElement === void 0 ? void 0 : adVideoElement.error)
1454
+ });
1296
1455
  }
1297
1456
  if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1298
1457
  return;
@@ -1404,9 +1563,9 @@ function createHlsAdPlayer(contentVideo, options) {
1404
1563
  delete contentVideo.dataset.stormcloudAdPlaying;
1405
1564
  }
1406
1565
  }
1407
- function resetQuartileTracking() {
1566
+ function resetQuartileTracking(preserveImpression) {
1408
1567
  trackingFired = {
1409
- impression: false,
1568
+ impression: preserveImpression ? trackingFired.impression : false,
1410
1569
  start: false,
1411
1570
  firstQuartile: false,
1412
1571
  midpoint: false,
@@ -1414,27 +1573,6 @@ function createHlsAdPlayer(contentVideo, options) {
1414
1573
  complete: false
1415
1574
  };
1416
1575
  }
1417
- function markCreativeRendered(reason) {
1418
- if (!currentAd || trackingFired.impression) return;
1419
- trackingFired.impression = true;
1420
- fireTrackingPixels(currentAd.trackingUrls.impression);
1421
- console.log("[HlsAdPlayer] Impression (pod ".concat(podIndex + 1, "/").concat(podAds.length || 1, ", reason: ").concat(reason, "): ").concat(currentAd.title));
1422
- emit("ad_impression", {
1423
- adId: currentAd.id,
1424
- title: currentAd.title,
1425
- durationSeconds: currentAd.duration,
1426
- mediaUrl: currentAdMediaUrl,
1427
- podIndex: podIndex,
1428
- podSize: podAds.length || 1,
1429
- reason: reason
1430
- });
1431
- }
1432
- function canDetectBlackFrames() {
1433
- if (!adVideoElement) return false;
1434
- if (requiresMediaPipelineResetAfterAds()) return false;
1435
- if (isRvfcSupported(adVideoElement)) return true;
1436
- return getDecodedVideoFrameCount(adVideoElement) !== void 0;
1437
- }
1438
1576
  function isRvfcSupported(video) {
1439
1577
  return typeof video.requestVideoFrameCallback === "function";
1440
1578
  }
@@ -1497,7 +1635,7 @@ function createHlsAdPlayer(contentVideo, options) {
1497
1635
  if (!mediaFile) {
1498
1636
  throw new Error("No media file available for ad");
1499
1637
  }
1500
- currentAdMediaUrl = mediaFile.url;
1638
+ currentAdMediaFile = mediaFile;
1501
1639
  var isHlsAd = isHlsMediaFile(mediaFile);
1502
1640
  console.log("[HlsAdPlayer] Loading ".concat(isHlsAd ? "HLS" : "progressive", " ad (pod ").concat(podIndex + 1, "/").concat(podAds.length || 1, ") from: ").concat(mediaFile.url));
1503
1641
  if (isHlsAd && import_hls.default.isSupported()) {
@@ -1541,9 +1679,11 @@ function createHlsAdPlayer(contentVideo, options) {
1541
1679
  }
1542
1680
  podIndex++;
1543
1681
  currentAd = podAds[podIndex];
1544
- currentAdMediaUrl = void 0;
1545
- resetQuartileTracking();
1682
+ currentAdMediaFile = void 0;
1683
+ resetQuartileTracking(false);
1546
1684
  if (currentAd) {
1685
+ fireTrackingPixels(currentAd.trackingUrls.impression);
1686
+ trackingFired.impression = true;
1547
1687
  console.log("[HlsAdPlayer] Advancing to next pod ad (".concat(podIndex + 1, "/").concat(podAds.length, "): ").concat(currentAd.title, ", duration: ").concat(currentAd.duration, "s"));
1548
1688
  }
1549
1689
  clearStallWatchdog();
@@ -1582,7 +1722,9 @@ function createHlsAdPlayer(contentVideo, options) {
1582
1722
  console.warn("[HlsAdPlayer] Ad playback stalled (no progress) - recovering to avoid a blank frame");
1583
1723
  clearStallWatchdog();
1584
1724
  if (currentAd) {
1585
- fireTrackingPixels(currentAd.trackingUrls.error);
1725
+ fireTrackingPixels(currentAd.trackingUrls.error, {
1726
+ errorCode: VAST_ERROR_MEDIA_DISPLAY
1727
+ });
1586
1728
  }
1587
1729
  if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1588
1730
  return;
@@ -1638,7 +1780,6 @@ function createHlsAdPlayer(contentVideo, options) {
1638
1780
  if (!adPlaying) return;
1639
1781
  sawDecodedVideoFrame = true;
1640
1782
  markRvfcReliable();
1641
- markCreativeRendered("first_presented_frame");
1642
1783
  };
1643
1784
  try {
1644
1785
  videoFrameCallbackHandle = rvfc.call(adVideoElement, onPresentedFrame);
@@ -1651,7 +1792,9 @@ function createHlsAdPlayer(contentVideo, options) {
1651
1792
  console.warn("[HlsAdPlayer] Ad audio is advancing but no video frames decoded (black screen) - skipping this creative");
1652
1793
  clearStallWatchdog();
1653
1794
  if (currentAd) {
1654
- fireTrackingPixels(currentAd.trackingUrls.error);
1795
+ fireTrackingPixels(currentAd.trackingUrls.error, {
1796
+ errorCode: VAST_ERROR_MEDIA_DISPLAY
1797
+ });
1655
1798
  }
1656
1799
  if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1657
1800
  return;
@@ -1673,7 +1816,6 @@ function createHlsAdPlayer(contentVideo, options) {
1673
1816
  if (decodedFrames !== void 0 && decodedFrames > 0) {
1674
1817
  sawDecodedVideoFrame = true;
1675
1818
  markFrameCounterReliable();
1676
- markCreativeRendered("decoded_frames");
1677
1819
  } else if (adVideoElement.currentTime >= BLACKFRAME_MIN_PLAYBACK_S) {
1678
1820
  var timeAdvancing = adVideoElement.currentTime > lastAdProgressPosition + 0.05;
1679
1821
  if (isRvfcSupported(adVideoElement) && timeAdvancing && isRvfcReliable()) {
@@ -1686,9 +1828,6 @@ function createHlsAdPlayer(contentVideo, options) {
1686
1828
  }
1687
1829
  }
1688
1830
  }
1689
- if (!trackingFired.impression && !adVideoElement.paused && adVideoElement.currentTime >= BLACKFRAME_MIN_PLAYBACK_S && (sawDecodedVideoFrame || !canDetectBlackFrames())) {
1690
- markCreativeRendered(sawDecodedVideoFrame ? "decoded_frames" : "sustained_playback");
1691
- }
1692
1831
  if (adVideoElement.currentTime > lastAdProgressPosition + 0.05) {
1693
1832
  noteAdProgress();
1694
1833
  return;
@@ -1789,7 +1928,6 @@ function createHlsAdPlayer(contentVideo, options) {
1789
1928
  ,
1790
1929
  6
1791
1930
  ]);
1792
- sessionId = generateSessionId();
1793
1931
  ads = [];
1794
1932
  if (!preloadedAds.has(vastTagUrl)) return [
1795
1933
  3,
@@ -1827,9 +1965,12 @@ function createHlsAdPlayer(contentVideo, options) {
1827
1965
  podAds = ads;
1828
1966
  podIndex = 0;
1829
1967
  currentAd = ads[0];
1830
- currentAdMediaUrl = void 0;
1831
- resetQuartileTracking();
1968
+ currentAdMediaFile = void 0;
1832
1969
  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"));
1970
+ if (currentAd) {
1971
+ fireTrackingPixels(currentAd.trackingUrls.impression);
1972
+ trackingFired.impression = true;
1973
+ }
1833
1974
  return [
1834
1975
  2,
1835
1976
  Promise.resolve()
@@ -1869,7 +2010,7 @@ function createHlsAdPlayer(contentVideo, options) {
1869
2010
  contentVideo[AD_VIDEO_PROP] = adVideoElement;
1870
2011
  }
1871
2012
  setupAdEventListeners();
1872
- resetQuartileTracking();
2013
+ resetQuartileTracking(true);
1873
2014
  contentVolume = contentVideo.volume;
1874
2015
  originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
1875
2016
  if (!(options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds)) {
@@ -1959,7 +2100,7 @@ function createHlsAdPlayer(contentVideo, options) {
1959
2100
  }
1960
2101
  }
1961
2102
  currentAd = void 0;
1962
- currentAdMediaUrl = void 0;
2103
+ currentAdMediaFile = void 0;
1963
2104
  podAds = [];
1964
2105
  podIndex = 0;
1965
2106
  return [
@@ -2000,6 +2141,7 @@ function createHlsAdPlayer(contentVideo, options) {
2000
2141
  teardownAdEventListeners();
2001
2142
  releaseAdDecoder();
2002
2143
  currentAd = void 0;
2144
+ currentAdMediaFile = void 0;
2003
2145
  podAds = [];
2004
2146
  podIndex = 0;
2005
2147
  listeners.clear();
@@ -3293,19 +3435,8 @@ function buildPlayerMetricEvent() {
3293
3435
  }).apply(this, arguments);
3294
3436
  }
3295
3437
  function publishTracking(licenseKey, channel, body) {
3296
- var debug = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : false;
3297
3438
  ensureMQTTClient();
3298
- var topic = buildPlayerTopic(licenseKey, channel);
3299
- var published = publishMQTT(topic, body);
3300
- if (debug) {
3301
- console.log("[StormcloudVideoPlayer] publishTracking:", JSON.stringify({
3302
- licenseKey: licenseKey,
3303
- channel: channel,
3304
- topic: topic,
3305
- body: body,
3306
- published: published
3307
- }, null, 2));
3308
- }
3439
+ publishMQTT(buildPlayerTopic(licenseKey, channel), body);
3309
3440
  }
3310
3441
  function sendInitialTracking(_0) {
3311
3442
  return _async_to_generator(function(licenseKey) {
@@ -3339,7 +3470,7 @@ function sendInitialTracking(_0) {
3339
3470
  events: [
3340
3471
  metricEvent
3341
3472
  ]
3342
- }, !!context.debugAdTiming);
3473
+ });
3343
3474
  return [
3344
3475
  3,
3345
3476
  4
@@ -3449,7 +3580,7 @@ function sendAdLoadedTracking(_0, _1) {
3449
3580
  }
3450
3581
  function sendAdImpressionTracking(_0, _1) {
3451
3582
  return _async_to_generator(function(licenseKey, adImpressionInfo) {
3452
- var context, _adImpressionInfo_adUrl, metricEvent, error;
3583
+ var context, metricEvent, error;
3453
3584
  var _arguments = arguments;
3454
3585
  return _ts_generator(this, function(_state) {
3455
3586
  switch(_state.label){
@@ -3474,18 +3605,17 @@ function sendAdImpressionTracking(_0, _1) {
3474
3605
  ];
3475
3606
  case 2:
3476
3607
  metricEvent = _state.sent();
3477
- publishTracking(licenseKey, "heartbeat", metricEvent, !!context.debugAdTiming);
3608
+ publishTracking(licenseKey, "heartbeat", metricEvent);
3478
3609
  publishTracking(licenseKey, "impressions", {
3479
3610
  events: [
3480
3611
  {
3481
- event_id: createUuid(),
3482
3612
  player_id: metricEvent.player_id,
3483
3613
  ad_played_count: 1,
3484
- ad_url: (_adImpressionInfo_adUrl = adImpressionInfo.adUrl) !== null && _adImpressionInfo_adUrl !== void 0 ? _adImpressionInfo_adUrl : adImpressionInfo.adId,
3614
+ ad_url: adImpressionInfo.adUrl,
3485
3615
  capture_at: adImpressionInfo.timestamp
3486
3616
  }
3487
3617
  ]
3488
- }, !!context.debugAdTiming);
3618
+ });
3489
3619
  return [
3490
3620
  3,
3491
3621
  4
@@ -3530,7 +3660,7 @@ function sendHeartbeat(_0) {
3530
3660
  ];
3531
3661
  case 2:
3532
3662
  heartbeatData = _state.sent();
3533
- publishTracking(licenseKey, "heartbeat", heartbeatData, !!context.debugAdTiming);
3663
+ publishTracking(licenseKey, "heartbeat", heartbeatData);
3534
3664
  return [
3535
3665
  3,
3536
3666
  4
@@ -7324,22 +7454,27 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7324
7454
  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 : "?"));
7325
7455
  }
7326
7456
  });
7327
- adPlayer.on("ad_impression", function(payload) {
7328
- var impressionInfo = {
7457
+ adPlayer.on("all_ads_completed", function() {
7458
+ sendAdImpressionTracking(_this.host.config.licenseKey, {
7329
7459
  source: "hls",
7330
7460
  adIndex: _this.timing.currentAdIndex,
7331
7461
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
7332
- };
7333
- if (payload === null || payload === void 0 ? void 0 : payload.adId) impressionInfo.adId = payload.adId;
7334
- if (payload === null || payload === void 0 ? void 0 : payload.mediaUrl) impressionInfo.adUrl = payload.mediaUrl;
7335
- if ((payload === null || payload === void 0 ? void 0 : payload.durationSeconds) != null) {
7336
- impressionInfo.durationSeconds = payload.durationSeconds;
7462
+ }, _this.analyticsContext).catch(function() {});
7463
+ _this.timing.recordPlayedAdDuration(_this.host.getAdPlayer());
7464
+ var remaining = _this.timing.getRemainingAdMs();
7465
+ _this.timing.consecutiveFailures = 0;
7466
+ if (_this.debug) {
7467
+ console.log("[StormcloudVideoPlayer] all_ads_completed event received - remaining=".concat(remaining, "ms, queued ads=").concat(_this.adRequestQueue.length), _this.adRequestQueue.length > 0 ? {
7468
+ queuedUrls: _to_consumable_array(_this.adRequestQueue)
7469
+ } : {});
7337
7470
  }
7338
- sendAdImpressionTracking(_this.host.config.licenseKey, impressionInfo, _this.analyticsContext).catch(function(error) {
7339
- if (_this.debug) {
7340
- console.warn("[AdBreakOrchestrator] Failed to send ad impression tracking:", error);
7471
+ if (_this.inAdBreak) {
7472
+ if (_this.timing.hasTimeToStartAnotherAd()) {
7473
+ _this.tryNextAvailableAdWithRateLimit();
7474
+ } else {
7475
+ _this.handleAdPodComplete();
7341
7476
  }
7342
- });
7477
+ }
7343
7478
  });
7344
7479
  adPlayer.on("ad_error", function(errorPayload) {
7345
7480
  var errorMessage = "Ad playback failed";
@@ -7382,6 +7517,11 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7382
7517
  }
7383
7518
  });
7384
7519
  adPlayer.on("content_resume", function() {
7520
+ sendAdImpressionTracking(_this.host.config.licenseKey, {
7521
+ source: "hls",
7522
+ adIndex: _this.timing.currentAdIndex,
7523
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
7524
+ }, _this.analyticsContext).catch(function() {});
7385
7525
  if (!_this.host.video.muted) {
7386
7526
  _this.host.video.muted = true;
7387
7527
  if (_this.debug) {