@oddin-gg/havik-player 2.24.0 → 2.25.1

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
@@ -315,25 +315,25 @@ function x(e) {
315
315
  function _e(e) {
316
316
  return e.fullscreenElement ?? e.webkitFullscreenElement ?? null;
317
317
  }
318
- function S(e, t) {
318
+ function ve(e, t) {
319
319
  let n = _e(x(e));
320
320
  return n != null && (n === e || t != null && n === t) || e.webkitDisplayingFullscreen === !0;
321
321
  }
322
- function C(e, t) {
322
+ function ye(e, t) {
323
323
  let n = t ?? e, r = x(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?.();
@@ -344,7 +344,7 @@ async function T(e, t) {
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,9 @@ var Vn = class {
1619
1640
  recoveryResetTimer = null;
1620
1641
  networkRetryTimer = null;
1621
1642
  licenseRetryTimer = null;
1643
+ offlineHold = !1;
1644
+ onOffline = null;
1645
+ onOnline = null;
1622
1646
  onVisibility = null;
1623
1647
  onSeeking = null;
1624
1648
  onPause = null;
@@ -1683,7 +1707,7 @@ var Vn = class {
1683
1707
  frameCounter;
1684
1708
  detachFrames = null;
1685
1709
  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;
1710
+ 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
1711
  }
1688
1712
  async load() {
1689
1713
  this.detachFrames ??= this.frameCounter.attach();
@@ -1696,14 +1720,23 @@ var Vn = class {
1696
1720
  });
1697
1721
  return;
1698
1722
  }
1699
- e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ge(r), Ye()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1723
+ e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ke(r), Xe()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1700
1724
  let e = this.hls;
1701
1725
  if (document.visibilityState !== "visible" || !e) return;
1702
1726
  let t = e.liveSyncPosition;
1703
1727
  if (typeof t != "number") return;
1704
1728
  let n = typeof e.targetLatency == "number" && e.targetLatency > 0 ? e.targetLatency : 3;
1705
1729
  t - r.currentTime > Math.max(n * 3, 8) && (r.currentTime = t);
1706
- }, document.addEventListener("visibilitychange", this.onVisibility)), this.onSeeking = () => {
1730
+ }, document.addEventListener("visibilitychange", this.onVisibility)), typeof window < "u" && (this.onOffline = () => {
1731
+ this.offlineHold = !0, this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null), this.lastAdvanceMs = this.lastAdvanceMs ? Date.now() : 0, this.resetStarvationWindow(), this.clearKick();
1732
+ }, this.onOnline = () => {
1733
+ if (this.offlineHold && (this.offlineHold = !1, this.networkRecoveries = 0, this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null), !this.stopped && this.hls && this.loadStarted && !this.loadSuspended)) {
1734
+ this.lastAdvanceMs = Date.now(), this.lastFragLoadingMs = 0, this.resetStarvationWindow(), this.resetChaseWindow(), this.clearKick();
1735
+ try {
1736
+ this.hls.startLoad(-1);
1737
+ } catch {}
1738
+ }
1739
+ }, window.addEventListener("offline", this.onOffline), window.addEventListener("online", this.onOnline), R() || this.onOffline()), this.onSeeking = () => {
1707
1740
  this.clampOverSeek(), this.loadSuspended && (this.resumeLoading(), this.schedulePauseSuspend());
1708
1741
  }, 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
1742
  }
@@ -1719,7 +1752,7 @@ var Vn = class {
1719
1752
  }
1720
1753
  this.loadSuspended = !0;
1721
1754
  }
1722
- }, sn));
1755
+ }, ln));
1723
1756
  }
1724
1757
  resumeLoading() {
1725
1758
  if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
@@ -1751,7 +1784,7 @@ var Vn = class {
1751
1784
  let t = e.liveSyncPosition;
1752
1785
  if (typeof t != "number" || !Number.isFinite(t)) return;
1753
1786
  let { video: n } = this.deps;
1754
- n.currentTime <= t + En || (n.currentTime = t);
1787
+ n.currentTime <= t + On || (n.currentTime = t);
1755
1788
  }
1756
1789
  reanchorPartTimeline(e, t) {
1757
1790
  let { frag: n, part: r } = t;
@@ -1763,7 +1796,7 @@ var Vn = class {
1763
1796
  let o = n.sn, s = i.fragments.find((e) => e && e.sn === o) ?? (i.fragmentHint?.sn === o ? i.fragmentHint : void 0);
1764
1797
  if (!s) return;
1765
1798
  let c = a.startPTS - s.start;
1766
- if (!(!Number.isFinite(c) || Math.abs(c) < $t)) {
1799
+ if (!(!Number.isFinite(c) || Math.abs(c) < tn)) {
1767
1800
  for (let e of i.fragments) e && e.setStart(e.start + c);
1768
1801
  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
1802
  }
@@ -1786,12 +1819,12 @@ var Vn = class {
1786
1819
  emeEnabled: !0,
1787
1820
  drmSystems: { ...this.licenseUrl ? { "com.widevine.alpha": { licenseUrl: this.licenseUrl } } : {} },
1788
1821
  drmSystemOptions: {
1789
- videoRobustness: F.video,
1790
- audioRobustness: F.audio,
1791
- videoEncryptionScheme: F.scheme,
1792
- audioEncryptionScheme: F.scheme
1822
+ videoRobustness: P.video,
1823
+ audioRobustness: P.audio,
1824
+ videoEncryptionScheme: P.scheme,
1825
+ audioEncryptionScheme: P.scheme
1793
1826
  },
1794
- ...N() ? { requestMediaKeySystemAccessFunc: We(t) } : {},
1827
+ ...j() ? { requestMediaKeySystemAccessFunc: Ge(t) } : {},
1795
1828
  licenseXhrSetup: (e, t) => {
1796
1829
  let o = performance.now(), s = () => {
1797
1830
  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 +1836,7 @@ var Vn = class {
1803
1836
  return;
1804
1837
  }
1805
1838
  let l = this.hls, u, d = new Promise((e) => {
1806
- u = setTimeout(() => e(void 0), Yt);
1839
+ u = setTimeout(() => e(void 0), Zt);
1807
1840
  });
1808
1841
  return Promise.race([c().catch(() => void 0), d]).finally(() => clearTimeout(u)).then((e) => {
1809
1842
  if (!this.hls || this.hls !== l) throw Error("havik-player: engine torn down during refresh");
@@ -1821,31 +1854,31 @@ var Vn = class {
1821
1854
  this.prefetch?.destroy(), this.prefetch = null;
1822
1855
  let p = !1, m = !1, h = u && this.deps.mediaDuringKey !== !1, g = this.deps.preloadHints === !0;
1823
1856
  if ((h || g) && !f.fLoader) {
1824
- let e = new Ft({
1857
+ let e = new Lt({
1825
1858
  sessionId: n.analytics?.sid,
1826
1859
  contentId: n.matchUrn
1827
- }), t = It(e);
1860
+ }), t = Rt(e);
1828
1861
  t && (this.prefetch = e, p = h, m = g, f.fLoader = t);
1829
1862
  }
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;
1863
+ 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
1864
  let _ = new e(f);
1832
1865
  if (this.hls = _, this.armHoldBack(_, f), _.on(e.Events.FRAG_PARSED, (e, t) => this.reanchorPartTimeline(_, t)), _.on(e.Events.MANIFEST_PARSED, () => {
1833
1866
  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
1867
  }), _.on(e.Events.FRAG_BUFFERED, (e, t) => {
1835
1868
  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
1869
  this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
1837
- }, Xt)));
1870
+ }, Qt)));
1838
1871
  }), _.on(e.Events.FRAG_LOADING, (e, t) => {
1839
1872
  t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
1840
1873
  }), _.on(e.Events.FRAG_LOADED, (e, t) => {
1841
1874
  t?.frag?.type === "main" && (this.mainFragsSinceTick += 1, this.bwFragsLoaded += 1, this.maybeRememberBandwidth(!1));
1842
- let n = t?.frag, r = Ln(t), i = r?.loaded;
1875
+ let n = t?.frag, r = zn(t), i = r?.loaded;
1843
1876
  typeof i == "number" && (this.bytesLoaded += i), !this.reportedFirstBytes && typeof i == "number" && i > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
1844
1877
  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);
1878
+ 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
1879
  let o = n?.url;
1847
1880
  if (o) {
1848
- let e = lt(o);
1881
+ let e = dt(o);
1849
1882
  e && (this.cdnHost = e);
1850
1883
  }
1851
1884
  }), _.on(e.Events.LEVEL_LOADED, (e, t) => {
@@ -1862,8 +1895,8 @@ var Vn = class {
1862
1895
  let i = e;
1863
1896
  if (!i?.live || !i.partList?.length || typeof i.edge != "number") return;
1864
1897
  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);
1898
+ if (i.edge - o > Wt * (i.partTarget || .5)) return;
1899
+ let s = Ht(e);
1867
1900
  s && t.prefetchHint(s, r);
1868
1901
  };
1869
1902
  _.on(e.Events.LEVEL_LOADED, (e, t) => {
@@ -1875,15 +1908,15 @@ var Vn = class {
1875
1908
  if (this.prefetch && p) {
1876
1909
  let t = this.prefetch;
1877
1910
  _.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)));
1911
+ let r = n?.frag, i = Bt(r?.type);
1912
+ if (r && t.isActive(i)) for (let e of Vt(_, r)) t.prefetch(e.url, i, e.kind);
1913
+ }), _.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(Bt(n?.frag?.type)));
1881
1914
  }
