@oddin-gg/havik-player 2.24.0 → 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 He = ["SW_SECURE_DECODE", "SW_SECURE_CRYPTO"];
704
- function Ue(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 P(e, t) {
708
- if (!Ue(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 = He.indexOf(e.robustness);
713
- return n === -1 || He.indexOf(t) > n;
712
+ let n = M.indexOf(e.robustness);
713
+ return n === -1 || M.indexOf(t) > n;
714
714
  });
715
- }, r = He.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 P(e, t) {
721
721
  })));
722
722
  return [...t, ...r];
723
723
  }
724
- function We(e) {
725
- return (t, n) => N() ? navigator.requestMediaKeySystemAccess(t, P(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 F = {
731
+ var P = {
732
732
  video: "SW_SECURE_DECODE",
733
733
  audio: "SW_SECURE_CRYPTO",
734
734
  scheme: "cbcs"
735
735
  };
736
- function Ge(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: F.scheme
741
+ encryptionScheme: P.scheme
742
742
  });
743
- We(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\"", F.audio)],
749
- videoCapabilities: [t("video/mp4; codecs=\"avc1.42e01e\"", F.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 I(e) {
753
- let t = L(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 L(e) {
760
+ function I(e) {
761
761
  return (e ?? "").trim().toLowerCase();
762
762
  }
763
- var Ke = {
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
- }, qe = /* @__PURE__ */ new Map(), R = /* @__PURE__ */ new Map();
769
- function Je(e) {
770
- let t = L(e), n = qe.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 Je(e) {
776
776
  sessionTypes: ["temporary"],
777
777
  videoCapabilities: [{
778
778
  contentType: `video/mp4; codecs="${e.trim()}"`,
779
- robustness: F.video,
780
- encryptionScheme: F.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", P("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) => (R.set(t, e), e));
789
- return qe.set(t, i), i;
788
+ })().then((e) => (L.set(t, e), e));
789
+ return Je.set(t, i), i;
790
790
  }
791
- function Ye() {
792
- if (N()) for (let e of Object.values(Ke)) Je(e);
791
+ function Xe() {
792
+ if (j()) for (let e of Object.values(qe)) Ye(e);
793
793
  }
794
- function Xe(e) {
795
- let t = I(e);
796
- if (t) return t === "avc" ? !0 : R.get(L(e)) ?? R.get(L(Ke[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 Ze = 5e3, Qe = "video/mp4; codecs=\"avc1.42E01E\"", $e = "audio/mp4; codecs=\"mp4a.40.2\"", et = {
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 tt(e) {
804
+ function nt(e) {
805
805
  return e === "fairplay" ? [{
806
806
  initDataTypes: [
807
807
  "sinf",
@@ -809,30 +809,30 @@ function tt(e) {
809
809
  "cenc"
810
810
  ],
811
811
  videoCapabilities: [{
812
- contentType: Qe,
812
+ contentType: $e,
813
813
  robustness: "",
814
814
  encryptionScheme: "cbcs"
815
815
  }],
816
816
  audioCapabilities: [{
817
- contentType: $e,
817
+ contentType: et,
818
818
  robustness: "",
819
819
  encryptionScheme: "cbcs"
820
820
  }]
821
- }] : P("com.widevine.alpha", [{
821
+ }] : N("com.widevine.alpha", [{
822
822
  initDataTypes: ["cenc"],
823
823
  videoCapabilities: [{
824
- contentType: Qe,
825
- robustness: F.video,
826
- encryptionScheme: F.scheme
824
+ contentType: $e,
825
+ robustness: P.video,
826
+ encryptionScheme: P.scheme
827
827
  }],
828
828
  audioCapabilities: [{
829
- contentType: $e,
830
- robustness: F.audio,
831
- encryptionScheme: F.scheme
829
+ contentType: et,
830
+ robustness: P.audio,
831
+ encryptionScheme: P.scheme
832
832
  }]
833
833
  }]);
834
834
  }
835
- function nt(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 nt(e, t) {
842
842
  });
843
843
  });
844
844
  }
845
- async function rt(e = {}) {
846
- let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Ze, 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 rt(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 = et[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 rt(e = {}) {
866
866
  break;
867
867
  }
868
868
  try {
869
- return await nt((await nt(i(n, tt(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,37 +890,58 @@ async function rt(e = {}) {
890
890
  }
891
891
  //#endregion
892
892
  //#region src/core/manifest.ts
893
- var it = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
894
- function at(e) {
895
- return it.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 ot = {
899
+ var st = {
900
900
  integration: "https://feed-dev.oddin-video.gg",
901
901
  production: "https://feed.oddin-video.gg"
902
902
  };
903
- function st(e) {
904
- let t = Object.prototype.hasOwnProperty.call(ot, e) ? ot[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 ct = { droppedFrames: 0 };
911
- function lt(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 ut = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
919
- function dt(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" || ut.test(i.name)) && i.startTime >= n) {
923
- let e = lt(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;
@@ -932,7 +953,7 @@ function z(e) {
932
953
  totalFrames: t?.totalVideoFrames ?? 0
933
954
  };
934
955
  }
935
- var ft = class {
956
+ var mt = class {
936
957
  video;
937
958
  baseFrames = 0;
938
959
  baseDropped = 0;
@@ -955,7 +976,7 @@ var ft = class {
955
976
  };
956
977
  }
957
978
  };
958
- function pt(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 pt(e, t) {
972
993
  }
973
994
  //#endregion
974
995
  //#region src/core/engine/native.ts
975
- var mt = 2e3, ht = 3, B = 500, gt = 6e3, _t = .25, vt = 250, yt = .05, bt = 4, xt = 12e3, St = .25, Ct = 1e3;
976
- function wt(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];
@@ -989,7 +1010,7 @@ function H() {
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 Tt() {
1013
+ function Dt() {
993
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;
@@ -1024,7 +1045,7 @@ var U = class {
1024
1045
  frameCounter;
1025
1046
  detachFrames = null;
1026
1047
  constructor(e) {
1027
- this.deps = e, this.frameCounter = new ft(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 U = 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 = Dt(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 U = class {
1073
1094
  };
1074
1095
  this.onEncrypted = (n) => {
1075
1096
  let a = n;
1076
- a.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = wt(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 U = class {
1173
1194
  droppedFrames: t.dropped,
1174
1195
  decodedFrames: t.totalFrames
1175
1196
  };
1176
- if (this.cdnHost ||= dt(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 <= bt, !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
  }
@@ -1194,7 +1215,7 @@ var U = class {
1194
1215
  return;
1195
1216
  }
1196
1217
  let t = this.hiddenSince;
1197
- this.hiddenSince = null, t != null && e - t >= mt && 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));
@@ -1204,7 +1225,7 @@ var U = class {
1204
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
1227
  r += B;
1207
- let a = this.liveEnd(), o = a != null && (e == null || a >= e + _t), s = Math.max(r, t() - n) >= gt;
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;
@@ -1224,9 +1245,9 @@ var U = 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 = Et(e, e.currentTime);
1228
- t != null && ((this.lastBufferedEnd == null || Math.abs(t - this.lastBufferedEnd) >= yt) && (this.bufferedAdvancedAt = W()), this.lastBufferedEnd = t);
1229
- }, vt);
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;
@@ -1234,14 +1255,14 @@ var U = class {
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) >= St;
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 > Ct || 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) > xt && (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,7 +1276,7 @@ var U = 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 = Et(e, e.currentTime) ?? this.lastBufferedEnd;
1279
+ let t = this.liveEnd(), n = Ot(e, e.currentTime) ?? this.lastBufferedEnd;
1259
1280
  if (n != null) {
1260
1281
  let e = this.bufferedAdvancedAt, r = n + (e == null ? 0 : Math.max(0, (W() - e) / 1e3));
1261
1282
  (t == null || r > t) && (t = r);
@@ -1271,7 +1292,7 @@ var U = 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 - ht, 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 {}
@@ -1292,7 +1313,7 @@ var U = class {
1292
1313
  function W() {
1293
1314
  return typeof performance < "u" ? performance.now() : Date.now();
1294
1315
  }
1295
- function Et(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,7 +1322,7 @@ function Et(e, t) {
1301
1322
  }
1302
1323
  return null;
1303
1324
  }
1304
- function Dt(e, t) {
1325
+ function kt(e, t) {
1305
1326
  return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
1306
1327
  }
1307
1328
  //#endregion
@@ -1318,13 +1339,13 @@ function G(e, t = Date.now()) {
1318
1339
  }
1319
1340
  //#endregion
1320
1341
  //#region src/core/drm/xhrBody.ts
1321
- var Ot = 4096;
1322
- function kt(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 > Ot)) 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,7 +1353,7 @@ function kt(e) {
1332
1353
  }
1333
1354
  //#endregion
1334
1355
  //#region src/core/engine/prefetch.ts
1335
- var At = 15e3, jt = 5e3, Mt = 6, Nt = 4e3, Pt = 2;
1356
+ var Mt = 15e3, Nt = 5e3, Pt = 6, Ft = 4e3, It = 2;
1336
1357
  function K(e) {
1337
1358
  try {
1338
1359
  let t = new URL(e);
@@ -1341,7 +1362,7 @@ function K(e) {
1341
1362
  return e;
1342
1363
  }
1343
1364
  }
1344
- var Ft = class {
1365
+ var Lt = class {
1345
1366
  cmcd;
1346
1367
  entries = /* @__PURE__ */ new Map();
1347
1368
  keyed = /* @__PURE__ */ new Set();
@@ -1373,17 +1394,17 @@ var Ft = class {
1373
1394
  let r = K(e);
1374
1395
  if (this.entries.has(r)) return;
1375
1396
  let i = this.perTrack.get(t) ?? 0;
1376
- i >= Mt || (this.perTrack.set(t, i + 1), this.start(r, this.withCmcd(e, t, n), !1, At), this.stats.started += 1);
1397
+ i >= Pt || (this.perTrack.set(t, i + 1), this.start(r, this.withCmcd(e, t, n), !1, Mt), this.stats.started += 1);
1377
1398
  }
1378
1399
  prefetchHint(e, t) {
1379
1400
  let n = K(e);
1380
1401
  if (this.entries.has(n)) return;
1381
1402
  let r = this.hints.get(t) ?? [];
1382
- for (; r.length >= Pt;) {
1403
+ for (; r.length >= It;) {
1383
1404
  let e = r.shift();
1384
1405
  e !== void 0 && this.drop(e) && (this.stats.hintDropped += 1);
1385
1406
  }
1386
- r.push(n), this.hints.set(t, r), this.start(n, this.withCmcd(e, t, "media"), !0, Nt), this.stats.hintStarted += 1;
1407
+ r.push(n), this.hints.set(t, r), this.start(n, this.withCmcd(e, t, "media"), !0, Ft), this.stats.hintStarted += 1;
1387
1408
  }
1388
1409
  dropHints(e) {
1389
1410
  for (let t of this.hints.get(e) ?? []) this.drop(t) && (this.stats.hintDropped += 1);
@@ -1436,14 +1457,14 @@ var Ft = class {
1436
1457
  }
1437
1458
  }
1438
1459
  };
1439
- function It(t) {
1460
+ function Rt(t) {
1440
1461
  let n = e.DefaultConfig?.loader;
1441
1462
  if (typeof n != "function") return;
1442
1463
  class r extends n {
1443
1464
  served = !1;
1444
1465
  cancelled = !1;
1445
1466
  entry;
1446
- stats = Lt();
1467
+ stats = zt();
1447
1468
  load(e, n, r) {
1448
1469
  let i = e.rangeEnd ? void 0 : t.take(e.url);
1449
1470
  if (!i) {
@@ -1455,7 +1476,7 @@ function It(t) {
1455
1476
  i.hint ? t.stats.hintFailed += 1 : t.stats.failed += 1;
1456
1477
  }, s = () => {
1457
1478
  !this.cancelled && this.served && (i.abort.abort(), o(), this.served = !1, this.entry = void 0, super.load(e, n, r));
1458
- }, c = n?.loadPolicy, l = c?.maxTimeToFirstByteMs || jt, u = setTimeout(s, l);
1479
+ }, c = n?.loadPolicy, l = c?.maxTimeToFirstByteMs || Nt, u = setTimeout(s, l);
1459
1480
  i.headers.then(() => {
1460
1481
  clearTimeout(u);
1461
1482
  let e = c?.maxLoadTimeMs;
@@ -1488,7 +1509,7 @@ function It(t) {
1488
1509
  }
1489
1510
  return r;
1490
1511
  }
1491
- function Lt() {
1512
+ function zt() {
1492
1513
  return {
1493
1514
  aborted: !1,
1494
1515
  loaded: 0,
@@ -1512,10 +1533,10 @@ function Lt() {
1512
1533
  }
1513
1534
  };
1514
1535
  }
1515
- function Rt(e) {
1536
+ function Bt(e) {
1516
1537
  return e === "audio" ? "audio" : "main";
1517
1538
  }
1518
- function zt(e, t) {
1539
+ function Vt(e, t) {
1519
1540
  let n = [];
1520
1541
  t.initSegment?.url && !t.initSegment.data && n.push({
1521
1542
  url: t.initSegment.url,
@@ -1532,7 +1553,7 @@ function zt(e, t) {
1532
1553
  });
1533
1554
  return n;
1534
1555
  }
1535
- function Bt(e) {
1556
+ function Ht(e) {
1536
1557
  let t = e, n = t?.preloadHint;
1537
1558
  if (!n || !t?.url || n.TYPE !== "PART" || n["BYTERANGE-START"] !== void 0 || n["BYTERANGE-LENGTH"] !== void 0) return null;
1538
1559
  let r = n.URI;
@@ -1550,11 +1571,11 @@ function q(e, t) {
1550
1571
  }
1551
1572
  //#endregion
1552
1573
  //#region src/core/engine/hls.ts
1553
- function Vt() {
1574
+ function Ut() {
1554
1575
  return e.isSupported();
1555
1576
  }
1556
- var Ht = 3, Ut = 1e6, Wt = 20, Gt = 1e4, Kt = 3, qt = 5, Jt = 3, Yt = 1e4, Xt = 3e4, Zt = 12e3, Qt = 3e3, $t = .02, en = 6e3, tn = .5, nn = 3, rn = .5, an = 1.1, on = .25, sn = 5e3, cn = 4e3, ln = 2, un = 5, dn = 2, fn = 2, pn = 4, mn = 4, hn = 2e3, gn = 3e4, _n = 1, vn = 2;
1557
- function yn(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) {
1558
1579
  if (n <= 0 || t < 0 || t >= e.length) return t;
1559
1580
  let r = (t, n) => e[t].width === e[n].width && e[t].height === e[n].height, i = (t) => {
1560
1581
  for (; t + 1 < e.length && r(t + 1, t);) t++;
@@ -1563,11 +1584,11 @@ function yn(e, t, n) {
1563
1584
  for (let t = 0; t < n && a + 1 < e.length; t++) a = i(a + 1);
1564
1585
  return a;
1565
1586
  }
1566
- var bn = .2, xn = 30, Sn = 2, Cn = 2, wn = 2, Tn = 9, En = .5, Dn = 64, On = 1e4, kn = 8, An = .6, jn = .4, Mn = .4, Nn = 2, Pn = 6e4, J = .5, Fn = 3.5, In = 300;
1567
- function Ln(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) {
1568
1589
  return (e?.part ?? e?.frag)?.stats;
1569
1590
  }
1570
- function Rn() {
1591
+ function Bn() {
1571
1592
  if (typeof navigator > "u") return 0;
1572
1593
  try {
1573
1594
  let e = navigator.connection?.rtt;
@@ -1576,20 +1597,20 @@ function Rn() {
1576
1597
  return 0;
1577
1598
  }
1578
1599
  }
1579
- function zn(e) {
1600
+ function Vn(e) {
1580
1601
  if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
1581
1602
  delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
1582
1603
  return;
1583
1604
  }
1584
- e.liveSyncDuration ??= wn;
1585
- let t = Math.max(12, e.liveSyncDuration + Tn);
1586
- (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), Bn(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);
1587
1608
  }
1588
- function Bn(e, t) {
1609
+ function Hn(e, t) {
1589
1610
  let n = (e, t, n) => Math.min(n, Math.max(t, e));
1590
1611
  e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
1591
1612
  }
1592
- var Vn = class {
1613
+ var Un = class {
1593
1614
  name = "hls";
1594
1615
  hls = null;
1595
1616
  deps;
@@ -1619,6 +1640,8 @@ var Vn = class {
1619
1640
  recoveryResetTimer = null;
1620
1641
  networkRetryTimer = null;
1621
1642
  licenseRetryTimer = null;
1643
+ offlineHold = !1;
1644
+ onOnline = null;
1622
1645
  onVisibility = null;
1623
1646
  onSeeking = null;
1624
1647
  onPause = null;
@@ -1683,7 +1706,7 @@ var Vn = class {
1683
1706
  frameCounter;
1684
1707
  detachFrames = null;
1685
1708
  constructor(e) {
1686
- this.deps = e, this.holdBackEnabled = e.adaptiveHoldBack !== !1, this.frameCounter = new ft(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;
1687
1710
  }
1688
1711
  async load() {
1689
1712
  this.detachFrames ??= this.frameCounter.attach();
@@ -1696,14 +1719,21 @@ var Vn = class {
1696
1719
  });
1697
1720
  return;
1698
1721
  }
1699
- e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ge(r), Ye()), 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 = () => {
1700
1723
  let e = this.hls;
1701
1724
  if (document.visibilityState !== "visible" || !e) return;
1702
1725
  let t = e.liveSyncPosition;
1703
1726
  if (typeof t != "number") return;
1704
1727
  let n = typeof e.targetLatency == "number" && e.targetLatency > 0 ? e.targetLatency : 3;
1705
1728
  t - r.currentTime > Math.max(n * 3, 8) && (r.currentTime = t);
1706
- }, 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 = () => {
1707
1737
  this.clampOverSeek(), this.loadSuspended && (this.resumeLoading(), this.schedulePauseSuspend());
1708
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());
1709
1739
  }
@@ -1719,7 +1749,7 @@ var Vn = class {
1719
1749
  }
1720
1750
  this.loadSuspended = !0;
1721
1751
  }
1722
- }, sn));
1752
+ }, ln));
1723
1753
  }
1724
1754
  resumeLoading() {
1725
1755
  if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
@@ -1751,7 +1781,7 @@ var Vn = class {
1751
1781
  let t = e.liveSyncPosition;
1752
1782
  if (typeof t != "number" || !Number.isFinite(t)) return;
1753
1783
  let { video: n } = this.deps;
1754
- n.currentTime <= t + En || (n.currentTime = t);
1784
+ n.currentTime <= t + On || (n.currentTime = t);
1755
1785
  }
1756
1786
  reanchorPartTimeline(e, t) {
1757
1787
  let { frag: n, part: r } = t;
@@ -1763,7 +1793,7 @@ var Vn = class {
1763
1793
  let o = n.sn, s = i.fragments.find((e) => e && e.sn === o) ?? (i.fragmentHint?.sn === o ? i.fragmentHint : void 0);
1764
1794
  if (!s) return;
1765
1795
  let c = a.startPTS - s.start;
1766
- if (!(!Number.isFinite(c) || Math.abs(c) < $t)) {
1796
+ if (!(!Number.isFinite(c) || Math.abs(c) < tn)) {
1767
1797
  for (let e of i.fragments) e && e.setStart(e.start + c);
1768
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})`);
1769
1799
  }
@@ -1786,12 +1816,12 @@ var Vn = class {
1786
1816
  emeEnabled: !0,
1787
1817
  drmSystems: { ...this.licenseUrl ? { "com.widevine.alpha": { licenseUrl: this.licenseUrl } } : {} },
1788
1818
  drmSystemOptions: {
1789
- videoRobustness: F.video,
1790
- audioRobustness: F.audio,
1791
- videoEncryptionScheme: F.scheme,
1792
- audioEncryptionScheme: F.scheme
1819
+ videoRobustness: P.video,
1820
+ audioRobustness: P.audio,
1821
+ videoEncryptionScheme: P.scheme,
1822
+ audioEncryptionScheme: P.scheme
1793
1823
  },
1794
- ...N() ? { requestMediaKeySystemAccessFunc: We(t) } : {},
1824
+ ...j() ? { requestMediaKeySystemAccessFunc: Ge(t) } : {},
1795
1825
  licenseXhrSetup: (e, t) => {
1796
1826
  let o = performance.now(), s = () => {
1797
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", () => {
@@ -1803,7 +1833,7 @@ var Vn = class {
1803
1833
  return;
1804
1834
  }
1805
1835
  let l = this.hls, u, d = new Promise((e) => {
1806
- u = setTimeout(() => e(void 0), Yt);
1836
+ u = setTimeout(() => e(void 0), Zt);
1807
1837
  });
1808
1838
  return Promise.race([c().catch(() => void 0), d]).finally(() => clearTimeout(u)).then((e) => {
1809
1839
  if (!this.hls || this.hls !== l) throw Error("havik-player: engine torn down during refresh");
@@ -1821,31 +1851,31 @@ var Vn = class {
1821
1851
  this.prefetch?.destroy(), this.prefetch = null;
1822
1852
  let p = !1, m = !1, h = u && this.deps.mediaDuringKey !== !1, g = this.deps.preloadHints === !0;
1823
1853
  if ((h || g) && !f.fLoader) {
1824
- let e = new Ft({
1854
+ let e = new Lt({
1825
1855
  sessionId: n.analytics?.sid,
1826
1856
  contentId: n.matchUrn
1827
- }), t = It(e);
1857
+ }), t = Rt(e);
1828
1858
  t && (this.prefetch = e, p = h, m = g, f.fLoader = t);
1829
1859
  }
1830
- zn(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;
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;
1831
1861
  let _ = new e(f);
1832
1862
  if (this.hls = _, this.armHoldBack(_, f), _.on(e.Events.FRAG_PARSED, (e, t) => this.reanchorPartTimeline(_, t)), _.on(e.Events.MANIFEST_PARSED, () => {
1833
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" });
1834
1864
  }), _.on(e.Events.FRAG_BUFFERED, (e, t) => {
1835
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(() => {
1836
1866
  this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
1837
- }, Xt)));
1867
+ }, Qt)));
1838
1868
  }), _.on(e.Events.FRAG_LOADING, (e, t) => {
1839
1869
  t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
1840
1870
  }), _.on(e.Events.FRAG_LOADED, (e, t) => {
1841
1871
  t?.frag?.type === "main" && (this.mainFragsSinceTick += 1, this.bwFragsLoaded += 1, this.maybeRememberBandwidth(!1));
1842
- let n = t?.frag, r = Ln(t), i = r?.loaded;
1872
+ let n = t?.frag, r = zn(t), i = r?.loaded;
1843
1873
  typeof i == "number" && (this.bytesLoaded += i), !this.reportedFirstBytes && typeof i == "number" && i > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
1844
1874
  let a = r?.loading;
1845
- 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 > Dn && 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);
1846
1876
  let o = n?.url;
1847
1877
  if (o) {
1848
- let e = lt(o);
1878
+ let e = dt(o);
1849
1879
  e && (this.cdnHost = e);
1850
1880
  }
1851
1881
  }), _.on(e.Events.LEVEL_LOADED, (e, t) => {
@@ -1862,8 +1892,8 @@ var Vn = class {
1862
1892
  let i = e;
1863
1893
  if (!i?.live || !i.partList?.length || typeof i.edge != "number") return;
1864
1894
  let a = n.buffered, o = a.length ? a.end(a.length - 1) : 0;
1865
- if (i.edge - o > Ht * (i.partTarget || .5)) return;
1866
- let s = Bt(e);
1895
+ if (i.edge - o > Wt * (i.partTarget || .5)) return;
1896
+ let s = Ht(e);
1867
1897
  s && t.prefetchHint(s, r);
1868
1898
  };
1869
1899
  _.on(e.Events.LEVEL_LOADED, (e, t) => {
@@ -1875,15 +1905,15 @@ var Vn = class {
1875
1905
  if (this.prefetch && p) {
1876
1906
  let t = this.prefetch;
1877
1907
  _.on(e.Events.KEY_LOADING, (e, n) => {
1878
- let r = n?.frag, i = Rt(r?.type);
1879
- if (r && t.isActive(i)) for (let e of zt(_, r)) t.prefetch(e.url, i, e.kind);
1880
- }), _.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(Rt(n?.frag?.type)));
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)));
1881
1911
  }
1882
1912
  _.on(e.Events.KEY_LOADED, () => {
1883
1913
  u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
1884
1914
  }), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
1885
1915
  this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.adaptHoldBack(), this.checkFrameDrops();
1886
- }, Qt), _.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1916
+ }, en), _.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1887
1917
  this.renditionSwitches += 1;
1888
1918
  let n = this.lastLevelIndex >= 0 ? _.levels[this.lastLevelIndex] : void 0, r = _.levels[t.level];
1889
1919
  n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, this.armFrameDropGrace(), l({
@@ -1934,9 +1964,9 @@ var Vn = class {
1934
1964
  let o = e.config ?? {}, s = typeof self < "u" && self.devicePixelRatio > 0 ? self.devicePixelRatio : 1, c = o.ignoreDevicePixelRatio ? 1 : s;
1935
1965
  c = Math.min(c, o.maxDevicePixelRatio ?? Infinity);
1936
1966
  let l = t.getMaxLevelByMediaSize(e.levels, i * c, a * c), u = this.deps.sizeCapHeadroom;
1937
- if (u == null && s >= vn) return l;
1938
- let d = u ?? _n, f = Number.isNaN(d) ? _n : d === Infinity ? e.levels.length : Math.max(0, Math.floor(d));
1939
- return yn(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);
1940
1970
  }
1941
1971
  onMediaResize() {
1942
1972
  if (!this.sizeCapManaged) return;
@@ -1951,7 +1981,7 @@ var Vn = class {
1951
1981
  return;
1952
1982
  }
1953
1983
  this.capTimer && clearTimeout(this.capTimer);
1954
- let t = e > this.sizeCapLevel ? hn : gn;
1984
+ let t = e > this.sizeCapLevel ? _n : vn;
1955
1985
  this.capTimer = setTimeout(() => {
1956
1986
  this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
1957
1987
  }, t);
@@ -1961,9 +1991,9 @@ var Vn = class {
1961
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;
1962
1992
  }
1963
1993
  dropLevelsWidevineCannotPlay(e) {
1964
- this.removeLevelsWhere(e, (e) => Xe(e) !== !0);
1965
- let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && I(e) !== "avc" && !!I(e)));
1966
- for (let n of t) Je(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) => {
1967
1997
  t || this.hls !== e || this.removeLevelsWhere(e, (e) => e === n) && (this.measureLadder(e), this.applySizeCap());
1968
1998
  });
1969
1999
  }
@@ -1971,10 +2001,10 @@ var Vn = class {
1971
2001
  let n = e.levels ?? [], r = [], i = /* @__PURE__ */ new Set();
1972
2002
  if (n.forEach((e, n) => {
1973
2003
  let a = e.videoCodec;
1974
- a && I(a) && t(a) && (r.push(n), i.add(a));
2004
+ a && F(a) && t(a) && (r.push(n), i.add(a));
1975
2005
  }), !r.length) return !1;
1976
2006
  let a = [...i].join(", ");
1977
- if (!n.some((e, t) => r.includes(t) ? !1 : !I(e.videoCodec) || Xe(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;
1978
2008
  for (let t = r.length - 1; t >= 0; --t) e.removeLevel(r[t]);
1979
2009
  return console.info(`havik-player: skipped ${r.length} rendition(s) Widevine cannot play on this browser (${a})`), !0;
1980
2010
  }
@@ -2077,12 +2107,12 @@ var Vn = class {
2077
2107
  this.lastAdvanceMs = Date.now();
2078
2108
  return;
2079
2109
  }
2080
- if (this.loadSuspended) {
2110
+ if (this.loadSuspended || this.offlineHold) {
2081
2111
  this.lastAdvanceMs = Date.now();
2082
2112
  return;
2083
2113
  }
2084
2114
  let e = Date.now() - this.lastAdvanceMs;
2085
- !this.chaseSuspended && e > en && this.suspendChasing(), e > Zt && this.emitEnded("stalled");
2115
+ !this.chaseSuspended && e > nn && this.suspendChasing(), e > $t && this.emitEnded("stalled");
2086
2116
  }
2087
2117
  resetStarvationWindow() {
2088
2118
  this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
@@ -2093,11 +2123,11 @@ var Vn = class {
2093
2123
  checkStarvation() {
2094
2124
  let e = this.hls, { video: t } = this.deps;
2095
2125
  if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended) return;
2096
- if (typeof document < "u" && document.hidden || this.loadSuspended) {
2126
+ if (typeof document < "u" && document.hidden || this.loadSuspended || this.offlineHold) {
2097
2127
  this.resetStarvationWindow();
2098
2128
  return;
2099
2129
  }
2100
- let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < en, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > cn, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = z(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;
2101
2131
  if (this.starvedFrames = c, !a || l) {
2102
2132
  (t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
2103
2133
  return;
@@ -2106,12 +2136,12 @@ var Vn = class {
2106
2136
  this.resetStarvationWindow();
2107
2137
  return;
2108
2138
  }
2109
- 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 > pn && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= dn && (this.clearKick(), this.starvationRebuilds < fn)) {
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)) {
2110
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");
2111
2141
  return;
2112
2142
  }
2113
- let u = i && this.starvedTicks >= ln, d = !i && this.deadTicks >= pn && this.recentMainFrags.reduce((e, t) => e + t, 0) >= mn;
2114
- if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= un))) {
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))) {
2115
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");
2116
2146
  try {
2117
2147
  e.stopLoad(), e.startLoad(-1);
@@ -2122,11 +2152,11 @@ var Vn = class {
2122
2152
  }
2123
2153
  updateCatchUpBand() {
2124
2154
  let e = this.hls;
2125
- if (!e || this.catchUpRate <= 1 || this.chaseSuspended || this.loadSuspended) return;
2155
+ if (!e || this.catchUpRate <= 1 || this.chaseSuspended || this.loadSuspended || this.offlineHold) return;
2126
2156
  let t = e.latency, n = e.targetLatency;
2127
2157
  if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
2128
2158
  let r = t - n;
2129
- !this.catchUpEngaged && r > tn ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= tn && 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);
2130
2160
  let i = this.catchUpEngaged ? this.catchUpRate : 1;
2131
2161
  e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
2132
2162
  }
@@ -2139,19 +2169,19 @@ var Vn = class {
2139
2169
  }), n < 0 ? 0 : n;
2140
2170
  }
2141
2171
  armFrameDropGrace() {
2142
- this.fpsGraceTicks > 0 || (this.fpsGraceTicks = Cn, this.fpsBadTicks = 0);
2172
+ this.fpsGraceTicks > 0 || (this.fpsGraceTicks = Tn, this.fpsBadTicks = 0);
2143
2173
  }
2144
2174
  resetFrameDropWindow() {
2145
2175
  this.fpsLastFrames = -1, this.fpsLastDropped = -1, this.fpsBadTicks = 0;
2146
2176
  }
2147
2177
  checkFrameDrops() {
2148
2178
  let e = this.hls, { video: t } = this.deps;
2149
- 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) {
2150
2180
  this.resetFrameDropWindow();
2151
2181
  return;
2152
2182
  }
2153
2183
  let { totalFrames: n, dropped: r } = z(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
2154
- if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < xn || o < 0) {
2184
+ if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < Cn || o < 0) {
2155
2185
  this.fpsBadTicks = 0;
2156
2186
  return;
2157
2187
  }
@@ -2159,11 +2189,11 @@ var Vn = class {
2159
2189
  --this.fpsGraceTicks, this.fpsBadTicks = 0;
2160
2190
  return;
2161
2191
  }
2162
- if (o <= bn * a) {
2192
+ if (o <= Sn * a) {
2163
2193
  this.fpsBadTicks = 0;
2164
2194
  return;
2165
2195
  }
2166
- if (this.fpsBadTicks += 1, this.fpsBadTicks < Sn) return;
2196
+ if (this.fpsBadTicks += 1, this.fpsBadTicks < wn) return;
2167
2197
  this.fpsBadTicks = 0;
2168
2198
  let s = e.levels, c = s[e.currentLevel];
2169
2199
  if (!c) return;
@@ -2175,27 +2205,27 @@ var Vn = class {
2175
2205
  }
2176
2206
  checkFutileChase() {
2177
2207
  let e = this.hls, { video: t } = this.deps;
2178
- 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) {
2179
2209
  this.resetChaseWindow();
2180
2210
  return;
2181
2211
  }
2182
2212
  let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
2183
- if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(an, 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))) {
2184
2214
  this.resetChaseWindow();
2185
2215
  return;
2186
2216
  }
2187
- if (this.chaseLatency < 0 || this.chaseLatency - n >= rn) {
2217
+ if (this.chaseLatency < 0 || this.chaseLatency - n >= on) {
2188
2218
  this.chaseLatency = n, this.chaseTicks = 0;
2189
2219
  return;
2190
2220
  }
2191
- if (this.chaseTicks += 1, this.chaseTicks < nn) return;
2221
+ if (this.chaseTicks += 1, this.chaseTicks < an) return;
2192
2222
  this.resetChaseWindow();
2193
2223
  let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
2194
2224
  if (!(a > 1)) return;
2195
2225
  let o = e.targetLatency;
2196
2226
  if (typeof o != "number" || !(o > 0)) return;
2197
2227
  let s = Math.min(n, a - 1);
2198
- s < o + on || (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({
2199
2229
  type: "livetargetchange",
2200
2230
  change: {
2201
2231
  targetSeconds: s,
@@ -2212,13 +2242,13 @@ var Vn = class {
2212
2242
  if (!this.holdBackEnabled || this.holdBackPriorChecked || !e || (this.holdBackPriorChecked = !0, this.holdBackApplied > 0 || this.holdBackStepCount > 0)) return;
2213
2243
  let t = e.targetLatency;
2214
2244
  if (this.holdBackBase < 0 && typeof t == "number" && t > 0 && (this.holdBackBase = t), this.holdBackBase < 0) return;
2215
- let n = Rn();
2216
- if (!(n >= In)) return;
2245
+ let n = Bn();
2246
+ if (!(n >= Rn)) return;
2217
2247
  let r = typeof t == "number" && t > 0 ? t : this.holdBackBase, i = Math.min(this.holdBackCeiling(e), this.holdBackBase + J);
2218
2248
  i > r && (this.holdBackStepCount = 1, this.moveHoldBack(e, r, i, "connection-rtt", `connection rtt ${n} ms`));
2219
2249
  }
2220
2250
  holdBackCeiling(e) {
2221
- let t = this.deps.adaptiveHoldBackCeiling, n = typeof t == "number" && Number.isFinite(t) ? t : Fn, 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;
2222
2252
  return r > 1 ? Math.min(n, r - 1) : n;
2223
2253
  }
2224
2254
  sampleHoldBack(e) {
@@ -2227,7 +2257,7 @@ var Vn = class {
2227
2257
  if (t !== "main" && t !== "audio") return;
2228
2258
  let n = e.part ? e.part.duration : this.detectedLowLatency ? 0 : e.frag?.duration;
2229
2259
  if (typeof n != "number" || !(n > 0)) return;
2230
- let r = Ln(e)?.loading;
2260
+ let r = zn(e)?.loading;
2231
2261
  if (!r || !(r.start > 0) || !(r.end > 0)) return;
2232
2262
  let i = r.first > r.start ? r.first : r.end, a = Math.max(0, i - r.start) / (n * 1e3);
2233
2263
  this.holdBackSamples.push({
@@ -2238,24 +2268,24 @@ var Vn = class {
2238
2268
  adaptHoldBack() {
2239
2269
  if (!this.holdBackEnabled) return;
2240
2270
  let e = this.hls;
2241
- 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) {
2242
2272
  this.holdBackSlowTicks = 0, this.holdBackFastSince = 0, this.holdBackSamples = [];
2243
2273
  return;
2244
2274
  }
2245
- let t = Date.now(), n = t - On, r = this.holdBackSamples, i = 0;
2275
+ let t = Date.now(), n = t - An, r = this.holdBackSamples, i = 0;
2246
2276
  for (; i < r.length && r[i].t < n;) i += 1;
2247
2277
  i > 0 && r.splice(0, i);
2248
2278
  let a = e.targetLatency;
2249
2279
  if (typeof a != "number" || !(a > 0)) return;
2250
2280
  this.holdBackBase < 0 && (this.holdBackBase = a);
2251
2281
  let o = this.holdBackBase, s = this.holdBackCeiling(e);
2252
- if (r.length < kn) {
2282
+ if (r.length < jn) {
2253
2283
  this.holdBackSlowTicks = 0;
2254
2284
  return;
2255
2285
  }
2256
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);
2257
- if (l >= An && u >= jn) {
2258
- if (this.holdBackFastSince = 0, this.holdBackSlowTicks += 1, this.holdBackSlowTicks < Nn) return;
2287
+ if (l >= Mn && u >= Nn) {
2288
+ if (this.holdBackFastSince = 0, this.holdBackSlowTicks += 1, this.holdBackSlowTicks < Fn) return;
2259
2289
  this.holdBackSlowTicks = 0;
2260
2290
  let t = Math.ceil((s - o) / J), n = Math.ceil((a - o) / J - 1e-9);
2261
2291
  if (n > this.holdBackStepCount && (this.holdBackStepCount = n), this.holdBackStepCount >= t) return;
@@ -2265,7 +2295,7 @@ var Vn = class {
2265
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)`);
2266
2296
  return;
2267
2297
  }
2268
- if (this.holdBackSlowTicks = 0, l >= Mn) {
2298
+ if (this.holdBackSlowTicks = 0, l >= Pn) {
2269
2299
  this.holdBackFastSince = 0;
2270
2300
  return;
2271
2301
  }
@@ -2273,7 +2303,7 @@ var Vn = class {
2273
2303
  this.holdBackFastSince = t;
2274
2304
  return;
2275
2305
  }
2276
- if (t - this.holdBackFastSince < Pn || (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;
2277
2307
  --this.holdBackStepCount;
2278
2308
  let f = Math.max(o, o + this.holdBackStepCount * J);
2279
2309
  f >= a || this.moveHoldBack(e, a, f, "fast-fetches", `part fetches fast again (p95 first byte ${d} ms per 1 s of media)`);
@@ -2316,17 +2346,17 @@ var Vn = class {
2316
2346
  } catch {}
2317
2347
  }
2318
2348
  startEstimate() {
2319
- return this.deps.rememberBandwidth === !1 ? Ut : Le() ?? Ut;
2349
+ return this.deps.rememberBandwidth === !1 ? Gt : ze() ?? Gt;
2320
2350
  }
2321
2351
  maybeRememberBandwidth(e) {
2322
- if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded < Wt) return;
2352
+ if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded < Kt) return;
2323
2353
  let t = Date.now();
2324
- if (!e && t - this.bwSavedAt < Gt) return;
2354
+ if (!e && t - this.bwSavedAt < qt) return;
2325
2355
  let n = this.hls?.bandwidthEstimate;
2326
- 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));
2327
2357
  }
2328
2358
  destroy() {
2329
- 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) {
2330
2360
  try {
2331
2361
  this.hls.destroy();
2332
2362
  } catch (e) {
@@ -2341,7 +2371,7 @@ var Vn = class {
2341
2371
  scheduleLicenseRetry(t) {
2342
2372
  if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
2343
2373
  let n = t.response?.code ?? 0;
2344
- if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= Jt) return !1;
2374
+ if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= Xt) return !1;
2345
2375
  this.licenseRecoveries += 1;
2346
2376
  let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
2347
2377
  return this.licenseRetryTimer = setTimeout(() => {
@@ -2373,7 +2403,11 @@ var Vn = class {
2373
2403
  return;
2374
2404
  }
2375
2405
  if (t.type === e.ErrorTypes.NETWORK_ERROR) {
2376
- if (this.networkRecoveries < qt) {
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) {
2377
2411
  this.networkRecoveries += 1;
2378
2412
  let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
2379
2413
  this.networkRetryTimer = setTimeout(() => {
@@ -2390,7 +2424,7 @@ var Vn = class {
2390
2424
  return;
2391
2425
  }
2392
2426
  if (t.type === e.ErrorTypes.MEDIA_ERROR) {
2393
- if (this.mediaRecoveries < Kt) {
2427
+ if (this.mediaRecoveries < Jt) {
2394
2428
  this.mediaRecoveries += 1, n.recoverMediaError();
2395
2429
  return;
2396
2430
  }
@@ -2411,18 +2445,18 @@ var Vn = class {
2411
2445
  }
2412
2446
  }
2413
2447
  toError(t, r = "PLAYBACK") {
2414
- 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(kt(t.networkDetails)) : void 0;
2415
- 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);
2416
2450
  }
2417
- }, Hn = 15e3, Un = 6e5, Wn = 3e5, Gn = 100, Y = 1, Kn = 1e3, qn = 3e4, Jn = 1e3, Yn = {
2451
+ }, Wn = 15e3, Gn = 6e5, Kn = 3e5, qn = 100, Y = 1, Jn = 1e3, Yn = 3e4, Xn = 1e3, Zn = {
2418
2452
  inline: "PRESENTATION_INLINE",
2419
2453
  fullscreen: "PRESENTATION_FULLSCREEN",
2420
2454
  pip: "PRESENTATION_PIP"
2421
- }, Xn = {
2455
+ }, Qn = {
2422
2456
  widevine: "KEY_SYSTEM_WIDEVINE",
2423
2457
  fairplay: "KEY_SYSTEM_FAIRPLAY",
2424
2458
  none: "KEY_SYSTEM_NONE"
2425
- }, Zn = /* @__PURE__ */ new Set([
2459
+ }, $n = /* @__PURE__ */ new Set([
2426
2460
  "INVALID_URN",
2427
2461
  "NOT_FOUND",
2428
2462
  "GEO_DENIED",
@@ -2443,7 +2477,7 @@ var Vn = class {
2443
2477
  ended: "PLAYER_STATE_ENDED",
2444
2478
  error: "PLAYER_STATE_ERROR"
2445
2479
  };
2446
- function Qn(e) {
2480
+ function er(e) {
2447
2481
  try {
2448
2482
  let t = new URL(e), [n, ...r] = t.hostname.split(".");
2449
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);
@@ -2451,8 +2485,8 @@ function Qn(e) {
2451
2485
  return;
2452
2486
  }
2453
2487
  }
2454
- var $n = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), er = /* @__PURE__ */ new Set(), Z = /* @__PURE__ */ new Set(), Q = /* @__PURE__ */ new Set(), tr = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
2455
- function nr(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) {
2456
2490
  if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
2457
2491
  let t;
2458
2492
  try {
@@ -2461,19 +2495,19 @@ function nr(e) {
2461
2495
  } catch {
2462
2496
  return;
2463
2497
  }
2464
- if (er.has(t) && !Z.has(t)) {
2465
- Z.add(t), _(tr(new URL(t).origin));
2498
+ if (nr.has(t) && !Z.has(t)) {
2499
+ Z.add(t), _(rr(new URL(t).origin));
2466
2500
  for (let e of Q) e.noteCspBlocked();
2467
2501
  }
2468
2502
  }
2469
- function rr(e, t) {
2503
+ function ar(e, t) {
2470
2504
  return _(t, e), { disabledReason: t };
2471
2505
  }
2472
- function ir(e, t, n) {
2473
- if (n) return t && !$n(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 };
2474
2508
  if (t) return { endpoint: t };
2475
- if (t !== void 0) return rr("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).");
2476
- let r = Qn(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);
2477
2511
  if (r) return { endpoint: r };
2478
2512
  let i;
2479
2513
  try {
@@ -2481,9 +2515,9 @@ function ir(e, t, n) {
2481
2515
  } catch {
2482
2516
  i = e;
2483
2517
  }
2484
- return rr(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).`);
2485
2519
  }
2486
- var ar = class {
2520
+ var sr = class {
2487
2521
  opts;
2488
2522
  url;
2489
2523
  cspKey;
@@ -2565,8 +2599,8 @@ var ar = class {
2565
2599
  constructor(e) {
2566
2600
  this.opts = {
2567
2601
  ...e,
2568
- heartbeatMs: e.heartbeatMs ?? Hn,
2569
- idleMs: e.idleMs ?? Un
2602
+ heartbeatMs: e.heartbeatMs ?? Wn,
2603
+ idleMs: e.idleMs ?? Gn
2570
2604
  }, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
2571
2605
  try {
2572
2606
  let e = new URL(this.url);
@@ -2583,11 +2617,11 @@ var ar = class {
2583
2617
  sdkVersion: this.opts.sdkVersion,
2584
2618
  ...this.opts.environment
2585
2619
  };
2586
- this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Kn), 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 && er.add(this.cspKey), document.addEventListener("securitypolicyviolation", nr), 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());
2587
2621
  }
2588
2622
  checkSuspension(e) {
2589
2623
  if (this.endedFlag || !this.opts.idleMs) return !1;
2590
- let t = Math.max(this.opts.idleMs, Wn);
2624
+ let t = Math.max(this.opts.idleMs, Kn);
2591
2625
  return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
2592
2626
  }
2593
2627
  syncIdle(e) {
@@ -2610,12 +2644,12 @@ var ar = class {
2610
2644
  let a = {
2611
2645
  fromState: X[e] ?? "PLAYER_STATE_UNSPECIFIED",
2612
2646
  toState: X[t] ?? "PLAYER_STATE_UNSPECIFIED",
2613
- presentation: Yn[this.presentation]
2647
+ presentation: Zn[this.presentation]
2614
2648
  }, o = this.causeOf(e, t, i);
2615
2649
  o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
2616
2650
  }
2617
2651
  seekInduced(e) {
2618
- return this.lastSeekMs >= 0 && e - this.lastSeekMs < Jn;
2652
+ return this.lastSeekMs >= 0 && e - this.lastSeekMs < Xn;
2619
2653
  }
2620
2654
  causeOf(e, t, n) {
2621
2655
  if (t === "error") return "TRANSITION_CAUSE_ERROR";
@@ -2689,7 +2723,7 @@ var ar = class {
2689
2723
  let r = n ?? "";
2690
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";
2691
2725
  if (e === "DRM_CLIENT" || e === "DRM_DEVICE_REVOKED") return "ERROR_STAGE_DRM";
2692
- if (Zn.has(e)) return "ERROR_STAGE_RESOLVE";
2726
+ if ($n.has(e)) return "ERROR_STAGE_RESOLVE";
2693
2727
  let i = t ?? "";
2694
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";
2695
2729
  }
@@ -2743,7 +2777,7 @@ var ar = class {
2743
2777
  maybeEmitMediaInfo(e) {
2744
2778
  if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
2745
2779
  let t = {};
2746
- e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = Xn[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);
2747
2781
  let n = JSON.stringify(t);
2748
2782
  n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
2749
2783
  }
@@ -2763,7 +2797,7 @@ var ar = class {
2763
2797
  let c = r?.positionMs ?? 0;
2764
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));
2765
2799
  let l = e !== "END_REASON_ENDED";
2766
- l && this.lastStallMs > 0 && n - this.lastStallMs <= qn && (i.abandonAfterStallMs = Math.max(Y, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= qn && (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);
2767
2801
  let u = r?.decodedFrames ?? this.lastDecoded;
2768
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");
2769
2803
  }
@@ -2783,13 +2817,13 @@ var ar = class {
2783
2817
  };
2784
2818
  }
2785
2819
  noteCspBlocked() {
2786
- this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(tr(new URL(this.url).origin)));
2820
+ this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(rr(new URL(this.url).origin)));
2787
2821
  }
2788
2822
  cspBlocked() {
2789
2823
  return !!this.cspKey && Z.has(this.cspKey);
2790
2824
  }
2791
2825
  enqueue(e) {
2792
- if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > Gn;) {
2826
+ if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > qn;) {
2793
2827
  let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
2794
2828
  this.pending.splice(e >= 0 ? e : 0, 1);
2795
2829
  }
@@ -2816,7 +2850,7 @@ var ar = class {
2816
2850
  };
2817
2851
  //#endregion
2818
2852
  //#region src/core/environment.ts
2819
- function or() {
2853
+ function cr() {
2820
2854
  if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
2821
2855
  let e;
2822
2856
  try {
@@ -2841,14 +2875,14 @@ function or() {
2841
2875
  integration: "INTEGRATION_KIND_IFRAME"
2842
2876
  };
2843
2877
  }
2844
- function sr() {
2878
+ function lr() {
2845
2879
  if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
2846
2880
  let e = navigator.userAgentData, t = e?.platform ?? "";
2847
2881
  if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
2848
2882
  let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
2849
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";
2850
2884
  }
2851
- function cr() {
2885
+ function ur() {
2852
2886
  let e = typeof navigator < "u" ? navigator.connection : void 0;
2853
2887
  if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
2854
2888
  let t = {
@@ -2867,17 +2901,17 @@ function cr() {
2867
2901
  }
2868
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;
2869
2903
  }
2870
- function lr(e) {
2871
- let t = or(), n = {
2872
- deviceClass: sr(),
2904
+ function dr(e) {
2905
+ let t = cr(), n = {
2906
+ deviceClass: lr(),
2873
2907
  integration: t.integration,
2874
- ...cr()
2908
+ ...ur()
2875
2909
  };
2876
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);
2877
2911
  let r = e.getBoundingClientRect?.();
2878
2912
  return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
2879
2913
  }
2880
- async function ur() {
2914
+ async function fr() {
2881
2915
  let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
2882
2916
  if (!e?.getHighEntropyValues) return {};
2883
2917
  try {
@@ -2889,7 +2923,7 @@ async function ur() {
2889
2923
  }
2890
2924
  //#endregion
2891
2925
  //#region src/core/version.ts
2892
- var dr = "2.24.0", fr = {
2926
+ var pr = "2.25.0", mr = {
2893
2927
  accent: "#E1B600",
2894
2928
  accentText: "#1B1C23",
2895
2929
  background: "#0e0f13",
@@ -2900,7 +2934,7 @@ var dr = "2.24.0", fr = {
2900
2934
  border: "rgba(255, 255, 255, 0.1)",
2901
2935
  radius: "8px",
2902
2936
  fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
2903
- }, pr = {
2937
+ }, hr = {
2904
2938
  accent: "--havik-accent",
2905
2939
  accentText: "--havik-accent-text",
2906
2940
  background: "--havik-bg",
@@ -2912,26 +2946,26 @@ var dr = "2.24.0", fr = {
2912
2946
  radius: "--havik-radius",
2913
2947
  fontFamily: "--havik-font"
2914
2948
  };
2915
- function mr(e, t) {
2949
+ function gr(e, t) {
2916
2950
  let n = {
2917
- ...fr,
2951
+ ...mr,
2918
2952
  ...t
2919
2953
  };
2920
- for (let t of Object.keys(pr)) e.style.setProperty(pr[t], n[t]);
2954
+ for (let t of Object.keys(hr)) e.style.setProperty(hr[t], n[t]);
2921
2955
  n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
2922
2956
  }
2923
2957
  //#endregion
2924
2958
  //#region src/ui/styles.ts
2925
- var hr = "havik-player-styles", gr = "\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", _r = /* @__PURE__ */ new WeakMap();
2926
- function vr(e = document, t) {
2927
- let n = e.querySelector(`style#${hr}`);
2928
- if (n && (!t || _r.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;
2929
2963
  let r = e.createElement("style");
2930
- r.id = hr, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = gr, _r.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);
2931
2965
  }
2932
2966
  //#endregion
2933
2967
  //#region src/ui/icons.ts
2934
- var yr = {
2968
+ var xr = {
2935
2969
  play: "<path d=\"M8 5v14l11-7z\"/>",
2936
2970
  pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
2937
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\"/>",
@@ -2945,11 +2979,11 @@ var yr = {
2945
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\"/>"
2946
2980
  };
2947
2981
  function $(e) {
2948
- return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${yr[e]}</svg>`;
2982
+ return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${xr[e]}</svg>`;
2949
2983
  }
2950
2984
  //#endregion
2951
2985
  //#region src/ui/controls.ts
2952
- var br = 3e3, xr = 250, Sr = /* @__PURE__ */ new Set([
2986
+ var Sr = 3e3, Cr = 250, wr = /* @__PURE__ */ new Set([
2953
2987
  "GONE",
2954
2988
  "NOT_FOUND",
2955
2989
  "GEO_DENIED",
@@ -2957,15 +2991,15 @@ var br = 3e3, xr = 250, Sr = /* @__PURE__ */ new Set([
2957
2991
  "UNAUTHORIZED",
2958
2992
  "DRM_DEVICE_REVOKED"
2959
2993
  ]);
2960
- function Cr(e) {
2994
+ function Tr(e) {
2961
2995
  let t = "This match isn't available in your country";
2962
2996
  return e ? `${t} (${e})` : t;
2963
2997
  }
2964
- var wr = "This device can't play protected video";
2965
- function Tr(e) {
2966
- return new Er(e);
2998
+ var Er = "This device can't play protected video";
2999
+ function Dr(e) {
3000
+ return new Or(e);
2967
3001
  }
2968
- var Er = class {
3002
+ var Or = class {
2969
3003
  root;
2970
3004
  video;
2971
3005
  player;
@@ -3004,6 +3038,7 @@ var Er = class {
3004
3038
  endedMessage;
3005
3039
  interruptedMessage;
3006
3040
  errorMessage;
3041
+ offlineMessage;
3007
3042
  hideTimer;
3008
3043
  tapTimer;
3009
3044
  surfacePointerType = "";
@@ -3013,7 +3048,7 @@ var Er = class {
3013
3048
  scrubbing = !1;
3014
3049
  offFns = [];
3015
3050
  constructor(e) {
3016
- this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? br, 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, vr(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");
3017
3052
  let t = (e, t, n) => {
3018
3053
  let r = this.doc.createElement(e);
3019
3054
  if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
@@ -3069,7 +3104,7 @@ var Er = class {
3069
3104
  }), this.on(this.muteBtn, "click", () => this.player.setMuted(!e.muted)), this.on(this.volSlider, "input", () => {
3070
3105
  let t = Number(this.volSlider.value);
3071
3106
  this.setVolumeFill(t), this.player.setVolume(t), t > 0 && e.muted && this.player.setMuted(!1);
3072
- }), 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) => {
3073
3108
  this.lastError = e, this.statusKind = null, this.syncState();
3074
3109
  }));
3075
3110
  let t = (e) => e.pointerType !== "touch";
@@ -3099,7 +3134,7 @@ var Er = class {
3099
3134
  let t = this.surfaceWasHidden;
3100
3135
  this.tapTimer = setTimeout(() => {
3101
3136
  this.tapTimer = void 0, this.toggleBar(t);
3102
- }, xr);
3137
+ }, Cr);
3103
3138
  }
3104
3139
  toggleBar(e) {
3105
3140
  e ? this.poke() : this.hideIfIdle();
@@ -3116,10 +3151,14 @@ var Er = class {
3116
3151
  }
3117
3152
  syncStatus(e) {
3118
3153
  let t = null;
3119
- 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);
3120
3159
  }
3121
3160
  statusMessageFor(e) {
3122
- 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" ? Cr(this.lastError.country) : this.lastError?.code === "DRM_DEVICE_REVOKED" ? wr : 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;
3123
3162
  }
3124
3163
  renderStatus(e) {
3125
3164
  let t = this.statusMessageFor(e);
@@ -3134,7 +3173,7 @@ var Er = class {
3134
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);
3135
3174
  } else {
3136
3175
  let r = this.doc.createElement("div");
3137
- if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !Sr.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)) {
3138
3177
  let e = this.doc.createElement("button");
3139
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);
3140
3179
  }
@@ -3175,7 +3214,7 @@ var Er = class {
3175
3214
  let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
3176
3215
  this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
3177
3216
  }
3178
- !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Dr(this.video.currentTime)} / ${Dr(this.video.duration)}`);
3217
+ !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${kr(this.video.currentTime)} / ${kr(this.video.duration)}`);
3179
3218
  }
3180
3219
  syncLive() {
3181
3220
  let e = this.player.getStats(), t = e.isLive !== !1, n = this.player.state === "ended", r = !t && !this.streamEnded();
@@ -3225,17 +3264,17 @@ var Er = class {
3225
3264
  renderQualityMenu() {
3226
3265
  let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
3227
3266
  n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
3228
- for (let n of e) this.menu.append(this.menuItem(Or(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)));
3229
3268
  }
3230
3269
  renderAudioMenu() {
3231
3270
  let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
3232
3271
  t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
3233
- for (let t of e) this.menu.append(this.menuItem(kr(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)));
3234
3273
  }
3235
3274
  renderCcMenu() {
3236
3275
  let e = this.player.getTextTracks(), t = this.doc.createElement("div");
3237
3276
  t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
3238
- for (let t of e) this.menu.append(this.menuItem(Ar(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)));
3239
3278
  }
3240
3279
  onTracksChanged() {
3241
3280
  this.openMenu && this.renderMenu(this.openMenu);
@@ -3255,14 +3294,14 @@ var Er = class {
3255
3294
  }
3256
3295
  async toggleFullscreen() {
3257
3296
  try {
3258
- 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);
3259
3298
  } catch {}
3260
3299
  }
3261
3300
  syncFullscreenSupport() {
3262
- 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";
3263
3302
  }
3264
3303
  syncFullscreen() {
3265
- let e = S(this.video, this.root);
3304
+ let e = ye(this.video, this.root);
3266
3305
  this.setIcon(this.fsBtn, e ? "fullscreenExit" : "fullscreen"), this.fsBtn.setAttribute("aria-label", e ? "Exit fullscreen" : "Fullscreen");
3267
3306
  }
3268
3307
  poke() {
@@ -3340,41 +3379,51 @@ var Er = class {
3340
3379
  this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
3341
3380
  }
3342
3381
  };
3343
- function Dr(e) {
3382
+ function kr(e) {
3344
3383
  (!Number.isFinite(e) || e < 0) && (e = 0);
3345
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");
3346
3385
  return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
3347
3386
  }
3348
- function Or(e) {
3387
+ function Ar(e) {
3349
3388
  return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
3350
3389
  }
3351
- function kr(e) {
3390
+ function jr(e) {
3352
3391
  return e.name || e.lang || `Track ${e.id}`;
3353
3392
  }
3354
- function Ar(e) {
3393
+ function Mr(e) {
3355
3394
  return e.name || e.lang || `Track ${e.id}`;
3356
3395
  }
3357
3396
  //#endregion
3358
3397
  //#region src/managed/index.ts
3359
- var jr = 6e3, Mr = 45e3, Nr = 2e3, Pr = 3, Fr = 5e3, Ir = 2e3, Lr = 48e4, Rr = "keySystemLicenseRequestFailed";
3360
- function zr(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) {
3361
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)})`);
3362
- if (e.env !== void 0) return st(e.env);
3411
+ if (e.env !== void 0) return ct(e.env);
3363
3412
  if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
3364
3413
  return e.baseUrl;
3365
3414
  }
3366
- async function Br(e) {
3415
+ async function Wr(e) {
3367
3416
  if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
3368
- let t = zr(e);
3417
+ let t = Ur(e);
3369
3418
  if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
3370
3419
  if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
3371
- let r = new Vr({
3420
+ let r = new Gr({
3372
3421
  ...e,
3373
3422
  baseUrl: t
3374
3423
  });
3375
3424
  return await r.start(), r;
3376
3425
  }
3377
- var Vr = class {
3426
+ var Gr = class {
3378
3427
  opts;
3379
3428
  abort = new AbortController();
3380
3429
  listeners = {};
@@ -3409,12 +3458,17 @@ var Vr = class {
3409
3458
  playRequested = !1;
3410
3459
  idleClosed = !1;
3411
3460
  pendingStartLoad = !1;
3461
+ connectivity = null;
3462
+ failedWhileOffline = !1;
3412
3463
  constructor(e) {
3413
3464
  this.opts = e;
3414
3465
  }
3415
3466
  get state() {
3416
3467
  return this._state;
3417
3468
  }
3469
+ get offline() {
3470
+ return !R();
3471
+ }
3418
3472
  get descriptor() {
3419
3473
  return this._descriptor;
3420
3474
  }
@@ -3422,7 +3476,7 @@ var Vr = class {
3422
3476
  return this._endedReason;
3423
3477
  }
3424
3478
  async start() {
3425
- 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");
3426
3480
  let e = ++this.loadGen, t = this.resolveOptions();
3427
3481
  try {
3428
3482
  let n = await v(t);
@@ -3435,7 +3489,7 @@ var Vr = class {
3435
3489
  this.setState("waiting"), this.beginArming(e, t.liveStartsAtMs);
3436
3490
  return;
3437
3491
  }
3438
- throw t;
3492
+ throw this.destroy(), t;
3439
3493
  }
3440
3494
  }
3441
3495
  resolveOptions() {
@@ -3448,7 +3502,7 @@ var Vr = class {
3448
3502
  };
3449
3503
  }
3450
3504
  beginArming(e, t, n = !1) {
3451
- 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);
3452
3506
  r ? this.armWithSse(e, r, t, n) : this.beginArmingByPolling(e);
3453
3507
  }
3454
3508
  beginArmingByPolling(e) {
@@ -3469,7 +3523,7 @@ var Vr = class {
3469
3523
  setTimeout(() => {
3470
3524
  a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
3471
3525
  phase: i ? "unavailable" : "tooEarly",
3472
- retryInMs: Mr,
3526
+ retryInMs: Pr,
3473
3527
  attempt: 1,
3474
3528
  elapsedMs: 0,
3475
3529
  ...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
@@ -3508,13 +3562,13 @@ var Vr = class {
3508
3562
  !a && !p() && h();
3509
3563
  }, e);
3510
3564
  };
3511
- _(jr), this.armingSub = D({
3565
+ _(Nr), this.armingSub = T({
3512
3566
  eventsBaseUrl: t,
3513
3567
  matchUrn: this.opts.matchUrn,
3514
3568
  credential: this.opts.credential,
3515
- onAlive: () => _(Mr),
3569
+ onAlive: () => _(Pr),
3516
3570
  onState: (e) => {
3517
- a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Nr);
3571
+ a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Fr);
3518
3572
  },
3519
3573
  onError: () => h()
3520
3574
  });
@@ -3537,7 +3591,7 @@ var Vr = class {
3537
3591
  let n = await c(this.opts.credential);
3538
3592
  if (this.destroyed || t !== this.loadGen) return;
3539
3593
  this.setState("loading");
3540
- let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = pt(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) => {
3541
3595
  this._state !== "ended" && this._state !== "error" && this.setState(e);
3542
3596
  });
3543
3597
  if (await i.load(), this.destroyed || t !== this.loadGen) {
@@ -3559,26 +3613,26 @@ var Vr = class {
3559
3613
  if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
3560
3614
  let i = e.analytics?.sid;
3561
3615
  if (!i) return;
3562
- let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = ir(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);
3563
3617
  if (!o) {
3564
3618
  s && setTimeout(() => {
3565
3619
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
3566
3620
  }, 0);
3567
3621
  return;
3568
3622
  }
3569
- let c = this.opts.video, l = new ar({
3623
+ let c = this.opts.video, l = new sr({
3570
3624
  endpoint: o,
3571
3625
  sid: i,
3572
3626
  player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
3573
- sdkVersion: dr,
3574
- environment: lr(c),
3627
+ sdkVersion: pr,
3628
+ environment: dr(c),
3575
3629
  idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
3576
3630
  onIdle: () => this.onAnalyticsIdle(t),
3577
3631
  onBlocked: (e) => setTimeout(() => {
3578
3632
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, e));
3579
3633
  }, 0),
3580
3634
  sample: () => {
3581
- let e = this.engine?.getStats() ?? ct, 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;
3582
3636
  return {
3583
3637
  ...e,
3584
3638
  bufferedMs: Math.round(t * 1e3),
@@ -3592,7 +3646,7 @@ var Vr = class {
3592
3646
  let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
3593
3647
  c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
3594
3648
  c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
3595
- }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), ur().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");
3596
3650
  }
3597
3651
  currentPresentation() {
3598
3652
  let e = this.opts.video;
@@ -3607,7 +3661,7 @@ var Vr = class {
3607
3661
  video: this.opts.video,
3608
3662
  descriptor: e,
3609
3663
  credential: t,
3610
- deviceId: j(),
3664
+ deviceId: k(),
3611
3665
  userId: this.opts.userId,
3612
3666
  lowLatency: this.opts.lowLatency === void 0 || this.opts.lowLatency === "auto" || this.opts.lowLatency,
3613
3667
  snapToLiveOnRefocus: this.opts.snapToLiveOnRefocus,
@@ -3624,9 +3678,9 @@ var Vr = class {
3624
3678
  freshLicenseUrl: () => this.refreshLicense()
3625
3679
  }, o = this.opts.engine ?? "auto";
3626
3680
  if (o === "native") return new U(a);
3627
- if (o === "hls") return new Vn(a);
3628
- if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && V(this.opts.video) && H() || !e.drmEnabled && Tt() && V(this.opts.video)) return new U(a);
3629
- if (Vt()) return new Vn(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);
3630
3684
  if (V(this.opts.video)) return new U(a);
3631
3685
  throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
3632
3686
  }
@@ -3677,11 +3731,11 @@ var Vr = class {
3677
3731
  }
3678
3732
  startLiveState(e) {
3679
3733
  if (this.opts.liveStateEvents === !1) return;
3680
- let t = this.opts.eventsBaseUrl ?? O(this.opts.baseUrl);
3734
+ let t = this.opts.eventsBaseUrl ?? E(this.opts.baseUrl);
3681
3735
  if (!t) return;
3682
3736
  this.closeLiveState();
3683
3737
  let i = 0, a = !1;
3684
- this.liveStateSub = D({
3738
+ this.liveStateSub = T({
3685
3739
  eventsBaseUrl: t,
3686
3740
  matchUrn: this.opts.matchUrn,
3687
3741
  credential: this.opts.credential,
@@ -3693,11 +3747,11 @@ var Vr = class {
3693
3747
  },
3694
3748
  onError: (o) => {
3695
3749
  if (!(this.destroyed || e !== this.loadGen || a) && !this.endedHandled) {
3696
- if (o instanceof E && (o.terminal || o.status === 404)) {
3750
+ if (o instanceof w && (o.terminal || o.status === 404)) {
3697
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."));
3698
3752
  return;
3699
3753
  }
3700
- i += 1, i >= Pr && (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.`)));
3701
3755
  }
3702
3756
  }
3703
3757
  });
@@ -3705,6 +3759,18 @@ var Vr = class {
3705
3759
  closeLiveState() {
3706
3760
  this.liveStateSub?.close(), this.liveStateSub = null;
3707
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
+ }
3708
3774
  watchReturn() {
3709
3775
  this.onReturnVisible || typeof document > "u" || this.opts.liveStateEvents !== !1 && (document.visibilityState === "hidden" && (this.hiddenAtMs = Date.now()), this.onReturnVisible = () => {
3710
3776
  if (document.visibilityState === "hidden") {
@@ -3712,7 +3778,7 @@ var Vr = class {
3712
3778
  return;
3713
3779
  }
3714
3780
  let e = this.hiddenAtMs;
3715
- this.hiddenAtMs = null, e != null && Date.now() - e >= Fr && this.resyncLiveState();
3781
+ this.hiddenAtMs = null, e != null && Date.now() - e >= Lr && this.resyncLiveState();
3716
3782
  }, this.onReturnPageShow = (e) => {
3717
3783
  e.persisted && this.resyncLiveState();
3718
3784
  }, document.addEventListener("visibilitychange", this.onReturnVisible), typeof window < "u" && window.addEventListener("pageshow", this.onReturnPageShow));
@@ -3744,7 +3810,7 @@ var Vr = class {
3744
3810
  scheduleRejoin(e) {
3745
3811
  this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
3746
3812
  this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
3747
- }, Math.random() * Nr));
3813
+ }, Math.random() * Fr));
3748
3814
  }
3749
3815
  cancelRejoin() {
3750
3816
  this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
@@ -3768,7 +3834,7 @@ var Vr = class {
3768
3834
  }
3769
3835
  t.controls = !1;
3770
3836
  let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
3771
- r && r.insertBefore(n, t), n.appendChild(t), mr(n, this.opts.theme), this.container = n, this.controlBar = Tr({
3837
+ r && r.insertBefore(n, t), n.appendChild(t), gr(n, this.opts.theme), this.container = n, this.controlBar = Dr({
3772
3838
  root: n,
3773
3839
  video: t,
3774
3840
  player: this,
@@ -3778,6 +3844,7 @@ var Vr = class {
3778
3844
  streamEnded: () => this.streamEnded,
3779
3845
  interruptedMessage: this.opts.interruptedMessage,
3780
3846
  errorMessage: this.opts.errorMessage,
3847
+ offlineMessage: this.opts.offlineMessage,
3781
3848
  cspNonce: this.opts.cspNonce
3782
3849
  });
3783
3850
  }
@@ -3806,7 +3873,7 @@ var Vr = class {
3806
3873
  }
3807
3874
  startStats() {
3808
3875
  this.stopStats();
3809
- let e = Math.max(500, this.opts.statsIntervalMs ?? Ir);
3876
+ let e = Math.max(500, this.opts.statsIntervalMs ?? Rr);
3810
3877
  this.statsTimer = setInterval(() => {
3811
3878
  if (!this.engine) return;
3812
3879
  let e = this.engine.getStats();
@@ -3817,14 +3884,14 @@ var Vr = class {
3817
3884
  this.statsTimer && clearInterval(this.statsTimer), this.statsTimer = void 0;
3818
3885
  }
3819
3886
  isStaleLicenseDenial(e) {
3820
- return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== Rr || e.error.httpStatus !== 403 || e.error.code !== "FORBIDDEN" || e.error.serverCode === "license_refused" ? !1 : G(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);
3821
3888
  }
3822
3889
  scheduleLicenseRefresh() {
3823
3890
  if (this.stopRefresh(), !this._descriptor?.drmEnabled) return;
3824
3891
  typeof document < "u" && this.engine?.name === "hls" && (this.onRefocus = () => {
3825
3892
  document.visibilityState !== "visible" || this.destroyed || G(this._descriptor?.drm?.widevine?.licenseUrl) && this.refreshLicense();
3826
3893
  }, document.addEventListener("visibilitychange", this.onRefocus));
3827
- let e = this.opts.licenseRefreshMs ?? Lr;
3894
+ let e = this.opts.licenseRefreshMs ?? zr;
3828
3895
  e && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
3829
3896
  }
3830
3897
  stopRefresh() {
@@ -3881,7 +3948,7 @@ var Vr = class {
3881
3948
  this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
3882
3949
  }
3883
3950
  getStats() {
3884
- return this.engine?.getStats() ?? ct;
3951
+ return this.engine?.getStats() ?? ut;
3885
3952
  }
3886
3953
  getQualityLevels() {
3887
3954
  return this.engine?.getQualityLevels() ?? [];
@@ -3920,13 +3987,13 @@ var Vr = class {
3920
3987
  e.pictureInPictureElement === this.opts.video && typeof e.exitPictureInPicture == "function" && await e.exitPictureInPicture();
3921
3988
  }
3922
3989
  async enterFullscreen() {
3923
- return !this.destroyed && w(this.opts.video, this.container ?? void 0);
3990
+ return !this.destroyed && S(this.opts.video, this.container ?? void 0);
3924
3991
  }
3925
3992
  async exitFullscreen() {
3926
- await T(this.opts.video, this.container ?? void 0);
3993
+ await C(this.opts.video, this.container ?? void 0);
3927
3994
  }
3928
3995
  fullscreenSupported() {
3929
- return !this.destroyed && C(this.opts.video, this.container ?? void 0);
3996
+ return !this.destroyed && x(this.opts.video, this.container ?? void 0);
3930
3997
  }
3931
3998
  retry() {
3932
3999
  return this.reload();
@@ -3951,13 +4018,13 @@ var Vr = class {
3951
4018
  return n.add(t), () => n.delete(t);
3952
4019
  }
3953
4020
  destroy() {
3954
- 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());
3955
4022
  }
3956
4023
  clearListeners() {
3957
4024
  for (let e of Object.keys(this.listeners)) this.listeners[e]?.clear();
3958
4025
  }
3959
4026
  fail(e) {
3960
- 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);
3961
4028
  }
3962
4029
  setState(e) {
3963
4030
  if (e === this._state) return;
@@ -3989,12 +4056,12 @@ var Vr = class {
3989
4056
  };
3990
4057
  //#endregion
3991
4058
  //#region src/embed/protocol.ts
3992
- function Hr(e) {
4059
+ function Kr(e) {
3993
4060
  return !!e && typeof e == "object" && typeof e.type == "string" && e.type.startsWith("oddin:");
3994
4061
  }
3995
4062
  //#endregion
3996
4063
  //#region src/embed/host.ts
3997
- function Ur(e) {
4064
+ function qr(e) {
3998
4065
  if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
3999
4066
  if (!e.src) throw Error("mountEmbed: opts.src is required");
4000
4067
  if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
@@ -4003,7 +4070,7 @@ function Ur(e) {
4003
4070
  let r = document.createElement("iframe");
4004
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);
4005
4072
  let i = /* @__PURE__ */ new Set(), a = (t) => {
4006
- if (t.source !== r.contentWindow || t.origin !== n || !Hr(t.data)) return;
4073
+ if (t.source !== r.contentWindow || t.origin !== n || !Kr(t.data)) return;
4007
4074
  let a = t.data;
4008
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));
4009
4076
  };
@@ -4053,15 +4120,15 @@ function Ur(e) {
4053
4120
  }
4054
4121
  //#endregion
4055
4122
  //#region src/embed/page.ts
4056
- var Wr = /^[A-Za-z0-9:_.-]{1,128}$/;
4057
- function Gr(e) {
4123
+ var Jr = /^[A-Za-z0-9:_.-]{1,128}$/;
4124
+ function Yr(e) {
4058
4125
  if (typeof e == "boolean") return e;
4059
4126
  if (typeof e == "object" && e) {
4060
4127
  let t = e.endpoint;
4061
4128
  return typeof t == "string" ? { endpoint: t } : {};
4062
4129
  }
4063
4130
  }
4064
- function Kr() {
4131
+ function Xr() {
4065
4132
  let e = window.HAVIK_EMBED_CONFIG;
4066
4133
  if (e) return {
4067
4134
  baseUrl: e.baseUrl ?? "",
@@ -4071,7 +4138,7 @@ function Kr() {
4071
4138
  autoplay: e.autoplay ?? !0,
4072
4139
  muted: e.muted ?? !0,
4073
4140
  waitForLive: e.waitForLive ?? !0,
4074
- analytics: Gr(e.analytics)
4141
+ analytics: Yr(e.analytics)
4075
4142
  };
4076
4143
  let t = new URLSearchParams(location.search);
4077
4144
  return {
@@ -4084,9 +4151,9 @@ function Kr() {
4084
4151
  waitForLive: !0
4085
4152
  };
4086
4153
  }
4087
- async function qr() {
4088
- let e = Kr();
4089
- Yr();
4154
+ async function Zr() {
4155
+ let e = Xr();
4156
+ $r();
4090
4157
  let t = document.createElement("video");
4091
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);
4092
4159
  let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
@@ -4142,12 +4209,12 @@ async function qr() {
4142
4209
  message: e.message,
4143
4210
  ...e.country === void 0 ? {} : { country: e.country }
4144
4211
  })), e.on("autoplayblocked", () => {
4145
- i({ type: "oddin:autoplayblocked" }), Jr(t, e);
4212
+ i({ type: "oddin:autoplayblocked" }), Qr(t, e);
4146
4213
  });
4147
4214
  }, s = async (r) => {
4148
4215
  a?.destroy(), a = null;
4149
4216
  try {
4150
- let n = await Br({
4217
+ let n = await Wr({
4151
4218
  video: t,
4152
4219
  baseUrl: e.baseUrl,
4153
4220
  matchUrn: r,
@@ -4210,30 +4277,30 @@ async function qr() {
4210
4277
  a?.retry();
4211
4278
  break;
4212
4279
  case "oddin:load":
4213
- typeof e.matchUrn == "string" && Wr.test(e.matchUrn) && s(e.matchUrn);
4280
+ typeof e.matchUrn == "string" && Jr.test(e.matchUrn) && s(e.matchUrn);
4214
4281
  break;
4215
4282
  case "oddin:destroy": c();
4216
4283
  }
4217
4284
  }, u = (e) => {
4218
- r && e.origin === r && Hr(e.data) && l(e.data);
4285
+ r && e.origin === r && Kr(e.data) && l(e.data);
4219
4286
  };
4220
4287
  r && window.addEventListener("message", u), window.addEventListener("pagehide", c, { once: !0 }), await s(e.matchUrn), i({
4221
4288
  type: "oddin:ready",
4222
4289
  protocol: 1
4223
4290
  });
4224
4291
  }
4225
- function Jr(e, t) {
4292
+ function Qr(e, t) {
4226
4293
  if (document.getElementById("havik-tap")) return;
4227
4294
  let n = document.createElement("button");
4228
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", () => {
4229
4296
  n.remove(), t.play();
4230
4297
  }), document.body.appendChild(n);
4231
4298
  }
4232
- function Yr() {
4299
+ function $r() {
4233
4300
  let e = document.createElement("style");
4234
4301
  e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
4235
4302
  }
4236
4303
  //#endregion
4237
- export { E as LiveStateHttpError, fr as ODDIN_THEME, n as PlaybackError, mr as applyTheme, st as baseUrlForEnv, qr as bootEmbed, De as clearDeviceId, ze as clearRememberedBandwidth, Br as createPlayer, O as deriveEventsBaseUrl, rt as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, ve as fetchCatalog, be as fetchTournament, Se as flattenMatches, C as fullscreenSupported, j as getDeviceId, at as isLowLatencyManifest, Hr as isOddinMessage, ke as licenseRequestHeaders, Ur 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 };
4238
4305
 
4239
4306
  //# sourceMappingURL=index.js.map