@oddin-gg/havik-player 2.23.4 → 2.25.0

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
@@ -309,42 +309,42 @@ function ge(e, t) {
309
309
  }
310
310
  //#endregion
311
311
  //#region src/core/fullscreen.ts
312
- function x(e) {
312
+ function _e(e) {
313
313
  return e.ownerDocument ?? document;
314
314
  }
315
- function _e(e) {
315
+ function ve(e) {
316
316
  return e.fullscreenElement ?? e.webkitFullscreenElement ?? null;
317
317
  }
318
- function S(e, t) {
319
- let n = _e(x(e));
318
+ function ye(e, t) {
319
+ let n = ve(_e(e));
320
320
  return n != null && (n === e || t != null && n === t) || e.webkitDisplayingFullscreen === !0;
321
321
  }
322
- function C(e, t) {
323
- let n = t ?? e, r = x(e);
322
+ function x(e, t) {
323
+ let n = t ?? e, r = _e(e);
324
324
  if (typeof n.requestFullscreen == "function") return r.fullscreenEnabled !== !1;
325
325
  if (typeof n.webkitRequestFullscreen == "function") return r.webkitFullscreenEnabled !== !1;
326
326
  let i = e;
327
327
  return i.webkitSupportsFullscreen === !0 && typeof i.webkitEnterFullscreen == "function" || e.readyState < 1;
328
328
  }
329
- async function w(e, t) {
329
+ async function S(e, t) {
330
330
  let n = t ?? e;
331
331
  if (typeof n.requestFullscreen == "function") return await n.requestFullscreen(), !0;
332
332
  if (typeof n.webkitRequestFullscreen == "function") return n.webkitRequestFullscreen(), !0;
333
333
  let r = e;
334
334
  return r.webkitSupportsFullscreen && typeof r.webkitEnterFullscreen == "function" ? (r.webkitEnterFullscreen(), !0) : !1;
335
335
  }
336
- async function T(e, t) {
336
+ async function C(e, t) {
337
337
  let n = e;
338
338
  if (n.webkitDisplayingFullscreen) {
339
339
  n.webkitExitFullscreen?.();
340
340
  return;
341
341
  }
342
- let r = x(e), i = _e(r);
342
+ let r = _e(e), i = ve(r);
343
343
  i != null && (i === e || t != null && i === t) && (typeof r.exitFullscreen == "function" ? await r.exitFullscreen() : r.webkitExitFullscreen?.());
344
344
  }
345
345
  //#endregion
346
346
  //#region src/core/catalog.ts
347
- async function ve(e) {
347
+ async function be(e) {
348
348
  let t = new URLSearchParams();
349
349
  e.status && t.set("status", Array.isArray(e.status) ? e.status.join(",") : e.status), e.sport && t.set("sport", e.sport);
350
350
  let i = t.toString(), a = f(e.baseUrl, "/v1/catalog" + (i ? `?${i}` : "")), o = new Headers();
@@ -362,12 +362,12 @@ async function ve(e) {
362
362
  };
363
363
  if (!s.ok) throw new n(r(s.status), s.status, `catalog request failed (HTTP ${s.status})`);
364
364
  return {
365
- tournaments: ye(await s.json()),
365
+ tournaments: xe(await s.json()),
366
366
  etag: s.headers.get("etag") ?? void 0,
367
367
  notModified: !1
368
368
  };
369
369
  }
370
- function ye(e) {
370
+ function xe(e) {
371
371
  return (e.tournaments ?? []).map((e) => {
372
372
  let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
373
373
  return {
@@ -389,7 +389,7 @@ function ye(e) {
389
389
  };
390
390
  });
391
391
  }
392
- async function be(e) {
392
+ async function Se(e) {
393
393
  let t = f(e.baseUrl, `/v1/tournaments/${encodeURIComponent(e.urn)}`), i = new Headers();
394
394
  e.etag && i.set("If-None-Match", e.etag);
395
395
  let a = await m(t, {
@@ -409,13 +409,13 @@ async function be(e) {
409
409
  };
410
410
  if (!a.ok) throw new n(r(a.status), a.status, `tournament request failed (HTTP ${a.status})`);
411
411
  return {
412
- tournament: xe(await a.json()),
412
+ tournament: Ce(await a.json()),
413
413
  etag: a.headers.get("etag") ?? void 0,
414
414
  notModified: !1,
415
415
  notFound: !1
416
416
  };
417
417
  }
418
- function xe(e) {
418
+ function Ce(e) {
419
419
  let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
420
420
  return {
421
421
  urn: t,
@@ -435,18 +435,18 @@ function xe(e) {
435
435
  }))
436
436
  };
437
437
  }
438
- function Se(e) {
438
+ function we(e) {
439
439
  return e.tournaments.flatMap((e) => e.matches);
440
440
  }
441
441
  //#endregion
442
442
  //#region src/core/poll.ts
443
- var Ce = /* @__PURE__ */ new Set([
443
+ var Te = /* @__PURE__ */ new Set([
444
444
  "NOT_FOUND",
445
445
  "GEO_DENIED",
446
446
  "GONE",
447
447
  "INVALID_URN"
448
448
  ]);
449
- function we(e) {
449
+ function Ee(e) {
450
450
  let t = Math.max(2e3, e.intervalMs ?? 1e4), i = new AbortController(), a, o, s, c = !1, d = () => {
451
451
  c || (a = setTimeout(p, t));
452
452
  }, p = async () => {
@@ -479,7 +479,7 @@ function we(e) {
479
479
  } catch (t) {
480
480
  if (!i.signal.aborted) {
481
481
  let r = t instanceof n ? t : new n("NETWORK", 0, String(t));
482
- Ce.has(r.code) && (c = !0), e.onError?.(r);
482
+ Te.has(r.code) && (c = !0), e.onError?.(r);
483
483
  }
484
484
  } finally {
485
485
  d();
@@ -491,16 +491,16 @@ function we(e) {
491
491
  }
492
492
  //#endregion
493
493
  //#region src/core/events.ts
494
- var Te = 45e3, E = class extends Error {
494
+ var De = 45e3, w = class extends Error {
495
495
  status;
496
496
  terminal;
497
497
  constructor(e) {
498
498
  let t = e === 410;
499
499
  super(t ? `live-state subscribe failed: HTTP ${e} — match is gone, not retrying` : e === 404 ? `live-state subscribe failed: HTTP ${e} — match not in the catalog, retrying slowly` : `live-state subscribe failed: HTTP ${e}`), this.name = "LiveStateHttpError", this.status = e, this.terminal = t;
500
500
  }
501
- }, Ee = 3e5;
502
- function D(e) {
503
- let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = Math.max(t, e.notFoundRetryMs ?? Ee), i = e.idleTimeoutMs ?? Te, a = Number.isFinite(i) && i > 0 ? i : 0, o = new AbortController(), s = !1, l = (e) => new Promise((t) => {
501
+ }, Oe = 3e5;
502
+ function T(e) {
503
+ let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = Math.max(t, e.notFoundRetryMs ?? Oe), i = e.idleTimeoutMs ?? De, a = Number.isFinite(i) && i > 0 ? i : 0, o = new AbortController(), s = !1, l = (e) => new Promise((t) => {
504
504
  if (o.signal.aborted) return t();
505
505
  let n = setTimeout(t, e);
506
506
  o.signal.addEventListener("abort", () => {
@@ -567,7 +567,7 @@ function D(e) {
567
567
  });
568
568
  if (clearTimeout(_), s) return;
569
569
  if (!o.ok || !o.body) {
570
- let t = new E(o.status);
570
+ let t = new w(o.status);
571
571
  h = t.terminal, g = o.status === 404, e.onError?.(t);
572
572
  } else await p(o.body, () => {
573
573
  i = t;
@@ -585,7 +585,7 @@ function D(e) {
585
585
  s || (s = !0, o.abort());
586
586
  } };
587
587
  }
588
- function O(e) {
588
+ function E(e) {
589
589
  try {
590
590
  let t = new URL(e);
591
591
  return t.hostname = `events.${t.hostname}`, t.pathname = "", t.search = "", t.origin;
@@ -595,27 +595,27 @@ function O(e) {
595
595
  }
596
596
  //#endregion
597
597
  //#region src/core/drm/deviceId.ts
598
- var k = "havik.player.deviceId", A;
599
- function j() {
600
- if (A) return A;
598
+ var D = "havik.player.deviceId", O;
599
+ function k() {
600
+ if (O) return O;
601
601
  try {
602
- let e = globalThis.localStorage?.getItem(k);
603
- if (e) return A = e, e;
602
+ let e = globalThis.localStorage?.getItem(D);
603
+ if (e) return O = e, e;
604
604
  } catch {}
605
- let e = Oe();
606
- A = e;
605
+ let e = Ae();
606
+ O = e;
607
607
  try {
608
- globalThis.localStorage?.setItem(k, e);
608
+ globalThis.localStorage?.setItem(D, e);
609
609
  } catch {}
610
610
  return e;
611
611
  }
612
- function De() {
613
- A = void 0;
612
+ function ke() {
613
+ O = void 0;
614
614
  try {
615
- globalThis.localStorage?.removeItem(k);
615
+ globalThis.localStorage?.removeItem(D);
616
616
  } catch {}
617
617
  }
618
- function Oe() {
618
+ function Ae() {
619
619
  let e = globalThis.crypto;
620
620
  if (e && typeof e.randomUUID == "function") return e.randomUUID();
621
621
  let t = /* @__PURE__ */ new Uint8Array(16);
@@ -627,32 +627,32 @@ function Oe() {
627
627
  }
628
628
  //#endregion
629
629
  //#region src/core/drm/headers.ts
630
- function ke(e, t, n = {}) {
630
+ function je(e, t, n = {}) {
631
631
  let r = {
632
632
  "x-api-key": t.apiKey,
633
633
  "X-Match-Urn": e.matchUrn,
634
- "X-Device-Id": n.deviceId ?? j(),
634
+ "X-Device-Id": n.deviceId ?? k(),
635
635
  "Content-Type": "application/octet-stream"
636
636
  };
637
637
  return n.userId && (r["X-User-Id"] = n.userId), r;
638
638
  }
639
639
  //#endregion
640
640
  //#region src/core/bandwidthMemory.ts
641
- var M = "havik.player.bandwidth", Ae = .8, je = 2e7, Me = 3e5;
642
- function Ne() {
641
+ var A = "havik.player.bandwidth", Me = .8, Ne = 2e7, Pe = 3e5;
642
+ function Fe() {
643
643
  return globalThis.navigator?.connection;
644
644
  }
645
- function Pe() {
646
- let e = Ne()?.type;
645
+ function Ie() {
646
+ let e = Fe()?.type;
647
647
  return typeof e == "string" && e !== "" && e !== "unknown" ? e : "any";
648
648
  }
649
- function Fe() {
650
- let e = Ne()?.downlink;
649
+ function Le() {
650
+ let e = Fe()?.downlink;
651
651
  return typeof e == "number" && Number.isFinite(e) && e > 0 ? e * 1e6 : void 0;
652
652
  }
653
- function Ie() {
653
+ function Re() {
654
654
  try {
655
- let e = globalThis.localStorage?.getItem(M);
655
+ let e = globalThis.localStorage?.getItem(A);
656
656
  if (!e) return {};
657
657
  let t = JSON.parse(e);
658
658
  return t && typeof t == "object" && !Array.isArray(t) ? t : {};
@@ -660,36 +660,36 @@ function Ie() {
660
660
  return {};
661
661
  }
662
662
  }
663
- function Le(e = Date.now()) {
664
- let t = Ie()[Pe()];
663
+ function ze(e = Date.now()) {
664
+ let t = Re()[Ie()];
665
665
  if (!t || typeof t.bps != "number" || typeof t.at != "number" || !Number.isFinite(t.bps) || t.bps <= 0) return;
666
666
  let n = e - t.at;
667
667
  if (n < 0 || n > 2592e5) return;
668
- let r = Fe(), i = r === void 0 ? t.bps : Math.min(t.bps, r);
669
- return Math.round(Math.min(je, Math.max(Me, i * Ae)));
668
+ let r = Le(), i = r === void 0 ? t.bps : Math.min(t.bps, r);
669
+ return Math.round(Math.min(Ne, Math.max(Pe, i * Me)));
670
670
  }
671
- function Re(e, t = Date.now()) {
671
+ function Be(e, t = Date.now()) {
672
672
  if (!Number.isFinite(e) || e <= 0) return;
673
- let n = Ie();
674
- n[Pe()] = {
673
+ let n = Re();
674
+ n[Ie()] = {
675
675
  bps: Math.round(e),
676
676
  at: t
677
677
  };
678
678
  try {
679
- globalThis.localStorage?.setItem(M, JSON.stringify(n));
679
+ globalThis.localStorage?.setItem(A, JSON.stringify(n));
680
680
  } catch {}
681
681
  }
682
- function ze() {
682
+ function Ve() {
683
683
  try {
684
- globalThis.localStorage?.removeItem(M);
684
+ globalThis.localStorage?.removeItem(A);
685
685
  } catch {}
686
686
  }
687
687
  //#endregion
688
688
  //#region src/core/drm/cdm.ts
689
- var Be = /* @__PURE__ */ new WeakMap();
690
- function Ve(e, t) {
691
- let n = Be.get(e);
692
- n || (n = /* @__PURE__ */ new Map(), Be.set(e, n));
689
+ var He = /* @__PURE__ */ new WeakMap();
690
+ function Ue(e, t) {
691
+ let n = He.get(e);
692
+ n || (n = /* @__PURE__ */ new Map(), He.set(e, n));
693
693
  let r = n.get(t.keySystem);
694
694
  if (r) return r;
695
695
  let i = t.createMediaKeys().catch((e) => {
@@ -697,22 +697,22 @@ function Ve(e, t) {
697
697
  });
698
698
  return n.set(t.keySystem, i), i;
699
699
  }
700
- function N() {
700
+ function j() {
701
701
  return typeof navigator < "u" && typeof navigator.requestMediaKeySystemAccess == "function";
702
702
  }
703
- var P = ["SW_SECURE_DECODE", "SW_SECURE_CRYPTO"];
704
- function He(e) {
703
+ var M = ["SW_SECURE_DECODE", "SW_SECURE_CRYPTO"];
704
+ function We(e) {
705
705
  return e.startsWith("com.widevine");
706
706
  }
707
- function F(e, t) {
708
- if (!He(e)) return t;
707
+ function N(e, t) {
708
+ if (!We(e)) return t;
709
709
  let n = (e, t) => {
710
710
  let n = e.videoCapabilities;
711
711
  return !n?.length || !n.some((e) => e.robustness) ? !1 : n.every((e) => {
712
- let n = P.indexOf(e.robustness);
713
- return n === -1 || P.indexOf(t) > n;
712
+ let n = M.indexOf(e.robustness);
713
+ return n === -1 || M.indexOf(t) > n;
714
714
  });
715
- }, r = P.flatMap((e) => t.filter((t) => n(t, e)).map((t) => ({
715
+ }, r = M.flatMap((e) => t.filter((t) => n(t, e)).map((t) => ({
716
716
  ...t,
717
717
  videoCapabilities: t.videoCapabilities?.map((t) => ({
718
718
  ...t,
@@ -721,53 +721,53 @@ function F(e, t) {
721
721
  })));
722
722
  return [...t, ...r];
723
723
  }
724
- function Ue(e) {
725
- return (t, n) => N() ? navigator.requestMediaKeySystemAccess(t, F(t, n)).then((t) => ({
724
+ function Ge(e) {
725
+ return (t, n) => j() ? navigator.requestMediaKeySystemAccess(t, N(t, n)).then((t) => ({
726
726
  keySystem: t.keySystem,
727
727
  getConfiguration: () => t.getConfiguration(),
728
- createMediaKeys: () => Ve(e, t)
728
+ createMediaKeys: () => Ue(e, t)
729
729
  })) : Promise.reject(/* @__PURE__ */ Error("navigator.requestMediaKeySystemAccess is unavailable — EME needs a secure context (https, or localhost)"));
730
730
  }
731
- var I = {
731
+ var P = {
732
732
  video: "SW_SECURE_DECODE",
733
733
  audio: "SW_SECURE_CRYPTO",
734
734
  scheme: "cbcs"
735
735
  };
736
- function We(e) {
737
- if (!N()) return;
736
+ function Ke(e) {
737
+ if (!j()) return;
738
738
  let t = (e, t) => ({
739
739
  contentType: e,
740
740
  robustness: t,
741
- encryptionScheme: I.scheme
741
+ encryptionScheme: P.scheme
742
742
  });
743
- Ue(e)("com.widevine.alpha", [{
743
+ Ge(e)("com.widevine.alpha", [{
744
744
  initDataTypes: ["cenc"],
745
745
  distinctiveIdentifier: "optional",
746
746
  persistentState: "optional",
747
747
  sessionTypes: ["temporary"],
748
- audioCapabilities: [t("audio/mp4; codecs=\"mp4a.40.2\"", I.audio)],
749
- videoCapabilities: [t("video/mp4; codecs=\"avc1.42e01e\"", I.video)]
748
+ audioCapabilities: [t("audio/mp4; codecs=\"mp4a.40.2\"", P.audio)],
749
+ videoCapabilities: [t("video/mp4; codecs=\"avc1.42e01e\"", P.video)]
750
750
  }]).then((e) => e.createMediaKeys()).catch(() => {});
751
751
  }
752
- function L(e) {
753
- let t = R(e);
752
+ function F(e) {
753
+ let t = I(e);
754
754
  if (/^avc[13]/.test(t)) return "avc";
755
755
  if (/^(hvc1|hev1)/.test(t)) return "hevc";
756
756
  if (/^(dvh1|dvhe)/.test(t)) return "dv";
757
757
  if (t.startsWith("av01")) return "av1";
758
758
  if (/^vp0?9/.test(t)) return "vp9";
759
759
  }
760
- function R(e) {
760
+ function I(e) {
761
761
  return (e ?? "").trim().toLowerCase();
762
762
  }
763
- var Ge = {
763
+ var qe = {
764
764
  hevc: "hvc1.1.6.L93.90",
765
765
  dv: "dvh1.05.06",
766
766
  av1: "av01.0.05M.08",
767
767
  vp9: "vp09.00.10.08"
768
- }, Ke = /* @__PURE__ */ new Map(), z = /* @__PURE__ */ new Map();
769
- function qe(e) {
770
- let t = R(e), n = Ke.get(t);
768
+ }, Je = /* @__PURE__ */ new Map(), L = /* @__PURE__ */ new Map();
769
+ function Ye(e) {
770
+ let t = I(e), n = Je.get(t);
771
771
  if (n) return n;
772
772
  let r = {
773
773
  initDataTypes: ["cenc"],
@@ -776,32 +776,32 @@ function qe(e) {
776
776
  sessionTypes: ["temporary"],
777
777
  videoCapabilities: [{
778
778
  contentType: `video/mp4; codecs="${e.trim()}"`,
779
- robustness: I.video,
780
- encryptionScheme: I.scheme
779
+ robustness: P.video,
780
+ encryptionScheme: P.scheme
781
781
  }]
782
782
  }, i = (async () => {
783
783
  try {
784
- return await navigator.requestMediaKeySystemAccess("com.widevine.alpha", F("com.widevine.alpha", [r])), !0;
784
+ return await navigator.requestMediaKeySystemAccess("com.widevine.alpha", N("com.widevine.alpha", [r])), !0;
785
785
  } catch {
786
786
  return !1;
787
787
  }
788
- })().then((e) => (z.set(t, e), e));
789
- return Ke.set(t, i), i;
788
+ })().then((e) => (L.set(t, e), e));
789
+ return Je.set(t, i), i;
790
790
  }
791
- function Je() {
792
- if (N()) for (let e of Object.values(Ge)) qe(e);
791
+ function Xe() {
792
+ if (j()) for (let e of Object.values(qe)) Ye(e);
793
793
  }
794
- function Ye(e) {
795
- let t = L(e);
796
- if (t) return t === "avc" ? !0 : z.get(R(e)) ?? z.get(R(Ge[t]));
794
+ function Ze(e) {
795
+ let t = F(e);
796
+ if (t) return t === "avc" ? !0 : L.get(I(e)) ?? L.get(I(qe[t]));
797
797
  }
798
798
  //#endregion
799
799
  //#region src/core/drm/support.ts
800
- var Xe = 5e3, Ze = "video/mp4; codecs=\"avc1.42E01E\"", Qe = "audio/mp4; codecs=\"mp4a.40.2\"", $e = {
800
+ var Qe = 5e3, $e = "video/mp4; codecs=\"avc1.42E01E\"", et = "audio/mp4; codecs=\"mp4a.40.2\"", tt = {
801
801
  widevine: ["com.widevine.alpha"],
802
802
  fairplay: ["com.apple.fps"]
803
803
  };
804
- function et(e) {
804
+ function nt(e) {
805
805
  return e === "fairplay" ? [{
806
806
  initDataTypes: [
807
807
  "sinf",
@@ -809,30 +809,30 @@ function et(e) {
809
809
  "cenc"
810
810
  ],
811
811
  videoCapabilities: [{
812
- contentType: Ze,
812
+ contentType: $e,
813
813
  robustness: "",
814
814
  encryptionScheme: "cbcs"
815
815
  }],
816
816
  audioCapabilities: [{
817
- contentType: Qe,
817
+ contentType: et,
818
818
  robustness: "",
819
819
  encryptionScheme: "cbcs"
820
820
  }]
821
- }] : F("com.widevine.alpha", [{
821
+ }] : N("com.widevine.alpha", [{
822
822
  initDataTypes: ["cenc"],
823
823
  videoCapabilities: [{
824
- contentType: Ze,
825
- robustness: I.video,
826
- encryptionScheme: I.scheme
824
+ contentType: $e,
825
+ robustness: P.video,
826
+ encryptionScheme: P.scheme
827
827
  }],
828
828
  audioCapabilities: [{
829
- contentType: Qe,
830
- robustness: I.audio,
831
- encryptionScheme: I.scheme
829
+ contentType: et,
830
+ robustness: P.audio,
831
+ encryptionScheme: P.scheme
832
832
  }]
833
833
  }]);
834
834
  }
835
- function tt(e, t) {
835
+ function rt(e, t) {
836
836
  return new Promise((n, r) => {
837
837
  let i = setTimeout(() => r(/* @__PURE__ */ Error("probe-timeout")), t);
838
838
  e.then((e) => {
@@ -842,8 +842,8 @@ function tt(e, t) {
842
842
  });
843
843
  });
844
844
  }
845
- async function nt(e = {}) {
846
- let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Xe, r = {};
845
+ async function it(e = {}) {
846
+ let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Qe, r = {};
847
847
  if (typeof window < "u" && window.isSecureContext === !1) return {
848
848
  verdict: "insecure-context",
849
849
  detail: r
@@ -855,7 +855,7 @@ async function nt(e = {}) {
855
855
  };
856
856
  let a = !1, o = !1, s = Date.now() + n, c = () => Math.max(1, s - Date.now());
857
857
  for (let e of t) {
858
- let t = $e[e];
858
+ let t = tt[e];
859
859
  if (!t) {
860
860
  r[e] = "unknown system";
861
861
  continue;
@@ -866,7 +866,7 @@ async function nt(e = {}) {
866
866
  break;
867
867
  }
868
868
  try {
869
- return await tt((await tt(i(n, et(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
869
+ return await rt((await rt(i(n, nt(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
870
870
  verdict: "supported",
871
871
  system: e,
872
872
  detail: r
@@ -890,49 +890,70 @@ async function nt(e = {}) {
890
890
  }
891
891
  //#endregion
892
892
  //#region src/core/manifest.ts
893
- var rt = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
894
- function it(e) {
895
- return rt.test(e);
893
+ var at = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
894
+ function ot(e) {
895
+ return at.test(e);
896
896
  }
897
897
  //#endregion
898
898
  //#region src/core/env.ts
899
- var at = {
899
+ var st = {
900
900
  integration: "https://feed-dev.oddin-video.gg",
901
901
  production: "https://feed.oddin-video.gg"
902
902
  };
903
- function ot(e) {
904
- let t = Object.prototype.hasOwnProperty.call(at, e) ? at[e] : void 0;
903
+ function ct(e) {
904
+ let t = Object.prototype.hasOwnProperty.call(st, e) ? st[e] : void 0;
905
905
  if (!t) throw new n("INTERNAL", 0, `unknown env ${JSON.stringify(e)} — expected 'integration' or 'production'`);
906
906
  return t;
907
907
  }
908
908
  //#endregion
909
+ //#region src/core/connectivity.ts
910
+ function R() {
911
+ return typeof navigator > "u" || navigator.onLine !== !1;
912
+ }
913
+ function lt() {
914
+ let e = /* @__PURE__ */ new Set(), t = (t) => {
915
+ for (let n of Array.from(e)) n(t);
916
+ }, n = () => t(!0), r = () => t(!1), i = typeof window < "u" && typeof window.addEventListener == "function";
917
+ return i && (window.addEventListener("online", n), window.addEventListener("offline", r)), {
918
+ isOnline: R,
919
+ onChange(t) {
920
+ return e.add(t), () => {
921
+ e.delete(t);
922
+ };
923
+ },
924
+ destroy() {
925
+ e.clear(), i && (window.removeEventListener("online", n), window.removeEventListener("offline", r));
926
+ }
927
+ };
928
+ }
929
+ //#endregion
909
930
  //#region src/core/stats.ts
910
- var st = { droppedFrames: 0 };
911
- function ct(e) {
931
+ var ut = { droppedFrames: 0 };
932
+ function dt(e) {
912
933
  try {
913
934
  return new URL(e).host;
914
935
  } catch {
915
936
  return "";
916
937
  }
917
938
  }
918
- var lt = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
919
- function ut(e) {
939
+ var ft = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
940
+ function pt(e) {
920
941
  if (typeof performance > "u" || typeof performance.getEntriesByType != "function") return "";
921
942
  let t = "", n = -1, r = performance.getEntriesByType("resource");
922
- for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || lt.test(i.name)) && i.startTime >= n) {
923
- let e = ct(i.name);
943
+ for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || ft.test(i.name)) && i.startTime >= n) {
944
+ let e = dt(i.name);
924
945
  e && (t = e, n = i.startTime);
925
946
  }
926
947
  return t;
927
948
  }
928
- function B(e) {
949
+ function z(e) {
929
950
  let t = e.getVideoPlaybackQuality?.();
930
951
  return {
931
952
  dropped: t?.droppedVideoFrames ?? 0,
932
953
  totalFrames: t?.totalVideoFrames ?? 0
933
954
  };
934
955
  }
935
- var dt = class {
956
+ var mt = class {
936
957
  video;
937
958
  baseFrames = 0;
938
959
  baseDropped = 0;
@@ -942,7 +963,7 @@ var dt = class {
942
963
  this.video = e;
943
964
  }
944
965
  read() {
945
- let e = B(this.video);
966
+ let e = z(this.video);
946
967
  return e.totalFrames < this.lastFrames && (this.baseFrames += this.lastFrames), e.dropped < this.lastDropped && (this.baseDropped += this.lastDropped), this.lastFrames = e.totalFrames, this.lastDropped = e.dropped, {
947
968
  dropped: this.baseDropped + e.dropped,
948
969
  totalFrames: this.baseFrames + e.totalFrames
@@ -955,7 +976,7 @@ var dt = class {
955
976
  };
956
977
  }
957
978
  };
958
- function ft(e, t) {
979
+ function ht(e, t) {
959
980
  let n = [
960
981
  ["playing", () => t("playing")],
961
982
  ["waiting", () => t("buffering")],
@@ -972,8 +993,8 @@ function ft(e, t) {
972
993
  }
973
994
  //#endregion
974
995
  //#region src/core/engine/native.ts
975
- var pt = 2e3, mt = 3, V = 500, ht = 6e3, gt = .25, _t = 250, vt = .05, yt = 4, bt = 12e3, xt = .25, St = 1e3;
976
- function Ct(e) {
996
+ var gt = 2e3, _t = 3, B = 500, vt = 6e3, yt = .25, bt = 250, xt = .05, St = 4, Ct = 12e3, wt = .25, Tt = 1e3;
997
+ function Et(e) {
977
998
  try {
978
999
  let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
979
1000
  return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
@@ -981,20 +1002,20 @@ function Ct(e) {
981
1002
  return;
982
1003
  }
983
1004
  }
984
- function H(e) {
1005
+ function V(e) {
985
1006
  return !!(e ?? (typeof document < "u" ? document.createElement("video") : void 0))?.canPlayType("application/vnd.apple.mpegurl");
986
1007
  }
987
- function U() {
1008
+ function H() {
988
1009
  if (typeof window > "u") return !1;
989
1010
  let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
990
1011
  return e || t;
991
1012
  }
992
- function wt() {
993
- if (typeof navigator > "u" || !U()) return !1;
1013
+ function Dt() {
1014
+ if (typeof navigator > "u" || !H()) return !1;
994
1015
  let e = navigator.userAgent ?? "";
995
1016
  return /iPhone|iPad|iPod/.test(e) ? !0 : /Macintosh/.test(e) && typeof navigator.maxTouchPoints == "number" && navigator.maxTouchPoints > 1;
996
1017
  }
997
- var W = class {
1018
+ var U = class {
998
1019
  name = "native";
999
1020
  deps;
1000
1021
  onLoaded;
@@ -1024,7 +1045,7 @@ var W = class {
1024
1045
  frameCounter;
1025
1046
  detachFrames = null;
1026
1047
  constructor(e) {
1027
- this.deps = e, this.frameCounter = new dt(e.video), this.loadStarted = e.deferLoad !== !0, this.builtAt = typeof performance < "u" ? performance.now() : 0;
1048
+ this.deps = e, this.frameCounter = new mt(e.video), this.loadStarted = e.deferLoad !== !0, this.builtAt = typeof performance < "u" ? performance.now() : 0;
1028
1049
  }
1029
1050
  async load() {
1030
1051
  this.detachFrames ??= this.frameCounter.attach();
@@ -1043,9 +1064,9 @@ var W = class {
1043
1064
  let i = !this.loadStarted;
1044
1065
  this.onLoaded = i ? void 0 : () => r({ type: "ready" }), this.onError = () => r({
1045
1066
  type: "error",
1046
- error: new n("INTERNAL", 0, "native HLS playback error"),
1067
+ error: R() ? new n("INTERNAL", 0, "native HLS playback error") : new n("NETWORK", 0, "native HLS playback error while offline"),
1047
1068
  fatal: !0
1048
- }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = Et(t.manifestUrl, t.analytics?.sid), e.load();
1069
+ }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = kt(t.manifestUrl, t.analytics?.sid), e.load();
1049
1070
  }
1050
1071
  startLoad() {
1051
1072
  this.loadStarted || (this.loadStarted = !0, this.restorePreload());
@@ -1073,7 +1094,7 @@ var W = class {
1073
1094
  };
1074
1095
  this.onEncrypted = (n) => {
1075
1096
  let a = n;
1076
- a.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = Ct(a.initData), (async () => {
1097
+ a.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = Et(a.initData), (async () => {
1077
1098
  try {
1078
1099
  let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
1079
1100
  initDataTypes: [a.initDataType],
@@ -1173,10 +1194,10 @@ var W = class {
1173
1194
  droppedFrames: t.dropped,
1174
1195
  decodedFrames: t.totalFrames
1175
1196
  };
1176
- if (this.cdnHost ||= ut(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity) {
1197
+ if (this.cdnHost ||= pt(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity) {
1177
1198
  n.isLive = !0;
1178
1199
  let t = this.liveEdgeEstimate(), r = t == null ? NaN : t - e.currentTime;
1179
- Number.isFinite(r) && (n.atLiveEdge = r <= yt, !e.paused && r >= 0 && (n.latencySeconds = r));
1200
+ Number.isFinite(r) && (n.atLiveEdge = r <= St, !e.paused && r >= 0 && (n.latencySeconds = r));
1180
1201
  } else Number.isFinite(e.duration) && e.duration > 0 && (n.isLive = !1);
1181
1202
  return n;
1182
1203
  }
@@ -1188,30 +1209,30 @@ var W = class {
1188
1209
  }
1189
1210
  watchRefocus() {
1190
1211
  this.deps.snapToLiveOnRefocus === !1 || typeof document > "u" || this.onVisibility || (this.onVisibility = () => {
1191
- let e = G();
1212
+ let e = W();
1192
1213
  if (document.visibilityState === "hidden") {
1193
1214
  this.hiddenSince = e, this.cancelRefocus();
1194
1215
  return;
1195
1216
  }
1196
1217
  let t = this.hiddenSince;
1197
- this.hiddenSince = null, t != null && e - t >= pt && this.armRefocus();
1218
+ this.hiddenSince = null, t != null && e - t >= gt && this.armRefocus();
1198
1219
  }, this.onPageShow = (e) => {
1199
1220
  e.persisted && this.armRefocus();
1200
1221
  }, document.addEventListener("visibilitychange", this.onVisibility), typeof window < "u" && window.addEventListener("pageshow", this.onPageShow));
1201
1222
  }
1202
1223
  armRefocus() {
1203
1224
  if (this.cancelRefocus(), Number.isFinite(this.deps.video.duration)) return;
1204
- let e = this.liveEnd(), t = G, n = t(), r = 0, i = () => {
1225
+ let e = this.liveEnd(), t = W, n = t(), r = 0, i = () => {
1205
1226
  if (this.refocusTimer = null, Number.isFinite(this.deps.video.duration)) return;
1206
- r += V;
1207
- let a = this.liveEnd(), o = a != null && (e == null || a >= e + gt), s = Math.max(r, t() - n) >= ht;
1227
+ r += B;
1228
+ let a = this.liveEnd(), o = a != null && (e == null || a >= e + yt), s = Math.max(r, t() - n) >= vt;
1208
1229
  if (o || s && a != null) {
1209
1230
  this.snapToLive();
1210
1231
  return;
1211
1232
  }
1212
- this.refocusTimer = setTimeout(i, V);
1233
+ this.refocusTimer = setTimeout(i, B);
1213
1234
  };
1214
- this.refocusTimer = setTimeout(i, V);
1235
+ this.refocusTimer = setTimeout(i, B);
1215
1236
  }
1216
1237
  cancelRefocus() {
1217
1238
  this.refocusTimer != null && clearTimeout(this.refocusTimer), this.refocusTimer = null;
@@ -1224,24 +1245,24 @@ var W = class {
1224
1245
  }, e.addEventListener("seeking", this.onEdgeReset), e.addEventListener("emptied", this.onEdgeReset), this.edgeTimer = setInterval(() => {
1225
1246
  if (e.duration !== Infinity) return;
1226
1247
  this.checkEndStale();
1227
- let t = Tt(e, e.currentTime);
1228
- t != null && ((this.lastBufferedEnd == null || Math.abs(t - this.lastBufferedEnd) >= vt) && (this.bufferedAdvancedAt = G()), this.lastBufferedEnd = t);
1229
- }, _t);
1248
+ let t = Ot(e, e.currentTime);
1249
+ t != null && ((this.lastBufferedEnd == null || Math.abs(t - this.lastBufferedEnd) >= xt) && (this.bufferedAdvancedAt = W()), this.lastBufferedEnd = t);
1250
+ }, bt);
1230
1251
  }
1231
1252
  checkEndStale() {
1232
1253
  if (this.endedEmitted) return;
1233
- let e = G(), t = this.lastTickAt == null ? 0 : e - this.lastTickAt;
1254
+ let e = W(), t = this.lastTickAt == null ? 0 : e - this.lastTickAt;
1234
1255
  this.lastTickAt = e;
1235
1256
  let n = this.liveEnd();
1236
1257
  if (n == null) return;
1237
- let r = this.lastSeekableEnd == null || Math.abs(n - this.lastSeekableEnd) >= xt;
1258
+ let r = this.lastSeekableEnd == null || Math.abs(n - this.lastSeekableEnd) >= wt;
1238
1259
  this.lastSeekableEnd = n;
1239
1260
  let i = this.deps.video, a = typeof document < "u" && document.visibilityState === "hidden";
1240
- if (r || t > St || a || i.paused) {
1261
+ if (r || t > Tt || a || i.paused) {
1241
1262
  this.edgeStampedAt = e;
1242
1263
  return;
1243
1264
  }
1244
- e - (this.edgeStampedAt ?? e) > bt && (this.endedEmitted = !0, this.deps.emit({
1265
+ e - (this.edgeStampedAt ?? e) > Ct && (this.endedEmitted = !0, this.deps.emit({
1245
1266
  type: "ended",
1246
1267
  reason: "stalled"
1247
1268
  }));
@@ -1255,9 +1276,9 @@ var W = class {
1255
1276
  liveEdgeEstimate() {
1256
1277
  let e = this.deps.video;
1257
1278
  if (e.duration !== Infinity) return null;
1258
- let t = this.liveEnd(), n = Tt(e, e.currentTime) ?? this.lastBufferedEnd;
1279
+ let t = this.liveEnd(), n = Ot(e, e.currentTime) ?? this.lastBufferedEnd;
1259
1280
  if (n != null) {
1260
- let e = this.bufferedAdvancedAt, r = n + (e == null ? 0 : Math.max(0, (G() - e) / 1e3));
1281
+ let e = this.bufferedAdvancedAt, r = n + (e == null ? 0 : Math.max(0, (W() - e) / 1e3));
1261
1282
  (t == null || r > t) && (t = r);
1262
1283
  }
1263
1284
  return t != null && Number.isFinite(t) ? t : null;
@@ -1271,7 +1292,7 @@ var W = class {
1271
1292
  snapToLive() {
1272
1293
  let e = this.deps.video, t = this.liveEnd();
1273
1294
  if (t == null) return;
1274
- let n = e.seekable.start(e.seekable.length - 1), r = Math.min(e.currentTime, t), i = Math.max(n, t - mt, r);
1295
+ let n = e.seekable.start(e.seekable.length - 1), r = Math.min(e.currentTime, t), i = Math.max(n, t - _t, r);
1275
1296
  try {
1276
1297
  e.currentTime = i;
1277
1298
  } catch {}
@@ -1289,10 +1310,10 @@ var W = class {
1289
1310
  } catch {}
1290
1311
  }
1291
1312
  };
1292
- function G() {
1313
+ function W() {
1293
1314
  return typeof performance < "u" ? performance.now() : Date.now();
1294
1315
  }
1295
- function Tt(e, t) {
1316
+ function Ot(e, t) {
1296
1317
  let n = e.buffered;
1297
1318
  if (!n || !Number.isFinite(t)) return null;
1298
1319
  for (let e = 0; e < n.length; e += 1) if (n.start(e) <= t + .1 && n.end(e) > t) {
@@ -1301,12 +1322,12 @@ function Tt(e, t) {
1301
1322
  }
1302
1323
  return null;
1303
1324
  }
1304
- function Et(e, t) {
1325
+ function kt(e, t) {
1305
1326
  return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
1306
1327
  }
1307
1328
  //#endregion
1308
1329
  //#region src/core/drm/signedUrl.ts
1309
- function K(e, t = Date.now()) {
1330
+ function G(e, t = Date.now()) {
1310
1331
  if (!e) return !1;
1311
1332
  let n;
1312
1333
  try {
@@ -1318,13 +1339,13 @@ function K(e, t = Date.now()) {
1318
1339
  }
1319
1340
  //#endregion
1320
1341
  //#region src/core/drm/xhrBody.ts
1321
- var Dt = 4096;
1322
- function Ot(e) {
1342
+ var At = 4096;
1343
+ function jt(e) {
1323
1344
  if (!e || typeof e != "object") return;
1324
1345
  let { response: t } = e;
1325
1346
  if (typeof t == "string") return t;
1326
1347
  let n;
1327
- if (Object.prototype.toString.call(t) === "[object ArrayBuffer]" ? n = new Uint8Array(t) : ArrayBuffer.isView(t) && (n = new Uint8Array(t.buffer, t.byteOffset, t.byteLength)), !(!n || n.byteLength === 0 || n.byteLength > Dt)) try {
1348
+ if (Object.prototype.toString.call(t) === "[object ArrayBuffer]" ? n = new Uint8Array(t) : ArrayBuffer.isView(t) && (n = new Uint8Array(t.buffer, t.byteOffset, t.byteLength)), !(!n || n.byteLength === 0 || n.byteLength > At)) try {
1328
1349
  return new TextDecoder().decode(n);
1329
1350
  } catch {
1330
1351
  return;
@@ -1332,8 +1353,8 @@ function Ot(e) {
1332
1353
  }
1333
1354
  //#endregion
1334
1355
  //#region src/core/engine/prefetch.ts
1335
- var kt = 15e3, At = 5e3, jt = 6;
1336
- function Mt(e) {
1356
+ var Mt = 15e3, Nt = 5e3, Pt = 6, Ft = 4e3, It = 2;
1357
+ function K(e) {
1337
1358
  try {
1338
1359
  let t = new URL(e);
1339
1360
  return t.searchParams.delete("CMCD"), t.toString();
@@ -1341,17 +1362,23 @@ function Mt(e) {
1341
1362
  return e;
1342
1363
  }
1343
1364
  }
1344
- var Nt = class {
1365
+ var Lt = class {
1345
1366
  cmcd;
1346
1367
  entries = /* @__PURE__ */ new Map();
1347
1368
  keyed = /* @__PURE__ */ new Set();
1348
1369
  perTrack = /* @__PURE__ */ new Map();
1370
+ hints = /* @__PURE__ */ new Map();
1349
1371
  stats = {
1350
1372
  started: 0,
1351
1373
  served: 0,
1352
1374
  missed: 0,
1353
1375
  failed: 0,
1354
- expired: 0
1376
+ expired: 0,
1377
+ hintStarted: 0,
1378
+ hintServed: 0,
1379
+ hintFailed: 0,
1380
+ hintExpired: 0,
1381
+ hintDropped: 0
1355
1382
  };
1356
1383
  constructor(e = {}) {
1357
1384
  this.cmcd = e;
@@ -1364,32 +1391,58 @@ var Nt = class {
1364
1391
  }
1365
1392
  prefetch(e, t, n) {
1366
1393
  if (!this.isActive(t)) return;
1367
- let r = Mt(e);
1394
+ let r = K(e);
1368
1395
  if (this.entries.has(r)) return;
1369
1396
  let i = this.perTrack.get(t) ?? 0;
1370
- if (i >= jt) return;
1371
- this.perTrack.set(t, i + 1);
1372
- let a = new AbortController(), o = {
1397
+ i >= Pt || (this.perTrack.set(t, i + 1), this.start(r, this.withCmcd(e, t, n), !1, Mt), this.stats.started += 1);
1398
+ }
1399
+ prefetchHint(e, t) {
1400
+ let n = K(e);
1401
+ if (this.entries.has(n)) return;
1402
+ let r = this.hints.get(t) ?? [];
1403
+ for (; r.length >= It;) {
1404
+ let e = r.shift();
1405
+ e !== void 0 && this.drop(e) && (this.stats.hintDropped += 1);
1406
+ }
1407
+ r.push(n), this.hints.set(t, r), this.start(n, this.withCmcd(e, t, "media"), !0, Ft), this.stats.hintStarted += 1;
1408
+ }
1409
+ dropHints(e) {
1410
+ for (let t of this.hints.get(e) ?? []) this.drop(t) && (this.stats.hintDropped += 1);
1411
+ this.hints.delete(e);
1412
+ }
1413
+ drop(e) {
1414
+ let t = this.entries.get(e);
1415
+ return t ? (this.entries.delete(e), t.abort.abort(), !0) : !1;
1416
+ }
1417
+ start(e, t, n, r) {
1418
+ let i = new AbortController(), a = {
1373
1419
  started: performance.now(),
1374
1420
  first: 0,
1421
+ end: 0,
1422
+ hint: n,
1423
+ headers: Promise.resolve(),
1375
1424
  bytes: Promise.resolve(null),
1376
- abort: a
1377
- };
1378
- o.bytes = fetch(this.withCmcd(e, t, n), {
1425
+ abort: i
1426
+ }, o = () => {};
1427
+ a.headers = new Promise((e) => o = e), a.bytes = fetch(t, {
1379
1428
  credentials: "omit",
1380
1429
  mode: "cors",
1381
- signal: a.signal
1382
- }).then(async (e) => (o.first = performance.now(), e.ok ? e.arrayBuffer() : null)).catch(() => null), this.entries.set(r, o), this.stats.started += 1, setTimeout(() => {
1383
- this.entries.get(r) === o && (this.entries.delete(r), a.abort(), this.stats.expired += 1);
1384
- }, kt);
1430
+ signal: i.signal
1431
+ }).then(async (e) => {
1432
+ if (a.first = performance.now(), o(), !e.ok) return null;
1433
+ let t = await e.arrayBuffer();
1434
+ return a.end = performance.now(), t;
1435
+ }).catch(() => null).finally(o), this.entries.set(e, a), setTimeout(() => {
1436
+ this.entries.get(e) === a && (this.entries.delete(e), i.abort(), n ? this.stats.hintExpired += 1 : this.stats.expired += 1);
1437
+ }, r);
1385
1438
  }
1386
1439
  take(e) {
1387
- let t = Mt(e), n = this.entries.get(t);
1440
+ let t = K(e), n = this.entries.get(t);
1388
1441
  return n && this.entries.delete(t), n;
1389
1442
  }
1390
1443
  destroy() {
1391
1444
  for (let e of this.entries.values()) e.abort.abort();
1392
- this.entries.clear();
1445
+ this.entries.clear(), this.hints.clear();
1393
1446
  }
1394
1447
  withCmcd(e, t, n) {
1395
1448
  let { sessionId: r, contentId: i } = this.cmcd;
@@ -1404,40 +1457,51 @@ var Nt = class {
1404
1457
  }
1405
1458
  }
1406
1459
  };
1407
- function Pt(t) {
1460
+ function Rt(t) {
1408
1461
  let n = e.DefaultConfig?.loader;
1409
1462
  if (typeof n != "function") return;
1410
1463
  class r extends n {
1411
1464
  served = !1;
1412
1465
  cancelled = !1;
1413
- stats = Ft();
1466
+ entry;
1467
+ stats = zt();
1414
1468
  load(e, n, r) {
1415
1469
  let i = e.rangeEnd ? void 0 : t.take(e.url);
1416
1470
  if (!i) {
1417
1471
  super.load(e, n, r);
1418
1472
  return;
1419
1473
  }
1420
- this.served = !0;
1421
- let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || At, s = setTimeout(() => {
1422
- !this.cancelled && this.served && (i.abort.abort(), t.stats.failed += 1, this.served = !1, super.load(e, n, r));
1423
- }, o);
1424
- i.bytes.then((o) => {
1425
- if (clearTimeout(s), this.cancelled || !this.served) return;
1426
- if (!o) {
1427
- t.stats.failed += 1, this.served = !1, super.load(e, n, r);
1474
+ this.served = !0, this.entry = i;
1475
+ let a = performance.now(), o = () => {
1476
+ i.hint ? t.stats.hintFailed += 1 : t.stats.failed += 1;
1477
+ }, s = () => {
1478
+ !this.cancelled && this.served && (i.abort.abort(), o(), this.served = !1, this.entry = void 0, super.load(e, n, r));
1479
+ }, c = n?.loadPolicy, l = c?.maxTimeToFirstByteMs || Nt, u = setTimeout(s, l);
1480
+ i.headers.then(() => {
1481
+ clearTimeout(u);
1482
+ let e = c?.maxLoadTimeMs;
1483
+ e && (u = setTimeout(s, Math.max(0, e - (performance.now() - a))));
1484
+ }), i.bytes.then((s) => {
1485
+ if (clearTimeout(u), this.cancelled || !this.served) return;
1486
+ if (!s) {
1487
+ o(), this.served = !1, super.load(e, n, r);
1428
1488
  return;
1429
1489
  }
1430
- t.stats.served += 1;
1431
1490
  let c = this.stats;
1432
- c.loading.start = a, c.loading.first = Math.max(a, i.first || a), c.loading.end = performance.now(), c.loaded = c.total = o.byteLength, r.onSuccess({
1491
+ if (i.hint) {
1492
+ t.stats.hintServed += 1;
1493
+ let e = performance.now(), n = Math.max(0, (i.end || e) - (i.first || e)), r = Math.max(0, (i.first || e) - a);
1494
+ c.loading.end = e, c.loading.first = e - n, c.loading.start = c.loading.first - r;
1495
+ } else t.stats.served += 1, c.loading.start = a, c.loading.first = Math.max(a, i.first || a), c.loading.end = performance.now();
1496
+ c.loaded = c.total = s.byteLength, this.entry = void 0, r.onSuccess({
1433
1497
  url: e.url,
1434
- data: o
1498
+ data: s
1435
1499
  }, c, e, null);
1436
1500
  });
1437
1501
  }
1438
1502
  abort() {
1439
1503
  if (this.served) {
1440
- this.cancelled = !0, this.stats.aborted = !0;
1504
+ this.cancelled = !0, this.stats.aborted = !0, this.entry?.abort.abort(), this.entry = void 0;
1441
1505
  return;
1442
1506
  }
1443
1507
  super.abort();
@@ -1445,7 +1509,7 @@ function Pt(t) {
1445
1509
  }
1446
1510
  return r;
1447
1511
  }
1448
- function Ft() {
1512
+ function zt() {
1449
1513
  return {
1450
1514
  aborted: !1,
1451
1515
  loaded: 0,
@@ -1469,10 +1533,10 @@ function Ft() {
1469
1533
  }
1470
1534
  };
1471
1535
  }
1472
- function It(e) {
1536
+ function Bt(e) {
1473
1537
  return e === "audio" ? "audio" : "main";
1474
1538
  }
1475
- function Lt(e, t) {
1539
+ function Vt(e, t) {
1476
1540
  let n = [];
1477
1541
  t.initSegment?.url && !t.initSegment.data && n.push({
1478
1542
  url: t.initSegment.url,
@@ -1489,6 +1553,17 @@ function Lt(e, t) {
1489
1553
  });
1490
1554
  return n;
1491
1555
  }
1556
+ function Ht(e) {
1557
+ let t = e, n = t?.preloadHint;
1558
+ if (!n || !t?.url || n.TYPE !== "PART" || n["BYTERANGE-START"] !== void 0 || n["BYTERANGE-LENGTH"] !== void 0) return null;
1559
+ let r = n.URI;
1560
+ if (typeof r != "string" || !r) return null;
1561
+ try {
1562
+ return new URL(r, t.url).toString();
1563
+ } catch {
1564
+ return null;
1565
+ }
1566
+ }
1492
1567
  //#endregion
1493
1568
  //#region src/core/percentile.ts
1494
1569
  function q(e, t) {
@@ -1496,11 +1571,11 @@ function q(e, t) {
1496
1571
  }
1497
1572
  //#endregion
1498
1573
  //#region src/core/engine/hls.ts
1499
- function Rt() {
1574
+ function Ut() {
1500
1575
  return e.isSupported();
1501
1576
  }
1502
- var zt = 1e6, Bt = 20, Vt = 1e4, Ht = 3, Ut = 5, Wt = 3, Gt = 1e4, Kt = 3e4, qt = 12e3, Jt = 3e3, Yt = .02, Xt = 6e3, Zt = .5, Qt = 3, $t = .5, en = 1.1, tn = .25, nn = 5e3, rn = 4e3, an = 2, on = 5, sn = 2, cn = 2, ln = 4, un = 4, dn = 2e3, fn = 3e4, pn = 1, mn = 2;
1503
- function hn(e, t, n) {
1577
+ var Wt = 3, Gt = 1e6, Kt = 20, qt = 1e4, Jt = 3, Yt = 5, Xt = 3, Zt = 1e4, Qt = 3e4, $t = 12e3, en = 3e3, tn = .02, nn = 6e3, rn = .5, an = 3, on = .5, sn = 1.1, cn = .25, ln = 5e3, un = 4e3, dn = 2, fn = 5, pn = 2, mn = 2, hn = 4, gn = 4, _n = 2e3, vn = 3e4, yn = 1, bn = 2;
1578
+ function xn(e, t, n) {
1504
1579
  if (n <= 0 || t < 0 || t >= e.length) return t;
1505
1580
  let r = (t, n) => e[t].width === e[n].width && e[t].height === e[n].height, i = (t) => {
1506
1581
  for (; t + 1 < e.length && r(t + 1, t);) t++;
@@ -1509,11 +1584,11 @@ function hn(e, t, n) {
1509
1584
  for (let t = 0; t < n && a + 1 < e.length; t++) a = i(a + 1);
1510
1585
  return a;
1511
1586
  }
1512
- var gn = .2, _n = 30, vn = 2, yn = 2, bn = 2, xn = 9, Sn = .5, Cn = 64, wn = 1e4, Tn = 8, En = .6, Dn = .4, On = .4, kn = 2, An = 6e4, J = .5, jn = 3.5, Mn = 300;
1513
- function Nn(e) {
1587
+ var Sn = .2, Cn = 30, wn = 2, Tn = 2, En = 2, Dn = 9, On = .5, kn = 64, An = 1e4, jn = 8, Mn = .6, Nn = .4, Pn = .4, Fn = 2, In = 6e4, J = .5, Ln = 3.5, Rn = 300;
1588
+ function zn(e) {
1514
1589
  return (e?.part ?? e?.frag)?.stats;
1515
1590
  }
1516
- function Pn() {
1591
+ function Bn() {
1517
1592
  if (typeof navigator > "u") return 0;
1518
1593
  try {
1519
1594
  let e = navigator.connection?.rtt;
@@ -1522,20 +1597,20 @@ function Pn() {
1522
1597
  return 0;
1523
1598
  }
1524
1599
  }
1525
- function Fn(e) {
1600
+ function Vn(e) {
1526
1601
  if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
1527
1602
  delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
1528
1603
  return;
1529
1604
  }
1530
- e.liveSyncDuration ??= bn;
1531
- let t = Math.max(12, e.liveSyncDuration + xn);
1532
- (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), In(e, e.liveSyncDuration);
1605
+ e.liveSyncDuration ??= En;
1606
+ let t = Math.max(12, e.liveSyncDuration + Dn);
1607
+ (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), Hn(e, e.liveSyncDuration);
1533
1608
  }
1534
- function In(e, t) {
1609
+ function Hn(e, t) {
1535
1610
  let n = (e, t, n) => Math.min(n, Math.max(t, e));
1536
1611
  e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
1537
1612
  }
1538
- var Ln = class {
1613
+ var Un = class {
1539
1614
  name = "hls";
1540
1615
  hls = null;
1541
1616
  deps;
@@ -1565,6 +1640,8 @@ var Ln = class {
1565
1640
  recoveryResetTimer = null;
1566
1641
  networkRetryTimer = null;
1567
1642
  licenseRetryTimer = null;
1643
+ offlineHold = !1;
1644
+ onOnline = null;
1568
1645
  onVisibility = null;
1569
1646
  onSeeking = null;
1570
1647
  onPause = null;
@@ -1629,11 +1706,11 @@ var Ln = class {
1629
1706
  frameCounter;
1630
1707
  detachFrames = null;
1631
1708
  constructor(e) {
1632
- this.deps = e, this.holdBackEnabled = e.adaptiveHoldBack !== !1, this.frameCounter = new dt(e.video), this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
1709
+ this.deps = e, this.holdBackEnabled = e.adaptiveHoldBack !== !1, this.frameCounter = new mt(e.video), this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
1633
1710
  }
1634
1711
  async load() {
1635
1712
  this.detachFrames ??= this.frameCounter.attach();
1636
- let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = H(r) && U(), o = !!e.drm?.widevine?.licenseUrl && !a;
1713
+ let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = V(r) && H(), o = !!e.drm?.widevine?.licenseUrl && !a;
1637
1714
  if (e.drmEnabled && !o) {
1638
1715
  i({
1639
1716
  type: "error",
@@ -1642,14 +1719,21 @@ var Ln = class {
1642
1719
  });
1643
1720
  return;
1644
1721
  }
1645
- e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (We(r), Je()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1722
+ e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ke(r), Xe()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1646
1723
  let e = this.hls;
1647
1724
  if (document.visibilityState !== "visible" || !e) return;
1648
1725
  let t = e.liveSyncPosition;
1649
1726
  if (typeof t != "number") return;
1650
1727
  let n = typeof e.targetLatency == "number" && e.targetLatency > 0 ? e.targetLatency : 3;
1651
1728
  t - r.currentTime > Math.max(n * 3, 8) && (r.currentTime = t);
1652
- }, document.addEventListener("visibilitychange", this.onVisibility)), this.onSeeking = () => {
1729
+ }, document.addEventListener("visibilitychange", this.onVisibility)), typeof window < "u" && (this.onOnline = () => {
1730
+ if (this.offlineHold && (this.offlineHold = !1, this.networkRecoveries = 0, this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null), !this.stopped && this.hls)) {
1731
+ this.lastAdvanceMs = Date.now(), this.lastFragLoadingMs = 0, this.resetStarvationWindow(), this.resetChaseWindow(), this.clearKick();
1732
+ try {
1733
+ this.hls.startLoad();
1734
+ } catch {}
1735
+ }
1736
+ }, window.addEventListener("online", this.onOnline)), this.onSeeking = () => {
1653
1737
  this.clampOverSeek(), this.loadSuspended && (this.resumeLoading(), this.schedulePauseSuspend());
1654
1738
  }, r.addEventListener("seeking", this.onSeeking), this.onTimeUpdate = () => this.updateCatchUpBand(), r.addEventListener("timeupdate", this.onTimeUpdate), this.onPause = () => this.schedulePauseSuspend(), this.onPlay = () => this.resumeLoading(), r.addEventListener("pause", this.onPause), r.addEventListener("play", this.onPlay), this.sizeCapManaged && typeof ResizeObserver < "u" && (this.capObserver = new ResizeObserver(() => this.onMediaResize()), this.capObserver.observe(r), this.watchDprChanges());
1655
1739
  }
@@ -1665,7 +1749,7 @@ var Ln = class {
1665
1749
  }
1666
1750
  this.loadSuspended = !0;
1667
1751
  }
1668
- }, nn));
1752
+ }, ln));
1669
1753
  }
1670
1754
  resumeLoading() {
1671
1755
  if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
@@ -1697,7 +1781,7 @@ var Ln = class {
1697
1781
  let t = e.liveSyncPosition;
1698
1782
  if (typeof t != "number" || !Number.isFinite(t)) return;
1699
1783
  let { video: n } = this.deps;
1700
- n.currentTime <= t + Sn || (n.currentTime = t);
1784
+ n.currentTime <= t + On || (n.currentTime = t);
1701
1785
  }
1702
1786
  reanchorPartTimeline(e, t) {
1703
1787
  let { frag: n, part: r } = t;
@@ -1709,7 +1793,7 @@ var Ln = class {
1709
1793
  let o = n.sn, s = i.fragments.find((e) => e && e.sn === o) ?? (i.fragmentHint?.sn === o ? i.fragmentHint : void 0);
1710
1794
  if (!s) return;
1711
1795
  let c = a.startPTS - s.start;
1712
- if (!(!Number.isFinite(c) || Math.abs(c) < Yt)) {
1796
+ if (!(!Number.isFinite(c) || Math.abs(c) < tn)) {
1713
1797
  for (let e of i.fragments) e && e.setStart(e.start + c);
1714
1798
  i.fragmentHint?.setStart(i.fragmentHint.start + c), this.deps.debug === !0 && console.info(`havik-player: LL-HLS timeline re-anchored by ${c >= 0 ? "+" : ""}${c.toFixed(3)}s at sn ${n.sn} (level ${n.level})`);
1715
1799
  }
@@ -1717,7 +1801,7 @@ var Ln = class {
1717
1801
  startHls() {
1718
1802
  let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps;
1719
1803
  this.clearKick(), this.resetStarvationWindow(), this.resetChaseWindow(), this.resetFrameDropWindow(), this.lastFragLoadingMs = 0, this.lastEndSN = -1, this.lastAdvanceMs = 0;
1720
- let u = n.drmEnabled && !!(n.drm?.widevine?.licenseUrl || n.drm?.fairplay?.licenseUrl), d = H(this.deps.video) && U(), f = {
1804
+ let u = n.drmEnabled && !!(n.drm?.widevine?.licenseUrl || n.drm?.fairplay?.licenseUrl), d = V(this.deps.video) && H(), f = {
1721
1805
  debug: s === !0,
1722
1806
  enableWorker: !o,
1723
1807
  lowLatencyMode: o,
@@ -1732,24 +1816,24 @@ var Ln = class {
1732
1816
  emeEnabled: !0,
1733
1817
  drmSystems: { ...this.licenseUrl ? { "com.widevine.alpha": { licenseUrl: this.licenseUrl } } : {} },
1734
1818
  drmSystemOptions: {
1735
- videoRobustness: I.video,
1736
- audioRobustness: I.audio,
1737
- videoEncryptionScheme: I.scheme,
1738
- audioEncryptionScheme: I.scheme
1819
+ videoRobustness: P.video,
1820
+ audioRobustness: P.audio,
1821
+ videoEncryptionScheme: P.scheme,
1822
+ audioEncryptionScheme: P.scheme
1739
1823
  },
1740
- ...N() ? { requestMediaKeySystemAccessFunc: Ue(t) } : {},
1824
+ ...j() ? { requestMediaKeySystemAccessFunc: Ge(t) } : {},
1741
1825
  licenseXhrSetup: (e, t) => {
1742
1826
  let o = performance.now(), s = () => {
1743
1827
  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", () => {
1744
1828
  this.licenseTimeMs === 0 && (this.licenseTimeMs = Math.max(1, Math.round(performance.now() - o)));
1745
1829
  });
1746
1830
  }, { freshLicenseUrl: c } = this.deps;
1747
- if (!c || !K(this.licenseUrl)) {
1831
+ if (!c || !G(this.licenseUrl)) {
1748
1832
  s();
1749
1833
  return;
1750
1834
  }
1751
1835
  let l = this.hls, u, d = new Promise((e) => {
1752
- u = setTimeout(() => e(void 0), Gt);
1836
+ u = setTimeout(() => e(void 0), Zt);
1753
1837
  });
1754
1838
  return Promise.race([c().catch(() => void 0), d]).finally(() => clearTimeout(u)).then((e) => {
1755
1839
  if (!this.hls || this.hls !== l) throw Error("havik-player: engine torn down during refresh");
@@ -1764,35 +1848,37 @@ var Ln = class {
1764
1848
  } } : {},
1765
1849
  ...c
1766
1850
  };
1767
- if (this.prefetch?.destroy(), this.prefetch = null, u && this.deps.mediaDuringKey !== !1 && !f.fLoader) {
1768
- let e = new Nt({
1851
+ this.prefetch?.destroy(), this.prefetch = null;
1852
+ let p = !1, m = !1, h = u && this.deps.mediaDuringKey !== !1, g = this.deps.preloadHints === !0;
1853
+ if ((h || g) && !f.fLoader) {
1854
+ let e = new Lt({
1769
1855
  sessionId: n.analytics?.sid,
1770
1856
  contentId: n.matchUrn
1771
- }), t = Pt(e);
1772
- t && (this.prefetch = e, f.fLoader = t);
1857
+ }), t = Rt(e);
1858
+ t && (this.prefetch = e, p = h, m = g, f.fLoader = t);
1773
1859
  }
1774
- Fn(f), this.catchUpRate = typeof f.maxLiveSyncPlaybackRate == "number" ? f.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (f.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = f.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = f.autoStartLoad !== !1;
1775
- let p = new e(f);
1776
- if (this.hls = p, this.armHoldBack(p, f), p.on(e.Events.FRAG_PARSED, (e, t) => this.reanchorPartTimeline(p, t)), p.on(e.Events.MANIFEST_PARSED, () => {
1777
- this.mediaRecoveries = 0, this.networkRecoveries = 0, u && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && this.dropLevelsWidevineCannotPlay(p), this.measureLadder(p), this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
1778
- }), p.on(e.Events.FRAG_BUFFERED, (e, t) => {
1860
+ Vn(f), this.catchUpRate = typeof f.maxLiveSyncPlaybackRate == "number" ? f.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (f.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = f.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = f.autoStartLoad !== !1;
1861
+ let _ = new e(f);
1862
+ if (this.hls = _, this.armHoldBack(_, f), _.on(e.Events.FRAG_PARSED, (e, t) => this.reanchorPartTimeline(_, t)), _.on(e.Events.MANIFEST_PARSED, () => {
1863
+ this.mediaRecoveries = 0, this.networkRecoveries = 0, u && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && this.dropLevelsWidevineCannotPlay(_), this.measureLadder(_), this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
1864
+ }), _.on(e.Events.FRAG_BUFFERED, (e, t) => {
1779
1865
  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(() => {
1780
1866
  this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
1781
- }, Kt)));
1782
- }), p.on(e.Events.FRAG_LOADING, (e, t) => {
1867
+ }, Qt)));
1868
+ }), _.on(e.Events.FRAG_LOADING, (e, t) => {
1783
1869
  t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
1784
- }), p.on(e.Events.FRAG_LOADED, (e, t) => {
1870
+ }), _.on(e.Events.FRAG_LOADED, (e, t) => {
1785
1871
  t?.frag?.type === "main" && (this.mainFragsSinceTick += 1, this.bwFragsLoaded += 1, this.maybeRememberBandwidth(!1));
1786
- let n = t?.frag, r = Nn(t), i = r?.loaded;
1872
+ let n = t?.frag, r = zn(t), i = r?.loaded;
1787
1873
  typeof i == "number" && (this.bytesLoaded += i), !this.reportedFirstBytes && typeof i == "number" && i > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
1788
1874
  let a = r?.loading;
1789
- a && a.end > 0 && a.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(a.end - a.start))), this.requestTimesMs.length > Cn && this.requestTimesMs.shift()), this.sampleHoldBack(t);
1875
+ a && a.end > 0 && a.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(a.end - a.start))), this.requestTimesMs.length > kn && this.requestTimesMs.shift()), this.sampleHoldBack(t);
1790
1876
  let o = n?.url;
1791
1877
  if (o) {
1792
- let e = ct(o);
1878
+ let e = dt(o);
1793
1879
  e && (this.cdnHost = e);
1794
1880
  }
1795
- }), p.on(e.Events.LEVEL_LOADED, (e, t) => {
1881
+ }), _.on(e.Events.LEVEL_LOADED, (e, t) => {
1796
1882
  let n = t?.stats?.loaded;
1797
1883
  if (typeof n == "number" && (this.playlistBytesLoaded += n), this.reportedFirstPlaylist || (this.reportedFirstPlaylist = !0, l({ type: "firstPlaylist" })), this.detectedLowLatency) return;
1798
1884
  let r = t.details;
@@ -1800,31 +1886,47 @@ var Ln = class {
1800
1886
  type: "lowLatencyDetected",
1801
1887
  value: !0
1802
1888
  }));
1803
- }), p.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.prefetch) {
1889
+ }), _.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.prefetch && m) {
1890
+ let t = this.prefetch, n = this.deps.video, r = (e, r) => {
1891
+ if (n.paused) return;
1892
+ let i = e;
1893
+ if (!i?.live || !i.partList?.length || typeof i.edge != "number") return;
1894
+ let a = n.buffered, o = a.length ? a.end(a.length - 1) : 0;
1895
+ if (i.edge - o > Wt * (i.partTarget || .5)) return;
1896
+ let s = Ht(e);
1897
+ s && t.prefetchHint(s, r);
1898
+ };
1899
+ _.on(e.Events.LEVEL_LOADED, (e, t) => {
1900
+ t.level === _.loadLevel && r(t.details, "main");
1901
+ }), _.on(e.Events.AUDIO_TRACK_LOADED, (e, t) => {
1902
+ t?.id === _.audioTrack && r(t?.details, "audio");
1903
+ }), _.on(e.Events.LEVEL_SWITCHING, () => t.dropHints("main")), _.on(e.Events.AUDIO_TRACK_SWITCHING, () => t.dropHints("audio"));
1904
+ }
1905
+ if (this.prefetch && p) {
1804
1906
  let t = this.prefetch;
1805
- p.on(e.Events.KEY_LOADING, (e, n) => {
1806
- let r = n?.frag, i = It(r?.type);
1807
- if (r && t.isActive(i)) for (let e of Lt(p, r)) t.prefetch(e.url, i, e.kind);
1808
- }), p.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(It(n?.frag?.type)));
1907
+ _.on(e.Events.KEY_LOADING, (e, n) => {
1908
+ let r = n?.frag, i = Bt(r?.type);
1909
+ if (r && t.isActive(i)) for (let e of Vt(_, r)) t.prefetch(e.url, i, e.kind);
1910
+ }), _.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(Bt(n?.frag?.type)));
1809
1911
  }
1810
- p.on(e.Events.KEY_LOADED, () => {
1912
+ _.on(e.Events.KEY_LOADED, () => {
1811
1913
  u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
1812
1914
  }), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
1813
1915
  this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.adaptHoldBack(), this.checkFrameDrops();
1814
- }, Jt), p.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1916
+ }, en), _.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1815
1917
  this.renditionSwitches += 1;
1816
- let n = this.lastLevelIndex >= 0 ? p.levels[this.lastLevelIndex] : void 0, r = p.levels[t.level];
1918
+ let n = this.lastLevelIndex >= 0 ? _.levels[this.lastLevelIndex] : void 0, r = _.levels[t.level];
1817
1919
  n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, this.armFrameDropGrace(), l({
1818
1920
  type: "qualitychange",
1819
1921
  index: t.level
1820
1922
  });
1821
- }), p.on(e.Events.AUDIO_TRACK_SWITCHED, (e, t) => l({
1923
+ }), _.on(e.Events.AUDIO_TRACK_SWITCHED, (e, t) => l({
1822
1924
  type: "audiotrackchange",
1823
1925
  id: t.id
1824
- })), p.on(e.Events.SUBTITLE_TRACK_SWITCH, (e, t) => l({
1926
+ })), _.on(e.Events.SUBTITLE_TRACK_SWITCH, (e, t) => l({
1825
1927
  type: "texttrackchange",
1826
1928
  id: t.id
1827
- })), p.on(e.Events.ERROR, (e, t) => this.onError(t)), p.loadSource(n.manifestUrl), p.attachMedia(t);
1929
+ })), _.on(e.Events.ERROR, (e, t) => this.onError(t)), _.loadSource(n.manifestUrl), _.attachMedia(t);
1828
1930
  }
1829
1931
  getQualityLevels() {
1830
1932
  return this.hls ? this.hls.levels.map((e, t) => ({
@@ -1862,9 +1964,9 @@ var Ln = class {
1862
1964
  let o = e.config ?? {}, s = typeof self < "u" && self.devicePixelRatio > 0 ? self.devicePixelRatio : 1, c = o.ignoreDevicePixelRatio ? 1 : s;
1863
1965
  c = Math.min(c, o.maxDevicePixelRatio ?? Infinity);
1864
1966
  let l = t.getMaxLevelByMediaSize(e.levels, i * c, a * c), u = this.deps.sizeCapHeadroom;
1865
- if (u == null && s >= mn) return l;
1866
- let d = u ?? pn, f = Number.isNaN(d) ? pn : d === Infinity ? e.levels.length : Math.max(0, Math.floor(d));
1867
- return hn(e.levels, l, f);
1967
+ if (u == null && s >= bn) return l;
1968
+ let d = u ?? yn, f = Number.isNaN(d) ? yn : d === Infinity ? e.levels.length : Math.max(0, Math.floor(d));
1969
+ return xn(e.levels, l, f);
1868
1970
  }
1869
1971
  onMediaResize() {
1870
1972
  if (!this.sizeCapManaged) return;
@@ -1879,7 +1981,7 @@ var Ln = class {
1879
1981
  return;
1880
1982
  }
1881
1983
  this.capTimer && clearTimeout(this.capTimer);
1882
- let t = e > this.sizeCapLevel ? dn : fn;
1984
+ let t = e > this.sizeCapLevel ? _n : vn;
1883
1985
  this.capTimer = setTimeout(() => {
1884
1986
  this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
1885
1987
  }, t);
@@ -1889,9 +1991,9 @@ var Ln = class {
1889
1991
  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;
1890
1992
  }
1891
1993
  dropLevelsWidevineCannotPlay(e) {
1892
- this.removeLevelsWhere(e, (e) => Ye(e) !== !0);
1893
- let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && L(e) !== "avc" && !!L(e)));
1894
- for (let n of t) qe(n).then((t) => {
1994
+ this.removeLevelsWhere(e, (e) => Ze(e) !== !0);
1995
+ let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && F(e) !== "avc" && !!F(e)));
1996
+ for (let n of t) Ye(n).then((t) => {
1895
1997
  t || this.hls !== e || this.removeLevelsWhere(e, (e) => e === n) && (this.measureLadder(e), this.applySizeCap());
1896
1998
  });
1897
1999
  }
@@ -1899,10 +2001,10 @@ var Ln = class {
1899
2001
  let n = e.levels ?? [], r = [], i = /* @__PURE__ */ new Set();
1900
2002
  if (n.forEach((e, n) => {
1901
2003
  let a = e.videoCodec;
1902
- a && L(a) && t(a) && (r.push(n), i.add(a));
2004
+ a && F(a) && t(a) && (r.push(n), i.add(a));
1903
2005
  }), !r.length) return !1;
1904
2006
  let a = [...i].join(", ");
1905
- if (!n.some((e, t) => r.includes(t) ? !1 : !L(e.videoCodec) || Ye(e.videoCodec) === !0)) return console.warn(`havik-player: every rendition is ${a}, which Widevine may not play on this browser; keeping them`), !1;
2007
+ if (!n.some((e, t) => r.includes(t) ? !1 : !F(e.videoCodec) || Ze(e.videoCodec) === !0)) return console.warn(`havik-player: every rendition is ${a}, which Widevine may not play on this browser; keeping them`), !1;
1906
2008
  for (let t = r.length - 1; t >= 0; --t) e.removeLevel(r[t]);
1907
2009
  return console.info(`havik-player: skipped ${r.length} rendition(s) Widevine cannot play on this browser (${a})`), !0;
1908
2010
  }
@@ -2005,12 +2107,12 @@ var Ln = class {
2005
2107
  this.lastAdvanceMs = Date.now();
2006
2108
  return;
2007
2109
  }
2008
- if (this.loadSuspended) {
2110
+ if (this.loadSuspended || this.offlineHold) {
2009
2111
  this.lastAdvanceMs = Date.now();
2010
2112
  return;
2011
2113
  }
2012
2114
  let e = Date.now() - this.lastAdvanceMs;
2013
- !this.chaseSuspended && e > Xt && this.suspendChasing(), e > qt && this.emitEnded("stalled");
2115
+ !this.chaseSuspended && e > nn && this.suspendChasing(), e > $t && this.emitEnded("stalled");
2014
2116
  }
2015
2117
  resetStarvationWindow() {
2016
2118
  this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
@@ -2021,11 +2123,11 @@ var Ln = class {
2021
2123
  checkStarvation() {
2022
2124
  let e = this.hls, { video: t } = this.deps;
2023
2125
  if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended) return;
2024
- if (typeof document < "u" && document.hidden || this.loadSuspended) {
2126
+ if (typeof document < "u" && document.hidden || this.loadSuspended || this.offlineHold) {
2025
2127
  this.resetStarvationWindow();
2026
2128
  return;
2027
2129
  }
2028
- let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < Xt, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > rn, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = B(t), c = o - s, l = c !== this.starvedFrames;
2130
+ let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < nn, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > un, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = z(t), c = o - s, l = c !== this.starvedFrames;
2029
2131
  if (this.starvedFrames = c, !a || l) {
2030
2132
  (t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
2031
2133
  return;
@@ -2034,12 +2136,12 @@ var Ln = class {
2034
2136
  this.resetStarvationWindow();
2035
2137
  return;
2036
2138
  }
2037
- 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 > ln && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= sn && (this.clearKick(), this.starvationRebuilds < cn)) {
2139
+ 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 > hn && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= pn && (this.clearKick(), this.starvationRebuilds < mn)) {
2038
2140
  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");
2039
2141
  return;
2040
2142
  }
2041
- let u = i && this.starvedTicks >= an, d = !i && this.deadTicks >= ln && this.recentMainFrags.reduce((e, t) => e + t, 0) >= un;
2042
- if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= on))) {
2143
+ let u = i && this.starvedTicks >= dn, d = !i && this.deadTicks >= hn && this.recentMainFrags.reduce((e, t) => e + t, 0) >= gn;
2144
+ if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= fn))) {
2043
2145
  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");
2044
2146
  try {
2045
2147
  e.stopLoad(), e.startLoad(-1);
@@ -2050,11 +2152,11 @@ var Ln = class {
2050
2152
  }
2051
2153
  updateCatchUpBand() {
2052
2154
  let e = this.hls;
2053
- if (!e || this.catchUpRate <= 1 || this.chaseSuspended || this.loadSuspended) return;
2155
+ if (!e || this.catchUpRate <= 1 || this.chaseSuspended || this.loadSuspended || this.offlineHold) return;
2054
2156
  let t = e.latency, n = e.targetLatency;
2055
2157
  if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
2056
2158
  let r = t - n;
2057
- !this.catchUpEngaged && r > Zt ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= Zt && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
2159
+ !this.catchUpEngaged && r > rn ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= rn && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
2058
2160
  let i = this.catchUpEngaged ? this.catchUpRate : 1;
2059
2161
  e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
2060
2162
  }
@@ -2067,19 +2169,19 @@ var Ln = class {
2067
2169
  }), n < 0 ? 0 : n;
2068
2170
  }
2069
2171
  armFrameDropGrace() {
2070
- this.fpsGraceTicks > 0 || (this.fpsGraceTicks = yn, this.fpsBadTicks = 0);
2172
+ this.fpsGraceTicks > 0 || (this.fpsGraceTicks = Tn, this.fpsBadTicks = 0);
2071
2173
  }
2072
2174
  resetFrameDropWindow() {
2073
2175
  this.fpsLastFrames = -1, this.fpsLastDropped = -1, this.fpsBadTicks = 0;
2074
2176
  }
2075
2177
  checkFrameDrops() {
2076
2178
  let e = this.hls, { video: t } = this.deps;
2077
- if (!e || !this.fpsCapManaged || this.loadSuspended || t.paused || !e.autoLevelEnabled || typeof document < "u" && document.hidden) {
2179
+ if (!e || !this.fpsCapManaged || this.loadSuspended || this.offlineHold || t.paused || !e.autoLevelEnabled || typeof document < "u" && document.hidden) {
2078
2180
  this.resetFrameDropWindow();
2079
2181
  return;
2080
2182
  }
2081
- let { totalFrames: n, dropped: r } = B(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
2082
- if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < _n || o < 0) {
2183
+ let { totalFrames: n, dropped: r } = z(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
2184
+ if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < Cn || o < 0) {
2083
2185
  this.fpsBadTicks = 0;
2084
2186
  return;
2085
2187
  }
@@ -2087,11 +2189,11 @@ var Ln = class {
2087
2189
  --this.fpsGraceTicks, this.fpsBadTicks = 0;
2088
2190
  return;
2089
2191
  }
2090
- if (o <= gn * a) {
2192
+ if (o <= Sn * a) {
2091
2193
  this.fpsBadTicks = 0;
2092
2194
  return;
2093
2195
  }
2094
- if (this.fpsBadTicks += 1, this.fpsBadTicks < vn) return;
2196
+ if (this.fpsBadTicks += 1, this.fpsBadTicks < wn) return;
2095
2197
  this.fpsBadTicks = 0;
2096
2198
  let s = e.levels, c = s[e.currentLevel];
2097
2199
  if (!c) return;
@@ -2103,27 +2205,27 @@ var Ln = class {
2103
2205
  }
2104
2206
  checkFutileChase() {
2105
2207
  let e = this.hls, { video: t } = this.deps;
2106
- if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended || this.loadSuspended || typeof document < "u" && document.hidden) {
2208
+ if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended || this.loadSuspended || this.offlineHold || typeof document < "u" && document.hidden) {
2107
2209
  this.resetChaseWindow();
2108
2210
  return;
2109
2211
  }
2110
2212
  let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
2111
- if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(en, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
2213
+ if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(sn, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
2112
2214
  this.resetChaseWindow();
2113
2215
  return;
2114
2216
  }
2115
- if (this.chaseLatency < 0 || this.chaseLatency - n >= $t) {
2217
+ if (this.chaseLatency < 0 || this.chaseLatency - n >= on) {
2116
2218
  this.chaseLatency = n, this.chaseTicks = 0;
2117
2219
  return;
2118
2220
  }
2119
- if (this.chaseTicks += 1, this.chaseTicks < Qt) return;
2221
+ if (this.chaseTicks += 1, this.chaseTicks < an) return;
2120
2222
  this.resetChaseWindow();
2121
2223
  let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
2122
2224
  if (!(a > 1)) return;
2123
2225
  let o = e.targetLatency;
2124
2226
  if (typeof o != "number" || !(o > 0)) return;
2125
2227
  let s = Math.min(n, a - 1);
2126
- s < o + tn || (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, this.deps.emit({
2228
+ s < o + cn || (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, this.deps.emit({
2127
2229
  type: "livetargetchange",
2128
2230
  change: {
2129
2231
  targetSeconds: s,
@@ -2140,13 +2242,13 @@ var Ln = class {
2140
2242
  if (!this.holdBackEnabled || this.holdBackPriorChecked || !e || (this.holdBackPriorChecked = !0, this.holdBackApplied > 0 || this.holdBackStepCount > 0)) return;
2141
2243
  let t = e.targetLatency;
2142
2244
  if (this.holdBackBase < 0 && typeof t == "number" && t > 0 && (this.holdBackBase = t), this.holdBackBase < 0) return;
2143
- let n = Pn();
2144
- if (!(n >= Mn)) return;
2245
+ let n = Bn();
2246
+ if (!(n >= Rn)) return;
2145
2247
  let r = typeof t == "number" && t > 0 ? t : this.holdBackBase, i = Math.min(this.holdBackCeiling(e), this.holdBackBase + J);
2146
2248
  i > r && (this.holdBackStepCount = 1, this.moveHoldBack(e, r, i, "connection-rtt", `connection rtt ${n} ms`));
2147
2249
  }
2148
2250
  holdBackCeiling(e) {
2149
- let t = this.deps.adaptiveHoldBackCeiling, n = typeof t == "number" && Number.isFinite(t) ? t : jn, r = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
2251
+ let t = this.deps.adaptiveHoldBackCeiling, n = typeof t == "number" && Number.isFinite(t) ? t : Ln, r = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
2150
2252
  return r > 1 ? Math.min(n, r - 1) : n;
2151
2253
  }
2152
2254
  sampleHoldBack(e) {
@@ -2155,7 +2257,7 @@ var Ln = class {
2155
2257
  if (t !== "main" && t !== "audio") return;
2156
2258
  let n = e.part ? e.part.duration : this.detectedLowLatency ? 0 : e.frag?.duration;
2157
2259
  if (typeof n != "number" || !(n > 0)) return;
2158
- let r = Nn(e)?.loading;
2260
+ let r = zn(e)?.loading;
2159
2261
  if (!r || !(r.start > 0) || !(r.end > 0)) return;
2160
2262
  let i = r.first > r.start ? r.first : r.end, a = Math.max(0, i - r.start) / (n * 1e3);
2161
2263
  this.holdBackSamples.push({
@@ -2166,24 +2268,24 @@ var Ln = class {
2166
2268
  adaptHoldBack() {
2167
2269
  if (!this.holdBackEnabled) return;
2168
2270
  let e = this.hls;
2169
- if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended || this.loadSuspended || typeof document < "u" && document.hidden) {
2271
+ if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended || this.loadSuspended || this.offlineHold || typeof document < "u" && document.hidden) {
2170
2272
  this.holdBackSlowTicks = 0, this.holdBackFastSince = 0, this.holdBackSamples = [];
2171
2273
  return;
2172
2274
  }
2173
- let t = Date.now(), n = t - wn, r = this.holdBackSamples, i = 0;
2275
+ let t = Date.now(), n = t - An, r = this.holdBackSamples, i = 0;
2174
2276
  for (; i < r.length && r[i].t < n;) i += 1;
2175
2277
  i > 0 && r.splice(0, i);
2176
2278
  let a = e.targetLatency;
2177
2279
  if (typeof a != "number" || !(a > 0)) return;
2178
2280
  this.holdBackBase < 0 && (this.holdBackBase = a);
2179
2281
  let o = this.holdBackBase, s = this.holdBackCeiling(e);
2180
- if (r.length < Tn) {
2282
+ if (r.length < jn) {
2181
2283
  this.holdBackSlowTicks = 0;
2182
2284
  return;
2183
2285
  }
2184
2286
  let c = r.map((e) => e.ratio).sort((e, t) => e - t), l = q(c, 95), u = q(c, 50), d = Math.round(l * 1e3);
2185
- if (l >= En && u >= Dn) {
2186
- if (this.holdBackFastSince = 0, this.holdBackSlowTicks += 1, this.holdBackSlowTicks < kn) return;
2287
+ if (l >= Mn && u >= Nn) {
2288
+ if (this.holdBackFastSince = 0, this.holdBackSlowTicks += 1, this.holdBackSlowTicks < Fn) return;
2187
2289
  this.holdBackSlowTicks = 0;
2188
2290
  let t = Math.ceil((s - o) / J), n = Math.ceil((a - o) / J - 1e-9);
2189
2291
  if (n > this.holdBackStepCount && (this.holdBackStepCount = n), this.holdBackStepCount >= t) return;
@@ -2193,7 +2295,7 @@ var Ln = class {
2193
2295
  this.moveHoldBack(e, a, r, "slow-fetches", `part fetches slow (first byte p50 ${Math.round(u * 1e3)} / p95 ${d} ms per 1 s of media)`);
2194
2296
  return;
2195
2297
  }
2196
- if (this.holdBackSlowTicks = 0, l >= On) {
2298
+ if (this.holdBackSlowTicks = 0, l >= Pn) {
2197
2299
  this.holdBackFastSince = 0;
2198
2300
  return;
2199
2301
  }
@@ -2201,7 +2303,7 @@ var Ln = class {
2201
2303
  this.holdBackFastSince = t;
2202
2304
  return;
2203
2305
  }
2204
- if (t - this.holdBackFastSince < An || (this.holdBackFastSince = t, this.holdBackStepCount === 0 || a !== this.holdBackApplied)) return;
2306
+ if (t - this.holdBackFastSince < In || (this.holdBackFastSince = t, this.holdBackStepCount === 0 || a !== this.holdBackApplied)) return;
2205
2307
  --this.holdBackStepCount;
2206
2308
  let f = Math.max(o, o + this.holdBackStepCount * J);
2207
2309
  f >= a || this.moveHoldBack(e, a, f, "fast-fetches", `part fetches fast again (p95 first byte ${d} ms per 1 s of media)`);
@@ -2244,17 +2346,17 @@ var Ln = class {
2244
2346
  } catch {}
2245
2347
  }
2246
2348
  startEstimate() {
2247
- return this.deps.rememberBandwidth === !1 ? zt : Le() ?? zt;
2349
+ return this.deps.rememberBandwidth === !1 ? Gt : ze() ?? Gt;
2248
2350
  }
2249
2351
  maybeRememberBandwidth(e) {
2250
- if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded < Bt) return;
2352
+ if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded < Kt) return;
2251
2353
  let t = Date.now();
2252
- if (!e && t - this.bwSavedAt < Vt) return;
2354
+ if (!e && t - this.bwSavedAt < qt) return;
2253
2355
  let n = this.hls?.bandwidthEstimate;
2254
- typeof n != "number" || !Number.isFinite(n) || n <= 0 || (this.bwSavedAt = t, Re(n));
2356
+ typeof n != "number" || !Number.isFinite(n) || n <= 0 || (this.bwSavedAt = t, Be(n));
2255
2357
  }
2256
2358
  destroy() {
2257
- if (this.maybeRememberBandwidth(!0), this.detachFrames?.(), this.detachFrames = null, this.prefetch?.destroy(), this.prefetch = null, this.clearRecoveryReset(), this.capTimer &&= (clearTimeout(this.capTimer), null), this.capObserver &&= (this.capObserver.disconnect(), null), this.unwatchDprChanges(), this.endWatchdog &&= (clearInterval(this.endWatchdog), null), this.onVisibility && typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), this.onVisibility = null), this.onSeeking &&= (this.deps.video.removeEventListener("seeking", this.onSeeking), null), this.onTimeUpdate &&= (this.deps.video.removeEventListener("timeupdate", this.onTimeUpdate), null), this.onPause &&= (this.deps.video.removeEventListener("pause", this.onPause), null), this.onPlay &&= (this.deps.video.removeEventListener("play", this.onPlay), null), this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null), this.licenseRetryTimer &&= (clearTimeout(this.licenseRetryTimer), null), this.hls) {
2359
+ if (this.maybeRememberBandwidth(!0), this.detachFrames?.(), this.detachFrames = null, this.prefetch?.destroy(), this.prefetch = null, this.clearRecoveryReset(), this.capTimer &&= (clearTimeout(this.capTimer), null), this.capObserver &&= (this.capObserver.disconnect(), null), this.unwatchDprChanges(), this.endWatchdog &&= (clearInterval(this.endWatchdog), null), this.onVisibility && typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), this.onVisibility = null), this.onOnline && typeof window < "u" && (window.removeEventListener("online", this.onOnline), this.onOnline = null), this.onSeeking &&= (this.deps.video.removeEventListener("seeking", this.onSeeking), null), this.onTimeUpdate &&= (this.deps.video.removeEventListener("timeupdate", this.onTimeUpdate), null), this.onPause &&= (this.deps.video.removeEventListener("pause", this.onPause), null), this.onPlay &&= (this.deps.video.removeEventListener("play", this.onPlay), null), this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null), this.licenseRetryTimer &&= (clearTimeout(this.licenseRetryTimer), null), this.hls) {
2258
2360
  try {
2259
2361
  this.hls.destroy();
2260
2362
  } catch (e) {
@@ -2269,7 +2371,7 @@ var Ln = class {
2269
2371
  scheduleLicenseRetry(t) {
2270
2372
  if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
2271
2373
  let n = t.response?.code ?? 0;
2272
- if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= Wt) return !1;
2374
+ if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= Xt) return !1;
2273
2375
  this.licenseRecoveries += 1;
2274
2376
  let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
2275
2377
  return this.licenseRetryTimer = setTimeout(() => {
@@ -2301,7 +2403,11 @@ var Ln = class {
2301
2403
  return;
2302
2404
  }
2303
2405
  if (t.type === e.ErrorTypes.NETWORK_ERROR) {
2304
- if (this.networkRecoveries < Ut) {
2406
+ if (!R() && (t.response?.code ?? 0) === 0) {
2407
+ this.offlineHold = !0, this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null);
2408
+ return;
2409
+ }
2410
+ if (this.networkRecoveries < Yt) {
2305
2411
  this.networkRecoveries += 1;
2306
2412
  let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
2307
2413
  this.networkRetryTimer = setTimeout(() => {
@@ -2318,7 +2424,7 @@ var Ln = class {
2318
2424
  return;
2319
2425
  }
2320
2426
  if (t.type === e.ErrorTypes.MEDIA_ERROR) {
2321
- if (this.mediaRecoveries < Ht) {
2427
+ if (this.mediaRecoveries < Jt) {
2322
2428
  this.mediaRecoveries += 1, n.recoverMediaError();
2323
2429
  return;
2324
2430
  }
@@ -2339,18 +2445,18 @@ var Ln = class {
2339
2445
  }
2340
2446
  }
2341
2447
  toError(t, r = "PLAYBACK") {
2342
- let o = t.response?.code ?? 0, s = t.details ?? t.type, c = t.reason ?? t.error?.message ?? "", l = r === "DRM" && o === 403 && t.details === e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED ? i(Ot(t.networkDetails)) : void 0;
2343
- return new n(r === "DRM" ? a(o, l) : o === 401 ? "UNAUTHORIZED" : o === 403 ? "FORBIDDEN" : "INTERNAL", o, `${r} error: ${s}${c ? ` (${c})` : ""}`, l ? { serverCode: l } : void 0);
2448
+ let o = t.response?.code ?? 0, s = t.details ?? t.type, c = t.reason ?? t.error?.message ?? "", l = r === "DRM" && o === 403 && t.details === e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED ? i(jt(t.networkDetails)) : void 0;
2449
+ return new n(r === "DRM" ? a(o, l) : r === "NETWORK" && o === 0 ? "NETWORK" : o === 401 ? "UNAUTHORIZED" : o === 403 ? "FORBIDDEN" : "INTERNAL", o, `${r} error: ${s}${c ? ` (${c})` : ""}`, l ? { serverCode: l } : void 0);
2344
2450
  }
2345
- }, Rn = 15e3, zn = 6e5, Bn = 3e5, Vn = 100, Y = 1, Hn = 1e3, Un = 3e4, Wn = 1e3, Gn = {
2451
+ }, Wn = 15e3, Gn = 6e5, Kn = 3e5, qn = 100, Y = 1, Jn = 1e3, Yn = 3e4, Xn = 1e3, Zn = {
2346
2452
  inline: "PRESENTATION_INLINE",
2347
2453
  fullscreen: "PRESENTATION_FULLSCREEN",
2348
2454
  pip: "PRESENTATION_PIP"
2349
- }, Kn = {
2455
+ }, Qn = {
2350
2456
  widevine: "KEY_SYSTEM_WIDEVINE",
2351
2457
  fairplay: "KEY_SYSTEM_FAIRPLAY",
2352
2458
  none: "KEY_SYSTEM_NONE"
2353
- }, qn = /* @__PURE__ */ new Set([
2459
+ }, $n = /* @__PURE__ */ new Set([
2354
2460
  "INVALID_URN",
2355
2461
  "NOT_FOUND",
2356
2462
  "GEO_DENIED",
@@ -2371,7 +2477,7 @@ var Ln = class {
2371
2477
  ended: "PLAYER_STATE_ENDED",
2372
2478
  error: "PLAYER_STATE_ERROR"
2373
2479
  };
2374
- function Jn(e) {
2480
+ function er(e) {
2375
2481
  try {
2376
2482
  let t = new URL(e), [n, ...r] = t.hostname.split(".");
2377
2483
  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);
@@ -2379,8 +2485,8 @@ function Jn(e) {
2379
2485
  return;
2380
2486
  }
2381
2487
  }
2382
- var Yn = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), Xn = /* @__PURE__ */ new Set(), Z = /* @__PURE__ */ new Set(), Q = /* @__PURE__ */ new Set(), Zn = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
2383
- function Qn(e) {
2488
+ var tr = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), nr = /* @__PURE__ */ new Set(), Z = /* @__PURE__ */ new Set(), Q = /* @__PURE__ */ new Set(), rr = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
2489
+ function ir(e) {
2384
2490
  if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
2385
2491
  let t;
2386
2492
  try {
@@ -2389,19 +2495,19 @@ function Qn(e) {
2389
2495
  } catch {
2390
2496
  return;
2391
2497
  }
2392
- if (Xn.has(t) && !Z.has(t)) {
2393
- Z.add(t), _(Zn(new URL(t).origin));
2498
+ if (nr.has(t) && !Z.has(t)) {
2499
+ Z.add(t), _(rr(new URL(t).origin));
2394
2500
  for (let e of Q) e.noteCspBlocked();
2395
2501
  }
2396
2502
  }
2397
- function $n(e, t) {
2503
+ function ar(e, t) {
2398
2504
  return _(t, e), { disabledReason: t };
2399
2505
  }
2400
- function er(e, t, n) {
2401
- if (n) return t && !Yn(t, n) && _(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
2506
+ function or(e, t, n) {
2507
+ if (n) return t && !tr(t, n) && _(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
2402
2508
  if (t) return { endpoint: t };
2403
- if (t !== void 0) return $n("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).");
2404
- let r = Jn(e);
2509
+ if (t !== void 0) return ar("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).");
2510
+ let r = er(e);
2405
2511
  if (r) return { endpoint: r };
2406
2512
  let i;
2407
2513
  try {
@@ -2409,9 +2515,9 @@ function er(e, t, n) {
2409
2515
  } catch {
2410
2516
  i = e;
2411
2517
  }
2412
- return $n(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).`);
2518
+ return ar(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).`);
2413
2519
  }
2414
- var tr = class {
2520
+ var sr = class {
2415
2521
  opts;
2416
2522
  url;
2417
2523
  cspKey;
@@ -2493,8 +2599,8 @@ var tr = class {
2493
2599
  constructor(e) {
2494
2600
  this.opts = {
2495
2601
  ...e,
2496
- heartbeatMs: e.heartbeatMs ?? Rn,
2497
- idleMs: e.idleMs ?? zn
2602
+ heartbeatMs: e.heartbeatMs ?? Wn,
2603
+ idleMs: e.idleMs ?? Gn
2498
2604
  }, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
2499
2605
  try {
2500
2606
  let e = new URL(this.url);
@@ -2511,11 +2617,11 @@ var tr = class {
2511
2617
  sdkVersion: this.opts.sdkVersion,
2512
2618
  ...this.opts.environment
2513
2619
  };
2514
- this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Hn), 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 && Xn.add(this.cspKey), document.addEventListener("securitypolicyviolation", Qn), Q.add(this), this.noteCspBlocked(), this.onVisibility());
2620
+ this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Jn), 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 && nr.add(this.cspKey), document.addEventListener("securitypolicyviolation", ir), Q.add(this), this.noteCspBlocked(), this.onVisibility());
2515
2621
  }
2516
2622
  checkSuspension(e) {
2517
2623
  if (this.endedFlag || !this.opts.idleMs) return !1;
2518
- let t = Math.max(this.opts.idleMs, Bn);
2624
+ let t = Math.max(this.opts.idleMs, Kn);
2519
2625
  return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
2520
2626
  }
2521
2627
  syncIdle(e) {
@@ -2538,12 +2644,12 @@ var tr = class {
2538
2644
  let a = {
2539
2645
  fromState: X[e] ?? "PLAYER_STATE_UNSPECIFIED",
2540
2646
  toState: X[t] ?? "PLAYER_STATE_UNSPECIFIED",
2541
- presentation: Gn[this.presentation]
2647
+ presentation: Zn[this.presentation]
2542
2648
  }, o = this.causeOf(e, t, i);
2543
2649
  o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
2544
2650
  }
2545
2651
  seekInduced(e) {
2546
- return this.lastSeekMs >= 0 && e - this.lastSeekMs < Wn;
2652
+ return this.lastSeekMs >= 0 && e - this.lastSeekMs < Xn;
2547
2653
  }
2548
2654
  causeOf(e, t, n) {
2549
2655
  if (t === "error") return "TRANSITION_CAUSE_ERROR";
@@ -2617,7 +2723,7 @@ var tr = class {
2617
2723
  let r = n ?? "";
2618
2724
  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";
2619
2725
  if (e === "DRM_CLIENT" || e === "DRM_DEVICE_REVOKED") return "ERROR_STAGE_DRM";
2620
- if (qn.has(e)) return "ERROR_STAGE_RESOLVE";
2726
+ if ($n.has(e)) return "ERROR_STAGE_RESOLVE";
2621
2727
  let i = t ?? "";
2622
2728
  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";
2623
2729
  }
@@ -2671,7 +2777,7 @@ var tr = class {
2671
2777
  maybeEmitMediaInfo(e) {
2672
2778
  if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
2673
2779
  let t = {};
2674
- e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = Kn[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);
2780
+ e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = Qn[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);
2675
2781
  let n = JSON.stringify(t);
2676
2782
  n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
2677
2783
  }
@@ -2691,7 +2797,7 @@ var tr = class {
2691
2797
  let c = r?.positionMs ?? 0;
2692
2798
  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));
2693
2799
  let l = e !== "END_REASON_ENDED";
2694
- l && this.lastStallMs > 0 && n - this.lastStallMs <= Un && (i.abandonAfterStallMs = Math.max(Y, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= Un && (i.abandonAfterErrorMs = Math.max(Y, 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);
2800
+ l && this.lastStallMs > 0 && n - this.lastStallMs <= Yn && (i.abandonAfterStallMs = Math.max(Y, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= Yn && (i.abandonAfterErrorMs = Math.max(Y, 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);
2695
2801
  let u = r?.decodedFrames ?? this.lastDecoded;
2696
2802
  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");
2697
2803
  }
@@ -2711,13 +2817,13 @@ var tr = class {
2711
2817
  };
2712
2818
  }
2713
2819
  noteCspBlocked() {
2714
- this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(Zn(new URL(this.url).origin)));
2820
+ this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(rr(new URL(this.url).origin)));
2715
2821
  }
2716
2822
  cspBlocked() {
2717
2823
  return !!this.cspKey && Z.has(this.cspKey);
2718
2824
  }
2719
2825
  enqueue(e) {
2720
- if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > Vn;) {
2826
+ if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > qn;) {
2721
2827
  let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
2722
2828
  this.pending.splice(e >= 0 ? e : 0, 1);
2723
2829
  }
@@ -2744,7 +2850,7 @@ var tr = class {
2744
2850
  };
2745
2851
  //#endregion
2746
2852
  //#region src/core/environment.ts
2747
- function nr() {
2853
+ function cr() {
2748
2854
  if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
2749
2855
  let e;
2750
2856
  try {
@@ -2769,14 +2875,14 @@ function nr() {
2769
2875
  integration: "INTEGRATION_KIND_IFRAME"
2770
2876
  };
2771
2877
  }
2772
- function rr() {
2878
+ function lr() {
2773
2879
  if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
2774
2880
  let e = navigator.userAgentData, t = e?.platform ?? "";
2775
2881
  if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
2776
2882
  let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
2777
2883
  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";
2778
2884
  }
2779
- function ir() {
2885
+ function ur() {
2780
2886
  let e = typeof navigator < "u" ? navigator.connection : void 0;
2781
2887
  if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
2782
2888
  let t = {
@@ -2795,17 +2901,17 @@ function ir() {
2795
2901
  }
2796
2902
  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;
2797
2903
  }
2798
- function ar(e) {
2799
- let t = nr(), n = {
2800
- deviceClass: rr(),
2904
+ function dr(e) {
2905
+ let t = cr(), n = {
2906
+ deviceClass: lr(),
2801
2907
  integration: t.integration,
2802
- ...ir()
2908
+ ...ur()
2803
2909
  };
2804
2910
  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);
2805
2911
  let r = e.getBoundingClientRect?.();
2806
2912
  return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
2807
2913
  }
2808
- async function or() {
2914
+ async function fr() {
2809
2915
  let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
2810
2916
  if (!e?.getHighEntropyValues) return {};
2811
2917
  try {
@@ -2817,7 +2923,7 @@ async function or() {
2817
2923
  }
2818
2924
  //#endregion
2819
2925
  //#region src/core/version.ts
2820
- var sr = "2.23.4", cr = {
2926
+ var pr = "2.25.0", mr = {
2821
2927
  accent: "#E1B600",
2822
2928
  accentText: "#1B1C23",
2823
2929
  background: "#0e0f13",
@@ -2828,7 +2934,7 @@ var sr = "2.23.4", cr = {
2828
2934
  border: "rgba(255, 255, 255, 0.1)",
2829
2935
  radius: "8px",
2830
2936
  fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
2831
- }, lr = {
2937
+ }, hr = {
2832
2938
  accent: "--havik-accent",
2833
2939
  accentText: "--havik-accent-text",
2834
2940
  background: "--havik-bg",
@@ -2840,26 +2946,26 @@ var sr = "2.23.4", cr = {
2840
2946
  radius: "--havik-radius",
2841
2947
  fontFamily: "--havik-font"
2842
2948
  };
2843
- function ur(e, t) {
2949
+ function gr(e, t) {
2844
2950
  let n = {
2845
- ...cr,
2951
+ ...mr,
2846
2952
  ...t
2847
2953
  };
2848
- for (let t of Object.keys(lr)) e.style.setProperty(lr[t], n[t]);
2954
+ for (let t of Object.keys(hr)) e.style.setProperty(hr[t], n[t]);
2849
2955
  n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
2850
2956
  }
2851
2957
  //#endregion
2852
2958
  //#region src/ui/styles.ts
2853
- var dr = "havik-player-styles", fr = "\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", pr = /* @__PURE__ */ new WeakMap();
2854
- function mr(e = document, t) {
2855
- let n = e.querySelector(`style#${dr}`);
2856
- if (n && (!t || pr.get(n) === t)) return;
2959
+ var _r = "havik-player-styles", vr = "\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", yr = /* @__PURE__ */ new WeakMap();
2960
+ function br(e = document, t) {
2961
+ let n = e.querySelector(`style#${_r}`);
2962
+ if (n && (!t || yr.get(n) === t)) return;
2857
2963
  let r = e.createElement("style");
2858
- r.id = dr, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = fr, pr.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
2964
+ r.id = _r, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = vr, yr.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
2859
2965
  }
2860
2966
  //#endregion
2861
2967
  //#region src/ui/icons.ts
2862
- var hr = {
2968
+ var xr = {
2863
2969
  play: "<path d=\"M8 5v14l11-7z\"/>",
2864
2970
  pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
2865
2971
  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\"/>",
@@ -2873,11 +2979,11 @@ var hr = {
2873
2979
  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\"/>"
2874
2980
  };
2875
2981
  function $(e) {
2876
- return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${hr[e]}</svg>`;
2982
+ return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${xr[e]}</svg>`;
2877
2983
  }
2878
2984
  //#endregion
2879
2985
  //#region src/ui/controls.ts
2880
- var gr = 3e3, _r = 250, vr = /* @__PURE__ */ new Set([
2986
+ var Sr = 3e3, Cr = 250, wr = /* @__PURE__ */ new Set([
2881
2987
  "GONE",
2882
2988
  "NOT_FOUND",
2883
2989
  "GEO_DENIED",
@@ -2885,15 +2991,15 @@ var gr = 3e3, _r = 250, vr = /* @__PURE__ */ new Set([
2885
2991
  "UNAUTHORIZED",
2886
2992
  "DRM_DEVICE_REVOKED"
2887
2993
  ]);
2888
- function yr(e) {
2994
+ function Tr(e) {
2889
2995
  let t = "This match isn't available in your country";
2890
2996
  return e ? `${t} (${e})` : t;
2891
2997
  }
2892
- var br = "This device can't play protected video";
2893
- function xr(e) {
2894
- return new Sr(e);
2998
+ var Er = "This device can't play protected video";
2999
+ function Dr(e) {
3000
+ return new Or(e);
2895
3001
  }
2896
- var Sr = class {
3002
+ var Or = class {
2897
3003
  root;
2898
3004
  video;
2899
3005
  player;
@@ -2932,6 +3038,7 @@ var Sr = class {
2932
3038
  endedMessage;
2933
3039
  interruptedMessage;
2934
3040
  errorMessage;
3041
+ offlineMessage;
2935
3042
  hideTimer;
2936
3043
  tapTimer;
2937
3044
  surfacePointerType = "";
@@ -2941,7 +3048,7 @@ var Sr = class {
2941
3048
  scrubbing = !1;
2942
3049
  offFns = [];
2943
3050
  constructor(e) {
2944
- this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? gr, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.streamEnded = e.streamEnded ?? (() => !1), this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, mr(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");
3051
+ this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Sr, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.streamEnded = e.streamEnded ?? (() => !1), this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, this.offlineMessage = e.offlineMessage ?? "No internet connection — waiting to reconnect", br(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");
2945
3052
  let t = (e, t, n) => {
2946
3053
  let r = this.doc.createElement(e);
2947
3054
  if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
@@ -2997,7 +3104,7 @@ var Sr = class {
2997
3104
  }), this.on(this.muteBtn, "click", () => this.player.setMuted(!e.muted)), this.on(this.volSlider, "input", () => {
2998
3105
  let t = Number(this.volSlider.value);
2999
3106
  this.setVolumeFill(t), this.player.setVolume(t), t > 0 && e.muted && this.player.setMuted(!1);
3000
- }), this.on(this.liveGo, "click", () => this.player.seekToLive()), this.on(this.pipBtn, "click", () => void this.togglePip()), this.on(this.fsBtn, "click", () => void this.toggleFullscreen()), this.on(this.ccBtn, "click", () => this.toggleMenu("cc")), this.on(this.audioBtn, "click", () => this.toggleMenu("audio")), this.on(this.qualityBtn, "click", () => this.toggleMenu("quality")), this.on(this.seek, "pointerdown", (e) => this.onSeekDown(e)), this.on(this.seek, "keydown", (e) => this.onSeekKey(e)), this.on(e, "play", () => this.syncPlayPause()), this.on(e, "pause", () => this.syncPlayPause()), this.on(e, "volumechange", () => this.syncVolume()), this.on(e, "timeupdate", () => this.syncProgress()), this.on(e, "progress", () => this.syncProgress()), this.on(e, "durationchange", () => this.syncProgress()), this.on(e, "loadedmetadata", () => this.syncFullscreenSupport()), this.offFns.push(this.player.on("statechange", () => this.syncState())), this.offFns.push(this.player.on("ended", () => this.syncState())), this.offFns.push(this.player.on("ready", () => this.refreshTracks())), this.offFns.push(this.player.on("qualitychange", () => this.onTracksChanged())), this.offFns.push(this.player.on("audiotrackchange", () => this.onTracksChanged())), this.offFns.push(this.player.on("texttrackchange", () => this.onTracksChanged())), this.offFns.push(this.player.on("pipchange", (e) => this.syncPip(e))), this.offFns.push(this.player.on("stats", () => this.syncLive())), this.offFns.push(this.player.on("error", (e) => {
3107
+ }), this.on(this.liveGo, "click", () => this.player.seekToLive()), this.on(this.pipBtn, "click", () => void this.togglePip()), this.on(this.fsBtn, "click", () => void this.toggleFullscreen()), this.on(this.ccBtn, "click", () => this.toggleMenu("cc")), this.on(this.audioBtn, "click", () => this.toggleMenu("audio")), this.on(this.qualityBtn, "click", () => this.toggleMenu("quality")), this.on(this.seek, "pointerdown", (e) => this.onSeekDown(e)), this.on(this.seek, "keydown", (e) => this.onSeekKey(e)), this.on(e, "play", () => this.syncPlayPause()), this.on(e, "pause", () => this.syncPlayPause()), this.on(e, "volumechange", () => this.syncVolume()), this.on(e, "timeupdate", () => this.syncProgress()), this.on(e, "progress", () => this.syncProgress()), this.on(e, "durationchange", () => this.syncProgress()), this.on(e, "loadedmetadata", () => this.syncFullscreenSupport()), this.offFns.push(this.player.on("statechange", () => this.syncState())), this.offFns.push(this.player.on("ended", () => this.syncState())), this.offFns.push(this.player.on("offline", () => this.syncState())), this.offFns.push(this.player.on("online", () => this.syncState())), this.offFns.push(this.player.on("ready", () => this.refreshTracks())), this.offFns.push(this.player.on("qualitychange", () => this.onTracksChanged())), this.offFns.push(this.player.on("audiotrackchange", () => this.onTracksChanged())), this.offFns.push(this.player.on("texttrackchange", () => this.onTracksChanged())), this.offFns.push(this.player.on("pipchange", (e) => this.syncPip(e))), this.offFns.push(this.player.on("stats", () => this.syncLive())), this.offFns.push(this.player.on("error", (e) => {
3001
3108
  this.lastError = e, this.statusKind = null, this.syncState();
3002
3109
  }));
3003
3110
  let t = (e) => e.pointerType !== "touch";
@@ -3027,7 +3134,7 @@ var Sr = class {
3027
3134
  let t = this.surfaceWasHidden;
3028
3135
  this.tapTimer = setTimeout(() => {
3029
3136
  this.tapTimer = void 0, this.toggleBar(t);
3030
- }, _r);
3137
+ }, Cr);
3031
3138
  }
3032
3139
  toggleBar(e) {
3033
3140
  e ? this.poke() : this.hideIfIdle();
@@ -3044,10 +3151,14 @@ var Sr = class {
3044
3151
  }
3045
3152
  syncStatus(e) {
3046
3153
  let t = null;
3047
- this.statusOverlays && (e === "ended" ? t = "ended" : e === "error" ? t = "error" : e === "waiting" ? t = "waiting" : !this.hasPlayed && (e === "idle" || e === "paused") && (t = "preplay")), this.renderStatus(t);
3154
+ if (this.statusOverlays) {
3155
+ let n = this.player.offline && e !== "ended" && e !== "idle", r = !this.hasPlayed && (e === "paused" || e === "waiting");
3156
+ e === "ended" ? t = "ended" : n && !r ? t = "offline" : e === "error" ? t = "error" : e === "waiting" ? t = "waiting" : !this.hasPlayed && (e === "idle" || e === "paused") && (t = "preplay");
3157
+ }
3158
+ this.renderStatus(t);
3048
3159
  }
3049
3160
  statusMessageFor(e) {
3050
- return e === "ended" ? this.player.endedReason === "interrupted" ? this.interruptedMessage : this.endedMessage : e === "waiting" ? this.hasPlayed ? "Reconnecting — please stand by" : "Starting soon…" : e === "error" ? this.errorMessage === void 0 ? this.lastError?.code === "GEO_DENIED" ? yr(this.lastError.country) : this.lastError?.code === "DRM_DEVICE_REVOKED" ? br : this.lastError?.message ?? "Playback unavailable" : this.errorMessage : null;
3161
+ return e === "ended" ? this.player.endedReason === "interrupted" ? this.interruptedMessage : this.endedMessage : e === "offline" ? this.offlineMessage : e === "waiting" ? this.hasPlayed ? "Reconnecting — please stand by" : "Starting soon…" : e === "error" ? this.errorMessage === void 0 ? this.lastError?.code === "GEO_DENIED" ? Tr(this.lastError.country) : this.lastError?.code === "DRM_DEVICE_REVOKED" ? Er : this.lastError?.message ?? "Playback unavailable" : this.errorMessage : null;
3051
3162
  }
3052
3163
  renderStatus(e) {
3053
3164
  let t = this.statusMessageFor(e);
@@ -3062,7 +3173,7 @@ var Sr = class {
3062
3173
  e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML = $("play"), e.addEventListener("click", () => void this.player.play()), n.append(e);
3063
3174
  } else {
3064
3175
  let r = this.doc.createElement("div");
3065
- if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !vr.has(this.lastError.code)) {
3176
+ if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !wr.has(this.lastError.code)) {
3066
3177
  let e = this.doc.createElement("button");
3067
3178
  e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${$("retry")}<span>Retry</span>`, e.addEventListener("click", () => void this.player.retry()), n.append(e);
3068
3179
  }
@@ -3103,7 +3214,7 @@ var Sr = class {
3103
3214
  let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
3104
3215
  this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
3105
3216
  }
3106
- !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Cr(this.video.currentTime)} / ${Cr(this.video.duration)}`);
3217
+ !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${kr(this.video.currentTime)} / ${kr(this.video.duration)}`);
3107
3218
  }
3108
3219
  syncLive() {
3109
3220
  let e = this.player.getStats(), t = e.isLive !== !1, n = this.player.state === "ended", r = !t && !this.streamEnded();
@@ -3153,17 +3264,17 @@ var Sr = class {
3153
3264
  renderQualityMenu() {
3154
3265
  let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
3155
3266
  n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
3156
- for (let n of e) this.menu.append(this.menuItem(wr(n), t === n.index, () => this.player.setQuality(n.index)));
3267
+ for (let n of e) this.menu.append(this.menuItem(Ar(n), t === n.index, () => this.player.setQuality(n.index)));
3157
3268
  }
3158
3269
  renderAudioMenu() {
3159
3270
  let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
3160
3271
  t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
3161
- for (let t of e) this.menu.append(this.menuItem(Tr(t), t.default, () => this.player.setAudioTrack(t.id)));
3272
+ for (let t of e) this.menu.append(this.menuItem(jr(t), t.default, () => this.player.setAudioTrack(t.id)));
3162
3273
  }
3163
3274
  renderCcMenu() {
3164
3275
  let e = this.player.getTextTracks(), t = this.doc.createElement("div");
3165
3276
  t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
3166
- for (let t of e) this.menu.append(this.menuItem(Er(t), !1, () => this.player.setTextTrack(t.id)));
3277
+ for (let t of e) this.menu.append(this.menuItem(Mr(t), !1, () => this.player.setTextTrack(t.id)));
3167
3278
  }
3168
3279
  onTracksChanged() {
3169
3280
  this.openMenu && this.renderMenu(this.openMenu);
@@ -3183,14 +3294,14 @@ var Sr = class {
3183
3294
  }
3184
3295
  async toggleFullscreen() {
3185
3296
  try {
3186
- S(this.video, this.root) ? await T(this.video, this.root) : await w(this.video, this.root);
3297
+ ye(this.video, this.root) ? await C(this.video, this.root) : await S(this.video, this.root);
3187
3298
  } catch {}
3188
3299
  }
3189
3300
  syncFullscreenSupport() {
3190
- this.fsSupported = C(this.video, this.root), this.fsBtn.style.display = this.fsSupported ? "" : "none";
3301
+ this.fsSupported = x(this.video, this.root), this.fsBtn.style.display = this.fsSupported ? "" : "none";
3191
3302
  }
3192
3303
  syncFullscreen() {
3193
- let e = S(this.video, this.root);
3304
+ let e = ye(this.video, this.root);
3194
3305
  this.setIcon(this.fsBtn, e ? "fullscreenExit" : "fullscreen"), this.fsBtn.setAttribute("aria-label", e ? "Exit fullscreen" : "Fullscreen");
3195
3306
  }
3196
3307
  poke() {
@@ -3268,41 +3379,51 @@ var Sr = class {
3268
3379
  this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
3269
3380
  }
3270
3381
  };
3271
- function Cr(e) {
3382
+ function kr(e) {
3272
3383
  (!Number.isFinite(e) || e < 0) && (e = 0);
3273
3384
  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");
3274
3385
  return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
3275
3386
  }
3276
- function wr(e) {
3387
+ function Ar(e) {
3277
3388
  return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
3278
3389
  }
3279
- function Tr(e) {
3390
+ function jr(e) {
3280
3391
  return e.name || e.lang || `Track ${e.id}`;
3281
3392
  }
3282
- function Er(e) {
3393
+ function Mr(e) {
3283
3394
  return e.name || e.lang || `Track ${e.id}`;
3284
3395
  }
3285
3396
  //#endregion
3286
3397
  //#region src/managed/index.ts
3287
- var Dr = 6e3, Or = 45e3, kr = 2e3, Ar = 3, jr = 5e3, Mr = 2e3, Nr = 48e4, Pr = "keySystemLicenseRequestFailed";
3288
- function Fr(e) {
3398
+ var Nr = 6e3, Pr = 45e3, Fr = 2e3, Ir = 3, Lr = 5e3, Rr = 2e3, zr = 48e4, Br = "keySystemLicenseRequestFailed", Vr = /* @__PURE__ */ new Set([
3399
+ "GONE",
3400
+ "NOT_FOUND",
3401
+ "INVALID_URN",
3402
+ "UNAUTHORIZED",
3403
+ "GEO_DENIED",
3404
+ "DRM_DEVICE_REVOKED"
3405
+ ]);
3406
+ function Hr(e) {
3407
+ return !Vr.has(e);
3408
+ }
3409
+ function Ur(e) {
3289
3410
  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)})`);
3290
- if (e.env !== void 0) return ot(e.env);
3411
+ if (e.env !== void 0) return ct(e.env);
3291
3412
  if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
3292
3413
  return e.baseUrl;
3293
3414
  }
3294
- async function Ir(e) {
3415
+ async function Wr(e) {
3295
3416
  if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
3296
- let t = Fr(e);
3417
+ let t = Ur(e);
3297
3418
  if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
3298
3419
  if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
3299
- let r = new Lr({
3420
+ let r = new Gr({
3300
3421
  ...e,
3301
3422
  baseUrl: t
3302
3423
  });
3303
3424
  return await r.start(), r;
3304
3425
  }
3305
- var Lr = class {
3426
+ var Gr = class {
3306
3427
  opts;
3307
3428
  abort = new AbortController();
3308
3429
  listeners = {};
@@ -3337,12 +3458,17 @@ var Lr = class {
3337
3458
  playRequested = !1;
3338
3459
  idleClosed = !1;
3339
3460
  pendingStartLoad = !1;
3461
+ connectivity = null;
3462
+ failedWhileOffline = !1;
3340
3463
  constructor(e) {
3341
3464
  this.opts = e;
3342
3465
  }
3343
3466
  get state() {
3344
3467
  return this._state;
3345
3468
  }
3469
+ get offline() {
3470
+ return !R();
3471
+ }
3346
3472
  get descriptor() {
3347
3473
  return this._descriptor;
3348
3474
  }
@@ -3350,7 +3476,7 @@ var Lr = class {
3350
3476
  return this._endedReason;
3351
3477
  }
3352
3478
  async start() {
3353
- this.opts.muted && (this.opts.video.muted = !0), this.opts.poster && (this.opts.video.poster = this.opts.poster), this.mountControls(), this.attachPipListeners(), this.attachEndedPlayGuard(), this.setState("loading");
3479
+ this.opts.muted && (this.opts.video.muted = !0), this.opts.poster && (this.opts.video.poster = this.opts.poster), this.mountControls(), this.attachPipListeners(), this.attachEndedPlayGuard(), this.watchConnectivity(), this.setState("loading");
3354
3480
  let e = ++this.loadGen, t = this.resolveOptions();
3355
3481
  try {
3356
3482
  let n = await v(t);
@@ -3363,7 +3489,7 @@ var Lr = class {
3363
3489
  this.setState("waiting"), this.beginArming(e, t.liveStartsAtMs);
3364
3490
  return;
3365
3491
  }
3366
- throw t;
3492
+ throw this.destroy(), t;
3367
3493
  }
3368
3494
  }
3369
3495
  resolveOptions() {
@@ -3376,7 +3502,7 @@ var Lr = class {
3376
3502
  };
3377
3503
  }
3378
3504
  beginArming(e, t, n = !1) {
3379
- let r = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? O(this.opts.baseUrl);
3505
+ let r = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? E(this.opts.baseUrl);
3380
3506
  r ? this.armWithSse(e, r, t, n) : this.beginArmingByPolling(e);
3381
3507
  }
3382
3508
  beginArmingByPolling(e) {
@@ -3397,7 +3523,7 @@ var Lr = class {
3397
3523
  setTimeout(() => {
3398
3524
  a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
3399
3525
  phase: i ? "unavailable" : "tooEarly",
3400
- retryInMs: Or,
3526
+ retryInMs: Pr,
3401
3527
  attempt: 1,
3402
3528
  elapsedMs: 0,
3403
3529
  ...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
@@ -3436,13 +3562,13 @@ var Lr = class {
3436
3562
  !a && !p() && h();
3437
3563
  }, e);
3438
3564
  };
3439
- _(Dr), this.armingSub = D({
3565
+ _(Nr), this.armingSub = T({
3440
3566
  eventsBaseUrl: t,
3441
3567
  matchUrn: this.opts.matchUrn,
3442
3568
  credential: this.opts.credential,
3443
- onAlive: () => _(Or),
3569
+ onAlive: () => _(Pr),
3444
3570
  onState: (e) => {
3445
- a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * kr);
3571
+ a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Fr);
3446
3572
  },
3447
3573
  onError: () => h()
3448
3574
  });
@@ -3465,7 +3591,7 @@ var Lr = class {
3465
3591
  let n = await c(this.opts.credential);
3466
3592
  if (this.destroyed || t !== this.loadGen) return;
3467
3593
  this.setState("loading");
3468
- let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = ft(this.opts.video, (e) => {
3594
+ let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = ht(this.opts.video, (e) => {
3469
3595
  this._state !== "ended" && this._state !== "error" && this.setState(e);
3470
3596
  });
3471
3597
  if (await i.load(), this.destroyed || t !== this.loadGen) {
@@ -3487,26 +3613,26 @@ var Lr = class {
3487
3613
  if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
3488
3614
  let i = e.analytics?.sid;
3489
3615
  if (!i) return;
3490
- let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = er(this.opts.baseUrl, a, e.analytics?.endpoint);
3616
+ let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = or(this.opts.baseUrl, a, e.analytics?.endpoint);
3491
3617
  if (!o) {
3492
3618
  s && setTimeout(() => {
3493
3619
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
3494
3620
  }, 0);
3495
3621
  return;
3496
3622
  }
3497
- let c = this.opts.video, l = new tr({
3623
+ let c = this.opts.video, l = new sr({
3498
3624
  endpoint: o,
3499
3625
  sid: i,
3500
3626
  player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
3501
- sdkVersion: sr,
3502
- environment: ar(c),
3627
+ sdkVersion: pr,
3628
+ environment: dr(c),
3503
3629
  idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
3504
3630
  onIdle: () => this.onAnalyticsIdle(t),
3505
3631
  onBlocked: (e) => setTimeout(() => {
3506
3632
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, e));
3507
3633
  }, 0),
3508
3634
  sample: () => {
3509
- let e = this.engine?.getStats() ?? st, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
3635
+ let e = this.engine?.getStats() ?? ut, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
3510
3636
  return {
3511
3637
  ...e,
3512
3638
  bufferedMs: Math.round(t * 1e3),
@@ -3520,7 +3646,7 @@ var Lr = class {
3520
3646
  let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
3521
3647
  c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
3522
3648
  c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
3523
- }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), or().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
3649
+ }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), fr().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
3524
3650
  }
3525
3651
  currentPresentation() {
3526
3652
  let e = this.opts.video;
@@ -3535,7 +3661,7 @@ var Lr = class {
3535
3661
  video: this.opts.video,
3536
3662
  descriptor: e,
3537
3663
  credential: t,
3538
- deviceId: j(),
3664
+ deviceId: k(),
3539
3665
  userId: this.opts.userId,
3540
3666
  lowLatency: this.opts.lowLatency === void 0 || this.opts.lowLatency === "auto" || this.opts.lowLatency,
3541
3667
  snapToLiveOnRefocus: this.opts.snapToLiveOnRefocus,
@@ -3544,17 +3670,18 @@ var Lr = class {
3544
3670
  adaptiveHoldBack: this.opts.adaptiveHoldBack,
3545
3671
  adaptiveHoldBackCeiling: this.opts.adaptiveHoldBackCeiling,
3546
3672
  mediaDuringKey: this.opts.mediaDuringKey,
3673
+ preloadHints: this.opts.preloadHints,
3547
3674
  debug: this.opts.debug,
3548
3675
  deferLoad: r,
3549
3676
  hlsConfig: i,
3550
3677
  emit: (e) => this.onEngineEvent(e),
3551
3678
  freshLicenseUrl: () => this.refreshLicense()
3552
3679
  }, o = this.opts.engine ?? "auto";
3553
- if (o === "native") return new W(a);
3554
- if (o === "hls") return new Ln(a);
3555
- if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && H(this.opts.video) && U() || !e.drmEnabled && wt() && H(this.opts.video)) return new W(a);
3556
- if (Rt()) return new Ln(a);
3557
- if (H(this.opts.video)) return new W(a);
3680
+ if (o === "native") return new U(a);
3681
+ if (o === "hls") return new Un(a);
3682
+ if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && V(this.opts.video) && H() || !e.drmEnabled && Dt() && V(this.opts.video)) return new U(a);
3683
+ if (Ut()) return new Un(a);
3684
+ if (V(this.opts.video)) return new U(a);
3558
3685
  throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
3559
3686
  }
3560
3687
  onEngineEvent(e) {
@@ -3604,11 +3731,11 @@ var Lr = class {
3604
3731
  }
3605
3732
  startLiveState(e) {
3606
3733
  if (this.opts.liveStateEvents === !1) return;
3607
- let t = this.opts.eventsBaseUrl ?? O(this.opts.baseUrl);
3734
+ let t = this.opts.eventsBaseUrl ?? E(this.opts.baseUrl);
3608
3735
  if (!t) return;
3609
3736
  this.closeLiveState();
3610
3737
  let i = 0, a = !1;
3611
- this.liveStateSub = D({
3738
+ this.liveStateSub = T({
3612
3739
  eventsBaseUrl: t,
3613
3740
  matchUrn: this.opts.matchUrn,
3614
3741
  credential: this.opts.credential,
@@ -3620,11 +3747,11 @@ var Lr = class {
3620
3747
  },
3621
3748
  onError: (o) => {
3622
3749
  if (!(this.destroyed || e !== this.loadGen || a) && !this.endedHandled) {
3623
- if (o instanceof E && (o.terminal || o.status === 404)) {
3750
+ if (o instanceof w && (o.terminal || o.status === 404)) {
3624
3751
  a = !0, this.emit("warning", new n(r(o.status), o.status, `live-state events answered HTTP ${o.status} for ${this.opts.matchUrn}: the match is ` + (o.terminal ? "gone, so the subscription stopped" : "not in the catalog (ended and dropped, or not listed yet), so it retries every 5 min") + " — end-of-stream detection falls back to the HLS staleness watchdog."));
3625
3752
  return;
3626
3753
  }
3627
- i += 1, i >= Ar && (a = !0, this.emit("warning", new n("NETWORK", 0, `live-state events unreachable at ${t} after ${i} 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.`)));
3754
+ i += 1, i >= Ir && (a = !0, this.emit("warning", new n("NETWORK", 0, `live-state events unreachable at ${t} after ${i} 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.`)));
3628
3755
  }
3629
3756
  }
3630
3757
  });
@@ -3632,6 +3759,18 @@ var Lr = class {
3632
3759
  closeLiveState() {
3633
3760
  this.liveStateSub?.close(), this.liveStateSub = null;
3634
3761
  }
3762
+ watchConnectivity() {
3763
+ this.connectivity || (this.connectivity = lt(), this.connectivity.onChange((e) => {
3764
+ if (this.destroyed) return;
3765
+ if (!e) {
3766
+ this.emit("offline");
3767
+ return;
3768
+ }
3769
+ if (this.emit("online"), this._state !== "error" || !this._lastError) return;
3770
+ let t = this._lastError.code;
3771
+ Hr(t) && (t === "NETWORK" || this.failedWhileOffline) && this.retry().catch(() => void 0);
3772
+ }));
3773
+ }
3635
3774
  watchReturn() {
3636
3775
  this.onReturnVisible || typeof document > "u" || this.opts.liveStateEvents !== !1 && (document.visibilityState === "hidden" && (this.hiddenAtMs = Date.now()), this.onReturnVisible = () => {
3637
3776
  if (document.visibilityState === "hidden") {
@@ -3639,7 +3778,7 @@ var Lr = class {
3639
3778
  return;
3640
3779
  }
3641
3780
  let e = this.hiddenAtMs;
3642
- this.hiddenAtMs = null, e != null && Date.now() - e >= jr && this.resyncLiveState();
3781
+ this.hiddenAtMs = null, e != null && Date.now() - e >= Lr && this.resyncLiveState();
3643
3782
  }, this.onReturnPageShow = (e) => {
3644
3783
  e.persisted && this.resyncLiveState();
3645
3784
  }, document.addEventListener("visibilitychange", this.onReturnVisible), typeof window < "u" && window.addEventListener("pageshow", this.onReturnPageShow));
@@ -3671,7 +3810,7 @@ var Lr = class {
3671
3810
  scheduleRejoin(e) {
3672
3811
  this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
3673
3812
  this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
3674
- }, Math.random() * kr));
3813
+ }, Math.random() * Fr));
3675
3814
  }
3676
3815
  cancelRejoin() {
3677
3816
  this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
@@ -3695,7 +3834,7 @@ var Lr = class {
3695
3834
  }
3696
3835
  t.controls = !1;
3697
3836
  let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
3698
- r && r.insertBefore(n, t), n.appendChild(t), ur(n, this.opts.theme), this.container = n, this.controlBar = xr({
3837
+ r && r.insertBefore(n, t), n.appendChild(t), gr(n, this.opts.theme), this.container = n, this.controlBar = Dr({
3699
3838
  root: n,
3700
3839
  video: t,
3701
3840
  player: this,
@@ -3705,6 +3844,7 @@ var Lr = class {
3705
3844
  streamEnded: () => this.streamEnded,
3706
3845
  interruptedMessage: this.opts.interruptedMessage,
3707
3846
  errorMessage: this.opts.errorMessage,
3847
+ offlineMessage: this.opts.offlineMessage,
3708
3848
  cspNonce: this.opts.cspNonce
3709
3849
  });
3710
3850
  }
@@ -3733,7 +3873,7 @@ var Lr = class {
3733
3873
  }
3734
3874
  startStats() {
3735
3875
  this.stopStats();
3736
- let e = Math.max(500, this.opts.statsIntervalMs ?? Mr);
3876
+ let e = Math.max(500, this.opts.statsIntervalMs ?? Rr);
3737
3877
  this.statsTimer = setInterval(() => {
3738
3878
  if (!this.engine) return;
3739
3879
  let e = this.engine.getStats();
@@ -3744,14 +3884,14 @@ var Lr = class {
3744
3884
  this.statsTimer && clearInterval(this.statsTimer), this.statsTimer = void 0;
3745
3885
  }
3746
3886
  isStaleLicenseDenial(e) {
3747
- return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== Pr || e.error.httpStatus !== 403 || e.error.code !== "FORBIDDEN" || e.error.serverCode === "license_refused" ? !1 : K(this._descriptor?.drm?.widevine?.licenseUrl);
3887
+ return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== Br || e.error.httpStatus !== 403 || e.error.code !== "FORBIDDEN" || e.error.serverCode === "license_refused" ? !1 : G(this._descriptor?.drm?.widevine?.licenseUrl);
3748
3888
  }
3749
3889
  scheduleLicenseRefresh() {
3750
3890
  if (this.stopRefresh(), !this._descriptor?.drmEnabled) return;
3751
3891
  typeof document < "u" && this.engine?.name === "hls" && (this.onRefocus = () => {
3752
- document.visibilityState !== "visible" || this.destroyed || K(this._descriptor?.drm?.widevine?.licenseUrl) && this.refreshLicense();
3892
+ document.visibilityState !== "visible" || this.destroyed || G(this._descriptor?.drm?.widevine?.licenseUrl) && this.refreshLicense();
3753
3893
  }, document.addEventListener("visibilitychange", this.onRefocus));
3754
- let e = this.opts.licenseRefreshMs ?? Nr;
3894
+ let e = this.opts.licenseRefreshMs ?? zr;
3755
3895
  e && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
3756
3896
  }
3757
3897
  stopRefresh() {
@@ -3808,7 +3948,7 @@ var Lr = class {
3808
3948
  this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
3809
3949
  }
3810
3950
  getStats() {
3811
- return this.engine?.getStats() ?? st;
3951
+ return this.engine?.getStats() ?? ut;
3812
3952
  }
3813
3953
  getQualityLevels() {
3814
3954
  return this.engine?.getQualityLevels() ?? [];
@@ -3847,13 +3987,13 @@ var Lr = class {
3847
3987
  e.pictureInPictureElement === this.opts.video && typeof e.exitPictureInPicture == "function" && await e.exitPictureInPicture();
3848
3988
  }
3849
3989
  async enterFullscreen() {
3850
- return !this.destroyed && w(this.opts.video, this.container ?? void 0);
3990
+ return !this.destroyed && S(this.opts.video, this.container ?? void 0);
3851
3991
  }
3852
3992
  async exitFullscreen() {
3853
- await T(this.opts.video, this.container ?? void 0);
3993
+ await C(this.opts.video, this.container ?? void 0);
3854
3994
  }
3855
3995
  fullscreenSupported() {
3856
- return !this.destroyed && C(this.opts.video, this.container ?? void 0);
3996
+ return !this.destroyed && x(this.opts.video, this.container ?? void 0);
3857
3997
  }
3858
3998
  retry() {
3859
3999
  return this.reload();
@@ -3878,13 +4018,13 @@ var Lr = class {
3878
4018
  return n.add(t), () => n.delete(t);
3879
4019
  }
3880
4020
  destroy() {
3881
- this.destroyed || (this.destroyed = !0, this.loadGen += 1, this.abort.abort(), this.stopStats(), this.stopRefresh(), this.unmountControls(), this.cancelRejoin(), this.closeArming(), this.closeLiveState(), this.unwatchReturn(), this.detachMedia?.(), this.detachPip?.(), this.detachEndedPlayGuard?.(), this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.engine?.destroy(), this.engine = null, this.setState("idle"), this.clearListeners());
4021
+ this.destroyed || (this.destroyed = !0, this.loadGen += 1, this.abort.abort(), this.stopStats(), this.stopRefresh(), this.unmountControls(), this.cancelRejoin(), this.closeArming(), this.closeLiveState(), this.unwatchReturn(), this.connectivity?.destroy(), this.connectivity = null, this.detachMedia?.(), this.detachPip?.(), this.detachEndedPlayGuard?.(), this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.engine?.destroy(), this.engine = null, this.setState("idle"), this.clearListeners());
3882
4022
  }
3883
4023
  clearListeners() {
3884
4024
  for (let e of Object.keys(this.listeners)) this.listeners[e]?.clear();
3885
4025
  }
3886
4026
  fail(e) {
3887
- this._lastError = e, this.setState("error"), this.analyticsSession?.noteFatal(), this.emit("error", e);
4027
+ this._lastError = e, this.failedWhileOffline = !R(), this.setState("error"), this.analyticsSession?.noteFatal(), this.emit("error", e);
3888
4028
  }
3889
4029
  setState(e) {
3890
4030
  if (e === this._state) return;
@@ -3916,12 +4056,12 @@ var Lr = class {
3916
4056
  };
3917
4057
  //#endregion
3918
4058
  //#region src/embed/protocol.ts
3919
- function Rr(e) {
4059
+ function Kr(e) {
3920
4060
  return !!e && typeof e == "object" && typeof e.type == "string" && e.type.startsWith("oddin:");
3921
4061
  }
3922
4062
  //#endregion
3923
4063
  //#region src/embed/host.ts
3924
- function zr(e) {
4064
+ function qr(e) {
3925
4065
  if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
3926
4066
  if (!e.src) throw Error("mountEmbed: opts.src is required");
3927
4067
  if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
@@ -3930,7 +4070,7 @@ function zr(e) {
3930
4070
  let r = document.createElement("iframe");
3931
4071
  r.src = t.toString(), r.allow = "autoplay; encrypted-media; fullscreen", r.setAttribute("allowfullscreen", ""), r.referrerPolicy = "no-referrer", r.setAttribute("sandbox", e.sandbox ?? "allow-scripts allow-same-origin allow-presentation"), r.style.cssText = "border:0;width:100%;height:100%;display:block", e.container.appendChild(r);
3932
4072
  let i = /* @__PURE__ */ new Set(), a = (t) => {
3933
- if (t.source !== r.contentWindow || t.origin !== n || !Rr(t.data)) return;
4073
+ if (t.source !== r.contentWindow || t.origin !== n || !Kr(t.data)) return;
3934
4074
  let a = t.data;
3935
4075
  a.type === "oddin:ready" && a.protocol !== 1 && console.warn(`havik-player: embed protocol v${a.protocol} != host v1. Pin the embed page version to the SDK version to avoid skew.`), e.onEvent?.(a), i.forEach((e) => e(a));
3936
4076
  };
@@ -3980,15 +4120,15 @@ function zr(e) {
3980
4120
  }
3981
4121
  //#endregion
3982
4122
  //#region src/embed/page.ts
3983
- var Br = /^[A-Za-z0-9:_.-]{1,128}$/;
3984
- function Vr(e) {
4123
+ var Jr = /^[A-Za-z0-9:_.-]{1,128}$/;
4124
+ function Yr(e) {
3985
4125
  if (typeof e == "boolean") return e;
3986
4126
  if (typeof e == "object" && e) {
3987
4127
  let t = e.endpoint;
3988
4128
  return typeof t == "string" ? { endpoint: t } : {};
3989
4129
  }
3990
4130
  }
3991
- function Hr() {
4131
+ function Xr() {
3992
4132
  let e = window.HAVIK_EMBED_CONFIG;
3993
4133
  if (e) return {
3994
4134
  baseUrl: e.baseUrl ?? "",
@@ -3998,7 +4138,7 @@ function Hr() {
3998
4138
  autoplay: e.autoplay ?? !0,
3999
4139
  muted: e.muted ?? !0,
4000
4140
  waitForLive: e.waitForLive ?? !0,
4001
- analytics: Vr(e.analytics)
4141
+ analytics: Yr(e.analytics)
4002
4142
  };
4003
4143
  let t = new URLSearchParams(location.search);
4004
4144
  return {
@@ -4011,9 +4151,9 @@ function Hr() {
4011
4151
  waitForLive: !0
4012
4152
  };
4013
4153
  }
4014
- async function Ur() {
4015
- let e = Hr();
4016
- Gr();
4154
+ async function Zr() {
4155
+ let e = Xr();
4156
+ $r();
4017
4157
  let t = document.createElement("video");
4018
4158
  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);
4019
4159
  let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
@@ -4069,12 +4209,12 @@ async function Ur() {
4069
4209
  message: e.message,
4070
4210
  ...e.country === void 0 ? {} : { country: e.country }
4071
4211
  })), e.on("autoplayblocked", () => {
4072
- i({ type: "oddin:autoplayblocked" }), Wr(t, e);
4212
+ i({ type: "oddin:autoplayblocked" }), Qr(t, e);
4073
4213
  });
4074
4214
  }, s = async (r) => {
4075
4215
  a?.destroy(), a = null;
4076
4216
  try {
4077
- let n = await Ir({
4217
+ let n = await Wr({
4078
4218
  video: t,
4079
4219
  baseUrl: e.baseUrl,
4080
4220
  matchUrn: r,
@@ -4137,30 +4277,30 @@ async function Ur() {
4137
4277
  a?.retry();
4138
4278
  break;
4139
4279
  case "oddin:load":
4140
- typeof e.matchUrn == "string" && Br.test(e.matchUrn) && s(e.matchUrn);
4280
+ typeof e.matchUrn == "string" && Jr.test(e.matchUrn) && s(e.matchUrn);
4141
4281
  break;
4142
4282
  case "oddin:destroy": c();
4143
4283
  }
4144
4284
  }, u = (e) => {
4145
- r && e.origin === r && Rr(e.data) && l(e.data);
4285
+ r && e.origin === r && Kr(e.data) && l(e.data);
4146
4286
  };
4147
4287
  r && window.addEventListener("message", u), window.addEventListener("pagehide", c, { once: !0 }), await s(e.matchUrn), i({
4148
4288
  type: "oddin:ready",
4149
4289
  protocol: 1
4150
4290
  });
4151
4291
  }
4152
- function Wr(e, t) {
4292
+ function Qr(e, t) {
4153
4293
  if (document.getElementById("havik-tap")) return;
4154
4294
  let n = document.createElement("button");
4155
4295
  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", () => {
4156
4296
  n.remove(), t.play();
4157
4297
  }), document.body.appendChild(n);
4158
4298
  }
4159
- function Gr() {
4299
+ function $r() {
4160
4300
  let e = document.createElement("style");
4161
4301
  e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
4162
4302
  }
4163
4303
  //#endregion
4164
- export { E as LiveStateHttpError, cr as ODDIN_THEME, n as PlaybackError, ur as applyTheme, ot as baseUrlForEnv, Ur as bootEmbed, De as clearDeviceId, ze as clearRememberedBandwidth, Ir as createPlayer, O as deriveEventsBaseUrl, nt as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, ve as fetchCatalog, be as fetchTournament, Se as flattenMatches, C as fullscreenSupported, j as getDeviceId, it as isLowLatencyManifest, Rr as isOddinMessage, ke as licenseRequestHeaders, zr as mountEmbed, fe as pollToLive, y as resolveStream, D as subscribeLiveState, S as videoFullscreenActive, we as watchStatus };
4304
+ export { w as LiveStateHttpError, mr as ODDIN_THEME, n as PlaybackError, gr as applyTheme, ct as baseUrlForEnv, Zr as bootEmbed, ke as clearDeviceId, Ve as clearRememberedBandwidth, Wr as createPlayer, E as deriveEventsBaseUrl, it as detectDrmSupport, S as enterVideoFullscreen, C as exitVideoFullscreen, be as fetchCatalog, Se as fetchTournament, we as flattenMatches, x as fullscreenSupported, k as getDeviceId, ot as isLowLatencyManifest, Kr as isOddinMessage, je as licenseRequestHeaders, qr as mountEmbed, fe as pollToLive, y as resolveStream, T as subscribeLiveState, ye as videoFullscreenActive, Ee as watchStatus };
4165
4305
 
4166
4306
  //# sourceMappingURL=index.js.map