@oddin-gg/havik-player 2.16.5 → 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,34 +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
- };
1968
- //#endregion
1969
- //#region src/core/drm/signedUrl.ts
1970
- function Gt(e, t = Date.now()) {
1971
- if (!e) return !1;
1972
- let n;
1973
- try {
1974
- n = new URL(e).searchParams.get("exp");
1975
- } catch {
1976
- return !1;
1977
- }
1978
- return !n || !/^\d+$/.test(n) ? !1 : Number(n) * 1e3 <= t;
1979
- }
1980
- //#endregion
1981
- //#region src/core/analytics.ts
1982
- var Kt = 15e3, qt = 6e5, Jt = 3e5, Yt = 100, q = 1, Xt = 1e3, Zt = 3e4, Qt = 1e3, $t = {
1990
+ }, qt = 15e3, Jt = 6e5, Yt = 3e5, Xt = 100, q = 1, Zt = 1e3, Qt = 3e4, $t = 1e3, en = {
1983
1991
  inline: "PRESENTATION_INLINE",
1984
1992
  fullscreen: "PRESENTATION_FULLSCREEN",
1985
1993
  pip: "PRESENTATION_PIP"
1986
- }, en = {
1994
+ }, tn = {
1987
1995
  widevine: "KEY_SYSTEM_WIDEVINE",
1988
1996
  fairplay: "KEY_SYSTEM_FAIRPLAY",
1989
1997
  none: "KEY_SYSTEM_NONE"
1990
1998
  };
