stormcloud-video-player 0.8.59 → 0.8.60

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 (79) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +1369 -1369
  3. package/dist/stormcloud-vp.min.js +3 -1
  4. package/lib/Player.cjs +548 -0
  5. package/lib/Player.cjs.map +1 -0
  6. package/lib/Player.d.cts +146 -0
  7. package/lib/{index.js → StormcloudPlayer.cjs} +1108 -1877
  8. package/lib/StormcloudPlayer.cjs.map +1 -0
  9. package/lib/{index.d.ts → StormcloudPlayer.d.cts} +7 -400
  10. package/lib/index.cjs +979 -251
  11. package/lib/index.cjs.map +1 -1
  12. package/lib/index.d.cts +18 -4032
  13. package/lib/patterns.cjs +111 -0
  14. package/lib/patterns.cjs.map +1 -0
  15. package/lib/patterns.d.cts +14 -0
  16. package/lib/player/AdBreakOrchestrator.cjs +48 -14
  17. package/lib/player/AdBreakOrchestrator.cjs.map +1 -1
  18. package/lib/player/AdBreakOrchestrator.d.cts +3 -1
  19. package/lib/player/AdConfigManager.cjs +155 -17
  20. package/lib/player/AdConfigManager.cjs.map +1 -1
  21. package/lib/player/AdConfigManager.d.cts +1 -1
  22. package/lib/player/AdTimingService.cjs.map +1 -1
  23. package/lib/player/AdTimingService.d.cts +1 -1
  24. package/lib/player/HlsEngine.cjs.map +1 -1
  25. package/lib/player/HlsEngine.d.cts +1 -1
  26. package/lib/player/PlaceholderLayer.cjs.map +1 -1
  27. package/lib/player/PlayerControls.cjs.map +1 -1
  28. package/lib/player/PlayerControls.d.cts +1 -1
  29. package/lib/player/Scte35CueManager.cjs.map +1 -1
  30. package/lib/player/Scte35CueManager.d.cts +1 -1
  31. package/lib/player/Scte35Parser.cjs.map +1 -1
  32. package/lib/player/Scte35Parser.d.cts +1 -1
  33. package/lib/player/StormcloudVideoPlayer.cjs +979 -251
  34. package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
  35. package/lib/player/StormcloudVideoPlayer.d.cts +1 -1
  36. package/lib/player/playerTypes.cjs.map +1 -1
  37. package/lib/player/playerTypes.d.cts +1 -1
  38. package/lib/players/FilePlayer.cjs.map +1 -1
  39. package/lib/players/HlsPlayer.cjs +979 -251
  40. package/lib/players/HlsPlayer.cjs.map +1 -1
  41. package/lib/players/HlsPlayer.d.cts +1 -1
  42. package/lib/players/index.cjs +979 -251
  43. package/lib/players/index.cjs.map +1 -1
  44. package/lib/props.cjs +186 -0
  45. package/lib/props.cjs.map +1 -0
  46. package/lib/props.d.cts +62 -0
  47. package/lib/sdk/hlsAdPlayer.cjs +884 -234
  48. package/lib/sdk/hlsAdPlayer.cjs.map +1 -1
  49. package/lib/sdk/hlsAdPlayer.d.cts +1 -1
  50. package/lib/sdk/pal.cjs.map +1 -1
  51. package/lib/types.cjs +49 -0
  52. package/lib/types.cjs.map +1 -0
  53. package/lib/{types-52ASml2N.d.cts → types.d.cts} +47 -1
  54. package/lib/ui/StormcloudVideoPlayer.cjs +979 -251
  55. package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
  56. package/lib/ui/StormcloudVideoPlayer.d.cts +1 -1
  57. package/lib/utils/browserCompat.cjs.map +1 -1
  58. package/lib/utils/ctvVastSignals.cjs +155 -17
  59. package/lib/utils/ctvVastSignals.cjs.map +1 -1
  60. package/lib/utils/devUrl.cjs.map +1 -1
  61. package/lib/utils/polyfills.cjs.map +1 -1
  62. package/lib/utils/tracking.cjs +42 -14
  63. package/lib/utils/tracking.cjs.map +1 -1
  64. package/lib/utils/tracking.d.cts +1 -1
  65. package/lib/utils/trackingIngest.cjs.map +1 -1
  66. package/lib/utils/vastEnvironmentSignals.cjs +167 -17
  67. package/lib/utils/vastEnvironmentSignals.cjs.map +1 -1
  68. package/lib/utils/vastEnvironmentSignals.d.cts +12 -1
  69. package/lib/utils/vastMacros.cjs +26 -0
  70. package/lib/utils/vastMacros.cjs.map +1 -1
  71. package/lib/utils/vastTrackingMacros.cjs +5 -0
  72. package/lib/utils/vastTrackingMacros.cjs.map +1 -1
  73. package/lib/utils/vastTrackingMacros.d.cts +2 -0
  74. package/lib/utils.cjs +292 -0
  75. package/lib/utils.cjs.map +1 -0
  76. package/lib/utils.d.cts +17 -0
  77. package/package.json +91 -91
  78. package/rollup.config.js +90 -90
  79. package/lib/index.js.map +0 -1