1882
1915
  _.on(e.Events.KEY_LOADED, () => {
1883
1916
  u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
1884
1917
  }), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
1885
1918
  this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.adaptHoldBack(), this.checkFrameDrops();
1886
- }, Qt), _.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1919
+ }, en), _.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1887
1920
  this.renditionSwitches += 1;
1888
1921
  let n = this.lastLevelIndex >= 0 ? _.levels[this.lastLevelIndex] : void 0, r = _.levels[t.level];
1889
1922
  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 +1967,9 @@ var Vn = class {
1934
1967
  let o = e.config ?? {}, s = typeof self < "u" && self.devicePixelRatio > 0 ? self.devicePixelRatio : 1, c = o.ignoreDevicePixelRatio ? 1 : s;
1935
1968
  c = Math.min(c, o.maxDevicePixelRatio ?? Infinity);
1936
1969
  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);
1970
+ if (u == null && s >= bn) return l;
1971
+ let d = u ?? yn, f = Number.isNaN(d) ? yn : d === Infinity ? e.levels.length : Math.max(0, Math.floor(d));
1972
+ return xn(e.levels, l, f);
1940
1973
  }
1941
1974
  onMediaResize() {
1942
1975
  if (!this.sizeCapManaged) return;
@@ -1951,7 +1984,7 @@ var Vn = class {
1951
1984
  return;
1952
1985
  }
1953
1986
  this.capTimer && clearTimeout(this.capTimer);
1954
- let t = e > this.sizeCapLevel ? hn : gn;
1987
+ let t = e > this.sizeCapLevel ? _n : vn;
1955
1988
  this.capTimer = setTimeout(() => {
1956
1989
  this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
1957
1990
  }, t);
@@ -1961,9 +1994,9 @@ var Vn = class {
1961
1994
  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
1995
  }
1963
1996
  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) => {
1997
+ this.removeLevelsWhere(e, (e) => Ze(e) !== !0);
1998
+ let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && F(e) !== "avc" && !!F(e)));
1999
+ for (let n of t) Ye(n).then((t) => {
1967
2000
  t || this.hls !== e || this.removeLevelsWhere(e, (e) => e === n) && (this.measureLadder(e), this.applySizeCap());
1968
2001
  });
1969
2002
  }
@@ -1971,10 +2004,10 @@ var Vn = class {
1971
2004
  let n = e.levels ?? [], r = [], i = /* @__PURE__ */ new Set();
1972
2005
  if (n.forEach((e, n) => {
1973
2006
  let a = e.videoCodec;
1974
- a && I(a) && t(a) && (r.push(n), i.add(a));
2007
+ a && F(a) && t(a) && (r.push(n), i.add(a));
1975
2008
  }), !r.length) return !1;
1976
2009
  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;
2010
+ 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
2011
  for (let t = r.length - 1; t >= 0; --t) e.removeLevel(r[t]);
1979
2012
  return console.info(`havik-player: skipped ${r.length} rendition(s) Widevine cannot play on this browser (${a})`), !0;
1980
2013
  }
@@ -2077,12 +2110,12 @@ var Vn = class {
2077
2110
  this.lastAdvanceMs = Date.now();
2078
2111
  return;
2079
2112
  }
2080
- if (this.loadSuspended) {
2113
+ if (this.loadSuspended || this.offlineHold || !R()) {
2081
2114
  this.lastAdvanceMs = Date.now();
2082
2115
  return;
2083
2116
  }
2084
2117
  let e = Date.now() - this.lastAdvanceMs;
2085
- !this.chaseSuspended && e > en && this.suspendChasing(), e > Zt && this.emitEnded("stalled");
2118
+ !this.chaseSuspended && e > nn && this.suspendChasing(), e > $t && this.emitEnded("stalled");
2086
2119
  }
2087
2120
  resetStarvationWindow() {
2088
2121
  this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
@@ -2093,11 +2126,11 @@ var Vn = class {
2093
2126
  checkStarvation() {
2094
2127
  let e = this.hls, { video: t } = this.deps;
2095
2128
  if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended) return;
2096
- if (typeof document < "u" && document.hidden || this.loadSuspended) {
2129
+ if (typeof document < "u" && document.hidden || this.loadSuspended || this.offlineHold || !R()) {
2097
2130
  this.resetStarvationWindow();
2098
2131
  return;
2099
2132
  }
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;
2133
+ 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
2134
  if (this.starvedFrames = c, !a || l) {
2102
2135
  (t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
2103
2136
  return;
@@ -2106,12 +2139,12 @@ var Vn = class {
2106
2139
  this.resetStarvationWindow();
2107
2140
  return;
2108
2141
  }
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)) {
2142
+ 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
2143
  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
2144
  return;
2112
2145
  }
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))) {
2146
+ let u = i && this.starvedTicks >= dn, d = !i && this.deadTicks >= hn && this.recentMainFrags.reduce((e, t) => e + t, 0) >= gn;
2147
+ if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= fn))) {
2115
2148
  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
2149
  try {
2117
2150
  e.stopLoad(), e.startLoad(-1);
@@ -2122,11 +2155,11 @@ var Vn = class {
2122
2155
  }
2123
2156
  updateCatchUpBand() {
2124
2157
  let e = this.hls;
2125
- if (!e || this.catchUpRate <= 1 || this.chaseSuspended || this.loadSuspended) return;
2158
+ if (!e || this.catchUpRate <= 1 || this.chaseSuspended || this.loadSuspended || this.offlineHold) return;
2126
2159
  let t = e.latency, n = e.targetLatency;
2127
2160
  if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
2128
2161
  let r = t - n;
2129
- !this.catchUpEngaged && r > tn ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= tn && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
2162
+ !this.catchUpEngaged && r > rn ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= rn && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
2130
2163
  let i = this.catchUpEngaged ? this.catchUpRate : 1;
2131
2164
  e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
2132
2165
  }
@@ -2139,19 +2172,19 @@ var Vn = class {
2139
2172
  }), n < 0 ? 0 : n;
2140
2173
  }
2141
2174
  armFrameDropGrace() {
2142
- this.fpsGraceTicks > 0 || (this.fpsGraceTicks = Cn, this.fpsBadTicks = 0);
2175
+ this.fpsGraceTicks > 0 || (this.fpsGraceTicks = Tn, this.fpsBadTicks = 0);
2143
2176
  }
2144
2177
  resetFrameDropWindow() {
2145
2178
  this.fpsLastFrames = -1, this.fpsLastDropped = -1, this.fpsBadTicks = 0;
2146
2179
  }