1991
- function tn(e, t) {
1999
+ function nn(e, t) {
1992
2000
  return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
1993
2001
  }
1994
- var nn = /* @__PURE__ */ new Set([
2002
+ var rn = /* @__PURE__ */ new Set([
1995
2003
  "INVALID_URN",
1996
2004
  "NOT_FOUND",
1997
2005
  "GONE",
@@ -2011,7 +2019,7 @@ var nn = /* @__PURE__ */ new Set([
2011
2019
  ended: "PLAYER_STATE_ENDED",
2012
2020
  error: "PLAYER_STATE_ERROR"
2013
2021
  };
2014
- function rn(e) {
2022
+ function an(e) {
2015
2023
  try {
2016
2024
  let t = new URL(e), [n, ...r] = t.hostname.split(".");
2017
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);
@@ -2019,8 +2027,8 @@ function rn(e) {
2019
2027
  return;
2020
2028
  }
2021
2029
  }
2022
- var an = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), on = /* @__PURE__ */ new Set(), Y = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), sn = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
2023
- function cn(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) {
2024
2032
  if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
2025
2033
  let t;
2026
2034
  try {
@@ -2029,19 +2037,19 @@ function cn(e) {
2029
2037
  } catch {
2030
2038
  return;
2031
2039
  }
2032
- if (on.has(t) && !Y.has(t)) {
2033
- Y.add(t), g(sn(new URL(t).origin));
2040
+ if (sn.has(t) && !Y.has(t)) {
2041
+ Y.add(t), g(cn(new URL(t).origin));
2034
2042
  for (let e of X) e.noteCspBlocked();
2035
2043
  }
2036
2044
  }
2037
- function ln(e, t) {
2045
+ function un(e, t) {
2038
2046
  return g(t, e), { disabledReason: t };
2039
2047
  }
2040
- function un(e, t, n) {
2041
- if (n) return t && !an(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 };
2042
2050
  if (t) return { endpoint: t };
2043
- if (t !== void 0) return ln("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).");
2044
- let r = rn(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);
2045
2053
  if (r) return { endpoint: r };
2046
2054
  let i;
2047
2055
  try {
@@ -2049,9 +2057,9 @@ function un(e, t, n) {
2049
2057
  } catch {
2050
2058
  i = e;
2051
2059
  }
2052
- return ln(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).`);
2053
2061
  }
2054
- var dn = class {
2062
+ var fn = class {
2055
2063
  opts;
2056
2064
  url;
2057
2065
  cspKey;
@@ -2133,8 +2141,8 @@ var dn = class {
2133
2141
  constructor(e) {
2134
2142
  this.opts = {
2135
2143
  ...e,
2136
- heartbeatMs: e.heartbeatMs ?? Kt,
2137
- idleMs: e.idleMs ?? qt
2144
+ heartbeatMs: e.heartbeatMs ?? qt,
2145
+ idleMs: e.idleMs ?? Jt
2138
2146
  }, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
2139
2147
  try {
2140
2148
  let e = new URL(this.url);
@@ -2151,11 +2159,11 @@ var dn = class {
2151
2159
  sdkVersion: this.opts.sdkVersion,
2152
2160
  ...this.opts.environment
2153
2161
  };
2154
- this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Xt), 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 && on.add(this.cspKey), document.addEventListener("securitypolicyviolation", cn), 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());
2155
2163
  }
2156
2164
  checkSuspension(e) {
2157
2165
  if (this.endedFlag || !this.opts.idleMs) return !1;
2158
- let t = Math.max(this.opts.idleMs, Jt);
2166
+ let t = Math.max(this.opts.idleMs, Yt);
2159
2167
  return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
2160
2168
  }
2161
2169
  syncIdle(e) {
@@ -2178,12 +2186,12 @@ var dn = class {
2178
2186
  let a = {
2179
2187
  fromState: J[e] ?? "PLAYER_STATE_UNSPECIFIED",
2180
2188
  toState: J[t] ?? "PLAYER_STATE_UNSPECIFIED",
2181
- presentation: $t[this.presentation]
2189
+ presentation: en[this.presentation]
2182
2190
  }, o = this.causeOf(e, t, i);
2183
2191
  o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
2184
2192
  }
2185
2193
  seekInduced(e) {
2186
- return this.lastSeekMs >= 0 && e - this.lastSeekMs < Qt;
2194
+ return this.lastSeekMs >= 0 && e - this.lastSeekMs < $t;
2187
2195
  }
2188
2196
  causeOf(e, t, n) {
2189
2197
  if (t === "error") return "TRANSITION_CAUSE_ERROR";
@@ -2257,7 +2265,7 @@ var dn = class {
2257
2265
  let r = n ?? "";
2258
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";
2259
2267
  if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
2260
- if (nn.has(e)) return "ERROR_STAGE_RESOLVE";
2268
+ if (rn.has(e)) return "ERROR_STAGE_RESOLVE";
2261
2269
  let i = t ?? "";
2262
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";
2263
2271
  }
@@ -2304,14 +2312,14 @@ var dn = class {
2304
2312
  if (this.lastRequestCount = g, _ > 0) {
2305
2313
  o.requestCountDelta = _;
2306
2314
  let e = t.requestTimesMs ?? [], n = e.slice(Math.max(0, e.length - _)).sort((e, t) => e - t);
2307
- n.length > 0 && (o.requestTimeP50Ms = tn(n, 50), o.requestTimeP95Ms = tn(n, 95));
2315
+ n.length > 0 && (o.requestTimeP50Ms = nn(n, 50), o.requestTimeP95Ms = nn(n, 95));
2308
2316
  }
2309
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();
2310
2318
  }
2311
2319
  maybeEmitMediaInfo(e) {
2312
2320
  if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
2313
2321
  let t = {};
2314
- e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = en[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);
2315
2323
  let n = JSON.stringify(t);
2316
2324
  n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
2317
2325
  }
@@ -2331,7 +2339,7 @@ var dn = class {
2331
2339
  let c = r?.positionMs ?? 0;
2332
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));
2333
2341
  let l = e !== "END_REASON_ENDED";
2334
- l && this.lastStallMs > 0 && n - this.lastStallMs <= Zt && (i.abandonAfterStallMs = Math.max(q, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= Zt && (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);
2335
2343
  let u = r?.decodedFrames ?? this.lastDecoded;
2336
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");
2337
2345
  }
@@ -2351,13 +2359,13 @@ var dn = class {
2351
2359
  };
2352
2360
  }
2353
2361
  noteCspBlocked() {
2354
- this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(sn(new URL(this.url).origin)));
2362
+ this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(cn(new URL(this.url).origin)));
2355
2363
  }
2356
2364
  cspBlocked() {
2357
2365
  return !!this.cspKey && Y.has(this.cspKey);
2358
2366
  }
2359
2367
  enqueue(e) {
2360
- if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > Yt;) {
2368
+ if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > Xt;) {
2361
2369
  let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
2362
2370
  this.pending.splice(e >= 0 ? e : 0, 1);
2363
2371
  }
@@ -2384,7 +2392,7 @@ var dn = class {
2384
2392
  };
2385
2393
  //#endregion
2386
2394
  //#region src/core/environment.ts
2387
- function fn() {
2395
+ function pn() {
2388
2396
  if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
2389
2397
  let e;
2390
2398
  try {
@@ -2409,14 +2417,14 @@ function fn() {
2409
2417
  integration: "INTEGRATION_KIND_IFRAME"
2410
2418
  };
2411
2419
  }
2412
- function pn() {
2420
+ function mn() {
2413
2421
  if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
2414
2422
  let e = navigator.userAgentData, t = e?.platform ?? "";
2415
2423
  if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
2416
2424
  let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
2417
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";
2418
2426
  }
2419
- function mn() {
2427
+ function hn() {
2420
2428
  let e = typeof navigator < "u" ? navigator.connection : void 0;
2421
2429
  if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
2422
2430
  let t = {
@@ -2435,17 +2443,17 @@ function mn() {
2435
2443
  }
2436
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;
2437
2445
  }
2438
- function hn(e) {
2439
- let t = fn(), n = {
2440
- deviceClass: pn(),
2446
+ function gn(e) {
2447
+ let t = pn(), n = {
2448
+ deviceClass: mn(),
2441
2449
  integration: t.integration,
2442
- ...mn()
2450
+ ...hn()
2443
2451
  };
2444
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);
2445
2453
  let r = e.getBoundingClientRect?.();
2446
2454
  return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
2447
2455
  }
2448
- async function gn() {
2456
+ async function _n() {
2449
2457
  let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
2450
2458
  if (!e?.getHighEntropyValues) return {};
2451
2459
  try {
@@ -2457,7 +2465,7 @@ async function gn() {
2457
2465
  }
2458
2466
  //#endregion
2459
2467
  //#region src/core/version.ts
2460
- var _n = "2.16.5", vn = {
2468
+ var vn = "2.16.6", yn = {
2461
2469
  accent: "#E1B600",
2462
2470
  accentText: "#1B1C23",
2463
2471
  background: "#0e0f13",
@@ -2468,7 +2476,7 @@ var _n = "2.16.5", vn = {
2468
2476
  border: "rgba(255, 255, 255, 0.1)",
2469
2477
  radius: "8px",
2470
2478
  fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
2471
- }, yn = {
2479
+ }, bn = {
2472
2480
  accent: "--havik-accent",
2473
2481
  accentText: "--havik-accent-text",
2474
2482
  background: "--havik-bg",
@@ -2480,26 +2488,26 @@ var _n = "2.16.5", vn = {
2480
2488
  radius: "--havik-radius",
2481
2489
  fontFamily: "--havik-font"
2482
2490
  };
2483
- function Z(e, t) {
2491
+ function xn(e, t) {
2484
2492
  let n = {
2485
- ...vn,
2493
+ ...yn,
2486
2494
  ...t
2487
2495
  };
2488
- for (let t of Object.keys(yn)) e.style.setProperty(yn[t], n[t]);
2496
+ for (let t of Object.keys(bn)) e.style.setProperty(bn[t], n[t]);
2489
2497
  n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
2490
2498
  }
2491
2499
  //#endregion
2492
2500
  //#region src/ui/styles.ts
2493
- var bn = "havik-player-styles", xn = "\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", Sn = /* @__PURE__ */ new WeakMap();
2494
- function Cn(e = document, t) {
2495
- let n = e.querySelector(`style#${bn}`);
2496
- if (n && (!t || Sn.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;
2497
2505
  let r = e.createElement("style");
2498
- r.id = bn, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = xn, Sn.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);
2499
2507
  }
2500
2508
  //#endregion
2501
2509
  //#region src/ui/icons.ts
2502
- var wn = {
2510
+ var Tn = {
2503
2511
  play: "<path d=\"M8 5v14l11-7z\"/>",
2504
2512
  pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
2505
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\"/>",
@@ -2513,20 +2521,20 @@ var wn = {
2513
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\"/>"
2514
2522
  };
2515
2523
  function Q(e) {
2516
- return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${wn[e]}</svg>`;
2524
+ return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Tn[e]}</svg>`;
2517
2525
  }
2518
2526
  //#endregion
2519
2527
  //#region src/ui/controls.ts
2520
- var Tn = 3e3, En = 250, Dn = /* @__PURE__ */ new Set([
2528
+ var En = 3e3, Dn = 250, On = /* @__PURE__ */ new Set([
2521
2529
  "GONE",
2522
2530
  "NOT_FOUND",
2523
2531
  "INVALID_URN",
2524
2532
  "UNAUTHORIZED"
2525
2533
  ]);
2526
- function On(e) {
2527
- return new kn(e);
2534
+ function kn(e) {
2535
+ return new An(e);
2528
2536
  }
2529
- var kn = class {
2537
+ var An = class {
2530
2538
  root;
2531
2539
  video;
2532
2540
  player;
@@ -2572,7 +2580,7 @@ var kn = class {
2572
2580
  scrubbing = !1;
2573
2581
  offFns = [];
2574
2582
  constructor(e) {
2575
- this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Tn, 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, Cn(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");
2576
2584
  let t = (e, t, n) => {
2577
2585
  let r = this.doc.createElement(e);
2578
2586
  if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
@@ -2658,7 +2666,7 @@ var kn = class {
2658
2666
  let t = this.surfaceWasHidden;
2659
2667
  this.tapTimer = setTimeout(() => {
2660
2668
  this.tapTimer = void 0, this.toggleBar(t);
2661
- }, En);
2669
+ }, Dn);
2662
2670
  }
2663
2671
  toggleBar(e) {
2664
2672
  e ? this.poke() : this.hideIfIdle();
@@ -2693,7 +2701,7 @@ var kn = class {
2693
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);
2694
2702
  } else {
2695
2703
  let r = this.doc.createElement("div");
2696
- if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !Dn.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)) {
2697
2705
  let e = this.doc.createElement("button");
2698
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);
2699
2707
  }
@@ -2734,7 +2742,7 @@ var kn = class {
2734
2742
  let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
2735
2743
  this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
2736
2744
  }
2737
- !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${An(this.video.currentTime)} / ${An(this.video.duration)}`);
2745
+ !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${jn(this.video.currentTime)} / ${jn(this.video.duration)}`);
2738
2746
  }
2739
2747
  syncLive() {
2740
2748
  let e = this.player.getStats(), t = e.isLive !== !1;
@@ -2784,17 +2792,17 @@ var kn = class {
2784
2792
  renderQualityMenu() {
2785
2793
  let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
2786
2794
  n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
2787
- for (let n of e) this.menu.append(this.menuItem(jn(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)));
2788
2796
  }
2789
2797
  renderAudioMenu() {
2790
2798
  let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
2791
2799
  t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
2792
- for (let t of e) this.menu.append(this.menuItem(Mn(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)));
2793
2801
  }
2794
2802
  renderCcMenu() {
2795
2803
  let e = this.player.getTextTracks(), t = this.doc.createElement("div");
2796
2804
  t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
2797
- for (let t of e) this.menu.append(this.menuItem(Nn(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)));
2798
2806
  }
2799
2807
  onTracksChanged() {
2800
2808
  this.openMenu && this.renderMenu(this.openMenu);
@@ -2895,41 +2903,41 @@ var kn = class {
2895
2903
  this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
2896
2904
  }
2897
2905
  };
2898
- function An(e) {
2906
+ function jn(e) {
2899
2907
  (!Number.isFinite(e) || e < 0) && (e = 0);
2900
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");
2901
2909
  return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
2902
2910
  }
2903
- function jn(e) {
2911
+ function Mn(e) {
2904
2912
  return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
2905
2913
  }
2906
- function Mn(e) {
2914
+ function Nn(e) {
2907
2915
  return e.name || e.lang || `Track ${e.id}`;
2908
2916
  }
2909
- function Nn(e) {
2917
+ function Pn(e) {
2910
2918
  return e.name || e.lang || `Track ${e.id}`;
2911
2919
  }
2912
2920
  //#endregion
2913
2921
  //#region src/managed/index.ts
2914
- var Pn = 6e3, Fn = 45e3, In = 2e3, Ln = 3, Rn = 2e3, zn = 48e4, Bn = "keySystemLicenseRequestFailed";
2915
- function Vn(e) {
2922
+ var Fn = 6e3, In = 45e3, Ln = 2e3, Rn = 3, zn = 2e3, Bn = 48e4, Vn = "keySystemLicenseRequestFailed";
2923
+ function Hn(e) {
2916
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)})`);
2917
- if (e.env !== void 0) return Ke(e.env);
2925
+ if (e.env !== void 0) return We(e.env);
2918
2926
  if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
2919
2927
  return e.baseUrl;
2920
2928
  }
2921
- async function Hn(e) {
2929
+ async function Un(e) {
2922
2930
  if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
2923
- let t = Vn(e);
2931
+ let t = Hn(e);
2924
2932
  if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
2925
2933
  if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
2926
- let r = new Un({
2934
+ let r = new Wn({
2927
2935
  ...e,
2928
2936
  baseUrl: t
2929
2937
  });
2930
2938
  return await r.start(), r;
2931
2939
  }
2932
- var Un = class {
2940
+ var Wn = class {
2933
2941
  opts;
2934
2942
  abort = new AbortController();
2935
2943
  listeners = {};
@@ -2940,6 +2948,8 @@ var Un = class {
2940
2948
  detachPip;
2941
2949
  statsTimer;
2942
2950
  refreshTimer;
2951
+ refreshInFlight;
2952
+ onRefocus;
2943
2953
  staleLicenseReloaded = !1;
2944
2954
  _state = "idle";
2945
2955
  _descriptor = null;
@@ -2974,7 +2984,7 @@ var Un = class {
2974
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");
2975
2985
  let e = ++this.loadGen, t = this.resolveOptions();
2976
2986
  try {
2977
- let n = await v(t);
2987
+ let n = await y(t);
2978
2988
  if (await this.onResolved(n, e), e === this.loadGen && this._state === "error" && this._lastError) {
2979
2989
  let e = this._lastError;
2980
2990
  throw this.destroy(), e;
@@ -3001,7 +3011,7 @@ var Un = class {
3001
3011
  r ? this.armWithSse(e, r, t, n) : this.beginArmingByPolling(e);
3002
3012
  }
3003
3013
  beginArmingByPolling(e) {
3004
- y({
3014
+ b({
3005
3015
  ...this.resolveOptions(),
3006
3016
  signal: this.abort.signal,
3007
3017
  waitForLive: this.buildWaitConfig(e)
@@ -3018,7 +3028,7 @@ var Un = class {
3018
3028
  setTimeout(() => {
3019
3029
  a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
3020
3030
  phase: i ? "unavailable" : "tooEarly",
3021
- retryInMs: Fn,
3031
+ retryInMs: In,
3022
3032
  attempt: 1,
3023
3033
  elapsedMs: 0,
3024
3034
  ...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
@@ -3035,7 +3045,7 @@ var Un = class {
3035
3045
  }
3036
3046
  }
3037
3047
  }, h = () => {
3038
- a || s || p() || (s = !0, y({
3048
+ a || s || p() || (s = !0, b({
3039
3049
  ...this.resolveOptions(),
3040
3050
  signal: c.signal,
3041
3051
  waitForLive: this.buildWaitConfig(e)
@@ -3043,7 +3053,7 @@ var Un = class {
3043
3053
  a || p() || c.signal.aborted || (a = !0, this.closeArming(), this.fail(e instanceof n ? e : new n("INTERNAL", 0, String(e))));
3044
3054
  }));
3045
3055
  }, g = () => {
3046
- a || p() || v(this.resolveOptions()).then((e) => m(e)).catch((e) => {
3056
+ a || p() || y(this.resolveOptions()).then((e) => m(e)).catch((e) => {
3047
3057
  if (!(a || p())) {
3048
3058
  if (e instanceof n && o(e.code)) {
3049
3059
  h();
@@ -3057,13 +3067,13 @@ var Un = class {
3057
3067
  !a && !p() && h();
3058
3068
  }, e);
3059
3069
  };
3060
- _(Pn), this.armingSub = T({
3070
+ _(Fn), this.armingSub = T({
3061
3071
  eventsBaseUrl: t,
3062
3072
  matchUrn: this.opts.matchUrn,
3063
3073
  credential: this.opts.credential,
3064
- onAlive: () => _(Fn),
3074
+ onAlive: () => _(In),
3065
3075
  onState: (e) => {
3066
- a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * In);
3076
+ a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Ln);
3067
3077
  },
3068
3078
  onError: () => h()
3069
3079
  });
@@ -3086,7 +3096,7 @@ var Un = class {
3086
3096
  let n = await s(this.opts.credential);
3087
3097
  if (this.destroyed || t !== this.loadGen) return;
3088
3098
  this.setState("loading");
3089
- 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) => {
3090
3100
  this._state !== "ended" && this._state !== "error" && this.setState(e);
3091
3101
  });
3092
3102
  if (await i.load(), this.destroyed || t !== this.loadGen) {
@@ -3108,26 +3118,26 @@ var Un = class {
3108
3118
  if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
3109
3119
  let i = e.analytics?.sid;
3110
3120
  if (!i) return;
3111
- let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = un(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);
3112
3122
  if (!o) {
3113
3123
  s && setTimeout(() => {
3114
3124
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
3115
3125
  }, 0);
3116
3126
  return;
3117
3127
  }
3118
- let c = this.opts.video, l = new dn({
3128
+ let c = this.opts.video, l = new fn({
3119
3129
  endpoint: o,
3120
3130
  sid: i,
3121
3131
  player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
3122
- sdkVersion: _n,
3123
- environment: hn(c),
3132
+ sdkVersion: vn,
3133
+ environment: gn(c),
3124
3134
  idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
3125
3135
  onIdle: () => this.onAnalyticsIdle(t),
3126
3136
  onBlocked: (e) => setTimeout(() => {
3127
3137
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, e));
3128
3138
  }, 0),
3129
3139
  sample: () => {
3130
- 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;
3131
3141
  return {
3132
3142
  ...e,
3133
3143
  bufferedMs: Math.round(t * 1e3),
@@ -3141,7 +3151,7 @@ var Un = class {
3141
3151
  let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
3142
3152
  c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
3143
3153
  c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
3144
- }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), gn().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");
3145
3155
  }
3146
3156
  currentPresentation() {
3147
3157
  let e = this.opts.video;
@@ -3164,13 +3174,14 @@ var Un = class {
3164
3174
  debug: this.opts.debug,
3165
3175
  deferLoad: r,
3166
3176
  hlsConfig: i,
3167
- emit: (e) => this.onEngineEvent(e)
3177
+ emit: (e) => this.onEngineEvent(e),
3178
+ freshLicenseUrl: () => this.refreshLicense()
3168
3179
  }, o = this.opts.engine ?? "auto";
3169
- if (o === "native") return new K(a);
3170
- if (o === "hls") return new Wt(a);
3171
- 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);
3172
- if (ft()) return new Wt(a);
3173
- 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);
3174
3185
  throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
3175
3186
  }
3176
3187
  onEngineEvent(e) {
@@ -3232,7 +3243,7 @@ var Un = class {
3232
3243
  r = 0, i = !1;
3233
3244
  },
3234
3245
  onError: () => {
3235
- this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= Ln && (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.`))));
3236
3247
  }
3237
3248
  });
3238
3249
  }
@@ -3254,7 +3265,7 @@ var Un = class {
3254
3265
  scheduleRejoin(e) {
3255
3266
  this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
3256
3267
  this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
3257
- }, Math.random() * In));
3268
+ }, Math.random() * Ln));
3258
3269
  }
3259
3270
  cancelRejoin() {
3260
3271
  this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
@@ -3278,7 +3289,7 @@ var Un = class {
3278
3289
  }
3279
3290
  t.controls = !1;
3280
3291
  let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
3281
- r && r.insertBefore(n, t), n.appendChild(t), Z(n, this.opts.theme), this.container = n, this.controlBar = On({
3292
+ r && r.insertBefore(n, t), n.appendChild(t), xn(n, this.opts.theme), this.container = n, this.controlBar = kn({
3282
3293
  root: n,
3283
3294
  video: t,
3284
3295
  player: this,
@@ -3309,7 +3320,7 @@ var Un = class {
3309
3320
  }
3310
3321
  startStats() {
3311
3322
  this.stopStats();
3312
- let e = Math.max(500, this.opts.statsIntervalMs ?? Rn);
3323
+ let e = Math.max(500, this.opts.statsIntervalMs ?? zn);
3313
3324
  this.statsTimer = setInterval(() => {
3314
3325
  if (!this.engine) return;
3315
3326
  let e = this.engine.getStats();
@@ -3320,29 +3331,43 @@ var Un = class {
3320
3331
  this.statsTimer && clearInterval(this.statsTimer), this.statsTimer = void 0;
3321
3332
  }
3322
3333
  isStaleLicenseDenial(e) {
3323
- return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== Bn || e.error.httpStatus !== 403 ? !1 : Gt(this._descriptor?.drm?.widevine?.licenseUrl);
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);
3324
3335
  }
3325
3336
  scheduleLicenseRefresh() {
3326
- this.stopRefresh();
3327
- let e = this.opts.licenseRefreshMs ?? zn;
3328
- 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));
3329
3343
  }
3330
3344
  stopRefresh() {
3331
- 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);
3332
3346
  }
3333
- async refreshLicense() {
3347
+ refreshLicense() {
3334
3348
  let e = this.engine;
3335
- if (!this.destroyed && e) try {
3336
- let t = await v(this.resolveOptions());
3337
- if (this.destroyed || this.engine !== e) return;
3338
- let n = t.drm?.widevine?.licenseUrl, r = t.drm?.fairplay?.licenseUrl;
3339
- (n || r) && (e.setLicenseUrls({
3340
- widevine: n,
3341
- fairplay: r
3342
- }), this._descriptor = t);
3343
- } catch (e) {
3344
- e instanceof n && !o(e.code) && (this.stopRefresh(), this.destroyed || this.emit("warning", e));
3345
- }
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;
3346
3371
  }
3347
3372
  async play() {
3348
3373
  if (this.destroyed) return;
@@ -3369,7 +3394,7 @@ var Un = class {
3369
3394
  this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
3370
3395
  }
3371
3396
  getStats() {
3372
- return this.engine?.getStats() ?? z;
3397
+ return this.engine?.getStats() ?? Ge;
3373
3398
  }
3374
3399
  getQualityLevels() {
3375
3400
  return this.engine?.getQualityLevels() ?? [];
@@ -3421,7 +3446,7 @@ var Un = class {
3421
3446
  let e = ++this.loadGen;
3422
3447
  this.teardownPlayback();
3423
3448
  try {
3424
- let t = await y({
3449
+ let t = await b({
3425
3450
  ...this.resolveOptions(),
3426
3451
  waitForLive: this.opts.waitForLive ? this.buildWaitConfig(e) : void 0
3427
3452
  });
@@ -3479,7 +3504,7 @@ function $(e) {
3479
3504
  }
3480
3505
  //#endregion
3481
3506
  //#region src/embed/host.ts
3482
- function Wn(e) {
3507
+ function Gn(e) {
3483
3508
  if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
3484
3509
  if (!e.src) throw Error("mountEmbed: opts.src is required");
3485
3510
  if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
@@ -3538,15 +3563,15 @@ function Wn(e) {
3538
3563
  }
3539
3564
  //#endregion
3540
3565
  //#region src/embed/page.ts
3541
- var Gn = /^[A-Za-z0-9:_.-]{1,128}$/;
3542
- function Kn(e) {
3566
+ var Kn = /^[A-Za-z0-9:_.-]{1,128}$/;
3567
+ function qn(e) {
3543
3568
  if (typeof e == "boolean") return e;
3544
3569
  if (typeof e == "object" && e) {
3545
3570
  let t = e.endpoint;
3546
3571
  return typeof t == "string" ? { endpoint: t } : {};
3547
3572
  }
3548
3573
  }
3549
- function qn() {
3574
+ function Jn() {
3550
3575
  let e = window.HAVIK_EMBED_CONFIG;
3551
3576
  if (e) return {
3552
3577
  baseUrl: e.baseUrl ?? "",
@@ -3556,7 +3581,7 @@ function qn() {
3556
3581
  autoplay: e.autoplay ?? !0,
3557
3582
  muted: e.muted ?? !0,
3558
3583
  waitForLive: e.waitForLive ?? !0,
3559
- analytics: Kn(e.analytics)
3584
+ analytics: qn(e.analytics)
3560
3585
  };
3561
3586
  let t = new URLSearchParams(location.search);
3562
3587
  return {
@@ -3569,9 +3594,9 @@ function qn() {
3569
3594
  waitForLive: !0
3570
3595
  };
3571
3596
  }
3572
- async function Jn() {
3573
- let e = qn();
3574
- Xn();
3597
+ async function Yn() {
3598
+ let e = Jn();
3599
+ Zn();
3575
3600
  let t = document.createElement("video");
3576
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);
3577
3602
  let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
@@ -3626,12 +3651,12 @@ async function Jn() {
3626
3651
  code: e.code,
3627
3652
  message: e.message
3628
3653
  })), e.on("autoplayblocked", () => {
3629
- i({ type: "oddin:autoplayblocked" }), Yn(t, e);
3654
+ i({ type: "oddin:autoplayblocked" }), Xn(t, e);
3630
3655
  });
3631
3656
  }, s = async (r) => {
3632
3657
  a?.destroy(), a = null;
3633
3658
  try {
3634
- let n = await Hn({
3659
+ let n = await Un({
3635
3660
  video: t,
3636
3661
  baseUrl: e.baseUrl,
3637
3662
  matchUrn: r,
@@ -3693,7 +3718,7 @@ async function Jn() {
3693
3718
  a?.retry();
3694
3719
  break;
3695
3720
  case "oddin:load":
3696
- typeof e.matchUrn == "string" && Gn.test(e.matchUrn) && s(e.matchUrn);
3721
+ typeof e.matchUrn == "string" && Kn.test(e.matchUrn) && s(e.matchUrn);
3697
3722
  break;
3698
3723
  case "oddin:destroy": c();
3699
3724
  }
@@ -3705,18 +3730,18 @@ async function Jn() {
3705
3730
  protocol: 1
3706
3731
  });
3707
3732
  }
3708
- function Yn(e, t) {
3733
+ function Xn(e, t) {
3709
3734
  if (document.getElementById("havik-tap")) return;
3710
3735
  let n = document.createElement("button");
3711
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", () => {
3712
3737
  n.remove(), t.play();
3713
3738
  }), document.body.appendChild(n);
3714
3739
  }
3715
- function Xn() {
3740
+ function Zn() {
3716
3741
  let e = document.createElement("style");
3717
3742
  e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
3718
3743
  }
3719
3744
  //#endregion
3720
- export { vn as ODDIN_THEME, n as PlaybackError, Z as applyTheme, Ke as baseUrlForEnv, Jn as bootEmbed, Te as clearDeviceId, Hn 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, Wn 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 };
3721
3746
 
3722
3747
  //# sourceMappingURL=index.js.map