@@ -602,6 +602,7 @@ var KNOWN_VAST_MACROS = /* @__PURE__ */ new Set([
602
602
  "PLAYERSIZE",
603
603
  "PLAYERSTATE",
604
604
  "PODSEQUENCE",
605
+ "REASON",
605
606
  "REGULATIONS",
606
607
  "SERVERSIDE",
607
608
  "SERVERUA",
@@ -660,6 +661,10 @@ function resolveMacroValues(ctx) {
660
661
  if (ctx.podSequence != null) {
661
662
  set("PODSEQUENCE", String(ctx.podSequence));
662
663
  }
664
+ set("ADSERVINGID", ctx.adServingId);
665
+ if (ctx.reason != null && ctx.reason !== "") {
666
+ set("REASON", String(ctx.reason));
667
+ }
663
668
  return values;
664
669
  }
665
670
  function substituteVastTrackingMacros(url) {
@@ -676,10 +681,72 @@ function substituteVastTrackingMacros(url) {
676
681
  });
677
682
  }
678
683
  // src/sdk/hlsAdPlayer.ts
684
+ var LINEAR_TRACKING_EVENTS = [
685
+ "creativeView",
686
+ "loaded",
687
+ "start",
688
+ "firstQuartile",
689
+ "midpoint",
690
+ "thirdQuartile",
691
+ "complete",
692
+ "mute",
693
+ "unmute",
694
+ "pause",
695
+ "resume",
696
+ "fullscreen",
697
+ "exitFullscreen",
698
+ "playerExpand",
699
+ "playerCollapse",
700
+ "notUsed"
701
+ ];
702
+ function textOf(el) {
703
+ var _el_textContent;
704
+ var value = el === null || el === void 0 ? void 0 : (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
705
+ return value ? value : void 0;
706
+ }
707
+ function parseVastTime(value) {
708
+ if (!value) return void 0;
709
+ var parts = value.trim().split(":");
710
+ if (parts.length !== 3) return void 0;
711
+ var _parts_map = _sliced_to_array(parts.map(function(p) {
712
+ return parseFloat(p);
713
+ }), 3), h = _parts_map[0], m = _parts_map[1], s = _parts_map[2];
714
+ if (![
715
+ h,
716
+ m,
717
+ s
718
+ ].every(function(n) {
719
+ return n !== void 0 && Number.isFinite(n);
720
+ })) {
721
+ return void 0;
722
+ }
723
+ return h * 3600 + m * 60 + s;
724
+ }
725
+ function parseProgressOffset(offset) {
726
+ if (!offset) return void 0;
727
+ var trimmed = offset.trim();
728
+ if (trimmed.endsWith("%")) {
729
+ var percent = parseFloat(trimmed);
730
+ return Number.isFinite(percent) ? {
731
+ offsetPercent: percent
732
+ } : void 0;
733
+ }
734
+ var seconds = parseVastTime(trimmed);
735
+ return seconds !== void 0 ? {
736
+ offsetSeconds: seconds
737
+ } : void 0;
738
+ }
679
739
  var MAX_VAST_WRAPPER_DEPTH = 5;
680
740
  var BEACON_TIMEOUT_MS = 3e4;
681
741
  var inFlightBeacons = /* @__PURE__ */ new Set();
682
742
  var VAST_ERROR_MEDIA_DISPLAY = 405;
743
+ var VAST_ERROR_WRAPPER_TIMEOUT = 301;
744
+ var VAST_ERROR_WRAPPER_LIMIT = 302;
745
+ var VAST_ERROR_WRAPPER_NO_ADS = 303;
746
+ var VAST_ERROR_NO_SUPPORTED_MEDIA = 403;
747
+ var VERIFICATION_NOT_SUPPORTED_REASON = 2;
748
+ var VIEWABLE_MIN_VISIBLE_RATIO = 0.5;
749
+ var VIEWABLE_MIN_CONTINUOUS_S = 2;
683
750
  function toVastMediaErrorCode(error) {
684
751
  switch(error === null || error === void 0 ? void 0 : error.code){
685
752
  case 1:
@@ -707,6 +774,7 @@ function createHlsAdPlayer(contentVideo, options) {
707
774
  var adHls;
708
775
  var adContainerEl = (_contentVideo_AD_CONTAINER_PROP = contentVideo[AD_CONTAINER_PROP]) !== null && _contentVideo_AD_CONTAINER_PROP !== void 0 ? _contentVideo_AD_CONTAINER_PROP : void 0;
709
776
  var adEventHandlers = [];
777
+ var containerHandlers = [];
710
778
  var currentAd;
711
779
  var currentAdMediaFile;
712
780
  var podAds = [];
@@ -724,14 +792,28 @@ function createHlsAdPlayer(contentVideo, options) {
724
792
  var sawDecodedVideoFrame = false;
725
793
  var videoFrameCallbackHandle;
726
794
  var pendingPlayPromise;
727
- var trackingFired = {
728
- impression: false,
729
- start: false,
730
- firstQuartile: false,
731
- midpoint: false,
732
- thirdQuartile: false,
733
- complete: false
734
- };
795
+ function createTrackingState() {
796
+ return {
797
+ impression: false,
798
+ loaded: false,
799
+ start: false,
800
+ firstQuartile: false,
801
+ midpoint: false,
802
+ thirdQuartile: false,
803
+ complete: false,
804
+ viewabilitySettled: false,
805
+ lastMuted: void 0,
806
+ progressFired: /* @__PURE__ */ new Set()
807
+ };
808
+ }
809
+ var trackingFired = createTrackingState();
810
+ var resolvedAds = /* @__PURE__ */ new Set();
811
+ var viewObserver;
812
+ var visibleRatio = 0;
813
+ var continuousVisibleS = 0;
814
+ var lastViewSampleTime;
815
+ var lastPlayerExpanded = false;
816
+ var documentHandlers = [];
735
817
  function emit(event, payload) {
736
818
  var set = listeners.get(event);
737
819
  if (!set) return;
@@ -760,7 +842,11 @@ function createHlsAdPlayer(contentVideo, options) {
760
842
  }
761
843
  }
762
844
  }
763
- function buildTrackingMacroContext(errorCode) {
845
+ function buildTrackingMacroContext() {
846
+ var options2 = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
847
+ var _options2_ad;
848
+ var errorCode = options2.errorCode, reason = options2.reason;
849
+ var ad = (_options2_ad = options2.ad) !== null && _options2_ad !== void 0 ? _options2_ad : currentAd;
764
850
  var context = {
765
851
  adPlayheadSeconds: adVideoElement === null || adVideoElement === void 0 ? void 0 : adVideoElement.currentTime,
766
852
  contentPlayheadSeconds: contentVideo.currentTime,
@@ -781,11 +867,17 @@ function createHlsAdPlayer(contentVideo, options) {
781
867
  if (podAds.length > 0) {
782
868
  context.podSequence = podIndex + 1;
783
869
  }
870
+ if (ad === null || ad === void 0 ? void 0 : ad.adServingId) {
871
+ context.adServingId = ad.adServingId;
872
+ }
873
+ if (reason != null) {
874
+ context.reason = reason;
875
+ }
784
876
  return context;
785
877
  }
786
878
  function fireTrackingPixels(urls, options2) {
787
879
  if (!urls || urls.length === 0) return;
788
- var macroContext = buildTrackingMacroContext(options2 === null || options2 === void 0 ? void 0 : options2.errorCode);
880
+ var macroContext = buildTrackingMacroContext(options2);
789
881
  urls.forEach(function(url) {
790
882
  try {
791
883
  var trackingUrl = substituteVastTrackingMacros(url, macroContext);
@@ -896,8 +988,8 @@ function createHlsAdPlayer(contentVideo, options) {
896
988
  var url = (mediaFile.url.toLowerCase().split("?")[0] || "").trim();
897
989
  return type.startsWith("audio/") || url.endsWith(".mp3") || url.endsWith(".aac") || url.endsWith(".m4a") || url.endsWith(".ogg") || url.endsWith(".oga") || url.endsWith(".opus") || url.endsWith(".wav") || url.endsWith(".weba");
898
990
  }
899
- function collectVideoMediaFiles(scope, verbose) {
900
- var mediaFileElements = scope.querySelectorAll("MediaFile");
991
+ function collectVideoMediaFiles(linear, verbose) {
992
+ var mediaFileElements = linear.querySelectorAll(":scope > MediaFiles > MediaFile");
901
993
  var mediaFiles = [];
902
994
  if (verbose) {
903
995
  console.log("[HlsAdPlayer] Found ".concat(mediaFileElements.length, " MediaFile element(s) in VAST XML"));
@@ -917,6 +1009,13 @@ function createHlsAdPlayer(contentVideo, options) {
917
1009
  }
918
1010
  return;
919
1011
  }
1012
+ var apiFramework = (mf.getAttribute("apiFramework") || "").toUpperCase();
1013
+ if (apiFramework === "VPAID") {
1014
+ if (verbose) {
1015
+ console.log("[HlsAdPlayer] MediaFile ".concat(index, " ignored (VPAID creatives are not supported)"));
1016
+ }
1017
+ return;
1018
+ }
920
1019
  var bitrateAttr = mf.getAttribute("bitrate");
921
1020
  var bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;
922
1021
  var mediaFile = {
@@ -947,114 +1046,144 @@ function createHlsAdPlayer(contentVideo, options) {
947
1046
  return mediaFiles;
948
1047
  }
949
1048
  function createEmptyTrackingUrls() {
950
- return {
1049
+ var urls = {
951
1050
  impression: [],
952
- start: [],
953
- firstQuartile: [],
954
- midpoint: [],
955
- thirdQuartile: [],
956
- complete: [],
957
- mute: [],
958
- unmute: [],
959
- pause: [],
960
- resume: [],
961
- fullscreen: [],
962
- exitFullscreen: [],
963
- skip: [],
964
- error: []
1051
+ clickTracking: [],
1052
+ error: [],
1053
+ viewable: [],
1054
+ notViewable: [],
1055
+ viewUndetermined: [],
1056
+ verificationNotExecuted: [],
1057
+ progress: []
965
1058
  };
1059
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1060
+ try {
1061
+ for(var _iterator = LINEAR_TRACKING_EVENTS[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1062
+ var event = _step.value;
1063
+ urls[event] = [];
1064
+ }
1065
+ } catch (err) {
1066
+ _didIteratorError = true;
1067
+ _iteratorError = err;
1068
+ } finally{
1069
+ try {
1070
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1071
+ _iterator.return();
1072
+ }
1073
+ } finally{
1074
+ if (_didIteratorError) {
1075
+ throw _iteratorError;
1076
+ }
1077
+ }
1078
+ }
1079
+ return urls;
966
1080
  }
967
- function extractTrackingUrls(scope) {
968
- var trackingUrls = createEmptyTrackingUrls();
969
- scope.querySelectorAll("Impression").forEach(function(el) {
970
- var _el_textContent;
971
- var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
972
- if (url) trackingUrls.impression.push(url);
1081
+ function pushUrls(target, elements) {
1082
+ elements.forEach(function(el) {
1083
+ var url = textOf(el);
1084
+ if (url) target.push(url);
973
1085
  });
974
- scope.querySelectorAll("Tracking").forEach(function(el) {
975
- var _el_textContent;
1086
+ }
1087
+ function collectLinearTracking(linear, into) {
1088
+ linear.querySelectorAll(":scope > TrackingEvents > Tracking").forEach(function(el) {
976
1089
  var event = el.getAttribute("event");
977
- var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
978
- if (event && url) {
979
- var eventKey = event;
980
- if (trackingUrls[eventKey]) {
981
- trackingUrls[eventKey].push(url);
982
- }
1090
+ var url = textOf(el);
1091
+ if (!event || !url) return;
1092
+ if (event === "progress") {
1093
+ var offset = parseProgressOffset(el.getAttribute("offset"));
1094
+ if (offset) into.progress.push(_object_spread({
1095
+ url: url
1096
+ }, offset));
1097
+ return;
1098
+ }
1099
+ if (LINEAR_TRACKING_EVENTS.indexOf(event) !== -1) {
1100
+ into[event].push(url);
983
1101
  }
984
1102
  });
985
- scope.querySelectorAll("Error").forEach(function(el) {
986
- var _el_textContent;
987
- var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
988
- if (url) trackingUrls.error.push(url);
1103
+ pushUrls(into.clickTracking, linear.querySelectorAll(":scope > VideoClicks > ClickTracking"));
1104
+ }
1105
+ function collectAdLevelTracking(adBody, into) {
1106
+ pushUrls(into.impression, adBody.querySelectorAll(":scope > Impression"));
1107
+ pushUrls(into.error, adBody.querySelectorAll(":scope > Error"));
1108
+ pushUrls(into.viewable, adBody.querySelectorAll(":scope > ViewableImpression > Viewable"));
1109
+ pushUrls(into.notViewable, adBody.querySelectorAll(":scope > ViewableImpression > NotViewable"));
1110
+ pushUrls(into.viewUndetermined, adBody.querySelectorAll(":scope > ViewableImpression > ViewUndetermined"));
1111
+ adBody.querySelectorAll(':scope > AdVerifications > Verification, :scope > Extensions > Extension[type="AdVerifications"] > AdVerifications > Verification').forEach(function(verification) {
1112
+ pushUrls(into.verificationNotExecuted, verification.querySelectorAll(':scope > TrackingEvents > Tracking[event="verificationNotExecuted"]'));
989
1113
  });
990
- return trackingUrls;
991
1114
  }
992
1115
  function mergeTrackingUrls(target, source) {
993
- Object.keys(target).forEach(function(key) {
994
- if (source[key] && source[key].length > 0) {
995
- target[key] = target[key].concat(source[key]);
1116
+ var targetLists = target;
1117
+ var sourceLists = source;
1118
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1119
+ try {
1120
+ for(var _iterator = Object.keys(targetLists)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1121
+ var key = _step.value;
1122
+ var incoming = sourceLists[key];
1123
+ if (incoming && incoming.length > 0) {
1124
+ targetLists[key] = targetLists[key].concat(incoming);
1125
+ }
996
1126
  }
997
- });
1127
+ } catch (err) {
1128
+ _didIteratorError = true;
1129
+ _iteratorError = err;
1130
+ } finally{
1131
+ try {
1132
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1133
+ _iterator.return();
1134
+ }
1135
+ } finally{
1136
+ if (_didIteratorError) {
1137
+ throw _iteratorError;
1138
+ }
1139
+ }
1140
+ }
998
1141
  return target;
999
1142
  }
1143
+ function parseXml(xmlString) {
1144
+ var xmlDoc = new DOMParser().parseFromString(xmlString, "text/xml");
1145
+ var parserError = xmlDoc.querySelector("parsererror");
1146
+ if (parserError) {
1147
+ console.error("[HlsAdPlayer] XML parsing error (malformed VAST XML):", parserError.textContent);
1148
+ return null;
1149
+ }
1150
+ return xmlDoc;
1151
+ }
1152
+ function getAdSequence(adElement) {
1153
+ var sequence = parseInt(adElement.getAttribute("sequence") || "", 10);
1154
+ return Number.isFinite(sequence) ? sequence : void 0;
1155
+ }
1156
+ function emptyVastResult(root) {
1157
+ var errorUrls = [];
1158
+ pushUrls(errorUrls, root.querySelectorAll(":scope > Error"));
1159
+ return {
1160
+ type: "empty",
1161
+ errorUrls: errorUrls,
1162
+ errorCode: VAST_ERROR_WRAPPER_NO_ADS
1163
+ };
1164
+ }
1000
1165
  function parseVastXml(xmlString) {
1001
1166
  try {
1002
- var _xmlDoc_querySelector, _xmlDoc_querySelector_textContent, _xmlDoc_querySelector1, _xmlDoc_querySelector_textContent1, _xmlDoc_querySelector2, _xmlDoc_querySelector3;
1003
- var parser = new DOMParser();
1004
- var xmlDoc = parser.parseFromString(xmlString, "text/xml");
1005
- var parserError = xmlDoc.querySelector("parsererror");
1006
- if (parserError) {
1007
- console.error("[HlsAdPlayer] XML parsing error (malformed VAST XML):", parserError.textContent);
1008
- return {
1009
- type: "empty"
1010
- };
1011
- }
1012
- var adElement = xmlDoc.querySelector("Ad");
1167
+ var _adElements_find;
1168
+ var xmlDoc = parseXml(xmlString);
1169
+ if (!xmlDoc) return {
1170
+ type: "empty"
1171
+ };
1172
+ var root = xmlDoc.documentElement;
1173
+ var adElements = Array.from(root.querySelectorAll(":scope > Ad"));
1174
+ var adElement = (_adElements_find = adElements.find(function(el) {
1175
+ return getAdSequence(el) === void 0;
1176
+ })) !== null && _adElements_find !== void 0 ? _adElements_find : adElements[0];
1013
1177
  if (!adElement) {
1014
- console.warn("[HlsAdPlayer] No Ad element found in VAST XML");
1015
- return {
1016
- type: "empty"
1017
- };
1178
+ var _root_getAttribute;
1179
+ console.warn("[HlsAdPlayer] No Ad element found in VAST ".concat((_root_getAttribute = root.getAttribute("version")) !== null && _root_getAttribute !== void 0 ? _root_getAttribute : "", " response"));
1180
+ return emptyVastResult(root);
1018
1181
  }
1019
- var adId = adElement.getAttribute("id") || "unknown";
1020
- var title = ((_xmlDoc_querySelector = xmlDoc.querySelector("AdTitle")) === null || _xmlDoc_querySelector === void 0 ? void 0 : _xmlDoc_querySelector.textContent) || "Ad";
1021
- var clickThrough = (_xmlDoc_querySelector1 = xmlDoc.querySelector("ClickThrough")) === null || _xmlDoc_querySelector1 === void 0 ? void 0 : (_xmlDoc_querySelector_textContent = _xmlDoc_querySelector1.textContent) === null || _xmlDoc_querySelector_textContent === void 0 ? void 0 : _xmlDoc_querySelector_textContent.trim();
1022
- var wrapperUri = (_xmlDoc_querySelector2 = xmlDoc.querySelector("VASTAdTagURI")) === null || _xmlDoc_querySelector2 === void 0 ? void 0 : (_xmlDoc_querySelector_textContent1 = _xmlDoc_querySelector2.textContent) === null || _xmlDoc_querySelector_textContent1 === void 0 ? void 0 : _xmlDoc_querySelector_textContent1.trim();
1023
- if (wrapperUri) {
1024
- console.log("[HlsAdPlayer] VAST wrapper detected, following VASTAdTagURI: ".concat(wrapperUri));
1025
- return {
1026
- type: "wrapper",
1027
- vastAdTagUri: wrapperUri,
1028
- trackingUrls: extractTrackingUrls(xmlDoc),
1029
- clickThrough: clickThrough
1030
- };
1182
+ var parsed = parseAdElement(adElement, true);
1183
+ if (parsed.type === "wrapper") {
1184
+ console.log("[HlsAdPlayer] VAST wrapper detected, following VASTAdTagURI: ".concat(parsed.vastAdTagUri));
1031
1185
  }
1032
- var isNoAdAvailable = adId === "empty" || title.toLowerCase().includes("no ad available") || title.toLowerCase() === "no ad available";
1033
- var durationText = ((_xmlDoc_querySelector3 = xmlDoc.querySelector("Duration")) === null || _xmlDoc_querySelector3 === void 0 ? void 0 : _xmlDoc_querySelector3.textContent) || "00:00:30";
1034
- var durationParts = durationText.split(":");
1035
- var duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseInt(durationParts[2] || "0", 10);
1036
- var mediaFiles = collectVideoMediaFiles(xmlDoc, true);
1037
- if (mediaFiles.length === 0) {
1038
- if (isNoAdAvailable) {
1039
- console.warn("[HlsAdPlayer] No ads available (VAST response indicates no ads)");
1040
- } else {
1041
- console.warn("[HlsAdPlayer] No supported media files found in VAST XML");
1042
- }
1043
- return {
1044
- type: "empty"
1045
- };
1046
- }
1047
- return {
1048
- type: "inline",
1049
- ad: {
1050
- id: adId,
1051
- title: title,
1052
- duration: duration,
1053
- mediaFiles: mediaFiles,
1054
- trackingUrls: extractTrackingUrls(xmlDoc),
1055
- clickThrough: clickThrough
1056
- }
1057
- };
1186
+ return parsed;
1058
1187
  } catch (error) {
1059
1188
  console.error("[HlsAdPlayer] Error parsing VAST XML:", error);
1060
1189
  return {
@@ -1063,48 +1192,101 @@ function createHlsAdPlayer(contentVideo, options) {
1063
1192
  }
1064
1193
  }
1065
1194
  function parseAdElement(adElement) {
1195
+ var verbose = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : false;
1066
1196
  try {
1067
- var _adElement_querySelector, _adElement_querySelector_textContent, _adElement_querySelector1, _adElement_querySelector_textContent1, _adElement_querySelector2, _adElement_querySelector3;
1068
- var adId = adElement.getAttribute("id") || "unknown";
1069
- var title = ((_adElement_querySelector = adElement.querySelector("AdTitle")) === null || _adElement_querySelector === void 0 ? void 0 : _adElement_querySelector.textContent) || "Ad";
1070
- 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();
1071
- 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();
1072
- if (wrapperUri) {
1197
+ var _parseVastTime;
1198
+ var wrapper = adElement.querySelector(":scope > Wrapper");
1199
+ if (wrapper) {
1200
+ var vastAdTagUri = textOf(wrapper.querySelector(":scope > VASTAdTagURI"));
1201
+ if (!vastAdTagUri) {
1202
+ console.warn("[HlsAdPlayer] <Wrapper> has no VASTAdTagURI");
1203
+ return {
1204
+ type: "empty"
1205
+ };
1206
+ }
1207
+ var trackingUrls2 = createEmptyTrackingUrls();
1208
+ collectAdLevelTracking(wrapper, trackingUrls2);
1209
+ wrapper.querySelectorAll(":scope > Creatives > Creative > Linear").forEach(function(linear2) {
1210
+ return collectLinearTracking(linear2, trackingUrls2);
1211
+ });
1073
1212
  return {
1074
1213
  type: "wrapper",
1075
- vastAdTagUri: wrapperUri,
1076
- trackingUrls: extractTrackingUrls(adElement),
1077
- clickThrough: clickThrough
1214
+ vastAdTagUri: vastAdTagUri,
1215
+ trackingUrls: trackingUrls2,
1216
+ rules: {
1217
+ followAdditionalWrappers: wrapper.getAttribute("followAdditionalWrappers") !== "false"
1218
+ }
1078
1219
  };
1079
1220
  }
1080
- var isNoAdAvailable = adId === "empty" || title.toLowerCase().includes("no ad available") || title.toLowerCase() === "no ad available";
1081
- var durationText = ((_adElement_querySelector3 = adElement.querySelector("Duration")) === null || _adElement_querySelector3 === void 0 ? void 0 : _adElement_querySelector3.textContent) || "00:00:30";
1082
- var durationParts = durationText.split(":");
1083
- var duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseInt(durationParts[2] || "0", 10);
1084
- var mediaFiles = collectVideoMediaFiles(adElement, false);
1085
- if (mediaFiles.length === 0) {
1086
- if (isNoAdAvailable) {
1087
- console.warn("[HlsAdPlayer] Pod <Ad> indicates no ad available");
1088
- } else {
1089
- console.warn("[HlsAdPlayer] No supported media files in pod <Ad>");
1090
- }
1221
+ var inLine = adElement.querySelector(":scope > InLine");
1222
+ if (!inLine) {
1223
+ console.warn("[HlsAdPlayer] <Ad> has neither <InLine> nor <Wrapper>");
1091
1224
  return {
1092
1225
  type: "empty"
1093
1226
  };
1094
1227
  }
1228
+ var errorUrls = [];
1229
+ pushUrls(errorUrls, inLine.querySelectorAll(":scope > Error"));
1230
+ if (adElement.getAttribute("conditionalAd") === "true") {
1231
+ console.warn("[HlsAdPlayer] Skipping conditional <Ad> (VPAID-only)");
1232
+ return {
1233
+ type: "empty",
1234
+ errorUrls: errorUrls,
1235
+ errorCode: VAST_ERROR_NO_SUPPORTED_MEDIA
1236
+ };
1237
+ }
1238
+ var linear;
1239
+ var mediaFiles = [];
1240
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1241
+ try {
1242
+ for(var _iterator = Array.from(inLine.querySelectorAll(":scope > Creatives > Creative > Linear"))[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1243
+ var candidate = _step.value;
1244
+ var files = collectVideoMediaFiles(candidate, verbose);
1245
+ if (files.length > 0) {
1246
+ linear = candidate;
1247
+ mediaFiles = files;
1248
+ break;
1249
+ }
1250
+ }
1251
+ } catch (err) {
1252
+ _didIteratorError = true;
1253
+ _iteratorError = err;
1254
+ } finally{
1255
+ try {
1256
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1257
+ _iterator.return();
1258
+ }
1259
+ } finally{
1260
+ if (_didIteratorError) {
1261
+ throw _iteratorError;
1262
+ }
1263
+ }
1264
+ }
1265
+ if (!linear) {
1266
+ console.warn("[HlsAdPlayer] No supported linear media files in <Ad>");
1267
+ return {
1268
+ type: "empty",
1269
+ errorUrls: errorUrls,
1270
+ errorCode: VAST_ERROR_NO_SUPPORTED_MEDIA
1271
+ };
1272
+ }
1273
+ var trackingUrls = createEmptyTrackingUrls();
1274
+ collectAdLevelTracking(inLine, trackingUrls);
1275
+ collectLinearTracking(linear, trackingUrls);
1095
1276
  return {
1096
1277
  type: "inline",
1097
1278
  ad: {
1098
- id: adId,
1099
- title: title,
1100
- duration: duration,
1279
+ id: adElement.getAttribute("id") || "unknown",
1280
+ title: textOf(inLine.querySelector(":scope > AdTitle")) || "Ad",
1281
+ duration: (_parseVastTime = parseVastTime(textOf(linear.querySelector(":scope > Duration")))) !== null && _parseVastTime !== void 0 ? _parseVastTime : 30,
1101
1282
  mediaFiles: mediaFiles,
1102
- trackingUrls: extractTrackingUrls(adElement),
1103
- clickThrough: clickThrough
1283
+ trackingUrls: trackingUrls,
1284
+ clickThrough: textOf(linear.querySelector(":scope > VideoClicks > ClickThrough")),
1285
+ adServingId: textOf(inLine.querySelector(":scope > AdServingId"))
1104
1286
  }
1105
1287
  };
1106
1288
  } catch (error) {
1107
- console.error("[HlsAdPlayer] Error parsing pod <Ad> element:", error);
1289
+ console.error("[HlsAdPlayer] Error parsing <Ad> element:", error);
1108
1290
  return {
1109
1291
  type: "empty"
1110
1292
  };
@@ -1183,30 +1365,63 @@ function createHlsAdPlayer(contentVideo, options) {
1183
1365
  }
1184
1366
  function fetchAndParseVastAd(_0) {
1185
1367
  return _async_to_generator(function(vastTagUrl) {
1186
- var depth, accumulatedTracking, vastXml, parsed;
1368
+ var depth, accumulatedTracking, rules, vastXml, error, parsed, _parsed_errorUrls, _parsed_errorCode;
1187
1369
  var _arguments = arguments;
1188
1370
  return _ts_generator(this, function(_state) {
1189
1371
  switch(_state.label){
1190
1372
  case 0:
1191
- depth = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : 0, accumulatedTracking = _arguments.length > 2 && _arguments[2] !== void 0 ? _arguments[2] : createEmptyTrackingUrls();
1373
+ depth = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : 0, accumulatedTracking = _arguments.length > 2 && _arguments[2] !== void 0 ? _arguments[2] : createEmptyTrackingUrls(), rules = _arguments.length > 3 && _arguments[3] !== void 0 ? _arguments[3] : {
1374
+ followAdditionalWrappers: true
1375
+ };
1376
+ _state.label = 1;
1377
+ case 1:
1378
+ _state.trys.push([
1379
+ 1,
1380
+ 3,
1381
+ ,
1382
+ 4
1383
+ ]);
1192
1384
  return [
1193
1385
  4,
1194
1386
  fetchVastXml(vastTagUrl, depth === 0 ? "include" : "omit")
1195
1387
  ];
1196
- case 1:
1388
+ case 2:
1197
1389
  vastXml = _state.sent();
1390
+ return [
1391
+ 3,
1392
+ 4
1393
+ ];
1394
+ case 3:
1395
+ error = _state.sent();
1396
+ if (depth === 0) throw error;
1397
+ console.warn("[HlsAdPlayer] Wrapped VAST request failed:", error);
1398
+ fireTrackingPixels(accumulatedTracking.error, {
1399
+ errorCode: VAST_ERROR_WRAPPER_TIMEOUT
1400
+ });
1401
+ return [
1402
+ 2,
1403
+ null
1404
+ ];
1405
+ case 4:
1198
1406
  console.log("[HlsAdPlayer] VAST XML received");
1199
1407
  console.log("[HlsAdPlayer] VAST XML content (first 2000 chars):", vastXml.substring(0, 2e3));
1200
1408
  parsed = parseVastXml(vastXml);
1201
1409
  if (parsed.type === "empty") {
1410
+ ;
1411
+ fireTrackingPixels(((_parsed_errorUrls = parsed.errorUrls) !== null && _parsed_errorUrls !== void 0 ? _parsed_errorUrls : []).concat(accumulatedTracking.error), {
1412
+ errorCode: (_parsed_errorCode = parsed.errorCode) !== null && _parsed_errorCode !== void 0 ? _parsed_errorCode : VAST_ERROR_WRAPPER_NO_ADS
1413
+ });
1202
1414
  return [
1203
1415
  2,
1204
1416
  null
1205
1417
  ];
1206
1418
  }
1207
1419
  if (parsed.type === "wrapper") {
1208
- if (depth >= MAX_VAST_WRAPPER_DEPTH) {
1209
- console.warn("[HlsAdPlayer] VAST wrapper depth limit (".concat(MAX_VAST_WRAPPER_DEPTH, ") reached, aborting redirect chain"));
1420
+ if (depth >= MAX_VAST_WRAPPER_DEPTH || !rules.followAdditionalWrappers) {
1421
+ console.warn(rules.followAdditionalWrappers ? "[HlsAdPlayer] VAST wrapper depth limit (".concat(MAX_VAST_WRAPPER_DEPTH, ") reached, aborting redirect chain") : '[HlsAdPlayer] Parent wrapper set followAdditionalWrappers="false"; rejecting nested wrapper');
1422
+ fireTrackingPixels(accumulatedTracking.error.concat(parsed.trackingUrls.error), {
1423
+ errorCode: VAST_ERROR_WRAPPER_LIMIT
1424
+ });
1210
1425
  return [
1211
1426
  2,
1212
1427
  null
@@ -1215,7 +1430,7 @@ function createHlsAdPlayer(contentVideo, options) {
1215
1430
  mergeTrackingUrls(accumulatedTracking, parsed.trackingUrls);
1216
1431
  return [
1217
1432
  2,
1218
- fetchAndParseVastAd(parsed.vastAdTagUri, depth + 1, accumulatedTracking)
1433
+ fetchAndParseVastAd(parsed.vastAdTagUri, depth + 1, accumulatedTracking, parsed.rules)
1219
1434
  ];
1220
1435
  }
1221
1436
  mergeTrackingUrls(parsed.ad.trackingUrls, accumulatedTracking);
@@ -1229,7 +1444,7 @@ function createHlsAdPlayer(contentVideo, options) {
1229
1444
  }
1230
1445
  function fetchAndParsePod(vastTagUrl) {
1231
1446
  return _async_to_generator(function() {
1232
- var vastXml, trimmedXml, parser, xmlDoc, adElements, ads, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, adElement, parsed, resolved, error, err;
1447
+ var _root_getAttribute, vastXml, trimmedXml, xmlDoc, root, adElements, _root_getAttribute1, _empty_errorUrls, empty, _empty_errorCode, resolveAd, podElements, buffet, ads, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, adElement, ad, err, _iteratorNormalCompletion1, _didIteratorError1, _iteratorError1, _iterator1, _step1, adElement1, ad1, err;
1233
1448
  return _ts_generator(this, function(_state) {
1234
1449
  switch(_state.label){
1235
1450
  case 0:
@@ -1248,125 +1463,212 @@ function createHlsAdPlayer(contentVideo, options) {
1248
1463
  []
1249
1464
  ];
1250
1465
  }
1251
- parser = new DOMParser();
1252
- xmlDoc = parser.parseFromString(vastXml, "text/xml");
1253
- if (xmlDoc.querySelector("parsererror")) {
1254
- console.error("[HlsAdPlayer] Pod VAST XML parsing error (malformed). Content (first 2000 chars):", vastXml.substring(0, 2e3));
1466
+ xmlDoc = parseXml(vastXml);
1467
+ if (!xmlDoc) {
1468
+ console.error("[HlsAdPlayer] Pod VAST XML content (first 2000 chars):", vastXml.substring(0, 2e3));
1255
1469
  return [
1256
1470
  2,
1257
1471
  []
1258
1472
  ];
1259
1473
  }
1260
- adElements = Array.from(xmlDoc.querySelectorAll("Ad"));
1474
+ root = xmlDoc.documentElement;
1475
+ adElements = Array.from(root.querySelectorAll(":scope > Ad"));
1261
1476
  if (adElements.length === 0) {
1262
- console.warn("[HlsAdPlayer] No <Ad> elements found in pod VAST response (no fill). Content (first 2000 chars):", vastXml.substring(0, 2e3));
1477
+ ;
1478
+ ;
1479
+ console.warn("[HlsAdPlayer] No <Ad> elements in VAST ".concat((_root_getAttribute1 = root.getAttribute("version")) !== null && _root_getAttribute1 !== void 0 ? _root_getAttribute1 : "", " pod response (no fill)"));
1480
+ empty = emptyVastResult(root);
1481
+ if (empty.type === "empty" && ((_empty_errorUrls = empty.errorUrls) === null || _empty_errorUrls === void 0 ? void 0 : _empty_errorUrls.length)) {
1482
+ ;
1483
+ fireTrackingPixels(empty.errorUrls, {
1484
+ errorCode: (_empty_errorCode = empty.errorCode) !== null && _empty_errorCode !== void 0 ? _empty_errorCode : VAST_ERROR_WRAPPER_NO_ADS
1485
+ });
1486
+ }
1263
1487
  return [
1264
1488
  2,
1265
1489
  []
1266
1490
  ];
1267
1491
  }
1268
- adElements.sort(function(a, b) {
1269
- var aSeq = parseInt(a.getAttribute("sequence") || "", 10);
1270
- var bSeq = parseInt(b.getAttribute("sequence") || "", 10);
1271
- var aVal = Number.isFinite(aSeq) ? aSeq : Number.MAX_SAFE_INTEGER;
1272
- var bVal = Number.isFinite(bSeq) ? bSeq : Number.MAX_SAFE_INTEGER;
1273
- return aVal - bVal;
1492
+ resolveAd = function resolveAd(adElement) {
1493
+ return _async_to_generator(function() {
1494
+ var _parsed_errorUrls, parsed, _parsed_errorCode;
1495
+ return _ts_generator(this, function(_state) {
1496
+ parsed = parseAdElement(adElement);
1497
+ if (parsed.type === "inline") return [
1498
+ 2,
1499
+ parsed.ad
1500
+ ];
1501
+ if (parsed.type === "wrapper") {
1502
+ return [
1503
+ 2,
1504
+ fetchAndParseVastAd(parsed.vastAdTagUri, 1, parsed.trackingUrls, parsed.rules)
1505
+ ];
1506
+ }
1507
+ if ((_parsed_errorUrls = parsed.errorUrls) === null || _parsed_errorUrls === void 0 ? void 0 : _parsed_errorUrls.length) {
1508
+ ;
1509
+ fireTrackingPixels(parsed.errorUrls, {
1510
+ errorCode: (_parsed_errorCode = parsed.errorCode) !== null && _parsed_errorCode !== void 0 ? _parsed_errorCode : VAST_ERROR_NO_SUPPORTED_MEDIA
1511
+ });
1512
+ }
1513
+ return [
1514
+ 2,
1515
+ null
1516
+ ];
1517
+ });
1518
+ })();
1519
+ };
1520
+ podElements = adElements.filter(function(el) {
1521
+ return getAdSequence(el) !== void 0;
1522
+ }).sort(function(a, b) {
1523
+ return getAdSequence(a) - getAdSequence(b);
1524
+ });
1525
+ buffet = adElements.filter(function(el) {
1526
+ return getAdSequence(el) === void 0;
1274
1527
  });
1275
1528
  ads = [];
1529
+ if (!(podElements.length === 0)) return [
1530
+ 3,
1531
+ 10
1532
+ ];
1276
1533
  _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1277
1534
  _state.label = 2;
1278
1535
  case 2:
1279
1536
  _state.trys.push([
1280
1537
  2,
1281
- 10,
1282
- 11,
1283
- 12
1538
+ 7,
1539
+ 8,
1540
+ 9
1284
1541
  ]);
1285
- _iterator = adElements[Symbol.iterator]();
1542
+ _iterator = buffet[Symbol.iterator]();
1286
1543
  _state.label = 3;
1287
1544
  case 3:
1288
1545
  if (!!(_iteratorNormalCompletion = (_step = _iterator.next()).done)) return [
1289
1546
  3,
1290
- 9
1547
+ 6
1291
1548
  ];
1292
1549
  adElement = _step.value;
1293
- parsed = parseAdElement(adElement);
1294
- if (!(parsed.type === "inline")) return [
1295
- 3,
1296
- 4
1297
- ];
1298
- ads.push(parsed.ad);
1299
1550
  return [
1300
- 3,
1301
- 8
1551
+ 4,
1552
+ resolveAd(adElement)
1302
1553
  ];
1303
1554
  case 4:
1304
- if (!(parsed.type === "wrapper")) return [
1305
- 3,
1306
- 8
1307
- ];
1555
+ ad = _state.sent();
1556
+ if (ad) ads.push(ad);
1308
1557
  _state.label = 5;
1309
1558
  case 5:
1310
- _state.trys.push([
1311
- 5,
1312
- 7,
1313
- ,
1314
- 8
1315
- ]);
1559
+ _iteratorNormalCompletion = true;
1316
1560
  return [
1317
- 4,
1318
- fetchAndParseVastAd(parsed.vastAdTagUri, 1, parsed.trackingUrls)
1561
+ 3,
1562
+ 3
1319
1563
  ];
1320
1564
  case 6:
1321
- resolved = _state.sent();
1322
- if (resolved) {
1323
- ads.push(resolved);
1324
- }
1325
1565
  return [
1326
1566
  3,
1327
- 8
1567
+ 9
1328
1568
  ];
1329
1569
  case 7:
1330
- error = _state.sent();
1331
- console.warn("[HlsAdPlayer] Failed to resolve wrapper <Ad> in pod:", error);
1570
+ err = _state.sent();
1571
+ _didIteratorError = true;
1572
+ _iteratorError = err;
1332
1573
  return [
1333
1574
  3,
1334
- 8
1575
+ 9
1335
1576
  ];
1336
1577
  case 8:
1337
- _iteratorNormalCompletion = true;
1578
+ try {
1579
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1580
+ _iterator.return();
1581
+ }
1582
+ } finally{
1583
+ if (_didIteratorError) {
1584
+ throw _iteratorError;
1585
+ }
1586
+ }
1338
1587
  return [
1339
- 3,
1340
- 3
1588
+ 7
1341
1589
  ];
1342
1590
  case 9:
1343
1591
  return [
1344
1592
  3,
1345
- 12
1593
+ 21
1346
1594
  ];
1347
1595
  case 10:
1348
- err = _state.sent();
1349
- _didIteratorError = true;
1350
- _iteratorError = err;
1596
+ _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
1597
+ _state.label = 11;
1598
+ case 11:
1599
+ _state.trys.push([
1600
+ 11,
1601
+ 19,
1602
+ 20,
1603
+ 21
1604
+ ]);
1605
+ _iterator1 = podElements[Symbol.iterator]();
1606
+ _state.label = 12;
1607
+ case 12:
1608
+ if (!!(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done)) return [
1609
+ 3,
1610
+ 18
1611
+ ];
1612
+ adElement1 = _step1.value;
1613
+ return [
1614
+ 4,
1615
+ resolveAd(adElement1)
1616
+ ];
1617
+ case 13:
1618
+ ad1 = _state.sent();
1619
+ _state.label = 14;
1620
+ case 14:
1621
+ if (!(!ad1 && buffet.length > 0)) return [
1622
+ 3,
1623
+ 16
1624
+ ];
1625
+ return [
1626
+ 4,
1627
+ resolveAd(buffet.shift())
1628
+ ];
1629
+ case 15:
1630
+ ad1 = _state.sent();
1631
+ return [
1632
+ 3,
1633
+ 14
1634
+ ];
1635
+ case 16:
1636
+ if (ad1) ads.push(ad1);
1637
+ _state.label = 17;
1638
+ case 17:
1639
+ _iteratorNormalCompletion1 = true;
1351
1640
  return [
1352
1641
  3,
1353
1642
  12
1354
1643
  ];
1355
- case 11:
1644
+ case 18:
1645
+ return [
1646
+ 3,
1647
+ 21
1648
+ ];
1649
+ case 19:
1650
+ err = _state.sent();
1651
+ _didIteratorError1 = true;
1652
+ _iteratorError1 = err;
1653
+ return [
1654
+ 3,
1655
+ 21
1656
+ ];
1657
+ case 20:
1356
1658
  try {
1357
- if (!_iteratorNormalCompletion && _iterator.return != null) {
1358
- _iterator.return();
1659
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
1660
+ _iterator1.return();
1359
1661
  }
1360
1662
  } finally{
1361
- if (_didIteratorError) {
1362
- throw _iteratorError;
1663
+ if (_didIteratorError1) {
1664
+ throw _iteratorError1;
1363
1665
  }
1364
1666
  }
1365
1667
  return [
1366
1668
  7
1367
1669
  ];
1368
- case 12:
1369
- console.log("[HlsAdPlayer] Parsed ".concat(ads.length, " ad(s) from pod VAST response"));
1670
+ case 21:
1671
+ console.log("[HlsAdPlayer] Parsed ".concat(ads.length, " ad(s) from VAST ").concat((_root_getAttribute = root.getAttribute("version")) !== null && _root_getAttribute !== void 0 ? _root_getAttribute : "", " pod response"));
1370
1672
  return [
1371
1673
  2,
1372
1674
  ads
@@ -1396,7 +1698,40 @@ function createHlsAdPlayer(contentVideo, options) {
1396
1698
  var onTimeUpdate = function onTimeUpdate() {
1397
1699
  if (!currentAd || !adVideoElement) return;
1398
1700
  noteAdProgress();
1399
- var progress = adVideoElement.currentTime / currentAd.duration;
1701
+ sampleViewability();
1702
+ var currentTime = adVideoElement.currentTime;
1703
+ if (trackingFired.start) {
1704
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1705
+ try {
1706
+ for(var _iterator = currentAd.trackingUrls.progress[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1707
+ var event = _step.value;
1708
+ var _event_offsetSeconds, _event_offsetPercent;
1709
+ if (trackingFired.progressFired.has(event)) continue;
1710
+ var threshold = (_event_offsetSeconds = event.offsetSeconds) !== null && _event_offsetSeconds !== void 0 ? _event_offsetSeconds : ((_event_offsetPercent = event.offsetPercent) !== null && _event_offsetPercent !== void 0 ? _event_offsetPercent : 0) / 100 * currentAd.duration;
1711
+ if (currentTime >= threshold) {
1712
+ trackingFired.progressFired.add(event);
1713
+ fireTrackingPixels([
1714
+ event.url
1715
+ ]);
1716
+ }
1717
+ }
1718
+ } catch (err) {
1719
+ _didIteratorError = true;
1720
+ _iteratorError = err;
1721
+ } finally{
1722
+ try {
1723
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1724
+ _iterator.return();
1725
+ }
1726
+ } finally{
1727
+ if (_didIteratorError) {
1728
+ throw _iteratorError;
1729
+ }
1730
+ }
1731
+ }
1732
+ }
1733
+ if (!(currentAd.duration > 0)) return;
1734
+ var progress = currentTime / currentAd.duration;
1400
1735
  if (progress >= 0.25 && !trackingFired.firstQuartile) {
1401
1736
  trackingFired.firstQuartile = true;
1402
1737
  fireTrackingPixels(currentAd.trackingUrls.firstQuartile);
@@ -1418,15 +1753,38 @@ function createHlsAdPlayer(contentVideo, options) {
1418
1753
  handleVideoDecodeFailure();
1419
1754
  }
1420
1755
  };
1756
+ var onCanPlay = function onCanPlay() {
1757
+ if (!currentAd || trackingFired.loaded) return;
1758
+ trackingFired.loaded = true;
1759
+ fireTrackingPixels(currentAd.trackingUrls.loaded);
1760
+ };
1421
1761
  var onPlaying = function onPlaying() {
1422
1762
  startStallWatchdog();
1423
- if (!currentAd || trackingFired.start) return;
1763
+ if (!currentAd || !adVideoElement) return;
1764
+ if (!trackingFired.impression) {
1765
+ trackingFired.impression = true;
1766
+ resolvedAds.add(currentAd);
1767
+ fireTrackingPixels(currentAd.trackingUrls.impression);
1768
+ fireTrackingPixels(currentAd.trackingUrls.creativeView);
1769
+ fireTrackingPixels(currentAd.trackingUrls.verificationNotExecuted, {
1770
+ reason: VERIFICATION_NOT_SUPPORTED_REASON
1771
+ });
1772
+ emit("ad_impression", {
1773
+ adId: currentAd.id,
1774
+ index: podIndex,
1775
+ total: podAds.length || 1
1776
+ });
1777
+ }
1778
+ if (trackingFired.start) return;
1424
1779
  trackingFired.start = true;
1780
+ trackingFired.lastMuted = adVideoElement.muted || adVideoElement.volume === 0;
1425
1781
  fireTrackingPixels(currentAd.trackingUrls.start);
1426
1782
  console.log("[HlsAdPlayer] Ad started playing");
1427
1783
  };
1428
1784
  var onEnded = function onEnded() {
1429
1785
  if (!currentAd || trackingFired.complete) return;
1786
+ sampleViewability();
1787
+ settleViewability();
1430
1788
  trackingFired.complete = true;
1431
1789
  fireTrackingPixels(currentAd.trackingUrls.complete);
1432
1790
  console.log("[HlsAdPlayer] Ad completed");
@@ -1438,11 +1796,7 @@ function createHlsAdPlayer(contentVideo, options) {
1438
1796
  var onError = function onError(e) {
1439
1797
  if (!adPlaying) return;
1440
1798
  console.error("[HlsAdPlayer] Ad video error:", e);
1441
- if (currentAd) {
1442
- fireTrackingPixels(currentAd.trackingUrls.error, {
1443
- errorCode: toVastMediaErrorCode(adVideoElement === null || adVideoElement === void 0 ? void 0 : adVideoElement.error)
1444
- });
1445
- }
1799
+ reportCurrentAdError(toVastMediaErrorCode(adVideoElement === null || adVideoElement === void 0 ? void 0 : adVideoElement.error));
1446
1800
  if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1447
1801
  return;
1448
1802
  }
@@ -1450,19 +1804,26 @@ function createHlsAdPlayer(contentVideo, options) {
1450
1804
  };
1451
1805
  var onVolumeChange = function onVolumeChange() {
1452
1806
  if (!currentAd || !adVideoElement) return;
1453
- if (adVideoElement.muted) {
1454
- fireTrackingPixels(currentAd.trackingUrls.mute);
1455
- } else {
1456
- fireTrackingPixels(currentAd.trackingUrls.unmute);
1807
+ var muted = adVideoElement.muted || adVideoElement.volume === 0;
1808
+ if (!trackingFired.start) {
1809
+ trackingFired.lastMuted = muted;
1810
+ return;
1457
1811
  }
1812
+ if (muted === trackingFired.lastMuted) return;
1813
+ trackingFired.lastMuted = muted;
1814
+ fireTrackingPixels(muted ? currentAd.trackingUrls.mute : currentAd.trackingUrls.unmute);
1815
+ };
1816
+ var isTrackablePlayback = function isTrackablePlayback() {
1817
+ return adPlaying && !!currentAd && !!adVideoElement && trackingFired.start && !trackingFired.complete && !adVideoElement.ended;
1458
1818
  };
1459
1819
  var onPause = function onPause() {
1460
- if (currentAd && adVideoElement && !adVideoElement.ended) {
1820
+ continuousVisibleS = 0;
1821
+ if (isTrackablePlayback()) {
1461
1822
  fireTrackingPixels(currentAd.trackingUrls.pause);
1462
1823
  }
1463
1824
  };
1464
1825
  var onPlay = function onPlay() {
1465
- if (currentAd && adVideoElement && adVideoElement.currentTime > 0) {
1826
+ if (isTrackablePlayback()) {
1466
1827
  fireTrackingPixels(currentAd.trackingUrls.resume);
1467
1828
  }
1468
1829
  };
@@ -1475,6 +1836,10 @@ function createHlsAdPlayer(contentVideo, options) {
1475
1836
  type: "loadedmetadata",
1476
1837
  handler: onLoadedMetadata
1477
1838
  },
1839
+ {
1840
+ type: "canplay",
1841
+ handler: onCanPlay
1842
+ },
1478
1843
  {
1479
1844
  type: "playing",
1480
1845
  handler: onPlaying
@@ -1546,6 +1911,229 @@ function createHlsAdPlayer(contentVideo, options) {
1546
1911
  }
1547
1912
  adEventHandlers = [];
1548
1913
  }
1914
+ function handleAdClick() {
1915
+ if (!adPlaying || !currentAd) return;
1916
+ fireTrackingPixels(currentAd.trackingUrls.clickTracking);
1917
+ emit("ad_click", {
1918
+ adId: currentAd.id,
1919
+ clickThrough: currentAd.clickThrough
1920
+ });
1921
+ if (currentAd.clickThrough) {
1922
+ try {
1923
+ window.open(currentAd.clickThrough, "_blank", "noopener");
1924
+ } catch (error) {
1925
+ console.warn("[HlsAdPlayer] Failed to open ClickThrough URL:", error);
1926
+ }
1927
+ }
1928
+ }
1929
+ function reportCurrentAdError(errorCode) {
1930
+ if (!currentAd) return;
1931
+ resolvedAds.add(currentAd);
1932
+ fireTrackingPixels(currentAd.trackingUrls.error, {
1933
+ errorCode: errorCode
1934
+ });
1935
+ }
1936
+ function fireNotUsedForUnplayedAds() {
1937
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1938
+ try {
1939
+ for(var _iterator = podAds[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1940
+ var ad = _step.value;
1941
+ if (resolvedAds.has(ad)) continue;
1942
+ resolvedAds.add(ad);
1943
+ fireTrackingPixels(ad.trackingUrls.notUsed, {
1944
+ ad: ad
1945
+ });
1946
+ }
1947
+ } catch (err) {
1948
+ _didIteratorError = true;
1949
+ _iteratorError = err;
1950
+ } finally{
1951
+ try {
1952
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1953
+ _iterator.return();
1954
+ }
1955
+ } finally{
1956
+ if (_didIteratorError) {
1957
+ throw _iteratorError;
1958
+ }
1959
+ }
1960
+ }
1961
+ }
1962
+ function sampleViewability() {
1963
+ if (!currentAd || !adVideoElement || !viewObserver || !trackingFired.impression || trackingFired.viewabilitySettled) {
1964
+ return;
1965
+ }
1966
+ var now = adVideoElement.currentTime;
1967
+ var inView = visibleRatio >= VIEWABLE_MIN_VISIBLE_RATIO && document.visibilityState === "visible" && !adVideoElement.paused;
1968
+ if (!inView) {
1969
+ continuousVisibleS = 0;
1970
+ } else if (lastViewSampleTime !== void 0 && now >= lastViewSampleTime) {
1971
+ continuousVisibleS += now - lastViewSampleTime;
1972
+ }
1973
+ lastViewSampleTime = now;
1974
+ if (continuousVisibleS >= VIEWABLE_MIN_CONTINUOUS_S) {
1975
+ trackingFired.viewabilitySettled = true;
1976
+ fireTrackingPixels(currentAd.trackingUrls.viewable);
1977
+ }
1978
+ }
1979
+ function settleViewability() {
1980
+ if (!currentAd || !trackingFired.impression || trackingFired.viewabilitySettled) {
1981
+ return;
1982
+ }
1983
+ trackingFired.viewabilitySettled = true;
1984
+ fireTrackingPixels(viewObserver ? currentAd.trackingUrls.notViewable : currentAd.trackingUrls.viewUndetermined);
1985
+ }
1986
+ function handleFullscreenChange() {
1987
+ var _document_fullscreenElement;
1988
+ if (!adPlaying || !currentAd || !adContainerEl || !trackingFired.start) return;
1989
+ var fullscreenEl = (_document_fullscreenElement = document.fullscreenElement) !== null && _document_fullscreenElement !== void 0 ? _document_fullscreenElement : document.webkitFullscreenElement;
1990
+ var expanded = !!fullscreenEl && fullscreenEl.contains(adContainerEl);
1991
+ if (expanded === lastPlayerExpanded) return;
1992
+ lastPlayerExpanded = expanded;
1993
+ var urls = currentAd.trackingUrls;
1994
+ fireTrackingPixels(expanded ? urls.fullscreen.concat(urls.playerExpand) : urls.exitFullscreen.concat(urls.playerCollapse));
1995
+ }
1996
+ function attachContainerHandlers() {
1997
+ if (!adContainerEl || containerHandlers.length > 0) return;
1998
+ var onClick = function onClick() {
1999
+ return handleAdClick();
2000
+ };
2001
+ var onInteraction = function onInteraction(event) {
2002
+ if (adPlaying) emit("ad_interaction", event);
2003
+ };
2004
+ containerHandlers = [
2005
+ {
2006
+ type: "click",
2007
+ handler: onClick
2008
+ },
2009
+ {
2010
+ type: "mousedown",
2011
+ handler: onInteraction
2012
+ },
2013
+ {
2014
+ type: "touchstart",
2015
+ handler: onInteraction
2016
+ }
2017
+ ];
2018
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2019
+ try {
2020
+ for(var _iterator = containerHandlers[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2021
+ var _step_value = _step.value, type = _step_value.type, handler = _step_value.handler;
2022
+ adContainerEl.addEventListener(type, handler);
2023
+ }
2024
+ } catch (err) {
2025
+ _didIteratorError = true;
2026
+ _iteratorError = err;
2027
+ } finally{
2028
+ try {
2029
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
2030
+ _iterator.return();
2031
+ }
2032
+ } finally{
2033
+ if (_didIteratorError) {
2034
+ throw _iteratorError;
2035
+ }
2036
+ }
2037
+ }
2038
+ var onFullscreenChange = function onFullscreenChange() {
2039
+ return handleFullscreenChange();
2040
+ };
2041
+ documentHandlers = [
2042
+ {
2043
+ type: "fullscreenchange",
2044
+ handler: onFullscreenChange
2045
+ },
2046
+ {
2047
+ type: "webkitfullscreenchange",
2048
+ handler: onFullscreenChange
2049
+ }
2050
+ ];
2051
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
2052
+ try {
2053
+ for(var _iterator1 = documentHandlers[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
2054
+ var _step_value1 = _step1.value, type1 = _step_value1.type, handler1 = _step_value1.handler;
2055
+ document.addEventListener(type1, handler1);
2056
+ }
2057
+ } catch (err) {
2058
+ _didIteratorError1 = true;
2059
+ _iteratorError1 = err;
2060
+ } finally{
2061
+ try {
2062
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
2063
+ _iterator1.return();
2064
+ }
2065
+ } finally{
2066
+ if (_didIteratorError1) {
2067
+ throw _iteratorError1;
2068
+ }
2069
+ }
2070
+ }
2071
+ if (typeof IntersectionObserver !== "undefined") {
2072
+ viewObserver = new IntersectionObserver(function(entries) {
2073
+ var entry = entries[entries.length - 1];
2074
+ if (entry) {
2075
+ visibleRatio = entry.isIntersecting ? entry.intersectionRatio : 0;
2076
+ }
2077
+ }, {
2078
+ threshold: [
2079
+ 0,
2080
+ 0.25,
2081
+ 0.5,
2082
+ 0.75,
2083
+ 1
2084
+ ]
2085
+ });
2086
+ viewObserver.observe(adContainerEl);
2087
+ }
2088
+ }
2089
+ function detachContainerHandlers() {
2090
+ if (adContainerEl) {
2091
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2092
+ try {
2093
+ for(var _iterator = containerHandlers[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2094
+ var _step_value = _step.value, type = _step_value.type, handler = _step_value.handler;
2095
+ adContainerEl.removeEventListener(type, handler);
2096
+ }
2097
+ } catch (err) {
2098
+ _didIteratorError = true;
2099
+ _iteratorError = err;
2100
+ } finally{
2101
+ try {
2102
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
2103
+ _iterator.return();
2104
+ }
2105
+ } finally{
2106
+ if (_didIteratorError) {
2107
+ throw _iteratorError;
2108
+ }
2109
+ }
2110
+ }
2111
+ }
2112
+ containerHandlers = [];
2113
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
2114
+ try {
2115
+ for(var _iterator1 = documentHandlers[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
2116
+ var _step_value1 = _step1.value, type1 = _step_value1.type, handler1 = _step_value1.handler;
2117
+ document.removeEventListener(type1, handler1);
2118
+ }
2119
+ } catch (err) {
2120
+ _didIteratorError1 = true;
2121
+ _iteratorError1 = err;
2122
+ } finally{
2123
+ try {
2124
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
2125
+ _iterator1.return();
2126
+ }
2127
+ } finally{
2128
+ if (_didIteratorError1) {
2129
+ throw _iteratorError1;
2130
+ }
2131
+ }
2132
+ }
2133
+ documentHandlers = [];
2134
+ viewObserver === null || viewObserver === void 0 ? void 0 : viewObserver.disconnect();
2135
+ viewObserver = void 0;
2136
+ }
1549
2137
  function setAdPlayingFlag(isPlaying) {
1550
2138
  if (isPlaying) {
1551
2139
  contentVideo.dataset.stormcloudAdPlaying = "true";
@@ -1553,15 +2141,10 @@ function createHlsAdPlayer(contentVideo, options) {
1553
2141
  delete contentVideo.dataset.stormcloudAdPlaying;
1554
2142
  }
1555
2143
  }
1556
- function resetQuartileTracking(preserveImpression) {
1557
- trackingFired = {
1558
- impression: preserveImpression ? trackingFired.impression : false,
1559
- start: false,
1560
- firstQuartile: false,
1561
- midpoint: false,
1562
- thirdQuartile: false,
1563
- complete: false
1564
- };
2144
+ function resetAdTracking() {
2145
+ trackingFired = createTrackingState();
2146
+ continuousVisibleS = 0;
2147
+ lastViewSampleTime = void 0;
1565
2148
  }
1566
2149
  function isRvfcSupported(video) {
1567
2150
  return typeof video.requestVideoFrameCallback === "function";
@@ -1667,13 +2250,12 @@ function createHlsAdPlayer(contentVideo, options) {
1667
2250
  if (podIndex >= podAds.length - 1) {
1668
2251
  return false;
1669
2252
  }
2253
+ settleViewability();
1670
2254
  podIndex++;
1671
2255
  currentAd = podAds[podIndex];
1672
2256
  currentAdMediaFile = void 0;
1673
- resetQuartileTracking(false);
2257
+ resetAdTracking();
1674
2258
  if (currentAd) {
1675
- fireTrackingPixels(currentAd.trackingUrls.impression);
1676
- trackingFired.impression = true;
1677
2259
  console.log("[HlsAdPlayer] Advancing to next pod ad (".concat(podIndex + 1, "/").concat(podAds.length, "): ").concat(currentAd.title, ", duration: ").concat(currentAd.duration, "s"));
1678
2260
  }
1679
2261
  clearStallWatchdog();
@@ -1711,11 +2293,7 @@ function createHlsAdPlayer(contentVideo, options) {
1711
2293
  function handleAdStall() {
1712
2294
  console.warn("[HlsAdPlayer] Ad playback stalled (no progress) - recovering to avoid a blank frame");
1713
2295
  clearStallWatchdog();
1714
- if (currentAd) {
1715
- fireTrackingPixels(currentAd.trackingUrls.error, {
1716
- errorCode: VAST_ERROR_MEDIA_DISPLAY
1717
- });
1718
- }
2296
+ reportCurrentAdError(VAST_ERROR_MEDIA_DISPLAY);
1719
2297
  if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1720
2298
  return;
1721
2299
  }
@@ -1781,11 +2359,7 @@ function createHlsAdPlayer(contentVideo, options) {
1781
2359
  function handleVideoDecodeFailure() {
1782
2360
  console.warn("[HlsAdPlayer] Ad audio is advancing but no video frames decoded (black screen) - skipping this creative");
1783
2361
  clearStallWatchdog();
1784
- if (currentAd) {
1785
- fireTrackingPixels(currentAd.trackingUrls.error, {
1786
- errorCode: VAST_ERROR_MEDIA_DISPLAY
1787
- });
1788
- }
2362
+ reportCurrentAdError(VAST_ERROR_MEDIA_DISPLAY);
1789
2363
  if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1790
2364
  return;
1791
2365
  }
@@ -1840,6 +2414,7 @@ function createHlsAdPlayer(contentVideo, options) {
1840
2414
  }
1841
2415
  function handleAdComplete() {
1842
2416
  console.log("[HlsAdPlayer] Handling ad completion");
2417
+ settleViewability();
1843
2418
  clearStallWatchdog();
1844
2419
  adPlaying = false;
1845
2420
  setAdPlayingFlag(false);
@@ -1863,6 +2438,7 @@ function createHlsAdPlayer(contentVideo, options) {
1863
2438
  }
1864
2439
  function handleAdError() {
1865
2440
  console.log("[HlsAdPlayer] Handling ad error");
2441
+ settleViewability();
1866
2442
  clearStallWatchdog();
1867
2443
  adPlaying = false;
1868
2444
  setAdPlayingFlag(false);
@@ -1895,6 +2471,7 @@ function createHlsAdPlayer(contentVideo, options) {
1895
2471
  adContainerEl = container;
1896
2472
  }
1897
2473
  contentVideo[AD_CONTAINER_PROP] = adContainerEl;
2474
+ attachContainerHandlers();
1898
2475
  },
1899
2476
  requestAds: function requestAds(vastTagUrl) {
1900
2477
  return _async_to_generator(function() {
@@ -1957,10 +2534,6 @@ function createHlsAdPlayer(contentVideo, options) {
1957
2534
  currentAd = ads[0];
1958
2535
  currentAdMediaFile = void 0;
1959
2536
  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"));
1960
- if (currentAd) {
1961
- fireTrackingPixels(currentAd.trackingUrls.impression);
1962
- trackingFired.impression = true;
1963
- }
1964
2537
  return [
1965
2538
  2,
1966
2539
  Promise.resolve()
@@ -2000,7 +2573,7 @@ function createHlsAdPlayer(contentVideo, options) {
2000
2573
  contentVideo[AD_VIDEO_PROP] = adVideoElement;
2001
2574
  }
2002
2575
  setupAdEventListeners();
2003
- resetQuartileTracking(true);
2576
+ resetAdTracking();
2004
2577
  contentVolume = contentVideo.volume;
2005
2578
  originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
2006
2579
  if (!(options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds)) {
@@ -2071,6 +2644,8 @@ function createHlsAdPlayer(contentVideo, options) {
2071
2644
  var previousMutedState;
2072
2645
  return _ts_generator(this, function(_state) {
2073
2646
  console.log("[HlsAdPlayer] Stopping ad");
2647
+ settleViewability();
2648
+ fireNotUsedForUnplayedAds();
2074
2649
  clearStallWatchdog();
2075
2650
  adPlaying = false;
2076
2651
  setAdPlayingFlag(false);
@@ -2101,6 +2676,8 @@ function createHlsAdPlayer(contentVideo, options) {
2101
2676
  },
2102
2677
  destroy: function destroy() {
2103
2678
  console.log("[HlsAdPlayer] Destroying");
2679
+ settleViewability();
2680
+ fireNotUsedForUnplayedAds();
2104
2681
  destroyed = true;
2105
2682
  clearStallWatchdog();
2106
2683
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
@@ -2129,6 +2706,7 @@ function createHlsAdPlayer(contentVideo, options) {
2129
2706
  contentVideo.muted = originalMutedState;
2130
2707
  contentVideo.volume = Math.max(0, Math.min(1, originalVolume));
2131
2708
  teardownAdEventListeners();
2709
+ detachContainerHandlers();
2132
2710
  releaseAdDecoder();
2133
2711
  currentAd = void 0;
2134
2712
  currentAdMediaFile = void 0;
@@ -2570,6 +3148,7 @@ function resolveVastEnvironmentSignals(isCtv) {
2570
3148
  limitAdTracking = (_ref1 = platformLat !== null && platformLat !== void 0 ? platformLat : readStoredLimitAdTracking()) !== null && _ref1 !== void 0 ? _ref1 : false;
2571
3149
  }
2572
3150
  }
3151
+ var deviceTypeHint = resolveDeviceTypeHint(isCtv);
2573
3152
  if (isCtv) {
2574
3153
  return _object_spread_props(_object_spread({
2575
3154
  isCtv: true,
@@ -2581,10 +3160,10 @@ function resolveVastEnvironmentSignals(isCtv) {
2581
3160
  } : {}, deviceId && limitAdTracking != null ? {
2582
3161
  limitAdTracking: limitAdTracking
2583
3162
  } : {}), {
2584
- deviceTypeHint: 5
3163
+ deviceTypeHint: deviceTypeHint
2585
3164
  });
2586
3165
  }
2587
- return _object_spread({
3166
+ return _object_spread_props(_object_spread({
2588
3167
  isCtv: false
2589
3168
  }, deviceId ? {
2590
3169
  deviceId: deviceId
@@ -2592,7 +3171,142 @@ function resolveVastEnvironmentSignals(isCtv) {
2592
3171
  deviceIdType: deviceIdType
2593
3172
  } : {}, deviceId && limitAdTracking != null ? {
2594
3173
  limitAdTracking: limitAdTracking
2595
- } : {});
3174
+ } : {}), {
3175
+ deviceTypeHint: deviceTypeHint
3176
+ });
3177
+ }
3178
+ var DEVICE_TYPE_HINT = {
3179
+ FEATURE_PHONE: 1,
3180
+ SMARTPHONE: 2,
3181
+ DESKTOP: 3,
3182
+ TABLET: 4,
3183
+ CONNECTED_TV: 5,
3184
+ GAME_CONSOLE: 6,
3185
+ SET_TOP_BOX: 7
3186
+ };
3187
+ var DEVICE_TYPE_HINT_ALIASES = {
3188
+ featurephone: DEVICE_TYPE_HINT.FEATURE_PHONE,
3189
+ smartphone: DEVICE_TYPE_HINT.SMARTPHONE,
3190
+ mobile: DEVICE_TYPE_HINT.SMARTPHONE,
3191
+ phone: DEVICE_TYPE_HINT.SMARTPHONE,
3192
+ desktop: DEVICE_TYPE_HINT.DESKTOP,
3193
+ pc: DEVICE_TYPE_HINT.DESKTOP,
3194
+ tablet: DEVICE_TYPE_HINT.TABLET,
3195
+ ctv: DEVICE_TYPE_HINT.CONNECTED_TV,
3196
+ tv: DEVICE_TYPE_HINT.CONNECTED_TV,
3197
+ connectedtv: DEVICE_TYPE_HINT.CONNECTED_TV,
3198
+ smarttv: DEVICE_TYPE_HINT.CONNECTED_TV,
3199
+ console: DEVICE_TYPE_HINT.GAME_CONSOLE,
3200
+ gameconsole: DEVICE_TYPE_HINT.GAME_CONSOLE,
3201
+ stb: DEVICE_TYPE_HINT.SET_TOP_BOX,
3202
+ settopbox: DEVICE_TYPE_HINT.SET_TOP_BOX
3203
+ };
3204
+ var SET_TOP_BOX_UA = /LGSTB|\bSTB\b|STB\d|Set-?Top|SetTopBox|TV ?Box|Kaon|Humax|Arris|Technicolor|Sagemcom|Infomir|MAG\d{3}|KreaTV|Amino|Formuler|Dune ?HD|TiVo|MiBOX|Mi Box|SHIELD Android TV|\bAFT[A-Z]|Roku|AppleTV|Apple TV|CrKey/i;
3205
+ var GAME_CONSOLE_UA = /PlayStation|Xbox|Nintendo/i;
3206
+ var CONNECTED_TV_UA = /Web0S|webOS|Tizen|SMART-TV|SmartTV|NetCast|BRAVIA|HbbTV|VIDAA|Hisense|Philips|Viera|AQUOS|Android TV|Google TV|\bTV\b/i;
3207
+ var FEATURE_PHONE_UA = /KAIOS|MIDP|J2ME|Series40|Opera Mini/i;
3208
+ function resolveDeviceTypeHint(isCtv) {
3209
+ var override = readDeviceTypeHintOverride();
3210
+ if (override != null) return override;
3211
+ return inferDeviceTypeHint(isCtv);
3212
+ }
3213
+ function inferDeviceTypeHint(isCtv) {
3214
+ var fallback = isCtv ? DEVICE_TYPE_HINT.CONNECTED_TV : DEVICE_TYPE_HINT.DESKTOP;
3215
+ if (typeof navigator === "undefined") return fallback;
3216
+ var ua = navigator.userAgent || "";
3217
+ var maxTouchPoints = navigator.maxTouchPoints || 0;
3218
+ if (SET_TOP_BOX_UA.test(ua)) return DEVICE_TYPE_HINT.SET_TOP_BOX;
3219
+ if (GAME_CONSOLE_UA.test(ua)) return DEVICE_TYPE_HINT.GAME_CONSOLE;
3220
+ if (CONNECTED_TV_UA.test(ua) && !/Mobile/i.test(ua)) {
3221
+ return DEVICE_TYPE_HINT.CONNECTED_TV;
3222
+ }
3223
+ if (FEATURE_PHONE_UA.test(ua)) return DEVICE_TYPE_HINT.FEATURE_PHONE;
3224
+ if (/iPad/i.test(ua) || /Macintosh/i.test(ua) && maxTouchPoints > 1) {
3225
+ return DEVICE_TYPE_HINT.TABLET;
3226
+ }
3227
+ if (/iPhone|iPod/i.test(ua)) return DEVICE_TYPE_HINT.SMARTPHONE;
3228
+ if (/Android/i.test(ua)) {
3229
+ if (/Mobile/i.test(ua)) return DEVICE_TYPE_HINT.SMARTPHONE;
3230
+ if (maxTouchPoints === 0) return DEVICE_TYPE_HINT.SET_TOP_BOX;
3231
+ return DEVICE_TYPE_HINT.TABLET;
3232
+ }
3233
+ if (/Mobile|Windows Phone|BlackBerry/i.test(ua)) return DEVICE_TYPE_HINT.SMARTPHONE;
3234
+ return fallback;
3235
+ }
3236
+ function readDeviceTypeHintOverride() {
3237
+ if (typeof window === "undefined") return void 0;
3238
+ var keys = [
3239
+ "dth",
3240
+ "deviceTypeHint"
3241
+ ];
3242
+ var fromGlobal = normalizeDeviceTypeHint(window.__STORMCLOUD_DTH__);
3243
+ if (fromGlobal != null) return fromGlobal;
3244
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
3245
+ try {
3246
+ for(var _iterator = getNativeBridgeSources()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
3247
+ var source = _step.value;
3248
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
3249
+ try {
3250
+ for(var _iterator1 = keys[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
3251
+ var key = _step1.value;
3252
+ var value = source === null || source === void 0 ? void 0 : source[key];
3253
+ var normalized = normalizeDeviceTypeHint(typeof value === "function" ? safeCall(value, source) : value);
3254
+ if (normalized != null) return normalized;
3255
+ }
3256
+ } catch (err) {
3257
+ _didIteratorError1 = true;
3258
+ _iteratorError1 = err;
3259
+ } finally{
3260
+ try {
3261
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
3262
+ _iterator1.return();
3263
+ }
3264
+ } finally{
3265
+ if (_didIteratorError1) {
3266
+ throw _iteratorError1;
3267
+ }
3268
+ }
3269
+ }
3270
+ }
3271
+ } catch (err) {
3272
+ _didIteratorError = true;
3273
+ _iteratorError = err;
3274
+ } finally{
3275
+ try {
3276
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
3277
+ _iterator.return();
3278
+ }
3279
+ } finally{
3280
+ if (_didIteratorError) {
3281
+ throw _iteratorError;
3282
+ }
3283
+ }
3284
+ }
3285
+ for(var _i = 0, _iter = [
3286
+ "stormcloud.dth",
3287
+ "dth"
3288
+ ]; _i < _iter.length; _i++){
3289
+ var key1 = _iter[_i];
3290
+ var normalized1 = normalizeDeviceTypeHint(readStoredString(key1));
3291
+ if (normalized1 != null) return normalized1;
3292
+ }
3293
+ return void 0;
3294
+ }
3295
+ function normalizeDeviceTypeHint(value) {
3296
+ if (typeof value === "number") {
3297
+ return Number.isInteger(value) && value >= 1 && value <= 7 ? value : void 0;
3298
+ }
3299
+ if (typeof value !== "string") return void 0;
3300
+ var trimmed = value.trim();
3301
+ if (/^[1-7]$/.test(trimmed)) return parseInt(trimmed, 10);
3302
+ return DEVICE_TYPE_HINT_ALIASES[trimmed.toLowerCase().replace(/[\s_-]/g, "")];
3303
+ }
3304
+ function safeCall(fn, thisArg) {
3305
+ try {
3306
+ return fn.call(thisArg);
3307
+ } catch (unused) {
3308
+ return void 0;
3309
+ }
2596
3310
  }
2597
3311
  function inferDeviceIdType() {
2598
3312
  if (typeof navigator === "undefined") {
@@ -2798,22 +3512,9 @@ function isZeroedAdId(value) {
2798
3512
  return ZEROED_AD_ID_PATTERNS.has(value.trim().toLowerCase());
2799
3513
  }
2800
3514
  function readNativeBridgeSignals() {
2801
- if (typeof window === "undefined") {
2802
- return {};
2803
- }
2804
- var candidates = [
2805
- window.__STORMCLOUD_CTV_AD_INFO__,
2806
- window.__STORMCLOUD_CTV__,
2807
- window.stormcloudCtv,
2808
- window.AiryTV,
2809
- window.Android,
2810
- window.webOS,
2811
- window.tizen,
2812
- window.amazon
2813
- ].filter(Boolean);
2814
3515
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2815
3516
  try {
2816
- for(var _iterator = candidates[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
3517
+ for(var _iterator = getNativeBridgeSources()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2817
3518
  var source = _step.value;
2818
3519
  var contentUrl = readBridgeValue(source, [
2819
3520
  "contentUrl",
@@ -2888,6 +3589,21 @@ function readNativeBridgeSignals() {
2888
3589
  }
2889
3590
  return {};
2890
3591
  }
3592
+ function getNativeBridgeSources() {
3593
+ if (typeof window === "undefined") {
3594
+ return [];
3595
+ }
3596
+ return [
3597
+ window.__STORMCLOUD_CTV_AD_INFO__,
3598
+ window.__STORMCLOUD_CTV__,
3599
+ window.stormcloudCtv,
3600
+ window.AiryTV,
3601
+ window.Android,
3602
+ window.webOS,
3603
+ window.tizen,
3604
+ window.amazon
3605
+ ].filter(Boolean);
3606
+ }
2891
3607
  function readBridgeValue(source, keys) {
2892
3608
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2893
3609
  try {
@@ -7344,6 +8060,12 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7344
8060
  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 : "?"));
7345
8061
  }
7346
8062
  });
8063
+ adPlayer.on("ad_click", function() {
8064
+ _this.host.onAdClick();
8065
+ });
8066
+ adPlayer.on("ad_interaction", function(event) {
8067
+ if (event) _this.host.onAdInteraction(event);
8068
+ });
7347
8069
  adPlayer.on("all_ads_completed", function() {
7348
8070
  sendAdImpressionTracking(_this.host.config.licenseKey, {
7349
8071
  source: "hls",
@@ -8873,6 +9595,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8873
9595
  },
8874
9596
  generatePodVastUrl: function generatePodVastUrl(base, breakDurationMs) {
8875
9597
  return _this.generatePodVastUrl(base, breakDurationMs);
9598
+ },
9599
+ onAdClick: function onAdClick() {
9600
+ return _this.palNonce.sendAdClick();
9601
+ },
9602
+ onAdInteraction: function onAdInteraction(event) {
9603
+ return _this.palNonce.sendAdTouch(event);
8876
9604
  }
8877
9605
  }, this.timing, this.adConfig, this.cueManager, this.placeholder);
8878
9606
  }