2147
2180
  checkFrameDrops() {
2148
2181
  let e = this.hls, { video: t } = this.deps;
2149
- if (!e || !this.fpsCapManaged || this.loadSuspended || t.paused || !e.autoLevelEnabled || typeof document < "u" && document.hidden) {
2182
+ if (!e || !this.fpsCapManaged || this.loadSuspended || this.offlineHold || t.paused || !e.autoLevelEnabled || typeof document < "u" && document.hidden) {
2150
2183
  this.resetFrameDropWindow();
2151
2184
  return;
2152
2185
  }
2153
2186
  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) {
2187
+ if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < Cn || o < 0) {
2155
2188
  this.fpsBadTicks = 0;
2156
2189
  return;
2157
2190
  }
@@ -2159,11 +2192,11 @@ var Vn = class {
2159
2192
  --this.fpsGraceTicks, this.fpsBadTicks = 0;
2160
2193
  return;
2161
2194
  }
2162
- if (o <= bn * a) {
2195
+ if (o <= Sn * a) {
2163
2196
  this.fpsBadTicks = 0;
2164
2197
  return;
2165
2198
  }
2166
- if (this.fpsBadTicks += 1, this.fpsBadTicks < Sn) return;
2199
+ if (this.fpsBadTicks += 1, this.fpsBadTicks < wn) return;
2167
2200
  this.fpsBadTicks = 0;
2168
2201
  let s = e.levels, c = s[e.currentLevel];
2169
2202
  if (!c) return;
@@ -2175,27 +2208,27 @@ var Vn = class {
2175
2208
  }
2176
2209
  checkFutileChase() {
2177
2210
  let e = this.hls, { video: t } = this.deps;
2178
- if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended || this.loadSuspended || typeof document < "u" && document.hidden) {
2211
+ if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended || this.loadSuspended || this.offlineHold || typeof document < "u" && document.hidden) {
2179
2212
  this.resetChaseWindow();
2180
2213
  return;
2181
2214
  }
2182
2215
  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))) {
2216
+ if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(sn, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
2184
2217
  this.resetChaseWindow();
2185
2218
  return;
2186
2219
  }
2187
- if (this.chaseLatency < 0 || this.chaseLatency - n >= rn) {
2220
+ if (this.chaseLatency < 0 || this.chaseLatency - n >= on) {
2188
2221
  this.chaseLatency = n, this.chaseTicks = 0;
2189
2222
  return;
2190
2223
  }
2191
- if (this.chaseTicks += 1, this.chaseTicks < nn) return;
2224
+ if (this.chaseTicks += 1, this.chaseTicks < an) return;
2192
2225
  this.resetChaseWindow();
2193
2226
  let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
2194
2227
  if (!(a > 1)) return;
2195
2228
  let o = e.targetLatency;
2196
2229
  if (typeof o != "number" || !(o > 0)) return;
2197
2230
  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({
2231
+ 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
2232
  type: "livetargetchange",
2200
2233
  change: {
2201
2234
  targetSeconds: s,
@@ -2212,13 +2245,13 @@ var Vn = class {
2212
2245
  if (!this.holdBackEnabled || this.holdBackPriorChecked || !e || (this.holdBackPriorChecked = !0, this.holdBackApplied > 0 || this.holdBackStepCount > 0)) return;
2213
2246
  let t = e.targetLatency;
2214
2247
  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;
2248
+ let n = Bn();
2249
+ if (!(n >= Rn)) return;
2217
2250
  let r = typeof t == "number" && t > 0 ? t : this.holdBackBase, i = Math.min(this.holdBackCeiling(e), this.holdBackBase + J);
2218
2251
  i > r && (this.holdBackStepCount = 1, this.moveHoldBack(e, r, i, "connection-rtt", `connection rtt ${n} ms`));
2219
2252
  }
2220
2253
  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;
2254
+ 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
2255
  return r > 1 ? Math.min(n, r - 1) : n;
2223
2256
  }
2224
2257
  sampleHoldBack(e) {
@@ -2227,7 +2260,7 @@ var Vn = class {
2227
2260
  if (t !== "main" && t !== "audio") return;
2228
2261
  let n = e.part ? e.part.duration : this.detectedLowLatency ? 0 : e.frag?.duration;
2229
2262
  if (typeof n != "number" || !(n > 0)) return;
2230
- let r = Ln(e)?.loading;
2263
+ let r = zn(e)?.loading;
2231
2264
  if (!r || !(r.start > 0) || !(r.end > 0)) return;
2232
2265
  let i = r.first > r.start ? r.first : r.end, a = Math.max(0, i - r.start) / (n * 1e3);
2233
2266
  this.holdBackSamples.push({
@@ -2238,24 +2271,24 @@ var Vn = class {
2238
2271
  adaptHoldBack() {
2239
2272
  if (!this.holdBackEnabled) return;
2240
2273
  let e = this.hls;
2241
- if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended || this.loadSuspended || typeof document < "u" && document.hidden) {
2274
+ if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended || this.loadSuspended || this.offlineHold || typeof document < "u" && document.hidden) {
2242
2275
  this.holdBackSlowTicks = 0, this.holdBackFastSince = 0, this.holdBackSamples = [];
2243
2276
  return;
2244
2277
  }
2245
- let t = Date.now(), n = t - On, r = this.holdBackSamples, i = 0;
2278
+ let t = Date.now(), n = t - An, r = this.holdBackSamples, i = 0;
2246
2279
  for (; i < r.length && r[i].t < n;) i += 1;
2247
2280
  i > 0 && r.splice(0, i);
2248
2281
  let a = e.targetLatency;
2249
2282
  if (typeof a != "number" || !(a > 0)) return;
2250
2283
  this.holdBackBase < 0 && (this.holdBackBase = a);
2251
2284
  let o = this.holdBackBase, s = this.holdBackCeiling(e);
2252
- if (r.length < kn) {
2285
+ if (r.length < jn) {
2253
2286
  this.holdBackSlowTicks = 0;
2254
2287
  return;
2255
2288
  }
2256
2289
  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;
2290
+ if (l >= Mn && u >= Nn) {
2291
+ if (this.holdBackFastSince = 0, this.holdBackSlowTicks += 1, this.holdBackSlowTicks < Fn) return;
2259
2292
  this.holdBackSlowTicks = 0;
2260
2293
  let t = Math.ceil((s - o) / J), n = Math.ceil((a - o) / J - 1e-9);
2261
2294
  if (n > this.holdBackStepCount && (this.holdBackStepCount = n), this.holdBackStepCount >= t) return;
@@ -2265,7 +2298,7 @@ var Vn = class {
2265
2298
  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
2299
  return;
2267
2300
  }
2268
- if (this.holdBackSlowTicks = 0, l >= Mn) {
2301
+ if (this.holdBackSlowTicks = 0, l >= Pn) {
2269
2302
  this.holdBackFastSince = 0;
2270
2303
  return;
2271
2304
  }
@@ -2273,7 +2306,7 @@ var Vn = class {
2273
2306
  this.holdBackFastSince = t;
2274
2307
  return;
2275
2308
  }
2276
- if (t - this.holdBackFastSince < Pn || (this.holdBackFastSince = t, this.holdBackStepCount === 0 || a !== this.holdBackApplied)) return;
2309
+ if (t - this.holdBackFastSince < In || (this.holdBackFastSince = t, this.holdBackStepCount === 0 || a !== this.holdBackApplied)) return;
2277
2310
  --this.holdBackStepCount;
2278
2311
  let f = Math.max(o, o + this.holdBackStepCount * J);
2279
2312
  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 +2349,17 @@ var Vn = class {
2316
2349
  } catch {}
2317
2350
  }
2318
2351
  startEstimate() {
2319
- return this.deps.rememberBandwidth === !1 ? Ut : Le() ?? Ut;
2352
+ return this.deps.rememberBandwidth === !1 ? Gt : ze() ?? Gt;
2320
2353
  }
2321
2354
  maybeRememberBandwidth(e) {
2322
- if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded < Wt) return;
2355
+ if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded < Kt) return;
2323
2356
  let t = Date.now();
2324
- if (!e && t - this.bwSavedAt < Gt) return;
2357
+ if (!e && t - this.bwSavedAt < qt) return;
2325
2358
  let n = this.hls?.bandwidthEstimate;
2326
- typeof n != "number" || !Number.isFinite(n) || n <= 0 || (this.bwSavedAt = t, Re(n));
2359
+ typeof n != "number" || !Number.isFinite(n) || n <= 0 || (this.bwSavedAt = t, Be(n));
2327
2360
  }
2328
2361
  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) {
2362
+ 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.onOffline && typeof window < "u" && (window.removeEventListener("offline", this.onOffline), this.onOffline = 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
2363
  try {
2331
2364
  this.hls.destroy();
2332
2365
  } catch (e) {
@@ -2341,7 +2374,7 @@ var Vn = class {
2341
2374
  scheduleLicenseRetry(t) {
2342
2375
  if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
2343
2376
  let n = t.response?.code ?? 0;
2344
- if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= Jt) return !1;
2377
+ if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= Xt) return !1;
2345
2378
  this.licenseRecoveries += 1;
2346
2379
  let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
2347
2380
  return this.licenseRetryTimer = setTimeout(() => {
@@ -2373,7 +2406,11 @@ var Vn = class {
2373
2406
  return;
2374
2407
  }
2375
2408
  if (t.type === e.ErrorTypes.NETWORK_ERROR) {
2376
- if (this.networkRecoveries < qt) {
2409
+ if (!R() && (t.response?.code ?? 0) === 0) {
2410
+ this.offlineHold = !0, this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null);
2411
+ return;
2412
+ }
2413
+ if (this.networkRecoveries < Yt) {
2377
2414
  this.networkRecoveries += 1;
2378
2415
  let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
2379
2416
  this.networkRetryTimer = setTimeout(() => {
@@ -2390,7 +2427,7 @@ var Vn = class {
2390
2427
  return;
2391
2428
  }
2392
2429
  if (t.type === e.ErrorTypes.MEDIA_ERROR) {
2393
- if (this.mediaRecoveries < Kt) {
2430
+ if (this.mediaRecoveries < Jt) {
2394
2431
  this.mediaRecoveries += 1, n.recoverMediaError();
2395
2432
  return;
2396
2433
  }
@@ -2411,18 +2448,18 @@ var Vn = class {
2411
2448
  }
2412
2449
  }
2413
2450
  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);
2451
+ 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;
2452
+ 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
2453
  }
2417
- }, Hn = 15e3, Un = 6e5, Wn = 3e5, Gn = 100, Y = 1, Kn = 1e3, qn = 3e4, Jn = 1e3, Yn = {
2454
+ }, Wn = 15e3, Gn = 6e5, Kn = 3e5, qn = 100, Y = 1, Jn = 1e3, Yn = 3e4, Xn = 1e3, Zn = {
2418
2455
  inline: "PRESENTATION_INLINE",
2419
2456
  fullscreen: "PRESENTATION_FULLSCREEN",
2420
2457
  pip: "PRESENTATION_PIP"
2421
- }, Xn = {
2458
+ }, Qn = {
2422
2459
  widevine: "KEY_SYSTEM_WIDEVINE",
2423
2460
  fairplay: "KEY_SYSTEM_FAIRPLAY",
2424
2461
  none: "KEY_SYSTEM_NONE"
2425
- }, Zn = /* @__PURE__ */ new Set([
2462
+ }, $n = /* @__PURE__ */ new Set([
2426
2463
  "INVALID_URN",
2427
2464
  "NOT_FOUND",
2428
2465
  "GEO_DENIED",
@@ -2443,7 +2480,7 @@ var Vn = class {
2443
2480
  ended: "PLAYER_STATE_ENDED",
2444
2481
  error: "PLAYER_STATE_ERROR"
2445
2482
  };
2446
- function Qn(e) {
2483
+ function er(e) {
2447
2484
  try {
2448
2485
  let t = new URL(e), [n, ...r] = t.hostname.split(".");
2449
2486
  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 +2488,8 @@ function Qn(e) {
2451
2488
  return;
2452
2489
  }
2453
2490
  }
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) {
2491
+ 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.`;
2492
+ function ir(e) {
2456
2493
  if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
2457
2494
  let t;
2458
2495
  try {
@@ -2461,19 +2498,19 @@ function nr(e) {
2461
2498
  } catch {
2462
2499
  return;
2463
2500
  }
2464
- if (er.has(t) && !Z.has(t)) {
2465
- Z.add(t), _(tr(new URL(t).origin));
2501
+ if (nr.has(t) && !Z.has(t)) {
2502
+ Z.add(t), _(rr(new URL(t).origin));
2466
2503
  for (let e of Q) e.noteCspBlocked();
2467
2504
  }
2468
2505
  }
2469
- function rr(e, t) {
2506
+ function ar(e, t) {
2470
2507
  return _(t, e), { disabledReason: t };
2471
2508
  }
2472
- function ir(e, t, n) {
2473
- if (n) return t && !$n(t, n) && _(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
2509
+ function or(e, t, n) {
2510
+ if (n) return t && !tr(t, n) && _(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
2474
2511
  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);
2512
+ 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).");
2513
+ let r = er(e);
2477
2514
  if (r) return { endpoint: r };
2478
2515
  let i;
2479
2516
  try {
@@ -2481,9 +2518,9 @@ function ir(e, t, n) {
2481
2518
  } catch {
2482
2519
  i = e;
2483
2520
  }
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).`);
2521
+ 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
2522
  }
2486
- var ar = class {
2523
+ var sr = class {
2487
2524
  opts;
2488
2525
  url;
2489
2526
  cspKey;
@@ -2565,8 +2602,8 @@ var ar = class {
2565
2602
  constructor(e) {
2566
2603
  this.opts = {
2567
2604
  ...e,
2568
- heartbeatMs: e.heartbeatMs ?? Hn,
2569
- idleMs: e.idleMs ?? Un
2605
+ heartbeatMs: e.heartbeatMs ?? Wn,
2606
+ idleMs: e.idleMs ?? Gn
2570
2607
  }, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
2571
2608
  try {
2572
2609
  let e = new URL(this.url);
@@ -2583,11 +2620,11 @@ var ar = class {
2583
2620
  sdkVersion: this.opts.sdkVersion,
2584
2621
  ...this.opts.environment
2585
2622
  };
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());
2623
+ 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
2624
  }
2588
2625
  checkSuspension(e) {
2589
2626
  if (this.endedFlag || !this.opts.idleMs) return !1;
2590
- let t = Math.max(this.opts.idleMs, Wn);
2627
+ let t = Math.max(this.opts.idleMs, Kn);
2591
2628
  return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
2592
2629
  }
2593
2630
  syncIdle(e) {
@@ -2610,12 +2647,12 @@ var ar = class {
2610
2647
  let a = {
2611
2648
  fromState: X[e] ?? "PLAYER_STATE_UNSPECIFIED",
2612
2649
  toState: X[t] ?? "PLAYER_STATE_UNSPECIFIED",
2613
- presentation: Yn[this.presentation]
2650
+ presentation: Zn[this.presentation]
2614
2651
  }, o = this.causeOf(e, t, i);
2615
2652
  o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
2616
2653
  }
2617
2654
  seekInduced(e) {
2618
- return this.lastSeekMs >= 0 && e - this.lastSeekMs < Jn;
2655
+ return this.lastSeekMs >= 0 && e - this.lastSeekMs < Xn;
2619
2656
  }
2620
2657
  causeOf(e, t, n) {
2621
2658
  if (t === "error") return "TRANSITION_CAUSE_ERROR";
@@ -2689,7 +2726,7 @@ var ar = class {
2689
2726
  let r = n ?? "";
2690
2727
  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
2728
  if (e === "DRM_CLIENT" || e === "DRM_DEVICE_REVOKED") return "ERROR_STAGE_DRM";
2692
- if (Zn.has(e)) return "ERROR_STAGE_RESOLVE";
2729
+ if ($n.has(e)) return "ERROR_STAGE_RESOLVE";
2693
2730
  let i = t ?? "";
2694
2731
  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
2732
  }
@@ -2743,7 +2780,7 @@ var ar = class {
2743
2780
  maybeEmitMediaInfo(e) {
2744
2781
  if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
2745
2782
  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);
2783
+ 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
2784
  let n = JSON.stringify(t);
2748
2785
  n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
2749
2786
  }
@@ -2763,7 +2800,7 @@ var ar = class {
2763
2800
  let c = r?.positionMs ?? 0;
2764
2801
  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
2802
  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);
2803
+ 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
2804
  let u = r?.decodedFrames ?? this.lastDecoded;
2768
2805
  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
2806
  }
@@ -2783,13 +2820,13 @@ var ar = class {
2783
2820
  };
2784
2821
  }
2785
2822
  noteCspBlocked() {
2786
- this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(tr(new URL(this.url).origin)));
2823
+ this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(rr(new URL(this.url).origin)));
2787
2824
  }
2788
2825
  cspBlocked() {
2789
2826
  return !!this.cspKey && Z.has(this.cspKey);
2790
2827
  }
2791
2828
  enqueue(e) {
2792
- if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > Gn;) {
2829
+ if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > qn;) {
2793
2830
  let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
2794
2831
  this.pending.splice(e >= 0 ? e : 0, 1);
2795
2832
  }
@@ -2816,7 +2853,7 @@ var ar = class {
2816
2853
  };
2817
2854
  //#endregion
2818
2855
  //#region src/core/environment.ts
2819
- function or() {
2856
+ function cr() {
2820
2857
  if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
2821
2858
  let e;
2822
2859
  try {
@@ -2841,14 +2878,14 @@ function or() {
2841
2878
  integration: "INTEGRATION_KIND_IFRAME"
2842
2879
  };
2843
2880
  }
2844
- function sr() {
2881
+ function lr() {
2845
2882
  if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
2846
2883
  let e = navigator.userAgentData, t = e?.platform ?? "";
2847
2884
  if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
2848
2885
  let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
2849
2886
  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
2887
  }
2851
- function cr() {
2888
+ function ur() {
2852
2889
  let e = typeof navigator < "u" ? navigator.connection : void 0;
2853
2890
  if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
2854
2891
  let t = {
@@ -2867,17 +2904,17 @@ function cr() {
2867
2904
  }
2868
2905
  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
2906
  }
2870
- function lr(e) {
2871
- let t = or(), n = {
2872
- deviceClass: sr(),
2907
+ function dr(e) {
2908
+ let t = cr(), n = {
2909
+ deviceClass: lr(),
2873
2910
  integration: t.integration,
2874
- ...cr()
2911
+ ...ur()
2875
2912
  };
2876
2913
  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
2914
  let r = e.getBoundingClientRect?.();
2878
2915
  return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
2879
2916
  }
2880
- async function ur() {
2917
+ async function fr() {
2881
2918
  let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
2882
2919
  if (!e?.getHighEntropyValues) return {};
2883
2920
  try {
@@ -2889,7 +2926,7 @@ async function ur() {
2889
2926
  }
2890
2927
  //#endregion
2891
2928
  //#region src/core/version.ts
2892
- var dr = "2.24.0", fr = {
2929
+ var pr = "2.25.1", mr = {
2893
2930
  accent: "#E1B600",
2894
2931
  accentText: "#1B1C23",
2895
2932
  background: "#0e0f13",
@@ -2900,7 +2937,7 @@ var dr = "2.24.0", fr = {
2900
2937
  border: "rgba(255, 255, 255, 0.1)",
2901
2938
  radius: "8px",
2902
2939
  fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
2903
- }, pr = {
2940
+ }, hr = {
2904
2941
  accent: "--havik-accent",
2905
2942
  accentText: "--havik-accent-text",
2906
2943
  background: "--havik-bg",
@@ -2912,26 +2949,26 @@ var dr = "2.24.0", fr = {
2912
2949
  radius: "--havik-radius",
2913
2950
  fontFamily: "--havik-font"
2914
2951
  };
2915
- function mr(e, t) {
2952
+ function gr(e, t) {
2916
2953
  let n = {
2917
- ...fr,
2954
+ ...mr,
2918
2955
  ...t
2919
2956
  };
2920
- for (let t of Object.keys(pr)) e.style.setProperty(pr[t], n[t]);
2957
+ for (let t of Object.keys(hr)) e.style.setProperty(hr[t], n[t]);
2921
2958
  n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
2922
2959
  }
2923
2960
  //#endregion
2924
2961
  //#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;
2962
+ 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();
2963
+ function br(e = document, t) {
2964
+ let n = e.querySelector(`style#${_r}`);
2965
+ if (n && (!t || yr.get(n) === t)) return;
2929
2966
  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);
2967
+ 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
2968
  }
2932
2969
  //#endregion
2933
2970
  //#region src/ui/icons.ts
2934
- var yr = {
2971
+ var xr = {
2935
2972
  play: "<path d=\"M8 5v14l11-7z\"/>",
2936
2973
  pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
2937
2974
  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 +2982,11 @@ var yr = {
2945
2982
  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
2983
  };
2947
2984
  function $(e) {
2948
- return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${yr[e]}</svg>`;
2985
+ return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${xr[e]}</svg>`;
2949
2986
  }
2950
2987
  //#endregion
2951
2988
  //#region src/ui/controls.ts
2952
- var br = 3e3, xr = 250, Sr = /* @__PURE__ */ new Set([
2989
+ var Sr = 3e3, Cr = 250, wr = /* @__PURE__ */ new Set([
2953
2990
  "GONE",
2954
2991
  "NOT_FOUND",
2955
2992
  "GEO_DENIED",
@@ -2957,15 +2994,15 @@ var br = 3e3, xr = 250, Sr = /* @__PURE__ */ new Set([
2957
2994
  "UNAUTHORIZED",
2958
2995
  "DRM_DEVICE_REVOKED"
2959
2996
  ]);
2960
- function Cr(e) {
2997
+ function Tr(e) {
2961
2998
  let t = "This match isn't available in your country";
2962
2999
  return e ? `${t} (${e})` : t;
2963
3000
  }
2964
- var wr = "This device can't play protected video";
2965
- function Tr(e) {
2966
- return new Er(e);
3001
+ var Er = "This device can't play protected video";
3002
+ function Dr(e) {
3003
+ return new Or(e);
2967
3004
  }
2968
- var Er = class {
3005
+ var Or = class {
2969
3006
  root;
2970
3007
  video;
2971
3008
  player;
@@ -3004,6 +3041,7 @@ var Er = class {
3004
3041
  endedMessage;
3005
3042
  interruptedMessage;
3006
3043
  errorMessage;
3044
+ offlineMessage;
3007
3045
  hideTimer;
3008
3046
  tapTimer;
3009
3047
  surfacePointerType = "";
@@ -3013,7 +3051,7 @@ var Er = class {
3013
3051
  scrubbing = !1;
3014
3052
  offFns = [];
3015
3053
  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");
3054
+ 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
3055
  let t = (e, t, n) => {
3018
3056
  let r = this.doc.createElement(e);
3019
3057
  if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
@@ -3069,7 +3107,7 @@ var Er = class {
3069
3107
  }), this.on(this.muteBtn, "click", () => this.player.setMuted(!e.muted)), this.on(this.volSlider, "input", () => {
3070
3108
  let t = Number(this.volSlider.value);
3071
3109
  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) => {
3110
+ }), 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
3111
  this.lastError = e, this.statusKind = null, this.syncState();
3074
3112
  }));
3075
3113
  let t = (e) => e.pointerType !== "touch";
@@ -3099,7 +3137,7 @@ var Er = class {
3099
3137
  let t = this.surfaceWasHidden;
3100
3138
  this.tapTimer = setTimeout(() => {
3101
3139
  this.tapTimer = void 0, this.toggleBar(t);
3102
- }, xr);
3140
+ }, Cr);
3103
3141
  }
3104
3142
  toggleBar(e) {
3105
3143
  e ? this.poke() : this.hideIfIdle();
@@ -3116,10 +3154,14 @@ var Er = class {
3116
3154
  }
3117
3155
  syncStatus(e) {
3118
3156
  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);
3157
+ if (this.statusOverlays) {
3158
+ let n = this.player.offline && e !== "ended" && e !== "idle", r = !this.hasPlayed && (e === "paused" || e === "waiting");
3159
+ e === "ended" ? t = "ended" : n && !r ? t = "offline" : e === "error" ? t = "error" : e === "waiting" ? t = "waiting" : !this.hasPlayed && (e === "idle" || e === "paused") && (t = "preplay");
3160
+ }
3161
+ this.renderStatus(t);
3120
3162
  }
3121
3163
  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;
3164
+ 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
3165
  }
3124
3166
  renderStatus(e) {
3125
3167
  let t = this.statusMessageFor(e);
@@ -3134,7 +3176,7 @@ var Er = class {
3134
3176
  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
3177
  } else {
3136
3178
  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)) {
3179
+ if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !wr.has(this.lastError.code)) {
3138
3180
  let e = this.doc.createElement("button");
3139
3181
  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
3182
  }
@@ -3175,7 +3217,7 @@ var Er = class {
3175
3217
  let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
3176
3218
  this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
3177
3219
  }
3178
- !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Dr(this.video.currentTime)} / ${Dr(this.video.duration)}`);
3220
+ !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${kr(this.video.currentTime)} / ${kr(this.video.duration)}`);
3179
3221
  }
3180
3222
  syncLive() {
3181
3223
  let e = this.player.getStats(), t = e.isLive !== !1, n = this.player.state === "ended", r = !t && !this.streamEnded();
@@ -3225,17 +3267,17 @@ var Er = class {
3225
3267
  renderQualityMenu() {
3226
3268
  let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
3227
3269
  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)));
3270
+ for (let n of e) this.menu.append(this.menuItem(Ar(n), t === n.index, () => this.player.setQuality(n.index)));
3229
3271
  }
3230
3272
  renderAudioMenu() {
3231
3273
  let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
3232
3274
  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)));
3275
+ for (let t of e) this.menu.append(this.menuItem(jr(t), t.default, () => this.player.setAudioTrack(t.id)));
3234
3276
  }
3235
3277
  renderCcMenu() {
3236
3278
  let e = this.player.getTextTracks(), t = this.doc.createElement("div");
3237
3279
  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)));
3280
+ for (let t of e) this.menu.append(this.menuItem(Mr(t), !1, () => this.player.setTextTrack(t.id)));
3239
3281
  }
3240
3282
  onTracksChanged() {
3241
3283
  this.openMenu && this.renderMenu(this.openMenu);
@@ -3255,14 +3297,14 @@ var Er = class {
3255
3297
  }
3256
3298
  async toggleFullscreen() {
3257
3299
  try {
3258
- S(this.video, this.root) ? await T(this.video, this.root) : await w(this.video, this.root);
3300
+ ve(this.video, this.root) ? await C(this.video, this.root) : await S(this.video, this.root);
3259
3301
  } catch {}
3260
3302
  }
3261
3303
  syncFullscreenSupport() {
3262
- this.fsSupported = C(this.video, this.root), this.fsBtn.style.display = this.fsSupported ? "" : "none";
3304
+ this.fsSupported = ye(this.video, this.root), this.fsBtn.style.display = this.fsSupported ? "" : "none";
3263
3305
  }
3264
3306
  syncFullscreen() {
3265
- let e = S(this.video, this.root);
3307
+ let e = ve(this.video, this.root);
3266
3308
  this.setIcon(this.fsBtn, e ? "fullscreenExit" : "fullscreen"), this.fsBtn.setAttribute("aria-label", e ? "Exit fullscreen" : "Fullscreen");
3267
3309
  }
3268
3310
  poke() {
@@ -3340,41 +3382,51 @@ var Er = class {
3340
3382
  this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
3341
3383
  }
3342
3384
  };
3343
- function Dr(e) {
3385
+ function kr(e) {
3344
3386
  (!Number.isFinite(e) || e < 0) && (e = 0);
3345
3387
  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
3388
  return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
3347
3389
  }
3348
- function Or(e) {
3390
+ function Ar(e) {
3349
3391
  return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
3350
3392
  }
3351
- function kr(e) {
3393
+ function jr(e) {
3352
3394
  return e.name || e.lang || `Track ${e.id}`;
3353
3395
  }
3354
- function Ar(e) {
3396
+ function Mr(e) {
3355
3397
  return e.name || e.lang || `Track ${e.id}`;
3356
3398
  }
3357
3399
  //#endregion
3358
3400
  //#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) {
3401
+ var Nr = 6e3, Pr = 45e3, Fr = 2e3, Ir = 3, Lr = 5e3, Rr = 2e3, zr = 48e4, Br = "keySystemLicenseRequestFailed", Vr = /* @__PURE__ */ new Set([
3402
+ "GONE",
3403
+ "NOT_FOUND",
3404
+ "INVALID_URN",
3405
+ "UNAUTHORIZED",
3406
+ "GEO_DENIED",
3407
+ "DRM_DEVICE_REVOKED"
3408
+ ]);
3409
+ function Hr(e) {
3410
+ return !Vr.has(e);
3411
+ }
3412
+ function Ur(e) {
3361
3413
  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);
3414
+ if (e.env !== void 0) return ct(e.env);
3363
3415
  if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
3364
3416
  return e.baseUrl;
3365
3417
  }
3366
- async function Br(e) {
3418
+ async function Wr(e) {
3367
3419
  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);
3420
+ let t = Ur(e);
3369
3421
  if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
3370
3422
  if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
3371
- let r = new Vr({
3423
+ let r = new Gr({
3372
3424
  ...e,
3373
3425
  baseUrl: t
3374
3426
  });
3375
3427
  return await r.start(), r;
3376
3428
  }
3377
- var Vr = class {
3429
+ var Gr = class {
3378
3430
  opts;
3379
3431
  abort = new AbortController();
3380
3432
  listeners = {};
@@ -3409,12 +3461,17 @@ var Vr = class {
3409
3461
  playRequested = !1;
3410
3462
  idleClosed = !1;
3411
3463
  pendingStartLoad = !1;
3464
+ connectivity = null;
3465
+ failedWhileOffline = !1;
3412
3466
  constructor(e) {
3413
3467
  this.opts = e;
3414
3468
  }
3415
3469
  get state() {
3416
3470
  return this._state;
3417
3471
  }
3472
+ get offline() {
3473
+ return !R();
3474
+ }
3418
3475
  get descriptor() {
3419
3476
  return this._descriptor;
3420
3477
  }
@@ -3422,7 +3479,7 @@ var Vr = class {
3422
3479
  return this._endedReason;
3423
3480
  }
3424
3481
  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");
3482
+ 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
3483
  let e = ++this.loadGen, t = this.resolveOptions();
3427
3484
  try {
3428
3485
  let n = await v(t);
@@ -3435,7 +3492,7 @@ var Vr = class {
3435
3492
  this.setState("waiting"), this.beginArming(e, t.liveStartsAtMs);
3436
3493
  return;
3437
3494
  }
3438
- throw t;
3495
+ throw this.destroy(), t;
3439
3496
  }
3440
3497
  }
3441
3498
  resolveOptions() {
@@ -3448,7 +3505,7 @@ var Vr = class {
3448
3505
  };
3449
3506
  }
3450
3507
  beginArming(e, t, n = !1) {
3451
- let r = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? O(this.opts.baseUrl);
3508
+ let r = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? E(this.opts.baseUrl);
3452
3509
  r ? this.armWithSse(e, r, t, n) : this.beginArmingByPolling(e);
3453
3510
  }
3454
3511
  beginArmingByPolling(e) {
@@ -3469,7 +3526,7 @@ var Vr = class {
3469
3526
  setTimeout(() => {
3470
3527
  a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
3471
3528
  phase: i ? "unavailable" : "tooEarly",
3472
- retryInMs: Mr,
3529
+ retryInMs: Pr,
3473
3530
  attempt: 1,
3474
3531
  elapsedMs: 0,
3475
3532
  ...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
@@ -3508,13 +3565,13 @@ var Vr = class {
3508
3565
  !a && !p() && h();
3509
3566
  }, e);
3510
3567
  };
3511
- _(jr), this.armingSub = D({
3568
+ _(Nr), this.armingSub = T({
3512
3569
  eventsBaseUrl: t,
3513
3570
  matchUrn: this.opts.matchUrn,
3514
3571
  credential: this.opts.credential,
3515
- onAlive: () => _(Mr),
3572
+ onAlive: () => _(Pr),
3516
3573
  onState: (e) => {
3517
- a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Nr);
3574
+ a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Fr);
3518
3575
  },
3519
3576
  onError: () => h()
3520
3577
  });
@@ -3537,7 +3594,7 @@ var Vr = class {
3537
3594
  let n = await c(this.opts.credential);
3538
3595
  if (this.destroyed || t !== this.loadGen) return;
3539
3596
  this.setState("loading");
3540
- let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = pt(this.opts.video, (e) => {
3597
+ let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = ht(this.opts.video, (e) => {
3541
3598
  this._state !== "ended" && this._state !== "error" && this.setState(e);
3542
3599
  });
3543
3600
  if (await i.load(), this.destroyed || t !== this.loadGen) {
@@ -3559,26 +3616,26 @@ var Vr = class {
3559
3616
  if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
3560
3617
  let i = e.analytics?.sid;
3561
3618
  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);
3619
+ 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
3620
  if (!o) {
3564
3621
  s && setTimeout(() => {
3565
3622
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
3566
3623
  }, 0);
3567
3624
  return;
3568
3625
  }
3569
- let c = this.opts.video, l = new ar({
3626
+ let c = this.opts.video, l = new sr({
3570
3627
  endpoint: o,
3571
3628
  sid: i,
3572
3629
  player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
3573
- sdkVersion: dr,
3574
- environment: lr(c),
3630
+ sdkVersion: pr,
3631
+ environment: dr(c),
3575
3632
  idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
3576
3633
  onIdle: () => this.onAnalyticsIdle(t),
3577
3634
  onBlocked: (e) => setTimeout(() => {
3578
3635
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, e));
3579
3636
  }, 0),
3580
3637
  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;
3638
+ let e = this.engine?.getStats() ?? ut, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
3582
3639
  return {
3583
3640
  ...e,
3584
3641
  bufferedMs: Math.round(t * 1e3),
@@ -3592,7 +3649,7 @@ var Vr = class {
3592
3649
  let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
3593
3650
  c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
3594
3651
  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");
3652
+ }, 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
3653
  }
3597
3654
  currentPresentation() {
3598
3655
  let e = this.opts.video;
@@ -3607,7 +3664,7 @@ var Vr = class {
3607
3664
  video: this.opts.video,
3608
3665
  descriptor: e,
3609
3666
  credential: t,
3610
- deviceId: j(),
3667
+ deviceId: k(),
3611
3668
  userId: this.opts.userId,
3612
3669
  lowLatency: this.opts.lowLatency === void 0 || this.opts.lowLatency === "auto" || this.opts.lowLatency,
3613
3670
  snapToLiveOnRefocus: this.opts.snapToLiveOnRefocus,
@@ -3624,9 +3681,9 @@ var Vr = class {
3624
3681
  freshLicenseUrl: () => this.refreshLicense()
3625
3682
  }, o = this.opts.engine ?? "auto";
3626
3683
  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);
3684
+ if (o === "hls") return new Un(a);
3685
+ 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);
3686
+ if (Ut()) return new Un(a);
3630
3687
  if (V(this.opts.video)) return new U(a);
3631
3688
  throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
3632
3689
  }
@@ -3677,11 +3734,11 @@ var Vr = class {
3677
3734
  }
3678
3735
  startLiveState(e) {
3679
3736
  if (this.opts.liveStateEvents === !1) return;
3680
- let t = this.opts.eventsBaseUrl ?? O(this.opts.baseUrl);
3737
+ let t = this.opts.eventsBaseUrl ?? E(this.opts.baseUrl);
3681
3738
  if (!t) return;
3682
3739
  this.closeLiveState();
3683
3740
  let i = 0, a = !1;
3684
- this.liveStateSub = D({
3741
+ this.liveStateSub = T({
3685
3742
  eventsBaseUrl: t,
3686
3743
  matchUrn: this.opts.matchUrn,
3687
3744
  credential: this.opts.credential,
@@ -3693,11 +3750,11 @@ var Vr = class {
3693
3750
  },
3694
3751
  onError: (o) => {
3695
3752
  if (!(this.destroyed || e !== this.loadGen || a) && !this.endedHandled) {
3696
- if (o instanceof E && (o.terminal || o.status === 404)) {
3753
+ if (o instanceof w && (o.terminal || o.status === 404)) {
3697
3754
  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
3755
  return;
3699
3756
  }
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.`)));
3757
+ 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
3758
  }
3702
3759
  }
3703
3760
  });
@@ -3705,6 +3762,18 @@ var Vr = class {
3705
3762
  closeLiveState() {
3706
3763
  this.liveStateSub?.close(), this.liveStateSub = null;
3707
3764
  }
3765
+ watchConnectivity() {
3766
+ this.connectivity || (this.connectivity = lt(), this.connectivity.onChange((e) => {
3767
+ if (this.destroyed) return;
3768
+ if (!e) {
3769
+ this.emit("offline");
3770
+ return;
3771
+ }
3772
+ if (this.emit("online"), this._state !== "error" || !this._lastError) return;
3773
+ let t = this._lastError.code;
3774
+ Hr(t) && (t === "NETWORK" || this.failedWhileOffline) && this.retry().catch(() => void 0);
3775
+ }));
3776
+ }
3708
3777
  watchReturn() {
3709
3778
  this.onReturnVisible || typeof document > "u" || this.opts.liveStateEvents !== !1 && (document.visibilityState === "hidden" && (this.hiddenAtMs = Date.now()), this.onReturnVisible = () => {
3710
3779
  if (document.visibilityState === "hidden") {
@@ -3712,7 +3781,7 @@ var Vr = class {
3712
3781
  return;
3713
3782
  }
3714
3783
  let e = this.hiddenAtMs;
3715
- this.hiddenAtMs = null, e != null && Date.now() - e >= Fr && this.resyncLiveState();
3784
+ this.hiddenAtMs = null, e != null && Date.now() - e >= Lr && this.resyncLiveState();
3716
3785
  }, this.onReturnPageShow = (e) => {
3717
3786
  e.persisted && this.resyncLiveState();
3718
3787
  }, document.addEventListener("visibilitychange", this.onReturnVisible), typeof window < "u" && window.addEventListener("pageshow", this.onReturnPageShow));
@@ -3744,7 +3813,7 @@ var Vr = class {
3744
3813
  scheduleRejoin(e) {
3745
3814
  this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
3746
3815
  this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
3747
- }, Math.random() * Nr));
3816
+ }, Math.random() * Fr));
3748
3817
  }
3749
3818
  cancelRejoin() {
3750
3819
  this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
@@ -3768,7 +3837,7 @@ var Vr = class {
3768
3837
  }
3769
3838
  t.controls = !1;
3770
3839
  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({
3840
+ r && r.insertBefore(n, t), n.appendChild(t), gr(n, this.opts.theme), this.container = n, this.controlBar = Dr({
3772
3841
  root: n,
3773
3842
  video: t,
3774
3843
  player: this,
@@ -3778,6 +3847,7 @@ var Vr = class {
3778
3847
  streamEnded: () => this.streamEnded,
3779
3848
  interruptedMessage: this.opts.interruptedMessage,
3780
3849
  errorMessage: this.opts.errorMessage,
3850
+ offlineMessage: this.opts.offlineMessage,
3781
3851
  cspNonce: this.opts.cspNonce
3782
3852
  });
3783
3853
  }
@@ -3806,7 +3876,7 @@ var Vr = class {
3806
3876
  }
3807
3877
  startStats() {
3808
3878
  this.stopStats();
3809
- let e = Math.max(500, this.opts.statsIntervalMs ?? Ir);
3879
+ let e = Math.max(500, this.opts.statsIntervalMs ?? Rr);
3810
3880
  this.statsTimer = setInterval(() => {
3811
3881
  if (!this.engine) return;
3812
3882
  let e = this.engine.getStats();
@@ -3817,14 +3887,14 @@ var Vr = class {
3817
3887
  this.statsTimer && clearInterval(this.statsTimer), this.statsTimer = void 0;
3818
3888
  }
3819
3889
  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);
3890
+ 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
3891
  }
3822
3892
  scheduleLicenseRefresh() {
3823
3893
  if (this.stopRefresh(), !this._descriptor?.drmEnabled) return;
3824
3894
  typeof document < "u" && this.engine?.name === "hls" && (this.onRefocus = () => {
3825
3895
  document.visibilityState !== "visible" || this.destroyed || G(this._descriptor?.drm?.widevine?.licenseUrl) && this.refreshLicense();
3826
3896
  }, document.addEventListener("visibilitychange", this.onRefocus));
3827
- let e = this.opts.licenseRefreshMs ?? Lr;
3897
+ let e = this.opts.licenseRefreshMs ?? zr;
3828
3898
  e && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
3829
3899
  }
3830
3900
  stopRefresh() {
@@ -3881,7 +3951,7 @@ var Vr = class {
3881
3951
  this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
3882
3952
  }
3883
3953
  getStats() {
3884
- return this.engine?.getStats() ?? ct;
3954
+ return this.engine?.getStats() ?? ut;
3885
3955
  }
3886
3956
  getQualityLevels() {
3887
3957
  return this.engine?.getQualityLevels() ?? [];
@@ -3920,13 +3990,13 @@ var Vr = class {
3920
3990
  e.pictureInPictureElement === this.opts.video && typeof e.exitPictureInPicture == "function" && await e.exitPictureInPicture();
3921
3991
  }
3922
3992
  async enterFullscreen() {
3923
- return !this.destroyed && w(this.opts.video, this.container ?? void 0);
3993
+ return !this.destroyed && S(this.opts.video, this.container ?? void 0);
3924
3994
  }
3925
3995
  async exitFullscreen() {
3926
- await T(this.opts.video, this.container ?? void 0);
3996
+ await C(this.opts.video, this.container ?? void 0);
3927
3997
  }
3928
3998
  fullscreenSupported() {
3929
- return !this.destroyed && C(this.opts.video, this.container ?? void 0);
3999
+ return !this.destroyed && ye(this.opts.video, this.container ?? void 0);
3930
4000
  }
3931
4001
  retry() {
3932
4002
  return this.reload();
@@ -3951,13 +4021,13 @@ var Vr = class {
3951
4021
  return n.add(t), () => n.delete(t);
3952
4022
  }
3953
4023
  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());
4024
+ 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
4025
  }
3956
4026
  clearListeners() {
3957
4027
  for (let e of Object.keys(this.listeners)) this.listeners[e]?.clear();
3958
4028
  }
3959
4029
  fail(e) {
3960
- this._lastError = e, this.setState("error"), this.analyticsSession?.noteFatal(), this.emit("error", e);
4030
+ this._lastError = e, this.failedWhileOffline = !R(), this.setState("error"), this.analyticsSession?.noteFatal(), this.emit("error", e);
3961
4031
  }
3962
4032
  setState(e) {
3963
4033
  if (e === this._state) return;
@@ -3989,12 +4059,12 @@ var Vr = class {
3989
4059
  };
3990
4060
  //#endregion
3991
4061
  //#region src/embed/protocol.ts
3992
- function Hr(e) {
4062
+ function Kr(e) {
3993
4063
  return !!e && typeof e == "object" && typeof e.type == "string" && e.type.startsWith("oddin:");
3994
4064
  }
3995
4065
  //#endregion
3996
4066
  //#region src/embed/host.ts
3997
- function Ur(e) {
4067
+ function qr(e) {
3998
4068
  if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
3999
4069
  if (!e.src) throw Error("mountEmbed: opts.src is required");
4000
4070
  if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
@@ -4003,7 +4073,7 @@ function Ur(e) {
4003
4073
  let r = document.createElement("iframe");
4004
4074
  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
4075
  let i = /* @__PURE__ */ new Set(), a = (t) => {
4006
- if (t.source !== r.contentWindow || t.origin !== n || !Hr(t.data)) return;
4076
+ if (t.source !== r.contentWindow || t.origin !== n || !Kr(t.data)) return;
4007
4077
  let a = t.data;
4008
4078
  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
4079
  };
@@ -4053,15 +4123,15 @@ function Ur(e) {
4053
4123
  }
4054
4124
  //#endregion
4055
4125
  //#region src/embed/page.ts
4056
- var Wr = /^[A-Za-z0-9:_.-]{1,128}$/;
4057
- function Gr(e) {
4126
+ var Jr = /^[A-Za-z0-9:_.-]{1,128}$/;
4127
+ function Yr(e) {
4058
4128
  if (typeof e == "boolean") return e;
4059
4129
  if (typeof e == "object" && e) {
4060
4130
  let t = e.endpoint;
4061
4131
  return typeof t == "string" ? { endpoint: t } : {};
4062
4132
  }
4063
4133
  }
4064
- function Kr() {
4134
+ function Xr() {
4065
4135
  let e = window.HAVIK_EMBED_CONFIG;
4066
4136
  if (e) return {
4067
4137
  baseUrl: e.baseUrl ?? "",
@@ -4071,7 +4141,7 @@ function Kr() {
4071
4141
  autoplay: e.autoplay ?? !0,
4072
4142
  muted: e.muted ?? !0,
4073
4143
  waitForLive: e.waitForLive ?? !0,
4074
- analytics: Gr(e.analytics)
4144
+ analytics: Yr(e.analytics)
4075
4145
  };
4076
4146
  let t = new URLSearchParams(location.search);
4077
4147
  return {
@@ -4084,9 +4154,9 @@ function Kr() {
4084
4154
  waitForLive: !0
4085
4155
  };
4086
4156
  }
4087
- async function qr() {
4088
- let e = Kr();
4089
- Yr();
4157
+ async function Zr() {
4158
+ let e = Xr();
4159
+ $r();
4090
4160
  let t = document.createElement("video");
4091
4161
  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
4162
  let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
@@ -4142,12 +4212,12 @@ async function qr() {
4142
4212
  message: e.message,
4143
4213
  ...e.country === void 0 ? {} : { country: e.country }
4144
4214
  })), e.on("autoplayblocked", () => {
4145
- i({ type: "oddin:autoplayblocked" }), Jr(t, e);
4215
+ i({ type: "oddin:autoplayblocked" }), Qr(t, e);
4146
4216
  });
4147
4217
  }, s = async (r) => {
4148
4218
  a?.destroy(), a = null;
4149
4219
  try {
4150
- let n = await Br({
4220
+ let n = await Wr({
4151
4221
  video: t,
4152
4222
  baseUrl: e.baseUrl,
4153
4223
  matchUrn: r,
@@ -4210,30 +4280,30 @@ async function qr() {
4210
4280
  a?.retry();
4211
4281
  break;
4212
4282
  case "oddin:load":
4213
- typeof e.matchUrn == "string" && Wr.test(e.matchUrn) && s(e.matchUrn);
4283
+ typeof e.matchUrn == "string" && Jr.test(e.matchUrn) && s(e.matchUrn);
4214
4284
  break;
4215
4285
  case "oddin:destroy": c();
4216
4286
  }
4217
4287
  }, u = (e) => {
4218
- r && e.origin === r && Hr(e.data) && l(e.data);
4288
+ r && e.origin === r && Kr(e.data) && l(e.data);
4219
4289
  };
4220
4290
  r && window.addEventListener("message", u), window.addEventListener("pagehide", c, { once: !0 }), await s(e.matchUrn), i({
4221
4291
  type: "oddin:ready",
4222
4292
  protocol: 1
4223
4293
  });
4224
4294
  }
4225
- function Jr(e, t) {
4295
+ function Qr(e, t) {
4226
4296
  if (document.getElementById("havik-tap")) return;
4227
4297
  let n = document.createElement("button");
4228
4298
  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
4299
  n.remove(), t.play();
4230
4300
  }), document.body.appendChild(n);
4231
4301
  }
4232
- function Yr() {
4302
+ function $r() {
4233
4303
  let e = document.createElement("style");
4234
4304
  e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
4235
4305
  }
4236
4306
  //#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 };
4307
+ 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, ye 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, ve as videoFullscreenActive, Ee as watchStatus };
4238
4308
 
4239
4309
  //# sourceMappingURL=index.js.map