@oddin-gg/havik-player 2.16.4 → 2.16.6

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.
package/dist/index.js CHANGED
@@ -174,7 +174,7 @@ function ue(e, t) {
174
174
  t?.addEventListener("abort", a, { once: !0 });
175
175
  });
176
176
  }
177
- async function de(e, t, r) {
177
+ async function v(e, t, r) {
178
178
  let i = ae(t), a = Date.now(), s = i.timeoutMs == null ? Infinity : a + i.timeoutMs, c = 0, l;
179
179
  for (;;) {
180
180
  if (r?.aborted) throw new n("ABORTED", 0, "wait-for-live aborted");
@@ -200,21 +200,21 @@ async function de(e, t, r) {
200
200
  }
201
201
  //#endregion
202
202
  //#region src/core/resolve.ts
203
- async function v(e) {
203
+ async function y(e) {
204
204
  if (!e.matchUrn || typeof e.matchUrn != "string") throw new n("INVALID_URN", 0, "resolveStream: a non-empty matchUrn is required");
205
205
  let t = await p(d(e.baseUrl, `/v1/playback/${encodeURIComponent(e.matchUrn)}`), {
206
206
  credential: e.credential,
207
207
  signal: e.signal,
208
208
  apiHeaders: e.apiHeaders
209
209
  });
210
- if (!t.ok) throw await fe(t);
211
- return he(await t.json(), e.matchUrn);
210
+ if (!t.ok) throw await de(t);
211
+ return me(await t.json(), e.matchUrn);
212
212
  }
213
- function y(e) {
214
- let t = () => v(e);
215
- return e.waitForLive ? de(t, e.waitForLive, e.signal) : t();
213
+ function b(e) {
214
+ let t = () => y(e);
215
+ return e.waitForLive ? v(t, e.waitForLive, e.signal) : t();
216
216
  }
217
- async function fe(e) {
217
+ async function de(e) {
218
218
  let t = f(e.headers.get("retry-after")), i = e.headers.get("x-request-id") ?? e.headers.get("x-amzn-requestid") ?? void 0, a = e.statusText || `HTTP ${e.status}`, o, s;
219
219
  try {
220
220
  let t = await e.json();
@@ -230,7 +230,7 @@ async function fe(e) {
230
230
  liveStartsAtMs: s
231
231
  });
232
232
  }
233
- var pe = /* @__PURE__ */ new Set([
233
+ var fe = /* @__PURE__ */ new Set([
234
234
  "matchUrn",
235
235
  "protocol",
236
236
  "drmEnabled",
@@ -241,7 +241,7 @@ var pe = /* @__PURE__ */ new Set([
241
241
  "expiresAt",
242
242
  "analytics"
243
243
  ]);
244
- function b(e, t) {
244
+ function x(e, t) {
245
245
  let r;
246
246
  try {
247
247
  r = new URL(t);
@@ -251,7 +251,7 @@ function b(e, t) {
251
251
  if (r.protocol !== "https:" && r.protocol !== "http:") throw new n("INTERNAL", 0, `playback ${e} has a disallowed scheme: ${r.protocol}`);
252
252
  return t;
253
253
  }
254
- function me(e) {
254
+ function pe(e) {
255
255
  if (e !== void 0) {
256
256
  if (typeof e == "string" && !e.endsWith("/")) try {
257
257
  let t = new URL(e);
@@ -260,41 +260,41 @@ function me(e) {
260
260
  g(`server analytics.endpoint ${JSON.stringify(e)} ignored: not a bare https origin.`);
261
261
  }
262
262
  }
263
- function he(e, t) {
263
+ function me(e, t) {
264
264
  if (!e.manifestUrl) throw new n("INTERNAL", 0, "playback response is missing manifestUrl");
265
265
  let r = e.drmEnabled ?? !!e.drm, i = {
266
266
  matchUrn: e.matchUrn ?? t,
267
267
  protocol: "hls",
268
268
  drmEnabled: r,
269
- manifestUrl: b("manifestUrl", e.manifestUrl),
269
+ manifestUrl: x("manifestUrl", e.manifestUrl),
270
270
  serverTime: e.serverTime ?? ""
271
271
  };
272
272
  if (e.liveStartsAt && (i.liveStartsAt = e.liveStartsAt), typeof e.analytics?.sid == "string" && e.analytics.sid) {
273
273
  i.analytics = { sid: e.analytics.sid };
274
- let t = me(e.analytics.endpoint);
274
+ let t = pe(e.analytics.endpoint);
275
275
  t && (i.analytics.endpoint = t);
276
276
  }
277
277
  if (r && e.drm) {
278
278
  let t = {};
279
- e.drm.widevine?.licenseUrl && (t.widevine = { licenseUrl: b("widevine licenseUrl", e.drm.widevine.licenseUrl) }), e.drm.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && (t.fairplay = {
280
- licenseUrl: b("fairplay licenseUrl", e.drm.fairplay.licenseUrl),
281
- certificateUrl: b("fairplay certificateUrl", e.drm.fairplay.certificateUrl)
279
+ e.drm.widevine?.licenseUrl && (t.widevine = { licenseUrl: x("widevine licenseUrl", e.drm.widevine.licenseUrl) }), e.drm.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && (t.fairplay = {
280
+ licenseUrl: x("fairplay licenseUrl", e.drm.fairplay.licenseUrl),
281
+ certificateUrl: x("fairplay certificateUrl", e.drm.fairplay.certificateUrl)
282
282
  }), (t.widevine || t.fairplay) && (i.drm = t);
283
283
  }
284
284
  let a = {};
285
- for (let [t, n] of Object.entries(e)) pe.has(t) || (a[t] = n);
285
+ for (let [t, n] of Object.entries(e)) fe.has(t) || (a[t] = n);
286
286
  return Object.keys(a).length > 0 && (i.extensions = a), i;
287
287
  }
288
288
  //#endregion
289
289
  //#region src/core/fullscreen.ts
290
- function ge(e) {
290
+ function he(e) {
291
291
  return e.ownerDocument ?? document;
292
292
  }
293
- function x(e) {
293
+ function ge(e) {
294
294
  return e.fullscreenElement ?? e.webkitFullscreenElement ?? null;
295
295
  }
296
296
  function S(e, t) {
297
- let n = x(ge(e));
297
+ let n = ge(he(e));
298
298
  return n != null && (n === e || t != null && n === t) || e.webkitDisplayingFullscreen === !0;
299
299
  }
300
300
  async function C(e, t) {
@@ -310,7 +310,7 @@ async function w(e, t) {
310
310
  n.webkitExitFullscreen?.();
311
311
  return;
312
312
  }
313
- let r = ge(e), i = x(r);
313
+ let r = he(e), i = ge(r);
314
314
  i != null && (i === e || t != null && i === t) && (typeof r.exitFullscreen == "function" ? await r.exitFullscreen() : r.webkitExitFullscreen?.());
315
315
  }
316
316
  //#endregion
@@ -671,14 +671,14 @@ function I(e) {
671
671
  function L(e) {
672
672
  return (e ?? "").trim().toLowerCase();
673
673
  }
674
- var je = {
674
+ var R = {
675
675
  hevc: "hvc1.1.6.L93.90",
676
676
  dv: "dvh1.05.06",
677
677
  av1: "av01.0.05M.08",
678
678
  vp9: "vp09.00.10.08"
679
- }, Me = /* @__PURE__ */ new Map(), R = /* @__PURE__ */ new Map();
680
- function Ne(e) {
681
- let t = L(e), n = Me.get(t);
679
+ }, z = /* @__PURE__ */ new Map(), B = /* @__PURE__ */ new Map();
680
+ function je(e) {
681
+ let t = L(e), n = z.get(t);
682
682
  if (n) return n;
683
683
  let r = {
684
684
  initDataTypes: ["cenc"],
@@ -696,23 +696,23 @@ function Ne(e) {
696
696
  } catch {
697
697
  return !1;
698
698
  }
699
- })().then((e) => (R.set(t, e), e));
700
- return Me.set(t, i), i;
699
+ })().then((e) => (B.set(t, e), e));
700
+ return z.set(t, i), i;
701
701
  }
702
- function Pe() {
703
- if (j()) for (let e of Object.values(je)) Ne(e);
702
+ function Me() {
703
+ if (j()) for (let e of Object.values(R)) je(e);
704
704
  }
705
- function Fe(e) {
705
+ function Ne(e) {
706
706
  let t = I(e);
707
- if (t) return t === "avc" ? !0 : R.get(L(e)) ?? R.get(L(je[t]));
707
+ if (t) return t === "avc" ? !0 : B.get(L(e)) ?? B.get(L(R[t]));
708
708
  }
709
709
  //#endregion
710
710
  //#region src/core/drm/support.ts
711
- var Ie = 5e3, Le = "video/mp4; codecs=\"avc1.42E01E\"", Re = "audio/mp4; codecs=\"mp4a.40.2\"", ze = {
711
+ var Pe = 5e3, Fe = "video/mp4; codecs=\"avc1.42E01E\"", Ie = "audio/mp4; codecs=\"mp4a.40.2\"", Le = {
712
712
  widevine: ["com.widevine.alpha"],
713
713
  fairplay: ["com.apple.fps"]
714
714
  };
715
- function Be(e) {
715
+ function Re(e) {
716
716
  return e === "fairplay" ? [{
717
717
  initDataTypes: [
718
718
  "sinf",
@@ -720,30 +720,30 @@ function Be(e) {
720
720
  "cenc"
721
721
  ],
722
722
  videoCapabilities: [{
723
- contentType: Le,
723
+ contentType: Fe,
724
724
  robustness: "",
725
725
  encryptionScheme: "cbcs"
726
726
  }],
727
727
  audioCapabilities: [{
728
- contentType: Re,
728
+ contentType: Ie,
729
729
  robustness: "",
730
730
  encryptionScheme: "cbcs"
731
731
  }]
732
732
  }] : N("com.widevine.alpha", [{
733
733
  initDataTypes: ["cenc"],
734
734
  videoCapabilities: [{
735
- contentType: Le,
735
+ contentType: Fe,
736
736
  robustness: F.video,
737
737
  encryptionScheme: F.scheme
738
738
  }],
739
739
  audioCapabilities: [{
740
- contentType: Re,
740
+ contentType: Ie,
741
741
  robustness: F.audio,
742
742
  encryptionScheme: F.scheme
743
743
  }]
744
744
  }]);
745
745
  }
746
- function Ve(e, t) {
746
+ function ze(e, t) {
747
747
  return new Promise((n, r) => {
748
748
  let i = setTimeout(() => r(/* @__PURE__ */ Error("probe-timeout")), t);
749
749
  e.then((e) => {
@@ -753,8 +753,8 @@ function Ve(e, t) {
753
753
  });
754
754
  });
755
755
  }
756
- async function He(e = {}) {
757
- let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Ie, r = {};
756
+ async function Be(e = {}) {
757
+ let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Pe, r = {};
758
758
  if (typeof window < "u" && window.isSecureContext === !1) return {
759
759
  verdict: "insecure-context",
760
760
  detail: r
@@ -766,7 +766,7 @@ async function He(e = {}) {
766
766
  };
767
767
  let a = !1, o = !1, s = Date.now() + n, c = () => Math.max(1, s - Date.now());
768
768
  for (let e of t) {
769
- let t = ze[e];
769
+ let t = Le[e];
770
770
  if (!t) {
771
771
  r[e] = "unknown system";
772
772
  continue;
@@ -777,7 +777,7 @@ async function He(e = {}) {
777
777
  break;
778
778
  }
779
779
  try {
780
- return await Ve((await Ve(i(n, Be(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
780
+ return await ze((await ze(i(n, Re(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
781
781
  verdict: "supported",
782
782
  system: e,
783
783
  detail: r
@@ -801,25 +801,25 @@ async function He(e = {}) {
801
801
  }
802
802
  //#endregion
803
803
  //#region src/core/manifest.ts
804
- var Ue = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
805
- function We(e) {
806
- return Ue.test(e);
804
+ var Ve = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
805
+ function He(e) {
806
+ return Ve.test(e);
807
807
  }
808
808
  //#endregion
809
809
  //#region src/core/env.ts
810
- var Ge = {
810
+ var Ue = {
811
811
  integration: "https://feed-dev.oddin-video.gg",
812
812
  production: "https://feed.oddin-video.gg"
813
813
  };
814
- function Ke(e) {
815
- let t = Object.prototype.hasOwnProperty.call(Ge, e) ? Ge[e] : void 0;
814
+ function We(e) {
815
+ let t = Object.prototype.hasOwnProperty.call(Ue, e) ? Ue[e] : void 0;
816
816
  if (!t) throw new n("INTERNAL", 0, `unknown env ${JSON.stringify(e)} — expected 'integration' or 'production'`);
817
817
  return t;
818
818
  }
819
819
  //#endregion
820
820
  //#region src/core/stats.ts
821
- var z = { droppedFrames: 0 };
822
- function B(e) {
821
+ var Ge = { droppedFrames: 0 };
822
+ function Ke(e) {
823
823
  try {
824
824
  return new URL(e).host;
825
825
  } catch {
@@ -831,7 +831,7 @@ function Je(e) {
831
831
  if (typeof performance > "u" || typeof performance.getEntriesByType != "function") return "";
832
832
  let t = "", n = -1, r = performance.getEntriesByType("resource");
833
833
  for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || qe.test(i.name)) && i.startTime >= n) {
834
- let e = B(i.name);
834
+ let e = Ke(i.name);
835
835
  e && (t = e, n = i.startTime);
836
836
  }
837
837
  return t;
@@ -843,7 +843,7 @@ function V(e) {
843
843
  totalFrames: t?.totalVideoFrames ?? 0
844
844
  };
845
845
  }
846
- var H = class {
846
+ var Ye = class {
847
847
  video;
848
848
  baseFrames = 0;
849
849
  baseDropped = 0;
@@ -866,7 +866,7 @@ var H = class {
866
866
  };
867
867
  }
868
868
  };
869
- function Ye(e, t) {
869
+ function Xe(e, t) {
870
870
  let n = [
871
871
  ["playing", () => t("playing")],
872
872
  ["waiting", () => t("buffering")],
@@ -883,8 +883,8 @@ function Ye(e, t) {
883
883
  }
884
884
  //#endregion
885
885
  //#region src/core/engine/native.ts
886
- var Xe = 2e3, Ze = 3, U = 500, Qe = 6e3, $e = .25;
887
- function et(e) {
886
+ var Ze = 2e3, Qe = 3, H = 500, $e = 6e3, et = .25;
887
+ function tt(e) {
888
888
  try {
889
889
  let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
890
890
  return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
@@ -892,20 +892,20 @@ function et(e) {
892
892
  return;
893
893
  }
894
894
  }
895
- function W(e) {
895
+ function U(e) {
896
896
  return !!(e ?? (typeof document < "u" ? document.createElement("video") : void 0))?.canPlayType("application/vnd.apple.mpegurl");
897
897
  }
898
- function G() {
898
+ function W() {
899
899
  if (typeof window > "u") return !1;
900
900
  let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
901
901
  return e || t;
902
902
  }
903
- function tt() {
904
- if (typeof navigator > "u" || !G()) return !1;
903
+ function nt() {
904
+ if (typeof navigator > "u" || !W()) return !1;
905
905
  let e = navigator.userAgent ?? "";
906
906
  return /iPhone|iPad|iPod/.test(e) ? !0 : /Macintosh/.test(e) && typeof navigator.maxTouchPoints == "number" && navigator.maxTouchPoints > 1;
907
907
  }
908
- var K = class {
908
+ var G = class {
909
909
  name = "native";
910
910
  deps;
911
911
  onLoaded;
@@ -927,7 +927,7 @@ var K = class {
927
927
  frameCounter;
928
928
  detachFrames = null;
929
929
  constructor(e) {
930
- this.deps = e, this.frameCounter = new H(e.video), this.loadStarted = e.deferLoad !== !0, this.builtAt = typeof performance < "u" ? performance.now() : 0;
930
+ this.deps = e, this.frameCounter = new Ye(e.video), this.loadStarted = e.deferLoad !== !0, this.builtAt = typeof performance < "u" ? performance.now() : 0;
931
931
  }
932
932
  async load() {
933
933
  this.detachFrames ??= this.frameCounter.attach();
@@ -948,7 +948,7 @@ var K = class {
948
948
  type: "error",
949
949
  error: new n("INTERNAL", 0, "native HLS playback error"),
950
950
  fatal: !0
951
- }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = nt(t.manifestUrl, t.analytics?.sid), e.load();
951
+ }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = rt(t.manifestUrl, t.analytics?.sid), e.load();
952
952
  }
953
953
  startLoad() {
954
954
  this.loadStarted || (this.loadStarted = !0, this.restorePreload());
@@ -970,7 +970,7 @@ var K = class {
970
970
  });
971
971
  this.onEncrypted = (n) => {
972
972
  let i = n;
973
- i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = et(i.initData), (async () => {
973
+ i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = tt(i.initData), (async () => {
974
974
  try {
975
975
  let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
976
976
  initDataTypes: [i.initDataType],
@@ -1092,7 +1092,7 @@ var K = class {
1092
1092
  return;
1093
1093
  }
1094
1094
  let t = this.hiddenSince;
1095
- this.hiddenSince = null, t != null && e - t >= Xe && this.armRefocus();
1095
+ this.hiddenSince = null, t != null && e - t >= Ze && this.armRefocus();
1096
1096
  }, this.onPageShow = (e) => {
1097
1097
  e.persisted && this.armRefocus();
1098
1098
  }, document.addEventListener("visibilitychange", this.onVisibility), typeof window < "u" && window.addEventListener("pageshow", this.onPageShow));
@@ -1101,15 +1101,15 @@ var K = class {
1101
1101
  if (this.cancelRefocus(), Number.isFinite(this.deps.video.duration)) return;
1102
1102
  let e = this.liveEnd(), t = () => typeof performance < "u" ? performance.now() : Date.now(), n = t(), r = 0, i = () => {
1103
1103
  if (this.refocusTimer = null, Number.isFinite(this.deps.video.duration)) return;
1104
- r += U;
1105
- let a = this.liveEnd(), o = a != null && (e == null || a >= e + $e), s = Math.max(r, t() - n) >= Qe;
1104
+ r += H;
1105
+ let a = this.liveEnd(), o = a != null && (e == null || a >= e + et), s = Math.max(r, t() - n) >= $e;
1106
1106
  if (o || s && a != null) {
1107
1107
  this.snapToLive();
1108
1108
  return;
1109
1109
  }
1110
- this.refocusTimer = setTimeout(i, U);
1110
+ this.refocusTimer = setTimeout(i, H);
1111
1111
  };
1112
- this.refocusTimer = setTimeout(i, U);
1112
+ this.refocusTimer = setTimeout(i, H);
1113
1113
  }
1114
1114
  cancelRefocus() {
1115
1115
  this.refocusTimer != null && clearTimeout(this.refocusTimer), this.refocusTimer = null;
@@ -1123,7 +1123,7 @@ var K = class {
1123
1123
  snapToLive() {
1124
1124
  let e = this.deps.video, t = this.liveEnd();
1125
1125
  if (t == null) return;
1126
- let n = e.seekable.start(e.seekable.length - 1), r = Math.min(e.currentTime, t), i = Math.max(n, t - Ze, r);
1126
+ let n = e.seekable.start(e.seekable.length - 1), r = Math.min(e.currentTime, t), i = Math.max(n, t - Qe, r);
1127
1127
  try {
1128
1128
  e.currentTime = i;
1129
1129
  } catch {}
@@ -1141,13 +1141,25 @@ var K = class {
1141
1141
  } catch {}
1142
1142
  }
1143
1143
  };
1144
- function nt(e, t) {
1144
+ function rt(e, t) {
1145
1145
  return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
1146
1146
  }
1147
1147
  //#endregion
1148
+ //#region src/core/drm/signedUrl.ts
1149
+ function K(e, t = Date.now()) {
1150
+ if (!e) return !1;
1151
+ let n;
1152
+ try {
1153
+ n = new URL(e).searchParams.get("exp");
1154
+ } catch {
1155
+ return !1;
1156
+ }
1157
+ return !n || !/^\d+$/.test(n) ? !1 : Number(n) * 1e3 <= t;
1158
+ }
1159
+ //#endregion
1148
1160
  //#region src/core/engine/prefetch.ts
1149
- var rt = 15e3, it = 5e3, at = 6;
1150
- function ot(e) {
1161
+ var it = 15e3, at = 5e3, ot = 6;
1162
+ function st(e) {
1151
1163
  try {
1152
1164
  let t = new URL(e);
1153
1165
  return t.searchParams.delete("CMCD"), t.toString();
@@ -1155,7 +1167,7 @@ function ot(e) {
1155
1167
  return e;
1156
1168
  }
1157
1169
  }
1158
- var st = class {
1170
+ var ct = class {
1159
1171
  cmcd;
1160
1172
  entries = /* @__PURE__ */ new Map();
1161
1173
  keyed = /* @__PURE__ */ new Set();
@@ -1178,10 +1190,10 @@ var st = class {
1178
1190
  }
1179
1191
  prefetch(e, t, n) {
1180
1192
  if (!this.isActive(t)) return;
1181
- let r = ot(e);
1193
+ let r = st(e);
1182
1194
  if (this.entries.has(r)) return;
1183
1195
  let i = this.perTrack.get(t) ?? 0;
1184
- if (i >= at) return;
1196
+ if (i >= ot) return;
1185
1197
  this.perTrack.set(t, i + 1);
1186
1198
  let a = new AbortController(), o = {
1187
1199
  started: performance.now(),
@@ -1195,10 +1207,10 @@ var st = class {
1195
1207
  signal: a.signal
1196
1208
  }).then(async (e) => (o.first = performance.now(), e.ok ? e.arrayBuffer() : null)).catch(() => null), this.entries.set(r, o), this.stats.started += 1, setTimeout(() => {
1197
1209
  this.entries.get(r) === o && (this.entries.delete(r), a.abort(), this.stats.expired += 1);
1198
- }, rt);
1210
+ }, it);
1199
1211
  }
1200
1212
  take(e) {
1201
- let t = ot(e), n = this.entries.get(t);
1213
+ let t = st(e), n = this.entries.get(t);
1202
1214
  return n && this.entries.delete(t), n;
1203
1215
  }
1204
1216
  destroy() {
@@ -1218,13 +1230,13 @@ var st = class {
1218
1230
  }
1219
1231
  }
1220
1232
  };
1221
- function ct(t) {
1233
+ function lt(t) {
1222
1234
  let n = e.DefaultConfig?.loader;
1223
1235
  if (typeof n != "function") return;
1224
1236
  class r extends n {
1225
1237
  served = !1;
1226
1238
  cancelled = !1;
1227
- stats = lt();
1239
+ stats = ut();
1228
1240
  load(e, n, r) {
1229
1241
  let i = e.rangeEnd ? void 0 : t.take(e.url);
1230
1242
  if (!i) {
@@ -1232,7 +1244,7 @@ function ct(t) {
1232
1244
  return;
1233
1245
  }
1234
1246
  this.served = !0;
1235
- let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || it, s = setTimeout(() => {
1247
+ let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || at, s = setTimeout(() => {
1236
1248
  !this.cancelled && this.served && (i.abort.abort(), t.stats.failed += 1, this.served = !1, super.load(e, n, r));
1237
1249
  }, o);
1238
1250
  i.bytes.then((o) => {
@@ -1259,7 +1271,7 @@ function ct(t) {
1259
1271
  }
1260
1272
  return r;
1261
1273
  }
1262
- function lt() {
1274
+ function ut() {
1263
1275
  return {
1264
1276
  aborted: !1,
1265
1277
  loaded: 0,
@@ -1283,10 +1295,10 @@ function lt() {
1283
1295
  }
1284
1296
  };
1285
1297
  }
1286
- function ut(e) {
1298
+ function dt(e) {
1287
1299
  return e === "audio" ? "audio" : "main";
1288
1300
  }
1289
- function dt(e, t) {
1301
+ function ft(e, t) {
1290
1302
  let n = [];
1291
1303
  t.initSegment?.url && !t.initSegment.data && n.push({
1292
1304
  url: t.initSegment.url,
@@ -1305,24 +1317,24 @@ function dt(e, t) {
1305
1317
  }
1306
1318
  //#endregion
1307
1319
  //#region src/core/engine/hls.ts
1308
- function ft() {
1320
+ function pt() {
1309
1321
  return e.isSupported();
1310
1322
  }
1311
- var pt = 3, mt = 5, ht = 3, gt = 3e4, _t = 12e3, vt = 3e3, yt = 6e3, bt = .5, xt = 3, St = .5, Ct = 1.1, wt = .25, Tt = 5e3, Et = 4e3, Dt = 2, Ot = 5, kt = 2, At = 2, jt = 4, Mt = 4, Nt = 2e3, Pt = 3e4, Ft = .2, It = 30, Lt = 2, Rt = 2, zt = 9, Bt = .5, Vt = 64;
1312
- function Ht(e) {
1323
+ var mt = 3, ht = 5, gt = 3, _t = 1e4, vt = 3e4, yt = 12e3, bt = 3e3, xt = 6e3, St = .5, Ct = 3, wt = .5, Tt = 1.1, Et = .25, Dt = 5e3, Ot = 4e3, kt = 2, At = 5, jt = 2, Mt = 2, Nt = 4, Pt = 4, Ft = 2e3, It = 3e4, Lt = .2, Rt = 30, zt = 2, Bt = 2, Vt = 9, Ht = .5, Ut = 64;
1324
+ function Wt(e) {
1313
1325
  if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
1314
1326
  delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
1315
1327
  return;
1316
1328
  }
1317
- e.liveSyncDuration ??= Rt;
1318
- let t = Math.max(12, e.liveSyncDuration + zt);
1319
- (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), Ut(e, e.liveSyncDuration);
1329
+ e.liveSyncDuration ??= Bt;
1330
+ let t = Math.max(12, e.liveSyncDuration + Vt);
1331
+ (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), Gt(e, e.liveSyncDuration);
1320
1332
  }
1321
- function Ut(e, t) {
1333
+ function Gt(e, t) {
1322
1334
  let n = (e, t, n) => Math.min(n, Math.max(t, e));
1323
1335
  e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
1324
1336
  }
1325
- var Wt = class {
1337
+ var Kt = class {
1326
1338
  name = "hls";
1327
1339
  hls = null;
1328
1340
  deps;
@@ -1402,11 +1414,11 @@ var Wt = class {
1402
1414
  frameCounter;
1403
1415
  detachFrames = null;
1404
1416
  constructor(e) {
1405
- this.deps = e, this.frameCounter = new H(e.video), this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
1417
+ this.deps = e, this.frameCounter = new Ye(e.video), this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
1406
1418
  }
1407
1419
  async load() {
1408
1420
  this.detachFrames ??= this.frameCounter.attach();
1409
- let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = W(r) && G(), o = !!e.drm?.widevine?.licenseUrl && !a;
1421
+ let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = U(r) && W(), o = !!e.drm?.widevine?.licenseUrl && !a;
1410
1422
  if (e.drmEnabled && !o) {
1411
1423
  i({
1412
1424
  type: "error",
@@ -1415,7 +1427,7 @@ var Wt = class {
1415
1427
  });
1416
1428
  return;
1417
1429
  }
1418
- e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ae(r), Pe()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1430
+ e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ae(r), Me()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1419
1431
  let e = this.hls;
1420
1432
  if (document.visibilityState !== "visible" || !e) return;
1421
1433
  let t = e.liveSyncPosition;
@@ -1438,7 +1450,7 @@ var Wt = class {
1438
1450
  }
1439
1451
  this.loadSuspended = !0;
1440
1452
  }
1441
- }, Tt));
1453
+ }, Dt));
1442
1454
  }
1443
1455
  resumeLoading() {
1444
1456
  if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
@@ -1470,7 +1482,7 @@ var Wt = class {
1470
1482
  let t = e.liveSyncPosition;
1471
1483
  if (typeof t != "number" || !Number.isFinite(t)) return;
1472
1484
  let { video: n } = this.deps;
1473
- n.currentTime <= t + Bt || (n.currentTime = t);
1485
+ n.currentTime <= t + Ht || (n.currentTime = t);
1474
1486
  }
1475
1487
  startHls() {
1476
1488
  let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps;
@@ -1496,10 +1508,21 @@ var Wt = class {
1496
1508
  },
1497
1509
  ...j() ? { requestMediaKeySystemAccessFunc: P(t) } : {},
1498
1510
  licenseXhrSetup: (e, t) => {
1499
- e.open("POST", this.licenseUrl ?? t, !0), e.setRequestHeader("x-api-key", r.apiKey), e.setRequestHeader("X-Match-Urn", n.matchUrn), e.setRequestHeader("X-Device-Id", i), a && e.setRequestHeader("X-User-Id", a), this.licenseRequested = !0;
1500
- let o = performance.now();
1501
- e.addEventListener("loadend", () => {
1502
- this.licenseTimeMs === 0 && (this.licenseTimeMs = Math.max(1, Math.round(performance.now() - o)));
1511
+ let o = performance.now(), s = () => {
1512
+ e.open("POST", this.licenseUrl ?? t, !0), e.setRequestHeader("x-api-key", r.apiKey), e.setRequestHeader("X-Match-Urn", n.matchUrn), e.setRequestHeader("X-Device-Id", i), a && e.setRequestHeader("X-User-Id", a), this.licenseRequested = !0, e.addEventListener("loadend", () => {
1513
+ this.licenseTimeMs === 0 && (this.licenseTimeMs = Math.max(1, Math.round(performance.now() - o)));
1514
+ });
1515
+ }, { freshLicenseUrl: c } = this.deps;
1516
+ if (!c || !K(this.licenseUrl)) {
1517
+ s();
1518
+ return;
1519
+ }
1520
+ let l = this.hls, u, d = new Promise((e) => {
1521
+ u = setTimeout(() => e(void 0), _t);
1522
+ });
1523
+ return Promise.race([c().catch(() => void 0), d]).finally(() => clearTimeout(u)).then((e) => {
1524
+ if (!this.hls || this.hls !== l) throw Error("havik-player: engine torn down during refresh");
1525
+ e && (this.licenseUrl = e), s();
1503
1526
  });
1504
1527
  }
1505
1528
  } : {},
@@ -1511,20 +1534,20 @@ var Wt = class {
1511
1534
  ...c
1512
1535
  };
1513
1536
  if (this.prefetch?.destroy(), this.prefetch = null, u && this.deps.mediaDuringKey !== !1 && !d.fLoader) {
1514
- let e = new st({
1537
+ let e = new ct({
1515
1538
  sessionId: n.analytics?.sid,
1516
1539
  contentId: n.matchUrn
1517
- }), t = ct(e);
1540
+ }), t = lt(e);
1518
1541
  t && (this.prefetch = e, d.fLoader = t);
1519
1542
  }
1520
- Ht(d), this.catchUpRate = typeof d.maxLiveSyncPlaybackRate == "number" ? d.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (d.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = d.autoStartLoad !== !1;
1543
+ Wt(d), this.catchUpRate = typeof d.maxLiveSyncPlaybackRate == "number" ? d.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (d.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = d.autoStartLoad !== !1;
1521
1544
  let f = new e(d);
1522
1545
  if (this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
1523
1546
  this.mediaRecoveries = 0, this.networkRecoveries = 0, u && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && this.dropLevelsWidevineCannotPlay(f), this.measureLadder(f), this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
1524
1547
  }), f.on(e.Events.FRAG_BUFFERED, (e, t) => {
1525
1548
  t?.frag?.type === "main" && (this.kickKind !== "dead" && this.clearKick(), (this.mediaRecoveries > 0 || this.networkRecoveries > 0 || this.licenseRecoveries > 0 || this.starvationKicks > 0 || this.starvationRebuilds > 0) && !this.recoveryResetTimer && (this.recoveryResetTimer = setTimeout(() => {
1526
1549
  this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
1527
- }, gt)));
1550
+ }, vt)));
1528
1551
  }), f.on(e.Events.FRAG_LOADING, (e, t) => {
1529
1552
  t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
1530
1553
  }), f.on(e.Events.FRAG_LOADED, (e, t) => {
@@ -1532,10 +1555,10 @@ var Wt = class {
1532
1555
  let n = t?.frag?.stats, r = n?.loaded;
1533
1556
  typeof r == "number" && (this.bytesLoaded += r), !this.reportedFirstBytes && typeof r == "number" && r > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
1534
1557
  let i = n?.loading;
1535
- i && i.end > 0 && i.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(i.end - i.start))), this.requestTimesMs.length > Vt && this.requestTimesMs.shift());
1558
+ i && i.end > 0 && i.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(i.end - i.start))), this.requestTimesMs.length > Ut && this.requestTimesMs.shift());
1536
1559
  let a = t?.frag?.url;
1537
1560
  if (a) {
1538
- let e = B(a);
1561
+ let e = Ke(a);
1539
1562
  e && (this.cdnHost = e);
1540
1563
  }
1541
1564
  }), f.on(e.Events.LEVEL_LOADED, (e, t) => {
@@ -1549,15 +1572,15 @@ var Wt = class {
1549
1572
  }), f.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.prefetch) {
1550
1573
  let t = this.prefetch;
1551
1574
  f.on(e.Events.KEY_LOADING, (e, n) => {
1552
- let r = n?.frag, i = ut(r?.type);
1553
- if (r && t.isActive(i)) for (let e of dt(f, r)) t.prefetch(e.url, i, e.kind);
1554
- }), f.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(ut(n?.frag?.type)));
1575
+ let r = n?.frag, i = dt(r?.type);
1576
+ if (r && t.isActive(i)) for (let e of ft(f, r)) t.prefetch(e.url, i, e.kind);
1577
+ }), f.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(dt(n?.frag?.type)));
1555
1578
  }
1556
1579
  f.on(e.Events.KEY_LOADED, () => {
1557
1580
  u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
1558
1581
  }), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
1559
1582
  this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.checkFrameDrops();
1560
- }, vt), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1583
+ }, bt), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1561
1584
  this.renditionSwitches += 1;
1562
1585
  let n = this.lastLevelIndex >= 0 ? f.levels[this.lastLevelIndex] : void 0, r = f.levels[t.level];
1563
1586
  n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, l({
@@ -1621,7 +1644,7 @@ var Wt = class {
1621
1644
  return;
1622
1645
  }
1623
1646
  this.capTimer && clearTimeout(this.capTimer);
1624
- let t = e > this.sizeCapLevel ? Nt : Pt;
1647
+ let t = e > this.sizeCapLevel ? Ft : It;
1625
1648
  this.capTimer = setTimeout(() => {
1626
1649
  this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
1627
1650
  }, t);
@@ -1631,9 +1654,9 @@ var Wt = class {
1631
1654
  this.ladderHeights = t.length ? [...new Set(t)].sort((e, t) => e - t) : void 0, this.ladderTopBitrateKbps = e.levels.length ? Math.round(Math.max(...e.levels.map((e) => e.bitrate)) / 1e3) : 0;
1632
1655
  }
1633
1656
  dropLevelsWidevineCannotPlay(e) {
1634
- this.removeLevelsWhere(e, (e) => Fe(e) !== !0);
1657
+ this.removeLevelsWhere(e, (e) => Ne(e) !== !0);
1635
1658
  let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && I(e) !== "avc" && !!I(e)));
1636
- for (let n of t) Ne(n).then((t) => {
1659
+ for (let n of t) je(n).then((t) => {
1637
1660
  t || this.hls !== e || this.removeLevelsWhere(e, (e) => e === n) && (this.measureLadder(e), this.applySizeCap());
1638
1661
  });
1639
1662
  }
@@ -1644,7 +1667,7 @@ var Wt = class {
1644
1667
  a && I(a) && t(a) && (r.push(n), i.add(a));
1645
1668
  }), !r.length) return !1;
1646
1669
  let a = [...i].join(", ");
1647
- if (!n.some((e, t) => r.includes(t) ? !1 : !I(e.videoCodec) || Fe(e.videoCodec) === !0)) return console.warn(`havik-player: every rendition is ${a}, which Widevine may not play on this browser; keeping them`), !1;
1670
+ if (!n.some((e, t) => r.includes(t) ? !1 : !I(e.videoCodec) || Ne(e.videoCodec) === !0)) return console.warn(`havik-player: every rendition is ${a}, which Widevine may not play on this browser; keeping them`), !1;
1648
1671
  for (let t = r.length - 1; t >= 0; --t) e.removeLevel(r[t]);
1649
1672
  return console.info(`havik-player: skipped ${r.length} rendition(s) Widevine cannot play on this browser (${a})`), !0;
1650
1673
  }
@@ -1742,7 +1765,7 @@ var Wt = class {
1742
1765
  return;
1743
1766
  }
1744
1767
  let e = Date.now() - this.lastAdvanceMs;
1745
- !this.chaseSuspended && e > yt && this.suspendChasing(), e > _t && this.emitEnded("stalled");
1768
+ !this.chaseSuspended && e > xt && this.suspendChasing(), e > yt && this.emitEnded("stalled");
1746
1769
  }
1747
1770
  resetStarvationWindow() {
1748
1771
  this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
@@ -1757,7 +1780,7 @@ var Wt = class {
1757
1780
  this.resetStarvationWindow();
1758
1781
  return;
1759
1782
  }
1760
- let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < yt, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > Et, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = V(t), c = o - s, l = c !== this.starvedFrames;
1783
+ let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < xt, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > Ot, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = V(t), c = o - s, l = c !== this.starvedFrames;
1761
1784
  if (this.starvedFrames = c, !a || l) {
1762
1785
  (t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
1763
1786
  return;
@@ -1766,12 +1789,12 @@ var Wt = class {
1766
1789
  this.resetStarvationWindow();
1767
1790
  return;
1768
1791
  }
1769
- if (this.kickPending && (this.kickKind === "dead" || i) && (this.kickTicks += 1), this.starvedTicks = i ? this.starvedTicks + 1 : 0, this.deadTicks += 1, this.recentMainFrags.push(this.mainFragsSinceTick), this.mainFragsSinceTick = 0, this.recentMainFrags.length > jt && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= kt && (this.clearKick(), this.starvationRebuilds < At)) {
1792
+ if (this.kickPending && (this.kickKind === "dead" || i) && (this.kickTicks += 1), this.starvedTicks = i ? this.starvedTicks + 1 : 0, this.deadTicks += 1, this.recentMainFrags.push(this.mainFragsSinceTick), this.mainFragsSinceTick = 0, this.recentMainFrags.length > Nt && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= jt && (this.clearKick(), this.starvationRebuilds < Mt)) {
1770
1793
  this.starvationRebuilds += 1, this.resetStarvationWindow(), this.clearRecoveryReset(), console.warn("havik-player: restarting the load did not resume video (the wedge is in hls.js state that only a rebuild clears) — rebuilding the player"), this.rebuildInstance("starvation rebuild");
1771
1794
  return;
1772
1795
  }
1773
- let u = i && this.starvedTicks >= Dt, d = !i && this.deadTicks >= jt && this.recentMainFrags.reduce((e, t) => e + t, 0) >= Mt;
1774
- if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= Ot))) {
1796
+ let u = i && this.starvedTicks >= kt, d = !i && this.deadTicks >= Nt && this.recentMainFrags.reduce((e, t) => e + t, 0) >= Pt;
1797
+ if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= At))) {
1775
1798
  this.starvationKicks += 1, this.kickPending = !0, this.kickTicks = 0, this.kickKind = d ? "dead" : "quiet", this.clearRecoveryReset(), console.warn(d ? "havik-player: video starved while hls.js keeps loading media it never plays (dead pipeline at the live edge) — restarting the load" : "havik-player: video starved while the live playlist advances (wedged hls.js fragment pipeline) — restarting the load");
1776
1799
  try {
1777
1800
  e.stopLoad(), e.startLoad(-1);
@@ -1786,7 +1809,7 @@ var Wt = class {
1786
1809
  let t = e.latency, n = e.targetLatency;
1787
1810
  if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
1788
1811
  let r = t - n;
1789
- !this.catchUpEngaged && r > bt ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= bt && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
1812
+ !this.catchUpEngaged && r > St ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= St && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
1790
1813
  let i = this.catchUpEngaged ? this.catchUpRate : 1;
1791
1814
  e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
1792
1815
  }
@@ -1808,15 +1831,15 @@ var Wt = class {
1808
1831
  return;
1809
1832
  }
1810
1833
  let { totalFrames: n, dropped: r } = V(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
1811
- if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < It || o < 0) {
1834
+ if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < Rt || o < 0) {
1812
1835
  this.fpsBadTicks = 0;
1813
1836
  return;
1814
1837
  }
1815
- if (o <= Ft * a) {
1838
+ if (o <= Lt * a) {
1816
1839
  this.fpsBadTicks = 0;
1817
1840
  return;
1818
1841
  }
1819
- if (this.fpsBadTicks += 1, this.fpsBadTicks < Lt) return;
1842
+ if (this.fpsBadTicks += 1, this.fpsBadTicks < zt) return;
1820
1843
  this.fpsBadTicks = 0;
1821
1844
  let s = e.levels, c = s[e.currentLevel];
1822
1845
  if (!c) return;
@@ -1833,20 +1856,20 @@ var Wt = class {
1833
1856
  return;
1834
1857
  }
1835
1858
  let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
1836
- if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(Ct, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
1859
+ if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(Tt, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
1837
1860
  this.resetChaseWindow();
1838
1861
  return;
1839
1862
  }
1840
- if (this.chaseLatency < 0 || this.chaseLatency - n >= St) {
1863
+ if (this.chaseLatency < 0 || this.chaseLatency - n >= wt) {
1841
1864
  this.chaseLatency = n, this.chaseTicks = 0;
1842
1865
  return;
1843
1866
  }
1844
- if (this.chaseTicks += 1, this.chaseTicks < xt) return;
1867
+ if (this.chaseTicks += 1, this.chaseTicks < Ct) return;
1845
1868
  this.resetChaseWindow();
1846
1869
  let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
1847
1870
  if (!(a > 1)) return;
1848
1871
  let o = typeof e.targetLatency == "number" ? e.targetLatency : 0, s = Math.min(n, a - 1);
1849
- s < o + wt || (console.warn(`havik-player: catch-up at ${r}x not gaining on the live edge (latency ${n.toFixed(1)}s); holding at ${s.toFixed(1)}s`), this.liveRetargets += 1, e.targetLatency = s);
1872
+ s < o + Et || (console.warn(`havik-player: catch-up at ${r}x not gaining on the live edge (latency ${n.toFixed(1)}s); holding at ${s.toFixed(1)}s`), this.liveRetargets += 1, e.targetLatency = s);
1850
1873
  }
1851
1874
  suspendChasing() {
1852
1875
  let e = this.hls;
@@ -1891,7 +1914,7 @@ var Wt = class {
1891
1914
  scheduleLicenseRetry(t) {
1892
1915
  if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
1893
1916
  let n = t.response?.code ?? 0;
1894
- if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= ht) return !1;
1917
+ if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= gt) return !1;
1895
1918
  this.licenseRecoveries += 1;
1896
1919
  let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
1897
1920
  return this.licenseRetryTimer = setTimeout(() => {
@@ -1923,7 +1946,7 @@ var Wt = class {
1923
1946
  return;
1924
1947
  }
1925
1948
  if (t.type === e.ErrorTypes.NETWORK_ERROR) {
1926
- if (this.networkRecoveries < mt) {
1949
+ if (this.networkRecoveries < ht) {
1927
1950
  this.networkRecoveries += 1;
1928
1951
  let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
1929
1952
  this.networkRetryTimer = setTimeout(() => {
@@ -1940,7 +1963,7 @@ var Wt = class {
1940
1963
  return;
1941
1964
  }
1942
1965
  if (t.type === e.ErrorTypes.MEDIA_ERROR) {
1943
- if (this.mediaRecoveries < pt) {
1966
+ if (this.mediaRecoveries < mt) {
1944
1967
  this.mediaRecoveries += 1, n.recoverMediaError();
1945
1968
  return;
1946
1969
  }
@@ -1964,19 +1987,19 @@ var Wt = class {
1964
1987
  let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
1965
1988
  return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
1966
1989
  }
1967
- }, Gt = 15e3, Kt = 6e5, qt = 3e5, Jt = 100, q = 1, Yt = 1e3, Xt = 3e4, Zt = 1e3, Qt = {
1990
+ }, qt = 15e3, Jt = 6e5, Yt = 3e5, Xt = 100, q = 1, Zt = 1e3, Qt = 3e4, $t = 1e3, en = {
1968
1991
  inline: "PRESENTATION_INLINE",
1969
1992
  fullscreen: "PRESENTATION_FULLSCREEN",
1970
1993
  pip: "PRESENTATION_PIP"
1971
- }, $t = {
1994
+ }, tn = {
1972
1995
  widevine: "KEY_SYSTEM_WIDEVINE",
1973
1996
  fairplay: "KEY_SYSTEM_FAIRPLAY",
1974
1997
  none: "KEY_SYSTEM_NONE"
1975
1998
  };
1976
- function en(e, t) {
1999
+ function nn(e, t) {
1977
2000
  return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
1978
2001
  }
1979
- var tn = /* @__PURE__ */ new Set([
2002
+ var rn = /* @__PURE__ */ new Set([
1980
2003
  "INVALID_URN",
1981
2004
  "NOT_FOUND",
1982
2005
  "GONE",
@@ -1996,7 +2019,7 @@ var tn = /* @__PURE__ */ new Set([
1996
2019
  ended: "PLAYER_STATE_ENDED",
1997
2020
  error: "PLAYER_STATE_ERROR"
1998
2021
  };
1999
- function nn(e) {
2022
+ function an(e) {
2000
2023
  try {
2001
2024
  let t = new URL(e), [n, ...r] = t.hostname.split(".");
2002
2025
  return !n || r.length === 0 || n !== "feed" && !n.startsWith("feed-") ? void 0 : (t.hostname = [n.replace(/^feed/, "beacons"), ...r].join("."), t.pathname = "", t.search = "", t.origin);
@@ -2004,8 +2027,8 @@ function nn(e) {
2004
2027
  return;
2005
2028
  }
2006
2029
  }
2007
- var rn = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), an = /* @__PURE__ */ new Set(), Y = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), on = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
2008
- function sn(e) {
2030
+ var on = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), sn = /* @__PURE__ */ new Set(), Y = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), cn = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
2031
+ function ln(e) {
2009
2032
  if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
2010
2033
  let t;
2011
2034
  try {
@@ -2014,19 +2037,19 @@ function sn(e) {
2014
2037
  } catch {
2015
2038
  return;
2016
2039
  }
2017
- if (an.has(t) && !Y.has(t)) {
2018
- Y.add(t), g(on(new URL(t).origin));
2040
+ if (sn.has(t) && !Y.has(t)) {
2041
+ Y.add(t), g(cn(new URL(t).origin));
2019
2042
  for (let e of X) e.noteCspBlocked();
2020
2043
  }
2021
2044
  }
2022
- function cn(e, t) {
2045
+ function un(e, t) {
2023
2046
  return g(t, e), { disabledReason: t };
2024
2047
  }
2025
- function ln(e, t, n) {
2026
- if (n) return t && !rn(t, n) && g(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
2048
+ function dn(e, t, n) {
2049
+ if (n) return t && !on(t, n) && g(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
2027
2050
  if (t) return { endpoint: t };
2028
- if (t !== void 0) return cn("empty-endpoint", "analytics is disabled: no QoE beacons will be sent. analytics.endpoint was supplied but empty. Pass a real beacons origin, analytics: { endpoint: 'https://beacons[-dev].<domain>' }, or omit the option to derive it from baseUrl (or analytics: false to opt out).");
2029
- let r = nn(e);
2051
+ if (t !== void 0) return un("empty-endpoint", "analytics is disabled: no QoE beacons will be sent. analytics.endpoint was supplied but empty. Pass a real beacons origin, analytics: { endpoint: 'https://beacons[-dev].<domain>' }, or omit the option to derive it from baseUrl (or analytics: false to opt out).");
2052
+ let r = an(e);
2030
2053
  if (r) return { endpoint: r };
2031
2054
  let i;
2032
2055
  try {
@@ -2034,9 +2057,9 @@ function ln(e, t, n) {
2034
2057
  } catch {
2035
2058
  i = e;
2036
2059
  }
2037
- return cn(i, `analytics is disabled: no QoE beacons will be sent. The beacons endpoint cannot be derived from the baseUrl host "${i}" — the convention is feed[-dev].<domain> → beacons[-dev].<domain>. Pass an explicit endpoint, analytics: { endpoint: 'https://beacons[-dev].<domain>' }, to createPlayer (or analytics: false to opt out deliberately).`);
2060
+ return un(i, `analytics is disabled: no QoE beacons will be sent. The beacons endpoint cannot be derived from the baseUrl host "${i}" — the convention is feed[-dev].<domain> → beacons[-dev].<domain>. Pass an explicit endpoint, analytics: { endpoint: 'https://beacons[-dev].<domain>' }, to createPlayer (or analytics: false to opt out deliberately).`);
2038
2061
  }
2039
- var un = class {
2062
+ var fn = class {
2040
2063
  opts;
2041
2064
  url;
2042
2065
  cspKey;
@@ -2118,8 +2141,8 @@ var un = class {
2118
2141
  constructor(e) {
2119
2142
  this.opts = {
2120
2143
  ...e,
2121
- heartbeatMs: e.heartbeatMs ?? Gt,
2122
- idleMs: e.idleMs ?? Kt
2144
+ heartbeatMs: e.heartbeatMs ?? qt,
2145
+ idleMs: e.idleMs ?? Jt
2123
2146
  }, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
2124
2147
  try {
2125
2148
  let e = new URL(this.url);
@@ -2136,11 +2159,11 @@ var un = class {
2136
2159
  sdkVersion: this.opts.sdkVersion,
2137
2160
  ...this.opts.environment
2138
2161
  };
2139
- this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Yt), this.lastTickMs = this.now(), this.timer = setInterval(() => this.heartbeat(), this.opts.heartbeatMs), typeof window < "u" && window.addEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.addEventListener("visibilitychange", this.onVisibility), document.addEventListener("freeze", this.onFreeze), document.addEventListener("resume", this.onResume), this.cspKey && an.add(this.cspKey), document.addEventListener("securitypolicyviolation", sn), X.add(this), this.noteCspBlocked(), this.onVisibility());
2162
+ this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Zt), this.lastTickMs = this.now(), this.timer = setInterval(() => this.heartbeat(), this.opts.heartbeatMs), typeof window < "u" && window.addEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.addEventListener("visibilitychange", this.onVisibility), document.addEventListener("freeze", this.onFreeze), document.addEventListener("resume", this.onResume), this.cspKey && sn.add(this.cspKey), document.addEventListener("securitypolicyviolation", ln), X.add(this), this.noteCspBlocked(), this.onVisibility());
2140
2163
  }
2141
2164
  checkSuspension(e) {
2142
2165
  if (this.endedFlag || !this.opts.idleMs) return !1;
2143
- let t = Math.max(this.opts.idleMs, qt);
2166
+ let t = Math.max(this.opts.idleMs, Yt);
2144
2167
  return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
2145
2168
  }
2146
2169
  syncIdle(e) {
@@ -2163,12 +2186,12 @@ var un = class {
2163
2186
  let a = {
2164
2187
  fromState: J[e] ?? "PLAYER_STATE_UNSPECIFIED",
2165
2188
  toState: J[t] ?? "PLAYER_STATE_UNSPECIFIED",
2166
- presentation: Qt[this.presentation]
2189
+ presentation: en[this.presentation]
2167
2190
  }, o = this.causeOf(e, t, i);
2168
2191
  o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
2169
2192
  }
2170
2193
  seekInduced(e) {
2171
- return this.lastSeekMs >= 0 && e - this.lastSeekMs < Zt;
2194
+ return this.lastSeekMs >= 0 && e - this.lastSeekMs < $t;
2172
2195
  }
2173
2196
  causeOf(e, t, n) {
2174
2197
  if (t === "error") return "TRANSITION_CAUSE_ERROR";
@@ -2242,7 +2265,7 @@ var un = class {
2242
2265
  let r = n ?? "";
2243
2266
  if (r !== "") return /^fragLoad/i.test(r) ? this.sawFirstBytes ? "ERROR_STAGE_SEGMENT" : "ERROR_STAGE_FIRST_SEGMENT" : /^(manifest|level|audioTrack|subtitleTrack)/i.test(r) ? "ERROR_STAGE_MANIFEST" : /key|licen[cs]e/i.test(r) ? "ERROR_STAGE_DRM" : /parsing|append|buffer|remux|decrypt|media/i.test(r) ? "ERROR_STAGE_DECODE" : "ERROR_STAGE_OTHER";
2244
2267
  if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
2245
- if (tn.has(e)) return "ERROR_STAGE_RESOLVE";
2268
+ if (rn.has(e)) return "ERROR_STAGE_RESOLVE";
2246
2269
  let i = t ?? "";
2247
2270
  return /frag|segment/i.test(i) ? this.sawFirstBytes ? "ERROR_STAGE_SEGMENT" : "ERROR_STAGE_FIRST_SEGMENT" : /manifest|level|playlist/i.test(i) ? "ERROR_STAGE_MANIFEST" : /key|licen[cs]e/i.test(i) ? "ERROR_STAGE_DRM" : /buffer|decode|media|append/i.test(i) ? "ERROR_STAGE_DECODE" : "ERROR_STAGE_OTHER";
2248
2271
  }
@@ -2289,14 +2312,14 @@ var un = class {
2289
2312
  if (this.lastRequestCount = g, _ > 0) {
2290
2313
  o.requestCountDelta = _;
2291
2314
  let e = t.requestTimesMs ?? [], n = e.slice(Math.max(0, e.length - _)).sort((e, t) => e - t);
2292
- n.length > 0 && (o.requestTimeP50Ms = en(n, 50), o.requestTimeP95Ms = en(n, 95));
2315
+ n.length > 0 && (o.requestTimeP50Ms = nn(n, 50), o.requestTimeP95Ms = nn(n, 95));
2293
2316
  }
2294
2317
  typeof t.latencySeconds == "number" && typeof t.targetLatencySeconds == "number" && (o.driftMs = Math.round((t.latencySeconds - t.targetLatencySeconds) * 1e3)), typeof t.playbackRate == "number" && t.playbackRate > 0 && (o.playbackRate = t.playbackRate), t.qualityPinned === !0 && (o.qualityPinned = !0), t.cdnHost && (o.cdnHost = t.cdnHost), this.maybeEmitMediaInfo(t), this.enqueue({ heartbeat: o }), this.flush(), s > 0 && this.noteFirstBytes();
2295
2318
  }
2296
2319
  maybeEmitMediaInfo(e) {
2297
2320
  if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
2298
2321
  let t = {};
2299
- e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = $t[e.keySystem]), e.drmSecurityLevel && (t.drmSecurityLevel = e.drmSecurityLevel), e.ladderHeights?.length && (t.ladderHeights = e.ladderHeights), e.ladderTopBitrateKbps && (t.ladderTopBitrateKbps = e.ladderTopBitrateKbps), e.lowLatency && (t.lowLatency = !0);
2322
+ e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = tn[e.keySystem]), e.drmSecurityLevel && (t.drmSecurityLevel = e.drmSecurityLevel), e.ladderHeights?.length && (t.ladderHeights = e.ladderHeights), e.ladderTopBitrateKbps && (t.ladderTopBitrateKbps = e.ladderTopBitrateKbps), e.lowLatency && (t.lowLatency = !0);
2300
2323
  let n = JSON.stringify(t);
2301
2324
  n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
2302
2325
  }
@@ -2316,7 +2339,7 @@ var un = class {
2316
2339
  let c = r?.positionMs ?? 0;
2317
2340
  c > 0 && (i.exitPositionMs = Math.round(c)), this.activeTotalMs > 0 && (i.activeWatchTimeMs = Math.round(this.activeTotalMs)), this.mutedTotalMs > 0 && (i.mutedTimeMs = Math.round(this.mutedTotalMs));
2318
2341
  let l = e !== "END_REASON_ENDED";
2319
- l && this.lastStallMs > 0 && n - this.lastStallMs <= Xt && (i.abandonAfterStallMs = Math.max(q, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= Xt && (i.abandonAfterErrorMs = Math.max(q, Math.round(n - this.lastErrorMs))), this.fullscreenTotalMs > 0 && (i.fullscreenTimeMs = Math.round(this.fullscreenTotalMs)), this.pipTotalMs > 0 && (i.pipTimeMs = Math.round(this.pipTotalMs)), this.volumeChanges > 0 && (i.volumeChanges = this.volumeChanges), this.muteChanges > 0 && (i.muteChanges = this.muteChanges);
2342
+ l && this.lastStallMs > 0 && n - this.lastStallMs <= Qt && (i.abandonAfterStallMs = Math.max(q, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= Qt && (i.abandonAfterErrorMs = Math.max(q, Math.round(n - this.lastErrorMs))), this.fullscreenTotalMs > 0 && (i.fullscreenTimeMs = Math.round(this.fullscreenTotalMs)), this.pipTotalMs > 0 && (i.pipTimeMs = Math.round(this.pipTotalMs)), this.volumeChanges > 0 && (i.volumeChanges = this.volumeChanges), this.muteChanges > 0 && (i.muteChanges = this.muteChanges);
2320
2343
  let u = r?.decodedFrames ?? this.lastDecoded;
2321
2344
  u > 0 && (i.decodedFramesTotal = u), e === "END_REASON_STOPPED" && this.startupTimeMs === 0 && this.lastErrorStage === null && (e = "END_REASON_ABORTED", i.reason = e), this.startupTimeMs === 0 && e !== "END_REASON_ABORTED" && (i.failedStage = this.lastErrorStage ?? (this.manifestLoadMs === 0 ? "ERROR_STAGE_MANIFEST" : this.firstFragLoadMs === 0 ? "ERROR_STAGE_FIRST_SEGMENT" : "ERROR_STAGE_OTHER")), this.pending.push(this.wrap({ sessionEnd: i })), this.flush(e === "END_REASON_PAGEHIDE");
2322
2345
  }
@@ -2336,13 +2359,13 @@ var un = class {
2336
2359
  };
2337
2360
  }
2338
2361
  noteCspBlocked() {
2339
- this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(on(new URL(this.url).origin)));
2362
+ this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(cn(new URL(this.url).origin)));
2340
2363
  }
2341
2364
  cspBlocked() {
2342
2365
  return !!this.cspKey && Y.has(this.cspKey);
2343
2366
  }
2344
2367
  enqueue(e) {
2345
- if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > Jt;) {
2368
+ if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > Xt;) {
2346
2369
  let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
2347
2370
  this.pending.splice(e >= 0 ? e : 0, 1);
2348
2371
  }
@@ -2369,7 +2392,7 @@ var un = class {
2369
2392
  };
2370
2393
  //#endregion
2371
2394
  //#region src/core/environment.ts
2372
- function dn() {
2395
+ function pn() {
2373
2396
  if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
2374
2397
  let e;
2375
2398
  try {
@@ -2394,14 +2417,14 @@ function dn() {
2394
2417
  integration: "INTEGRATION_KIND_IFRAME"
2395
2418
  };
2396
2419
  }
2397
- function fn() {
2420
+ function mn() {
2398
2421
  if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
2399
2422
  let e = navigator.userAgentData, t = e?.platform ?? "";
2400
2423
  if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
2401
2424
  let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
2402
2425
  return e?.mobile ?? (typeof navigator.maxTouchPoints == "number" && navigator.maxTouchPoints > 1 && n > 0 && n < 900) ? n >= 600 ? "DEVICE_CLASS_TABLET" : "DEVICE_CLASS_PHONE" : e || n >= 900 || /mac|win|linux|chrome os/i.test(t) ? "DEVICE_CLASS_DESKTOP" : "DEVICE_CLASS_OTHER";
2403
2426
  }
2404
- function pn() {
2427
+ function hn() {
2405
2428
  let e = typeof navigator < "u" ? navigator.connection : void 0;
2406
2429
  if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
2407
2430
  let t = {
@@ -2420,17 +2443,17 @@ function pn() {
2420
2443
  }
2421
2444
  return typeof e.downlink == "number" && e.downlink > 0 && (i.downlinkKbps = Math.round(e.downlink * 1e3)), typeof e.rtt == "number" && e.rtt > 0 && (i.rttMs = Math.round(e.rtt)), e.saveData && (i.saveData = !0), i;
2422
2445
  }
2423
- function mn(e) {
2424
- let t = dn(), n = {
2425
- deviceClass: fn(),
2446
+ function gn(e) {
2447
+ let t = pn(), n = {
2448
+ deviceClass: mn(),
2426
2449
  integration: t.integration,
2427
- ...pn()
2450
+ ...hn()
2428
2451
  };
2429
2452
  t.host && (n.host = t.host), typeof screen < "u" && screen.width > 0 && (n.screenWidth = screen.width, n.screenHeight = screen.height), typeof window < "u" && window.devicePixelRatio > 0 && (n.devicePixelRatio = Math.round(window.devicePixelRatio * 100) / 100);
2430
2453
  let r = e.getBoundingClientRect?.();
2431
2454
  return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
2432
2455
  }
2433
- async function hn() {
2456
+ async function _n() {
2434
2457
  let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
2435
2458
  if (!e?.getHighEntropyValues) return {};
2436
2459
  try {
@@ -2442,7 +2465,7 @@ async function hn() {
2442
2465
  }
2443
2466
  //#endregion
2444
2467
  //#region src/core/version.ts
2445
- var gn = "2.16.4", _n = {
2468
+ var vn = "2.16.6", yn = {
2446
2469
  accent: "#E1B600",
2447
2470
  accentText: "#1B1C23",
2448
2471
  background: "#0e0f13",
@@ -2453,7 +2476,7 @@ var gn = "2.16.4", _n = {
2453
2476
  border: "rgba(255, 255, 255, 0.1)",
2454
2477
  radius: "8px",
2455
2478
  fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
2456
- }, vn = {
2479
+ }, bn = {
2457
2480
  accent: "--havik-accent",
2458
2481
  accentText: "--havik-accent-text",
2459
2482
  background: "--havik-bg",
@@ -2465,26 +2488,26 @@ var gn = "2.16.4", _n = {
2465
2488
  radius: "--havik-radius",
2466
2489
  fontFamily: "--havik-font"
2467
2490
  };
2468
- function Z(e, t) {
2491
+ function xn(e, t) {
2469
2492
  let n = {
2470
- ..._n,
2493
+ ...yn,
2471
2494
  ...t
2472
2495
  };
2473
- for (let t of Object.keys(vn)) e.style.setProperty(vn[t], n[t]);
2496
+ for (let t of Object.keys(bn)) e.style.setProperty(bn[t], n[t]);
2474
2497
  n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
2475
2498
  }
2476
2499
  //#endregion
2477
2500
  //#region src/ui/styles.ts
2478
- var yn = "havik-player-styles", bn = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer;\n touch-action:manipulation}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n/* Absolutely centred, NOT a flex sibling of .havik-center: the hidden center\n button (.havik-gone) still occupies its 74px in the row, which pushed an\n in-flow spinner 37px right of centre. */\n.havik-spinner{position:absolute;inset:0;margin:auto;width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n/* A status card carries its own logo — the corner watermark would duplicate it. */\n.havik-player.havik-has-status .havik-watermark{display:none}\n\n.havik-bar{position:absolute;left:0;right:0;bottom:0;padding:0 12px 8px;\n opacity:1;transition:opacity .25s;z-index:2}\n.havik-seek{position:relative;height:16px;display:flex;align-items:center;cursor:pointer;margin-bottom:2px}\n.havik-seek__track{position:relative;width:100%;height:4px;border-radius:3px;background:rgba(255,255,255,.25)}\n.havik-seek__buffered{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:rgba(255,255,255,.4)}\n.havik-seek__played{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-seek__thumb{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;\n background:var(--havik-accent,#E1B600);transform:translate(-50%,-50%) scale(0);transition:transform .1s}\n.havik-seek:hover .havik-seek__thumb{transform:translate(-50%,-50%) scale(1)}\n\n.havik-controls{display:flex;align-items:center;gap:6px;height:40px}\n.havik-spacer{flex:1}\n.havik-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;border-radius:var(--havik-radius,8px);\n padding:0;transition:background .12s,color .12s}\n.havik-btn:hover{background:rgba(255,255,255,.12)}\n.havik-btn:focus-visible{outline:2px solid var(--havik-accent,#E1B600);outline-offset:1px}\n.havik-btn svg{width:22px;height:22px}\n\n/* The volume level is filled in accent up to the thumb, like the seek bar's\n played span — a native range input paints no \"elapsed\" side, which left the\n level readable only from the dot's position. --havik-vol (0..1) is set by\n syncVolume(); the track width and thumb size live here as variables because\n the WebKit fill has to compute the thumb centre from both. */\n.havik-vol{display:flex;align-items:center}\n.havik-vol__slider{--havik-vol-w:70px;--havik-vol-thumb:12px;--havik-vol:1;\n --havik-vol-pos:calc(var(--havik-vol-thumb) / 2 + var(--havik-vol) * (var(--havik-vol-w) - var(--havik-vol-thumb)));\n width:0;opacity:0;transition:width .18s,opacity .18s;height:4px;cursor:pointer;\n appearance:none;-webkit-appearance:none;background:transparent;border-radius:3px;margin:0 4px}\n.havik-vol:hover .havik-vol__slider,.havik-vol:focus-within .havik-vol__slider{width:var(--havik-vol-w);opacity:1}\n/* WebKit/Blink have no progress pseudo-element: paint the fill as a hard-stop\n gradient that ends at the thumb centre. */\n.havik-vol__slider::-webkit-slider-runnable-track{height:4px;border-radius:3px;\n background:linear-gradient(to right,var(--havik-accent,#E1B600) var(--havik-vol-pos),\n rgba(255,255,255,.3) var(--havik-vol-pos))}\n/* Firefox fills natively, and tracks the thumb exactly. */\n.havik-vol__slider::-moz-range-track{height:4px;border-radius:3px;background:rgba(255,255,255,.3)}\n.havik-vol__slider::-moz-range-progress{height:4px;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-vol__slider::-webkit-slider-thumb{-webkit-appearance:none;width:var(--havik-vol-thumb);\n height:var(--havik-vol-thumb);border-radius:50%;background:var(--havik-accent,#E1B600);\n margin-top:calc((4px - var(--havik-vol-thumb)) / 2)}\n.havik-vol__slider::-moz-range-thumb{width:var(--havik-vol-thumb);height:var(--havik-vol-thumb);\n border:0;border-radius:50%;background:var(--havik-accent,#E1B600)}\n\n.havik-time{font-size:12px;color:var(--havik-text-muted,#9aa0ad);\n font-variant-numeric:tabular-nums;padding:0 6px;white-space:nowrap}\n.havik-live{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;\n letter-spacing:.4px;padding:0 8px;color:var(--havik-text,#fff)}\n.havik-live svg{width:9px;height:9px;color:var(--havik-text-muted,#9aa0ad)}\n.havik-live.is-live svg{color:var(--havik-accent,#E1B600)}\n.havik-live__go{margin-left:2px;border:0;cursor:pointer;background:transparent;color:var(--havik-text-muted,#9aa0ad);\n font:inherit;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:6px}\n.havik-live.is-live .havik-live__go{display:none}\n.havik-live__go:hover{color:var(--havik-accent,#E1B600)}\n\n.havik-menu{position:absolute;bottom:54px;right:12px;min-width:170px;max-height:230px;overflow:auto;\n background:var(--havik-surface,#1B1C23);border:1px solid var(--havik-border,rgba(255,255,255,.1));\n border-radius:var(--havik-radius,8px);box-shadow:0 10px 30px rgba(0,0,0,.5);padding:6px;z-index:3}\n.havik-menu[hidden]{display:none}\n.havik-menu__title{font-size:11px;text-transform:uppercase;letter-spacing:.6px;\n color:var(--havik-text-muted,#9aa0ad);padding:6px 8px 4px}\n.havik-menu__item{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;font:inherit;font-size:13px;\n text-align:left;padding:7px 8px;border-radius:6px}\n.havik-menu__item:hover{background:var(--havik-surface-muted,#2a2c36)}\n.havik-menu__item[aria-checked=\"true\"]{color:var(--havik-accent,#E1B600);font-weight:600}\n.havik-menu__item[aria-checked=\"true\"]::after{content:'✓'}\n", xn = /* @__PURE__ */ new WeakMap();
2479
- function Sn(e = document, t) {
2480
- let n = e.querySelector(`style#${yn}`);
2481
- if (n && (!t || xn.get(n) === t)) return;
2501
+ var Sn = "havik-player-styles", Cn = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer;\n touch-action:manipulation}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n/* Absolutely centred, NOT a flex sibling of .havik-center: the hidden center\n button (.havik-gone) still occupies its 74px in the row, which pushed an\n in-flow spinner 37px right of centre. */\n.havik-spinner{position:absolute;inset:0;margin:auto;width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n/* A status card carries its own logo — the corner watermark would duplicate it. */\n.havik-player.havik-has-status .havik-watermark{display:none}\n\n.havik-bar{position:absolute;left:0;right:0;bottom:0;padding:0 12px 8px;\n opacity:1;transition:opacity .25s;z-index:2}\n.havik-seek{position:relative;height:16px;display:flex;align-items:center;cursor:pointer;margin-bottom:2px}\n.havik-seek__track{position:relative;width:100%;height:4px;border-radius:3px;background:rgba(255,255,255,.25)}\n.havik-seek__buffered{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:rgba(255,255,255,.4)}\n.havik-seek__played{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-seek__thumb{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;\n background:var(--havik-accent,#E1B600);transform:translate(-50%,-50%) scale(0);transition:transform .1s}\n.havik-seek:hover .havik-seek__thumb{transform:translate(-50%,-50%) scale(1)}\n\n.havik-controls{display:flex;align-items:center;gap:6px;height:40px}\n.havik-spacer{flex:1}\n.havik-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;border-radius:var(--havik-radius,8px);\n padding:0;transition:background .12s,color .12s}\n.havik-btn:hover{background:rgba(255,255,255,.12)}\n.havik-btn:focus-visible{outline:2px solid var(--havik-accent,#E1B600);outline-offset:1px}\n.havik-btn svg{width:22px;height:22px}\n\n/* The volume level is filled in accent up to the thumb, like the seek bar's\n played span — a native range input paints no \"elapsed\" side, which left the\n level readable only from the dot's position. --havik-vol (0..1) is set by\n syncVolume(); the track width and thumb size live here as variables because\n the WebKit fill has to compute the thumb centre from both. */\n.havik-vol{display:flex;align-items:center}\n.havik-vol__slider{--havik-vol-w:70px;--havik-vol-thumb:12px;--havik-vol:1;\n --havik-vol-pos:calc(var(--havik-vol-thumb) / 2 + var(--havik-vol) * (var(--havik-vol-w) - var(--havik-vol-thumb)));\n width:0;opacity:0;transition:width .18s,opacity .18s;height:4px;cursor:pointer;\n appearance:none;-webkit-appearance:none;background:transparent;border-radius:3px;margin:0 4px}\n.havik-vol:hover .havik-vol__slider,.havik-vol:focus-within .havik-vol__slider{width:var(--havik-vol-w);opacity:1}\n/* WebKit/Blink have no progress pseudo-element: paint the fill as a hard-stop\n gradient that ends at the thumb centre. */\n.havik-vol__slider::-webkit-slider-runnable-track{height:4px;border-radius:3px;\n background:linear-gradient(to right,var(--havik-accent,#E1B600) var(--havik-vol-pos),\n rgba(255,255,255,.3) var(--havik-vol-pos))}\n/* Firefox fills natively, and tracks the thumb exactly. */\n.havik-vol__slider::-moz-range-track{height:4px;border-radius:3px;background:rgba(255,255,255,.3)}\n.havik-vol__slider::-moz-range-progress{height:4px;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-vol__slider::-webkit-slider-thumb{-webkit-appearance:none;width:var(--havik-vol-thumb);\n height:var(--havik-vol-thumb);border-radius:50%;background:var(--havik-accent,#E1B600);\n margin-top:calc((4px - var(--havik-vol-thumb)) / 2)}\n.havik-vol__slider::-moz-range-thumb{width:var(--havik-vol-thumb);height:var(--havik-vol-thumb);\n border:0;border-radius:50%;background:var(--havik-accent,#E1B600)}\n\n.havik-time{font-size:12px;color:var(--havik-text-muted,#9aa0ad);\n font-variant-numeric:tabular-nums;padding:0 6px;white-space:nowrap}\n.havik-live{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;\n letter-spacing:.4px;padding:0 8px;color:var(--havik-text,#fff)}\n.havik-live svg{width:9px;height:9px;color:var(--havik-text-muted,#9aa0ad)}\n.havik-live.is-live svg{color:var(--havik-accent,#E1B600)}\n.havik-live__go{margin-left:2px;border:0;cursor:pointer;background:transparent;color:var(--havik-text-muted,#9aa0ad);\n font:inherit;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:6px}\n.havik-live.is-live .havik-live__go{display:none}\n.havik-live__go:hover{color:var(--havik-accent,#E1B600)}\n\n.havik-menu{position:absolute;bottom:54px;right:12px;min-width:170px;max-height:230px;overflow:auto;\n background:var(--havik-surface,#1B1C23);border:1px solid var(--havik-border,rgba(255,255,255,.1));\n border-radius:var(--havik-radius,8px);box-shadow:0 10px 30px rgba(0,0,0,.5);padding:6px;z-index:3}\n.havik-menu[hidden]{display:none}\n.havik-menu__title{font-size:11px;text-transform:uppercase;letter-spacing:.6px;\n color:var(--havik-text-muted,#9aa0ad);padding:6px 8px 4px}\n.havik-menu__item{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;font:inherit;font-size:13px;\n text-align:left;padding:7px 8px;border-radius:6px}\n.havik-menu__item:hover{background:var(--havik-surface-muted,#2a2c36)}\n.havik-menu__item[aria-checked=\"true\"]{color:var(--havik-accent,#E1B600);font-weight:600}\n.havik-menu__item[aria-checked=\"true\"]::after{content:'✓'}\n", Z = /* @__PURE__ */ new WeakMap();
2502
+ function wn(e = document, t) {
2503
+ let n = e.querySelector(`style#${Sn}`);
2504
+ if (n && (!t || Z.get(n) === t)) return;
2482
2505
  let r = e.createElement("style");
2483
- r.id = yn, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = bn, xn.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
2506
+ r.id = Sn, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = Cn, Z.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
2484
2507
  }
2485
2508
  //#endregion
2486
2509
  //#region src/ui/icons.ts
2487
- var Cn = {
2510
+ var Tn = {
2488
2511
  play: "<path d=\"M8 5v14l11-7z\"/>",
2489
2512
  pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
2490
2513
  volumeHigh: "<path d=\"M3 10v4h4l5 5V5L7 10H3zm13.5 2a4.5 4.5 0 0 0-2.5-4v8a4.5 4.5 0 0 0 2.5-4zm-2.5-9v2.06A7 7 0 0 1 14 19v2a9 9 0 0 0 0-18z\"/>",
@@ -2498,20 +2521,20 @@ var Cn = {
2498
2521
  retry: "<path d=\"M17.65 6.35A8 8 0 1 0 19.73 13h-2.08A6 6 0 1 1 12 6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z\"/>"
2499
2522
  };
2500
2523
  function Q(e) {
2501
- return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Cn[e]}</svg>`;
2524
+ return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Tn[e]}</svg>`;
2502
2525
  }
2503
2526
  //#endregion
2504
2527
  //#region src/ui/controls.ts
2505
- var wn = 3e3, Tn = 250, En = /* @__PURE__ */ new Set([
2528
+ var En = 3e3, Dn = 250, On = /* @__PURE__ */ new Set([
2506
2529
  "GONE",
2507
2530
  "NOT_FOUND",
2508
2531
  "INVALID_URN",
2509
2532
  "UNAUTHORIZED"
2510
2533
  ]);
2511
- function Dn(e) {
2512
- return new On(e);
2534
+ function kn(e) {
2535
+ return new An(e);
2513
2536
  }
2514
- var On = class {
2537
+ var An = class {
2515
2538
  root;
2516
2539
  video;
2517
2540
  player;
@@ -2557,7 +2580,7 @@ var On = class {
2557
2580
  scrubbing = !1;
2558
2581
  offFns = [];
2559
2582
  constructor(e) {
2560
- this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? wn, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, Sn(this.doc, e.cspNonce), this.root.classList.add("havik-player"), this.root.hasAttribute("tabindex") || (this.root.tabIndex = 0), this.root.setAttribute("role", "region"), this.root.setAttribute("aria-label", "Video player");
2583
+ this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? En, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, wn(this.doc, e.cspNonce), this.root.classList.add("havik-player"), this.root.hasAttribute("tabindex") || (this.root.tabIndex = 0), this.root.setAttribute("role", "region"), this.root.setAttribute("aria-label", "Video player");
2561
2584
  let t = (e, t, n) => {
2562
2585
  let r = this.doc.createElement(e);
2563
2586
  if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
@@ -2643,7 +2666,7 @@ var On = class {
2643
2666
  let t = this.surfaceWasHidden;
2644
2667
  this.tapTimer = setTimeout(() => {
2645
2668
  this.tapTimer = void 0, this.toggleBar(t);
2646
- }, Tn);
2669
+ }, Dn);
2647
2670
  }
2648
2671
  toggleBar(e) {
2649
2672
  e ? this.poke() : this.hideIfIdle();
@@ -2678,7 +2701,7 @@ var On = class {
2678
2701
  e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML = Q("play"), e.addEventListener("click", () => void this.player.play()), n.append(e);
2679
2702
  } else {
2680
2703
  let r = this.doc.createElement("div");
2681
- if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !En.has(this.lastError.code)) {
2704
+ if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !On.has(this.lastError.code)) {
2682
2705
  let e = this.doc.createElement("button");
2683
2706
  e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${Q("retry")}<span>Retry</span>`, e.addEventListener("click", () => void this.player.retry()), n.append(e);
2684
2707
  }
@@ -2719,7 +2742,7 @@ var On = class {
2719
2742
  let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
2720
2743
  this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
2721
2744
  }
2722
- !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${kn(this.video.currentTime)} / ${kn(this.video.duration)}`);
2745
+ !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${jn(this.video.currentTime)} / ${jn(this.video.duration)}`);
2723
2746
  }
2724
2747
  syncLive() {
2725
2748
  let e = this.player.getStats(), t = e.isLive !== !1;
@@ -2769,17 +2792,17 @@ var On = class {
2769
2792
  renderQualityMenu() {
2770
2793
  let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
2771
2794
  n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
2772
- for (let n of e) this.menu.append(this.menuItem(An(n), t === n.index, () => this.player.setQuality(n.index)));
2795
+ for (let n of e) this.menu.append(this.menuItem(Mn(n), t === n.index, () => this.player.setQuality(n.index)));
2773
2796
  }
2774
2797
  renderAudioMenu() {
2775
2798
  let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
2776
2799
  t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
2777
- for (let t of e) this.menu.append(this.menuItem(jn(t), t.default, () => this.player.setAudioTrack(t.id)));
2800
+ for (let t of e) this.menu.append(this.menuItem(Nn(t), t.default, () => this.player.setAudioTrack(t.id)));
2778
2801
  }
2779
2802
  renderCcMenu() {
2780
2803
  let e = this.player.getTextTracks(), t = this.doc.createElement("div");
2781
2804
  t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
2782
- for (let t of e) this.menu.append(this.menuItem(Mn(t), !1, () => this.player.setTextTrack(t.id)));
2805
+ for (let t of e) this.menu.append(this.menuItem(Pn(t), !1, () => this.player.setTextTrack(t.id)));
2783
2806
  }
2784
2807
  onTracksChanged() {
2785
2808
  this.openMenu && this.renderMenu(this.openMenu);
@@ -2880,41 +2903,41 @@ var On = class {
2880
2903
  this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
2881
2904
  }
2882
2905
  };
2883
- function kn(e) {
2906
+ function jn(e) {
2884
2907
  (!Number.isFinite(e) || e < 0) && (e = 0);
2885
2908
  let t = Math.floor(e % 60), n = Math.floor(e / 60 % 60), r = Math.floor(e / 3600), i = r > 0 ? String(n).padStart(2, "0") : String(n), a = String(t).padStart(2, "0");
2886
2909
  return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
2887
2910
  }
2888
- function An(e) {
2911
+ function Mn(e) {
2889
2912
  return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
2890
2913
  }
2891
- function jn(e) {
2914
+ function Nn(e) {
2892
2915
  return e.name || e.lang || `Track ${e.id}`;
2893
2916
  }
2894
- function Mn(e) {
2917
+ function Pn(e) {
2895
2918
  return e.name || e.lang || `Track ${e.id}`;
2896
2919
  }
2897
2920
  //#endregion
2898
2921
  //#region src/managed/index.ts
2899
- var Nn = 6e3, Pn = 45e3, Fn = 2e3, In = 3, Ln = 2e3, Rn = 48e4;
2900
- function zn(e) {
2922
+ var Fn = 6e3, In = 45e3, Ln = 2e3, Rn = 3, zn = 2e3, Bn = 48e4, Vn = "keySystemLicenseRequestFailed";
2923
+ function Hn(e) {
2901
2924
  if (e.env !== void 0 && e.baseUrl !== void 0) throw new n("INTERNAL", 0, `createPlayer: pass env OR baseUrl, not both (got env=${JSON.stringify(e.env)} and baseUrl=${JSON.stringify(e.baseUrl)})`);
2902
- if (e.env !== void 0) return Ke(e.env);
2925
+ if (e.env !== void 0) return We(e.env);
2903
2926
  if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
2904
2927
  return e.baseUrl;
2905
2928
  }
2906
- async function Bn(e) {
2929
+ async function Un(e) {
2907
2930
  if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
2908
- let t = zn(e);
2931
+ let t = Hn(e);
2909
2932
  if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
2910
2933
  if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
2911
- let r = new Vn({
2934
+ let r = new Wn({
2912
2935
  ...e,
2913
2936
  baseUrl: t
2914
2937
  });
2915
2938
  return await r.start(), r;
2916
2939
  }
2917
- var Vn = class {
2940
+ var Wn = class {
2918
2941
  opts;
2919
2942
  abort = new AbortController();
2920
2943
  listeners = {};
@@ -2925,6 +2948,9 @@ var Vn = class {
2925
2948
  detachPip;
2926
2949
  statsTimer;
2927
2950
  refreshTimer;
2951
+ refreshInFlight;
2952
+ onRefocus;
2953
+ staleLicenseReloaded = !1;
2928
2954
  _state = "idle";
2929
2955
  _descriptor = null;
2930
2956
  destroyed = !1;
@@ -2958,7 +2984,7 @@ var Vn = class {
2958
2984
  this.opts.muted && (this.opts.video.muted = !0), this.opts.poster && (this.opts.video.poster = this.opts.poster), this.mountControls(), this.attachPipListeners(), this.setState("loading");
2959
2985
  let e = ++this.loadGen, t = this.resolveOptions();
2960
2986
  try {
2961
- let n = await v(t);
2987
+ let n = await y(t);
2962
2988
  if (await this.onResolved(n, e), e === this.loadGen && this._state === "error" && this._lastError) {
2963
2989
  let e = this._lastError;
2964
2990
  throw this.destroy(), e;
@@ -2985,7 +3011,7 @@ var Vn = class {
2985
3011
  r ? this.armWithSse(e, r, t, n) : this.beginArmingByPolling(e);
2986
3012
  }
2987
3013
  beginArmingByPolling(e) {
2988
- y({
3014
+ b({
2989
3015
  ...this.resolveOptions(),
2990
3016
  signal: this.abort.signal,
2991
3017
  waitForLive: this.buildWaitConfig(e)
@@ -3002,7 +3028,7 @@ var Vn = class {
3002
3028
  setTimeout(() => {
3003
3029
  a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
3004
3030
  phase: i ? "unavailable" : "tooEarly",
3005
- retryInMs: Pn,
3031
+ retryInMs: In,
3006
3032
  attempt: 1,
3007
3033
  elapsedMs: 0,
3008
3034
  ...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
@@ -3019,7 +3045,7 @@ var Vn = class {
3019
3045
  }
3020
3046
  }
3021
3047
  }, h = () => {
3022
- a || s || p() || (s = !0, y({
3048
+ a || s || p() || (s = !0, b({
3023
3049
  ...this.resolveOptions(),
3024
3050
  signal: c.signal,
3025
3051
  waitForLive: this.buildWaitConfig(e)
@@ -3027,7 +3053,7 @@ var Vn = class {
3027
3053
  a || p() || c.signal.aborted || (a = !0, this.closeArming(), this.fail(e instanceof n ? e : new n("INTERNAL", 0, String(e))));
3028
3054
  }));
3029
3055
  }, g = () => {
3030
- a || p() || v(this.resolveOptions()).then((e) => m(e)).catch((e) => {
3056
+ a || p() || y(this.resolveOptions()).then((e) => m(e)).catch((e) => {
3031
3057
  if (!(a || p())) {
3032
3058
  if (e instanceof n && o(e.code)) {
3033
3059
  h();
@@ -3041,13 +3067,13 @@ var Vn = class {
3041
3067
  !a && !p() && h();
3042
3068
  }, e);
3043
3069
  };
3044
- _(Nn), this.armingSub = T({
3070
+ _(Fn), this.armingSub = T({
3045
3071
  eventsBaseUrl: t,
3046
3072
  matchUrn: this.opts.matchUrn,
3047
3073
  credential: this.opts.credential,
3048
- onAlive: () => _(Pn),
3074
+ onAlive: () => _(In),
3049
3075
  onState: (e) => {
3050
- a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Fn);
3076
+ a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Ln);
3051
3077
  },
3052
3078
  onError: () => h()
3053
3079
  });
@@ -3070,7 +3096,7 @@ var Vn = class {
3070
3096
  let n = await s(this.opts.credential);
3071
3097
  if (this.destroyed || t !== this.loadGen) return;
3072
3098
  this.setState("loading");
3073
- let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = Ye(this.opts.video, (e) => {
3099
+ let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = Xe(this.opts.video, (e) => {
3074
3100
  this._state !== "ended" && this._state !== "error" && this.setState(e);
3075
3101
  });
3076
3102
  if (await i.load(), this.destroyed || t !== this.loadGen) {
@@ -3092,26 +3118,26 @@ var Vn = class {
3092
3118
  if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
3093
3119
  let i = e.analytics?.sid;
3094
3120
  if (!i) return;
3095
- let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = ln(this.opts.baseUrl, a, e.analytics?.endpoint);
3121
+ let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = dn(this.opts.baseUrl, a, e.analytics?.endpoint);
3096
3122
  if (!o) {
3097
3123
  s && setTimeout(() => {
3098
3124
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
3099
3125
  }, 0);
3100
3126
  return;
3101
3127
  }
3102
- let c = this.opts.video, l = new un({
3128
+ let c = this.opts.video, l = new fn({
3103
3129
  endpoint: o,
3104
3130
  sid: i,
3105
3131
  player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
3106
- sdkVersion: gn,
3107
- environment: mn(c),
3132
+ sdkVersion: vn,
3133
+ environment: gn(c),
3108
3134
  idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
3109
3135
  onIdle: () => this.onAnalyticsIdle(t),
3110
3136
  onBlocked: (e) => setTimeout(() => {
3111
3137
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, e));
3112
3138
  }, 0),
3113
3139
  sample: () => {
3114
- let e = this.engine?.getStats() ?? z, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
3140
+ let e = this.engine?.getStats() ?? Ge, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
3115
3141
  return {
3116
3142
  ...e,
3117
3143
  bufferedMs: Math.round(t * 1e3),
@@ -3125,7 +3151,7 @@ var Vn = class {
3125
3151
  let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
3126
3152
  c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
3127
3153
  c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
3128
- }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), hn().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
3154
+ }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), _n().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
3129
3155
  }
3130
3156
  currentPresentation() {
3131
3157
  let e = this.opts.video;
@@ -3148,13 +3174,14 @@ var Vn = class {
3148
3174
  debug: this.opts.debug,
3149
3175
  deferLoad: r,
3150
3176
  hlsConfig: i,
3151
- emit: (e) => this.onEngineEvent(e)
3177
+ emit: (e) => this.onEngineEvent(e),
3178
+ freshLicenseUrl: () => this.refreshLicense()
3152
3179
  }, o = this.opts.engine ?? "auto";
3153
- if (o === "native") return new K(a);
3154
- if (o === "hls") return new Wt(a);
3155
- if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && W(this.opts.video) && G() || !e.drmEnabled && tt() && W(this.opts.video)) return new K(a);
3156
- if (ft()) return new Wt(a);
3157
- if (W(this.opts.video)) return new K(a);
3180
+ if (o === "native") return new G(a);
3181
+ if (o === "hls") return new Kt(a);
3182
+ if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && U(this.opts.video) && W() || !e.drmEnabled && nt() && U(this.opts.video)) return new G(a);
3183
+ if (pt()) return new Kt(a);
3184
+ if (U(this.opts.video)) return new G(a);
3158
3185
  throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
3159
3186
  }
3160
3187
  onEngineEvent(e) {
@@ -3166,7 +3193,7 @@ var Vn = class {
3166
3193
  this.analyticsSession?.noteFirstBytes();
3167
3194
  break;
3168
3195
  case "drmReady":
3169
- this.analyticsSession?.noteDrmReady();
3196
+ this.analyticsSession?.noteDrmReady(), this.staleLicenseReloaded = !1;
3170
3197
  break;
3171
3198
  case "ready":
3172
3199
  this.analyticsSession?.noteReady(), this.emit("ready"), (this.opts.autoplay !== !1 || this.playRequested) && this.play();
@@ -3186,7 +3213,17 @@ var Vn = class {
3186
3213
  case "ended":
3187
3214
  this.onStreamEnded();
3188
3215
  break;
3189
- case "error": this.analyticsSession?.noteError(e.error.code, e.error.message, e.fatal, e.error.httpStatus ?? 0, Math.round(this.opts.video.currentTime * 1e3), e.detail), e.fatal ? this.fail(e.error) : this.emit("warning", e.error);
3216
+ case "error": {
3217
+ let t = e.fatal && this.isStaleLicenseDenial(e);
3218
+ if (this.analyticsSession?.noteError(e.error.code, e.error.message, e.fatal && !t, e.error.httpStatus ?? 0, Math.round(this.opts.video.currentTime * 1e3), e.detail), t) {
3219
+ this.staleLicenseReloaded = !0;
3220
+ let t = this.loadGen;
3221
+ this.emit("warning", e.error), Promise.resolve().then(() => {
3222
+ if (!(this.destroyed || t !== this.loadGen) && this._state !== "error" && this._state !== "ended") return this.reload().catch(() => void 0);
3223
+ });
3224
+ } else e.fatal ? this.fail(e.error) : this.emit("warning", e.error);
3225
+ break;
3226
+ }
3190
3227
  }
3191
3228
  }
3192
3229
  startLiveState(e) {
@@ -3206,7 +3243,7 @@ var Vn = class {
3206
3243
  r = 0, i = !1;
3207
3244
  },
3208
3245
  onError: () => {
3209
- this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= In && (i = !0, this.emit("warning", new n("NETWORK", 0, `live-state events unreachable at ${t} after ${r} attempts — end-of-stream detection degraded to the HLS staleness watchdog. Check the events host, the api-key's allowed origins, and CSP connect-src.`))));
3246
+ this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= Rn && (i = !0, this.emit("warning", new n("NETWORK", 0, `live-state events unreachable at ${t} after ${r} attempts — end-of-stream detection degraded to the HLS staleness watchdog. Check the events host, the api-key's allowed origins, and CSP connect-src.`))));
3210
3247
  }
3211
3248
  });
3212
3249
  }
@@ -3228,7 +3265,7 @@ var Vn = class {
3228
3265
  scheduleRejoin(e) {
3229
3266
  this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
3230
3267
  this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
3231
- }, Math.random() * Fn));
3268
+ }, Math.random() * Ln));
3232
3269
  }
3233
3270
  cancelRejoin() {
3234
3271
  this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
@@ -3252,7 +3289,7 @@ var Vn = class {
3252
3289
  }
3253
3290
  t.controls = !1;
3254
3291
  let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
3255
- r && r.insertBefore(n, t), n.appendChild(t), Z(n, this.opts.theme), this.container = n, this.controlBar = Dn({
3292
+ r && r.insertBefore(n, t), n.appendChild(t), xn(n, this.opts.theme), this.container = n, this.controlBar = kn({
3256
3293
  root: n,
3257
3294
  video: t,
3258
3295
  player: this,
@@ -3283,7 +3320,7 @@ var Vn = class {
3283
3320
  }
3284
3321
  startStats() {
3285
3322
  this.stopStats();
3286
- let e = Math.max(500, this.opts.statsIntervalMs ?? Ln);
3323
+ let e = Math.max(500, this.opts.statsIntervalMs ?? zn);
3287
3324
  this.statsTimer = setInterval(() => {
3288
3325
  if (!this.engine) return;
3289
3326
  let e = this.engine.getStats();
@@ -3293,27 +3330,44 @@ var Vn = class {
3293
3330
  stopStats() {
3294
3331
  this.statsTimer && clearInterval(this.statsTimer), this.statsTimer = void 0;
3295
3332
  }
3333
+ isStaleLicenseDenial(e) {
3334
+ return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== Vn || e.error.httpStatus !== 403 ? !1 : K(this._descriptor?.drm?.widevine?.licenseUrl);
3335
+ }
3296
3336
  scheduleLicenseRefresh() {
3297
- this.stopRefresh();
3298
- let e = this.opts.licenseRefreshMs ?? Rn;
3299
- e && this._descriptor?.drmEnabled && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
3337
+ if (this.stopRefresh(), !this._descriptor?.drmEnabled) return;
3338
+ typeof document < "u" && this.engine?.name === "hls" && (this.onRefocus = () => {
3339
+ document.visibilityState !== "visible" || this.destroyed || K(this._descriptor?.drm?.widevine?.licenseUrl) && this.refreshLicense();
3340
+ }, document.addEventListener("visibilitychange", this.onRefocus));
3341
+ let e = this.opts.licenseRefreshMs ?? Bn;
3342
+ e && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
3300
3343
  }
3301
3344
  stopRefresh() {
3302
- this.refreshTimer && clearInterval(this.refreshTimer), this.refreshTimer = void 0;
3345
+ this.refreshTimer && clearInterval(this.refreshTimer), this.refreshTimer = void 0, this.onRefocus && typeof document < "u" && (document.removeEventListener("visibilitychange", this.onRefocus), this.onRefocus = void 0);
3303
3346
  }
3304
- async refreshLicense() {
3347
+ refreshLicense() {
3305
3348
  let e = this.engine;
3306
- if (!this.destroyed && e) try {
3307
- let t = await v(this.resolveOptions());
3308
- if (this.destroyed || this.engine !== e) return;
3309
- let n = t.drm?.widevine?.licenseUrl, r = t.drm?.fairplay?.licenseUrl;
3310
- (n || r) && (e.setLicenseUrls({
3311
- widevine: n,
3312
- fairplay: r
3313
- }), this._descriptor = t);
3314
- } catch (e) {
3315
- e instanceof n && !o(e.code) && (this.stopRefresh(), this.destroyed || this.emit("warning", e));
3316
- }
3349
+ if (this.destroyed || !e) return Promise.resolve(void 0);
3350
+ if (this.refreshInFlight?.engine === e) return this.refreshInFlight.promise;
3351
+ let t = (async () => {
3352
+ try {
3353
+ let t = await y(this.resolveOptions());
3354
+ if (this.destroyed || this.engine !== e) return;
3355
+ let n = t.drm?.widevine?.licenseUrl, r = t.drm?.fairplay?.licenseUrl;
3356
+ return (n || r) && (e.setLicenseUrls({
3357
+ widevine: n,
3358
+ fairplay: r
3359
+ }), this._descriptor = t), n;
3360
+ } catch (e) {
3361
+ e instanceof n && !o(e.code) && (this.stopRefresh(), this.destroyed || this.emit("warning", e));
3362
+ return;
3363
+ } finally {
3364
+ this.refreshInFlight?.promise === t && (this.refreshInFlight = void 0);
3365
+ }
3366
+ })();
3367
+ return this.refreshInFlight = {
3368
+ engine: e,
3369
+ promise: t
3370
+ }, t;
3317
3371
  }
3318
3372
  async play() {
3319
3373
  if (this.destroyed) return;
@@ -3340,7 +3394,7 @@ var Vn = class {
3340
3394
  this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
3341
3395
  }
3342
3396
  getStats() {
3343
- return this.engine?.getStats() ?? z;
3397
+ return this.engine?.getStats() ?? Ge;
3344
3398
  }
3345
3399
  getQualityLevels() {
3346
3400
  return this.engine?.getQualityLevels() ?? [];
@@ -3392,7 +3446,7 @@ var Vn = class {
3392
3446
  let e = ++this.loadGen;
3393
3447
  this.teardownPlayback();
3394
3448
  try {
3395
- let t = await y({
3449
+ let t = await b({
3396
3450
  ...this.resolveOptions(),
3397
3451
  waitForLive: this.opts.waitForLive ? this.buildWaitConfig(e) : void 0
3398
3452
  });
@@ -3450,7 +3504,7 @@ function $(e) {
3450
3504
  }
3451
3505
  //#endregion
3452
3506
  //#region src/embed/host.ts
3453
- function Hn(e) {
3507
+ function Gn(e) {
3454
3508
  if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
3455
3509
  if (!e.src) throw Error("mountEmbed: opts.src is required");
3456
3510
  if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
@@ -3509,15 +3563,15 @@ function Hn(e) {
3509
3563
  }
3510
3564
  //#endregion
3511
3565
  //#region src/embed/page.ts
3512
- var Un = /^[A-Za-z0-9:_.-]{1,128}$/;
3513
- function Wn(e) {
3566
+ var Kn = /^[A-Za-z0-9:_.-]{1,128}$/;
3567
+ function qn(e) {
3514
3568
  if (typeof e == "boolean") return e;
3515
3569
  if (typeof e == "object" && e) {
3516
3570
  let t = e.endpoint;
3517
3571
  return typeof t == "string" ? { endpoint: t } : {};
3518
3572
  }
3519
3573
  }
3520
- function Gn() {
3574
+ function Jn() {
3521
3575
  let e = window.HAVIK_EMBED_CONFIG;
3522
3576
  if (e) return {
3523
3577
  baseUrl: e.baseUrl ?? "",
@@ -3527,7 +3581,7 @@ function Gn() {
3527
3581
  autoplay: e.autoplay ?? !0,
3528
3582
  muted: e.muted ?? !0,
3529
3583
  waitForLive: e.waitForLive ?? !0,
3530
- analytics: Wn(e.analytics)
3584
+ analytics: qn(e.analytics)
3531
3585
  };
3532
3586
  let t = new URLSearchParams(location.search);
3533
3587
  return {
@@ -3540,9 +3594,9 @@ function Gn() {
3540
3594
  waitForLive: !0
3541
3595
  };
3542
3596
  }
3543
- async function Kn() {
3544
- let e = Gn();
3545
- Jn();
3597
+ async function Yn() {
3598
+ let e = Jn();
3599
+ Zn();
3546
3600
  let t = document.createElement("video");
3547
3601
  t.setAttribute("playsinline", ""), t.muted = e.muted ?? !0, t.style.cssText = "width:100%;height:100%;object-fit:contain;background:#000;aspect-ratio:auto", document.body.appendChild(t);
3548
3602
  let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
@@ -3597,12 +3651,12 @@ async function Kn() {
3597
3651
  code: e.code,
3598
3652
  message: e.message
3599
3653
  })), e.on("autoplayblocked", () => {
3600
- i({ type: "oddin:autoplayblocked" }), qn(t, e);
3654
+ i({ type: "oddin:autoplayblocked" }), Xn(t, e);
3601
3655
  });
3602
3656
  }, s = async (r) => {
3603
3657
  a?.destroy(), a = null;
3604
3658
  try {
3605
- let n = await Bn({
3659
+ let n = await Un({
3606
3660
  video: t,
3607
3661
  baseUrl: e.baseUrl,
3608
3662
  matchUrn: r,
@@ -3664,7 +3718,7 @@ async function Kn() {
3664
3718
  a?.retry();
3665
3719
  break;
3666
3720
  case "oddin:load":
3667
- typeof e.matchUrn == "string" && Un.test(e.matchUrn) && s(e.matchUrn);
3721
+ typeof e.matchUrn == "string" && Kn.test(e.matchUrn) && s(e.matchUrn);
3668
3722
  break;
3669
3723
  case "oddin:destroy": c();
3670
3724
  }
@@ -3676,18 +3730,18 @@ async function Kn() {
3676
3730
  protocol: 1
3677
3731
  });
3678
3732
  }
3679
- function qn(e, t) {
3733
+ function Xn(e, t) {
3680
3734
  if (document.getElementById("havik-tap")) return;
3681
3735
  let n = document.createElement("button");
3682
3736
  n.id = "havik-tap", n.textContent = "▶ Tap to play", n.style.cssText = "position:fixed;inset:0;width:100%;height:100%;border:0;background:rgba(0,0,0,.55);color:#fff;font:600 18px system-ui,sans-serif;cursor:pointer;z-index:9", n.addEventListener("click", () => {
3683
3737
  n.remove(), t.play();
3684
3738
  }), document.body.appendChild(n);
3685
3739
  }
3686
- function Jn() {
3740
+ function Zn() {
3687
3741
  let e = document.createElement("style");
3688
3742
  e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
3689
3743
  }
3690
3744
  //#endregion
3691
- export { _n as ODDIN_THEME, n as PlaybackError, Z as applyTheme, Ke as baseUrlForEnv, Kn as bootEmbed, Te as clearDeviceId, Bn as createPlayer, E as deriveEventsBaseUrl, He as detectDrmSupport, C as enterVideoFullscreen, w as exitVideoFullscreen, _e as fetchCatalog, ye as fetchTournament, xe as flattenMatches, k as getDeviceId, We as isLowLatencyManifest, $ as isOddinMessage, De as licenseRequestHeaders, Hn as mountEmbed, de as pollToLive, y as resolveStream, T as subscribeLiveState, S as videoFullscreenActive, Ce as watchStatus };
3745
+ export { yn as ODDIN_THEME, n as PlaybackError, xn as applyTheme, We as baseUrlForEnv, Yn as bootEmbed, Te as clearDeviceId, Un as createPlayer, E as deriveEventsBaseUrl, Be as detectDrmSupport, C as enterVideoFullscreen, w as exitVideoFullscreen, _e as fetchCatalog, ye as fetchTournament, xe as flattenMatches, k as getDeviceId, He as isLowLatencyManifest, $ as isOddinMessage, De as licenseRequestHeaders, Gn as mountEmbed, v as pollToLive, b as resolveStream, T as subscribeLiveState, S as videoFullscreenActive, Ce as watchStatus };
3692
3746
 
3693
3747
  //# sourceMappingURL=index.js.map