@oddin-gg/havik-player 2.15.3 → 2.15.5

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
@@ -290,32 +290,32 @@ function me(e, t) {
290
290
  function he(e) {
291
291
  return e.ownerDocument ?? document;
292
292
  }
293
- function ge(e) {
293
+ function S(e) {
294
294
  return e.fullscreenElement ?? e.webkitFullscreenElement ?? null;
295
295
  }
296
- function S(e, t) {
297
- let n = ge(he(e));
296
+ function C(e, t) {
297
+ let n = S(he(e));
298
298
  return n != null && (n === e || t != null && n === t) || e.webkitDisplayingFullscreen === !0;
299
299
  }
300
- async function C(e, t) {
300
+ async function w(e, t) {
301
301
  let n = t ?? e;
302
302
  if (typeof n.requestFullscreen == "function") return await n.requestFullscreen(), !0;
303
303
  if (typeof n.webkitRequestFullscreen == "function") return n.webkitRequestFullscreen(), !0;
304
304
  let r = e;
305
305
  return r.webkitSupportsFullscreen && typeof r.webkitEnterFullscreen == "function" ? (r.webkitEnterFullscreen(), !0) : !1;
306
306
  }
307
- async function w(e, t) {
307
+ async function T(e, t) {
308
308
  let n = e;
309
309
  if (n.webkitDisplayingFullscreen) {
310
310
  n.webkitExitFullscreen?.();
311
311
  return;
312
312
  }
313
- let r = he(e), i = ge(r);
313
+ let r = he(e), i = S(r);
314
314
  i != null && (i === e || t != null && i === t) && (typeof r.exitFullscreen == "function" ? await r.exitFullscreen() : r.webkitExitFullscreen?.());
315
315
  }
316
316
  //#endregion
317
317
  //#region src/core/catalog.ts
318
- async function _e(e) {
318
+ async function ge(e) {
319
319
  let t = new URLSearchParams();
320
320
  e.status && t.set("status", Array.isArray(e.status) ? e.status.join(",") : e.status), e.sport && t.set("sport", e.sport);
321
321
  let i = t.toString(), a = d(e.baseUrl, "/v1/catalog" + (i ? `?${i}` : "")), o = new Headers();
@@ -333,12 +333,12 @@ async function _e(e) {
333
333
  };
334
334
  if (!s.ok) throw new n(r(s.status), s.status, `catalog request failed (HTTP ${s.status})`);
335
335
  return {
336
- tournaments: ve(await s.json()),
336
+ tournaments: _e(await s.json()),
337
337
  etag: s.headers.get("etag") ?? void 0,
338
338
  notModified: !1
339
339
  };
340
340
  }
341
- function ve(e) {
341
+ function _e(e) {
342
342
  return (e.tournaments ?? []).map((e) => {
343
343
  let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
344
344
  return {
@@ -360,7 +360,7 @@ function ve(e) {
360
360
  };
361
361
  });
362
362
  }
363
- async function ye(e) {
363
+ async function ve(e) {
364
364
  let t = d(e.baseUrl, `/v1/tournaments/${encodeURIComponent(e.urn)}`), i = new Headers();
365
365
  e.etag && i.set("If-None-Match", e.etag);
366
366
  let a = await p(t, {
@@ -380,13 +380,13 @@ async function ye(e) {
380
380
  };
381
381
  if (!a.ok) throw new n(r(a.status), a.status, `tournament request failed (HTTP ${a.status})`);
382
382
  return {
383
- tournament: be(await a.json()),
383
+ tournament: ye(await a.json()),
384
384
  etag: a.headers.get("etag") ?? void 0,
385
385
  notModified: !1,
386
386
  notFound: !1
387
387
  };
388
388
  }
389
- function be(e) {
389
+ function ye(e) {
390
390
  let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
391
391
  return {
392
392
  urn: t,
@@ -406,17 +406,17 @@ function be(e) {
406
406
  }))
407
407
  };
408
408
  }
409
- function xe(e) {
409
+ function be(e) {
410
410
  return e.tournaments.flatMap((e) => e.matches);
411
411
  }
412
412
  //#endregion
413
413
  //#region src/core/poll.ts
414
- var Se = /* @__PURE__ */ new Set([
414
+ var xe = /* @__PURE__ */ new Set([
415
415
  "NOT_FOUND",
416
416
  "GONE",
417
417
  "INVALID_URN"
418
418
  ]);
419
- function Ce(e) {
419
+ function Se(e) {
420
420
  let t = Math.max(2e3, e.intervalMs ?? 1e4), i = new AbortController(), a, o, s, u = !1, f = () => {
421
421
  u || (a = setTimeout(m, t));
422
422
  }, m = async () => {
@@ -449,7 +449,7 @@ function Ce(e) {
449
449
  } catch (t) {
450
450
  if (!i.signal.aborted) {
451
451
  let r = t instanceof n ? t : new n("NETWORK", 0, String(t));
452
- Se.has(r.code) && (u = !0), e.onError?.(r);
452
+ xe.has(r.code) && (u = !0), e.onError?.(r);
453
453
  }
454
454
  } finally {
455
455
  f();
@@ -461,9 +461,9 @@ function Ce(e) {
461
461
  }
462
462
  //#endregion
463
463
  //#region src/core/events.ts
464
- var we = 45e3;
465
- function T(e) {
466
- let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = e.idleTimeoutMs ?? we, i = Number.isFinite(r) && r > 0 ? r : 0, a = new AbortController(), o = !1, c = (e) => new Promise((t) => {
464
+ var Ce = 45e3;
465
+ function E(e) {
466
+ let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = e.idleTimeoutMs ?? Ce, i = Number.isFinite(r) && r > 0 ? r : 0, a = new AbortController(), o = !1, c = (e) => new Promise((t) => {
467
467
  if (a.signal.aborted) return t();
468
468
  let n = setTimeout(t, e);
469
469
  a.signal.addEventListener("abort", () => {
@@ -544,7 +544,7 @@ function T(e) {
544
544
  o || (o = !0, a.abort());
545
545
  } };
546
546
  }
547
- function E(e) {
547
+ function D(e) {
548
548
  try {
549
549
  let t = new URL(e);
550
550
  return t.hostname = `events.${t.hostname}`, t.pathname = "", t.search = "", t.origin;
@@ -554,27 +554,27 @@ function E(e) {
554
554
  }
555
555
  //#endregion
556
556
  //#region src/core/drm/deviceId.ts
557
- var D = "havik.player.deviceId", O;
558
- function k() {
559
- if (O) return O;
557
+ var O = "havik.player.deviceId", k;
558
+ function A() {
559
+ if (k) return k;
560
560
  try {
561
- let e = globalThis.localStorage?.getItem(D);
562
- if (e) return O = e, e;
561
+ let e = globalThis.localStorage?.getItem(O);
562
+ if (e) return k = e, e;
563
563
  } catch {}
564
- let e = Ee();
565
- O = e;
564
+ let e = Te();
565
+ k = e;
566
566
  try {
567
- globalThis.localStorage?.setItem(D, e);
567
+ globalThis.localStorage?.setItem(O, e);
568
568
  } catch {}
569
569
  return e;
570
570
  }
571
- function Te() {
572
- O = void 0;
571
+ function we() {
572
+ k = void 0;
573
573
  try {
574
- globalThis.localStorage?.removeItem(D);
574
+ globalThis.localStorage?.removeItem(O);
575
575
  } catch {}
576
576
  }
577
- function Ee() {
577
+ function Te() {
578
578
  let e = globalThis.crypto;
579
579
  if (e && typeof e.randomUUID == "function") return e.randomUUID();
580
580
  let t = /* @__PURE__ */ new Uint8Array(16);
@@ -586,21 +586,21 @@ function Ee() {
586
586
  }
587
587
  //#endregion
588
588
  //#region src/core/drm/headers.ts
589
- function De(e, t, n = {}) {
589
+ function Ee(e, t, n = {}) {
590
590
  let r = {
591
591
  "x-api-key": t.apiKey,
592
592
  "X-Match-Urn": e.matchUrn,
593
- "X-Device-Id": n.deviceId ?? k(),
593
+ "X-Device-Id": n.deviceId ?? A(),
594
594
  "Content-Type": "application/octet-stream"
595
595
  };
596
596
  return n.userId && (r["X-User-Id"] = n.userId), r;
597
597
  }
598
598
  //#endregion
599
599
  //#region src/core/drm/cdm.ts
600
- var A = /* @__PURE__ */ new WeakMap();
601
- function Oe(e, t) {
602
- let n = A.get(e);
603
- n || (n = /* @__PURE__ */ new Map(), A.set(e, n));
600
+ var j = /* @__PURE__ */ new WeakMap();
601
+ function De(e, t) {
602
+ let n = j.get(e);
603
+ n || (n = /* @__PURE__ */ new Map(), j.set(e, n));
604
604
  let r = n.get(t.keySystem);
605
605
  if (r) return r;
606
606
  let i = t.createMediaKeys().catch((e) => {
@@ -608,22 +608,22 @@ function Oe(e, t) {
608
608
  });
609
609
  return n.set(t.keySystem, i), i;
610
610
  }
611
- function j() {
611
+ function M() {
612
612
  return typeof navigator < "u" && typeof navigator.requestMediaKeySystemAccess == "function";
613
613
  }
614
- var M = ["SW_SECURE_DECODE", "SW_SECURE_CRYPTO"];
615
- function ke(e) {
614
+ var N = ["SW_SECURE_DECODE", "SW_SECURE_CRYPTO"];
615
+ function Oe(e) {
616
616
  return e.startsWith("com.widevine");
617
617
  }
618
- function N(e, t) {
619
- if (!ke(e)) return t;
618
+ function P(e, t) {
619
+ if (!Oe(e)) return t;
620
620
  let n = (e, t) => {
621
621
  let n = e.videoCapabilities;
622
622
  return !n?.length || !n.some((e) => e.robustness) ? !1 : n.every((e) => {
623
- let n = M.indexOf(e.robustness);
624
- return n === -1 || M.indexOf(t) > n;
623
+ let n = N.indexOf(e.robustness);
624
+ return n === -1 || N.indexOf(t) > n;
625
625
  });
626
- }, r = M.flatMap((e) => t.filter((t) => n(t, e)).map((t) => ({
626
+ }, r = N.flatMap((e) => t.filter((t) => n(t, e)).map((t) => ({
627
627
  ...t,
628
628
  videoCapabilities: t.videoCapabilities?.map((t) => ({
629
629
  ...t,
@@ -632,53 +632,53 @@ function N(e, t) {
632
632
  })));
633
633
  return [...t, ...r];
634
634
  }
635
- function P(e) {
636
- return (t, n) => j() ? navigator.requestMediaKeySystemAccess(t, N(t, n)).then((t) => ({
635
+ function F(e) {
636
+ return (t, n) => M() ? navigator.requestMediaKeySystemAccess(t, P(t, n)).then((t) => ({
637
637
  keySystem: t.keySystem,
638
638
  getConfiguration: () => t.getConfiguration(),
639
- createMediaKeys: () => Oe(e, t)
639
+ createMediaKeys: () => De(e, t)
640
640
  })) : Promise.reject(/* @__PURE__ */ Error("navigator.requestMediaKeySystemAccess is unavailable — EME needs a secure context (https, or localhost)"));
641
641
  }
642
- var F = {
642
+ var I = {
643
643
  video: "SW_SECURE_DECODE",
644
644
  audio: "SW_SECURE_CRYPTO",
645
645
  scheme: "cbcs"
646
646
  };
647
- function Ae(e) {
648
- if (!j()) return;
647
+ function ke(e) {
648
+ if (!M()) return;
649
649
  let t = (e, t) => ({
650
650
  contentType: e,
651
651
  robustness: t,
652
- encryptionScheme: F.scheme
652
+ encryptionScheme: I.scheme
653
653
  });
654
- P(e)("com.widevine.alpha", [{
654
+ F(e)("com.widevine.alpha", [{
655
655
  initDataTypes: ["cenc"],
656
656
  distinctiveIdentifier: "optional",
657
657
  persistentState: "optional",
658
658
  sessionTypes: ["temporary"],
659
- audioCapabilities: [t("audio/mp4; codecs=\"mp4a.40.2\"", F.audio)],
660
- videoCapabilities: [t("video/mp4; codecs=\"avc1.42e01e\"", F.video)]
659
+ audioCapabilities: [t("audio/mp4; codecs=\"mp4a.40.2\"", I.audio)],
660
+ videoCapabilities: [t("video/mp4; codecs=\"avc1.42e01e\"", I.video)]
661
661
  }]).then((e) => e.createMediaKeys()).catch(() => {});
662
662
  }
663
- function I(e) {
664
- let t = L(e);
663
+ function L(e) {
664
+ let t = R(e);
665
665
  if (/^avc[13]/.test(t)) return "avc";
666
666
  if (/^(hvc1|hev1)/.test(t)) return "hevc";
667
667
  if (/^(dvh1|dvhe)/.test(t)) return "dv";
668
668
  if (t.startsWith("av01")) return "av1";
669
669
  if (/^vp0?9/.test(t)) return "vp9";
670
670
  }
671
- function L(e) {
671
+ function R(e) {
672
672
  return (e ?? "").trim().toLowerCase();
673
673
  }
674
- var R = {
674
+ var Ae = {
675
675
  hevc: "hvc1.1.6.L93.90",
676
676
  dv: "dvh1.05.06",
677
677
  av1: "av01.0.05M.08",
678
678
  vp9: "vp09.00.10.08"
679
- }, z = /* @__PURE__ */ new Map(), B = /* @__PURE__ */ new Map();
680
- function V(e) {
681
- let t = L(e), n = z.get(t);
679
+ }, je = /* @__PURE__ */ new Map(), z = /* @__PURE__ */ new Map();
680
+ function Me(e) {
681
+ let t = R(e), n = je.get(t);
682
682
  if (n) return n;
683
683
  let r = {
684
684
  initDataTypes: ["cenc"],
@@ -687,32 +687,32 @@ function V(e) {
687
687
  sessionTypes: ["temporary"],
688
688
  videoCapabilities: [{
689
689
  contentType: `video/mp4; codecs="${e.trim()}"`,
690
- robustness: F.video,
691
- encryptionScheme: F.scheme
690
+ robustness: I.video,
691
+ encryptionScheme: I.scheme
692
692
  }]
693
693
  }, i = (async () => {
694
694
  try {
695
- return await navigator.requestMediaKeySystemAccess("com.widevine.alpha", N("com.widevine.alpha", [r])), !0;
695
+ return await navigator.requestMediaKeySystemAccess("com.widevine.alpha", P("com.widevine.alpha", [r])), !0;
696
696
  } catch {
697
697
  return !1;
698
698
  }
699
- })().then((e) => (B.set(t, e), e));
700
- return z.set(t, i), i;
699
+ })().then((e) => (z.set(t, e), e));
700
+ return je.set(t, i), i;
701
701
  }
702
- function je() {
703
- if (j()) for (let e of Object.values(R)) V(e);
702
+ function Ne() {
703
+ if (M()) for (let e of Object.values(Ae)) Me(e);
704
704
  }
705
- function H(e) {
706
- let t = I(e);
707
- if (t) return t === "avc" ? !0 : B.get(L(e)) ?? B.get(L(R[t]));
705
+ function Pe(e) {
706
+ let t = L(e);
707
+ if (t) return t === "avc" ? !0 : z.get(R(e)) ?? z.get(R(Ae[t]));
708
708
  }
709
709
  //#endregion
710
710
  //#region src/core/drm/support.ts
711
- var Me = 5e3, U = "video/mp4; codecs=\"avc1.42E01E\"", Ne = "audio/mp4; codecs=\"mp4a.40.2\"", Pe = {
711
+ var Fe = 5e3, Ie = "video/mp4; codecs=\"avc1.42E01E\"", Le = "audio/mp4; codecs=\"mp4a.40.2\"", Re = {
712
712
  widevine: ["com.widevine.alpha"],
713
713
  fairplay: ["com.apple.fps"]
714
714
  };
715
- function Fe(e) {
715
+ function ze(e) {
716
716
  return e === "fairplay" ? [{
717
717
  initDataTypes: [
718
718
  "sinf",
@@ -720,30 +720,30 @@ function Fe(e) {
720
720
  "cenc"
721
721
  ],
722
722
  videoCapabilities: [{
723
- contentType: U,
723
+ contentType: Ie,
724
724
  robustness: "",
725
725
  encryptionScheme: "cbcs"
726
726
  }],
727
727
  audioCapabilities: [{
728
- contentType: Ne,
728
+ contentType: Le,
729
729
  robustness: "",
730
730
  encryptionScheme: "cbcs"
731
731
  }]
732
- }] : N("com.widevine.alpha", [{
732
+ }] : P("com.widevine.alpha", [{
733
733
  initDataTypes: ["cenc"],
734
734
  videoCapabilities: [{
735
- contentType: U,
736
- robustness: F.video,
737
- encryptionScheme: F.scheme
735
+ contentType: Ie,
736
+ robustness: I.video,
737
+ encryptionScheme: I.scheme
738
738
  }],
739
739
  audioCapabilities: [{
740
- contentType: Ne,
741
- robustness: F.audio,
742
- encryptionScheme: F.scheme
740
+ contentType: Le,
741
+ robustness: I.audio,
742
+ encryptionScheme: I.scheme
743
743
  }]
744
744
  }]);
745
745
  }
746
- function Ie(e, t) {
746
+ function Be(e, t) {
747
747
  return new Promise((n, r) => {
748
748
  let i = setTimeout(() => r(/* @__PURE__ */ Error("probe-timeout")), t);
749
749
  e.then((e) => {
@@ -753,8 +753,8 @@ function Ie(e, t) {
753
753
  });
754
754
  });
755
755
  }
756
- async function Le(e = {}) {
757
- let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Me, r = {};
756
+ async function Ve(e = {}) {
757
+ let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Fe, r = {};
758
758
  if (typeof window < "u" && window.isSecureContext === !1) return {
759
759
  verdict: "insecure-context",
760
760
  detail: r
@@ -766,7 +766,7 @@ async function Le(e = {}) {
766
766
  };
767
767
  let a = !1, o = !1, s = Date.now() + n, c = () => Math.max(1, s - Date.now());
768
768
  for (let e of t) {
769
- let t = Pe[e];
769
+ let t = Re[e];
770
770
  if (!t) {
771
771
  r[e] = "unknown system";
772
772
  continue;
@@ -777,7 +777,7 @@ async function Le(e = {}) {
777
777
  break;
778
778
  }
779
779
  try {
780
- return await Ie((await Ie(i(n, Fe(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
780
+ return await Be((await Be(i(n, ze(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
781
781
  verdict: "supported",
782
782
  system: e,
783
783
  detail: r
@@ -801,49 +801,49 @@ async function Le(e = {}) {
801
801
  }
802
802
  //#endregion
803
803
  //#region src/core/manifest.ts
804
- var Re = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
805
- function ze(e) {
806
- return Re.test(e);
804
+ var He = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
805
+ function Ue(e) {
806
+ return He.test(e);
807
807
  }
808
808
  //#endregion
809
809
  //#region src/core/env.ts
810
- var Be = {
810
+ var We = {
811
811
  integration: "https://feed-dev.oddin-video.gg",
812
812
  production: "https://feed.oddin-video.gg"
813
813
  };
814
- function Ve(e) {
815
- let t = Object.prototype.hasOwnProperty.call(Be, e) ? Be[e] : void 0;
814
+ function B(e) {
815
+ let t = Object.prototype.hasOwnProperty.call(We, e) ? We[e] : void 0;
816
816
  if (!t) throw new n("INTERNAL", 0, `unknown env ${JSON.stringify(e)} — expected 'integration' or 'production'`);
817
817
  return t;
818
818
  }
819
819
  //#endregion
820
820
  //#region src/core/stats.ts
821
- var He = { droppedFrames: 0 };
822
- function Ue(e) {
821
+ var V = { droppedFrames: 0 };
822
+ function H(e) {
823
823
  try {
824
824
  return new URL(e).host;
825
825
  } catch {
826
826
  return "";
827
827
  }
828
828
  }
829
- var We = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
830
- function Ge(e) {
829
+ var Ge = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
830
+ function Ke(e) {
831
831
  if (typeof performance > "u" || typeof performance.getEntriesByType != "function") return "";
832
832
  let t = "", n = -1, r = performance.getEntriesByType("resource");
833
- for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || We.test(i.name)) && i.startTime >= n) {
834
- let e = Ue(i.name);
833
+ for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || Ge.test(i.name)) && i.startTime >= n) {
834
+ let e = H(i.name);
835
835
  e && (t = e, n = i.startTime);
836
836
  }
837
837
  return t;
838
838
  }
839
- function W(e) {
839
+ function U(e) {
840
840
  let t = e.getVideoPlaybackQuality?.();
841
841
  return {
842
842
  dropped: t?.droppedVideoFrames ?? 0,
843
843
  totalFrames: t?.totalVideoFrames ?? 0
844
844
  };
845
845
  }
846
- function Ke(e, t) {
846
+ function qe(e, t) {
847
847
  let n = [
848
848
  ["playing", () => t("playing")],
849
849
  ["waiting", () => t("buffering")],
@@ -860,7 +860,7 @@ function Ke(e, t) {
860
860
  }
861
861
  //#endregion
862
862
  //#region src/core/engine/native.ts
863
- function qe(e) {
863
+ function Je(e) {
864
864
  try {
865
865
  let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
866
866
  return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
@@ -868,14 +868,19 @@ function qe(e) {
868
868
  return;
869
869
  }
870
870
  }
871
- function G(e) {
871
+ function W(e) {
872
872
  return !!(e ?? (typeof document < "u" ? document.createElement("video") : void 0))?.canPlayType("application/vnd.apple.mpegurl");
873
873
  }
874
- function Je() {
874
+ function G() {
875
875
  if (typeof window > "u") return !1;
876
876
  let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
877
877
  return e || t;
878
878
  }
879
+ function Ye() {
880
+ if (typeof navigator > "u" || !G()) return !1;
881
+ let e = navigator.userAgent ?? "";
882
+ return /iPhone|iPad|iPod/.test(e) ? !0 : /Macintosh/.test(e) && typeof navigator.maxTouchPoints == "number" && navigator.maxTouchPoints > 1;
883
+ }
879
884
  var K = class {
880
885
  name = "native";
881
886
  deps;
@@ -912,7 +917,7 @@ var K = class {
912
917
  type: "error",
913
918
  error: new n("INTERNAL", 0, "native HLS playback error"),
914
919
  fatal: !0
915
- }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = Ye(t.manifestUrl, t.analytics?.sid), e.load();
920
+ }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = Xe(t.manifestUrl, t.analytics?.sid), e.load();
916
921
  }
917
922
  startLoad() {
918
923
  this.loadStarted || (this.loadStarted = !0, this.restorePreload());
@@ -934,7 +939,7 @@ var K = class {
934
939
  });
935
940
  this.onEncrypted = (n) => {
936
941
  let i = n;
937
- i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = qe(i.initData), (async () => {
942
+ i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = Je(i.initData), (async () => {
938
943
  try {
939
944
  let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
940
945
  initDataTypes: [i.initDataType],
@@ -1029,11 +1034,11 @@ var K = class {
1029
1034
  e.seekable.length > 0 && (e.currentTime = e.seekable.end(e.seekable.length - 1));
1030
1035
  }
1031
1036
  getStats() {
1032
- let e = this.deps.video, t = W(e), n = {
1037
+ let e = this.deps.video, t = U(e), n = {
1033
1038
  droppedFrames: t.dropped,
1034
1039
  decodedFrames: t.totalFrames
1035
1040
  };
1036
- return this.cdnHost ||= Ge(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity ? (n.isLive = !0, e.seekable.length > 0 && (n.atLiveEdge = e.currentTime >= e.seekable.end(e.seekable.length - 1) - 2)) : Number.isFinite(e.duration) && e.duration > 0 && (n.isLive = !1), n;
1041
+ return this.cdnHost ||= Ke(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity ? (n.isLive = !0, e.seekable.length > 0 && (n.atLiveEdge = e.currentTime >= e.seekable.end(e.seekable.length - 1) - 2)) : Number.isFinite(e.duration) && e.duration > 0 && (n.isLive = !1), n;
1037
1042
  }
1038
1043
  stop() {
1039
1044
  try {
@@ -1052,13 +1057,13 @@ var K = class {
1052
1057
  } catch {}
1053
1058
  }
1054
1059
  };
1055
- function Ye(e, t) {
1060
+ function Xe(e, t) {
1056
1061
  return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
1057
1062
  }
1058
1063
  //#endregion
1059
1064
  //#region src/core/engine/prefetch.ts
1060
- var Xe = 15e3, Ze = 5e3, Qe = 6;
1061
- function $e(e) {
1065
+ var Ze = 15e3, Qe = 5e3, $e = 6;
1066
+ function et(e) {
1062
1067
  try {
1063
1068
  let t = new URL(e);
1064
1069
  return t.searchParams.delete("CMCD"), t.toString();
@@ -1066,7 +1071,7 @@ function $e(e) {
1066
1071
  return e;
1067
1072
  }
1068
1073
  }
1069
- var et = class {
1074
+ var tt = class {
1070
1075
  cmcd;
1071
1076
  entries = /* @__PURE__ */ new Map();
1072
1077
  keyed = /* @__PURE__ */ new Set();
@@ -1089,10 +1094,10 @@ var et = class {
1089
1094
  }
1090
1095
  prefetch(e, t, n) {
1091
1096
  if (!this.isActive(t)) return;
1092
- let r = $e(e);
1097
+ let r = et(e);
1093
1098
  if (this.entries.has(r)) return;
1094
1099
  let i = this.perTrack.get(t) ?? 0;
1095
- if (i >= Qe) return;
1100
+ if (i >= $e) return;
1096
1101
  this.perTrack.set(t, i + 1);
1097
1102
  let a = new AbortController(), o = {
1098
1103
  started: performance.now(),
@@ -1106,10 +1111,10 @@ var et = class {
1106
1111
  signal: a.signal
1107
1112
  }).then(async (e) => (o.first = performance.now(), e.ok ? e.arrayBuffer() : null)).catch(() => null), this.entries.set(r, o), this.stats.started += 1, setTimeout(() => {
1108
1113
  this.entries.get(r) === o && (this.entries.delete(r), a.abort(), this.stats.expired += 1);
1109
- }, Xe);
1114
+ }, Ze);
1110
1115
  }
1111
1116
  take(e) {
1112
- let t = $e(e), n = this.entries.get(t);
1117
+ let t = et(e), n = this.entries.get(t);
1113
1118
  return n && this.entries.delete(t), n;
1114
1119
  }
1115
1120
  destroy() {
@@ -1129,13 +1134,13 @@ var et = class {
1129
1134
  }
1130
1135
  }
1131
1136
  };
1132
- function tt(t) {
1137
+ function nt(t) {
1133
1138
  let n = e.DefaultConfig?.loader;
1134
1139
  if (typeof n != "function") return;
1135
1140
  class r extends n {
1136
1141
  served = !1;
1137
1142
  cancelled = !1;
1138
- stats = nt();
1143
+ stats = rt();
1139
1144
  load(e, n, r) {
1140
1145
  let i = e.rangeEnd ? void 0 : t.take(e.url);
1141
1146
  if (!i) {
@@ -1143,7 +1148,7 @@ function tt(t) {
1143
1148
  return;
1144
1149
  }
1145
1150
  this.served = !0;
1146
- let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || Ze, s = setTimeout(() => {
1151
+ let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || Qe, s = setTimeout(() => {
1147
1152
  !this.cancelled && this.served && (i.abort.abort(), t.stats.failed += 1, this.served = !1, super.load(e, n, r));
1148
1153
  }, o);
1149
1154
  i.bytes.then((o) => {
@@ -1170,7 +1175,7 @@ function tt(t) {
1170
1175
  }
1171
1176
  return r;
1172
1177
  }
1173
- function nt() {
1178
+ function rt() {
1174
1179
  return {
1175
1180
  aborted: !1,
1176
1181
  loaded: 0,
@@ -1194,10 +1199,10 @@ function nt() {
1194
1199
  }
1195
1200
  };
1196
1201
  }
1197
- function rt(e) {
1202
+ function it(e) {
1198
1203
  return e === "audio" ? "audio" : "main";
1199
1204
  }
1200
- function it(e, t) {
1205
+ function at(e, t) {
1201
1206
  let n = [];
1202
1207
  t.initSegment?.url && !t.initSegment.data && n.push({
1203
1208
  url: t.initSegment.url,
@@ -1216,24 +1221,24 @@ function it(e, t) {
1216
1221
  }
1217
1222
  //#endregion
1218
1223
  //#region src/core/engine/hls.ts
1219
- function at() {
1224
+ function ot() {
1220
1225
  return e.isSupported();
1221
1226
  }
1222
- var ot = 3, st = 5, ct = 3, lt = 3e4, ut = 12e3, dt = 3e3, ft = 6e3, pt = 3, mt = .5, ht = 1.1, gt = .25, _t = 5e3, vt = 4e3, yt = 2, bt = 5, xt = 2, St = 2, Ct = 4, wt = 4, Tt = 2e3, Et = 3e4, Dt = .2, Ot = 30, kt = 2, At = 2, jt = 9, Mt = .5, Nt = 64;
1223
- function Pt(e) {
1227
+ var st = 3, ct = 5, lt = 3, ut = 3e4, dt = 12e3, ft = 3e3, pt = 6e3, mt = .5, ht = 3, gt = .5, _t = 1.1, vt = .25, yt = 5e3, bt = 4e3, xt = 2, St = 5, Ct = 2, wt = 2, Tt = 4, Et = 4, Dt = 2e3, Ot = 3e4, kt = .2, At = 30, jt = 2, Mt = 2, Nt = 9, Pt = .5, Ft = 64;
1228
+ function It(e) {
1224
1229
  if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
1225
1230
  delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
1226
1231
  return;
1227
1232
  }
1228
- e.liveSyncDuration ??= At;
1229
- let t = Math.max(12, e.liveSyncDuration + jt);
1230
- (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), Ft(e, e.liveSyncDuration);
1233
+ e.liveSyncDuration ??= Mt;
1234
+ let t = Math.max(12, e.liveSyncDuration + Nt);
1235
+ (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), Lt(e, e.liveSyncDuration);
1231
1236
  }
1232
- function Ft(e, t) {
1237
+ function Lt(e, t) {
1233
1238
  let n = (e, t, n) => Math.min(n, Math.max(t, e));
1234
1239
  e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
1235
1240
  }
1236
- var It = class {
1241
+ var Rt = class {
1237
1242
  name = "hls";
1238
1243
  hls = null;
1239
1244
  deps;
@@ -1290,6 +1295,9 @@ var It = class {
1290
1295
  savedLiveMaxLatency;
1291
1296
  savedMaxSyncRate;
1292
1297
  chaseLatency = -1;
1298
+ catchUpRate = 1;
1299
+ catchUpEngaged = !1;
1300
+ onTimeUpdate = null;
1293
1301
  chaseTicks = 0;
1294
1302
  liveRetargets = 0;
1295
1303
  capObserver = null;
@@ -1311,7 +1319,7 @@ var It = class {
1311
1319
  this.deps = e, this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
1312
1320
  }
1313
1321
  async load() {
1314
- let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = G(r) && Je(), o = !!e.drm?.widevine?.licenseUrl && !a;
1322
+ let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = W(r) && G(), o = !!e.drm?.widevine?.licenseUrl && !a;
1315
1323
  if (e.drmEnabled && !o) {
1316
1324
  i({
1317
1325
  type: "error",
@@ -1320,7 +1328,7 @@ var It = class {
1320
1328
  });
1321
1329
  return;
1322
1330
  }
1323
- e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ae(r), je()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1331
+ e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (ke(r), Ne()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1324
1332
  let e = this.hls;
1325
1333
  if (document.visibilityState !== "visible" || !e) return;
1326
1334
  let t = e.liveSyncPosition;
@@ -1329,7 +1337,7 @@ var It = class {
1329
1337
  t - r.currentTime > Math.max(n * 3, 8) && (r.currentTime = t);
1330
1338
  }, document.addEventListener("visibilitychange", this.onVisibility)), this.onSeeking = () => {
1331
1339
  this.clampOverSeek(), this.loadSuspended && (this.resumeLoading(), this.schedulePauseSuspend());
1332
- }, r.addEventListener("seeking", this.onSeeking), 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());
1340
+ }, 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());
1333
1341
  }
1334
1342
  schedulePauseSuspend() {
1335
1343
  this.pauseSuspendTimer || this.loadSuspended || this.stopped || !this.loadStarted || (this.pauseSuspendTimer = setTimeout(() => {
@@ -1343,7 +1351,7 @@ var It = class {
1343
1351
  }
1344
1352
  this.loadSuspended = !0;
1345
1353
  }
1346
- }, _t));
1354
+ }, yt));
1347
1355
  }
1348
1356
  resumeLoading() {
1349
1357
  if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
@@ -1375,7 +1383,7 @@ var It = class {
1375
1383
  let t = e.liveSyncPosition;
1376
1384
  if (typeof t != "number" || !Number.isFinite(t)) return;
1377
1385
  let { video: n } = this.deps;
1378
- n.currentTime <= t + Mt || (n.currentTime = t);
1386
+ n.currentTime <= t + Pt || (n.currentTime = t);
1379
1387
  }
1380
1388
  startHls() {
1381
1389
  let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps;
@@ -1394,12 +1402,12 @@ var It = class {
1394
1402
  emeEnabled: !0,
1395
1403
  drmSystems: { ...this.licenseUrl ? { "com.widevine.alpha": { licenseUrl: this.licenseUrl } } : {} },
1396
1404
  drmSystemOptions: {
1397
- videoRobustness: F.video,
1398
- audioRobustness: F.audio,
1399
- videoEncryptionScheme: F.scheme,
1400
- audioEncryptionScheme: F.scheme
1405
+ videoRobustness: I.video,
1406
+ audioRobustness: I.audio,
1407
+ videoEncryptionScheme: I.scheme,
1408
+ audioEncryptionScheme: I.scheme
1401
1409
  },
1402
- ...j() ? { requestMediaKeySystemAccessFunc: P(t) } : {},
1410
+ ...M() ? { requestMediaKeySystemAccessFunc: F(t) } : {},
1403
1411
  licenseXhrSetup: (e, t) => {
1404
1412
  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;
1405
1413
  let o = performance.now();
@@ -1416,20 +1424,20 @@ var It = class {
1416
1424
  ...c
1417
1425
  };
1418
1426
  if (this.prefetch?.destroy(), this.prefetch = null, u && this.deps.mediaDuringKey !== !1 && !d.fLoader) {
1419
- let e = new et({
1427
+ let e = new tt({
1420
1428
  sessionId: n.analytics?.sid,
1421
1429
  contentId: n.matchUrn
1422
- }), t = tt(e);
1430
+ }), t = nt(e);
1423
1431
  t && (this.prefetch = e, d.fLoader = t);
1424
1432
  }
1425
- Pt(d), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = d.autoStartLoad !== !1;
1433
+ It(d), this.catchUpRate = typeof d.maxLiveSyncPlaybackRate == "number" ? d.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (d.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = d.autoStartLoad !== !1;
1426
1434
  let f = new e(d);
1427
1435
  if (this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
1428
1436
  this.mediaRecoveries = 0, this.networkRecoveries = 0, u && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && this.dropLevelsWidevineCannotPlay(f), this.measureLadder(f), this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
1429
1437
  }), f.on(e.Events.FRAG_BUFFERED, (e, t) => {
1430
1438
  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(() => {
1431
1439
  this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
1432
- }, lt)));
1440
+ }, ut)));
1433
1441
  }), f.on(e.Events.FRAG_LOADING, (e, t) => {
1434
1442
  t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
1435
1443
  }), f.on(e.Events.FRAG_LOADED, (e, t) => {
@@ -1437,10 +1445,10 @@ var It = class {
1437
1445
  let n = t?.frag?.stats, r = n?.loaded;
1438
1446
  typeof r == "number" && (this.bytesLoaded += r), !this.reportedFirstBytes && typeof r == "number" && r > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
1439
1447
  let i = n?.loading;
1440
- i && i.end > 0 && i.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(i.end - i.start))), this.requestTimesMs.length > Nt && this.requestTimesMs.shift());
1448
+ i && i.end > 0 && i.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(i.end - i.start))), this.requestTimesMs.length > Ft && this.requestTimesMs.shift());
1441
1449
  let a = t?.frag?.url;
1442
1450
  if (a) {
1443
- let e = Ue(a);
1451
+ let e = H(a);
1444
1452
  e && (this.cdnHost = e);
1445
1453
  }
1446
1454
  }), f.on(e.Events.LEVEL_LOADED, (e, t) => {
@@ -1454,15 +1462,15 @@ var It = class {
1454
1462
  }), f.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.prefetch) {
1455
1463
  let t = this.prefetch;
1456
1464
  f.on(e.Events.KEY_LOADING, (e, n) => {
1457
- let r = n?.frag, i = rt(r?.type);
1458
- if (r && t.isActive(i)) for (let e of it(f, r)) t.prefetch(e.url, i, e.kind);
1459
- }), f.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(rt(n?.frag?.type)));
1465
+ let r = n?.frag, i = it(r?.type);
1466
+ if (r && t.isActive(i)) for (let e of at(f, r)) t.prefetch(e.url, i, e.kind);
1467
+ }), f.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(it(n?.frag?.type)));
1460
1468
  }
1461
1469
  f.on(e.Events.KEY_LOADED, () => {
1462
1470
  u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
1463
1471
  }), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
1464
- this.checkEndStale(), this.checkStarvation(), this.checkFutileChase(), this.checkFrameDrops();
1465
- }, dt), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1472
+ this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.checkFrameDrops();
1473
+ }, ft), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1466
1474
  this.renditionSwitches += 1;
1467
1475
  let n = this.lastLevelIndex >= 0 ? f.levels[this.lastLevelIndex] : void 0, r = f.levels[t.level];
1468
1476
  n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, l({
@@ -1526,7 +1534,7 @@ var It = class {
1526
1534
  return;
1527
1535
  }
1528
1536
  this.capTimer && clearTimeout(this.capTimer);
1529
- let t = e > this.sizeCapLevel ? Tt : Et;
1537
+ let t = e > this.sizeCapLevel ? Dt : Ot;
1530
1538
  this.capTimer = setTimeout(() => {
1531
1539
  this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
1532
1540
  }, t);
@@ -1536,9 +1544,9 @@ var It = class {
1536
1544
  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;
1537
1545
  }
1538
1546
  dropLevelsWidevineCannotPlay(e) {
1539
- this.removeLevelsWhere(e, (e) => H(e) !== !0);
1540
- let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && I(e) !== "avc" && !!I(e)));
1541
- for (let n of t) V(n).then((t) => {
1547
+ this.removeLevelsWhere(e, (e) => Pe(e) !== !0);
1548
+ let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && L(e) !== "avc" && !!L(e)));
1549
+ for (let n of t) Me(n).then((t) => {
1542
1550
  t || this.hls !== e || this.removeLevelsWhere(e, (e) => e === n) && (this.measureLadder(e), this.applySizeCap());
1543
1551
  });
1544
1552
  }
@@ -1546,10 +1554,10 @@ var It = class {
1546
1554
  let n = e.levels ?? [], r = [], i = /* @__PURE__ */ new Set();
1547
1555
  if (n.forEach((e, n) => {
1548
1556
  let a = e.videoCodec;
1549
- a && I(a) && t(a) && (r.push(n), i.add(a));
1557
+ a && L(a) && t(a) && (r.push(n), i.add(a));
1550
1558
  }), !r.length) return !1;
1551
1559
  let a = [...i].join(", ");
1552
- if (!n.some((e, t) => r.includes(t) ? !1 : !I(e.videoCodec) || H(e.videoCodec) === !0)) return console.warn(`havik-player: every rendition is ${a}, which Widevine may not play on this browser; keeping them`), !1;
1560
+ if (!n.some((e, t) => r.includes(t) ? !1 : !L(e.videoCodec) || Pe(e.videoCodec) === !0)) return console.warn(`havik-player: every rendition is ${a}, which Widevine may not play on this browser; keeping them`), !1;
1553
1561
  for (let t = r.length - 1; t >= 0; --t) e.removeLevel(r[t]);
1554
1562
  return console.info(`havik-player: skipped ${r.length} rendition(s) Widevine cannot play on this browser (${a})`), !0;
1555
1563
  }
@@ -1599,7 +1607,7 @@ var It = class {
1599
1607
  e.widevine && (this.licenseUrl = e.widevine);
1600
1608
  }
1601
1609
  getStats() {
1602
- let e = this.hls, t = W(this.deps.video), n = {
1610
+ let e = this.hls, t = U(this.deps.video), n = {
1603
1611
  droppedFrames: t.dropped,
1604
1612
  decodedFrames: t.totalFrames,
1605
1613
  lowLatency: this.detectedLowLatency,
@@ -1647,7 +1655,7 @@ var It = class {
1647
1655
  return;
1648
1656
  }
1649
1657
  let e = Date.now() - this.lastAdvanceMs;
1650
- !this.chaseSuspended && e > ft && this.suspendChasing(), e > ut && this.emitEnded("stalled");
1658
+ !this.chaseSuspended && e > pt && this.suspendChasing(), e > dt && this.emitEnded("stalled");
1651
1659
  }
1652
1660
  resetStarvationWindow() {
1653
1661
  this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
@@ -1662,7 +1670,7 @@ var It = class {
1662
1670
  this.resetStarvationWindow();
1663
1671
  return;
1664
1672
  }
1665
- let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < ft, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > vt, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = W(t), c = o - s, l = c !== this.starvedFrames;
1673
+ let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < pt, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > bt, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = U(t), c = o - s, l = c !== this.starvedFrames;
1666
1674
  if (this.starvedFrames = c, !a || l) {
1667
1675
  (t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
1668
1676
  return;
@@ -1671,12 +1679,12 @@ var It = class {
1671
1679
  this.resetStarvationWindow();
1672
1680
  return;
1673
1681
  }
1674
- 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 > Ct && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= xt && (this.clearKick(), this.starvationRebuilds < St)) {
1682
+ 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 > Tt && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= Ct && (this.clearKick(), this.starvationRebuilds < wt)) {
1675
1683
  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");
1676
1684
  return;
1677
1685
  }
1678
- let u = i && this.starvedTicks >= yt, d = !i && this.deadTicks >= Ct && this.recentMainFrags.reduce((e, t) => e + t, 0) >= wt;
1679
- if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= bt))) {
1686
+ let u = i && this.starvedTicks >= xt, d = !i && this.deadTicks >= Tt && this.recentMainFrags.reduce((e, t) => e + t, 0) >= Et;
1687
+ if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= St))) {
1680
1688
  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");
1681
1689
  try {
1682
1690
  e.stopLoad(), e.startLoad(-1);
@@ -1685,6 +1693,16 @@ var It = class {
1685
1693
  }
1686
1694
  }
1687
1695
  }
1696
+ updateCatchUpBand() {
1697
+ let e = this.hls;
1698
+ if (!e || this.catchUpRate <= 1 || this.chaseSuspended || this.loadSuspended) return;
1699
+ let t = e.latency, n = e.targetLatency;
1700
+ if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
1701
+ let r = t - n;
1702
+ !this.catchUpEngaged && r > mt ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= mt && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
1703
+ let i = this.catchUpEngaged ? this.catchUpRate : 1;
1704
+ e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
1705
+ }
1688
1706
  fpsCapLevel(e) {
1689
1707
  if (this.fpsCapBitrate == null) return -1;
1690
1708
  let t = this.fpsCapFailedHeight, n = -1;
@@ -1702,16 +1720,16 @@ var It = class {
1702
1720
  this.resetFrameDropWindow();
1703
1721
  return;
1704
1722
  }
1705
- let { totalFrames: n, dropped: r } = W(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
1706
- if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < Ot || o < 0) {
1723
+ let { totalFrames: n, dropped: r } = U(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
1724
+ if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < At || o < 0) {
1707
1725
  this.fpsBadTicks = 0;
1708
1726
  return;
1709
1727
  }
1710
- if (o <= Dt * a) {
1728
+ if (o <= kt * a) {
1711
1729
  this.fpsBadTicks = 0;
1712
1730
  return;
1713
1731
  }
1714
- if (this.fpsBadTicks += 1, this.fpsBadTicks < kt) return;
1732
+ if (this.fpsBadTicks += 1, this.fpsBadTicks < jt) return;
1715
1733
  this.fpsBadTicks = 0;
1716
1734
  let s = e.levels, c = s[e.currentLevel];
1717
1735
  if (!c) return;
@@ -1728,24 +1746,27 @@ var It = class {
1728
1746
  return;
1729
1747
  }
1730
1748
  let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
1731
- if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(ht, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
1749
+ if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(_t, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
1732
1750
  this.resetChaseWindow();
1733
1751
  return;
1734
1752
  }
1735
- if (this.chaseLatency < 0 || this.chaseLatency - n >= mt) {
1753
+ if (this.chaseLatency < 0 || this.chaseLatency - n >= gt) {
1736
1754
  this.chaseLatency = n, this.chaseTicks = 0;
1737
1755
  return;
1738
1756
  }
1739
- if (this.chaseTicks += 1, this.chaseTicks < pt) return;
1757
+ if (this.chaseTicks += 1, this.chaseTicks < ht) return;
1740
1758
  this.resetChaseWindow();
1741
1759
  let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
1742
1760
  if (!(a > 1)) return;
1743
1761
  let o = typeof e.targetLatency == "number" ? e.targetLatency : 0, s = Math.min(n, a - 1);
1744
- s < o + gt || (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);
1762
+ s < o + vt || (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);
1745
1763
  }
1746
1764
  suspendChasing() {
1747
1765
  let e = this.hls;
1748
- e && (this.chaseSuspended = !0, this.savedLiveMaxLatency = e.config.liveMaxLatencyDuration, this.savedMaxSyncRate = e.config.maxLiveSyncPlaybackRate, e.config.liveMaxLatencyDuration = 2 ** 53 - 1, e.config.maxLiveSyncPlaybackRate = 1);
1766
+ if (!e) return;
1767
+ this.chaseSuspended = !0, this.savedLiveMaxLatency = e.config.liveMaxLatencyDuration, this.savedMaxSyncRate = e.config.maxLiveSyncPlaybackRate, e.config.liveMaxLatencyDuration = 2 ** 53 - 1, e.config.maxLiveSyncPlaybackRate = 1;
1768
+ let { video: t } = this.deps, n = this.savedMaxSyncRate;
1769
+ t.playbackRate > 1 && typeof n == "number" && t.playbackRate <= n && (t.playbackRate = 1);
1749
1770
  }
1750
1771
  resumeChasing() {
1751
1772
  this.chaseSuspended = !1;
@@ -1768,7 +1789,7 @@ var It = class {
1768
1789
  } catch {}
1769
1790
  }
1770
1791
  destroy() {
1771
- if (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.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) {
1792
+ if (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) {
1772
1793
  try {
1773
1794
  this.hls.destroy();
1774
1795
  } catch (e) {
@@ -1783,7 +1804,7 @@ var It = class {
1783
1804
  scheduleLicenseRetry(t) {
1784
1805
  if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
1785
1806
  let n = t.response?.code ?? 0;
1786
- if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= ct) return !1;
1807
+ if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= lt) return !1;
1787
1808
  this.licenseRecoveries += 1;
1788
1809
  let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
1789
1810
  return this.licenseRetryTimer = setTimeout(() => {
@@ -1815,7 +1836,7 @@ var It = class {
1815
1836
  return;
1816
1837
  }
1817
1838
  if (t.type === e.ErrorTypes.NETWORK_ERROR) {
1818
- if (this.networkRecoveries < st) {
1839
+ if (this.networkRecoveries < ct) {
1819
1840
  this.networkRecoveries += 1;
1820
1841
  let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
1821
1842
  this.networkRetryTimer = setTimeout(() => {
@@ -1832,7 +1853,7 @@ var It = class {
1832
1853
  return;
1833
1854
  }
1834
1855
  if (t.type === e.ErrorTypes.MEDIA_ERROR) {
1835
- if (this.mediaRecoveries < ot) {
1856
+ if (this.mediaRecoveries < st) {
1836
1857
  this.mediaRecoveries += 1, n.recoverMediaError();
1837
1858
  return;
1838
1859
  }
@@ -1856,19 +1877,19 @@ var It = class {
1856
1877
  let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
1857
1878
  return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
1858
1879
  }
1859
- }, Lt = 15e3, Rt = 6e5, zt = 3e5, Bt = 100, q = 1, Vt = 1e3, Ht = 3e4, Ut = 1e3, Wt = {
1880
+ }, zt = 15e3, Bt = 6e5, Vt = 3e5, Ht = 100, q = 1, Ut = 1e3, Wt = 3e4, Gt = 1e3, Kt = {
1860
1881
  inline: "PRESENTATION_INLINE",
1861
1882
  fullscreen: "PRESENTATION_FULLSCREEN",
1862
1883
  pip: "PRESENTATION_PIP"
1863
- }, Gt = {
1884
+ }, qt = {
1864
1885
  widevine: "KEY_SYSTEM_WIDEVINE",
1865
1886
  fairplay: "KEY_SYSTEM_FAIRPLAY",
1866
1887
  none: "KEY_SYSTEM_NONE"
1867
1888
  };
1868
- function Kt(e, t) {
1889
+ function Jt(e, t) {
1869
1890
  return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
1870
1891
  }
1871
- var qt = /* @__PURE__ */ new Set([
1892
+ var Yt = /* @__PURE__ */ new Set([
1872
1893
  "INVALID_URN",
1873
1894
  "NOT_FOUND",
1874
1895
  "GONE",
@@ -1888,7 +1909,7 @@ var qt = /* @__PURE__ */ new Set([
1888
1909
  ended: "PLAYER_STATE_ENDED",
1889
1910
  error: "PLAYER_STATE_ERROR"
1890
1911
  };
1891
- function Jt(e) {
1912
+ function Xt(e) {
1892
1913
  try {
1893
1914
  let t = new URL(e), [n, ...r] = t.hostname.split(".");
1894
1915
  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);
@@ -1896,8 +1917,8 @@ function Jt(e) {
1896
1917
  return;
1897
1918
  }
1898
1919
  }
1899
- var Yt = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), Xt = /* @__PURE__ */ new Set(), Y = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), Zt = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
1900
- function Qt(e) {
1920
+ var Zt = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), Qt = /* @__PURE__ */ new Set(), Y = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), $t = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
1921
+ function en(e) {
1901
1922
  if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
1902
1923
  let t;
1903
1924
  try {
@@ -1906,19 +1927,19 @@ function Qt(e) {
1906
1927
  } catch {
1907
1928
  return;
1908
1929
  }
1909
- if (Xt.has(t) && !Y.has(t)) {
1910
- Y.add(t), g(Zt(new URL(t).origin));
1930
+ if (Qt.has(t) && !Y.has(t)) {
1931
+ Y.add(t), g($t(new URL(t).origin));
1911
1932
  for (let e of X) e.noteCspBlocked();
1912
1933
  }
1913
1934
  }
1914
- function $t(e, t) {
1935
+ function tn(e, t) {
1915
1936
  return g(t, e), { disabledReason: t };
1916
1937
  }
1917
- function en(e, t, n) {
1918
- if (n) return t && !Yt(t, n) && g(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
1938
+ function nn(e, t, n) {
1939
+ if (n) return t && !Zt(t, n) && g(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
1919
1940
  if (t) return { endpoint: t };
1920
- if (t !== void 0) return $t("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).");
1921
- let r = Jt(e);
1941
+ if (t !== void 0) return tn("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).");
1942
+ let r = Xt(e);
1922
1943
  if (r) return { endpoint: r };
1923
1944
  let i;
1924
1945
  try {
@@ -1926,9 +1947,9 @@ function en(e, t, n) {
1926
1947
  } catch {
1927
1948
  i = e;
1928
1949
  }
1929
- return $t(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).`);
1950
+ return tn(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).`);
1930
1951
  }
1931
- var tn = class {
1952
+ var rn = class {
1932
1953
  opts;
1933
1954
  url;
1934
1955
  cspKey;
@@ -2010,8 +2031,8 @@ var tn = class {
2010
2031
  constructor(e) {
2011
2032
  this.opts = {
2012
2033
  ...e,
2013
- heartbeatMs: e.heartbeatMs ?? Lt,
2014
- idleMs: e.idleMs ?? Rt
2034
+ heartbeatMs: e.heartbeatMs ?? zt,
2035
+ idleMs: e.idleMs ?? Bt
2015
2036
  }, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
2016
2037
  try {
2017
2038
  let e = new URL(this.url);
@@ -2028,11 +2049,11 @@ var tn = class {
2028
2049
  sdkVersion: this.opts.sdkVersion,
2029
2050
  ...this.opts.environment
2030
2051
  };
2031
- this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Vt), 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 && Xt.add(this.cspKey), document.addEventListener("securitypolicyviolation", Qt), X.add(this), this.noteCspBlocked(), this.onVisibility());
2052
+ this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Ut), 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 && Qt.add(this.cspKey), document.addEventListener("securitypolicyviolation", en), X.add(this), this.noteCspBlocked(), this.onVisibility());
2032
2053
  }
2033
2054
  checkSuspension(e) {
2034
2055
  if (this.endedFlag || !this.opts.idleMs) return !1;
2035
- let t = Math.max(this.opts.idleMs, zt);
2056
+ let t = Math.max(this.opts.idleMs, Vt);
2036
2057
  return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
2037
2058
  }
2038
2059
  syncIdle(e) {
@@ -2055,12 +2076,12 @@ var tn = class {
2055
2076
  let a = {
2056
2077
  fromState: J[e] ?? "PLAYER_STATE_UNSPECIFIED",
2057
2078
  toState: J[t] ?? "PLAYER_STATE_UNSPECIFIED",
2058
- presentation: Wt[this.presentation]
2079
+ presentation: Kt[this.presentation]
2059
2080
  }, o = this.causeOf(e, t, i);
2060
2081
  o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
2061
2082
  }
2062
2083
  seekInduced(e) {
2063
- return this.lastSeekMs >= 0 && e - this.lastSeekMs < Ut;
2084
+ return this.lastSeekMs >= 0 && e - this.lastSeekMs < Gt;
2064
2085
  }
2065
2086
  causeOf(e, t, n) {
2066
2087
  if (t === "error") return "TRANSITION_CAUSE_ERROR";
@@ -2134,7 +2155,7 @@ var tn = class {
2134
2155
  let r = n ?? "";
2135
2156
  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";
2136
2157
  if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
2137
- if (qt.has(e)) return "ERROR_STAGE_RESOLVE";
2158
+ if (Yt.has(e)) return "ERROR_STAGE_RESOLVE";
2138
2159
  let i = t ?? "";
2139
2160
  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";
2140
2161
  }
@@ -2181,14 +2202,14 @@ var tn = class {
2181
2202
  if (this.lastRequestCount = g, _ > 0) {
2182
2203
  o.requestCountDelta = _;
2183
2204
  let e = t.requestTimesMs ?? [], n = e.slice(Math.max(0, e.length - _)).sort((e, t) => e - t);
2184
- n.length > 0 && (o.requestTimeP50Ms = Kt(n, 50), o.requestTimeP95Ms = Kt(n, 95));
2205
+ n.length > 0 && (o.requestTimeP50Ms = Jt(n, 50), o.requestTimeP95Ms = Jt(n, 95));
2185
2206
  }
2186
2207
  typeof t.latencySeconds == "number" && typeof t.targetLatencySeconds == "number" && (o.driftMs = Math.round((t.latencySeconds - t.targetLatencySeconds) * 1e3)), typeof t.playbackRate == "number" && t.playbackRate > 0 && (o.playbackRate = t.playbackRate), t.qualityPinned === !0 && (o.qualityPinned = !0), t.cdnHost && (o.cdnHost = t.cdnHost), this.maybeEmitMediaInfo(t), this.enqueue({ heartbeat: o }), this.flush(), s > 0 && this.noteFirstBytes();
2187
2208
  }
2188
2209
  maybeEmitMediaInfo(e) {
2189
2210
  if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
2190
2211
  let t = {};
2191
- e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = Gt[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);
2212
+ e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = qt[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);
2192
2213
  let n = JSON.stringify(t);
2193
2214
  n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
2194
2215
  }
@@ -2208,7 +2229,7 @@ var tn = class {
2208
2229
  let c = r?.positionMs ?? 0;
2209
2230
  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));
2210
2231
  let l = e !== "END_REASON_ENDED";
2211
- l && this.lastStallMs > 0 && n - this.lastStallMs <= Ht && (i.abandonAfterStallMs = Math.max(q, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= Ht && (i.abandonAfterErrorMs = Math.max(q, Math.round(n - this.lastErrorMs))), this.fullscreenTotalMs > 0 && (i.fullscreenTimeMs = Math.round(this.fullscreenTotalMs)), this.pipTotalMs > 0 && (i.pipTimeMs = Math.round(this.pipTotalMs)), this.volumeChanges > 0 && (i.volumeChanges = this.volumeChanges), this.muteChanges > 0 && (i.muteChanges = this.muteChanges);
2232
+ l && this.lastStallMs > 0 && n - this.lastStallMs <= Wt && (i.abandonAfterStallMs = Math.max(q, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= Wt && (i.abandonAfterErrorMs = Math.max(q, Math.round(n - this.lastErrorMs))), this.fullscreenTotalMs > 0 && (i.fullscreenTimeMs = Math.round(this.fullscreenTotalMs)), this.pipTotalMs > 0 && (i.pipTimeMs = Math.round(this.pipTotalMs)), this.volumeChanges > 0 && (i.volumeChanges = this.volumeChanges), this.muteChanges > 0 && (i.muteChanges = this.muteChanges);
2212
2233
  let u = r?.decodedFrames ?? this.lastDecoded;
2213
2234
  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");
2214
2235
  }
@@ -2228,13 +2249,13 @@ var tn = class {
2228
2249
  };
2229
2250
  }
2230
2251
  noteCspBlocked() {
2231
- this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(Zt(new URL(this.url).origin)));
2252
+ this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.($t(new URL(this.url).origin)));
2232
2253
  }
2233
2254
  cspBlocked() {
2234
2255
  return !!this.cspKey && Y.has(this.cspKey);
2235
2256
  }
2236
2257
  enqueue(e) {
2237
- if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > Bt;) {
2258
+ if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > Ht;) {
2238
2259
  let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
2239
2260
  this.pending.splice(e >= 0 ? e : 0, 1);
2240
2261
  }
@@ -2261,7 +2282,7 @@ var tn = class {
2261
2282
  };
2262
2283
  //#endregion
2263
2284
  //#region src/core/environment.ts
2264
- function nn() {
2285
+ function an() {
2265
2286
  if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
2266
2287
  let e;
2267
2288
  try {
@@ -2286,14 +2307,14 @@ function nn() {
2286
2307
  integration: "INTEGRATION_KIND_IFRAME"
2287
2308
  };
2288
2309
  }
2289
- function rn() {
2310
+ function on() {
2290
2311
  if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
2291
2312
  let e = navigator.userAgentData, t = e?.platform ?? "";
2292
2313
  if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
2293
2314
  let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
2294
2315
  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";
2295
2316
  }
2296
- function an() {
2317
+ function sn() {
2297
2318
  let e = typeof navigator < "u" ? navigator.connection : void 0;
2298
2319
  if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
2299
2320
  let t = {
@@ -2312,17 +2333,17 @@ function an() {
2312
2333
  }
2313
2334
  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;
2314
2335
  }
2315
- function on(e) {
2316
- let t = nn(), n = {
2317
- deviceClass: rn(),
2336
+ function cn(e) {
2337
+ let t = an(), n = {
2338
+ deviceClass: on(),
2318
2339
  integration: t.integration,
2319
- ...an()
2340
+ ...sn()
2320
2341
  };
2321
2342
  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);
2322
2343
  let r = e.getBoundingClientRect?.();
2323
2344
  return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
2324
2345
  }
2325
- async function sn() {
2346
+ async function ln() {
2326
2347
  let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
2327
2348
  if (!e?.getHighEntropyValues) return {};
2328
2349
  try {
@@ -2334,7 +2355,7 @@ async function sn() {
2334
2355
  }
2335
2356
  //#endregion
2336
2357
  //#region src/core/version.ts
2337
- var cn = "2.15.3", ln = {
2358
+ var un = "2.15.5", dn = {
2338
2359
  accent: "#E1B600",
2339
2360
  accentText: "#1B1C23",
2340
2361
  background: "#0e0f13",
@@ -2345,7 +2366,7 @@ var cn = "2.15.3", ln = {
2345
2366
  border: "rgba(255, 255, 255, 0.1)",
2346
2367
  radius: "8px",
2347
2368
  fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
2348
- }, un = {
2369
+ }, fn = {
2349
2370
  accent: "--havik-accent",
2350
2371
  accentText: "--havik-accent-text",
2351
2372
  background: "--havik-bg",
@@ -2357,26 +2378,26 @@ var cn = "2.15.3", ln = {
2357
2378
  radius: "--havik-radius",
2358
2379
  fontFamily: "--havik-font"
2359
2380
  };
2360
- function dn(e, t) {
2381
+ function pn(e, t) {
2361
2382
  let n = {
2362
- ...ln,
2383
+ ...dn,
2363
2384
  ...t
2364
2385
  };
2365
- for (let t of Object.keys(un)) e.style.setProperty(un[t], n[t]);
2386
+ for (let t of Object.keys(fn)) e.style.setProperty(fn[t], n[t]);
2366
2387
  n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
2367
2388
  }
2368
2389
  //#endregion
2369
2390
  //#region src/ui/styles.ts
2370
- var fn = "havik-player-styles", pn = "\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", mn = /* @__PURE__ */ new WeakMap();
2371
- function hn(e = document, t) {
2372
- let n = e.querySelector(`style#${fn}`);
2373
- if (n && (!t || mn.get(n) === t)) return;
2391
+ var mn = "havik-player-styles", hn = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer;\n touch-action:manipulation}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n/* Absolutely centred, NOT a flex sibling of .havik-center: the hidden center\n button (.havik-gone) still occupies its 74px in the row, which pushed an\n in-flow spinner 37px right of centre. */\n.havik-spinner{position:absolute;inset:0;margin:auto;width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n/* A status card carries its own logo — the corner watermark would duplicate it. */\n.havik-player.havik-has-status .havik-watermark{display:none}\n\n.havik-bar{position:absolute;left:0;right:0;bottom:0;padding:0 12px 8px;\n opacity:1;transition:opacity .25s;z-index:2}\n.havik-seek{position:relative;height:16px;display:flex;align-items:center;cursor:pointer;margin-bottom:2px}\n.havik-seek__track{position:relative;width:100%;height:4px;border-radius:3px;background:rgba(255,255,255,.25)}\n.havik-seek__buffered{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:rgba(255,255,255,.4)}\n.havik-seek__played{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-seek__thumb{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;\n background:var(--havik-accent,#E1B600);transform:translate(-50%,-50%) scale(0);transition:transform .1s}\n.havik-seek:hover .havik-seek__thumb{transform:translate(-50%,-50%) scale(1)}\n\n.havik-controls{display:flex;align-items:center;gap:6px;height:40px}\n.havik-spacer{flex:1}\n.havik-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;border-radius:var(--havik-radius,8px);\n padding:0;transition:background .12s,color .12s}\n.havik-btn:hover{background:rgba(255,255,255,.12)}\n.havik-btn:focus-visible{outline:2px solid var(--havik-accent,#E1B600);outline-offset:1px}\n.havik-btn svg{width:22px;height:22px}\n\n/* The volume level is filled in accent up to the thumb, like the seek bar's\n played span — a native range input paints no \"elapsed\" side, which left the\n level readable only from the dot's position. --havik-vol (0..1) is set by\n syncVolume(); the track width and thumb size live here as variables because\n the WebKit fill has to compute the thumb centre from both. */\n.havik-vol{display:flex;align-items:center}\n.havik-vol__slider{--havik-vol-w:70px;--havik-vol-thumb:12px;--havik-vol:1;\n --havik-vol-pos:calc(var(--havik-vol-thumb) / 2 + var(--havik-vol) * (var(--havik-vol-w) - var(--havik-vol-thumb)));\n width:0;opacity:0;transition:width .18s,opacity .18s;height:4px;cursor:pointer;\n appearance:none;-webkit-appearance:none;background:transparent;border-radius:3px;margin:0 4px}\n.havik-vol:hover .havik-vol__slider,.havik-vol:focus-within .havik-vol__slider{width:var(--havik-vol-w);opacity:1}\n/* WebKit/Blink have no progress pseudo-element: paint the fill as a hard-stop\n gradient that ends at the thumb centre. */\n.havik-vol__slider::-webkit-slider-runnable-track{height:4px;border-radius:3px;\n background:linear-gradient(to right,var(--havik-accent,#E1B600) var(--havik-vol-pos),\n rgba(255,255,255,.3) var(--havik-vol-pos))}\n/* Firefox fills natively, and tracks the thumb exactly. */\n.havik-vol__slider::-moz-range-track{height:4px;border-radius:3px;background:rgba(255,255,255,.3)}\n.havik-vol__slider::-moz-range-progress{height:4px;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-vol__slider::-webkit-slider-thumb{-webkit-appearance:none;width:var(--havik-vol-thumb);\n height:var(--havik-vol-thumb);border-radius:50%;background:var(--havik-accent,#E1B600);\n margin-top:calc((4px - var(--havik-vol-thumb)) / 2)}\n.havik-vol__slider::-moz-range-thumb{width:var(--havik-vol-thumb);height:var(--havik-vol-thumb);\n border:0;border-radius:50%;background:var(--havik-accent,#E1B600)}\n\n.havik-time{font-size:12px;color:var(--havik-text-muted,#9aa0ad);\n font-variant-numeric:tabular-nums;padding:0 6px;white-space:nowrap}\n.havik-live{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;\n letter-spacing:.4px;padding:0 8px;color:var(--havik-text,#fff)}\n.havik-live svg{width:9px;height:9px;color:var(--havik-text-muted,#9aa0ad)}\n.havik-live.is-live svg{color:var(--havik-accent,#E1B600)}\n.havik-live__go{margin-left:2px;border:0;cursor:pointer;background:transparent;color:var(--havik-text-muted,#9aa0ad);\n font:inherit;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:6px}\n.havik-live.is-live .havik-live__go{display:none}\n.havik-live__go:hover{color:var(--havik-accent,#E1B600)}\n\n.havik-menu{position:absolute;bottom:54px;right:12px;min-width:170px;max-height:230px;overflow:auto;\n background:var(--havik-surface,#1B1C23);border:1px solid var(--havik-border,rgba(255,255,255,.1));\n border-radius:var(--havik-radius,8px);box-shadow:0 10px 30px rgba(0,0,0,.5);padding:6px;z-index:3}\n.havik-menu[hidden]{display:none}\n.havik-menu__title{font-size:11px;text-transform:uppercase;letter-spacing:.6px;\n color:var(--havik-text-muted,#9aa0ad);padding:6px 8px 4px}\n.havik-menu__item{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;font:inherit;font-size:13px;\n text-align:left;padding:7px 8px;border-radius:6px}\n.havik-menu__item:hover{background:var(--havik-surface-muted,#2a2c36)}\n.havik-menu__item[aria-checked=\"true\"]{color:var(--havik-accent,#E1B600);font-weight:600}\n.havik-menu__item[aria-checked=\"true\"]::after{content:'✓'}\n", Z = /* @__PURE__ */ new WeakMap();
2392
+ function gn(e = document, t) {
2393
+ let n = e.querySelector(`style#${mn}`);
2394
+ if (n && (!t || Z.get(n) === t)) return;
2374
2395
  let r = e.createElement("style");
2375
- r.id = fn, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = pn, mn.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
2396
+ r.id = mn, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = hn, Z.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
2376
2397
  }
2377
2398
  //#endregion
2378
2399
  //#region src/ui/icons.ts
2379
- var gn = {
2400
+ var _n = {
2380
2401
  play: "<path d=\"M8 5v14l11-7z\"/>",
2381
2402
  pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
2382
2403
  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\"/>",
@@ -2389,21 +2410,21 @@ var gn = {
2389
2410
  liveDot: "<circle cx=\"12\" cy=\"12\" r=\"6\"/>",
2390
2411
  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\"/>"
2391
2412
  };
2392
- function Z(e) {
2393
- return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${gn[e]}</svg>`;
2413
+ function Q(e) {
2414
+ return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${_n[e]}</svg>`;
2394
2415
  }
2395
2416
  //#endregion
2396
2417
  //#region src/ui/controls.ts
2397
- var _n = 3e3, vn = 250, yn = /* @__PURE__ */ new Set([
2418
+ var vn = 3e3, yn = 250, bn = /* @__PURE__ */ new Set([
2398
2419
  "GONE",
2399
2420
  "NOT_FOUND",
2400
2421
  "INVALID_URN",
2401
2422
  "UNAUTHORIZED"
2402
2423
  ]);
2403
- function bn(e) {
2404
- return new xn(e);
2424
+ function xn(e) {
2425
+ return new Sn(e);
2405
2426
  }
2406
- var xn = class {
2427
+ var Sn = class {
2407
2428
  root;
2408
2429
  video;
2409
2430
  player;
@@ -2449,7 +2470,7 @@ var xn = class {
2449
2470
  scrubbing = !1;
2450
2471
  offFns = [];
2451
2472
  constructor(e) {
2452
- this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? _n, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, hn(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");
2473
+ this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? vn, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, gn(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");
2453
2474
  let t = (e, t, n) => {
2454
2475
  let r = this.doc.createElement(e);
2455
2476
  if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
@@ -2460,12 +2481,12 @@ var xn = class {
2460
2481
  "aria-label": r,
2461
2482
  title: r
2462
2483
  });
2463
- return i.innerHTML = Z(n), i;
2484
+ return i.innerHTML = Q(n), i;
2464
2485
  };
2465
2486
  this.overlay = t("div", "havik-overlay"), this.center = t("button", "havik-center", {
2466
2487
  type: "button",
2467
2488
  "aria-label": "Play"
2468
- }), this.center.innerHTML = Z("play"), this.spinner = t("div", "havik-spinner"), this.spinner.style.display = "none", this.overlay.append(this.center, this.spinner), this.gradient = t("div", "havik-gradient"), this.bar = t("div", "havik-bar"), this.seek = t("div", "havik-seek", {
2489
+ }), this.center.innerHTML = Q("play"), this.spinner = t("div", "havik-spinner"), this.spinner.style.display = "none", this.overlay.append(this.center, this.spinner), this.gradient = t("div", "havik-gradient"), this.bar = t("div", "havik-bar"), this.seek = t("div", "havik-seek", {
2469
2490
  role: "slider",
2470
2491
  "aria-label": "Seek",
2471
2492
  "aria-valuemin": "0",
@@ -2483,7 +2504,7 @@ var xn = class {
2483
2504
  "aria-label": "Volume"
2484
2505
  });
2485
2506
  let a = t("div", "havik-vol");
2486
- a.append(this.muteBtn, this.volSlider), this.live = t("div", "havik-live"), this.live.innerHTML = Z("liveDot");
2507
+ a.append(this.muteBtn, this.volSlider), this.live = t("div", "havik-live"), this.live.innerHTML = Q("liveDot");
2487
2508
  let o = this.doc.createElement("span");
2488
2509
  o.textContent = "LIVE", this.liveGo = t("button", "havik-live__go", { type: "button" }), this.liveGo.textContent = "Go live", this.live.append(o, this.liveGo), this.time = t("div", "havik-time"), this.time.textContent = "0:00", this.time.style.display = "none";
2489
2510
  let s = t("div", "havik-spacer");
@@ -2535,7 +2556,7 @@ var xn = class {
2535
2556
  let t = this.surfaceWasHidden;
2536
2557
  this.tapTimer = setTimeout(() => {
2537
2558
  this.tapTimer = void 0, this.toggleBar(t);
2538
- }, vn);
2559
+ }, yn);
2539
2560
  }
2540
2561
  toggleBar(e) {
2541
2562
  e ? this.poke() : this.hideIfIdle();
@@ -2567,12 +2588,12 @@ var xn = class {
2567
2588
  }
2568
2589
  if (e === "preplay") {
2569
2590
  let e = this.doc.createElement("button");
2570
- e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML = Z("play"), e.addEventListener("click", () => void this.player.play()), n.append(e);
2591
+ e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML = Q("play"), e.addEventListener("click", () => void this.player.play()), n.append(e);
2571
2592
  } else {
2572
2593
  let r = this.doc.createElement("div");
2573
- if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !yn.has(this.lastError.code)) {
2594
+ if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !bn.has(this.lastError.code)) {
2574
2595
  let e = this.doc.createElement("button");
2575
- e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${Z("retry")}<span>Retry</span>`, e.addEventListener("click", () => void this.player.retry()), n.append(e);
2596
+ e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${Q("retry")}<span>Retry</span>`, e.addEventListener("click", () => void this.player.retry()), n.append(e);
2576
2597
  }
2577
2598
  }
2578
2599
  this.root.append(n), this.statusBox = n, this.show();
@@ -2611,7 +2632,7 @@ var xn = class {
2611
2632
  let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
2612
2633
  this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
2613
2634
  }
2614
- !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Sn(this.video.currentTime)} / ${Sn(this.video.duration)}`);
2635
+ !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Cn(this.video.currentTime)} / ${Cn(this.video.duration)}`);
2615
2636
  }
2616
2637
  syncLive() {
2617
2638
  let e = this.player.getStats(), t = e.isLive !== !1;
@@ -2661,17 +2682,17 @@ var xn = class {
2661
2682
  renderQualityMenu() {
2662
2683
  let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
2663
2684
  n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
2664
- for (let n of e) this.menu.append(this.menuItem(Cn(n), t === n.index, () => this.player.setQuality(n.index)));
2685
+ for (let n of e) this.menu.append(this.menuItem(wn(n), t === n.index, () => this.player.setQuality(n.index)));
2665
2686
  }
2666
2687
  renderAudioMenu() {
2667
2688
  let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
2668
2689
  t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
2669
- for (let t of e) this.menu.append(this.menuItem(wn(t), t.default, () => this.player.setAudioTrack(t.id)));
2690
+ for (let t of e) this.menu.append(this.menuItem(Tn(t), t.default, () => this.player.setAudioTrack(t.id)));
2670
2691
  }
2671
2692
  renderCcMenu() {
2672
2693
  let e = this.player.getTextTracks(), t = this.doc.createElement("div");
2673
2694
  t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
2674
- for (let t of e) this.menu.append(this.menuItem(Tn(t), !1, () => this.player.setTextTrack(t.id)));
2695
+ for (let t of e) this.menu.append(this.menuItem(En(t), !1, () => this.player.setTextTrack(t.id)));
2675
2696
  }
2676
2697
  onTracksChanged() {
2677
2698
  this.openMenu && this.renderMenu(this.openMenu);
@@ -2691,11 +2712,11 @@ var xn = class {
2691
2712
  }
2692
2713
  async toggleFullscreen() {
2693
2714
  try {
2694
- S(this.video, this.root) ? await w(this.video, this.root) : await C(this.video, this.root);
2715
+ C(this.video, this.root) ? await T(this.video, this.root) : await w(this.video, this.root);
2695
2716
  } catch {}
2696
2717
  }
2697
2718
  syncFullscreen() {
2698
- let e = S(this.video, this.root);
2719
+ let e = C(this.video, this.root);
2699
2720
  this.setIcon(this.fsBtn, e ? "fullscreenExit" : "fullscreen"), this.fsBtn.setAttribute("aria-label", e ? "Exit fullscreen" : "Fullscreen");
2700
2721
  }
2701
2722
  poke() {
@@ -2755,7 +2776,7 @@ var xn = class {
2755
2776
  }
2756
2777
  }
2757
2778
  setIcon(e, t) {
2758
- e.innerHTML = Z(t);
2779
+ e.innerHTML = Q(t);
2759
2780
  }
2760
2781
  destroy() {
2761
2782
  this.hideTimer && clearTimeout(this.hideTimer), this.tapTimer && clearTimeout(this.tapTimer);
@@ -2772,41 +2793,41 @@ var xn = class {
2772
2793
  this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
2773
2794
  }
2774
2795
  };
2775
- function Sn(e) {
2796
+ function Cn(e) {
2776
2797
  (!Number.isFinite(e) || e < 0) && (e = 0);
2777
2798
  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");
2778
2799
  return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
2779
2800
  }
2780
- function Cn(e) {
2801
+ function wn(e) {
2781
2802
  return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
2782
2803
  }
2783
- function wn(e) {
2804
+ function Tn(e) {
2784
2805
  return e.name || e.lang || `Track ${e.id}`;
2785
2806
  }
2786
- function Tn(e) {
2807
+ function En(e) {
2787
2808
  return e.name || e.lang || `Track ${e.id}`;
2788
2809
  }
2789
2810
  //#endregion
2790
2811
  //#region src/managed/index.ts
2791
- var En = 6e3, Dn = 45e3, Q = 2e3, On = 3, kn = 2e3, An = 48e4;
2792
- function jn(e) {
2812
+ var Dn = 6e3, On = 45e3, kn = 2e3, An = 3, jn = 2e3, Mn = 48e4;
2813
+ function Nn(e) {
2793
2814
  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)})`);
2794
- if (e.env !== void 0) return Ve(e.env);
2815
+ if (e.env !== void 0) return B(e.env);
2795
2816
  if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
2796
2817
  return e.baseUrl;
2797
2818
  }
2798
- async function Mn(e) {
2819
+ async function Pn(e) {
2799
2820
  if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
2800
- let t = jn(e);
2821
+ let t = Nn(e);
2801
2822
  if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
2802
2823
  if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
2803
- let r = new Nn({
2824
+ let r = new Fn({
2804
2825
  ...e,
2805
2826
  baseUrl: t
2806
2827
  });
2807
2828
  return await r.start(), r;
2808
2829
  }
2809
- var Nn = class {
2830
+ var Fn = class {
2810
2831
  opts;
2811
2832
  abort = new AbortController();
2812
2833
  listeners = {};
@@ -2873,7 +2894,7 @@ var Nn = class {
2873
2894
  };
2874
2895
  }
2875
2896
  beginArming(e, t, n = !1) {
2876
- let r = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? E(this.opts.baseUrl);
2897
+ let r = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? D(this.opts.baseUrl);
2877
2898
  r ? this.armWithSse(e, r, t, n) : this.beginArmingByPolling(e);
2878
2899
  }
2879
2900
  beginArmingByPolling(e) {
@@ -2894,7 +2915,7 @@ var Nn = class {
2894
2915
  setTimeout(() => {
2895
2916
  a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
2896
2917
  phase: i ? "unavailable" : "tooEarly",
2897
- retryInMs: Dn,
2918
+ retryInMs: On,
2898
2919
  attempt: 1,
2899
2920
  elapsedMs: 0,
2900
2921
  ...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
@@ -2933,13 +2954,13 @@ var Nn = class {
2933
2954
  !a && !p() && h();
2934
2955
  }, e);
2935
2956
  };
2936
- _(En), this.armingSub = T({
2957
+ _(Dn), this.armingSub = E({
2937
2958
  eventsBaseUrl: t,
2938
2959
  matchUrn: this.opts.matchUrn,
2939
2960
  credential: this.opts.credential,
2940
- onAlive: () => _(Dn),
2961
+ onAlive: () => _(On),
2941
2962
  onState: (e) => {
2942
- a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Q);
2963
+ a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * kn);
2943
2964
  },
2944
2965
  onError: () => h()
2945
2966
  });
@@ -2962,7 +2983,7 @@ var Nn = class {
2962
2983
  let n = await s(this.opts.credential);
2963
2984
  if (this.destroyed || t !== this.loadGen) return;
2964
2985
  this.setState("loading");
2965
- let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = Ke(this.opts.video, (e) => {
2986
+ let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = qe(this.opts.video, (e) => {
2966
2987
  this._state !== "ended" && this._state !== "error" && this.setState(e);
2967
2988
  });
2968
2989
  if (await i.load(), this.destroyed || t !== this.loadGen) {
@@ -2984,26 +3005,26 @@ var Nn = class {
2984
3005
  if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
2985
3006
  let i = e.analytics?.sid;
2986
3007
  if (!i) return;
2987
- let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = en(this.opts.baseUrl, a, e.analytics?.endpoint);
3008
+ let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = nn(this.opts.baseUrl, a, e.analytics?.endpoint);
2988
3009
  if (!o) {
2989
3010
  s && setTimeout(() => {
2990
3011
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
2991
3012
  }, 0);
2992
3013
  return;
2993
3014
  }
2994
- let c = this.opts.video, l = new tn({
3015
+ let c = this.opts.video, l = new rn({
2995
3016
  endpoint: o,
2996
3017
  sid: i,
2997
3018
  player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
2998
- sdkVersion: cn,
2999
- environment: on(c),
3019
+ sdkVersion: un,
3020
+ environment: cn(c),
3000
3021
  idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
3001
3022
  onIdle: () => this.onAnalyticsIdle(t),
3002
3023
  onBlocked: (e) => setTimeout(() => {
3003
3024
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, e));
3004
3025
  }, 0),
3005
3026
  sample: () => {
3006
- let e = this.engine?.getStats() ?? He, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
3027
+ let e = this.engine?.getStats() ?? V, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
3007
3028
  return {
3008
3029
  ...e,
3009
3030
  bufferedMs: Math.round(t * 1e3),
@@ -3017,7 +3038,7 @@ var Nn = class {
3017
3038
  let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
3018
3039
  c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
3019
3040
  c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
3020
- }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), sn().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
3041
+ }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), ln().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
3021
3042
  }
3022
3043
  currentPresentation() {
3023
3044
  let e = this.opts.video;
@@ -3032,7 +3053,7 @@ var Nn = class {
3032
3053
  video: this.opts.video,
3033
3054
  descriptor: e,
3034
3055
  credential: t,
3035
- deviceId: k(),
3056
+ deviceId: A(),
3036
3057
  userId: this.opts.userId,
3037
3058
  lowLatency: this.opts.lowLatency === void 0 || this.opts.lowLatency === "auto" || this.opts.lowLatency,
3038
3059
  snapToLiveOnRefocus: this.opts.snapToLiveOnRefocus,
@@ -3043,10 +3064,10 @@ var Nn = class {
3043
3064
  emit: (e) => this.onEngineEvent(e)
3044
3065
  }, o = this.opts.engine ?? "auto";
3045
3066
  if (o === "native") return new K(a);
3046
- if (o === "hls") return new It(a);
3047
- if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && G(this.opts.video) && Je()) return new K(a);
3048
- if (at()) return new It(a);
3049
- if (G(this.opts.video)) return new K(a);
3067
+ if (o === "hls") return new Rt(a);
3068
+ if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && W(this.opts.video) && G() || !e.drmEnabled && Ye() && W(this.opts.video)) return new K(a);
3069
+ if (ot()) return new Rt(a);
3070
+ if (W(this.opts.video)) return new K(a);
3050
3071
  throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
3051
3072
  }
3052
3073
  onEngineEvent(e) {
@@ -3083,11 +3104,11 @@ var Nn = class {
3083
3104
  }
3084
3105
  startLiveState(e) {
3085
3106
  if (this.opts.liveStateEvents === !1) return;
3086
- let t = this.opts.eventsBaseUrl ?? E(this.opts.baseUrl);
3107
+ let t = this.opts.eventsBaseUrl ?? D(this.opts.baseUrl);
3087
3108
  if (!t) return;
3088
3109
  this.closeLiveState();
3089
3110
  let r = 0, i = !1;
3090
- this.liveStateSub = T({
3111
+ this.liveStateSub = E({
3091
3112
  eventsBaseUrl: t,
3092
3113
  matchUrn: this.opts.matchUrn,
3093
3114
  credential: this.opts.credential,
@@ -3098,7 +3119,7 @@ var Nn = class {
3098
3119
  r = 0, i = !1;
3099
3120
  },
3100
3121
  onError: () => {
3101
- this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= On && (i = !0, this.emit("warning", new n("NETWORK", 0, `live-state events unreachable at ${t} after ${r} attempts — end-of-stream detection degraded to the HLS staleness watchdog. Check the events host, the api-key's allowed origins, and CSP connect-src.`))));
3122
+ this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= An && (i = !0, this.emit("warning", new n("NETWORK", 0, `live-state events unreachable at ${t} after ${r} attempts — end-of-stream detection degraded to the HLS staleness watchdog. Check the events host, the api-key's allowed origins, and CSP connect-src.`))));
3102
3123
  }
3103
3124
  });
3104
3125
  }
@@ -3120,7 +3141,7 @@ var Nn = class {
3120
3141
  scheduleRejoin(e) {
3121
3142
  this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
3122
3143
  this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
3123
- }, Math.random() * Q));
3144
+ }, Math.random() * kn));
3124
3145
  }
3125
3146
  cancelRejoin() {
3126
3147
  this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
@@ -3144,7 +3165,7 @@ var Nn = class {
3144
3165
  }
3145
3166
  t.controls = !1;
3146
3167
  let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
3147
- r && r.insertBefore(n, t), n.appendChild(t), dn(n, this.opts.theme), this.container = n, this.controlBar = bn({
3168
+ r && r.insertBefore(n, t), n.appendChild(t), pn(n, this.opts.theme), this.container = n, this.controlBar = xn({
3148
3169
  root: n,
3149
3170
  video: t,
3150
3171
  player: this,
@@ -3175,7 +3196,7 @@ var Nn = class {
3175
3196
  }
3176
3197
  startStats() {
3177
3198
  this.stopStats();
3178
- let e = Math.max(500, this.opts.statsIntervalMs ?? kn);
3199
+ let e = Math.max(500, this.opts.statsIntervalMs ?? jn);
3179
3200
  this.statsTimer = setInterval(() => {
3180
3201
  if (!this.engine) return;
3181
3202
  let e = this.engine.getStats();
@@ -3187,7 +3208,7 @@ var Nn = class {
3187
3208
  }
3188
3209
  scheduleLicenseRefresh() {
3189
3210
  this.stopRefresh();
3190
- let e = this.opts.licenseRefreshMs ?? An;
3211
+ let e = this.opts.licenseRefreshMs ?? Mn;
3191
3212
  e && this._descriptor?.drmEnabled && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
3192
3213
  }
3193
3214
  stopRefresh() {
@@ -3232,7 +3253,7 @@ var Nn = class {
3232
3253
  this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
3233
3254
  }
3234
3255
  getStats() {
3235
- return this.engine?.getStats() ?? He;
3256
+ return this.engine?.getStats() ?? V;
3236
3257
  }
3237
3258
  getQualityLevels() {
3238
3259
  return this.engine?.getQualityLevels() ?? [];
@@ -3271,10 +3292,10 @@ var Nn = class {
3271
3292
  e.pictureInPictureElement === this.opts.video && typeof e.exitPictureInPicture == "function" && await e.exitPictureInPicture();
3272
3293
  }
3273
3294
  async enterFullscreen() {
3274
- return !this.destroyed && C(this.opts.video, this.container ?? void 0);
3295
+ return !this.destroyed && w(this.opts.video, this.container ?? void 0);
3275
3296
  }
3276
3297
  async exitFullscreen() {
3277
- await w(this.opts.video, this.container ?? void 0);
3298
+ await T(this.opts.video, this.container ?? void 0);
3278
3299
  }
3279
3300
  retry() {
3280
3301
  return this.reload();
@@ -3342,7 +3363,7 @@ function $(e) {
3342
3363
  }
3343
3364
  //#endregion
3344
3365
  //#region src/embed/host.ts
3345
- function Pn(e) {
3366
+ function In(e) {
3346
3367
  if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
3347
3368
  if (!e.src) throw Error("mountEmbed: opts.src is required");
3348
3369
  if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
@@ -3401,15 +3422,15 @@ function Pn(e) {
3401
3422
  }
3402
3423
  //#endregion
3403
3424
  //#region src/embed/page.ts
3404
- var Fn = /^[A-Za-z0-9:_.-]{1,128}$/;
3405
- function In(e) {
3425
+ var Ln = /^[A-Za-z0-9:_.-]{1,128}$/;
3426
+ function Rn(e) {
3406
3427
  if (typeof e == "boolean") return e;
3407
3428
  if (typeof e == "object" && e) {
3408
3429
  let t = e.endpoint;
3409
3430
  return typeof t == "string" ? { endpoint: t } : {};
3410
3431
  }
3411
3432
  }
3412
- function Ln() {
3433
+ function zn() {
3413
3434
  let e = window.HAVIK_EMBED_CONFIG;
3414
3435
  if (e) return {
3415
3436
  baseUrl: e.baseUrl ?? "",
@@ -3419,7 +3440,7 @@ function Ln() {
3419
3440
  autoplay: e.autoplay ?? !0,
3420
3441
  muted: e.muted ?? !0,
3421
3442
  waitForLive: e.waitForLive ?? !0,
3422
- analytics: In(e.analytics)
3443
+ analytics: Rn(e.analytics)
3423
3444
  };
3424
3445
  let t = new URLSearchParams(location.search);
3425
3446
  return {
@@ -3432,9 +3453,9 @@ function Ln() {
3432
3453
  waitForLive: !0
3433
3454
  };
3434
3455
  }
3435
- async function Rn() {
3436
- let e = Ln();
3437
- Bn();
3456
+ async function Bn() {
3457
+ let e = zn();
3458
+ Hn();
3438
3459
  let t = document.createElement("video");
3439
3460
  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);
3440
3461
  let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
@@ -3489,12 +3510,12 @@ async function Rn() {
3489
3510
  code: e.code,
3490
3511
  message: e.message
3491
3512
  })), e.on("autoplayblocked", () => {
3492
- i({ type: "oddin:autoplayblocked" }), zn(t, e);
3513
+ i({ type: "oddin:autoplayblocked" }), Vn(t, e);
3493
3514
  });
3494
3515
  }, s = async (r) => {
3495
3516
  a?.destroy(), a = null;
3496
3517
  try {
3497
- let n = await Mn({
3518
+ let n = await Pn({
3498
3519
  video: t,
3499
3520
  baseUrl: e.baseUrl,
3500
3521
  matchUrn: r,
@@ -3556,7 +3577,7 @@ async function Rn() {
3556
3577
  a?.retry();
3557
3578
  break;
3558
3579
  case "oddin:load":
3559
- typeof e.matchUrn == "string" && Fn.test(e.matchUrn) && s(e.matchUrn);
3580
+ typeof e.matchUrn == "string" && Ln.test(e.matchUrn) && s(e.matchUrn);
3560
3581
  break;
3561
3582
  case "oddin:destroy": c();
3562
3583
  }
@@ -3568,18 +3589,18 @@ async function Rn() {
3568
3589
  protocol: 1
3569
3590
  });
3570
3591
  }
3571
- function zn(e, t) {
3592
+ function Vn(e, t) {
3572
3593
  if (document.getElementById("havik-tap")) return;
3573
3594
  let n = document.createElement("button");
3574
3595
  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", () => {
3575
3596
  n.remove(), t.play();
3576
3597
  }), document.body.appendChild(n);
3577
3598
  }
3578
- function Bn() {
3599
+ function Hn() {
3579
3600
  let e = document.createElement("style");
3580
3601
  e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
3581
3602
  }
3582
3603
  //#endregion
3583
- export { ln as ODDIN_THEME, n as PlaybackError, dn as applyTheme, Ve as baseUrlForEnv, Rn as bootEmbed, Te as clearDeviceId, Mn as createPlayer, E as deriveEventsBaseUrl, Le as detectDrmSupport, C as enterVideoFullscreen, w as exitVideoFullscreen, _e as fetchCatalog, ye as fetchTournament, xe as flattenMatches, k as getDeviceId, ze as isLowLatencyManifest, $ as isOddinMessage, De as licenseRequestHeaders, Pn as mountEmbed, v as pollToLive, b as resolveStream, T as subscribeLiveState, S as videoFullscreenActive, Ce as watchStatus };
3604
+ export { dn as ODDIN_THEME, n as PlaybackError, pn as applyTheme, B as baseUrlForEnv, Bn as bootEmbed, we as clearDeviceId, Pn as createPlayer, D as deriveEventsBaseUrl, Ve as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, ge as fetchCatalog, ve as fetchTournament, be as flattenMatches, A as getDeviceId, Ue as isLowLatencyManifest, $ as isOddinMessage, Ee as licenseRequestHeaders, In as mountEmbed, v as pollToLive, b as resolveStream, E as subscribeLiveState, C as videoFullscreenActive, Se as watchStatus };
3584
3605
 
3585
3606
  //# sourceMappingURL=index.js.map