adgent-sdk 0.1.3 → 0.1.4

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.
@@ -1,8 +1,8 @@
1
1
  import { XMLParser as T } from "fast-xml-parser";
2
- var d = /* @__PURE__ */ ((r) => (r.Idle = "idle", r.Loading = "loading", r.Ready = "ready", r.Playing = "playing", r.Paused = "paused", r.Completed = "completed", r.Error = "error", r.WaitingForInteraction = "waiting_for_interaction", r))(d || {}), h = /* @__PURE__ */ ((r) => (r[r.XML_PARSING_ERROR = 100] = "XML_PARSING_ERROR", r[r.VAST_SCHEMA_VALIDATION_ERROR = 101] = "VAST_SCHEMA_VALIDATION_ERROR", r[r.VAST_VERSION_NOT_SUPPORTED = 102] = "VAST_VERSION_NOT_SUPPORTED", r[r.GENERAL_WRAPPER_ERROR = 300] = "GENERAL_WRAPPER_ERROR", r[r.WRAPPER_TIMEOUT = 301] = "WRAPPER_TIMEOUT", r[r.WRAPPER_LIMIT_REACHED = 302] = "WRAPPER_LIMIT_REACHED", r[r.NO_VAST_RESPONSE = 303] = "NO_VAST_RESPONSE", r[r.GENERAL_LINEAR_ERROR = 400] = "GENERAL_LINEAR_ERROR", r[r.FILE_NOT_FOUND = 401] = "FILE_NOT_FOUND", r[r.MEDIA_TIMEOUT = 402] = "MEDIA_TIMEOUT", r[r.MEDIA_NOT_SUPPORTED = 403] = "MEDIA_NOT_SUPPORTED", r[r.GENERAL_COMPANION_ERROR = 600] = "GENERAL_COMPANION_ERROR", r[r.UNDEFINED_ERROR = 900] = "UNDEFINED_ERROR", r))(h || {}), P = Object.defineProperty, A = (r, e, t) => e in r ? P(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t, E = (r, e, t) => A(r, typeof e != "symbol" ? e + "" : e, t);
3
- class O {
2
+ var c = /* @__PURE__ */ ((r) => (r.Idle = "idle", r.Loading = "loading", r.Ready = "ready", r.Playing = "playing", r.Paused = "paused", r.Completed = "completed", r.Error = "error", r.WaitingForInteraction = "waiting_for_interaction", r))(c || {}), p = /* @__PURE__ */ ((r) => (r[r.XML_PARSING_ERROR = 100] = "XML_PARSING_ERROR", r[r.VAST_SCHEMA_VALIDATION_ERROR = 101] = "VAST_SCHEMA_VALIDATION_ERROR", r[r.VAST_VERSION_NOT_SUPPORTED = 102] = "VAST_VERSION_NOT_SUPPORTED", r[r.GENERAL_WRAPPER_ERROR = 300] = "GENERAL_WRAPPER_ERROR", r[r.WRAPPER_TIMEOUT = 301] = "WRAPPER_TIMEOUT", r[r.WRAPPER_LIMIT_REACHED = 302] = "WRAPPER_LIMIT_REACHED", r[r.NO_VAST_RESPONSE = 303] = "NO_VAST_RESPONSE", r[r.GENERAL_LINEAR_ERROR = 400] = "GENERAL_LINEAR_ERROR", r[r.FILE_NOT_FOUND = 401] = "FILE_NOT_FOUND", r[r.MEDIA_TIMEOUT = 402] = "MEDIA_TIMEOUT", r[r.MEDIA_NOT_SUPPORTED = 403] = "MEDIA_NOT_SUPPORTED", r[r.GENERAL_COMPANION_ERROR = 600] = "GENERAL_COMPANION_ERROR", r[r.UNDEFINED_ERROR = 900] = "UNDEFINED_ERROR", r))(p || {}), P = Object.defineProperty, x = (r, e, t) => e in r ? P(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t, b = (r, e, t) => x(r, typeof e != "symbol" ? e + "" : e, t);
3
+ class A {
4
4
  constructor(e = {}) {
5
- E(this, "config"), E(this, "xmlParser");
5
+ b(this, "config"), b(this, "xmlParser");
6
6
  var t, i, s, a;
7
7
  this.config = {
8
8
  maxWrapperDepth: (t = e.maxWrapperDepth) != null ? t : 5,
@@ -29,7 +29,7 @@ class O {
29
29
  return {
30
30
  success: !1,
31
31
  error: {
32
- code: h.GENERAL_WRAPPER_ERROR,
32
+ code: p.GENERAL_WRAPPER_ERROR,
33
33
  message: i
34
34
  }
35
35
  };
@@ -46,8 +46,8 @@ class O {
46
46
  this.log(`Fetching VAST (depth: ${t}): ${e}`);
47
47
  const i = await this.fetchWithTimeout(e), s = this.parseXml(i), a = await Promise.all(
48
48
  s.ads.map(async (n) => {
49
- var u;
50
- return (u = n.wrapper) != null && u.vastAdTagURI ? this.resolveWrapper(n, t + 1) : n;
49
+ var d;
50
+ return (d = n.wrapper) != null && d.vastAdTagURI ? this.resolveWrapper(n, t + 1) : n;
51
51
  })
52
52
  );
53
53
  return {
@@ -278,8 +278,8 @@ class O {
278
278
  const i = e.filter(
279
279
  (n) => n.type.includes("mp4") || n.type.includes("video/mp4")
280
280
  );
281
- return [...i.length > 0 ? i : e].sort((n, u) => {
282
- const m = n.bitrate || 0, f = u.bitrate || 0, k = n.height > 1080 ? 1e4 : 0, w = u.height > 1080 ? 1e4 : 0, R = Math.abs(m - t) + k, S = Math.abs(f - t) + w;
281
+ return [...i.length > 0 ? i : e].sort((n, d) => {
282
+ const f = n.bitrate || 0, v = d.bitrate || 0, w = n.height > 1080 ? 1e4 : 0, k = d.height > 1080 ? 1e4 : 0, R = Math.abs(f - t) + w, S = Math.abs(v - t) + k;
283
283
  return R - S;
284
284
  })[0] || null;
285
285
  }
@@ -321,21 +321,21 @@ function g(r, e = {}) {
321
321
  encodeURIComponent(e.assetUri)
322
322
  )), e.contentPlayhead !== void 0 && (t = t.replace(
323
323
  /\[CONTENTPLAYHEAD\]/g,
324
- b(e.contentPlayhead)
324
+ E(e.contentPlayhead)
325
325
  )), e.adPlayhead !== void 0 && (t = t.replace(
326
326
  /\[ADPLAYHEAD\]/g,
327
- b(e.adPlayhead)
327
+ E(e.adPlayhead)
328
328
  )), e.errorCode !== void 0 && (t = t.replace(/\[ERRORCODE\]/g, e.errorCode.toString())), e.breakPosition !== void 0 && (t = t.replace(
329
329
  /\[BREAKPOSITION\]/g,
330
330
  e.breakPosition.toString()
331
331
  )), e.adType && (t = t.replace(/\[ADTYPE\]/g, e.adType)), t;
332
332
  }
333
- function b(r) {
333
+ function E(r) {
334
334
  const e = Math.floor(r / 3600), t = Math.floor(r % 3600 / 60), i = Math.floor(r % 60), s = Math.floor(r % 1 * 1e3);
335
335
  return e.toString().padStart(2, "0") + ":" + t.toString().padStart(2, "0") + ":" + i.toString().padStart(2, "0") + "." + s.toString().padStart(3, "0");
336
336
  }
337
- var o = /* @__PURE__ */ ((r) => (r.WebOS = "webos", r.Tizen = "tizen", r.Vidaa = "vidaa", r.WhaleOS = "whaleos", r.FireTV = "firetv", r.Roku = "roku", r.Xbox = "xbox", r.PlayStation = "playstation", r.AndroidTV = "androidtv", r.Vizio = "vizio", r.Generic = "generic", r))(o || {}), c = /* @__PURE__ */ ((r) => (r.Enter = "enter", r.Back = "back", r.Left = "left", r.Right = "right", r.Up = "up", r.Down = "down", r.Play = "play", r.Pause = "pause", r.PlayPause = "playPause", r.Stop = "stop", r.FastForward = "fastForward", r.Rewind = "rewind", r.Menu = "menu", r.Info = "info", r.Red = "red", r.Green = "green", r.Yellow = "yellow", r.Blue = "blue", r.ChannelUp = "channelUp", r.ChannelDown = "channelDown", r.VolumeUp = "volumeUp", r.VolumeDown = "volumeDown", r.Mute = "mute", r))(c || {});
338
- const I = {
337
+ var o = /* @__PURE__ */ ((r) => (r.WebOS = "webos", r.Tizen = "tizen", r.Vidaa = "vidaa", r.WhaleOS = "whaleos", r.FireTV = "firetv", r.Roku = "roku", r.Xbox = "xbox", r.PlayStation = "playstation", r.AndroidTV = "androidtv", r.Vizio = "vizio", r.Generic = "generic", r))(o || {}), u = /* @__PURE__ */ ((r) => (r.Enter = "enter", r.Back = "back", r.Left = "left", r.Right = "right", r.Up = "up", r.Down = "down", r.Play = "play", r.Pause = "pause", r.PlayPause = "playPause", r.Stop = "stop", r.FastForward = "fastForward", r.Rewind = "rewind", r.Menu = "menu", r.Info = "info", r.Red = "red", r.Green = "green", r.Yellow = "yellow", r.Blue = "blue", r.ChannelUp = "channelUp", r.ChannelDown = "channelDown", r.VolumeUp = "volumeUp", r.VolumeDown = "volumeDown", r.Mute = "mute", r))(u || {});
338
+ const O = {
339
339
  webos: {
340
340
  13: "enter",
341
341
  461: "back",
@@ -517,7 +517,7 @@ const I = {
517
517
  /* Mute */
518
518
  // M key
519
519
  }
520
- }, x = {
520
+ }, I = {
521
521
  tizen: [
522
522
  /Tizen/i,
523
523
  /SMART-TV.*Samsung/i
@@ -572,10 +572,10 @@ const I = {
572
572
  ],
573
573
  generic: []
574
574
  };
575
- var C = Object.defineProperty, N = (r, e, t) => e in r ? C(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t, p = (r, e, t) => N(r, typeof e != "symbol" ? e + "" : e, t);
576
- class F {
575
+ var C = Object.defineProperty, M = (r, e, t) => e in r ? C(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t, h = (r, e, t) => M(r, typeof e != "symbol" ? e + "" : e, t);
576
+ class N {
577
577
  constructor() {
578
- p(this, "platform"), p(this, "capabilities"), p(this, "deviceInfo"), p(this, "keyMap"), p(this, "reverseKeyMap"), this.platform = this.detectPlatform(), this.keyMap = I[this.platform], this.reverseKeyMap = this.buildReverseKeyMap(), this.capabilities = this.detectCapabilities(), this.deviceInfo = this.detectDeviceInfo();
578
+ h(this, "platform"), h(this, "capabilities"), h(this, "deviceInfo"), h(this, "keyMap"), h(this, "reverseKeyMap"), this.platform = this.detectPlatform(), this.keyMap = O[this.platform], this.reverseKeyMap = this.buildReverseKeyMap(), this.capabilities = this.detectCapabilities(), this.deviceInfo = this.detectDeviceInfo();
579
579
  }
580
580
  /**
581
581
  * Detect the current Smart TV platform using userAgent and global objects
@@ -588,7 +588,7 @@ class F {
588
588
  return o.Tizen;
589
589
  if (t.webOS || t.PalmSystem)
590
590
  return o.WebOS;
591
- for (const [i, s] of Object.entries(x))
591
+ for (const [i, s] of Object.entries(I))
592
592
  if (i !== o.Generic) {
593
593
  for (const a of s)
594
594
  if (a.test(e))
@@ -862,15 +862,34 @@ class F {
862
862
  };
863
863
  }
864
864
  }
865
+ /**
866
+ * Show debug message using platform-specific native notifications
867
+ * Falls back to console.log
868
+ */
869
+ debug(e) {
870
+ if (console.log(`[Adgent] ${e}`), this.platform === o.WebOS && typeof window < "u") {
871
+ const t = window;
872
+ t.webOS && t.webOS.service && t.webOS.service.request("luna://com.webos.notification", {
873
+ method: "createToast",
874
+ parameters: {
875
+ message: `[Adgent] ${e}`
876
+ },
877
+ onSuccess: () => {
878
+ },
879
+ onFailure: () => {
880
+ }
881
+ });
882
+ }
883
+ }
865
884
  }
866
885
  let y = null;
867
886
  function _() {
868
- return y || (y = new F()), y;
887
+ return y || (y = new N()), y;
869
888
  }
870
- var M = Object.defineProperty, D = (r, e, t) => e in r ? M(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t, v = (r, e, t) => D(r, typeof e != "symbol" ? e + "" : e, t);
889
+ var F = Object.defineProperty, D = (r, e, t) => e in r ? F(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t, m = (r, e, t) => D(r, typeof e != "symbol" ? e + "" : e, t);
871
890
  class L {
872
891
  constructor(e = [], t = {}) {
873
- v(this, "config"), v(this, "trackingEvents"), v(this, "firedEvents"), v(this, "macroContext");
892
+ m(this, "config"), m(this, "trackingEvents"), m(this, "firedEvents"), m(this, "macroContext");
874
893
  var i, s, a;
875
894
  this.config = {
876
895
  debug: (i = t.debug) != null ? i : !1,
@@ -983,7 +1002,7 @@ class L {
983
1002
  this.config.debug && console.log(`[AdTracker] ${e}`);
984
1003
  }
985
1004
  }
986
- var W = Object.defineProperty, U = (r, e, t) => e in r ? W(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t, l = (r, e, t) => U(r, typeof e != "symbol" ? e + "" : e, t);
1005
+ var U = Object.defineProperty, W = (r, e, t) => e in r ? U(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t, l = (r, e, t) => W(r, typeof e != "symbol" ? e + "" : e, t);
987
1006
  const B = {
988
1007
  targetBitrate: 2500,
989
1008
  maxWrapperDepth: 5,
@@ -991,14 +1010,14 @@ const B = {
991
1010
  debug: !1,
992
1011
  skipButtonText: "Skip Ad"
993
1012
  };
994
- class $ {
1013
+ class V {
995
1014
  constructor(e) {
996
- l(this, "config"), l(this, "platform"), l(this, "parser"), l(this, "videoElement", null), l(this, "overlayElement", null), l(this, "skipButtonElement", null), l(this, "tracker", null), l(this, "state"), l(this, "ads", []), l(this, "listeners", /* @__PURE__ */ new Set()), l(this, "quartilesFired", /* @__PURE__ */ new Set()), l(this, "boundKeyHandler", null), l(this, "focusTrap", null), this.config = { ...B, ...e }, this.platform = _(), this.parser = new O({
1015
+ l(this, "config"), l(this, "platform"), l(this, "parser"), l(this, "videoElement", null), l(this, "overlayElement", null), l(this, "skipButtonElement", null), l(this, "progressElement", null), l(this, "tracker", null), l(this, "state"), l(this, "ads", []), l(this, "listeners", /* @__PURE__ */ new Set()), l(this, "quartilesFired", /* @__PURE__ */ new Set()), l(this, "boundKeyHandler", null), l(this, "focusTrap", null), this.config = { ...B, ...e }, this.platform = _(), this.parser = new A({
997
1016
  maxWrapperDepth: this.config.maxWrapperDepth,
998
1017
  timeout: this.config.timeout,
999
1018
  debug: this.config.debug
1000
1019
  }), this.state = {
1001
- status: d.Idle,
1020
+ status: c.Idle,
1002
1021
  currentTime: 0,
1003
1022
  duration: 0,
1004
1023
  muted: !0,
@@ -1016,23 +1035,23 @@ class $ {
1016
1035
  var e, t;
1017
1036
  if (!this.config.container)
1018
1037
  throw new Error("Container element not found");
1019
- this.updateState({ status: d.Loading });
1038
+ this.updateState({ status: c.Loading });
1020
1039
  try {
1021
1040
  const i = await this.parser.parse(this.config.vastUrl);
1022
1041
  if (!i.success || !i.response)
1023
1042
  throw this.createError(
1024
- ((e = i.error) == null ? void 0 : e.code) || h.NO_VAST_RESPONSE,
1043
+ ((e = i.error) == null ? void 0 : e.code) || p.NO_VAST_RESPONSE,
1025
1044
  ((t = i.error) == null ? void 0 : t.message) || "Failed to parse VAST"
1026
1045
  );
1027
1046
  if (this.ads = i.response.ads, this.ads.length === 0)
1028
1047
  throw this.createError(
1029
- h.NO_VAST_RESPONSE,
1048
+ p.NO_VAST_RESPONSE,
1030
1049
  "No ads in VAST response"
1031
1050
  );
1032
1051
  const s = this.getFirstLinearCreative();
1033
1052
  if (!s)
1034
1053
  throw this.createError(
1035
- h.GENERAL_LINEAR_ERROR,
1054
+ p.GENERAL_LINEAR_ERROR,
1036
1055
  "No linear creative found"
1037
1056
  );
1038
1057
  const a = this.parser.selectBestMediaFile(
@@ -1041,14 +1060,14 @@ class $ {
1041
1060
  );
1042
1061
  if (!a)
1043
1062
  throw this.createError(
1044
- h.FILE_NOT_FOUND,
1063
+ p.FILE_NOT_FOUND,
1045
1064
  "No suitable media file found"
1046
1065
  );
1047
1066
  this.updateState({ mediaFile: a });
1048
1067
  const n = this.parser.aggregateTrackingEvents(this.ads);
1049
1068
  this.tracker = new L(n, { debug: this.config.debug }), this.tracker.updateMacroContext({ assetUri: a.url }), this.createVideoElement(a), this.setupFocusManagement(), await this.attemptAutoplay();
1050
1069
  } catch (i) {
1051
- const s = i instanceof Error ? this.createError(h.UNDEFINED_ERROR, i.message) : i;
1070
+ const s = i instanceof Error ? this.createError(p.UNDEFINED_ERROR, i.message) : i;
1052
1071
  this.handleError(s);
1053
1072
  }
1054
1073
  }
@@ -1068,9 +1087,11 @@ class $ {
1068
1087
  */
1069
1088
  createVideoElement(e) {
1070
1089
  const t = document.createElement("video"), i = this.platform.getVideoAttributes();
1071
- Object.entries(i).forEach(([s, a]) => {
1072
- typeof a == "boolean" ? a && t.setAttribute(s, "") : t.setAttribute(s, a);
1073
- }), t.src = e.url, t.style.cssText = `
1090
+ Object.entries(i).forEach(([a, n]) => {
1091
+ typeof n == "boolean" ? n && t.setAttribute(a, "") : t.setAttribute(a, n);
1092
+ }), t.removeAttribute("src"), t.innerHTML = "";
1093
+ const s = document.createElement("source");
1094
+ s.src = e.url, s.type = e.type || "video/mp4", t.appendChild(s), t.setAttribute("crossorigin", "anonymous"), t.style.cssText = `
1074
1095
  width: 100%;
1075
1096
  height: 100%;
1076
1097
  object-fit: contain;
@@ -1078,25 +1099,25 @@ class $ {
1078
1099
  `, t.addEventListener("loadedmetadata", () => {
1079
1100
  this.updateState({
1080
1101
  duration: t.duration,
1081
- status: d.Ready
1102
+ status: c.Ready
1082
1103
  }), this.emit({ type: "loaded" });
1083
1104
  }), t.addEventListener("timeupdate", () => {
1084
1105
  this.handleTimeUpdate(t);
1085
1106
  }), t.addEventListener("ended", () => {
1086
1107
  this.handleComplete();
1087
1108
  }), t.addEventListener("error", () => {
1088
- const s = t.error;
1109
+ const a = t.error;
1089
1110
  this.handleError(
1090
1111
  this.createError(
1091
- h.MEDIA_NOT_SUPPORTED,
1092
- (s == null ? void 0 : s.message) || "Video playback error"
1112
+ p.MEDIA_NOT_SUPPORTED,
1113
+ (a == null ? void 0 : a.message) || "Video playback error"
1093
1114
  )
1094
1115
  );
1095
1116
  }), t.addEventListener("play", () => {
1096
- this.updateState({ status: d.Playing });
1117
+ this.updateState({ status: c.Playing });
1097
1118
  }), t.addEventListener("pause", () => {
1098
- var s;
1099
- this.state.status !== d.Completed && (this.updateState({ status: d.Paused }), this.emit({ type: "pause" }), (s = this.tracker) == null || s.track("pause"));
1119
+ var a;
1120
+ this.state.status !== c.Completed && (this.updateState({ status: c.Paused }), this.emit({ type: "pause" }), (a = this.tracker) == null || a.track("pause"));
1100
1121
  }), this.config.container.appendChild(t), this.videoElement = t, this.log(`Video element created with src: ${e.url}`);
1101
1122
  }
1102
1123
  /**
@@ -1115,7 +1136,7 @@ class $ {
1115
1136
  * Show interactive overlay for manual ad start (autoplay fallback)
1116
1137
  */
1117
1138
  showStartOverlay() {
1118
- if (this.updateState({ status: d.WaitingForInteraction }), this.config.customStartOverlay) {
1139
+ if (this.updateState({ status: c.WaitingForInteraction }), this.config.customStartOverlay) {
1119
1140
  this.overlayElement = this.config.customStartOverlay, this.config.container.appendChild(this.overlayElement);
1120
1141
  return;
1121
1142
  }
@@ -1127,24 +1148,28 @@ class $ {
1127
1148
  left: 0;
1128
1149
  width: 100%;
1129
1150
  height: 100%;
1130
- display: flex;
1131
- align-items: center;
1132
- justify-content: center;
1133
- background: rgba(0, 0, 0, 0.7);
1151
+ display: table;
1152
+ background: rgba(0, 0, 0, 0.5);
1134
1153
  z-index: 100;
1135
1154
  ">
1136
- <button id="adgent-start-btn" style="
1137
- padding: 20px 40px;
1138
- font-size: 24px;
1139
- background: #fff;
1140
- color: #000;
1141
- border: none;
1142
- border-radius: 8px;
1143
- cursor: pointer;
1144
- font-weight: bold;
1145
- ">
1146
- Start Ad
1147
- </button>
1155
+ <div style="display: table-cell; vertical-align: middle; text-align: center;">
1156
+ <button id="adgent-start-btn" style="
1157
+ width: 80px;
1158
+ height: 80px;
1159
+ background: rgba(0, 0, 0, 0.7);
1160
+ border: 3px solid #fff;
1161
+ border-radius: 50%;
1162
+ cursor: pointer;
1163
+ display: inline-block;
1164
+ line-height: 80px;
1165
+ text-align: center;
1166
+ color: #fff;
1167
+ font-size: 40px;
1168
+ padding: 0 0 0 8px; /* Optical center for triangle */
1169
+ ">
1170
+
1171
+ </button>
1172
+ </div>
1148
1173
  </div>
1149
1174
  `, e.style.cssText = "position: absolute; top: 0; left: 0; width: 100%; height: 100%;";
1150
1175
  const t = e.querySelector("#adgent-start-btn");
@@ -1160,7 +1185,7 @@ class $ {
1160
1185
  } catch (e) {
1161
1186
  this.handleError(
1162
1187
  this.createError(
1163
- h.GENERAL_LINEAR_ERROR,
1188
+ p.GENERAL_LINEAR_ERROR,
1164
1189
  `Playback failed: ${e}`
1165
1190
  )
1166
1191
  );
@@ -1177,9 +1202,9 @@ class $ {
1177
1202
  */
1178
1203
  handlePlaybackStart() {
1179
1204
  var e, t, i, s, a;
1180
- this.updateState({ status: d.Playing }), this.emit({ type: "start" }), (t = (e = this.config).onStart) == null || t.call(e);
1205
+ this.updateState({ status: c.Playing }), this.emit({ type: "start" }), (t = (e = this.config).onStart) == null || t.call(e);
1181
1206
  const n = this.parser.aggregateImpressions(this.ads);
1182
- (i = this.tracker) == null || i.fireImpressions(n), (s = this.tracker) == null || s.track("start"), (a = this.tracker) == null || a.track("creativeView"), this.setupSkipButton(), this.log("Playback started");
1207
+ (i = this.tracker) == null || i.fireImpressions(n), (s = this.tracker) == null || s.track("start"), (a = this.tracker) == null || a.track("creativeView"), this.setupSkipButton(), this.setupProgressUI(), this.log("Playback started");
1183
1208
  }
1184
1209
  /**
1185
1210
  * Handle time updates for progress tracking
@@ -1188,18 +1213,18 @@ class $ {
1188
1213
  var t, i, s;
1189
1214
  const a = e.currentTime, n = e.duration;
1190
1215
  if (!n || isNaN(n)) return;
1191
- const u = a / n * 100, m = this.calculateQuartile(u);
1216
+ const d = a / n * 100, f = this.calculateQuartile(d);
1192
1217
  this.updateState({
1193
1218
  currentTime: a,
1194
1219
  duration: n
1195
- }), this.updateSkipCountdown(a), (t = this.tracker) == null || t.updateMacroContext({ adPlayhead: a });
1196
- const f = {
1220
+ }), this.updateSkipCountdown(a), (t = this.tracker) == null || t.updateMacroContext({ adPlayhead: a }), this.updateProgressUI(a, n);
1221
+ const v = {
1197
1222
  currentTime: a,
1198
1223
  duration: n,
1199
- percentage: u,
1200
- quartile: m
1224
+ percentage: d,
1225
+ quartile: f
1201
1226
  };
1202
- this.emit({ type: "progress", data: f }), (s = (i = this.config).onProgress) == null || s.call(i, f), this.fireQuartileEvents(u);
1227
+ this.emit({ type: "progress", data: v }), (s = (i = this.config).onProgress) == null || s.call(i, v), this.fireQuartileEvents(d);
1203
1228
  }
1204
1229
  /**
1205
1230
  * Calculate current quartile (0-4)
@@ -1253,7 +1278,7 @@ class $ {
1253
1278
  const i = this.getFirstLinearCreative(), s = (t = this.config.skipOffset) != null ? t : i == null ? void 0 : i.skipOffset;
1254
1279
  if (!s || !this.skipButtonElement) return;
1255
1280
  const a = Math.max(0, s - e);
1256
- this.updateState({ skipCountdown: a }), a <= 0 && !this.state.canSkip ? (this.updateState({ canSkip: !0 }), this.skipButtonElement.textContent = this.config.skipButtonText, this.skipButtonElement.style.opacity = "1") : a > 0 && (this.skipButtonElement.textContent = `Skip in ${Math.ceil(a)}s`, this.skipButtonElement.style.opacity = "0.6");
1281
+ this.updateState({ skipCountdown: a }), a <= 0 && !this.state.canSkip ? (this.updateState({ canSkip: !0 }), this.skipButtonElement.textContent = this.config.skipButtonText, this.skipButtonElement.style.opacity = "1", this.skipButtonElement.focus()) : a > 0 && (this.skipButtonElement.textContent = `Skip in ${Math.ceil(a)}s`, this.skipButtonElement.style.opacity = "0.6");
1257
1282
  }
1258
1283
  /**
1259
1284
  * Skip the ad
@@ -1271,7 +1296,7 @@ class $ {
1271
1296
  */
1272
1297
  handleComplete() {
1273
1298
  var e, t, i;
1274
- this.updateState({ status: d.Completed }), (e = this.tracker) == null || e.track("complete"), this.emit({ type: "complete" }), (i = (t = this.config).onComplete) == null || i.call(t), this.log("Ad completed");
1299
+ this.updateState({ status: c.Completed }), (e = this.tracker) == null || e.track("complete"), this.emit({ type: "complete" }), (i = (t = this.config).onComplete) == null || i.call(t), this.log("Ad completed");
1275
1300
  }
1276
1301
  /**
1277
1302
  * Handle errors with recovery attempt or callback
@@ -1279,7 +1304,7 @@ class $ {
1279
1304
  handleError(e) {
1280
1305
  var t, i, s;
1281
1306
  this.updateState({
1282
- status: d.Error,
1307
+ status: c.Error,
1283
1308
  error: e
1284
1309
  });
1285
1310
  const a = [];
@@ -1296,28 +1321,59 @@ class $ {
1296
1321
  t && (e.preventDefault(), e.stopPropagation(), this.handleKeyAction(t));
1297
1322
  }, document.addEventListener("keydown", this.boundKeyHandler, !0);
1298
1323
  }
1324
+ /**
1325
+ * Set up progress UI in top-left
1326
+ */
1327
+ setupProgressUI() {
1328
+ const e = document.createElement("div");
1329
+ e.style.cssText = `
1330
+ position: absolute;
1331
+ top: 20px;
1332
+ left: 20px;
1333
+ background: rgba(0, 0, 0, 0.7);
1334
+ color: #fff;
1335
+ padding: 6px 12px;
1336
+ border-radius: 4px;
1337
+ font-size: 14px;
1338
+ font-family: sans-serif;
1339
+ z-index: 101;
1340
+ display: block;
1341
+ white-space: nowrap;
1342
+ `, e.innerHTML = `
1343
+ <span style="display: inline-block; vertical-align: middle; margin-right: 8px; background: #f4b400; color: #000; padding: 2px 4px; border-radius: 2px; font-weight: bold; font-size: 12px;">Ad</span>
1344
+ <span id="adgent-progress-text" style="display: inline-block; vertical-align: middle;">1 of ${this.ads.length} • 0:00</span>
1345
+ `, this.config.container.appendChild(e), this.progressElement = e;
1346
+ }
1347
+ /**
1348
+ * Update progress UI text
1349
+ */
1350
+ updateProgressUI(e, t) {
1351
+ if (!this.progressElement) return;
1352
+ const i = Math.ceil(t - e), s = Math.floor(i / 60), a = i % 60, n = `${s}:${a.toString().padStart(2, "0")}`, d = this.progressElement.querySelector("#adgent-progress-text");
1353
+ d && (d.textContent = `1 of ${this.ads.length} • ${n}`);
1354
+ }
1299
1355
  /**
1300
1356
  * Handle key actions from remote control
1301
1357
  */
1302
1358
  handleKeyAction(e) {
1303
1359
  var t, i;
1304
1360
  switch (this.log(`Key action: ${e}`), e) {
1305
- case c.Enter:
1306
- this.state.status === d.WaitingForInteraction ? this.onStartClick() : this.state.canSkip && this.skip();
1361
+ case u.Enter:
1362
+ this.state.status === c.WaitingForInteraction ? this.onStartClick() : this.state.canSkip && this.skip();
1307
1363
  break;
1308
- case c.Back:
1364
+ case u.Back:
1309
1365
  this.log("Back pressed - ignoring during ad");
1310
1366
  break;
1311
- case c.Play:
1367
+ case u.Play:
1312
1368
  (t = this.videoElement) == null || t.play();
1313
1369
  break;
1314
- case c.Pause:
1370
+ case u.Pause:
1315
1371
  (i = this.videoElement) == null || i.pause();
1316
1372
  break;
1317
- case c.Left:
1318
- case c.Right:
1319
- case c.Up:
1320
- case c.Down:
1373
+ case u.Left:
1374
+ case u.Right:
1375
+ case u.Up:
1376
+ case u.Down:
1321
1377
  break;
1322
1378
  }
1323
1379
  }
@@ -1351,8 +1407,8 @@ class $ {
1351
1407
  * Clean up all resources
1352
1408
  */
1353
1409
  destroy() {
1354
- var e, t, i, s, a;
1355
- this.boundKeyHandler && (document.removeEventListener("keydown", this.boundKeyHandler, !0), this.boundKeyHandler = null), (e = this.videoElement) == null || e.remove(), (t = this.overlayElement) == null || t.remove(), (i = this.skipButtonElement) == null || i.remove(), (s = this.focusTrap) == null || s.remove(), this.videoElement = null, this.overlayElement = null, this.skipButtonElement = null, this.focusTrap = null, (a = this.tracker) == null || a.reset(), this.quartilesFired.clear(), this.listeners.clear(), this.ads = [], this.emit({ type: "destroy" }), this.log("Player destroyed");
1410
+ var e, t, i, s, a, n;
1411
+ this.boundKeyHandler && (document.removeEventListener("keydown", this.boundKeyHandler, !0), this.boundKeyHandler = null), (e = this.videoElement) == null || e.remove(), (t = this.overlayElement) == null || t.remove(), (i = this.skipButtonElement) == null || i.remove(), (s = this.progressElement) == null || s.remove(), (a = this.focusTrap) == null || a.remove(), this.videoElement = null, this.overlayElement = null, this.skipButtonElement = null, this.progressElement = null, this.focusTrap = null, (n = this.tracker) == null || n.reset(), this.quartilesFired.clear(), this.listeners.clear(), this.ads = [], this.emit({ type: "destroy" }), this.log("Player destroyed");
1356
1412
  }
1357
1413
  /**
1358
1414
  * Update internal state
@@ -1381,21 +1437,21 @@ class $ {
1381
1437
  * Debug logging
1382
1438
  */
1383
1439
  log(e) {
1384
- this.config.debug && console.log(`[AdPlayer] ${e}`);
1440
+ this.config.debug && this.platform.debug(e);
1385
1441
  }
1386
1442
  }
1387
1443
  export {
1388
- $ as AdPlayer,
1444
+ V as AdPlayer,
1389
1445
  L as AdTracker,
1390
- $ as AdgentSDK,
1391
- I as DEFAULT_KEY_CODES,
1392
- c as KeyAction,
1393
- x as PLATFORM_DETECTION_PATTERNS,
1446
+ V as AdgentSDK,
1447
+ O as DEFAULT_KEY_CODES,
1448
+ u as KeyAction,
1449
+ I as PLATFORM_DETECTION_PATTERNS,
1394
1450
  o as Platform,
1395
- F as PlatformAdapter,
1396
- d as PlaybackStatus,
1397
- h as VASTErrorCode,
1398
- O as VASTParser,
1451
+ N as PlatformAdapter,
1452
+ c as PlaybackStatus,
1453
+ p as VASTErrorCode,
1454
+ A as VASTParser,
1399
1455
  _ as getPlatformAdapter,
1400
1456
  g as replaceMacros
1401
1457
  };
@@ -1,35 +1,39 @@
1
- (function(l,f){typeof exports=="object"&&typeof module<"u"?f(exports,require("fast-xml-parser")):typeof define=="function"&&define.amd?define(["exports","fast-xml-parser"],f):(l=typeof globalThis<"u"?globalThis:l||self,f(l.AdgentSDK={},l.FastXMLParser))})(this,function(l,f){"use strict";var d=(r=>(r.Idle="idle",r.Loading="loading",r.Ready="ready",r.Playing="playing",r.Paused="paused",r.Completed="completed",r.Error="error",r.WaitingForInteraction="waiting_for_interaction",r))(d||{}),c=(r=>(r[r.XML_PARSING_ERROR=100]="XML_PARSING_ERROR",r[r.VAST_SCHEMA_VALIDATION_ERROR=101]="VAST_SCHEMA_VALIDATION_ERROR",r[r.VAST_VERSION_NOT_SUPPORTED=102]="VAST_VERSION_NOT_SUPPORTED",r[r.GENERAL_WRAPPER_ERROR=300]="GENERAL_WRAPPER_ERROR",r[r.WRAPPER_TIMEOUT=301]="WRAPPER_TIMEOUT",r[r.WRAPPER_LIMIT_REACHED=302]="WRAPPER_LIMIT_REACHED",r[r.NO_VAST_RESPONSE=303]="NO_VAST_RESPONSE",r[r.GENERAL_LINEAR_ERROR=400]="GENERAL_LINEAR_ERROR",r[r.FILE_NOT_FOUND=401]="FILE_NOT_FOUND",r[r.MEDIA_TIMEOUT=402]="MEDIA_TIMEOUT",r[r.MEDIA_NOT_SUPPORTED=403]="MEDIA_NOT_SUPPORTED",r[r.GENERAL_COMPANION_ERROR=600]="GENERAL_COMPANION_ERROR",r[r.UNDEFINED_ERROR=900]="UNDEFINED_ERROR",r))(c||{}),I=Object.defineProperty,x=(r,e,t)=>e in r?I(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,k=(r,e,t)=>x(r,typeof e!="symbol"?e+"":e,t);class w{constructor(e={}){k(this,"config"),k(this,"xmlParser");var t,i,s,a;this.config={maxWrapperDepth:(t=e.maxWrapperDepth)!=null?t:5,timeout:(i=e.timeout)!=null?i:1e4,debug:(s=e.debug)!=null?s:!1,fetchFn:(a=e.fetchFn)!=null?a:fetch.bind(globalThis)},this.xmlParser=new f.XMLParser({ignoreAttributes:!1,attributeNamePrefix:"@_",textNodeName:"#text",parseAttributeValue:!0,trimValues:!0})}async parse(e){try{return{success:!0,response:await this.fetchAndParse(e,0)}}catch(t){const i=t instanceof Error?t.message:"Unknown error";return{success:!1,error:{code:c.GENERAL_WRAPPER_ERROR,message:i}}}}async fetchAndParse(e,t){if(t>=this.config.maxWrapperDepth)throw new Error(`Wrapper limit exceeded (max: ${this.config.maxWrapperDepth})`);this.log(`Fetching VAST (depth: ${t}): ${e}`);const i=await this.fetchWithTimeout(e),s=this.parseXml(i),a=await Promise.all(s.ads.map(async n=>{var p;return(p=n.wrapper)!=null&&p.vastAdTagURI?this.resolveWrapper(n,t+1):n}));return{...s,ads:a.flat()}}async resolveWrapper(e,t){var i;if(!((i=e.wrapper)!=null&&i.vastAdTagURI))return[e];try{return(await this.fetchAndParse(e.wrapper.vastAdTagURI,t)).ads.map(a=>this.mergeWrapperTracking(e,a))}catch(s){if(this.log(`Wrapper resolution failed: ${s}`),e.wrapper.fallbackOnNoAd)return[];throw s}}mergeWrapperTracking(e,t){return{...t,impressions:[...e.impressions,...t.impressions],errors:[...e.errors,...t.errors],creatives:t.creatives.map(i=>({...i,linear:i.linear?{...i.linear,trackingEvents:[...this.getWrapperTrackingEvents(e),...i.linear.trackingEvents]}:void 0}))}}getWrapperTrackingEvents(e){var t;const i=[];for(const s of e.creatives)(t=s.linear)!=null&&t.trackingEvents&&i.push(...s.linear.trackingEvents);return i}async fetchWithTimeout(e){const t=new AbortController,i=setTimeout(()=>t.abort(),this.config.timeout);try{const s=await this.config.fetchFn(e,{signal:t.signal});if(!s.ok)throw new Error(`HTTP ${s.status}: ${s.statusText}`);return s.text()}finally{clearTimeout(i)}}parseXml(e){const i=this.xmlParser.parse(e).VAST;if(!i)throw new Error("Invalid VAST: missing VAST element");const s=i["@_version"]||"4.0",a=this.parseAds(i.Ad);return{version:s,ads:a,errors:this.parseErrors(i.Error)}}parseAds(e){return e?(Array.isArray(e)?e:[e]).map(i=>this.parseAd(i)):[]}parseAd(e){var t,i,s;const a=!!e.Wrapper,n=e.InLine||e.Wrapper;return{id:e["@_id"]||"",sequence:e["@_sequence"],adSystem:n!=null&&n.AdSystem?{name:typeof n.AdSystem=="string"?n.AdSystem:n.AdSystem["#text"]||"",version:(t=n.AdSystem)==null?void 0:t["@_version"]}:void 0,adTitle:n==null?void 0:n.AdTitle,impressions:this.parseImpressions(n==null?void 0:n.Impression),errors:this.parseErrors(n==null?void 0:n.Error),creatives:this.parseCreatives((i=n==null?void 0:n.Creatives)==null?void 0:i.Creative),wrapper:a?{vastAdTagURI:n.VASTAdTagURI,followAdditionalWrappers:n["@_followAdditionalWrappers"]!==!1,allowMultipleAds:n["@_allowMultipleAds"],fallbackOnNoAd:n["@_fallbackOnNoAd"]}:void 0,inLine:a?void 0:{adTitle:(n==null?void 0:n.AdTitle)||"",description:n==null?void 0:n.Description,advertiser:n==null?void 0:n.Advertiser,creatives:this.parseCreatives((s=n==null?void 0:n.Creatives)==null?void 0:s.Creative)}}}parseImpressions(e){return e?(Array.isArray(e)?e:[e]).map(i=>({id:i["@_id"],url:typeof i=="string"?i:i["#text"]||""})):[]}parseCreatives(e){return e?(Array.isArray(e)?e:[e]).map(i=>({id:i["@_id"],sequence:i["@_sequence"],adId:i["@_adId"],linear:i.Linear?this.parseLinear(i.Linear):void 0})):[]}parseLinear(e){var t,i;return{duration:this.parseDuration(e.Duration),skipOffset:e["@_skipoffset"]?this.parseDuration(e["@_skipoffset"]):void 0,mediaFiles:this.parseMediaFiles((t=e.MediaFiles)==null?void 0:t.MediaFile),trackingEvents:this.parseTrackingEvents((i=e.TrackingEvents)==null?void 0:i.Tracking),videoClicks:e.VideoClicks?{clickThrough:e.VideoClicks.ClickThrough?{id:e.VideoClicks.ClickThrough["@_id"],url:typeof e.VideoClicks.ClickThrough=="string"?e.VideoClicks.ClickThrough:e.VideoClicks.ClickThrough["#text"]||""}:void 0}:void 0,adParameters:e.AdParameters}}parseMediaFiles(e){return e?(Array.isArray(e)?e:[e]).map(i=>({id:i["@_id"],url:typeof i=="string"?i:i["#text"]||"",delivery:i["@_delivery"]||"progressive",type:i["@_type"]||"video/mp4",width:parseInt(i["@_width"],10)||0,height:parseInt(i["@_height"],10)||0,bitrate:i["@_bitrate"]?parseInt(i["@_bitrate"],10):void 0,codec:i["@_codec"],scalable:i["@_scalable"],maintainAspectRatio:i["@_maintainAspectRatio"]})):[]}parseTrackingEvents(e){return e?(Array.isArray(e)?e:[e]).map(i=>({event:i["@_event"],url:typeof i=="string"?i:i["#text"]||"",offset:i["@_offset"]?this.parseDuration(i["@_offset"]):void 0})):[]}parseErrors(e){return e?(Array.isArray(e)?e:[e]).map(i=>typeof i=="string"?i:i["#text"]||""):[]}parseDuration(e){if(typeof e=="number")return e;if(typeof e!="string")return 0;if(e.endsWith("%"))return parseFloat(e)/100;const t=e.match(/(\d+):(\d+):(\d+(?:\.\d+)?)/);if(t){const[,i,s,a]=t;return parseInt(i,10)*3600+parseInt(s,10)*60+parseFloat(a)}return parseFloat(e)||0}selectBestMediaFile(e,t=2500){if(e.length===0)return null;const i=e.filter(n=>n.type.includes("mp4")||n.type.includes("video/mp4"));return[...i.length>0?i:e].sort((n,p)=>{const _=n.bitrate||0,y=p.bitrate||0,W=n.height>1080?1e4:0,B=p.height>1080?1e4:0,V=Math.abs(_-t)+W,$=Math.abs(y-t)+B;return V-$})[0]||null}aggregateTrackingEvents(e){var t;const i=[];for(const s of e)for(const a of s.creatives)(t=a.linear)!=null&&t.trackingEvents&&i.push(...a.linear.trackingEvents);return i}aggregateImpressions(e){const t=[];for(const i of e)for(const s of i.impressions)t.push(s.url);return t}log(e){this.config.debug&&console.log(`[VASTParser] ${e}`)}}function m(r,e={}){let t=r;return t=t.replace(/\[TIMESTAMP\]/g,Date.now().toString()),t=t.replace(/\[CACHEBUSTING\]/g,Math.random().toString(36).substring(2,15)),e.assetUri&&(t=t.replace(/\[ASSETURI\]/g,encodeURIComponent(e.assetUri))),e.contentPlayhead!==void 0&&(t=t.replace(/\[CONTENTPLAYHEAD\]/g,R(e.contentPlayhead))),e.adPlayhead!==void 0&&(t=t.replace(/\[ADPLAYHEAD\]/g,R(e.adPlayhead))),e.errorCode!==void 0&&(t=t.replace(/\[ERRORCODE\]/g,e.errorCode.toString())),e.breakPosition!==void 0&&(t=t.replace(/\[BREAKPOSITION\]/g,e.breakPosition.toString())),e.adType&&(t=t.replace(/\[ADTYPE\]/g,e.adType)),t}function R(r){const e=Math.floor(r/3600),t=Math.floor(r%3600/60),i=Math.floor(r%60),s=Math.floor(r%1*1e3);return e.toString().padStart(2,"0")+":"+t.toString().padStart(2,"0")+":"+i.toString().padStart(2,"0")+"."+s.toString().padStart(3,"0")}var o=(r=>(r.WebOS="webos",r.Tizen="tizen",r.Vidaa="vidaa",r.WhaleOS="whaleos",r.FireTV="firetv",r.Roku="roku",r.Xbox="xbox",r.PlayStation="playstation",r.AndroidTV="androidtv",r.Vizio="vizio",r.Generic="generic",r))(o||{}),h=(r=>(r.Enter="enter",r.Back="back",r.Left="left",r.Right="right",r.Up="up",r.Down="down",r.Play="play",r.Pause="pause",r.PlayPause="playPause",r.Stop="stop",r.FastForward="fastForward",r.Rewind="rewind",r.Menu="menu",r.Info="info",r.Red="red",r.Green="green",r.Yellow="yellow",r.Blue="blue",r.ChannelUp="channelUp",r.ChannelDown="channelDown",r.VolumeUp="volumeUp",r.VolumeDown="volumeDown",r.Mute="mute",r))(h||{});const T={webos:{13:"enter",461:"back",37:"left",38:"up",39:"right",40:"down",415:"play",19:"pause",413:"stop",417:"fastForward",412:"rewind",457:"info",403:"red",404:"green",405:"yellow",406:"blue",33:"channelUp",34:"channelDown"},tizen:{13:"enter",10009:"back",37:"left",38:"up",39:"right",40:"down",415:"play",19:"pause",10252:"playPause",413:"stop",417:"fastForward",412:"rewind",457:"info",403:"red",404:"green",405:"yellow",406:"blue",427:"channelUp",428:"channelDown",447:"volumeUp",448:"volumeDown",449:"mute"},vidaa:{13:"enter",8:"back",27:"back",37:"left",38:"up",39:"right",40:"down",415:"play",19:"pause",413:"stop",417:"fastForward",412:"rewind"},whaleos:{13:"enter",27:"back",37:"left",38:"up",39:"right",40:"down",415:"play",19:"pause",413:"stop"},firetv:{13:"enter",4:"back",27:"back",37:"left",38:"up",39:"right",40:"down",85:"playPause",126:"play",127:"pause",89:"rewind",90:"fastForward",82:"menu"},roku:{13:"enter",27:"back",8:"back",37:"left",38:"up",39:"right",40:"down",179:"playPause",178:"stop",228:"fastForward",227:"rewind"},xbox:{13:"enter",27:"back",37:"left",38:"up",39:"right",40:"down",195:"menu",196:"menu"},playstation:{13:"enter",27:"back",37:"left",38:"up",39:"right",40:"down"},androidtv:{13:"enter",4:"back",27:"back",37:"left",38:"up",39:"right",40:"down",85:"playPause",126:"play",127:"pause",89:"rewind",90:"fastForward",82:"menu"},vizio:{13:"enter",27:"back",8:"back",37:"left",38:"up",39:"right",40:"down",415:"play",19:"pause"},generic:{13:"enter",27:"back",8:"back",37:"left",38:"up",39:"right",40:"down",32:"playPause",80:"play",83:"stop",77:"mute"}},S={tizen:[/Tizen/i,/SMART-TV.*Samsung/i],webos:[/Web0S/i,/WebOS/i,/LG.*NetCast/i,/LGE.*TV/i],vidaa:[/Vidaa/i,/VIDAA/i,/Hisense/i],whaleos:[/WhaleTV/i,/Whale/i],firetv:[/AFT/i,/AFTS/i,/AFTM/i,/Amazon.*Fire/i],roku:[/Roku/i],xbox:[/Xbox/i,/Edge.*Xbox/i],playstation:[/PlayStation/i,/PS4/i,/PS5/i],androidtv:[/Android.*TV/i,/Chromecast/i,/BRAVIA/i,/SHIELD/i],vizio:[/VIZIO/i,/SmartCast/i],generic:[]};var C=Object.defineProperty,N=(r,e,t)=>e in r?C(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,v=(r,e,t)=>N(r,typeof e!="symbol"?e+"":e,t);class P{constructor(){v(this,"platform"),v(this,"capabilities"),v(this,"deviceInfo"),v(this,"keyMap"),v(this,"reverseKeyMap"),this.platform=this.detectPlatform(),this.keyMap=T[this.platform],this.reverseKeyMap=this.buildReverseKeyMap(),this.capabilities=this.detectCapabilities(),this.deviceInfo=this.detectDeviceInfo()}detectPlatform(){if(typeof window>"u"||typeof navigator>"u")return o.Generic;const e=navigator.userAgent,t=window;if(t.tizen)return o.Tizen;if(t.webOS||t.PalmSystem)return o.WebOS;for(const[i,s]of Object.entries(S))if(i!==o.Generic){for(const a of s)if(a.test(e))return i}return o.Generic}detectCapabilities(){const e=typeof navigator<"u",t=typeof document<"u",i=typeof window<"u",s={sendBeacon:e&&"sendBeacon"in navigator,fetchKeepalive:typeof fetch<"u",mutedAutoplayRequired:!0,fullscreen:t&&("fullscreenEnabled"in document||"webkitFullscreenEnabled"in document),hardwareDecodeInfo:!1,hdr:!1,hdr10Plus:!1,dolbyVision:!1,dolbyAtmos:!1,hevc:this.isCodecSupported('video/mp4; codecs="hvc1"'),vp9:this.isCodecSupported('video/webm; codecs="vp9"'),av1:this.isCodecSupported('video/mp4; codecs="av01.0.05M.08"'),maxResolution:this.detectMaxResolution(),touch:i&&"ontouchstart"in window,voice:!1};switch(this.platform){case o.Tizen:return{...s,hardwareDecodeInfo:!0,hdr:!0,hevc:!0,voice:!0};case o.WebOS:return{...s,hardwareDecodeInfo:!0,hdr:!0,dolbyVision:!0,dolbyAtmos:!0,hevc:!0,voice:!0};case o.FireTV:return{...s,hdr:!0,hdr10Plus:!0,dolbyVision:!0,hevc:!0,voice:!0};case o.Roku:return{...s,hdr:!0,dolbyVision:!0,hevc:!0,voice:!0};case o.Xbox:return{...s,hdr:!0,dolbyVision:!0,dolbyAtmos:!0,hevc:!0,av1:!0,voice:!0};case o.PlayStation:return{...s,hdr:!0,hevc:!0};case o.AndroidTV:return{...s,hdr:!0,dolbyVision:!0,hevc:!0,vp9:!0,voice:!0};default:return s}}detectDeviceInfo(){var e,t,i;const s={platform:this.platform};typeof window<"u"&&(s.screenWidth=(e=window.screen)==null?void 0:e.width,s.screenHeight=(t=window.screen)==null?void 0:t.height,s.devicePixelRatio=window.devicePixelRatio);const a=window;if(this.platform===o.Tizen&&((i=a.tizen)!=null&&i.systeminfo))try{a.tizen.systeminfo.getPropertyValue("BUILD",n=>{s.model=n.model,s.manufacturer=n.manufacturer||"Samsung"})}catch{s.manufacturer="Samsung"}if(this.platform===o.WebOS&&a.webOSSystem)try{const n=a.webOSSystem.deviceInfo;s.model=n==null?void 0:n.modelName,s.manufacturer="LG",s.osVersion=n==null?void 0:n.version}catch{s.manufacturer="LG"}return s}detectMaxResolution(){var e,t;if(typeof window>"u")return"unknown";const i=((e=window.screen)==null?void 0:e.width)||0,s=((t=window.screen)==null?void 0:t.height)||0,a=Math.max(i,s);return a>=3840?"4k":a>=1920?"1080p":a>=1280?"720p":"unknown"}buildReverseKeyMap(){const e=new Map;for(const[t,i]of Object.entries(this.keyMap)){const s=parseInt(t,10),a=e.get(i)||[];a.push(s),e.set(i,a)}return e}normalizeKeyCode(e){var t;return(t=this.keyMap[e])!=null?t:null}getKeyCodesForAction(e){return this.reverseKeyMap.get(e)||[]}isCodecSupported(e){if(typeof document>"u")return!1;try{const i=document.createElement("video").canPlayType(e);return i==="probably"||i==="maybe"}catch{return!1}}registerTizenKeys(){if(this.platform!==o.Tizen)return;const e=window.tizen;e!=null&&e.tvinputdevice&&["MediaPlay","MediaPause","MediaStop","MediaFastForward","MediaRewind","MediaPlayPause","ColorF0Red","ColorF1Green","ColorF2Yellow","ColorF3Blue","Info"].forEach(i=>{try{e.tvinputdevice.registerKey(i)}catch{}})}registerWebOSKeys(){this.platform,o.WebOS}getVideoAttributes(){const e={muted:!0,playsinline:!0,autoplay:!0,"webkit-playsinline":!0};switch(this.platform){case o.Tizen:e["data-samsung-immersive"]="true";break;case o.WebOS:e["data-lg-immersive"]="true";break;case o.FireTV:case o.AndroidTV:e["x-webkit-airplay"]="allow";break}return e}getRecommendedVideoSettings(){switch(this.platform){case o.Tizen:case o.WebOS:return{maxBitrate:15e3,preferredCodec:"hevc",maxResolution:"4k"};case o.FireTV:return{maxBitrate:1e4,preferredCodec:"hevc",maxResolution:"4k"};case o.Roku:return{maxBitrate:8e3,preferredCodec:"h264",maxResolution:"4k"};case o.Xbox:case o.PlayStation:return{maxBitrate:2e4,preferredCodec:"hevc",maxResolution:"4k"};default:return{maxBitrate:5e3,preferredCodec:"h264",maxResolution:"1080p"}}}}let E=null;function b(){return E||(E=new P),E}var M=Object.defineProperty,D=(r,e,t)=>e in r?M(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,g=(r,e,t)=>D(r,typeof e!="symbol"?e+"":e,t);class A{constructor(e=[],t={}){g(this,"config"),g(this,"trackingEvents"),g(this,"firedEvents"),g(this,"macroContext");var i,s,a;this.config={debug:(i=t.debug)!=null?i:!1,retry:(s=t.retry)!=null?s:!1,maxRetries:(a=t.maxRetries)!=null?a:3},this.trackingEvents=this.groupEventsByType(e),this.firedEvents=new Set,this.macroContext={}}groupEventsByType(e){const t=new Map;for(const i of e){const s=t.get(i.event)||[];s.push(i),t.set(i.event,s)}return t}updateMacroContext(e){this.macroContext={...this.macroContext,...e}}track(e,t=!0){const i=this.trackingEvents.get(e);if(!i){this.log(`No tracking URLs for event: ${e}`);return}for(const s of i){const a=`${e}:${s.url}`;if(t&&this.firedEvents.has(a)){this.log(`Skipping duplicate event: ${e}`);continue}const n=m(s.url,this.macroContext);this.firePixel(n),t&&this.firedEvents.add(a)}}firePixel(e){const t=b();this.log(`Firing pixel: ${e}`);try{if(t.capabilities.sendBeacon&&navigator.sendBeacon(e))return;if(t.capabilities.fetchKeepalive){fetch(e,{method:"GET",keepalive:!0,mode:"no-cors",credentials:"omit"}).catch(()=>{});return}this.fireImageBeacon(e)}catch{this.log(`Failed to fire pixel: ${e}`)}}fireImageBeacon(e){const t=new Image(1,1);t.src=e}fireImpressions(e){for(const t of e){const i=m(t,this.macroContext);this.firePixel(i)}}fireError(e,t){const i={...this.macroContext,errorCode:t};for(const s of e){const a=m(s,i);this.firePixel(a)}}reset(){this.firedEvents.clear()}log(e){this.config.debug&&console.log(`[AdTracker] ${e}`)}}var F=Object.defineProperty,L=(r,e,t)=>e in r?F(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,u=(r,e,t)=>L(r,typeof e!="symbol"?e+"":e,t);const U={targetBitrate:2500,maxWrapperDepth:5,timeout:1e4,debug:!1,skipButtonText:"Skip Ad"};class O{constructor(e){u(this,"config"),u(this,"platform"),u(this,"parser"),u(this,"videoElement",null),u(this,"overlayElement",null),u(this,"skipButtonElement",null),u(this,"tracker",null),u(this,"state"),u(this,"ads",[]),u(this,"listeners",new Set),u(this,"quartilesFired",new Set),u(this,"boundKeyHandler",null),u(this,"focusTrap",null),this.config={...U,...e},this.platform=b(),this.parser=new w({maxWrapperDepth:this.config.maxWrapperDepth,timeout:this.config.timeout,debug:this.config.debug}),this.state={status:d.Idle,currentTime:0,duration:0,muted:!0,volume:1,canSkip:!1,skipCountdown:0,mediaFile:null,error:null},this.platform.platform==="tizen"&&this.platform.registerTizenKeys()}async init(){var e,t;if(!this.config.container)throw new Error("Container element not found");this.updateState({status:d.Loading});try{const i=await this.parser.parse(this.config.vastUrl);if(!i.success||!i.response)throw this.createError(((e=i.error)==null?void 0:e.code)||c.NO_VAST_RESPONSE,((t=i.error)==null?void 0:t.message)||"Failed to parse VAST");if(this.ads=i.response.ads,this.ads.length===0)throw this.createError(c.NO_VAST_RESPONSE,"No ads in VAST response");const s=this.getFirstLinearCreative();if(!s)throw this.createError(c.GENERAL_LINEAR_ERROR,"No linear creative found");const a=this.parser.selectBestMediaFile(s.mediaFiles,this.config.targetBitrate);if(!a)throw this.createError(c.FILE_NOT_FOUND,"No suitable media file found");this.updateState({mediaFile:a});const n=this.parser.aggregateTrackingEvents(this.ads);this.tracker=new A(n,{debug:this.config.debug}),this.tracker.updateMacroContext({assetUri:a.url}),this.createVideoElement(a),this.setupFocusManagement(),await this.attemptAutoplay()}catch(i){const s=i instanceof Error?this.createError(c.UNDEFINED_ERROR,i.message):i;this.handleError(s)}}getFirstLinearCreative(){for(const e of this.ads)for(const t of e.creatives)if(t.linear)return t.linear;return null}createVideoElement(e){const t=document.createElement("video"),i=this.platform.getVideoAttributes();Object.entries(i).forEach(([s,a])=>{typeof a=="boolean"?a&&t.setAttribute(s,""):t.setAttribute(s,a)}),t.src=e.url,t.style.cssText=`
1
+ (function(l,f){typeof exports=="object"&&typeof module<"u"?f(exports,require("fast-xml-parser")):typeof define=="function"&&define.amd?define(["exports","fast-xml-parser"],f):(l=typeof globalThis<"u"?globalThis:l||self,f(l.AdgentSDK={},l.FastXMLParser))})(this,function(l,f){"use strict";var c=(r=>(r.Idle="idle",r.Loading="loading",r.Ready="ready",r.Playing="playing",r.Paused="paused",r.Completed="completed",r.Error="error",r.WaitingForInteraction="waiting_for_interaction",r))(c||{}),p=(r=>(r[r.XML_PARSING_ERROR=100]="XML_PARSING_ERROR",r[r.VAST_SCHEMA_VALIDATION_ERROR=101]="VAST_SCHEMA_VALIDATION_ERROR",r[r.VAST_VERSION_NOT_SUPPORTED=102]="VAST_VERSION_NOT_SUPPORTED",r[r.GENERAL_WRAPPER_ERROR=300]="GENERAL_WRAPPER_ERROR",r[r.WRAPPER_TIMEOUT=301]="WRAPPER_TIMEOUT",r[r.WRAPPER_LIMIT_REACHED=302]="WRAPPER_LIMIT_REACHED",r[r.NO_VAST_RESPONSE=303]="NO_VAST_RESPONSE",r[r.GENERAL_LINEAR_ERROR=400]="GENERAL_LINEAR_ERROR",r[r.FILE_NOT_FOUND=401]="FILE_NOT_FOUND",r[r.MEDIA_TIMEOUT=402]="MEDIA_TIMEOUT",r[r.MEDIA_NOT_SUPPORTED=403]="MEDIA_NOT_SUPPORTED",r[r.GENERAL_COMPANION_ERROR=600]="GENERAL_COMPANION_ERROR",r[r.UNDEFINED_ERROR=900]="UNDEFINED_ERROR",r))(p||{}),x=Object.defineProperty,I=(r,e,t)=>e in r?x(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,w=(r,e,t)=>I(r,typeof e!="symbol"?e+"":e,t);class k{constructor(e={}){w(this,"config"),w(this,"xmlParser");var t,i,s,a;this.config={maxWrapperDepth:(t=e.maxWrapperDepth)!=null?t:5,timeout:(i=e.timeout)!=null?i:1e4,debug:(s=e.debug)!=null?s:!1,fetchFn:(a=e.fetchFn)!=null?a:fetch.bind(globalThis)},this.xmlParser=new f.XMLParser({ignoreAttributes:!1,attributeNamePrefix:"@_",textNodeName:"#text",parseAttributeValue:!0,trimValues:!0})}async parse(e){try{return{success:!0,response:await this.fetchAndParse(e,0)}}catch(t){const i=t instanceof Error?t.message:"Unknown error";return{success:!1,error:{code:p.GENERAL_WRAPPER_ERROR,message:i}}}}async fetchAndParse(e,t){if(t>=this.config.maxWrapperDepth)throw new Error(`Wrapper limit exceeded (max: ${this.config.maxWrapperDepth})`);this.log(`Fetching VAST (depth: ${t}): ${e}`);const i=await this.fetchWithTimeout(e),s=this.parseXml(i),a=await Promise.all(s.ads.map(async n=>{var u;return(u=n.wrapper)!=null&&u.vastAdTagURI?this.resolveWrapper(n,t+1):n}));return{...s,ads:a.flat()}}async resolveWrapper(e,t){var i;if(!((i=e.wrapper)!=null&&i.vastAdTagURI))return[e];try{return(await this.fetchAndParse(e.wrapper.vastAdTagURI,t)).ads.map(a=>this.mergeWrapperTracking(e,a))}catch(s){if(this.log(`Wrapper resolution failed: ${s}`),e.wrapper.fallbackOnNoAd)return[];throw s}}mergeWrapperTracking(e,t){return{...t,impressions:[...e.impressions,...t.impressions],errors:[...e.errors,...t.errors],creatives:t.creatives.map(i=>({...i,linear:i.linear?{...i.linear,trackingEvents:[...this.getWrapperTrackingEvents(e),...i.linear.trackingEvents]}:void 0}))}}getWrapperTrackingEvents(e){var t;const i=[];for(const s of e.creatives)(t=s.linear)!=null&&t.trackingEvents&&i.push(...s.linear.trackingEvents);return i}async fetchWithTimeout(e){const t=new AbortController,i=setTimeout(()=>t.abort(),this.config.timeout);try{const s=await this.config.fetchFn(e,{signal:t.signal});if(!s.ok)throw new Error(`HTTP ${s.status}: ${s.statusText}`);return s.text()}finally{clearTimeout(i)}}parseXml(e){const i=this.xmlParser.parse(e).VAST;if(!i)throw new Error("Invalid VAST: missing VAST element");const s=i["@_version"]||"4.0",a=this.parseAds(i.Ad);return{version:s,ads:a,errors:this.parseErrors(i.Error)}}parseAds(e){return e?(Array.isArray(e)?e:[e]).map(i=>this.parseAd(i)):[]}parseAd(e){var t,i,s;const a=!!e.Wrapper,n=e.InLine||e.Wrapper;return{id:e["@_id"]||"",sequence:e["@_sequence"],adSystem:n!=null&&n.AdSystem?{name:typeof n.AdSystem=="string"?n.AdSystem:n.AdSystem["#text"]||"",version:(t=n.AdSystem)==null?void 0:t["@_version"]}:void 0,adTitle:n==null?void 0:n.AdTitle,impressions:this.parseImpressions(n==null?void 0:n.Impression),errors:this.parseErrors(n==null?void 0:n.Error),creatives:this.parseCreatives((i=n==null?void 0:n.Creatives)==null?void 0:i.Creative),wrapper:a?{vastAdTagURI:n.VASTAdTagURI,followAdditionalWrappers:n["@_followAdditionalWrappers"]!==!1,allowMultipleAds:n["@_allowMultipleAds"],fallbackOnNoAd:n["@_fallbackOnNoAd"]}:void 0,inLine:a?void 0:{adTitle:(n==null?void 0:n.AdTitle)||"",description:n==null?void 0:n.Description,advertiser:n==null?void 0:n.Advertiser,creatives:this.parseCreatives((s=n==null?void 0:n.Creatives)==null?void 0:s.Creative)}}}parseImpressions(e){return e?(Array.isArray(e)?e:[e]).map(i=>({id:i["@_id"],url:typeof i=="string"?i:i["#text"]||""})):[]}parseCreatives(e){return e?(Array.isArray(e)?e:[e]).map(i=>({id:i["@_id"],sequence:i["@_sequence"],adId:i["@_adId"],linear:i.Linear?this.parseLinear(i.Linear):void 0})):[]}parseLinear(e){var t,i;return{duration:this.parseDuration(e.Duration),skipOffset:e["@_skipoffset"]?this.parseDuration(e["@_skipoffset"]):void 0,mediaFiles:this.parseMediaFiles((t=e.MediaFiles)==null?void 0:t.MediaFile),trackingEvents:this.parseTrackingEvents((i=e.TrackingEvents)==null?void 0:i.Tracking),videoClicks:e.VideoClicks?{clickThrough:e.VideoClicks.ClickThrough?{id:e.VideoClicks.ClickThrough["@_id"],url:typeof e.VideoClicks.ClickThrough=="string"?e.VideoClicks.ClickThrough:e.VideoClicks.ClickThrough["#text"]||""}:void 0}:void 0,adParameters:e.AdParameters}}parseMediaFiles(e){return e?(Array.isArray(e)?e:[e]).map(i=>({id:i["@_id"],url:typeof i=="string"?i:i["#text"]||"",delivery:i["@_delivery"]||"progressive",type:i["@_type"]||"video/mp4",width:parseInt(i["@_width"],10)||0,height:parseInt(i["@_height"],10)||0,bitrate:i["@_bitrate"]?parseInt(i["@_bitrate"],10):void 0,codec:i["@_codec"],scalable:i["@_scalable"],maintainAspectRatio:i["@_maintainAspectRatio"]})):[]}parseTrackingEvents(e){return e?(Array.isArray(e)?e:[e]).map(i=>({event:i["@_event"],url:typeof i=="string"?i:i["#text"]||"",offset:i["@_offset"]?this.parseDuration(i["@_offset"]):void 0})):[]}parseErrors(e){return e?(Array.isArray(e)?e:[e]).map(i=>typeof i=="string"?i:i["#text"]||""):[]}parseDuration(e){if(typeof e=="number")return e;if(typeof e!="string")return 0;if(e.endsWith("%"))return parseFloat(e)/100;const t=e.match(/(\d+):(\d+):(\d+(?:\.\d+)?)/);if(t){const[,i,s,a]=t;return parseInt(i,10)*3600+parseInt(s,10)*60+parseFloat(a)}return parseFloat(e)||0}selectBestMediaFile(e,t=2500){if(e.length===0)return null;const i=e.filter(n=>n.type.includes("mp4")||n.type.includes("video/mp4"));return[...i.length>0?i:e].sort((n,u)=>{const y=n.bitrate||0,b=u.bitrate||0,W=n.height>1080?1e4:0,B=u.height>1080?1e4:0,V=Math.abs(y-t)+W,$=Math.abs(b-t)+B;return V-$})[0]||null}aggregateTrackingEvents(e){var t;const i=[];for(const s of e)for(const a of s.creatives)(t=a.linear)!=null&&t.trackingEvents&&i.push(...a.linear.trackingEvents);return i}aggregateImpressions(e){const t=[];for(const i of e)for(const s of i.impressions)t.push(s.url);return t}log(e){this.config.debug&&console.log(`[VASTParser] ${e}`)}}function m(r,e={}){let t=r;return t=t.replace(/\[TIMESTAMP\]/g,Date.now().toString()),t=t.replace(/\[CACHEBUSTING\]/g,Math.random().toString(36).substring(2,15)),e.assetUri&&(t=t.replace(/\[ASSETURI\]/g,encodeURIComponent(e.assetUri))),e.contentPlayhead!==void 0&&(t=t.replace(/\[CONTENTPLAYHEAD\]/g,R(e.contentPlayhead))),e.adPlayhead!==void 0&&(t=t.replace(/\[ADPLAYHEAD\]/g,R(e.adPlayhead))),e.errorCode!==void 0&&(t=t.replace(/\[ERRORCODE\]/g,e.errorCode.toString())),e.breakPosition!==void 0&&(t=t.replace(/\[BREAKPOSITION\]/g,e.breakPosition.toString())),e.adType&&(t=t.replace(/\[ADTYPE\]/g,e.adType)),t}function R(r){const e=Math.floor(r/3600),t=Math.floor(r%3600/60),i=Math.floor(r%60),s=Math.floor(r%1*1e3);return e.toString().padStart(2,"0")+":"+t.toString().padStart(2,"0")+":"+i.toString().padStart(2,"0")+"."+s.toString().padStart(3,"0")}var o=(r=>(r.WebOS="webos",r.Tizen="tizen",r.Vidaa="vidaa",r.WhaleOS="whaleos",r.FireTV="firetv",r.Roku="roku",r.Xbox="xbox",r.PlayStation="playstation",r.AndroidTV="androidtv",r.Vizio="vizio",r.Generic="generic",r))(o||{}),h=(r=>(r.Enter="enter",r.Back="back",r.Left="left",r.Right="right",r.Up="up",r.Down="down",r.Play="play",r.Pause="pause",r.PlayPause="playPause",r.Stop="stop",r.FastForward="fastForward",r.Rewind="rewind",r.Menu="menu",r.Info="info",r.Red="red",r.Green="green",r.Yellow="yellow",r.Blue="blue",r.ChannelUp="channelUp",r.ChannelDown="channelDown",r.VolumeUp="volumeUp",r.VolumeDown="volumeDown",r.Mute="mute",r))(h||{});const T={webos:{13:"enter",461:"back",37:"left",38:"up",39:"right",40:"down",415:"play",19:"pause",413:"stop",417:"fastForward",412:"rewind",457:"info",403:"red",404:"green",405:"yellow",406:"blue",33:"channelUp",34:"channelDown"},tizen:{13:"enter",10009:"back",37:"left",38:"up",39:"right",40:"down",415:"play",19:"pause",10252:"playPause",413:"stop",417:"fastForward",412:"rewind",457:"info",403:"red",404:"green",405:"yellow",406:"blue",427:"channelUp",428:"channelDown",447:"volumeUp",448:"volumeDown",449:"mute"},vidaa:{13:"enter",8:"back",27:"back",37:"left",38:"up",39:"right",40:"down",415:"play",19:"pause",413:"stop",417:"fastForward",412:"rewind"},whaleos:{13:"enter",27:"back",37:"left",38:"up",39:"right",40:"down",415:"play",19:"pause",413:"stop"},firetv:{13:"enter",4:"back",27:"back",37:"left",38:"up",39:"right",40:"down",85:"playPause",126:"play",127:"pause",89:"rewind",90:"fastForward",82:"menu"},roku:{13:"enter",27:"back",8:"back",37:"left",38:"up",39:"right",40:"down",179:"playPause",178:"stop",228:"fastForward",227:"rewind"},xbox:{13:"enter",27:"back",37:"left",38:"up",39:"right",40:"down",195:"menu",196:"menu"},playstation:{13:"enter",27:"back",37:"left",38:"up",39:"right",40:"down"},androidtv:{13:"enter",4:"back",27:"back",37:"left",38:"up",39:"right",40:"down",85:"playPause",126:"play",127:"pause",89:"rewind",90:"fastForward",82:"menu"},vizio:{13:"enter",27:"back",8:"back",37:"left",38:"up",39:"right",40:"down",415:"play",19:"pause"},generic:{13:"enter",27:"back",8:"back",37:"left",38:"up",39:"right",40:"down",32:"playPause",80:"play",83:"stop",77:"mute"}},S={tizen:[/Tizen/i,/SMART-TV.*Samsung/i],webos:[/Web0S/i,/WebOS/i,/LG.*NetCast/i,/LGE.*TV/i],vidaa:[/Vidaa/i,/VIDAA/i,/Hisense/i],whaleos:[/WhaleTV/i,/Whale/i],firetv:[/AFT/i,/AFTS/i,/AFTM/i,/Amazon.*Fire/i],roku:[/Roku/i],xbox:[/Xbox/i,/Edge.*Xbox/i],playstation:[/PlayStation/i,/PS4/i,/PS5/i],androidtv:[/Android.*TV/i,/Chromecast/i,/BRAVIA/i,/SHIELD/i],vizio:[/VIZIO/i,/SmartCast/i],generic:[]};var C=Object.defineProperty,M=(r,e,t)=>e in r?C(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,v=(r,e,t)=>M(r,typeof e!="symbol"?e+"":e,t);class P{constructor(){v(this,"platform"),v(this,"capabilities"),v(this,"deviceInfo"),v(this,"keyMap"),v(this,"reverseKeyMap"),this.platform=this.detectPlatform(),this.keyMap=T[this.platform],this.reverseKeyMap=this.buildReverseKeyMap(),this.capabilities=this.detectCapabilities(),this.deviceInfo=this.detectDeviceInfo()}detectPlatform(){if(typeof window>"u"||typeof navigator>"u")return o.Generic;const e=navigator.userAgent,t=window;if(t.tizen)return o.Tizen;if(t.webOS||t.PalmSystem)return o.WebOS;for(const[i,s]of Object.entries(S))if(i!==o.Generic){for(const a of s)if(a.test(e))return i}return o.Generic}detectCapabilities(){const e=typeof navigator<"u",t=typeof document<"u",i=typeof window<"u",s={sendBeacon:e&&"sendBeacon"in navigator,fetchKeepalive:typeof fetch<"u",mutedAutoplayRequired:!0,fullscreen:t&&("fullscreenEnabled"in document||"webkitFullscreenEnabled"in document),hardwareDecodeInfo:!1,hdr:!1,hdr10Plus:!1,dolbyVision:!1,dolbyAtmos:!1,hevc:this.isCodecSupported('video/mp4; codecs="hvc1"'),vp9:this.isCodecSupported('video/webm; codecs="vp9"'),av1:this.isCodecSupported('video/mp4; codecs="av01.0.05M.08"'),maxResolution:this.detectMaxResolution(),touch:i&&"ontouchstart"in window,voice:!1};switch(this.platform){case o.Tizen:return{...s,hardwareDecodeInfo:!0,hdr:!0,hevc:!0,voice:!0};case o.WebOS:return{...s,hardwareDecodeInfo:!0,hdr:!0,dolbyVision:!0,dolbyAtmos:!0,hevc:!0,voice:!0};case o.FireTV:return{...s,hdr:!0,hdr10Plus:!0,dolbyVision:!0,hevc:!0,voice:!0};case o.Roku:return{...s,hdr:!0,dolbyVision:!0,hevc:!0,voice:!0};case o.Xbox:return{...s,hdr:!0,dolbyVision:!0,dolbyAtmos:!0,hevc:!0,av1:!0,voice:!0};case o.PlayStation:return{...s,hdr:!0,hevc:!0};case o.AndroidTV:return{...s,hdr:!0,dolbyVision:!0,hevc:!0,vp9:!0,voice:!0};default:return s}}detectDeviceInfo(){var e,t,i;const s={platform:this.platform};typeof window<"u"&&(s.screenWidth=(e=window.screen)==null?void 0:e.width,s.screenHeight=(t=window.screen)==null?void 0:t.height,s.devicePixelRatio=window.devicePixelRatio);const a=window;if(this.platform===o.Tizen&&((i=a.tizen)!=null&&i.systeminfo))try{a.tizen.systeminfo.getPropertyValue("BUILD",n=>{s.model=n.model,s.manufacturer=n.manufacturer||"Samsung"})}catch{s.manufacturer="Samsung"}if(this.platform===o.WebOS&&a.webOSSystem)try{const n=a.webOSSystem.deviceInfo;s.model=n==null?void 0:n.modelName,s.manufacturer="LG",s.osVersion=n==null?void 0:n.version}catch{s.manufacturer="LG"}return s}detectMaxResolution(){var e,t;if(typeof window>"u")return"unknown";const i=((e=window.screen)==null?void 0:e.width)||0,s=((t=window.screen)==null?void 0:t.height)||0,a=Math.max(i,s);return a>=3840?"4k":a>=1920?"1080p":a>=1280?"720p":"unknown"}buildReverseKeyMap(){const e=new Map;for(const[t,i]of Object.entries(this.keyMap)){const s=parseInt(t,10),a=e.get(i)||[];a.push(s),e.set(i,a)}return e}normalizeKeyCode(e){var t;return(t=this.keyMap[e])!=null?t:null}getKeyCodesForAction(e){return this.reverseKeyMap.get(e)||[]}isCodecSupported(e){if(typeof document>"u")return!1;try{const i=document.createElement("video").canPlayType(e);return i==="probably"||i==="maybe"}catch{return!1}}registerTizenKeys(){if(this.platform!==o.Tizen)return;const e=window.tizen;e!=null&&e.tvinputdevice&&["MediaPlay","MediaPause","MediaStop","MediaFastForward","MediaRewind","MediaPlayPause","ColorF0Red","ColorF1Green","ColorF2Yellow","ColorF3Blue","Info"].forEach(i=>{try{e.tvinputdevice.registerKey(i)}catch{}})}registerWebOSKeys(){this.platform,o.WebOS}getVideoAttributes(){const e={muted:!0,playsinline:!0,autoplay:!0,"webkit-playsinline":!0};switch(this.platform){case o.Tizen:e["data-samsung-immersive"]="true";break;case o.WebOS:e["data-lg-immersive"]="true";break;case o.FireTV:case o.AndroidTV:e["x-webkit-airplay"]="allow";break}return e}getRecommendedVideoSettings(){switch(this.platform){case o.Tizen:case o.WebOS:return{maxBitrate:15e3,preferredCodec:"hevc",maxResolution:"4k"};case o.FireTV:return{maxBitrate:1e4,preferredCodec:"hevc",maxResolution:"4k"};case o.Roku:return{maxBitrate:8e3,preferredCodec:"h264",maxResolution:"4k"};case o.Xbox:case o.PlayStation:return{maxBitrate:2e4,preferredCodec:"hevc",maxResolution:"4k"};default:return{maxBitrate:5e3,preferredCodec:"h264",maxResolution:"1080p"}}}debug(e){if(console.log(`[Adgent] ${e}`),this.platform===o.WebOS&&typeof window<"u"){const t=window;t.webOS&&t.webOS.service&&t.webOS.service.request("luna://com.webos.notification",{method:"createToast",parameters:{message:`[Adgent] ${e}`},onSuccess:()=>{},onFailure:()=>{}})}}}let E=null;function _(){return E||(E=new P),E}var N=Object.defineProperty,D=(r,e,t)=>e in r?N(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,g=(r,e,t)=>D(r,typeof e!="symbol"?e+"":e,t);class A{constructor(e=[],t={}){g(this,"config"),g(this,"trackingEvents"),g(this,"firedEvents"),g(this,"macroContext");var i,s,a;this.config={debug:(i=t.debug)!=null?i:!1,retry:(s=t.retry)!=null?s:!1,maxRetries:(a=t.maxRetries)!=null?a:3},this.trackingEvents=this.groupEventsByType(e),this.firedEvents=new Set,this.macroContext={}}groupEventsByType(e){const t=new Map;for(const i of e){const s=t.get(i.event)||[];s.push(i),t.set(i.event,s)}return t}updateMacroContext(e){this.macroContext={...this.macroContext,...e}}track(e,t=!0){const i=this.trackingEvents.get(e);if(!i){this.log(`No tracking URLs for event: ${e}`);return}for(const s of i){const a=`${e}:${s.url}`;if(t&&this.firedEvents.has(a)){this.log(`Skipping duplicate event: ${e}`);continue}const n=m(s.url,this.macroContext);this.firePixel(n),t&&this.firedEvents.add(a)}}firePixel(e){const t=_();this.log(`Firing pixel: ${e}`);try{if(t.capabilities.sendBeacon&&navigator.sendBeacon(e))return;if(t.capabilities.fetchKeepalive){fetch(e,{method:"GET",keepalive:!0,mode:"no-cors",credentials:"omit"}).catch(()=>{});return}this.fireImageBeacon(e)}catch{this.log(`Failed to fire pixel: ${e}`)}}fireImageBeacon(e){const t=new Image(1,1);t.src=e}fireImpressions(e){for(const t of e){const i=m(t,this.macroContext);this.firePixel(i)}}fireError(e,t){const i={...this.macroContext,errorCode:t};for(const s of e){const a=m(s,i);this.firePixel(a)}}reset(){this.firedEvents.clear()}log(e){this.config.debug&&console.log(`[AdTracker] ${e}`)}}var F=Object.defineProperty,L=(r,e,t)=>e in r?F(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,d=(r,e,t)=>L(r,typeof e!="symbol"?e+"":e,t);const U={targetBitrate:2500,maxWrapperDepth:5,timeout:1e4,debug:!1,skipButtonText:"Skip Ad"};class O{constructor(e){d(this,"config"),d(this,"platform"),d(this,"parser"),d(this,"videoElement",null),d(this,"overlayElement",null),d(this,"skipButtonElement",null),d(this,"progressElement",null),d(this,"tracker",null),d(this,"state"),d(this,"ads",[]),d(this,"listeners",new Set),d(this,"quartilesFired",new Set),d(this,"boundKeyHandler",null),d(this,"focusTrap",null),this.config={...U,...e},this.platform=_(),this.parser=new k({maxWrapperDepth:this.config.maxWrapperDepth,timeout:this.config.timeout,debug:this.config.debug}),this.state={status:c.Idle,currentTime:0,duration:0,muted:!0,volume:1,canSkip:!1,skipCountdown:0,mediaFile:null,error:null},this.platform.platform==="tizen"&&this.platform.registerTizenKeys()}async init(){var e,t;if(!this.config.container)throw new Error("Container element not found");this.updateState({status:c.Loading});try{const i=await this.parser.parse(this.config.vastUrl);if(!i.success||!i.response)throw this.createError(((e=i.error)==null?void 0:e.code)||p.NO_VAST_RESPONSE,((t=i.error)==null?void 0:t.message)||"Failed to parse VAST");if(this.ads=i.response.ads,this.ads.length===0)throw this.createError(p.NO_VAST_RESPONSE,"No ads in VAST response");const s=this.getFirstLinearCreative();if(!s)throw this.createError(p.GENERAL_LINEAR_ERROR,"No linear creative found");const a=this.parser.selectBestMediaFile(s.mediaFiles,this.config.targetBitrate);if(!a)throw this.createError(p.FILE_NOT_FOUND,"No suitable media file found");this.updateState({mediaFile:a});const n=this.parser.aggregateTrackingEvents(this.ads);this.tracker=new A(n,{debug:this.config.debug}),this.tracker.updateMacroContext({assetUri:a.url}),this.createVideoElement(a),this.setupFocusManagement(),await this.attemptAutoplay()}catch(i){const s=i instanceof Error?this.createError(p.UNDEFINED_ERROR,i.message):i;this.handleError(s)}}getFirstLinearCreative(){for(const e of this.ads)for(const t of e.creatives)if(t.linear)return t.linear;return null}createVideoElement(e){const t=document.createElement("video"),i=this.platform.getVideoAttributes();Object.entries(i).forEach(([a,n])=>{typeof n=="boolean"?n&&t.setAttribute(a,""):t.setAttribute(a,n)}),t.removeAttribute("src"),t.innerHTML="";const s=document.createElement("source");s.src=e.url,s.type=e.type||"video/mp4",t.appendChild(s),t.setAttribute("crossorigin","anonymous"),t.style.cssText=`
2
2
  width: 100%;
3
3
  height: 100%;
4
4
  object-fit: contain;
5
5
  background: #000;
6
- `,t.addEventListener("loadedmetadata",()=>{this.updateState({duration:t.duration,status:d.Ready}),this.emit({type:"loaded"})}),t.addEventListener("timeupdate",()=>{this.handleTimeUpdate(t)}),t.addEventListener("ended",()=>{this.handleComplete()}),t.addEventListener("error",()=>{const s=t.error;this.handleError(this.createError(c.MEDIA_NOT_SUPPORTED,(s==null?void 0:s.message)||"Video playback error"))}),t.addEventListener("play",()=>{this.updateState({status:d.Playing})}),t.addEventListener("pause",()=>{var s;this.state.status!==d.Completed&&(this.updateState({status:d.Paused}),this.emit({type:"pause"}),(s=this.tracker)==null||s.track("pause"))}),this.config.container.appendChild(t),this.videoElement=t,this.log(`Video element created with src: ${e.url}`)}async attemptAutoplay(){if(this.videoElement)try{await this.videoElement.play(),this.handlePlaybackStart()}catch(e){this.log(`Autoplay failed: ${e}`),this.showStartOverlay()}}showStartOverlay(){if(this.updateState({status:d.WaitingForInteraction}),this.config.customStartOverlay){this.overlayElement=this.config.customStartOverlay,this.config.container.appendChild(this.overlayElement);return}const e=document.createElement("div");e.innerHTML=`
6
+ `,t.addEventListener("loadedmetadata",()=>{this.updateState({duration:t.duration,status:c.Ready}),this.emit({type:"loaded"})}),t.addEventListener("timeupdate",()=>{this.handleTimeUpdate(t)}),t.addEventListener("ended",()=>{this.handleComplete()}),t.addEventListener("error",()=>{const a=t.error;this.handleError(this.createError(p.MEDIA_NOT_SUPPORTED,(a==null?void 0:a.message)||"Video playback error"))}),t.addEventListener("play",()=>{this.updateState({status:c.Playing})}),t.addEventListener("pause",()=>{var a;this.state.status!==c.Completed&&(this.updateState({status:c.Paused}),this.emit({type:"pause"}),(a=this.tracker)==null||a.track("pause"))}),this.config.container.appendChild(t),this.videoElement=t,this.log(`Video element created with src: ${e.url}`)}async attemptAutoplay(){if(this.videoElement)try{await this.videoElement.play(),this.handlePlaybackStart()}catch(e){this.log(`Autoplay failed: ${e}`),this.showStartOverlay()}}showStartOverlay(){if(this.updateState({status:c.WaitingForInteraction}),this.config.customStartOverlay){this.overlayElement=this.config.customStartOverlay,this.config.container.appendChild(this.overlayElement);return}const e=document.createElement("div");e.innerHTML=`
7
7
  <div style="
8
8
  position: absolute;
9
9
  top: 0;
10
10
  left: 0;
11
11
  width: 100%;
12
12
  height: 100%;
13
- display: flex;
14
- align-items: center;
15
- justify-content: center;
16
- background: rgba(0, 0, 0, 0.7);
13
+ display: table;
14
+ background: rgba(0, 0, 0, 0.5);
17
15
  z-index: 100;
18
16
  ">
19
- <button id="adgent-start-btn" style="
20
- padding: 20px 40px;
21
- font-size: 24px;
22
- background: #fff;
23
- color: #000;
24
- border: none;
25
- border-radius: 8px;
26
- cursor: pointer;
27
- font-weight: bold;
28
- ">
29
- Start Ad
30
- </button>
17
+ <div style="display: table-cell; vertical-align: middle; text-align: center;">
18
+ <button id="adgent-start-btn" style="
19
+ width: 80px;
20
+ height: 80px;
21
+ background: rgba(0, 0, 0, 0.7);
22
+ border: 3px solid #fff;
23
+ border-radius: 50%;
24
+ cursor: pointer;
25
+ display: inline-block;
26
+ line-height: 80px;
27
+ text-align: center;
28
+ color: #fff;
29
+ font-size: 40px;
30
+ padding: 0 0 0 8px; /* Optical center for triangle */
31
+ ">
32
+
33
+ </button>
34
+ </div>
31
35
  </div>
32
- `,e.style.cssText="position: absolute; top: 0; left: 0; width: 100%; height: 100%;";const t=e.querySelector("#adgent-start-btn");t==null||t.addEventListener("click",()=>this.onStartClick()),this.config.container.style.position="relative",this.config.container.appendChild(e),this.overlayElement=e,t==null||t.focus()}async onStartClick(){if(this.removeOverlay(),this.videoElement)try{await this.videoElement.play(),this.handlePlaybackStart()}catch(e){this.handleError(this.createError(c.GENERAL_LINEAR_ERROR,`Playback failed: ${e}`))}}removeOverlay(){this.overlayElement&&(this.overlayElement.remove(),this.overlayElement=null)}handlePlaybackStart(){var e,t,i,s,a;this.updateState({status:d.Playing}),this.emit({type:"start"}),(t=(e=this.config).onStart)==null||t.call(e);const n=this.parser.aggregateImpressions(this.ads);(i=this.tracker)==null||i.fireImpressions(n),(s=this.tracker)==null||s.track("start"),(a=this.tracker)==null||a.track("creativeView"),this.setupSkipButton(),this.log("Playback started")}handleTimeUpdate(e){var t,i,s;const a=e.currentTime,n=e.duration;if(!n||isNaN(n))return;const p=a/n*100,_=this.calculateQuartile(p);this.updateState({currentTime:a,duration:n}),this.updateSkipCountdown(a),(t=this.tracker)==null||t.updateMacroContext({adPlayhead:a});const y={currentTime:a,duration:n,percentage:p,quartile:_};this.emit({type:"progress",data:y}),(s=(i=this.config).onProgress)==null||s.call(i,y),this.fireQuartileEvents(p)}calculateQuartile(e){return e>=100?4:e>=75?3:e>=50?2:e>=25?1:0}fireQuartileEvents(e){var t;const i=[{threshold:25,event:"firstQuartile"},{threshold:50,event:"midpoint"},{threshold:75,event:"thirdQuartile"}];for(const{threshold:s,event:a}of i)e>=s&&!this.quartilesFired.has(s)&&(this.quartilesFired.add(s),(t=this.tracker)==null||t.track(a),this.emit({type:"quartile",data:{quartile:a}}),this.log(`Quartile fired: ${a}`))}setupSkipButton(){var e;const t=this.getFirstLinearCreative(),i=(e=this.config.skipOffset)!=null?e:t==null?void 0:t.skipOffset;if(!i||i<=0)return;this.updateState({skipCountdown:i,canSkip:!1});const s=document.createElement("button");s.id="adgent-skip-btn",s.style.cssText=`
36
+ `,e.style.cssText="position: absolute; top: 0; left: 0; width: 100%; height: 100%;";const t=e.querySelector("#adgent-start-btn");t==null||t.addEventListener("click",()=>this.onStartClick()),this.config.container.style.position="relative",this.config.container.appendChild(e),this.overlayElement=e,t==null||t.focus()}async onStartClick(){if(this.removeOverlay(),this.videoElement)try{await this.videoElement.play(),this.handlePlaybackStart()}catch(e){this.handleError(this.createError(p.GENERAL_LINEAR_ERROR,`Playback failed: ${e}`))}}removeOverlay(){this.overlayElement&&(this.overlayElement.remove(),this.overlayElement=null)}handlePlaybackStart(){var e,t,i,s,a;this.updateState({status:c.Playing}),this.emit({type:"start"}),(t=(e=this.config).onStart)==null||t.call(e);const n=this.parser.aggregateImpressions(this.ads);(i=this.tracker)==null||i.fireImpressions(n),(s=this.tracker)==null||s.track("start"),(a=this.tracker)==null||a.track("creativeView"),this.setupSkipButton(),this.setupProgressUI(),this.log("Playback started")}handleTimeUpdate(e){var t,i,s;const a=e.currentTime,n=e.duration;if(!n||isNaN(n))return;const u=a/n*100,y=this.calculateQuartile(u);this.updateState({currentTime:a,duration:n}),this.updateSkipCountdown(a),(t=this.tracker)==null||t.updateMacroContext({adPlayhead:a}),this.updateProgressUI(a,n);const b={currentTime:a,duration:n,percentage:u,quartile:y};this.emit({type:"progress",data:b}),(s=(i=this.config).onProgress)==null||s.call(i,b),this.fireQuartileEvents(u)}calculateQuartile(e){return e>=100?4:e>=75?3:e>=50?2:e>=25?1:0}fireQuartileEvents(e){var t;const i=[{threshold:25,event:"firstQuartile"},{threshold:50,event:"midpoint"},{threshold:75,event:"thirdQuartile"}];for(const{threshold:s,event:a}of i)e>=s&&!this.quartilesFired.has(s)&&(this.quartilesFired.add(s),(t=this.tracker)==null||t.track(a),this.emit({type:"quartile",data:{quartile:a}}),this.log(`Quartile fired: ${a}`))}setupSkipButton(){var e;const t=this.getFirstLinearCreative(),i=(e=this.config.skipOffset)!=null?e:t==null?void 0:t.skipOffset;if(!i||i<=0)return;this.updateState({skipCountdown:i,canSkip:!1});const s=document.createElement("button");s.id="adgent-skip-btn",s.style.cssText=`
33
37
  position: absolute;
34
38
  bottom: 20px;
35
39
  right: 20px;
@@ -42,4 +46,20 @@
42
46
  cursor: pointer;
43
47
  z-index: 101;
44
48
  transition: opacity 0.3s;
45
- `,s.textContent=`Skip in ${i}s`,s.addEventListener("click",()=>this.skip()),this.config.container.appendChild(s),this.skipButtonElement=s}updateSkipCountdown(e){var t;const i=this.getFirstLinearCreative(),s=(t=this.config.skipOffset)!=null?t:i==null?void 0:i.skipOffset;if(!s||!this.skipButtonElement)return;const a=Math.max(0,s-e);this.updateState({skipCountdown:a}),a<=0&&!this.state.canSkip?(this.updateState({canSkip:!0}),this.skipButtonElement.textContent=this.config.skipButtonText,this.skipButtonElement.style.opacity="1"):a>0&&(this.skipButtonElement.textContent=`Skip in ${Math.ceil(a)}s`,this.skipButtonElement.style.opacity="0.6")}skip(){var e,t,i;if(!this.state.canSkip){this.log("Skip not available yet");return}(e=this.tracker)==null||e.track("skip"),this.emit({type:"skip"}),(i=(t=this.config).onSkip)==null||i.call(t),this.destroy(),this.log("Ad skipped")}handleComplete(){var e,t,i;this.updateState({status:d.Completed}),(e=this.tracker)==null||e.track("complete"),this.emit({type:"complete"}),(i=(t=this.config).onComplete)==null||i.call(t),this.log("Ad completed")}handleError(e){var t,i,s;this.updateState({status:d.Error,error:e});const a=[];for(const n of this.ads)a.push(...n.errors);(t=this.tracker)==null||t.fireError(a,e.code),this.emit({type:"error",data:e}),(s=(i=this.config).onError)==null||s.call(i,e),this.log(`Error: ${e.message}`)}setupFocusManagement(){this.focusTrap=document.createElement("div"),this.focusTrap.tabIndex=0,this.focusTrap.style.cssText="position: absolute; opacity: 0; width: 0; height: 0;",this.config.container.appendChild(this.focusTrap),this.focusTrap.focus(),this.boundKeyHandler=e=>{const t=this.platform.normalizeKeyCode(e.keyCode);t&&(e.preventDefault(),e.stopPropagation(),this.handleKeyAction(t))},document.addEventListener("keydown",this.boundKeyHandler,!0)}handleKeyAction(e){var t,i;switch(this.log(`Key action: ${e}`),e){case h.Enter:this.state.status===d.WaitingForInteraction?this.onStartClick():this.state.canSkip&&this.skip();break;case h.Back:this.log("Back pressed - ignoring during ad");break;case h.Play:(t=this.videoElement)==null||t.play();break;case h.Pause:(i=this.videoElement)==null||i.pause();break;case h.Left:case h.Right:case h.Up:case h.Down:break}}unmute(){var e;this.videoElement&&(this.videoElement.muted=!1,this.updateState({muted:!1}),(e=this.tracker)==null||e.track("unmute"),this.emit({type:"unmute"}))}mute(){var e;this.videoElement&&(this.videoElement.muted=!0,this.updateState({muted:!0}),(e=this.tracker)==null||e.track("mute"),this.emit({type:"mute"}))}on(e){return this.listeners.add(e),()=>this.listeners.delete(e)}getState(){return{...this.state}}destroy(){var e,t,i,s,a;this.boundKeyHandler&&(document.removeEventListener("keydown",this.boundKeyHandler,!0),this.boundKeyHandler=null),(e=this.videoElement)==null||e.remove(),(t=this.overlayElement)==null||t.remove(),(i=this.skipButtonElement)==null||i.remove(),(s=this.focusTrap)==null||s.remove(),this.videoElement=null,this.overlayElement=null,this.skipButtonElement=null,this.focusTrap=null,(a=this.tracker)==null||a.reset(),this.quartilesFired.clear(),this.listeners.clear(),this.ads=[],this.emit({type:"destroy"}),this.log("Player destroyed")}updateState(e){this.state={...this.state,...e}}emit(e){for(const t of this.listeners)try{t(e)}catch(i){this.log(`Listener error: ${i}`)}}createError(e,t,i=!1){return{code:e,message:t,recoverable:i}}log(e){this.config.debug&&console.log(`[AdPlayer] ${e}`)}}l.AdPlayer=O,l.AdTracker=A,l.AdgentSDK=O,l.DEFAULT_KEY_CODES=T,l.KeyAction=h,l.PLATFORM_DETECTION_PATTERNS=S,l.Platform=o,l.PlatformAdapter=P,l.PlaybackStatus=d,l.VASTErrorCode=c,l.VASTParser=w,l.getPlatformAdapter=b,l.replaceMacros=m,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"})});
49
+ `,s.textContent=`Skip in ${i}s`,s.addEventListener("click",()=>this.skip()),this.config.container.appendChild(s),this.skipButtonElement=s}updateSkipCountdown(e){var t;const i=this.getFirstLinearCreative(),s=(t=this.config.skipOffset)!=null?t:i==null?void 0:i.skipOffset;if(!s||!this.skipButtonElement)return;const a=Math.max(0,s-e);this.updateState({skipCountdown:a}),a<=0&&!this.state.canSkip?(this.updateState({canSkip:!0}),this.skipButtonElement.textContent=this.config.skipButtonText,this.skipButtonElement.style.opacity="1",this.skipButtonElement.focus()):a>0&&(this.skipButtonElement.textContent=`Skip in ${Math.ceil(a)}s`,this.skipButtonElement.style.opacity="0.6")}skip(){var e,t,i;if(!this.state.canSkip){this.log("Skip not available yet");return}(e=this.tracker)==null||e.track("skip"),this.emit({type:"skip"}),(i=(t=this.config).onSkip)==null||i.call(t),this.destroy(),this.log("Ad skipped")}handleComplete(){var e,t,i;this.updateState({status:c.Completed}),(e=this.tracker)==null||e.track("complete"),this.emit({type:"complete"}),(i=(t=this.config).onComplete)==null||i.call(t),this.log("Ad completed")}handleError(e){var t,i,s;this.updateState({status:c.Error,error:e});const a=[];for(const n of this.ads)a.push(...n.errors);(t=this.tracker)==null||t.fireError(a,e.code),this.emit({type:"error",data:e}),(s=(i=this.config).onError)==null||s.call(i,e),this.log(`Error: ${e.message}`)}setupFocusManagement(){this.focusTrap=document.createElement("div"),this.focusTrap.tabIndex=0,this.focusTrap.style.cssText="position: absolute; opacity: 0; width: 0; height: 0;",this.config.container.appendChild(this.focusTrap),this.focusTrap.focus(),this.boundKeyHandler=e=>{const t=this.platform.normalizeKeyCode(e.keyCode);t&&(e.preventDefault(),e.stopPropagation(),this.handleKeyAction(t))},document.addEventListener("keydown",this.boundKeyHandler,!0)}setupProgressUI(){const e=document.createElement("div");e.style.cssText=`
50
+ position: absolute;
51
+ top: 20px;
52
+ left: 20px;
53
+ background: rgba(0, 0, 0, 0.7);
54
+ color: #fff;
55
+ padding: 6px 12px;
56
+ border-radius: 4px;
57
+ font-size: 14px;
58
+ font-family: sans-serif;
59
+ z-index: 101;
60
+ display: block;
61
+ white-space: nowrap;
62
+ `,e.innerHTML=`
63
+ <span style="display: inline-block; vertical-align: middle; margin-right: 8px; background: #f4b400; color: #000; padding: 2px 4px; border-radius: 2px; font-weight: bold; font-size: 12px;">Ad</span>
64
+ <span id="adgent-progress-text" style="display: inline-block; vertical-align: middle;">1 of ${this.ads.length} • 0:00</span>
65
+ `,this.config.container.appendChild(e),this.progressElement=e}updateProgressUI(e,t){if(!this.progressElement)return;const i=Math.ceil(t-e),s=Math.floor(i/60),a=i%60,n=`${s}:${a.toString().padStart(2,"0")}`,u=this.progressElement.querySelector("#adgent-progress-text");u&&(u.textContent=`1 of ${this.ads.length} • ${n}`)}handleKeyAction(e){var t,i;switch(this.log(`Key action: ${e}`),e){case h.Enter:this.state.status===c.WaitingForInteraction?this.onStartClick():this.state.canSkip&&this.skip();break;case h.Back:this.log("Back pressed - ignoring during ad");break;case h.Play:(t=this.videoElement)==null||t.play();break;case h.Pause:(i=this.videoElement)==null||i.pause();break;case h.Left:case h.Right:case h.Up:case h.Down:break}}unmute(){var e;this.videoElement&&(this.videoElement.muted=!1,this.updateState({muted:!1}),(e=this.tracker)==null||e.track("unmute"),this.emit({type:"unmute"}))}mute(){var e;this.videoElement&&(this.videoElement.muted=!0,this.updateState({muted:!0}),(e=this.tracker)==null||e.track("mute"),this.emit({type:"mute"}))}on(e){return this.listeners.add(e),()=>this.listeners.delete(e)}getState(){return{...this.state}}destroy(){var e,t,i,s,a,n;this.boundKeyHandler&&(document.removeEventListener("keydown",this.boundKeyHandler,!0),this.boundKeyHandler=null),(e=this.videoElement)==null||e.remove(),(t=this.overlayElement)==null||t.remove(),(i=this.skipButtonElement)==null||i.remove(),(s=this.progressElement)==null||s.remove(),(a=this.focusTrap)==null||a.remove(),this.videoElement=null,this.overlayElement=null,this.skipButtonElement=null,this.progressElement=null,this.focusTrap=null,(n=this.tracker)==null||n.reset(),this.quartilesFired.clear(),this.listeners.clear(),this.ads=[],this.emit({type:"destroy"}),this.log("Player destroyed")}updateState(e){this.state={...this.state,...e}}emit(e){for(const t of this.listeners)try{t(e)}catch(i){this.log(`Listener error: ${i}`)}}createError(e,t,i=!1){return{code:e,message:t,recoverable:i}}log(e){this.config.debug&&this.platform.debug(e)}}l.AdPlayer=O,l.AdTracker=A,l.AdgentSDK=O,l.DEFAULT_KEY_CODES=T,l.KeyAction=h,l.PLATFORM_DETECTION_PATTERNS=S,l.Platform=o,l.PlatformAdapter=P,l.PlaybackStatus=c,l.VASTErrorCode=p,l.VASTParser=k,l.getPlatformAdapter=_,l.replaceMacros=m,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"})});
package/dist/index.d.ts CHANGED
@@ -36,6 +36,7 @@ declare class AdPlayer {
36
36
  private videoElement;
37
37
  private overlayElement;
38
38
  private skipButtonElement;
39
+ private progressElement;
39
40
  private tracker;
40
41
  private state;
41
42
  private ads;
@@ -114,6 +115,14 @@ declare class AdPlayer {
114
115
  * Set up focus management to capture remote keys
115
116
  */
116
117
  private setupFocusManagement;
118
+ /**
119
+ * Set up progress UI in top-left
120
+ */
121
+ private setupProgressUI;
122
+ /**
123
+ * Update progress UI text
124
+ */
125
+ private updateProgressUI;
117
126
  /**
118
127
  * Handle key actions from remote control
119
128
  */
@@ -630,6 +639,11 @@ export declare class PlatformAdapter implements IPlatformAdapter {
630
639
  preferredCodec: string;
631
640
  maxResolution: string;
632
641
  };
642
+ /**
643
+ * Show debug message using platform-specific native notifications
644
+ * Falls back to console.log
645
+ */
646
+ debug(message: string): void;
633
647
  }
634
648
 
635
649
  /** Platform capability flags */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adgent-sdk",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Lightweight, framework-agnostic VAST Player SDK for Smart TV platforms",
5
5
  "type": "module",
6
6
  "main": "./dist/adgent-sdk.umd.js",