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
@@ -648,6 +648,7 @@ var KNOWN_VAST_MACROS = /* @__PURE__ */ new Set([
648
648
  "PLAYERSIZE",
649
649
  "PLAYERSTATE",
650
650
  "PODSEQUENCE",
651
+ "REASON",
651
652
  "REGULATIONS",
652
653
  "SERVERSIDE",
653
654
  "SERVERUA",
@@ -706,6 +707,10 @@ function resolveMacroValues(ctx) {
706
707
  if (ctx.podSequence != null) {
707
708
  set("PODSEQUENCE", String(ctx.podSequence));
708
709
  }
710
+ set("ADSERVINGID", ctx.adServingId);
711
+ if (ctx.reason != null && ctx.reason !== "") {
712
+ set("REASON", String(ctx.reason));
713
+ }
709
714
  return values;
710
715
  }
711
716
  function substituteVastTrackingMacros(url) {
@@ -722,10 +727,72 @@ function substituteVastTrackingMacros(url) {
722
727
  });
723
728
  }
724
729
  // src/sdk/hlsAdPlayer.ts
730
+ var LINEAR_TRACKING_EVENTS = [
731
+ "creativeView",
732
+ "loaded",
733
+ "start",
734
+ "firstQuartile",
735
+ "midpoint",
736
+ "thirdQuartile",
737
+ "complete",
738
+ "mute",
739
+ "unmute",
740
+ "pause",
741
+ "resume",
742
+ "fullscreen",
743
+ "exitFullscreen",
744
+ "playerExpand",
745
+ "playerCollapse",
746
+ "notUsed"
747
+ ];
748
+ function textOf(el) {
749
+ var _el_textContent;
750
+ var value = el === null || el === void 0 ? void 0 : (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
751
+ return value ? value : void 0;
752
+ }
753
+ function parseVastTime(value) {
754
+ if (!value) return void 0;
755
+ var parts = value.trim().split(":");
756
+ if (parts.length !== 3) return void 0;
757
+ var _parts_map = _sliced_to_array(parts.map(function(p) {
758
+ return parseFloat(p);
759
+ }), 3), h = _parts_map[0], m = _parts_map[1], s = _parts_map[2];
760
+ if (![
761
+ h,
762
+ m,
763
+ s
764
+ ].every(function(n) {
765
+ return n !== void 0 && Number.isFinite(n);
766
+ })) {
767
+ return void 0;
768
+ }
769
+ return h * 3600 + m * 60 + s;
770
+ }
771
+ function parseProgressOffset(offset) {
772
+ if (!offset) return void 0;
773
+ var trimmed = offset.trim();
774
+ if (trimmed.endsWith("%")) {
775
+ var percent = parseFloat(trimmed);
776
+ return Number.isFinite(percent) ? {
777
+ offsetPercent: percent
778
+ } : void 0;
779
+ }
780
+ var seconds = parseVastTime(trimmed);
781
+ return seconds !== void 0 ? {
782
+ offsetSeconds: seconds
783
+ } : void 0;
784
+ }
725
785
  var MAX_VAST_WRAPPER_DEPTH = 5;
726
786
  var BEACON_TIMEOUT_MS = 3e4;
727
787
  var inFlightBeacons = /* @__PURE__ */ new Set();
728
788
  var VAST_ERROR_MEDIA_DISPLAY = 405;
789
+ var VAST_ERROR_WRAPPER_TIMEOUT = 301;
790
+ var VAST_ERROR_WRAPPER_LIMIT = 302;
791
+ var VAST_ERROR_WRAPPER_NO_ADS = 303;
792
+ var VAST_ERROR_NO_SUPPORTED_MEDIA = 403;
793
+ var VERIFICATION_NOT_SUPPORTED_REASON = 2;
794
+ var VIEWABLE_MIN_VISIBLE_RATIO = 0.5;
795
+ var VIEWABLE_MIN_CONTINUOUS_S = 2;
729
796
  function toVastMediaErrorCode(error) {
730
797
  switch(error === null || error === void 0 ? void 0 : error.code){
731
798
  case 1:
@@ -753,6 +820,7 @@ function createHlsAdPlayer(contentVideo, options) {
753
820
  var adHls;
754
821
  var adContainerEl = (_contentVideo_AD_CONTAINER_PROP = contentVideo[AD_CONTAINER_PROP]) !== null && _contentVideo_AD_CONTAINER_PROP !== void 0 ? _contentVideo_AD_CONTAINER_PROP : void 0;
755
822
  var adEventHandlers = [];
823
+ var containerHandlers = [];
756
824
  var currentAd;
757
825
  var currentAdMediaFile;
758
826
  var podAds = [];
@@ -770,14 +838,28 @@ function createHlsAdPlayer(contentVideo, options) {
770
838
  var sawDecodedVideoFrame = false;
771
839
  var videoFrameCallbackHandle;
772
840
  var pendingPlayPromise;
773
- var trackingFired = {
774
- impression: false,
775
- start: false,
776
- firstQuartile: false,
777
- midpoint: false,
778
- thirdQuartile: false,
779
- complete: false
780
- };
841
+ function createTrackingState() {
842
+ return {
843
+ impression: false,
844
+ loaded: false,
845
+ start: false,
846
+ firstQuartile: false,
847
+ midpoint: false,
848
+ thirdQuartile: false,
849
+ complete: false,
850
+ viewabilitySettled: false,
851
+ lastMuted: void 0,
852
+ progressFired: /* @__PURE__ */ new Set()
853
+ };
854
+ }
855
+ var trackingFired = createTrackingState();
856
+ var resolvedAds = /* @__PURE__ */ new Set();
857
+ var viewObserver;
858
+ var visibleRatio = 0;
859
+ var continuousVisibleS = 0;
860
+ var lastViewSampleTime;
861
+ var lastPlayerExpanded = false;
862
+ var documentHandlers = [];
781
863
  function emit(event, payload) {
782
864
  var set = listeners.get(event);
783
865
  if (!set) return;
@@ -806,7 +888,11 @@ function createHlsAdPlayer(contentVideo, options) {
806
888
  }
807
889
  }
808
890
  }
809
- function buildTrackingMacroContext(errorCode) {
891
+ function buildTrackingMacroContext() {
892
+ var options2 = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
893
+ var _options2_ad;
894
+ var errorCode = options2.errorCode, reason = options2.reason;
895
+ var ad = (_options2_ad = options2.ad) !== null && _options2_ad !== void 0 ? _options2_ad : currentAd;
810
896
  var context = {
811
897
  adPlayheadSeconds: adVideoElement === null || adVideoElement === void 0 ? void 0 : adVideoElement.currentTime,
812
898
  contentPlayheadSeconds: contentVideo.currentTime,
@@ -827,11 +913,17 @@ function createHlsAdPlayer(contentVideo, options) {
827
913
  if (podAds.length > 0) {
828
914
  context.podSequence = podIndex + 1;
829
915
  }
916
+ if (ad === null || ad === void 0 ? void 0 : ad.adServingId) {
917
+ context.adServingId = ad.adServingId;
918
+ }
919
+ if (reason != null) {
920
+ context.reason = reason;
921
+ }
830
922
  return context;
831
923
  }
832
924
  function fireTrackingPixels(urls, options2) {
833
925
  if (!urls || urls.length === 0) return;
834
- var macroContext = buildTrackingMacroContext(options2 === null || options2 === void 0 ? void 0 : options2.errorCode);
926
+ var macroContext = buildTrackingMacroContext(options2);
835
927
  urls.forEach(function(url) {
836
928
  try {
837
929
  var trackingUrl = substituteVastTrackingMacros(url, macroContext);
@@ -942,8 +1034,8 @@ function createHlsAdPlayer(contentVideo, options) {
942
1034
  var url = (mediaFile.url.toLowerCase().split("?")[0] || "").trim();
943
1035
  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");
944
1036
  }
945
- function collectVideoMediaFiles(scope, verbose) {
946
- var mediaFileElements = scope.querySelectorAll("MediaFile");
1037
+ function collectVideoMediaFiles(linear, verbose) {
1038
+ var mediaFileElements = linear.querySelectorAll(":scope > MediaFiles > MediaFile");
947
1039
  var mediaFiles = [];
948
1040
  if (verbose) {
949
1041
  console.log("[HlsAdPlayer] Found ".concat(mediaFileElements.length, " MediaFile element(s) in VAST XML"));
@@ -963,6 +1055,13 @@ function createHlsAdPlayer(contentVideo, options) {
963
1055
  }
964
1056
  return;
965
1057
  }
1058
+ var apiFramework = (mf.getAttribute("apiFramework") || "").toUpperCase();
1059
+ if (apiFramework === "VPAID") {
1060
+ if (verbose) {
1061
+ console.log("[HlsAdPlayer] MediaFile ".concat(index, " ignored (VPAID creatives are not supported)"));
1062
+ }
1063
+ return;
1064
+ }
966
1065
  var bitrateAttr = mf.getAttribute("bitrate");
967
1066
  var bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;
968
1067
  var mediaFile = {
@@ -993,114 +1092,144 @@ function createHlsAdPlayer(contentVideo, options) {
993
1092
  return mediaFiles;
994
1093
  }
995
1094
  function createEmptyTrackingUrls() {
996
- return {
1095
+ var urls = {
997
1096
  impression: [],
998
- start: [],
999
- firstQuartile: [],
1000
- midpoint: [],
1001
- thirdQuartile: [],
1002
- complete: [],
1003
- mute: [],
1004
- unmute: [],
1005
- pause: [],
1006
- resume: [],
1007
- fullscreen: [],
1008
- exitFullscreen: [],
1009
- skip: [],
1010
- error: []
1097
+ clickTracking: [],
1098
+ error: [],
1099
+ viewable: [],
1100
+ notViewable: [],
1101
+ viewUndetermined: [],
1102
+ verificationNotExecuted: [],
1103
+ progress: []
1011
1104
  };
1105
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1106
+ try {
1107
+ for(var _iterator = LINEAR_TRACKING_EVENTS[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1108
+ var event = _step.value;
1109
+ urls[event] = [];
1110
+ }
1111
+ } catch (err) {
1112
+ _didIteratorError = true;
1113
+ _iteratorError = err;
1114
+ } finally{
1115
+ try {
1116
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1117
+ _iterator.return();
1118
+ }
1119
+ } finally{
1120
+ if (_didIteratorError) {
1121
+ throw _iteratorError;
1122
+ }
1123
+ }
1124
+ }
1125
+ return urls;
1012
1126
  }
1013
- function extractTrackingUrls(scope) {
1014
- var trackingUrls = createEmptyTrackingUrls();
1015
- scope.querySelectorAll("Impression").forEach(function(el) {
1016
- var _el_textContent;
1017
- var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
1018
- if (url) trackingUrls.impression.push(url);
1127
+ function pushUrls(target, elements) {
1128
+ elements.forEach(function(el) {
1129
+ var url = textOf(el);
1130
+ if (url) target.push(url);
1019
1131
  });
1020
- scope.querySelectorAll("Tracking").forEach(function(el) {
1021
- var _el_textContent;
1132
+ }
1133
+ function collectLinearTracking(linear, into) {
1134
+ linear.querySelectorAll(":scope > TrackingEvents > Tracking").forEach(function(el) {
1022
1135
  var event = el.getAttribute("event");
1023
- var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
1024
- if (event && url) {
1025
- var eventKey = event;
1026
- if (trackingUrls[eventKey]) {
1027
- trackingUrls[eventKey].push(url);
1028
- }
1136
+ var url = textOf(el);
1137
+ if (!event || !url) return;
1138
+ if (event === "progress") {
1139
+ var offset = parseProgressOffset(el.getAttribute("offset"));
1140
+ if (offset) into.progress.push(_object_spread({
1141
+ url: url
1142
+ }, offset));
1143
+ return;
1144
+ }
1145
+ if (LINEAR_TRACKING_EVENTS.indexOf(event) !== -1) {
1146
+ into[event].push(url);
1029
1147
  }
1030
1148
  });
1031
- scope.querySelectorAll("Error").forEach(function(el) {
1032
- var _el_textContent;
1033
- var url = (_el_textContent = el.textContent) === null || _el_textContent === void 0 ? void 0 : _el_textContent.trim();
1034
- if (url) trackingUrls.error.push(url);
1149
+ pushUrls(into.clickTracking, linear.querySelectorAll(":scope > VideoClicks > ClickTracking"));
1150
+ }
1151
+ function collectAdLevelTracking(adBody, into) {
1152
+ pushUrls(into.impression, adBody.querySelectorAll(":scope > Impression"));
1153
+ pushUrls(into.error, adBody.querySelectorAll(":scope > Error"));
1154
+ pushUrls(into.viewable, adBody.querySelectorAll(":scope > ViewableImpression > Viewable"));
1155
+ pushUrls(into.notViewable, adBody.querySelectorAll(":scope > ViewableImpression > NotViewable"));
1156
+ pushUrls(into.viewUndetermined, adBody.querySelectorAll(":scope > ViewableImpression > ViewUndetermined"));
1157
+ adBody.querySelectorAll(':scope > AdVerifications > Verification, :scope > Extensions > Extension[type="AdVerifications"] > AdVerifications > Verification').forEach(function(verification) {
1158
+ pushUrls(into.verificationNotExecuted, verification.querySelectorAll(':scope > TrackingEvents > Tracking[event="verificationNotExecuted"]'));
1035
1159
  });
1036
- return trackingUrls;
1037
1160
  }
1038
1161
  function mergeTrackingUrls(target, source) {
1039
- Object.keys(target).forEach(function(key) {
1040
- if (source[key] && source[key].length > 0) {
1041
- target[key] = target[key].concat(source[key]);
1162
+ var targetLists = target;
1163
+ var sourceLists = source;
1164
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1165
+ try {
1166
+ for(var _iterator = Object.keys(targetLists)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1167
+ var key = _step.value;
1168
+ var incoming = sourceLists[key];
1169
+ if (incoming && incoming.length > 0) {
1170
+ targetLists[key] = targetLists[key].concat(incoming);
1171
+ }
1042
1172
  }
1043
- });
1173
+ } catch (err) {
1174
+ _didIteratorError = true;
1175
+ _iteratorError = err;
1176
+ } finally{
1177
+ try {
1178
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1179
+ _iterator.return();
1180
+ }
1181
+ } finally{
1182
+ if (_didIteratorError) {
1183
+ throw _iteratorError;
1184
+ }
1185
+ }
1186
+ }
1044
1187
  return target;
1045
1188
  }
1189
+ function parseXml(xmlString) {
1190
+ var xmlDoc = new DOMParser().parseFromString(xmlString, "text/xml");
1191
+ var parserError = xmlDoc.querySelector("parsererror");
1192
+ if (parserError) {
1193
+ console.error("[HlsAdPlayer] XML parsing error (malformed VAST XML):", parserError.textContent);
1194
+ return null;
1195
+ }
1196
+ return xmlDoc;
1197
+ }
1198
+ function getAdSequence(adElement) {
1199
+ var sequence = parseInt(adElement.getAttribute("sequence") || "", 10);
1200
+ return Number.isFinite(sequence) ? sequence : void 0;
1201
+ }
1202
+ function emptyVastResult(root) {
1203
+ var errorUrls = [];
1204
+ pushUrls(errorUrls, root.querySelectorAll(":scope > Error"));
1205
+ return {
1206
+ type: "empty",
1207
+ errorUrls: errorUrls,
1208
+ errorCode: VAST_ERROR_WRAPPER_NO_ADS
1209
+ };
1210
+ }
1046
1211
  function parseVastXml(xmlString) {
1047
1212
  try {
1048
- var _xmlDoc_querySelector, _xmlDoc_querySelector_textContent, _xmlDoc_querySelector1, _xmlDoc_querySelector_textContent1, _xmlDoc_querySelector2, _xmlDoc_querySelector3;
1049
- var parser = new DOMParser();
1050
- var xmlDoc = parser.parseFromString(xmlString, "text/xml");
1051
- var parserError = xmlDoc.querySelector("parsererror");
1052
- if (parserError) {
1053
- console.error("[HlsAdPlayer] XML parsing error (malformed VAST XML):", parserError.textContent);
1054
- return {
1055
- type: "empty"
1056
- };
1057
- }
1058
- var adElement = xmlDoc.querySelector("Ad");
1213
+ var _adElements_find;
1214
+ var xmlDoc = parseXml(xmlString);
1215
+ if (!xmlDoc) return {
1216
+ type: "empty"
1217
+ };
1218
+ var root = xmlDoc.documentElement;
1219
+ var adElements = Array.from(root.querySelectorAll(":scope > Ad"));
1220
+ var adElement = (_adElements_find = adElements.find(function(el) {
1221
+ return getAdSequence(el) === void 0;
1222
+ })) !== null && _adElements_find !== void 0 ? _adElements_find : adElements[0];
1059
1223
  if (!adElement) {
1060
- console.warn("[HlsAdPlayer] No Ad element found in VAST XML");
1061
- return {
1062
- type: "empty"
1063
- };
1224
+ var _root_getAttribute;
1225
+ console.warn("[HlsAdPlayer] No Ad element found in VAST ".concat((_root_getAttribute = root.getAttribute("version")) !== null && _root_getAttribute !== void 0 ? _root_getAttribute : "", " response"));
1226
+ return emptyVastResult(root);
1064
1227
  }
1065
- var adId = adElement.getAttribute("id") || "unknown";
1066
- var title = ((_xmlDoc_querySelector = xmlDoc.querySelector("AdTitle")) === null || _xmlDoc_querySelector === void 0 ? void 0 : _xmlDoc_querySelector.textContent) || "Ad";
1067
- 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();
1068
- 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();
1069
- if (wrapperUri) {
1070
- console.log("[HlsAdPlayer] VAST wrapper detected, following VASTAdTagURI: ".concat(wrapperUri));
1071
- return {
1072
- type: "wrapper",
1073
- vastAdTagUri: wrapperUri,
1074
- trackingUrls: extractTrackingUrls(xmlDoc),
1075
- clickThrough: clickThrough
1076
- };
1228
+ var parsed = parseAdElement(adElement, true);
1229
+ if (parsed.type === "wrapper") {
1230
+ console.log("[HlsAdPlayer] VAST wrapper detected, following VASTAdTagURI: ".concat(parsed.vastAdTagUri));
1077
1231
  }
1078
- var isNoAdAvailable = adId === "empty" || title.toLowerCase().includes("no ad available") || title.toLowerCase() === "no ad available";
1079
- var durationText = ((_xmlDoc_querySelector3 = xmlDoc.querySelector("Duration")) === null || _xmlDoc_querySelector3 === void 0 ? void 0 : _xmlDoc_querySelector3.textContent) || "00:00:30";
1080
- var durationParts = durationText.split(":");
1081
- var duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseInt(durationParts[2] || "0", 10);
1082
- var mediaFiles = collectVideoMediaFiles(xmlDoc, true);
1083
- if (mediaFiles.length === 0) {
1084
- if (isNoAdAvailable) {
1085
- console.warn("[HlsAdPlayer] No ads available (VAST response indicates no ads)");
1086
- } else {
1087
- console.warn("[HlsAdPlayer] No supported media files found in VAST XML");
1088
- }
1089
- return {
1090
- type: "empty"
1091
- };
1092
- }
1093
- return {
1094
- type: "inline",
1095
- ad: {
1096
- id: adId,
1097
- title: title,
1098
- duration: duration,
1099
- mediaFiles: mediaFiles,
1100
- trackingUrls: extractTrackingUrls(xmlDoc),
1101
- clickThrough: clickThrough
1102
- }
1103
- };
1232
+ return parsed;
1104
1233
  } catch (error) {
1105
1234
  console.error("[HlsAdPlayer] Error parsing VAST XML:", error);
1106
1235
  return {
@@ -1109,48 +1238,101 @@ function createHlsAdPlayer(contentVideo, options) {
1109
1238
  }
1110
1239
  }
1111
1240
  function parseAdElement(adElement) {
1241
+ var verbose = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : false;
1112
1242
  try {
1113
- var _adElement_querySelector, _adElement_querySelector_textContent, _adElement_querySelector1, _adElement_querySelector_textContent1, _adElement_querySelector2, _adElement_querySelector3;
1114
- var adId = adElement.getAttribute("id") || "unknown";
1115
- var title = ((_adElement_querySelector = adElement.querySelector("AdTitle")) === null || _adElement_querySelector === void 0 ? void 0 : _adElement_querySelector.textContent) || "Ad";
1116
- 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();
1117
- 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();
1118
- if (wrapperUri) {
1243
+ var _parseVastTime;
1244
+ var wrapper = adElement.querySelector(":scope > Wrapper");
1245
+ if (wrapper) {
1246
+ var vastAdTagUri = textOf(wrapper.querySelector(":scope > VASTAdTagURI"));
1247
+ if (!vastAdTagUri) {
1248
+ console.warn("[HlsAdPlayer] <Wrapper> has no VASTAdTagURI");
1249
+ return {
1250
+ type: "empty"
1251
+ };
1252
+ }
1253
+ var trackingUrls2 = createEmptyTrackingUrls();
1254
+ collectAdLevelTracking(wrapper, trackingUrls2);
1255
+ wrapper.querySelectorAll(":scope > Creatives > Creative > Linear").forEach(function(linear2) {
1256
+ return collectLinearTracking(linear2, trackingUrls2);
1257
+ });
1119
1258
  return {
1120
1259
  type: "wrapper",
1121
- vastAdTagUri: wrapperUri,
1122
- trackingUrls: extractTrackingUrls(adElement),
1123
- clickThrough: clickThrough
1260
+ vastAdTagUri: vastAdTagUri,
1261
+ trackingUrls: trackingUrls2,
1262
+ rules: {
1263
+ followAdditionalWrappers: wrapper.getAttribute("followAdditionalWrappers") !== "false"
1264
+ }
1124
1265
  };
1125
1266
  }
1126
- var isNoAdAvailable = adId === "empty" || title.toLowerCase().includes("no ad available") || title.toLowerCase() === "no ad available";
1127
- var durationText = ((_adElement_querySelector3 = adElement.querySelector("Duration")) === null || _adElement_querySelector3 === void 0 ? void 0 : _adElement_querySelector3.textContent) || "00:00:30";
1128
- var durationParts = durationText.split(":");
1129
- var duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseInt(durationParts[2] || "0", 10);
1130
- var mediaFiles = collectVideoMediaFiles(adElement, false);
1131
- if (mediaFiles.length === 0) {
1132
- if (isNoAdAvailable) {
1133
- console.warn("[HlsAdPlayer] Pod <Ad> indicates no ad available");
1134
- } else {
1135
- console.warn("[HlsAdPlayer] No supported media files in pod <Ad>");
1136
- }
1267
+ var inLine = adElement.querySelector(":scope > InLine");
1268
+ if (!inLine) {
1269
+ console.warn("[HlsAdPlayer] <Ad> has neither <InLine> nor <Wrapper>");
1137
1270
  return {
1138
1271
  type: "empty"
1139
1272
  };
1140
1273
  }
1274
+ var errorUrls = [];
1275
+ pushUrls(errorUrls, inLine.querySelectorAll(":scope > Error"));
1276
+ if (adElement.getAttribute("conditionalAd") === "true") {
1277
+ console.warn("[HlsAdPlayer] Skipping conditional <Ad> (VPAID-only)");
1278
+ return {
1279
+ type: "empty",
1280
+ errorUrls: errorUrls,
1281
+ errorCode: VAST_ERROR_NO_SUPPORTED_MEDIA
1282
+ };
1283
+ }
1284
+ var linear;
1285
+ var mediaFiles = [];
1286
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1287
+ try {
1288
+ for(var _iterator = Array.from(inLine.querySelectorAll(":scope > Creatives > Creative > Linear"))[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1289
+ var candidate = _step.value;
1290
+ var files = collectVideoMediaFiles(candidate, verbose);
1291
+ if (files.length > 0) {
1292
+ linear = candidate;
1293
+ mediaFiles = files;
1294
+ break;
1295
+ }
1296
+ }
1297
+ } catch (err) {
1298
+ _didIteratorError = true;
1299
+ _iteratorError = err;
1300
+ } finally{
1301
+ try {
1302
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1303
+ _iterator.return();
1304
+ }
1305
+ } finally{
1306
+ if (_didIteratorError) {
1307
+ throw _iteratorError;
1308
+ }
1309
+ }
1310
+ }
1311
+ if (!linear) {
1312
+ console.warn("[HlsAdPlayer] No supported linear media files in <Ad>");
1313
+ return {
1314
+ type: "empty",
1315
+ errorUrls: errorUrls,
1316
+ errorCode: VAST_ERROR_NO_SUPPORTED_MEDIA
1317
+ };
1318
+ }
1319
+ var trackingUrls = createEmptyTrackingUrls();
1320
+ collectAdLevelTracking(inLine, trackingUrls);
1321
+ collectLinearTracking(linear, trackingUrls);
1141
1322
  return {
1142
1323
  type: "inline",
1143
1324
  ad: {
1144
- id: adId,
1145
- title: title,
1146
- duration: duration,
1325
+ id: adElement.getAttribute("id") || "unknown",
1326
+ title: textOf(inLine.querySelector(":scope > AdTitle")) || "Ad",
1327
+ duration: (_parseVastTime = parseVastTime(textOf(linear.querySelector(":scope > Duration")))) !== null && _parseVastTime !== void 0 ? _parseVastTime : 30,
1147
1328
  mediaFiles: mediaFiles,
1148
- trackingUrls: extractTrackingUrls(adElement),
1149
- clickThrough: clickThrough
1329
+ trackingUrls: trackingUrls,
1330
+ clickThrough: textOf(linear.querySelector(":scope > VideoClicks > ClickThrough")),
1331
+ adServingId: textOf(inLine.querySelector(":scope > AdServingId"))
1150
1332
  }
1151
1333
  };
1152
1334
  } catch (error) {
1153
- console.error("[HlsAdPlayer] Error parsing pod <Ad> element:", error);
1335
+ console.error("[HlsAdPlayer] Error parsing <Ad> element:", error);
1154
1336
  return {
1155
1337
  type: "empty"
1156
1338
  };
@@ -1229,30 +1411,63 @@ function createHlsAdPlayer(contentVideo, options) {
1229
1411
  }
1230
1412
  function fetchAndParseVastAd(_0) {
1231
1413
  return _async_to_generator(function(vastTagUrl) {
1232
- var depth, accumulatedTracking, vastXml, parsed;
1414
+ var depth, accumulatedTracking, rules, vastXml, error, parsed, _parsed_errorUrls, _parsed_errorCode;
1233
1415
  var _arguments = arguments;
1234
1416
  return _ts_generator(this, function(_state) {
1235
1417
  switch(_state.label){
1236
1418
  case 0:
1237
- depth = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : 0, accumulatedTracking = _arguments.length > 2 && _arguments[2] !== void 0 ? _arguments[2] : createEmptyTrackingUrls();
1419
+ 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] : {
1420
+ followAdditionalWrappers: true
1421
+ };
1422
+ _state.label = 1;
1423
+ case 1:
1424
+ _state.trys.push([
1425
+ 1,
1426
+ 3,
1427
+ ,
1428
+ 4
1429
+ ]);
1238
1430
  return [
1239
1431
  4,
1240
1432
  fetchVastXml(vastTagUrl, depth === 0 ? "include" : "omit")
1241
1433
  ];
1242
- case 1:
1434
+ case 2:
1243
1435
  vastXml = _state.sent();
1436
+ return [
1437
+ 3,
1438
+ 4
1439
+ ];
1440
+ case 3:
1441
+ error = _state.sent();
1442
+ if (depth === 0) throw error;
1443
+ console.warn("[HlsAdPlayer] Wrapped VAST request failed:", error);
1444
+ fireTrackingPixels(accumulatedTracking.error, {
1445
+ errorCode: VAST_ERROR_WRAPPER_TIMEOUT
1446
+ });
1447
+ return [
1448
+ 2,
1449
+ null
1450
+ ];
1451
+ case 4:
1244
1452
  console.log("[HlsAdPlayer] VAST XML received");
1245
1453
  console.log("[HlsAdPlayer] VAST XML content (first 2000 chars):", vastXml.substring(0, 2e3));
1246
1454
  parsed = parseVastXml(vastXml);
1247
1455
  if (parsed.type === "empty") {
1456
+ ;
1457
+ fireTrackingPixels(((_parsed_errorUrls = parsed.errorUrls) !== null && _parsed_errorUrls !== void 0 ? _parsed_errorUrls : []).concat(accumulatedTracking.error), {
1458
+ errorCode: (_parsed_errorCode = parsed.errorCode) !== null && _parsed_errorCode !== void 0 ? _parsed_errorCode : VAST_ERROR_WRAPPER_NO_ADS
1459
+ });
1248
1460
  return [
1249
1461
  2,
1250
1462
  null
1251
1463
  ];
1252
1464
  }
1253
1465
  if (parsed.type === "wrapper") {
1254
- if (depth >= MAX_VAST_WRAPPER_DEPTH) {
1255
- console.warn("[HlsAdPlayer] VAST wrapper depth limit (".concat(MAX_VAST_WRAPPER_DEPTH, ") reached, aborting redirect chain"));
1466
+ if (depth >= MAX_VAST_WRAPPER_DEPTH || !rules.followAdditionalWrappers) {
1467
+ 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');
1468
+ fireTrackingPixels(accumulatedTracking.error.concat(parsed.trackingUrls.error), {
1469
+ errorCode: VAST_ERROR_WRAPPER_LIMIT
1470
+ });
1256
1471
  return [
1257
1472
  2,
1258
1473
  null
@@ -1261,7 +1476,7 @@ function createHlsAdPlayer(contentVideo, options) {
1261
1476
  mergeTrackingUrls(accumulatedTracking, parsed.trackingUrls);
1262
1477
  return [
1263
1478
  2,
1264
- fetchAndParseVastAd(parsed.vastAdTagUri, depth + 1, accumulatedTracking)
1479
+ fetchAndParseVastAd(parsed.vastAdTagUri, depth + 1, accumulatedTracking, parsed.rules)
1265
1480
  ];
1266
1481
  }
1267
1482
  mergeTrackingUrls(parsed.ad.trackingUrls, accumulatedTracking);
@@ -1275,7 +1490,7 @@ function createHlsAdPlayer(contentVideo, options) {
1275
1490
  }
1276
1491
  function fetchAndParsePod(vastTagUrl) {
1277
1492
  return _async_to_generator(function() {
1278
- var vastXml, trimmedXml, parser, xmlDoc, adElements, ads, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, adElement, parsed, resolved, error, err;
1493
+ 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;
1279
1494
  return _ts_generator(this, function(_state) {
1280
1495
  switch(_state.label){
1281
1496
  case 0:
@@ -1294,125 +1509,212 @@ function createHlsAdPlayer(contentVideo, options) {
1294
1509
  []
1295
1510
  ];
1296
1511
  }
1297
- parser = new DOMParser();
1298
- xmlDoc = parser.parseFromString(vastXml, "text/xml");
1299
- if (xmlDoc.querySelector("parsererror")) {
1300
- console.error("[HlsAdPlayer] Pod VAST XML parsing error (malformed). Content (first 2000 chars):", vastXml.substring(0, 2e3));
1512
+ xmlDoc = parseXml(vastXml);
1513
+ if (!xmlDoc) {
1514
+ console.error("[HlsAdPlayer] Pod VAST XML content (first 2000 chars):", vastXml.substring(0, 2e3));
1301
1515
  return [
1302
1516
  2,
1303
1517
  []
1304
1518
  ];
1305
1519
  }
1306
- adElements = Array.from(xmlDoc.querySelectorAll("Ad"));
1520
+ root = xmlDoc.documentElement;
1521
+ adElements = Array.from(root.querySelectorAll(":scope > Ad"));
1307
1522
  if (adElements.length === 0) {
1308
- console.warn("[HlsAdPlayer] No <Ad> elements found in pod VAST response (no fill). Content (first 2000 chars):", vastXml.substring(0, 2e3));
1523
+ ;
1524
+ ;
1525
+ 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)"));
1526
+ empty = emptyVastResult(root);
1527
+ if (empty.type === "empty" && ((_empty_errorUrls = empty.errorUrls) === null || _empty_errorUrls === void 0 ? void 0 : _empty_errorUrls.length)) {
1528
+ ;
1529
+ fireTrackingPixels(empty.errorUrls, {
1530
+ errorCode: (_empty_errorCode = empty.errorCode) !== null && _empty_errorCode !== void 0 ? _empty_errorCode : VAST_ERROR_WRAPPER_NO_ADS
1531
+ });
1532
+ }
1309
1533
  return [
1310
1534
  2,
1311
1535
  []
1312
1536
  ];
1313
1537
  }
1314
- adElements.sort(function(a, b) {
1315
- var aSeq = parseInt(a.getAttribute("sequence") || "", 10);
1316
- var bSeq = parseInt(b.getAttribute("sequence") || "", 10);
1317
- var aVal = Number.isFinite(aSeq) ? aSeq : Number.MAX_SAFE_INTEGER;
1318
- var bVal = Number.isFinite(bSeq) ? bSeq : Number.MAX_SAFE_INTEGER;
1319
- return aVal - bVal;
1538
+ resolveAd = function resolveAd(adElement) {
1539
+ return _async_to_generator(function() {
1540
+ var _parsed_errorUrls, parsed, _parsed_errorCode;
1541
+ return _ts_generator(this, function(_state) {
1542
+ parsed = parseAdElement(adElement);
1543
+ if (parsed.type === "inline") return [
1544
+ 2,
1545
+ parsed.ad
1546
+ ];
1547
+ if (parsed.type === "wrapper") {
1548
+ return [
1549
+ 2,
1550
+ fetchAndParseVastAd(parsed.vastAdTagUri, 1, parsed.trackingUrls, parsed.rules)
1551
+ ];
1552
+ }
1553
+ if ((_parsed_errorUrls = parsed.errorUrls) === null || _parsed_errorUrls === void 0 ? void 0 : _parsed_errorUrls.length) {
1554
+ ;
1555
+ fireTrackingPixels(parsed.errorUrls, {
1556
+ errorCode: (_parsed_errorCode = parsed.errorCode) !== null && _parsed_errorCode !== void 0 ? _parsed_errorCode : VAST_ERROR_NO_SUPPORTED_MEDIA
1557
+ });
1558
+ }
1559
+ return [
1560
+ 2,
1561
+ null
1562
+ ];
1563
+ });
1564
+ })();
1565
+ };
1566
+ podElements = adElements.filter(function(el) {
1567
+ return getAdSequence(el) !== void 0;
1568
+ }).sort(function(a, b) {
1569
+ return getAdSequence(a) - getAdSequence(b);
1570
+ });
1571
+ buffet = adElements.filter(function(el) {
1572
+ return getAdSequence(el) === void 0;
1320
1573
  });
1321
1574
  ads = [];
1575
+ if (!(podElements.length === 0)) return [
1576
+ 3,
1577
+ 10
1578
+ ];
1322
1579
  _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1323
1580
  _state.label = 2;
1324
1581
  case 2:
1325
1582
  _state.trys.push([
1326
1583
  2,
1327
- 10,
1328
- 11,
1329
- 12
1584
+ 7,
1585
+ 8,
1586
+ 9
1330
1587
  ]);
1331
- _iterator = adElements[Symbol.iterator]();
1588
+ _iterator = buffet[Symbol.iterator]();
1332
1589
  _state.label = 3;
1333
1590
  case 3:
1334
1591
  if (!!(_iteratorNormalCompletion = (_step = _iterator.next()).done)) return [
1335
1592
  3,
1336
- 9
1593
+ 6
1337
1594
  ];
1338
1595
  adElement = _step.value;
1339
- parsed = parseAdElement(adElement);
1340
- if (!(parsed.type === "inline")) return [
1341
- 3,
1342
- 4
1343
- ];
1344
- ads.push(parsed.ad);
1345
1596
  return [
1346
- 3,
1347
- 8
1597
+ 4,
1598
+ resolveAd(adElement)
1348
1599
  ];
1349
1600
  case 4:
1350
- if (!(parsed.type === "wrapper")) return [
1351
- 3,
1352
- 8
1353
- ];
1601
+ ad = _state.sent();
1602
+ if (ad) ads.push(ad);
1354
1603
  _state.label = 5;
1355
1604
  case 5:
1356
- _state.trys.push([
1357
- 5,
1358
- 7,
1359
- ,
1360
- 8
1361
- ]);
1605
+ _iteratorNormalCompletion = true;
1362
1606
  return [
1363
- 4,
1364
- fetchAndParseVastAd(parsed.vastAdTagUri, 1, parsed.trackingUrls)
1607
+ 3,
1608
+ 3
1365
1609
  ];
1366
1610
  case 6:
1367
- resolved = _state.sent();
1368
- if (resolved) {
1369
- ads.push(resolved);
1370
- }
1371
1611
  return [
1372
1612
  3,
1373
- 8
1613
+ 9
1374
1614
  ];
1375
1615
  case 7:
1376
- error = _state.sent();
1377
- console.warn("[HlsAdPlayer] Failed to resolve wrapper <Ad> in pod:", error);
1616
+ err = _state.sent();
1617
+ _didIteratorError = true;
1618
+ _iteratorError = err;
1378
1619
  return [
1379
1620
  3,
1380
- 8
1621
+ 9
1381
1622
  ];
1382
1623
  case 8:
1383
- _iteratorNormalCompletion = true;
1624
+ try {
1625
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1626
+ _iterator.return();
1627
+ }
1628
+ } finally{
1629
+ if (_didIteratorError) {
1630
+ throw _iteratorError;
1631
+ }
1632
+ }
1384
1633
  return [
1385
- 3,
1386
- 3
1634
+ 7
1387
1635
  ];
1388
1636
  case 9:
1389
1637
  return [
1390
1638
  3,
1391
- 12
1639
+ 21
1392
1640
  ];
1393
1641
  case 10:
1394
- err = _state.sent();
1395
- _didIteratorError = true;
1396
- _iteratorError = err;
1642
+ _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
1643
+ _state.label = 11;
1644
+ case 11:
1645
+ _state.trys.push([
1646
+ 11,
1647
+ 19,
1648
+ 20,
1649
+ 21
1650
+ ]);
1651
+ _iterator1 = podElements[Symbol.iterator]();
1652
+ _state.label = 12;
1653
+ case 12:
1654
+ if (!!(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done)) return [
1655
+ 3,
1656
+ 18
1657
+ ];
1658
+ adElement1 = _step1.value;
1659
+ return [
1660
+ 4,
1661
+ resolveAd(adElement1)
1662
+ ];
1663
+ case 13:
1664
+ ad1 = _state.sent();
1665
+ _state.label = 14;
1666
+ case 14:
1667
+ if (!(!ad1 && buffet.length > 0)) return [
1668
+ 3,
1669
+ 16
1670
+ ];
1671
+ return [
1672
+ 4,
1673
+ resolveAd(buffet.shift())
1674
+ ];
1675
+ case 15:
1676
+ ad1 = _state.sent();
1677
+ return [
1678
+ 3,
1679
+ 14
1680
+ ];
1681
+ case 16:
1682
+ if (ad1) ads.push(ad1);
1683
+ _state.label = 17;
1684
+ case 17:
1685
+ _iteratorNormalCompletion1 = true;
1397
1686
  return [
1398
1687
  3,
1399
1688
  12
1400
1689
  ];
1401
- case 11:
1690
+ case 18:
1691
+ return [
1692
+ 3,
1693
+ 21
1694
+ ];
1695
+ case 19:
1696
+ err = _state.sent();
1697
+ _didIteratorError1 = true;
1698
+ _iteratorError1 = err;
1699
+ return [
1700
+ 3,
1701
+ 21
1702
+ ];
1703
+ case 20:
1402
1704
  try {
1403
- if (!_iteratorNormalCompletion && _iterator.return != null) {
1404
- _iterator.return();
1705
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
1706
+ _iterator1.return();
1405
1707
  }
1406
1708
  } finally{
1407
- if (_didIteratorError) {
1408
- throw _iteratorError;
1709
+ if (_didIteratorError1) {
1710
+ throw _iteratorError1;
1409
1711
  }
1410
1712
  }
1411
1713
  return [
1412
1714
  7
1413
1715
  ];
1414
- case 12:
1415
- console.log("[HlsAdPlayer] Parsed ".concat(ads.length, " ad(s) from pod VAST response"));
1716
+ case 21:
1717
+ 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"));
1416
1718
  return [
1417
1719
  2,
1418
1720
  ads
@@ -1442,7 +1744,40 @@ function createHlsAdPlayer(contentVideo, options) {
1442
1744
  var onTimeUpdate = function onTimeUpdate() {
1443
1745
  if (!currentAd || !adVideoElement) return;
1444
1746
  noteAdProgress();
1445
- var progress = adVideoElement.currentTime / currentAd.duration;
1747
+ sampleViewability();
1748
+ var currentTime = adVideoElement.currentTime;
1749
+ if (trackingFired.start) {
1750
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1751
+ try {
1752
+ for(var _iterator = currentAd.trackingUrls.progress[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1753
+ var event = _step.value;
1754
+ var _event_offsetSeconds, _event_offsetPercent;
1755
+ if (trackingFired.progressFired.has(event)) continue;
1756
+ 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;
1757
+ if (currentTime >= threshold) {
1758
+ trackingFired.progressFired.add(event);
1759
+ fireTrackingPixels([
1760
+ event.url
1761
+ ]);
1762
+ }
1763
+ }
1764
+ } catch (err) {
1765
+ _didIteratorError = true;
1766
+ _iteratorError = err;
1767
+ } finally{
1768
+ try {
1769
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1770
+ _iterator.return();
1771
+ }
1772
+ } finally{
1773
+ if (_didIteratorError) {
1774
+ throw _iteratorError;
1775
+ }
1776
+ }
1777
+ }
1778
+ }
1779
+ if (!(currentAd.duration > 0)) return;
1780
+ var progress = currentTime / currentAd.duration;
1446
1781
  if (progress >= 0.25 && !trackingFired.firstQuartile) {
1447
1782
  trackingFired.firstQuartile = true;
1448
1783
  fireTrackingPixels(currentAd.trackingUrls.firstQuartile);
@@ -1464,15 +1799,38 @@ function createHlsAdPlayer(contentVideo, options) {
1464
1799
  handleVideoDecodeFailure();
1465
1800
  }
1466
1801
  };
1802
+ var onCanPlay = function onCanPlay() {
1803
+ if (!currentAd || trackingFired.loaded) return;
1804
+ trackingFired.loaded = true;
1805
+ fireTrackingPixels(currentAd.trackingUrls.loaded);
1806
+ };
1467
1807
  var onPlaying = function onPlaying() {
1468
1808
  startStallWatchdog();
1469
- if (!currentAd || trackingFired.start) return;
1809
+ if (!currentAd || !adVideoElement) return;
1810
+ if (!trackingFired.impression) {
1811
+ trackingFired.impression = true;
1812
+ resolvedAds.add(currentAd);
1813
+ fireTrackingPixels(currentAd.trackingUrls.impression);
1814
+ fireTrackingPixels(currentAd.trackingUrls.creativeView);
1815
+ fireTrackingPixels(currentAd.trackingUrls.verificationNotExecuted, {
1816
+ reason: VERIFICATION_NOT_SUPPORTED_REASON
1817
+ });
1818
+ emit("ad_impression", {
1819
+ adId: currentAd.id,
1820
+ index: podIndex,
1821
+ total: podAds.length || 1
1822
+ });
1823
+ }
1824
+ if (trackingFired.start) return;
1470
1825
  trackingFired.start = true;
1826
+ trackingFired.lastMuted = adVideoElement.muted || adVideoElement.volume === 0;
1471
1827
  fireTrackingPixels(currentAd.trackingUrls.start);
1472
1828
  console.log("[HlsAdPlayer] Ad started playing");
1473
1829
  };
1474
1830
  var onEnded = function onEnded() {
1475
1831
  if (!currentAd || trackingFired.complete) return;
1832
+ sampleViewability();
1833
+ settleViewability();
1476
1834
  trackingFired.complete = true;
1477
1835
  fireTrackingPixels(currentAd.trackingUrls.complete);
1478
1836
  console.log("[HlsAdPlayer] Ad completed");
@@ -1484,11 +1842,7 @@ function createHlsAdPlayer(contentVideo, options) {
1484
1842
  var onError = function onError(e) {
1485
1843
  if (!adPlaying) return;
1486
1844
  console.error("[HlsAdPlayer] Ad video error:", e);
1487
- if (currentAd) {
1488
- fireTrackingPixels(currentAd.trackingUrls.error, {
1489
- errorCode: toVastMediaErrorCode(adVideoElement === null || adVideoElement === void 0 ? void 0 : adVideoElement.error)
1490
- });
1491
- }
1845
+ reportCurrentAdError(toVastMediaErrorCode(adVideoElement === null || adVideoElement === void 0 ? void 0 : adVideoElement.error));
1492
1846
  if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1493
1847
  return;
1494
1848
  }
@@ -1496,19 +1850,26 @@ function createHlsAdPlayer(contentVideo, options) {
1496
1850
  };
1497
1851
  var onVolumeChange = function onVolumeChange() {
1498
1852
  if (!currentAd || !adVideoElement) return;
1499
- if (adVideoElement.muted) {
1500
- fireTrackingPixels(currentAd.trackingUrls.mute);
1501
- } else {
1502
- fireTrackingPixels(currentAd.trackingUrls.unmute);
1853
+ var muted = adVideoElement.muted || adVideoElement.volume === 0;
1854
+ if (!trackingFired.start) {
1855
+ trackingFired.lastMuted = muted;
1856
+ return;
1503
1857
  }
1858
+ if (muted === trackingFired.lastMuted) return;
1859
+ trackingFired.lastMuted = muted;
1860
+ fireTrackingPixels(muted ? currentAd.trackingUrls.mute : currentAd.trackingUrls.unmute);
1861
+ };
1862
+ var isTrackablePlayback = function isTrackablePlayback() {
1863
+ return adPlaying && !!currentAd && !!adVideoElement && trackingFired.start && !trackingFired.complete && !adVideoElement.ended;
1504
1864
  };
1505
1865
  var onPause = function onPause() {
1506
- if (currentAd && adVideoElement && !adVideoElement.ended) {
1866
+ continuousVisibleS = 0;
1867
+ if (isTrackablePlayback()) {
1507
1868
  fireTrackingPixels(currentAd.trackingUrls.pause);
1508
1869
  }
1509
1870
  };
1510
1871
  var onPlay = function onPlay() {
1511
- if (currentAd && adVideoElement && adVideoElement.currentTime > 0) {
1872
+ if (isTrackablePlayback()) {
1512
1873
  fireTrackingPixels(currentAd.trackingUrls.resume);
1513
1874
  }
1514
1875
  };
@@ -1521,6 +1882,10 @@ function createHlsAdPlayer(contentVideo, options) {
1521
1882
  type: "loadedmetadata",
1522
1883
  handler: onLoadedMetadata
1523
1884
  },
1885
+ {
1886
+ type: "canplay",
1887
+ handler: onCanPlay
1888
+ },
1524
1889
  {
1525
1890
  type: "playing",
1526
1891
  handler: onPlaying
@@ -1592,6 +1957,229 @@ function createHlsAdPlayer(contentVideo, options) {
1592
1957
  }
1593
1958
  adEventHandlers = [];
1594
1959
  }
1960
+ function handleAdClick() {
1961
+ if (!adPlaying || !currentAd) return;
1962
+ fireTrackingPixels(currentAd.trackingUrls.clickTracking);
1963
+ emit("ad_click", {
1964
+ adId: currentAd.id,
1965
+ clickThrough: currentAd.clickThrough
1966
+ });
1967
+ if (currentAd.clickThrough) {
1968
+ try {
1969
+ window.open(currentAd.clickThrough, "_blank", "noopener");
1970
+ } catch (error) {
1971
+ console.warn("[HlsAdPlayer] Failed to open ClickThrough URL:", error);
1972
+ }
1973
+ }
1974
+ }
1975
+ function reportCurrentAdError(errorCode) {
1976
+ if (!currentAd) return;
1977
+ resolvedAds.add(currentAd);
1978
+ fireTrackingPixels(currentAd.trackingUrls.error, {
1979
+ errorCode: errorCode
1980
+ });
1981
+ }
1982
+ function fireNotUsedForUnplayedAds() {
1983
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1984
+ try {
1985
+ for(var _iterator = podAds[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1986
+ var ad = _step.value;
1987
+ if (resolvedAds.has(ad)) continue;
1988
+ resolvedAds.add(ad);
1989
+ fireTrackingPixels(ad.trackingUrls.notUsed, {
1990
+ ad: ad
1991
+ });
1992
+ }
1993
+ } catch (err) {
1994
+ _didIteratorError = true;
1995
+ _iteratorError = err;
1996
+ } finally{
1997
+ try {
1998
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1999
+ _iterator.return();
2000
+ }
2001
+ } finally{
2002
+ if (_didIteratorError) {
2003
+ throw _iteratorError;
2004
+ }
2005
+ }
2006
+ }
2007
+ }
2008
+ function sampleViewability() {
2009
+ if (!currentAd || !adVideoElement || !viewObserver || !trackingFired.impression || trackingFired.viewabilitySettled) {
2010
+ return;
2011
+ }
2012
+ var now = adVideoElement.currentTime;
2013
+ var inView = visibleRatio >= VIEWABLE_MIN_VISIBLE_RATIO && document.visibilityState === "visible" && !adVideoElement.paused;
2014
+ if (!inView) {
2015
+ continuousVisibleS = 0;
2016
+ } else if (lastViewSampleTime !== void 0 && now >= lastViewSampleTime) {
2017
+ continuousVisibleS += now - lastViewSampleTime;
2018
+ }
2019
+ lastViewSampleTime = now;
2020
+ if (continuousVisibleS >= VIEWABLE_MIN_CONTINUOUS_S) {
2021
+ trackingFired.viewabilitySettled = true;
2022
+ fireTrackingPixels(currentAd.trackingUrls.viewable);
2023
+ }
2024
+ }
2025
+ function settleViewability() {
2026
+ if (!currentAd || !trackingFired.impression || trackingFired.viewabilitySettled) {
2027
+ return;
2028
+ }
2029
+ trackingFired.viewabilitySettled = true;
2030
+ fireTrackingPixels(viewObserver ? currentAd.trackingUrls.notViewable : currentAd.trackingUrls.viewUndetermined);
2031
+ }
2032
+ function handleFullscreenChange() {
2033
+ var _document_fullscreenElement;
2034
+ if (!adPlaying || !currentAd || !adContainerEl || !trackingFired.start) return;
2035
+ var fullscreenEl = (_document_fullscreenElement = document.fullscreenElement) !== null && _document_fullscreenElement !== void 0 ? _document_fullscreenElement : document.webkitFullscreenElement;
2036
+ var expanded = !!fullscreenEl && fullscreenEl.contains(adContainerEl);
2037
+ if (expanded === lastPlayerExpanded) return;
2038
+ lastPlayerExpanded = expanded;
2039
+ var urls = currentAd.trackingUrls;
2040
+ fireTrackingPixels(expanded ? urls.fullscreen.concat(urls.playerExpand) : urls.exitFullscreen.concat(urls.playerCollapse));
2041
+ }
2042
+ function attachContainerHandlers() {
2043
+ if (!adContainerEl || containerHandlers.length > 0) return;
2044
+ var onClick = function onClick() {
2045
+ return handleAdClick();
2046
+ };
2047
+ var onInteraction = function onInteraction(event) {
2048
+ if (adPlaying) emit("ad_interaction", event);
2049
+ };
2050
+ containerHandlers = [
2051
+ {
2052
+ type: "click",
2053
+ handler: onClick
2054
+ },
2055
+ {
2056
+ type: "mousedown",
2057
+ handler: onInteraction
2058
+ },
2059
+ {
2060
+ type: "touchstart",
2061
+ handler: onInteraction
2062
+ }
2063
+ ];
2064
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2065
+ try {
2066
+ for(var _iterator = containerHandlers[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2067
+ var _step_value = _step.value, type = _step_value.type, handler = _step_value.handler;
2068
+ adContainerEl.addEventListener(type, handler);
2069
+ }
2070
+ } catch (err) {
2071
+ _didIteratorError = true;
2072
+ _iteratorError = err;
2073
+ } finally{
2074
+ try {
2075
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
2076
+ _iterator.return();
2077
+ }
2078
+ } finally{
2079
+ if (_didIteratorError) {
2080
+ throw _iteratorError;
2081
+ }
2082
+ }
2083
+ }
2084
+ var onFullscreenChange = function onFullscreenChange() {
2085
+ return handleFullscreenChange();
2086
+ };
2087
+ documentHandlers = [
2088
+ {
2089
+ type: "fullscreenchange",
2090
+ handler: onFullscreenChange
2091
+ },
2092
+ {
2093
+ type: "webkitfullscreenchange",
2094
+ handler: onFullscreenChange
2095
+ }
2096
+ ];
2097
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
2098
+ try {
2099
+ for(var _iterator1 = documentHandlers[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
2100
+ var _step_value1 = _step1.value, type1 = _step_value1.type, handler1 = _step_value1.handler;
2101
+ document.addEventListener(type1, handler1);
2102
+ }
2103
+ } catch (err) {
2104
+ _didIteratorError1 = true;
2105
+ _iteratorError1 = err;
2106
+ } finally{
2107
+ try {
2108
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
2109
+ _iterator1.return();
2110
+ }
2111
+ } finally{
2112
+ if (_didIteratorError1) {
2113
+ throw _iteratorError1;
2114
+ }
2115
+ }
2116
+ }
2117
+ if (typeof IntersectionObserver !== "undefined") {
2118
+ viewObserver = new IntersectionObserver(function(entries) {
2119
+ var entry = entries[entries.length - 1];
2120
+ if (entry) {
2121
+ visibleRatio = entry.isIntersecting ? entry.intersectionRatio : 0;
2122
+ }
2123
+ }, {
2124
+ threshold: [
2125
+ 0,
2126
+ 0.25,
2127
+ 0.5,
2128
+ 0.75,
2129
+ 1
2130
+ ]
2131
+ });
2132
+ viewObserver.observe(adContainerEl);
2133
+ }
2134
+ }
2135
+ function detachContainerHandlers() {
2136
+ if (adContainerEl) {
2137
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2138
+ try {
2139
+ for(var _iterator = containerHandlers[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2140
+ var _step_value = _step.value, type = _step_value.type, handler = _step_value.handler;
2141
+ adContainerEl.removeEventListener(type, handler);
2142
+ }
2143
+ } catch (err) {
2144
+ _didIteratorError = true;
2145
+ _iteratorError = err;
2146
+ } finally{
2147
+ try {
2148
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
2149
+ _iterator.return();
2150
+ }
2151
+ } finally{
2152
+ if (_didIteratorError) {
2153
+ throw _iteratorError;
2154
+ }
2155
+ }
2156
+ }
2157
+ }
2158
+ containerHandlers = [];
2159
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
2160
+ try {
2161
+ for(var _iterator1 = documentHandlers[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
2162
+ var _step_value1 = _step1.value, type1 = _step_value1.type, handler1 = _step_value1.handler;
2163
+ document.removeEventListener(type1, handler1);
2164
+ }
2165
+ } catch (err) {
2166
+ _didIteratorError1 = true;
2167
+ _iteratorError1 = err;
2168
+ } finally{
2169
+ try {
2170
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
2171
+ _iterator1.return();
2172
+ }
2173
+ } finally{
2174
+ if (_didIteratorError1) {
2175
+ throw _iteratorError1;
2176
+ }
2177
+ }
2178
+ }
2179
+ documentHandlers = [];
2180
+ viewObserver === null || viewObserver === void 0 ? void 0 : viewObserver.disconnect();
2181
+ viewObserver = void 0;
2182
+ }
1595
2183
  function setAdPlayingFlag(isPlaying) {
1596
2184
  if (isPlaying) {
1597
2185
  contentVideo.dataset.stormcloudAdPlaying = "true";
@@ -1599,15 +2187,10 @@ function createHlsAdPlayer(contentVideo, options) {
1599
2187
  delete contentVideo.dataset.stormcloudAdPlaying;
1600
2188
  }
1601
2189
  }
1602
- function resetQuartileTracking(preserveImpression) {
1603
- trackingFired = {
1604
- impression: preserveImpression ? trackingFired.impression : false,
1605
- start: false,
1606
- firstQuartile: false,
1607
- midpoint: false,
1608
- thirdQuartile: false,
1609
- complete: false
1610
- };
2190
+ function resetAdTracking() {
2191
+ trackingFired = createTrackingState();
2192
+ continuousVisibleS = 0;
2193
+ lastViewSampleTime = void 0;
1611
2194
  }
1612
2195
  function isRvfcSupported(video) {
1613
2196
  return typeof video.requestVideoFrameCallback === "function";
@@ -1713,13 +2296,12 @@ function createHlsAdPlayer(contentVideo, options) {
1713
2296
  if (podIndex >= podAds.length - 1) {
1714
2297
  return false;
1715
2298
  }
2299
+ settleViewability();
1716
2300
  podIndex++;
1717
2301
  currentAd = podAds[podIndex];
1718
2302
  currentAdMediaFile = void 0;
1719
- resetQuartileTracking(false);
2303
+ resetAdTracking();
1720
2304
  if (currentAd) {
1721
- fireTrackingPixels(currentAd.trackingUrls.impression);
1722
- trackingFired.impression = true;
1723
2305
  console.log("[HlsAdPlayer] Advancing to next pod ad (".concat(podIndex + 1, "/").concat(podAds.length, "): ").concat(currentAd.title, ", duration: ").concat(currentAd.duration, "s"));
1724
2306
  }
1725
2307
  clearStallWatchdog();
@@ -1757,11 +2339,7 @@ function createHlsAdPlayer(contentVideo, options) {
1757
2339
  function handleAdStall() {
1758
2340
  console.warn("[HlsAdPlayer] Ad playback stalled (no progress) - recovering to avoid a blank frame");
1759
2341
  clearStallWatchdog();
1760
- if (currentAd) {
1761
- fireTrackingPixels(currentAd.trackingUrls.error, {
1762
- errorCode: VAST_ERROR_MEDIA_DISPLAY
1763
- });
1764
- }
2342
+ reportCurrentAdError(VAST_ERROR_MEDIA_DISPLAY);
1765
2343
  if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1766
2344
  return;
1767
2345
  }
@@ -1827,11 +2405,7 @@ function createHlsAdPlayer(contentVideo, options) {
1827
2405
  function handleVideoDecodeFailure() {
1828
2406
  console.warn("[HlsAdPlayer] Ad audio is advancing but no video frames decoded (black screen) - skipping this creative");
1829
2407
  clearStallWatchdog();
1830
- if (currentAd) {
1831
- fireTrackingPixels(currentAd.trackingUrls.error, {
1832
- errorCode: VAST_ERROR_MEDIA_DISPLAY
1833
- });
1834
- }
2408
+ reportCurrentAdError(VAST_ERROR_MEDIA_DISPLAY);
1835
2409
  if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1836
2410
  return;
1837
2411
  }
@@ -1886,6 +2460,7 @@ function createHlsAdPlayer(contentVideo, options) {
1886
2460
  }
1887
2461
  function handleAdComplete() {
1888
2462
  console.log("[HlsAdPlayer] Handling ad completion");
2463
+ settleViewability();
1889
2464
  clearStallWatchdog();
1890
2465
  adPlaying = false;
1891
2466
  setAdPlayingFlag(false);
@@ -1909,6 +2484,7 @@ function createHlsAdPlayer(contentVideo, options) {
1909
2484
  }
1910
2485
  function handleAdError() {
1911
2486
  console.log("[HlsAdPlayer] Handling ad error");
2487
+ settleViewability();
1912
2488
  clearStallWatchdog();
1913
2489
  adPlaying = false;
1914
2490
  setAdPlayingFlag(false);
@@ -1941,6 +2517,7 @@ function createHlsAdPlayer(contentVideo, options) {
1941
2517
  adContainerEl = container;
1942
2518
  }
1943
2519
  contentVideo[AD_CONTAINER_PROP] = adContainerEl;
2520
+ attachContainerHandlers();
1944
2521
  },
1945
2522
  requestAds: function requestAds(vastTagUrl) {
1946
2523
  return _async_to_generator(function() {
@@ -2003,10 +2580,6 @@ function createHlsAdPlayer(contentVideo, options) {
2003
2580
  currentAd = ads[0];
2004
2581
  currentAdMediaFile = void 0;
2005
2582
  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"));
2006
- if (currentAd) {
2007
- fireTrackingPixels(currentAd.trackingUrls.impression);
2008
- trackingFired.impression = true;
2009
- }
2010
2583
  return [
2011
2584
  2,
2012
2585
  Promise.resolve()
@@ -2046,7 +2619,7 @@ function createHlsAdPlayer(contentVideo, options) {
2046
2619
  contentVideo[AD_VIDEO_PROP] = adVideoElement;
2047
2620
  }
2048
2621
  setupAdEventListeners();
2049
- resetQuartileTracking(true);
2622
+ resetAdTracking();
2050
2623
  contentVolume = contentVideo.volume;
2051
2624
  originalVolume = Math.max(0, Math.min(1, contentVolume || originalVolume));
2052
2625
  if (!(options === null || options === void 0 ? void 0 : options.continueLiveStreamDuringAds)) {
@@ -2117,6 +2690,8 @@ function createHlsAdPlayer(contentVideo, options) {
2117
2690
  var previousMutedState;
2118
2691
  return _ts_generator(this, function(_state) {
2119
2692
  console.log("[HlsAdPlayer] Stopping ad");
2693
+ settleViewability();
2694
+ fireNotUsedForUnplayedAds();
2120
2695
  clearStallWatchdog();
2121
2696
  adPlaying = false;
2122
2697
  setAdPlayingFlag(false);
@@ -2147,6 +2722,8 @@ function createHlsAdPlayer(contentVideo, options) {
2147
2722
  },
2148
2723
  destroy: function destroy() {
2149
2724
  console.log("[HlsAdPlayer] Destroying");
2725
+ settleViewability();
2726
+ fireNotUsedForUnplayedAds();
2150
2727
  destroyed = true;
2151
2728
  clearStallWatchdog();
2152
2729
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
@@ -2175,6 +2752,7 @@ function createHlsAdPlayer(contentVideo, options) {
2175
2752
  contentVideo.muted = originalMutedState;
2176
2753
  contentVideo.volume = Math.max(0, Math.min(1, originalVolume));
2177
2754
  teardownAdEventListeners();
2755
+ detachContainerHandlers();
2178
2756
  releaseAdDecoder();
2179
2757
  currentAd = void 0;
2180
2758
  currentAdMediaFile = void 0;
@@ -2616,6 +3194,7 @@ function resolveVastEnvironmentSignals(isCtv) {
2616
3194
  limitAdTracking = (_ref1 = platformLat !== null && platformLat !== void 0 ? platformLat : readStoredLimitAdTracking()) !== null && _ref1 !== void 0 ? _ref1 : false;
2617
3195
  }
2618
3196
  }
3197
+ var deviceTypeHint = resolveDeviceTypeHint(isCtv);
2619
3198
  if (isCtv) {
2620
3199
  return _object_spread_props(_object_spread({
2621
3200
  isCtv: true,
@@ -2627,10 +3206,10 @@ function resolveVastEnvironmentSignals(isCtv) {
2627
3206
  } : {}, deviceId && limitAdTracking != null ? {
2628
3207
  limitAdTracking: limitAdTracking
2629
3208
  } : {}), {
2630
- deviceTypeHint: 5
3209
+ deviceTypeHint: deviceTypeHint
2631
3210
  });
2632
3211
  }
2633
- return _object_spread({
3212
+ return _object_spread_props(_object_spread({
2634
3213
  isCtv: false
2635
3214
  }, deviceId ? {
2636
3215
  deviceId: deviceId
@@ -2638,7 +3217,142 @@ function resolveVastEnvironmentSignals(isCtv) {
2638
3217
  deviceIdType: deviceIdType
2639
3218
  } : {}, deviceId && limitAdTracking != null ? {
2640
3219
  limitAdTracking: limitAdTracking
2641
- } : {});
3220
+ } : {}), {
3221
+ deviceTypeHint: deviceTypeHint
3222
+ });
3223
+ }
3224
+ var DEVICE_TYPE_HINT = {
3225
+ FEATURE_PHONE: 1,
3226
+ SMARTPHONE: 2,
3227
+ DESKTOP: 3,
3228
+ TABLET: 4,
3229
+ CONNECTED_TV: 5,
3230
+ GAME_CONSOLE: 6,
3231
+ SET_TOP_BOX: 7
3232
+ };
3233
+ var DEVICE_TYPE_HINT_ALIASES = {
3234
+ featurephone: DEVICE_TYPE_HINT.FEATURE_PHONE,
3235
+ smartphone: DEVICE_TYPE_HINT.SMARTPHONE,
3236
+ mobile: DEVICE_TYPE_HINT.SMARTPHONE,
3237
+ phone: DEVICE_TYPE_HINT.SMARTPHONE,
3238
+ desktop: DEVICE_TYPE_HINT.DESKTOP,
3239
+ pc: DEVICE_TYPE_HINT.DESKTOP,
3240
+ tablet: DEVICE_TYPE_HINT.TABLET,
3241
+ ctv: DEVICE_TYPE_HINT.CONNECTED_TV,
3242
+ tv: DEVICE_TYPE_HINT.CONNECTED_TV,
3243
+ connectedtv: DEVICE_TYPE_HINT.CONNECTED_TV,
3244
+ smarttv: DEVICE_TYPE_HINT.CONNECTED_TV,
3245
+ console: DEVICE_TYPE_HINT.GAME_CONSOLE,
3246
+ gameconsole: DEVICE_TYPE_HINT.GAME_CONSOLE,
3247
+ stb: DEVICE_TYPE_HINT.SET_TOP_BOX,
3248
+ settopbox: DEVICE_TYPE_HINT.SET_TOP_BOX
3249
+ };
3250
+ 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;
3251
+ var GAME_CONSOLE_UA = /PlayStation|Xbox|Nintendo/i;
3252
+ 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;
3253
+ var FEATURE_PHONE_UA = /KAIOS|MIDP|J2ME|Series40|Opera Mini/i;
3254
+ function resolveDeviceTypeHint(isCtv) {
3255
+ var override = readDeviceTypeHintOverride();
3256
+ if (override != null) return override;
3257
+ return inferDeviceTypeHint(isCtv);
3258
+ }
3259
+ function inferDeviceTypeHint(isCtv) {
3260
+ var fallback = isCtv ? DEVICE_TYPE_HINT.CONNECTED_TV : DEVICE_TYPE_HINT.DESKTOP;
3261
+ if (typeof navigator === "undefined") return fallback;
3262
+ var ua = navigator.userAgent || "";
3263
+ var maxTouchPoints = navigator.maxTouchPoints || 0;
3264
+ if (SET_TOP_BOX_UA.test(ua)) return DEVICE_TYPE_HINT.SET_TOP_BOX;
3265
+ if (GAME_CONSOLE_UA.test(ua)) return DEVICE_TYPE_HINT.GAME_CONSOLE;
3266
+ if (CONNECTED_TV_UA.test(ua) && !/Mobile/i.test(ua)) {
3267
+ return DEVICE_TYPE_HINT.CONNECTED_TV;
3268
+ }
3269
+ if (FEATURE_PHONE_UA.test(ua)) return DEVICE_TYPE_HINT.FEATURE_PHONE;
3270
+ if (/iPad/i.test(ua) || /Macintosh/i.test(ua) && maxTouchPoints > 1) {
3271
+ return DEVICE_TYPE_HINT.TABLET;
3272
+ }
3273
+ if (/iPhone|iPod/i.test(ua)) return DEVICE_TYPE_HINT.SMARTPHONE;
3274
+ if (/Android/i.test(ua)) {
3275
+ if (/Mobile/i.test(ua)) return DEVICE_TYPE_HINT.SMARTPHONE;
3276
+ if (maxTouchPoints === 0) return DEVICE_TYPE_HINT.SET_TOP_BOX;
3277
+ return DEVICE_TYPE_HINT.TABLET;
3278
+ }
3279
+ if (/Mobile|Windows Phone|BlackBerry/i.test(ua)) return DEVICE_TYPE_HINT.SMARTPHONE;
3280
+ return fallback;
3281
+ }
3282
+ function readDeviceTypeHintOverride() {
3283
+ if (typeof window === "undefined") return void 0;
3284
+ var keys = [
3285
+ "dth",
3286
+ "deviceTypeHint"
3287
+ ];
3288
+ var fromGlobal = normalizeDeviceTypeHint(window.__STORMCLOUD_DTH__);
3289
+ if (fromGlobal != null) return fromGlobal;
3290
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
3291
+ try {
3292
+ for(var _iterator = getNativeBridgeSources()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
3293
+ var source = _step.value;
3294
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
3295
+ try {
3296
+ for(var _iterator1 = keys[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
3297
+ var key = _step1.value;
3298
+ var value = source === null || source === void 0 ? void 0 : source[key];
3299
+ var normalized = normalizeDeviceTypeHint(typeof value === "function" ? safeCall(value, source) : value);
3300
+ if (normalized != null) return normalized;
3301
+ }
3302
+ } catch (err) {
3303
+ _didIteratorError1 = true;
3304
+ _iteratorError1 = err;
3305
+ } finally{
3306
+ try {
3307
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
3308
+ _iterator1.return();
3309
+ }
3310
+ } finally{
3311
+ if (_didIteratorError1) {
3312
+ throw _iteratorError1;
3313
+ }
3314
+ }
3315
+ }
3316
+ }
3317
+ } catch (err) {
3318
+ _didIteratorError = true;
3319
+ _iteratorError = err;
3320
+ } finally{
3321
+ try {
3322
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
3323
+ _iterator.return();
3324
+ }
3325
+ } finally{
3326
+ if (_didIteratorError) {
3327
+ throw _iteratorError;
3328
+ }
3329
+ }
3330
+ }
3331
+ for(var _i = 0, _iter = [
3332
+ "stormcloud.dth",
3333
+ "dth"
3334
+ ]; _i < _iter.length; _i++){
3335
+ var key1 = _iter[_i];
3336
+ var normalized1 = normalizeDeviceTypeHint(readStoredString(key1));
3337
+ if (normalized1 != null) return normalized1;
3338
+ }
3339
+ return void 0;
3340
+ }
3341
+ function normalizeDeviceTypeHint(value) {
3342
+ if (typeof value === "number") {
3343
+ return Number.isInteger(value) && value >= 1 && value <= 7 ? value : void 0;
3344
+ }
3345
+ if (typeof value !== "string") return void 0;
3346
+ var trimmed = value.trim();
3347
+ if (/^[1-7]$/.test(trimmed)) return parseInt(trimmed, 10);
3348
+ return DEVICE_TYPE_HINT_ALIASES[trimmed.toLowerCase().replace(/[\s_-]/g, "")];
3349
+ }
3350
+ function safeCall(fn, thisArg) {
3351
+ try {
3352
+ return fn.call(thisArg);
3353
+ } catch (unused) {
3354
+ return void 0;
3355
+ }
2642
3356
  }
2643
3357
  function inferDeviceIdType() {
2644
3358
  if (typeof navigator === "undefined") {
@@ -2844,22 +3558,9 @@ function isZeroedAdId(value) {
2844
3558
  return ZEROED_AD_ID_PATTERNS.has(value.trim().toLowerCase());
2845
3559
  }
2846
3560
  function readNativeBridgeSignals() {
2847
- if (typeof window === "undefined") {
2848
- return {};
2849
- }
2850
- var candidates = [
2851
- window.__STORMCLOUD_CTV_AD_INFO__,
2852
- window.__STORMCLOUD_CTV__,
2853
- window.stormcloudCtv,
2854
- window.AiryTV,
2855
- window.Android,
2856
- window.webOS,
2857
- window.tizen,
2858
- window.amazon
2859
- ].filter(Boolean);
2860
3561
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2861
3562
  try {
2862
- for(var _iterator = candidates[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
3563
+ for(var _iterator = getNativeBridgeSources()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2863
3564
  var source = _step.value;
2864
3565
  var contentUrl = readBridgeValue(source, [
2865
3566
  "contentUrl",
@@ -2934,6 +3635,21 @@ function readNativeBridgeSignals() {
2934
3635
  }
2935
3636
  return {};
2936
3637
  }
3638
+ function getNativeBridgeSources() {
3639
+ if (typeof window === "undefined") {
3640
+ return [];
3641
+ }
3642
+ return [
3643
+ window.__STORMCLOUD_CTV_AD_INFO__,
3644
+ window.__STORMCLOUD_CTV__,
3645
+ window.stormcloudCtv,
3646
+ window.AiryTV,
3647
+ window.Android,
3648
+ window.webOS,
3649
+ window.tizen,
3650
+ window.amazon
3651
+ ].filter(Boolean);
3652
+ }
2937
3653
  function readBridgeValue(source, keys) {
2938
3654
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2939
3655
  try {
@@ -7390,6 +8106,12 @@ var AdBreakOrchestrator = /*#__PURE__*/ function() {
7390
8106
  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 : "?"));
7391
8107
  }
7392
8108
  });
8109
+ adPlayer.on("ad_click", function() {
8110
+ _this.host.onAdClick();
8111
+ });
8112
+ adPlayer.on("ad_interaction", function(event) {
8113
+ if (event) _this.host.onAdInteraction(event);
8114
+ });
7393
8115
  adPlayer.on("all_ads_completed", function() {
7394
8116
  sendAdImpressionTracking(_this.host.config.licenseKey, {
7395
8117
  source: "hls",
@@ -8919,6 +9641,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
8919
9641
  },
8920
9642
  generatePodVastUrl: function generatePodVastUrl(base, breakDurationMs) {
8921
9643
  return _this.generatePodVastUrl(base, breakDurationMs);
9644
+ },
9645
+ onAdClick: function onAdClick() {
9646
+ return _this.palNonce.sendAdClick();
9647
+ },
9648
+ onAdInteraction: function onAdInteraction(event) {
9649
+ return _this.palNonce.sendAdTouch(event);
8922
9650
  }
8923
9651
  }, this.timing, this.adConfig, this.cueManager, this.placeholder);
8924
9652
  }