@oddin-gg/havik-player 2.11.0 → 2.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -267,35 +267,35 @@ function de(e, t) {
267
267
  }
268
268
  //#endregion
269
269
  //#region src/core/fullscreen.ts
270
- function fe(e) {
270
+ function S(e) {
271
271
  return e.ownerDocument ?? document;
272
272
  }
273
- function S(e) {
273
+ function C(e) {
274
274
  return e.fullscreenElement ?? e.webkitFullscreenElement ?? null;
275
275
  }
276
- function C(e, t) {
277
- let n = S(fe(e));
276
+ function w(e, t) {
277
+ let n = C(S(e));
278
278
  return n != null && (n === e || t != null && n === t) || e.webkitDisplayingFullscreen === !0;
279
279
  }
280
- async function w(e, t) {
280
+ async function T(e, t) {
281
281
  let n = t ?? e;
282
282
  if (typeof n.requestFullscreen == "function") return await n.requestFullscreen(), !0;
283
283
  if (typeof n.webkitRequestFullscreen == "function") return n.webkitRequestFullscreen(), !0;
284
284
  let r = e;
285
285
  return r.webkitSupportsFullscreen && typeof r.webkitEnterFullscreen == "function" ? (r.webkitEnterFullscreen(), !0) : !1;
286
286
  }
287
- async function T(e, t) {
287
+ async function E(e, t) {
288
288
  let n = e;
289
289
  if (n.webkitDisplayingFullscreen) {
290
290
  n.webkitExitFullscreen?.();
291
291
  return;
292
292
  }
293
- let r = fe(e), i = S(r);
293
+ let r = S(e), i = C(r);
294
294
  i != null && (i === e || t != null && i === t) && (typeof r.exitFullscreen == "function" ? await r.exitFullscreen() : r.webkitExitFullscreen?.());
295
295
  }
296
296
  //#endregion
297
297
  //#region src/core/catalog.ts
298
- async function pe(e) {
298
+ async function fe(e) {
299
299
  let t = new URLSearchParams();
300
300
  e.status && t.set("status", Array.isArray(e.status) ? e.status.join(",") : e.status), e.sport && t.set("sport", e.sport);
301
301
  let i = t.toString(), a = d(e.baseUrl, "/v1/catalog" + (i ? `?${i}` : "")), o = new Headers();
@@ -313,12 +313,12 @@ async function pe(e) {
313
313
  };
314
314
  if (!s.ok) throw new n(r(s.status), s.status, `catalog request failed (HTTP ${s.status})`);
315
315
  return {
316
- tournaments: me(await s.json()),
316
+ tournaments: pe(await s.json()),
317
317
  etag: s.headers.get("etag") ?? void 0,
318
318
  notModified: !1
319
319
  };
320
320
  }
321
- function me(e) {
321
+ function pe(e) {
322
322
  return (e.tournaments ?? []).map((e) => {
323
323
  let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
324
324
  return {
@@ -340,7 +340,7 @@ function me(e) {
340
340
  };
341
341
  });
342
342
  }
343
- async function he(e) {
343
+ async function me(e) {
344
344
  let t = d(e.baseUrl, `/v1/tournaments/${encodeURIComponent(e.urn)}`), i = new Headers();
345
345
  e.etag && i.set("If-None-Match", e.etag);
346
346
  let a = await p(t, {
@@ -360,13 +360,13 @@ async function he(e) {
360
360
  };
361
361
  if (!a.ok) throw new n(r(a.status), a.status, `tournament request failed (HTTP ${a.status})`);
362
362
  return {
363
- tournament: ge(await a.json()),
363
+ tournament: he(await a.json()),
364
364
  etag: a.headers.get("etag") ?? void 0,
365
365
  notModified: !1,
366
366
  notFound: !1
367
367
  };
368
368
  }
369
- function ge(e) {
369
+ function he(e) {
370
370
  let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
371
371
  return {
372
372
  urn: t,
@@ -386,12 +386,12 @@ function ge(e) {
386
386
  }))
387
387
  };
388
388
  }
389
- function _e(e) {
389
+ function ge(e) {
390
390
  return e.tournaments.flatMap((e) => e.matches);
391
391
  }
392
392
  //#endregion
393
393
  //#region src/core/poll.ts
394
- function ve(e) {
394
+ function _e(e) {
395
395
  let t = Math.max(2e3, e.intervalMs ?? 1e4), i = new AbortController(), a, o, s, u = !1, f = () => {
396
396
  u || (a = setTimeout(m, t));
397
397
  }, m = async () => {
@@ -433,9 +433,9 @@ function ve(e) {
433
433
  }
434
434
  //#endregion
435
435
  //#region src/core/events.ts
436
- var ye = 45e3;
437
- function E(e) {
438
- let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = e.idleTimeoutMs ?? ye, i = Number.isFinite(r) && r > 0 ? r : 0, a = new AbortController(), o = !1, c = (e) => new Promise((t) => {
436
+ var ve = 45e3;
437
+ function D(e) {
438
+ let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = e.idleTimeoutMs ?? ve, i = Number.isFinite(r) && r > 0 ? r : 0, a = new AbortController(), o = !1, c = (e) => new Promise((t) => {
439
439
  if (a.signal.aborted) return t();
440
440
  let n = setTimeout(t, e);
441
441
  a.signal.addEventListener("abort", () => {
@@ -516,7 +516,7 @@ function E(e) {
516
516
  o || (o = !0, a.abort());
517
517
  } };
518
518
  }
519
- function D(e) {
519
+ function O(e) {
520
520
  try {
521
521
  let t = new URL(e);
522
522
  return t.hostname = `events.${t.hostname}`, t.pathname = "", t.search = "", t.origin;
@@ -526,27 +526,27 @@ function D(e) {
526
526
  }
527
527
  //#endregion
528
528
  //#region src/core/drm/deviceId.ts
529
- var O = "havik.player.deviceId", k;
530
- function A() {
531
- if (k) return k;
529
+ var k = "havik.player.deviceId", A;
530
+ function j() {
531
+ if (A) return A;
532
532
  try {
533
- let e = globalThis.localStorage?.getItem(O);
534
- if (e) return k = e, e;
533
+ let e = globalThis.localStorage?.getItem(k);
534
+ if (e) return A = e, e;
535
535
  } catch {}
536
- let e = xe();
537
- k = e;
536
+ let e = be();
537
+ A = e;
538
538
  try {
539
- globalThis.localStorage?.setItem(O, e);
539
+ globalThis.localStorage?.setItem(k, e);
540
540
  } catch {}
541
541
  return e;
542
542
  }
543
- function be() {
544
- k = void 0;
543
+ function ye() {
544
+ A = void 0;
545
545
  try {
546
- globalThis.localStorage?.removeItem(O);
546
+ globalThis.localStorage?.removeItem(k);
547
547
  } catch {}
548
548
  }
549
- function xe() {
549
+ function be() {
550
550
  let e = globalThis.crypto;
551
551
  if (e && typeof e.randomUUID == "function") return e.randomUUID();
552
552
  let t = /* @__PURE__ */ new Uint8Array(16);
@@ -558,21 +558,21 @@ function xe() {
558
558
  }
559
559
  //#endregion
560
560
  //#region src/core/drm/headers.ts
561
- function Se(e, t, n = {}) {
561
+ function xe(e, t, n = {}) {
562
562
  let r = {
563
563
  "x-api-key": t.apiKey,
564
564
  "X-Match-Urn": e.matchUrn,
565
- "X-Device-Id": n.deviceId ?? A(),
565
+ "X-Device-Id": n.deviceId ?? j(),
566
566
  "Content-Type": "application/octet-stream"
567
567
  };
568
568
  return n.userId && (r["X-User-Id"] = n.userId), r;
569
569
  }
570
570
  //#endregion
571
571
  //#region src/core/drm/cdm.ts
572
- var j = /* @__PURE__ */ new WeakMap();
573
- function Ce(e, t) {
574
- let n = j.get(e);
575
- n || (n = /* @__PURE__ */ new Map(), j.set(e, n));
572
+ var M = /* @__PURE__ */ new WeakMap();
573
+ function Se(e, t) {
574
+ let n = M.get(e);
575
+ n || (n = /* @__PURE__ */ new Map(), M.set(e, n));
576
576
  let r = n.get(t.keySystem);
577
577
  if (r) return r;
578
578
  let i = t.createMediaKeys().catch((e) => {
@@ -580,22 +580,22 @@ function Ce(e, t) {
580
580
  });
581
581
  return n.set(t.keySystem, i), i;
582
582
  }
583
- function M() {
583
+ function N() {
584
584
  return typeof navigator < "u" && typeof navigator.requestMediaKeySystemAccess == "function";
585
585
  }
586
- var N = ["SW_SECURE_DECODE", "SW_SECURE_CRYPTO"];
587
- function we(e) {
586
+ var P = ["SW_SECURE_DECODE", "SW_SECURE_CRYPTO"];
587
+ function Ce(e) {
588
588
  return e.startsWith("com.widevine");
589
589
  }
590
- function P(e, t) {
591
- if (!we(e)) return t;
590
+ function F(e, t) {
591
+ if (!Ce(e)) return t;
592
592
  let n = (e, t) => {
593
593
  let n = e.videoCapabilities;
594
594
  return !n?.length || !n.some((e) => e.robustness) ? !1 : n.every((e) => {
595
- let n = N.indexOf(e.robustness);
596
- return n === -1 || N.indexOf(t) > n;
595
+ let n = P.indexOf(e.robustness);
596
+ return n === -1 || P.indexOf(t) > n;
597
597
  });
598
- }, r = N.flatMap((e) => t.filter((t) => n(t, e)).map((t) => ({
598
+ }, r = P.flatMap((e) => t.filter((t) => n(t, e)).map((t) => ({
599
599
  ...t,
600
600
  videoCapabilities: t.videoCapabilities?.map((t) => ({
601
601
  ...t,
@@ -604,41 +604,87 @@ function P(e, t) {
604
604
  })));
605
605
  return [...t, ...r];
606
606
  }
607
- function Te(e) {
608
- return (t, n) => M() ? navigator.requestMediaKeySystemAccess(t, P(t, n)).then((t) => ({
607
+ function we(e) {
608
+ return (t, n) => N() ? navigator.requestMediaKeySystemAccess(t, F(t, n)).then((t) => ({
609
609
  keySystem: t.keySystem,
610
610
  getConfiguration: () => t.getConfiguration(),
611
- createMediaKeys: () => Ce(e, t)
611
+ createMediaKeys: () => Se(e, t)
612
612
  })) : Promise.reject(/* @__PURE__ */ Error("navigator.requestMediaKeySystemAccess is unavailable — EME needs a secure context (https, or localhost)"));
613
613
  }
614
- var F = {
614
+ var I = {
615
615
  video: "SW_SECURE_DECODE",
616
616
  audio: "SW_SECURE_CRYPTO",
617
617
  scheme: "cbcs"
618
618
  };
619
- function Ee(e) {
620
- if (!M()) return;
619
+ function Te(e) {
620
+ if (!N()) return;
621
621
  let t = (e, t) => ({
622
622
  contentType: e,
623
623
  robustness: t,
624
- encryptionScheme: F.scheme
624
+ encryptionScheme: I.scheme
625
625
  });
626
- Te(e)("com.widevine.alpha", [{
626
+ we(e)("com.widevine.alpha", [{
627
627
  initDataTypes: ["cenc"],
628
628
  distinctiveIdentifier: "optional",
629
629
  persistentState: "optional",
630
630
  sessionTypes: ["temporary"],
631
- audioCapabilities: [t("audio/mp4; codecs=\"mp4a.40.2\"", F.audio)],
632
- videoCapabilities: [t("video/mp4; codecs=\"avc1.42e01e\"", F.video)]
631
+ audioCapabilities: [t("audio/mp4; codecs=\"mp4a.40.2\"", I.audio)],
632
+ videoCapabilities: [t("video/mp4; codecs=\"avc1.42e01e\"", I.video)]
633
633
  }]).then((e) => e.createMediaKeys()).catch(() => {});
634
634
  }
635
+ function L(e) {
636
+ let t = R(e);
637
+ if (/^avc[13]/.test(t)) return "avc";
638
+ if (/^(hvc1|hev1)/.test(t)) return "hevc";
639
+ if (/^(dvh1|dvhe)/.test(t)) return "dv";
640
+ if (t.startsWith("av01")) return "av1";
641
+ if (/^vp0?9/.test(t)) return "vp9";
642
+ }
643
+ function R(e) {
644
+ return (e ?? "").trim().toLowerCase();
645
+ }
646
+ var Ee = {
647
+ hevc: "hvc1.1.6.L93.90",
648
+ dv: "dvh1.05.06",
649
+ av1: "av01.0.05M.08",
650
+ vp9: "vp09.00.10.08"
651
+ }, De = /* @__PURE__ */ new Map(), z = /* @__PURE__ */ new Map();
652
+ function Oe(e) {
653
+ let t = R(e), n = De.get(t);
654
+ if (n) return n;
655
+ let r = {
656
+ initDataTypes: ["cenc"],
657
+ distinctiveIdentifier: "optional",
658
+ persistentState: "optional",
659
+ sessionTypes: ["temporary"],
660
+ videoCapabilities: [{
661
+ contentType: `video/mp4; codecs="${e.trim()}"`,
662
+ robustness: I.video,
663
+ encryptionScheme: I.scheme
664
+ }]
665
+ }, i = (async () => {
666
+ try {
667
+ return await navigator.requestMediaKeySystemAccess("com.widevine.alpha", F("com.widevine.alpha", [r])), !0;
668
+ } catch {
669
+ return !1;
670
+ }
671
+ })().then((e) => (z.set(t, e), e));
672
+ return De.set(t, i), i;
673
+ }
674
+ function ke() {
675
+ if (N()) for (let e of Object.values(Ee)) Oe(e);
676
+ }
677
+ function Ae(e) {
678
+ let t = L(e);
679
+ if (t) return t === "avc" ? !0 : z.get(R(e)) ?? z.get(R(Ee[t]));
680
+ }
635
681
  //#endregion
636
682
  //#region src/core/drm/support.ts
637
- var De = 5e3, Oe = "video/mp4; codecs=\"avc1.42E01E\"", ke = "audio/mp4; codecs=\"mp4a.40.2\"", Ae = {
683
+ var je = 5e3, Me = "video/mp4; codecs=\"avc1.42E01E\"", B = "audio/mp4; codecs=\"mp4a.40.2\"", Ne = {
638
684
  widevine: ["com.widevine.alpha"],
639
685
  fairplay: ["com.apple.fps"]
640
686
  };
641
- function je(e) {
687
+ function Pe(e) {
642
688
  return e === "fairplay" ? [{
643
689
  initDataTypes: [
644
690
  "sinf",
@@ -646,30 +692,30 @@ function je(e) {
646
692
  "cenc"
647
693
  ],
648
694
  videoCapabilities: [{
649
- contentType: Oe,
695
+ contentType: Me,
650
696
  robustness: "",
651
697
  encryptionScheme: "cbcs"
652
698
  }],
653
699
  audioCapabilities: [{
654
- contentType: ke,
700
+ contentType: B,
655
701
  robustness: "",
656
702
  encryptionScheme: "cbcs"
657
703
  }]
658
- }] : P("com.widevine.alpha", [{
704
+ }] : F("com.widevine.alpha", [{
659
705
  initDataTypes: ["cenc"],
660
706
  videoCapabilities: [{
661
- contentType: Oe,
662
- robustness: F.video,
663
- encryptionScheme: F.scheme
707
+ contentType: Me,
708
+ robustness: I.video,
709
+ encryptionScheme: I.scheme
664
710
  }],
665
711
  audioCapabilities: [{
666
- contentType: ke,
667
- robustness: F.audio,
668
- encryptionScheme: F.scheme
712
+ contentType: B,
713
+ robustness: I.audio,
714
+ encryptionScheme: I.scheme
669
715
  }]
670
716
  }]);
671
717
  }
672
- function Me(e, t) {
718
+ function V(e, t) {
673
719
  return new Promise((n, r) => {
674
720
  let i = setTimeout(() => r(/* @__PURE__ */ Error("probe-timeout")), t);
675
721
  e.then((e) => {
@@ -679,8 +725,8 @@ function Me(e, t) {
679
725
  });
680
726
  });
681
727
  }
682
- async function Ne(e = {}) {
683
- let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? De, r = {};
728
+ async function Fe(e = {}) {
729
+ let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? je, r = {};
684
730
  if (typeof window < "u" && window.isSecureContext === !1) return {
685
731
  verdict: "insecure-context",
686
732
  detail: r
@@ -692,7 +738,7 @@ async function Ne(e = {}) {
692
738
  };
693
739
  let a = !1, o = !1, s = Date.now() + n, c = () => Math.max(1, s - Date.now());
694
740
  for (let e of t) {
695
- let t = Ae[e];
741
+ let t = Ne[e];
696
742
  if (!t) {
697
743
  r[e] = "unknown system";
698
744
  continue;
@@ -703,7 +749,7 @@ async function Ne(e = {}) {
703
749
  break;
704
750
  }
705
751
  try {
706
- return await Me((await Me(i(n, je(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
752
+ return await V((await V(i(n, Pe(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
707
753
  verdict: "supported",
708
754
  system: e,
709
755
  detail: r
@@ -727,49 +773,49 @@ async function Ne(e = {}) {
727
773
  }
728
774
  //#endregion
729
775
  //#region src/core/manifest.ts
730
- var Pe = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
731
- function Fe(e) {
732
- return Pe.test(e);
776
+ var Ie = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
777
+ function Le(e) {
778
+ return Ie.test(e);
733
779
  }
734
780
  //#endregion
735
781
  //#region src/core/env.ts
736
- var I = {
782
+ var H = {
737
783
  integration: "https://feed-dev.oddin-video.gg",
738
784
  production: "https://feed.oddin-video.gg"
739
785
  };
740
- function L(e) {
741
- let t = Object.prototype.hasOwnProperty.call(I, e) ? I[e] : void 0;
786
+ function U(e) {
787
+ let t = Object.prototype.hasOwnProperty.call(H, e) ? H[e] : void 0;
742
788
  if (!t) throw new n("INTERNAL", 0, `unknown env ${JSON.stringify(e)} — expected 'integration' or 'production'`);
743
789
  return t;
744
790
  }
745
791
  //#endregion
746
792
  //#region src/core/stats.ts
747
- var R = { droppedFrames: 0 };
748
- function z(e) {
793
+ var W = { droppedFrames: 0 };
794
+ function G(e) {
749
795
  try {
750
796
  return new URL(e).host;
751
797
  } catch {
752
798
  return "";
753
799
  }
754
800
  }
755
- var Ie = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
756
- function Le(e) {
801
+ var Re = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
802
+ function ze(e) {
757
803
  if (typeof performance > "u" || typeof performance.getEntriesByType != "function") return "";
758
804
  let t = "", n = -1, r = performance.getEntriesByType("resource");
759
- for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || Ie.test(i.name)) && i.startTime >= n) {
760
- let e = z(i.name);
805
+ for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || Re.test(i.name)) && i.startTime >= n) {
806
+ let e = G(i.name);
761
807
  e && (t = e, n = i.startTime);
762
808
  }
763
809
  return t;
764
810
  }
765
- function B(e) {
811
+ function K(e) {
766
812
  let t = e.getVideoPlaybackQuality?.();
767
813
  return {
768
814
  dropped: t?.droppedVideoFrames ?? 0,
769
815
  totalFrames: t?.totalVideoFrames ?? 0
770
816
  };
771
817
  }
772
- function Re(e, t) {
818
+ function Be(e, t) {
773
819
  let n = [
774
820
  ["playing", () => t("playing")],
775
821
  ["waiting", () => t("buffering")],
@@ -786,7 +832,7 @@ function Re(e, t) {
786
832
  }
787
833
  //#endregion
788
834
  //#region src/core/engine/native.ts
789
- function ze(e) {
835
+ function Ve(e) {
790
836
  try {
791
837
  let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
792
838
  return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
@@ -794,15 +840,15 @@ function ze(e) {
794
840
  return;
795
841
  }
796
842
  }
797
- function V(e) {
843
+ function q(e) {
798
844
  return !!(e ?? (typeof document < "u" ? document.createElement("video") : void 0))?.canPlayType("application/vnd.apple.mpegurl");
799
845
  }
800
- function H() {
846
+ function J() {
801
847
  if (typeof window > "u") return !1;
802
848
  let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
803
849
  return e || t;
804
850
  }
805
- var U = class {
851
+ var Y = class {
806
852
  name = "native";
807
853
  deps;
808
854
  onLoaded;
@@ -838,7 +884,7 @@ var U = class {
838
884
  type: "error",
839
885
  error: new n("INTERNAL", 0, "native HLS playback error"),
840
886
  fatal: !0
841
- }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = Be(t.manifestUrl, t.analytics?.sid), e.load();
887
+ }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = He(t.manifestUrl, t.analytics?.sid), e.load();
842
888
  }
843
889
  startLoad() {
844
890
  this.loadStarted || (this.loadStarted = !0, this.restorePreload());
@@ -860,7 +906,7 @@ var U = class {
860
906
  });
861
907
  this.onEncrypted = (n) => {
862
908
  let i = n;
863
- i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = ze(i.initData), (async () => {
909
+ i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = Ve(i.initData), (async () => {
864
910
  try {
865
911
  let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
866
912
  initDataTypes: [i.initDataType],
@@ -955,11 +1001,11 @@ var U = class {
955
1001
  e.seekable.length > 0 && (e.currentTime = e.seekable.end(e.seekable.length - 1));
956
1002
  }
957
1003
  getStats() {
958
- let e = this.deps.video, t = B(e), n = {
1004
+ let e = this.deps.video, t = K(e), n = {
959
1005
  droppedFrames: t.dropped,
960
1006
  decodedFrames: t.totalFrames
961
1007
  };
962
- return this.cdnHost ||= Le(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;
1008
+ return this.cdnHost ||= ze(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;
963
1009
  }
964
1010
  stop() {
965
1011
  try {
@@ -978,13 +1024,13 @@ var U = class {
978
1024
  } catch {}
979
1025
  }
980
1026
  };
981
- function Be(e, t) {
1027
+ function He(e, t) {
982
1028
  return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
983
1029
  }
984
1030
  //#endregion
985
1031
  //#region src/core/engine/prefetch.ts
986
- var Ve = 15e3, He = 5e3, Ue = 6;
987
- function W(e) {
1032
+ var Ue = 15e3, We = 5e3, Ge = 6;
1033
+ function Ke(e) {
988
1034
  try {
989
1035
  let t = new URL(e);
990
1036
  return t.searchParams.delete("CMCD"), t.toString();
@@ -992,7 +1038,7 @@ function W(e) {
992
1038
  return e;
993
1039
  }
994
1040
  }
995
- var We = class {
1041
+ var qe = class {
996
1042
  cmcd;
997
1043
  entries = /* @__PURE__ */ new Map();
998
1044
  keyed = /* @__PURE__ */ new Set();
@@ -1015,10 +1061,10 @@ var We = class {
1015
1061
  }
1016
1062
  prefetch(e, t, n) {
1017
1063
  if (!this.isActive(t)) return;
1018
- let r = W(e);
1064
+ let r = Ke(e);
1019
1065
  if (this.entries.has(r)) return;
1020
1066
  let i = this.perTrack.get(t) ?? 0;
1021
- if (i >= Ue) return;
1067
+ if (i >= Ge) return;
1022
1068
  this.perTrack.set(t, i + 1);
1023
1069
  let a = new AbortController(), o = {
1024
1070
  started: performance.now(),
@@ -1032,10 +1078,10 @@ var We = class {
1032
1078
  signal: a.signal
1033
1079
  }).then(async (e) => (o.first = performance.now(), e.ok ? e.arrayBuffer() : null)).catch(() => null), this.entries.set(r, o), this.stats.started += 1, setTimeout(() => {
1034
1080
  this.entries.get(r) === o && (this.entries.delete(r), a.abort(), this.stats.expired += 1);
1035
- }, Ve);
1081
+ }, Ue);
1036
1082
  }
1037
1083
  take(e) {
1038
- let t = W(e), n = this.entries.get(t);
1084
+ let t = Ke(e), n = this.entries.get(t);
1039
1085
  return n && this.entries.delete(t), n;
1040
1086
  }
1041
1087
  destroy() {
@@ -1055,13 +1101,13 @@ var We = class {
1055
1101
  }
1056
1102
  }
1057
1103
  };
1058
- function Ge(t) {
1104
+ function Je(t) {
1059
1105
  let n = e.DefaultConfig?.loader;
1060
1106
  if (typeof n != "function") return;
1061
1107
  class r extends n {
1062
1108
  served = !1;
1063
1109
  cancelled = !1;
1064
- stats = Ke();
1110
+ stats = Ye();
1065
1111
  load(e, n, r) {
1066
1112
  let i = e.rangeEnd ? void 0 : t.take(e.url);
1067
1113
  if (!i) {
@@ -1069,7 +1115,7 @@ function Ge(t) {
1069
1115
  return;
1070
1116
  }
1071
1117
  this.served = !0;
1072
- let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || He, s = setTimeout(() => {
1118
+ let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || We, s = setTimeout(() => {
1073
1119
  !this.cancelled && this.served && (i.abort.abort(), t.stats.failed += 1, this.served = !1, super.load(e, n, r));
1074
1120
  }, o);
1075
1121
  i.bytes.then((o) => {
@@ -1096,7 +1142,7 @@ function Ge(t) {
1096
1142
  }
1097
1143
  return r;
1098
1144
  }
1099
- function Ke() {
1145
+ function Ye() {
1100
1146
  return {
1101
1147
  aborted: !1,
1102
1148
  loaded: 0,
@@ -1120,10 +1166,10 @@ function Ke() {
1120
1166
  }
1121
1167
  };
1122
1168
  }
1123
- function G(e) {
1169
+ function Xe(e) {
1124
1170
  return e === "audio" ? "audio" : "main";
1125
1171
  }
1126
- function qe(e, t) {
1172
+ function Ze(e, t) {
1127
1173
  let n = [];
1128
1174
  t.initSegment?.url && !t.initSegment.data && n.push({
1129
1175
  url: t.initSegment.url,
@@ -1142,24 +1188,24 @@ function qe(e, t) {
1142
1188
  }
1143
1189
  //#endregion
1144
1190
  //#region src/core/engine/hls.ts
1145
- function Je() {
1191
+ function Qe() {
1146
1192
  return e.isSupported();
1147
1193
  }
1148
- var Ye = 3, Xe = 5, Ze = 3, Qe = 3e4, $e = 12e3, et = 3e3, K = 6e3, tt = 5e3, nt = 4e3, rt = 2, it = 5, at = 2, ot = 2, q = 4, st = 4, ct = 2e3, lt = 3e4, ut = 2, dt = 9, ft = .5, pt = 64;
1149
- function mt(e) {
1194
+ var $e = 3, et = 5, tt = 3, nt = 3e4, rt = 12e3, it = 3e3, at = 6e3, ot = 5e3, st = 4e3, ct = 2, lt = 5, ut = 2, dt = 2, ft = 4, pt = 4, mt = 2e3, ht = 3e4, gt = 2, _t = 9, vt = .5, yt = 64;
1195
+ function bt(e) {
1150
1196
  if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
1151
1197
  delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
1152
1198
  return;
1153
1199
  }
1154
- e.liveSyncDuration ??= ut;
1155
- let t = Math.max(12, e.liveSyncDuration + dt);
1156
- (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), ht(e, e.liveSyncDuration);
1200
+ e.liveSyncDuration ??= gt;
1201
+ let t = Math.max(12, e.liveSyncDuration + _t);
1202
+ (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), xt(e, e.liveSyncDuration);
1157
1203
  }
1158
- function ht(e, t) {
1204
+ function xt(e, t) {
1159
1205
  let n = (e, t, n) => Math.min(n, Math.max(t, e));
1160
1206
  e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
1161
1207
  }
1162
- var J = class {
1208
+ var St = class {
1163
1209
  name = "hls";
1164
1210
  hls = null;
1165
1211
  deps;
@@ -1227,7 +1273,7 @@ var J = class {
1227
1273
  this.deps = e, this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
1228
1274
  }
1229
1275
  async load() {
1230
- let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = V(r) && H(), o = !!e.drm?.widevine?.licenseUrl && !a;
1276
+ let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = q(r) && J(), o = !!e.drm?.widevine?.licenseUrl && !a;
1231
1277
  if (e.drmEnabled && !o) {
1232
1278
  i({
1233
1279
  type: "error",
@@ -1236,7 +1282,7 @@ var J = class {
1236
1282
  });
1237
1283
  return;
1238
1284
  }
1239
- e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && Ee(r), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1285
+ e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Te(r), ke()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1240
1286
  let e = this.hls;
1241
1287
  if (document.visibilityState !== "visible" || !e) return;
1242
1288
  let t = e.liveSyncPosition;
@@ -1259,7 +1305,7 @@ var J = class {
1259
1305
  }
1260
1306
  this.loadSuspended = !0;
1261
1307
  }
1262
- }, tt));
1308
+ }, ot));
1263
1309
  }
1264
1310
  resumeLoading() {
1265
1311
  if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
@@ -1291,7 +1337,7 @@ var J = class {
1291
1337
  let t = e.liveSyncPosition;
1292
1338
  if (typeof t != "number" || !Number.isFinite(t)) return;
1293
1339
  let { video: n } = this.deps;
1294
- n.currentTime <= t + ft || (n.currentTime = t);
1340
+ n.currentTime <= t + vt || (n.currentTime = t);
1295
1341
  }
1296
1342
  startHls() {
1297
1343
  let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps;
@@ -1310,12 +1356,12 @@ var J = class {
1310
1356
  emeEnabled: !0,
1311
1357
  drmSystems: { ...this.licenseUrl ? { "com.widevine.alpha": { licenseUrl: this.licenseUrl } } : {} },
1312
1358
  drmSystemOptions: {
1313
- videoRobustness: F.video,
1314
- audioRobustness: F.audio,
1315
- videoEncryptionScheme: F.scheme,
1316
- audioEncryptionScheme: F.scheme
1359
+ videoRobustness: I.video,
1360
+ audioRobustness: I.audio,
1361
+ videoEncryptionScheme: I.scheme,
1362
+ audioEncryptionScheme: I.scheme
1317
1363
  },
1318
- ...M() ? { requestMediaKeySystemAccessFunc: Te(t) } : {},
1364
+ ...N() ? { requestMediaKeySystemAccessFunc: we(t) } : {},
1319
1365
  licenseXhrSetup: (e, t) => {
1320
1366
  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;
1321
1367
  let o = performance.now();
@@ -1332,22 +1378,20 @@ var J = class {
1332
1378
  ...c
1333
1379
  };
1334
1380
  if (this.prefetch?.destroy(), this.prefetch = null, u && this.deps.mediaDuringKey !== !1 && !d.fLoader) {
1335
- let e = new We({
1381
+ let e = new qe({
1336
1382
  sessionId: n.analytics?.sid,
1337
1383
  contentId: n.matchUrn
1338
- }), t = Ge(e);
1384
+ }), t = Je(e);
1339
1385
  t && (this.prefetch = e, d.fLoader = t);
1340
1386
  }
1341
- mt(d), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.loadStarted = d.autoStartLoad !== !1;
1387
+ bt(d), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.loadStarted = d.autoStartLoad !== !1;
1342
1388
  let f = new e(d);
1343
1389
  if (this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
1344
- this.mediaRecoveries = 0, this.networkRecoveries = 0;
1345
- let e = f.levels.map((e) => e.height).filter((e) => !!e);
1346
- this.ladderHeights = e.length ? [...new Set(e)].sort((e, t) => e - t) : void 0, this.ladderTopBitrateKbps = f.levels.length ? Math.round(Math.max(...f.levels.map((e) => e.bitrate)) / 1e3) : 0, this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
1390
+ 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" });
1347
1391
  }), f.on(e.Events.FRAG_BUFFERED, (e, t) => {
1348
1392
  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(() => {
1349
1393
  this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
1350
- }, Qe)));
1394
+ }, nt)));
1351
1395
  }), f.on(e.Events.FRAG_LOADING, (e, t) => {
1352
1396
  t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
1353
1397
  }), f.on(e.Events.FRAG_LOADED, (e, t) => {
@@ -1355,10 +1399,10 @@ var J = class {
1355
1399
  let n = t?.frag?.stats, r = n?.loaded;
1356
1400
  typeof r == "number" && (this.bytesLoaded += r), !this.reportedFirstBytes && typeof r == "number" && r > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
1357
1401
  let i = n?.loading;
1358
- 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 > pt && this.requestTimesMs.shift());
1402
+ 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 > yt && this.requestTimesMs.shift());
1359
1403
  let a = t?.frag?.url;
1360
1404
  if (a) {
1361
- let e = z(a);
1405
+ let e = G(a);
1362
1406
  e && (this.cdnHost = e);
1363
1407
  }
1364
1408
  }), f.on(e.Events.LEVEL_LOADED, (e, t) => {
@@ -1372,15 +1416,15 @@ var J = class {
1372
1416
  }), f.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.prefetch) {
1373
1417
  let t = this.prefetch;
1374
1418
  f.on(e.Events.KEY_LOADING, (e, n) => {
1375
- let r = n?.frag, i = G(r?.type);
1376
- if (r && t.isActive(i)) for (let e of qe(f, r)) t.prefetch(e.url, i, e.kind);
1377
- }), f.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(G(n?.frag?.type)));
1419
+ let r = n?.frag, i = Xe(r?.type);
1420
+ if (r && t.isActive(i)) for (let e of Ze(f, r)) t.prefetch(e.url, i, e.kind);
1421
+ }), f.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(Xe(n?.frag?.type)));
1378
1422
  }
1379
1423
  f.on(e.Events.KEY_LOADED, () => {
1380
1424
  u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
1381
1425
  }), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
1382
1426
  this.checkEndStale(), this.checkStarvation();
1383
- }, et), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1427
+ }, it), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1384
1428
  this.renditionSwitches += 1;
1385
1429
  let n = this.lastLevelIndex >= 0 ? f.levels[this.lastLevelIndex] : void 0, r = f.levels[t.level];
1386
1430
  n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, l({
@@ -1444,11 +1488,33 @@ var J = class {
1444
1488
  return;
1445
1489
  }
1446
1490
  this.capTimer && clearTimeout(this.capTimer);
1447
- let t = e > this.sizeCapLevel ? ct : lt;
1491
+ let t = e > this.sizeCapLevel ? mt : ht;
1448
1492
  this.capTimer = setTimeout(() => {
1449
1493
  this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
1450
1494
  }, t);
1451
1495
  }
1496
+ measureLadder(e) {
1497
+ let t = e.levels.map((e) => e.height).filter((e) => !!e);
1498
+ 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;
1499
+ }
1500
+ dropLevelsWidevineCannotPlay(e) {
1501
+ this.removeLevelsWhere(e, (e) => Ae(e) !== !0);
1502
+ let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && L(e) !== "avc" && !!L(e)));
1503
+ for (let n of t) Oe(n).then((t) => {
1504
+ t || this.hls !== e || this.removeLevelsWhere(e, (e) => e === n) && (this.measureLadder(e), this.applySizeCap());
1505
+ });
1506
+ }
1507
+ removeLevelsWhere(e, t) {
1508
+ let n = e.levels ?? [], r = [], i = /* @__PURE__ */ new Set();
1509
+ if (n.forEach((e, n) => {
1510
+ let a = e.videoCodec;
1511
+ a && L(a) && t(a) && (r.push(n), i.add(a));
1512
+ }), !r.length) return !1;
1513
+ let a = [...i].join(", ");
1514
+ if (!n.some((e, t) => r.includes(t) ? !1 : !L(e.videoCodec) || Ae(e.videoCodec) === !0)) return console.warn(`havik-player: every rendition is ${a}, which Widevine may not play on this browser; keeping them`), !1;
1515
+ for (let t = r.length - 1; t >= 0; --t) e.removeLevel(r[t]);
1516
+ return console.info(`havik-player: skipped ${r.length} rendition(s) Widevine cannot play on this browser (${a})`), !0;
1517
+ }
1452
1518
  applySizeCap() {
1453
1519
  if (!this.sizeCapManaged) return;
1454
1520
  this.capTimer &&= (clearTimeout(this.capTimer), null);
@@ -1491,7 +1557,7 @@ var J = class {
1491
1557
  e.widevine && (this.licenseUrl = e.widevine);
1492
1558
  }
1493
1559
  getStats() {
1494
- let e = this.hls, t = B(this.deps.video), n = {
1560
+ let e = this.hls, t = K(this.deps.video), n = {
1495
1561
  droppedFrames: t.dropped,
1496
1562
  decodedFrames: t.totalFrames,
1497
1563
  lowLatency: this.detectedLowLatency,
@@ -1537,7 +1603,7 @@ var J = class {
1537
1603
  return;
1538
1604
  }
1539
1605
  let e = Date.now() - this.lastAdvanceMs;
1540
- !this.chaseSuspended && e > K && this.suspendChasing(), e > $e && this.emitEnded("stalled");
1606
+ !this.chaseSuspended && e > at && this.suspendChasing(), e > rt && this.emitEnded("stalled");
1541
1607
  }
1542
1608
  resetStarvationWindow() {
1543
1609
  this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
@@ -1552,7 +1618,7 @@ var J = class {
1552
1618
  this.resetStarvationWindow();
1553
1619
  return;
1554
1620
  }
1555
- let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < K, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > nt, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = B(t), c = o - s, l = c !== this.starvedFrames;
1621
+ let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < at, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > st, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = K(t), c = o - s, l = c !== this.starvedFrames;
1556
1622
  if (this.starvedFrames = c, !a || l) {
1557
1623
  (t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
1558
1624
  return;
@@ -1561,12 +1627,12 @@ var J = class {
1561
1627
  this.resetStarvationWindow();
1562
1628
  return;
1563
1629
  }
1564
- 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 > q && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= at && (this.clearKick(), this.starvationRebuilds < ot)) {
1630
+ 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 > ft && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= ut && (this.clearKick(), this.starvationRebuilds < dt)) {
1565
1631
  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");
1566
1632
  return;
1567
1633
  }
1568
- let u = i && this.starvedTicks >= rt, d = !i && this.deadTicks >= q && this.recentMainFrags.reduce((e, t) => e + t, 0) >= st;
1569
- if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= it))) {
1634
+ let u = i && this.starvedTicks >= ct, d = !i && this.deadTicks >= ft && this.recentMainFrags.reduce((e, t) => e + t, 0) >= pt;
1635
+ if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= lt))) {
1570
1636
  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");
1571
1637
  try {
1572
1638
  e.stopLoad(), e.startLoad(-1);
@@ -1615,7 +1681,7 @@ var J = class {
1615
1681
  scheduleLicenseRetry(t) {
1616
1682
  if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
1617
1683
  let n = t.response?.code ?? 0;
1618
- if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= Ze) return !1;
1684
+ if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= tt) return !1;
1619
1685
  this.licenseRecoveries += 1;
1620
1686
  let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
1621
1687
  return this.licenseRetryTimer = setTimeout(() => {
@@ -1647,7 +1713,7 @@ var J = class {
1647
1713
  return;
1648
1714
  }
1649
1715
  if (t.type === e.ErrorTypes.NETWORK_ERROR) {
1650
- if (this.networkRecoveries < Xe) {
1716
+ if (this.networkRecoveries < et) {
1651
1717
  this.networkRecoveries += 1;
1652
1718
  let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
1653
1719
  this.networkRetryTimer = setTimeout(() => {
@@ -1664,7 +1730,7 @@ var J = class {
1664
1730
  return;
1665
1731
  }
1666
1732
  if (t.type === e.ErrorTypes.MEDIA_ERROR) {
1667
- if (this.mediaRecoveries < Ye) {
1733
+ if (this.mediaRecoveries < $e) {
1668
1734
  this.mediaRecoveries += 1, n.recoverMediaError();
1669
1735
  return;
1670
1736
  }
@@ -1688,19 +1754,19 @@ var J = class {
1688
1754
  let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
1689
1755
  return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
1690
1756
  }
1691
- }, gt = 15e3, _t = 6e5, vt = 3e5, yt = 100, Y = 1, bt = 1e3, xt = 3e4, St = 1e3, Ct = {
1757
+ }, Ct = 15e3, wt = 6e5, Tt = 3e5, Et = 100, X = 1, Dt = 1e3, Ot = 3e4, kt = 1e3, At = {
1692
1758
  inline: "PRESENTATION_INLINE",
1693
1759
  fullscreen: "PRESENTATION_FULLSCREEN",
1694
1760
  pip: "PRESENTATION_PIP"
1695
- }, wt = {
1761
+ }, jt = {
1696
1762
  widevine: "KEY_SYSTEM_WIDEVINE",
1697
1763
  fairplay: "KEY_SYSTEM_FAIRPLAY",
1698
1764
  none: "KEY_SYSTEM_NONE"
1699
1765
  };
1700
- function Tt(e, t) {
1766
+ function Mt(e, t) {
1701
1767
  return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
1702
1768
  }
1703
- var Et = /* @__PURE__ */ new Set([
1769
+ var Nt = /* @__PURE__ */ new Set([
1704
1770
  "INVALID_URN",
1705
1771
  "NOT_FOUND",
1706
1772
  "GONE",
@@ -1710,7 +1776,7 @@ var Et = /* @__PURE__ */ new Set([
1710
1776
  "FORBIDDEN",
1711
1777
  "RATE_LIMITED",
1712
1778
  "TIMEOUT"
1713
- ]), X = {
1779
+ ]), Z = {
1714
1780
  idle: "PLAYER_STATE_IDLE",
1715
1781
  waiting: "PLAYER_STATE_WAITING",
1716
1782
  loading: "PLAYER_STATE_LOADING",
@@ -1720,7 +1786,7 @@ var Et = /* @__PURE__ */ new Set([
1720
1786
  ended: "PLAYER_STATE_ENDED",
1721
1787
  error: "PLAYER_STATE_ERROR"
1722
1788
  };
1723
- function Dt(e) {
1789
+ function Pt(e) {
1724
1790
  try {
1725
1791
  let t = new URL(e), [n, ...r] = t.hostname.split(".");
1726
1792
  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);
@@ -1728,14 +1794,14 @@ function Dt(e) {
1728
1794
  return;
1729
1795
  }
1730
1796
  }
1731
- var Ot = /* @__PURE__ */ new Set();
1732
- function kt(e, t) {
1733
- return Ot.has(e) || (Ot.add(e), console.warn(`havik-player: ${t}`)), { disabledReason: t };
1797
+ var Ft = /* @__PURE__ */ new Set();
1798
+ function It(e, t) {
1799
+ return Ft.has(e) || (Ft.add(e), console.warn(`havik-player: ${t}`)), { disabledReason: t };
1734
1800
  }
1735
- function At(e, t) {
1801
+ function Lt(e, t) {
1736
1802
  if (t) return { endpoint: t };
1737
- if (t !== void 0) return kt("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).");
1738
- let n = Dt(e);
1803
+ if (t !== void 0) return It("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).");
1804
+ let n = Pt(e);
1739
1805
  if (n) return { endpoint: n };
1740
1806
  let r;
1741
1807
  try {
@@ -1743,9 +1809,9 @@ function At(e, t) {
1743
1809
  } catch {
1744
1810
  r = e;
1745
1811
  }
1746
- return kt(r, `analytics is disabled: no QoE beacons will be sent. The beacons endpoint cannot be derived from the baseUrl host "${r}" — 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).`);
1812
+ return It(r, `analytics is disabled: no QoE beacons will be sent. The beacons endpoint cannot be derived from the baseUrl host "${r}" — 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).`);
1747
1813
  }
1748
- var jt = class {
1814
+ var Rt = class {
1749
1815
  opts;
1750
1816
  url;
1751
1817
  now;
@@ -1825,8 +1891,8 @@ var jt = class {
1825
1891
  constructor(e) {
1826
1892
  this.opts = {
1827
1893
  ...e,
1828
- heartbeatMs: e.heartbeatMs ?? gt,
1829
- idleMs: e.idleMs ?? _t
1894
+ heartbeatMs: e.heartbeatMs ?? Ct,
1895
+ idleMs: e.idleMs ?? wt
1830
1896
  }, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`, this.now = e.now ?? (() => Date.now()), this.bornMs = this.now(), this.presentationSinceMs = this.bornMs, this.startupAnchorMs = this.bornMs;
1831
1897
  }
1832
1898
  start() {
@@ -1836,11 +1902,11 @@ var jt = class {
1836
1902
  sdkVersion: this.opts.sdkVersion,
1837
1903
  ...this.opts.environment
1838
1904
  };
1839
- this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), bt), 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.onVisibility());
1905
+ this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Dt), 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.onVisibility());
1840
1906
  }
1841
1907
  checkSuspension(e) {
1842
1908
  if (this.endedFlag || !this.opts.idleMs) return !1;
1843
- let t = Math.max(this.opts.idleMs, vt);
1909
+ let t = Math.max(this.opts.idleMs, Tt);
1844
1910
  return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
1845
1911
  }
1846
1912
  syncIdle(e) {
@@ -1854,21 +1920,21 @@ var jt = class {
1854
1920
  noteStateChange(e, t, n, r) {
1855
1921
  if (this.endedFlag || e === t) return;
1856
1922
  let i = this.now();
1857
- if (t === "playing" ? (this.playingSinceMs === null && (this.playingSinceMs = i), this.startupTimeMs === 0 && (this.startupTimeMs = Math.max(Y, i - this.startupAnchorMs)), this.firstAudioMs === 0 && !this.isMuted && (this.firstAudioMs = Math.max(Y, i - this.startupAnchorMs)), this.isMuted && this.mutedSinceMs === null && (this.mutedSinceMs = i)) : this.playingSinceMs !== null && (this.playingTotalMs += i - this.playingSinceMs, this.playingSinceMs = null, this.mutedSinceMs !== null && (this.mutedTotalMs += i - this.mutedSinceMs, this.mutedSinceMs = null)), this.isPlaying = t === "playing", this.syncActive(), t === "waiting" ? this.waitingSinceMs = i : this.waitingSinceMs !== null && (this.waitingTotalMs += i - this.waitingSinceMs, this.waitingSinceMs = null), t === "buffering" && e === "playing") {
1923
+ if (t === "playing" ? (this.playingSinceMs === null && (this.playingSinceMs = i), this.startupTimeMs === 0 && (this.startupTimeMs = Math.max(X, i - this.startupAnchorMs)), this.firstAudioMs === 0 && !this.isMuted && (this.firstAudioMs = Math.max(X, i - this.startupAnchorMs)), this.isMuted && this.mutedSinceMs === null && (this.mutedSinceMs = i)) : this.playingSinceMs !== null && (this.playingTotalMs += i - this.playingSinceMs, this.playingSinceMs = null, this.mutedSinceMs !== null && (this.mutedTotalMs += i - this.mutedSinceMs, this.mutedSinceMs = null)), this.isPlaying = t === "playing", this.syncActive(), t === "waiting" ? this.waitingSinceMs = i : this.waitingSinceMs !== null && (this.waitingTotalMs += i - this.waitingSinceMs, this.waitingSinceMs = null), t === "buffering" && e === "playing") {
1858
1924
  this.stallIsSeekInduced = this.seekInduced(i);
1859
1925
  let e = !this.isHidden && !this.stallIsSeekInduced;
1860
- e && (this.rebufferCount += 1), this.isBuffering = !0, this.lastStallMs = i, e && this.timeToFirstStallMs === 0 && (this.timeToFirstStallMs = Math.max(Y, Math.round(this.playingTotalMs)));
1926
+ e && (this.rebufferCount += 1), this.isBuffering = !0, this.lastStallMs = i, e && this.timeToFirstStallMs === 0 && (this.timeToFirstStallMs = Math.max(X, Math.round(this.playingTotalMs)));
1861
1927
  } else e === "buffering" && (this.isBuffering = !1, this.stallIsSeekInduced = !1);
1862
1928
  this.syncBuffering(), t === "paused" && (this.pauseCount += 1), this.syncIdle(t);
1863
1929
  let a = {
1864
- fromState: X[e] ?? "PLAYER_STATE_UNSPECIFIED",
1865
- toState: X[t] ?? "PLAYER_STATE_UNSPECIFIED",
1866
- presentation: Ct[this.presentation]
1930
+ fromState: Z[e] ?? "PLAYER_STATE_UNSPECIFIED",
1931
+ toState: Z[t] ?? "PLAYER_STATE_UNSPECIFIED",
1932
+ presentation: At[this.presentation]
1867
1933
  }, o = this.causeOf(e, t, i);
1868
1934
  o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
1869
1935
  }
1870
1936
  seekInduced(e) {
1871
- return this.lastSeekMs >= 0 && e - this.lastSeekMs < St;
1937
+ return this.lastSeekMs >= 0 && e - this.lastSeekMs < kt;
1872
1938
  }
1873
1939
  causeOf(e, t, n) {
1874
1940
  if (t === "error") return "TRANSITION_CAUSE_ERROR";
@@ -1905,25 +1971,25 @@ var jt = class {
1905
1971
  }
1906
1972
  this.muteChanges += 1;
1907
1973
  let r = this.now();
1908
- n ? this.isPlaying && this.mutedSinceMs === null && (this.mutedSinceMs = r) : (this.mutedSinceMs !== null && (this.mutedTotalMs += r - this.mutedSinceMs, this.mutedSinceMs = null), this.firstAudioMs === 0 && this.isPlaying && (this.firstAudioMs = Math.max(Y, r - this.startupAnchorMs))), this.isMuted = n, this.syncActive();
1974
+ n ? this.isPlaying && this.mutedSinceMs === null && (this.mutedSinceMs = r) : (this.mutedSinceMs !== null && (this.mutedTotalMs += r - this.mutedSinceMs, this.mutedSinceMs = null), this.firstAudioMs === 0 && this.isPlaying && (this.firstAudioMs = Math.max(X, r - this.startupAnchorMs))), this.isMuted = n, this.syncActive();
1909
1975
  }
1910
1976
  notePresentation(e) {
1911
1977
  this.endedFlag || e === this.presentation || (this.closePresentation(), this.presentation = e);
1912
1978
  }
1913
1979
  notePlayIntent() {
1914
- this.endedFlag || this.startupTimeMs > 0 || (this.startupAnchorMs = this.now(), this.manifestLoadMs > 0 && (this.manifestLoadMs = Y), this.firstPlaylistMs > 0 && (this.firstPlaylistMs = Y), this.firstFragLoadMs > 0 && (this.firstFragLoadMs = Y), this.drmSetupMs > 0 && (this.drmSetupMs = Y));
1980
+ this.endedFlag || this.startupTimeMs > 0 || (this.startupAnchorMs = this.now(), this.manifestLoadMs > 0 && (this.manifestLoadMs = X), this.firstPlaylistMs > 0 && (this.firstPlaylistMs = X), this.firstFragLoadMs > 0 && (this.firstFragLoadMs = X), this.drmSetupMs > 0 && (this.drmSetupMs = X));
1915
1981
  }
1916
1982
  noteReady() {
1917
- this.manifestLoadMs === 0 && (this.manifestLoadMs = Math.max(Y, this.now() - this.startupAnchorMs));
1983
+ this.manifestLoadMs === 0 && (this.manifestLoadMs = Math.max(X, this.now() - this.startupAnchorMs));
1918
1984
  }
1919
1985
  noteFirstPlaylist() {
1920
- this.firstPlaylistMs === 0 && (this.firstPlaylistMs = Math.max(Y, this.now() - this.startupAnchorMs));
1986
+ this.firstPlaylistMs === 0 && (this.firstPlaylistMs = Math.max(X, this.now() - this.startupAnchorMs));
1921
1987
  }
1922
1988
  noteDrmReady() {
1923
- this.drmSetupMs === 0 && (this.drmSetupMs = Math.max(Y, this.now() - this.startupAnchorMs));
1989
+ this.drmSetupMs === 0 && (this.drmSetupMs = Math.max(X, this.now() - this.startupAnchorMs));
1924
1990
  }
1925
1991
  noteFirstBytes() {
1926
- this.sawFirstBytes = !0, this.firstFragLoadMs === 0 && (this.firstFragLoadMs = Math.max(Y, this.now() - this.startupAnchorMs));
1992
+ this.sawFirstBytes = !0, this.firstFragLoadMs === 0 && (this.firstFragLoadMs = Math.max(X, this.now() - this.startupAnchorMs));
1927
1993
  }
1928
1994
  noteSeek() {
1929
1995
  this.endedFlag || (this.seekCount += 1, this.lastSeekMs = this.now());
@@ -1942,7 +2008,7 @@ var jt = class {
1942
2008
  let r = n ?? "";
1943
2009
  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";
1944
2010
  if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
1945
- if (Et.has(e)) return "ERROR_STAGE_RESOLVE";
2011
+ if (Nt.has(e)) return "ERROR_STAGE_RESOLVE";
1946
2012
  let i = t ?? "";
1947
2013
  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";
1948
2014
  }
@@ -1974,7 +2040,7 @@ var jt = class {
1974
2040
  let l = t.droppedFrames ?? 0;
1975
2041
  l > this.lastDropped && (o.droppedFramesDelta = l - this.lastDropped), this.lastDropped = l;
1976
2042
  let u = t.renditionSwitches ?? 0;
1977
- u > this.lastSwitches && (o.renditionSwitchesDelta = u - this.lastSwitches), this.lastSwitches = u, n > this.lastHbPlayingMs && (o.playingMsDelta = Math.round(n - this.lastHbPlayingMs)), this.lastHbPlayingMs = n, r > this.lastHbHiddenMs && (o.hiddenMsDelta = Math.round(r - this.lastHbHiddenMs)), this.lastHbHiddenMs = r, i > this.lastHbRebufferMs && (o.rebufferMsDelta = Math.round(i - this.lastHbRebufferMs)), this.lastHbRebufferMs = i, this.rebufferCount > this.lastHbRebufferCount && (o.rebufferCountDelta = this.rebufferCount - this.lastHbRebufferCount), this.lastHbRebufferCount = this.rebufferCount, a > this.lastHbActiveMs && (o.activeMsDelta = Math.round(a - this.lastHbActiveMs)), this.lastHbActiveMs = a, typeof t.latencySeconds == "number" && (o.latencyMs = Math.round(t.latencySeconds * 1e3)), typeof t.targetLatencySeconds == "number" && (o.targetLatencyMs = Math.round(t.targetLatencySeconds * 1e3)), typeof t.bandwidthKbps == "number" && (o.bandwidthEstKbps = t.bandwidthKbps), typeof t.levelHeight == "number" && (o.renditionHeight = t.levelHeight), typeof t.renditionBitrateKbps == "number" && (o.renditionBitrateKbps = t.renditionBitrateKbps), t.atLiveEdge === !0 && (o.atLiveEdge = !0), typeof t.bufferedMs == "number" && t.bufferedMs > 0 && (o.bufferedMs = Math.round(t.bufferedMs)), o.playerState = X[t.state] ?? "PLAYER_STATE_UNSPECIFIED";
2043
+ u > this.lastSwitches && (o.renditionSwitchesDelta = u - this.lastSwitches), this.lastSwitches = u, n > this.lastHbPlayingMs && (o.playingMsDelta = Math.round(n - this.lastHbPlayingMs)), this.lastHbPlayingMs = n, r > this.lastHbHiddenMs && (o.hiddenMsDelta = Math.round(r - this.lastHbHiddenMs)), this.lastHbHiddenMs = r, i > this.lastHbRebufferMs && (o.rebufferMsDelta = Math.round(i - this.lastHbRebufferMs)), this.lastHbRebufferMs = i, this.rebufferCount > this.lastHbRebufferCount && (o.rebufferCountDelta = this.rebufferCount - this.lastHbRebufferCount), this.lastHbRebufferCount = this.rebufferCount, a > this.lastHbActiveMs && (o.activeMsDelta = Math.round(a - this.lastHbActiveMs)), this.lastHbActiveMs = a, typeof t.latencySeconds == "number" && (o.latencyMs = Math.round(t.latencySeconds * 1e3)), typeof t.targetLatencySeconds == "number" && (o.targetLatencyMs = Math.round(t.targetLatencySeconds * 1e3)), typeof t.bandwidthKbps == "number" && (o.bandwidthEstKbps = t.bandwidthKbps), typeof t.levelHeight == "number" && (o.renditionHeight = t.levelHeight), typeof t.renditionBitrateKbps == "number" && (o.renditionBitrateKbps = t.renditionBitrateKbps), t.atLiveEdge === !0 && (o.atLiveEdge = !0), typeof t.bufferedMs == "number" && t.bufferedMs > 0 && (o.bufferedMs = Math.round(t.bufferedMs)), o.playerState = Z[t.state] ?? "PLAYER_STATE_UNSPECIFIED";
1978
2044
  let d = this.mutedTotalMs;
1979
2045
  this.mutedSinceMs !== null && (d += e - this.mutedSinceMs), d > this.lastHbMutedMs && (o.mutedMsDelta = Math.round(d - this.lastHbMutedMs)), this.lastHbMutedMs = d;
1980
2046
  let f = t.upshifts ?? 0;
@@ -1989,14 +2055,14 @@ var jt = class {
1989
2055
  if (this.lastRequestCount = g, _ > 0) {
1990
2056
  o.requestCountDelta = _;
1991
2057
  let e = t.requestTimesMs ?? [], n = e.slice(Math.max(0, e.length - _)).sort((e, t) => e - t);
1992
- n.length > 0 && (o.requestTimeP50Ms = Tt(n, 50), o.requestTimeP95Ms = Tt(n, 95));
2058
+ n.length > 0 && (o.requestTimeP50Ms = Mt(n, 50), o.requestTimeP95Ms = Mt(n, 95));
1993
2059
  }
1994
2060
  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();
1995
2061
  }
1996
2062
  maybeEmitMediaInfo(e) {
1997
2063
  if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
1998
2064
  let t = {};
1999
- e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = wt[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);
2065
+ e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = jt[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);
2000
2066
  let n = JSON.stringify(t);
2001
2067
  n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
2002
2068
  }
@@ -2016,7 +2082,7 @@ var jt = class {
2016
2082
  let c = r?.positionMs ?? 0;
2017
2083
  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));
2018
2084
  let l = e !== "END_REASON_ENDED";
2019
- l && this.lastStallMs > 0 && n - this.lastStallMs <= xt && (i.abandonAfterStallMs = Math.max(Y, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= xt && (i.abandonAfterErrorMs = Math.max(Y, Math.round(n - this.lastErrorMs))), this.fullscreenTotalMs > 0 && (i.fullscreenTimeMs = Math.round(this.fullscreenTotalMs)), this.pipTotalMs > 0 && (i.pipTimeMs = Math.round(this.pipTotalMs)), this.volumeChanges > 0 && (i.volumeChanges = this.volumeChanges), this.muteChanges > 0 && (i.muteChanges = this.muteChanges);
2085
+ l && this.lastStallMs > 0 && n - this.lastStallMs <= Ot && (i.abandonAfterStallMs = Math.max(X, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= Ot && (i.abandonAfterErrorMs = Math.max(X, 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);
2020
2086
  let u = r?.decodedFrames ?? this.lastDecoded;
2021
2087
  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");
2022
2088
  }
@@ -2036,7 +2102,7 @@ var jt = class {
2036
2102
  };
2037
2103
  }
2038
2104
  enqueue(e) {
2039
- for (this.pending.push(this.wrap(e)); this.pending.length > yt;) {
2105
+ for (this.pending.push(this.wrap(e)); this.pending.length > Et;) {
2040
2106
  let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
2041
2107
  this.pending.splice(e >= 0 ? e : 0, 1);
2042
2108
  }
@@ -2059,7 +2125,7 @@ var jt = class {
2059
2125
  };
2060
2126
  //#endregion
2061
2127
  //#region src/core/environment.ts
2062
- function Mt() {
2128
+ function zt() {
2063
2129
  if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
2064
2130
  let e;
2065
2131
  try {
@@ -2084,14 +2150,14 @@ function Mt() {
2084
2150
  integration: "INTEGRATION_KIND_IFRAME"
2085
2151
  };
2086
2152
  }
2087
- function Nt() {
2153
+ function Bt() {
2088
2154
  if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
2089
2155
  let e = navigator.userAgentData, t = e?.platform ?? "";
2090
2156
  if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
2091
2157
  let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
2092
2158
  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";
2093
2159
  }
2094
- function Pt() {
2160
+ function Vt() {
2095
2161
  let e = typeof navigator < "u" ? navigator.connection : void 0;
2096
2162
  if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
2097
2163
  let t = {
@@ -2110,17 +2176,17 @@ function Pt() {
2110
2176
  }
2111
2177
  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;
2112
2178
  }
2113
- function Ft(e) {
2114
- let t = Mt(), n = {
2115
- deviceClass: Nt(),
2179
+ function Ht(e) {
2180
+ let t = zt(), n = {
2181
+ deviceClass: Bt(),
2116
2182
  integration: t.integration,
2117
- ...Pt()
2183
+ ...Vt()
2118
2184
  };
2119
2185
  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);
2120
2186
  let r = e.getBoundingClientRect?.();
2121
2187
  return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
2122
2188
  }
2123
- async function It() {
2189
+ async function Ut() {
2124
2190
  let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
2125
2191
  if (!e?.getHighEntropyValues) return {};
2126
2192
  try {
@@ -2132,7 +2198,7 @@ async function It() {
2132
2198
  }
2133
2199
  //#endregion
2134
2200
  //#region src/core/version.ts
2135
- var Lt = "2.11.0", Rt = {
2201
+ var Wt = "2.11.1", Gt = {
2136
2202
  accent: "#E1B600",
2137
2203
  accentText: "#1B1C23",
2138
2204
  background: "#0e0f13",
@@ -2143,7 +2209,7 @@ var Lt = "2.11.0", Rt = {
2143
2209
  border: "rgba(255, 255, 255, 0.1)",
2144
2210
  radius: "8px",
2145
2211
  fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
2146
- }, zt = {
2212
+ }, Kt = {
2147
2213
  accent: "--havik-accent",
2148
2214
  accentText: "--havik-accent-text",
2149
2215
  background: "--havik-bg",
@@ -2155,25 +2221,25 @@ var Lt = "2.11.0", Rt = {
2155
2221
  radius: "--havik-radius",
2156
2222
  fontFamily: "--havik-font"
2157
2223
  };
2158
- function Z(e, t) {
2224
+ function qt(e, t) {
2159
2225
  let n = {
2160
- ...Rt,
2226
+ ...Gt,
2161
2227
  ...t
2162
2228
  };
2163
- for (let t of Object.keys(zt)) e.style.setProperty(zt[t], n[t]);
2229
+ for (let t of Object.keys(Kt)) e.style.setProperty(Kt[t], n[t]);
2164
2230
  n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
2165
2231
  }
2166
2232
  //#endregion
2167
2233
  //#region src/ui/styles.ts
2168
- var Bt = "havik-player-styles", Vt = "\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.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";
2169
- function Ht(e = document) {
2170
- if (e.getElementById(Bt)) return;
2234
+ var Jt = "havik-player-styles", Yt = "\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.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";
2235
+ function Xt(e = document) {
2236
+ if (e.getElementById(Jt)) return;
2171
2237
  let t = e.createElement("style");
2172
- t.id = Bt, t.textContent = Vt, e.head.appendChild(t);
2238
+ t.id = Jt, t.textContent = Yt, e.head.appendChild(t);
2173
2239
  }
2174
2240
  //#endregion
2175
2241
  //#region src/ui/icons.ts
2176
- var Ut = {
2242
+ var Zt = {
2177
2243
  play: "<path d=\"M8 5v14l11-7z\"/>",
2178
2244
  pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
2179
2245
  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\"/>",
@@ -2187,20 +2253,20 @@ var Ut = {
2187
2253
  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\"/>"
2188
2254
  };
2189
2255
  function Q(e) {
2190
- return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Ut[e]}</svg>`;
2256
+ return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Zt[e]}</svg>`;
2191
2257
  }
2192
2258
  //#endregion
2193
2259
  //#region src/ui/controls.ts
2194
- var Wt = 3e3, Gt = /* @__PURE__ */ new Set([
2260
+ var Qt = 3e3, $t = /* @__PURE__ */ new Set([
2195
2261
  "GONE",
2196
2262
  "NOT_FOUND",
2197
2263
  "INVALID_URN",
2198
2264
  "UNAUTHORIZED"
2199
2265
  ]);
2200
- function Kt(e) {
2201
- return new qt(e);
2266
+ function en(e) {
2267
+ return new tn(e);
2202
2268
  }
2203
- var qt = class {
2269
+ var tn = class {
2204
2270
  root;
2205
2271
  video;
2206
2272
  player;
@@ -2242,7 +2308,7 @@ var qt = class {
2242
2308
  scrubbing = !1;
2243
2309
  offFns = [];
2244
2310
  constructor(e) {
2245
- this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Wt, 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, Ht(this.doc), 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");
2311
+ this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Qt, 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, Xt(this.doc), 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");
2246
2312
  let t = (e, t, n) => {
2247
2313
  let r = this.doc.createElement(e);
2248
2314
  if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
@@ -2333,7 +2399,7 @@ var qt = class {
2333
2399
  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);
2334
2400
  } else {
2335
2401
  let r = this.doc.createElement("div");
2336
- if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !Gt.has(this.lastError.code)) {
2402
+ if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !$t.has(this.lastError.code)) {
2337
2403
  let e = this.doc.createElement("button");
2338
2404
  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);
2339
2405
  }
@@ -2374,7 +2440,7 @@ var qt = class {
2374
2440
  let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
2375
2441
  this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
2376
2442
  }
2377
- !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Jt(this.video.currentTime)} / ${Jt(this.video.duration)}`);
2443
+ !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${nn(this.video.currentTime)} / ${nn(this.video.duration)}`);
2378
2444
  }
2379
2445
  syncLive() {
2380
2446
  let e = this.player.getStats(), t = e.isLive !== !1;
@@ -2424,17 +2490,17 @@ var qt = class {
2424
2490
  renderQualityMenu() {
2425
2491
  let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
2426
2492
  n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
2427
- for (let n of e) this.menu.append(this.menuItem(Yt(n), t === n.index, () => this.player.setQuality(n.index)));
2493
+ for (let n of e) this.menu.append(this.menuItem(rn(n), t === n.index, () => this.player.setQuality(n.index)));
2428
2494
  }
2429
2495
  renderAudioMenu() {
2430
2496
  let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
2431
2497
  t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
2432
- for (let t of e) this.menu.append(this.menuItem(Xt(t), t.default, () => this.player.setAudioTrack(t.id)));
2498
+ for (let t of e) this.menu.append(this.menuItem(an(t), t.default, () => this.player.setAudioTrack(t.id)));
2433
2499
  }
2434
2500
  renderCcMenu() {
2435
2501
  let e = this.player.getTextTracks(), t = this.doc.createElement("div");
2436
2502
  t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
2437
- for (let t of e) this.menu.append(this.menuItem(Zt(t), !1, () => this.player.setTextTrack(t.id)));
2503
+ for (let t of e) this.menu.append(this.menuItem(on(t), !1, () => this.player.setTextTrack(t.id)));
2438
2504
  }
2439
2505
  onTracksChanged() {
2440
2506
  this.openMenu && this.renderMenu(this.openMenu);
@@ -2454,11 +2520,11 @@ var qt = class {
2454
2520
  }
2455
2521
  async toggleFullscreen() {
2456
2522
  try {
2457
- C(this.video, this.root) ? await T(this.video, this.root) : await w(this.video, this.root);
2523
+ w(this.video, this.root) ? await E(this.video, this.root) : await T(this.video, this.root);
2458
2524
  } catch {}
2459
2525
  }
2460
2526
  syncFullscreen() {
2461
- let e = C(this.video, this.root);
2527
+ let e = w(this.video, this.root);
2462
2528
  this.setIcon(this.fsBtn, e ? "fullscreenExit" : "fullscreen"), this.fsBtn.setAttribute("aria-label", e ? "Exit fullscreen" : "Fullscreen");
2463
2529
  }
2464
2530
  poke() {
@@ -2534,41 +2600,41 @@ var qt = class {
2534
2600
  this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
2535
2601
  }
2536
2602
  };
2537
- function Jt(e) {
2603
+ function nn(e) {
2538
2604
  (!Number.isFinite(e) || e < 0) && (e = 0);
2539
2605
  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");
2540
2606
  return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
2541
2607
  }
2542
- function Yt(e) {
2608
+ function rn(e) {
2543
2609
  return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
2544
2610
  }
2545
- function Xt(e) {
2611
+ function an(e) {
2546
2612
  return e.name || e.lang || `Track ${e.id}`;
2547
2613
  }
2548
- function Zt(e) {
2614
+ function on(e) {
2549
2615
  return e.name || e.lang || `Track ${e.id}`;
2550
2616
  }
2551
2617
  //#endregion
2552
2618
  //#region src/managed/index.ts
2553
- var Qt = 6e3, $t = 45e3, en = 2e3, tn = 3, nn = 2e3, rn = 48e4;
2554
- function an(e) {
2619
+ var sn = 6e3, cn = 45e3, ln = 2e3, un = 3, dn = 2e3, fn = 48e4;
2620
+ function pn(e) {
2555
2621
  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)})`);
2556
- if (e.env !== void 0) return L(e.env);
2622
+ if (e.env !== void 0) return U(e.env);
2557
2623
  if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
2558
2624
  return e.baseUrl;
2559
2625
  }
2560
- async function on(e) {
2626
+ async function mn(e) {
2561
2627
  if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
2562
- let t = an(e);
2628
+ let t = pn(e);
2563
2629
  if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
2564
2630
  if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
2565
- let r = new sn({
2631
+ let r = new hn({
2566
2632
  ...e,
2567
2633
  baseUrl: t
2568
2634
  });
2569
2635
  return await r.start(), r;
2570
2636
  }
2571
- var sn = class {
2637
+ var hn = class {
2572
2638
  opts;
2573
2639
  abort = new AbortController();
2574
2640
  listeners = {};
@@ -2635,7 +2701,7 @@ var sn = class {
2635
2701
  };
2636
2702
  }
2637
2703
  beginArming(e, t, n = !1) {
2638
- let r = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? D(this.opts.baseUrl);
2704
+ let r = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? O(this.opts.baseUrl);
2639
2705
  r ? this.armWithSse(e, r, t, n) : this.beginArmingByPolling(e);
2640
2706
  }
2641
2707
  beginArmingByPolling(e) {
@@ -2656,7 +2722,7 @@ var sn = class {
2656
2722
  setTimeout(() => {
2657
2723
  a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
2658
2724
  phase: i ? "unavailable" : "tooEarly",
2659
- retryInMs: $t,
2725
+ retryInMs: cn,
2660
2726
  attempt: 1,
2661
2727
  elapsedMs: 0,
2662
2728
  ...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
@@ -2695,13 +2761,13 @@ var sn = class {
2695
2761
  !a && !p() && h();
2696
2762
  }, e);
2697
2763
  };
2698
- _(Qt), this.armingSub = E({
2764
+ _(sn), this.armingSub = D({
2699
2765
  eventsBaseUrl: t,
2700
2766
  matchUrn: this.opts.matchUrn,
2701
2767
  credential: this.opts.credential,
2702
- onAlive: () => _($t),
2768
+ onAlive: () => _(cn),
2703
2769
  onState: (e) => {
2704
- a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * en);
2770
+ a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * ln);
2705
2771
  },
2706
2772
  onError: () => h()
2707
2773
  });
@@ -2724,7 +2790,7 @@ var sn = class {
2724
2790
  let n = await s(this.opts.credential);
2725
2791
  if (this.destroyed || t !== this.loadGen) return;
2726
2792
  this.setState("loading");
2727
- let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = Re(this.opts.video, (e) => {
2793
+ let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = Be(this.opts.video, (e) => {
2728
2794
  this._state !== "ended" && this._state !== "error" && this.setState(e);
2729
2795
  });
2730
2796
  if (await i.load(), this.destroyed || t !== this.loadGen) {
@@ -2746,23 +2812,23 @@ var sn = class {
2746
2812
  if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
2747
2813
  let i = e.analytics?.sid;
2748
2814
  if (!i) return;
2749
- let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = At(this.opts.baseUrl, a);
2815
+ let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = Lt(this.opts.baseUrl, a);
2750
2816
  if (!o) {
2751
2817
  s && setTimeout(() => {
2752
2818
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
2753
2819
  }, 0);
2754
2820
  return;
2755
2821
  }
2756
- let c = this.opts.video, l = new jt({
2822
+ let c = this.opts.video, l = new Rt({
2757
2823
  endpoint: o,
2758
2824
  sid: i,
2759
2825
  player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
2760
- sdkVersion: Lt,
2761
- environment: Ft(c),
2826
+ sdkVersion: Wt,
2827
+ environment: Ht(c),
2762
2828
  idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
2763
2829
  onIdle: () => this.onAnalyticsIdle(t),
2764
2830
  sample: () => {
2765
- let e = this.engine?.getStats() ?? R, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
2831
+ let e = this.engine?.getStats() ?? W, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
2766
2832
  return {
2767
2833
  ...e,
2768
2834
  bufferedMs: Math.round(t * 1e3),
@@ -2776,7 +2842,7 @@ var sn = class {
2776
2842
  let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
2777
2843
  c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
2778
2844
  c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
2779
- }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), It().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
2845
+ }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), Ut().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
2780
2846
  }
2781
2847
  currentPresentation() {
2782
2848
  let e = this.opts.video;
@@ -2791,7 +2857,7 @@ var sn = class {
2791
2857
  video: this.opts.video,
2792
2858
  descriptor: e,
2793
2859
  credential: t,
2794
- deviceId: A(),
2860
+ deviceId: j(),
2795
2861
  userId: this.opts.userId,
2796
2862
  lowLatency: this.opts.lowLatency === void 0 || this.opts.lowLatency === "auto" || this.opts.lowLatency,
2797
2863
  snapToLiveOnRefocus: this.opts.snapToLiveOnRefocus,
@@ -2801,11 +2867,11 @@ var sn = class {
2801
2867
  hlsConfig: i,
2802
2868
  emit: (e) => this.onEngineEvent(e)
2803
2869
  }, o = this.opts.engine ?? "auto";
2804
- if (o === "native") return new U(a);
2805
- if (o === "hls") return new J(a);
2806
- if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && V(this.opts.video) && H()) return new U(a);
2807
- if (Je()) return new J(a);
2808
- if (V(this.opts.video)) return new U(a);
2870
+ if (o === "native") return new Y(a);
2871
+ if (o === "hls") return new St(a);
2872
+ if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && q(this.opts.video) && J()) return new Y(a);
2873
+ if (Qe()) return new St(a);
2874
+ if (q(this.opts.video)) return new Y(a);
2809
2875
  throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
2810
2876
  }
2811
2877
  onEngineEvent(e) {
@@ -2842,11 +2908,11 @@ var sn = class {
2842
2908
  }
2843
2909
  startLiveState(e) {
2844
2910
  if (this.opts.liveStateEvents === !1) return;
2845
- let t = this.opts.eventsBaseUrl ?? D(this.opts.baseUrl);
2911
+ let t = this.opts.eventsBaseUrl ?? O(this.opts.baseUrl);
2846
2912
  if (!t) return;
2847
2913
  this.closeLiveState();
2848
2914
  let r = 0, i = !1;
2849
- this.liveStateSub = E({
2915
+ this.liveStateSub = D({
2850
2916
  eventsBaseUrl: t,
2851
2917
  matchUrn: this.opts.matchUrn,
2852
2918
  credential: this.opts.credential,
@@ -2857,7 +2923,7 @@ var sn = class {
2857
2923
  r = 0, i = !1;
2858
2924
  },
2859
2925
  onError: () => {
2860
- this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= tn && (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.`))));
2926
+ this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= un && (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.`))));
2861
2927
  }
2862
2928
  });
2863
2929
  }
@@ -2879,7 +2945,7 @@ var sn = class {
2879
2945
  scheduleRejoin(e) {
2880
2946
  this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
2881
2947
  this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
2882
- }, Math.random() * en));
2948
+ }, Math.random() * ln));
2883
2949
  }
2884
2950
  cancelRejoin() {
2885
2951
  this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
@@ -2903,7 +2969,7 @@ var sn = class {
2903
2969
  }
2904
2970
  t.controls = !1;
2905
2971
  let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
2906
- r && r.insertBefore(n, t), n.appendChild(t), Z(n, this.opts.theme), this.container = n, this.controlBar = Kt({
2972
+ r && r.insertBefore(n, t), n.appendChild(t), qt(n, this.opts.theme), this.container = n, this.controlBar = en({
2907
2973
  root: n,
2908
2974
  video: t,
2909
2975
  player: this,
@@ -2933,7 +2999,7 @@ var sn = class {
2933
2999
  }
2934
3000
  startStats() {
2935
3001
  this.stopStats();
2936
- let e = Math.max(500, this.opts.statsIntervalMs ?? nn);
3002
+ let e = Math.max(500, this.opts.statsIntervalMs ?? dn);
2937
3003
  this.statsTimer = setInterval(() => {
2938
3004
  if (!this.engine) return;
2939
3005
  let e = this.engine.getStats();
@@ -2945,7 +3011,7 @@ var sn = class {
2945
3011
  }
2946
3012
  scheduleLicenseRefresh() {
2947
3013
  this.stopRefresh();
2948
- let e = this.opts.licenseRefreshMs ?? rn;
3014
+ let e = this.opts.licenseRefreshMs ?? fn;
2949
3015
  e && this._descriptor?.drmEnabled && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
2950
3016
  }
2951
3017
  stopRefresh() {
@@ -2990,7 +3056,7 @@ var sn = class {
2990
3056
  this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
2991
3057
  }
2992
3058
  getStats() {
2993
- return this.engine?.getStats() ?? R;
3059
+ return this.engine?.getStats() ?? W;
2994
3060
  }
2995
3061
  getQualityLevels() {
2996
3062
  return this.engine?.getQualityLevels() ?? [];
@@ -3029,10 +3095,10 @@ var sn = class {
3029
3095
  e.pictureInPictureElement === this.opts.video && typeof e.exitPictureInPicture == "function" && await e.exitPictureInPicture();
3030
3096
  }
3031
3097
  async enterFullscreen() {
3032
- return !this.destroyed && w(this.opts.video, this.container ?? void 0);
3098
+ return !this.destroyed && T(this.opts.video, this.container ?? void 0);
3033
3099
  }
3034
3100
  async exitFullscreen() {
3035
- await T(this.opts.video, this.container ?? void 0);
3101
+ await E(this.opts.video, this.container ?? void 0);
3036
3102
  }
3037
3103
  retry() {
3038
3104
  return this.reload();
@@ -3100,7 +3166,7 @@ function $(e) {
3100
3166
  }
3101
3167
  //#endregion
3102
3168
  //#region src/embed/host.ts
3103
- function cn(e) {
3169
+ function gn(e) {
3104
3170
  if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
3105
3171
  if (!e.src) throw Error("mountEmbed: opts.src is required");
3106
3172
  if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
@@ -3159,15 +3225,15 @@ function cn(e) {
3159
3225
  }
3160
3226
  //#endregion
3161
3227
  //#region src/embed/page.ts
3162
- var ln = /^[A-Za-z0-9:_.-]{1,128}$/;
3163
- function un(e) {
3228
+ var _n = /^[A-Za-z0-9:_.-]{1,128}$/;
3229
+ function vn(e) {
3164
3230
  if (typeof e == "boolean") return e;
3165
3231
  if (typeof e == "object" && e) {
3166
3232
  let t = e.endpoint;
3167
3233
  return typeof t == "string" ? { endpoint: t } : {};
3168
3234
  }
3169
3235
  }
3170
- function dn() {
3236
+ function yn() {
3171
3237
  let e = window.HAVIK_EMBED_CONFIG;
3172
3238
  if (e) return {
3173
3239
  baseUrl: e.baseUrl ?? "",
@@ -3177,7 +3243,7 @@ function dn() {
3177
3243
  autoplay: e.autoplay ?? !0,
3178
3244
  muted: e.muted ?? !0,
3179
3245
  waitForLive: e.waitForLive ?? !0,
3180
- analytics: un(e.analytics)
3246
+ analytics: vn(e.analytics)
3181
3247
  };
3182
3248
  let t = new URLSearchParams(location.search);
3183
3249
  return {
@@ -3190,9 +3256,9 @@ function dn() {
3190
3256
  waitForLive: !0
3191
3257
  };
3192
3258
  }
3193
- async function fn() {
3194
- let e = dn();
3195
- mn();
3259
+ async function bn() {
3260
+ let e = yn();
3261
+ Sn();
3196
3262
  let t = document.createElement("video");
3197
3263
  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);
3198
3264
  let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
@@ -3247,12 +3313,12 @@ async function fn() {
3247
3313
  code: e.code,
3248
3314
  message: e.message
3249
3315
  })), e.on("autoplayblocked", () => {
3250
- i({ type: "oddin:autoplayblocked" }), pn(t, e);
3316
+ i({ type: "oddin:autoplayblocked" }), xn(t, e);
3251
3317
  });
3252
3318
  }, s = async (r) => {
3253
3319
  a?.destroy(), a = null;
3254
3320
  try {
3255
- let n = await on({
3321
+ let n = await mn({
3256
3322
  video: t,
3257
3323
  baseUrl: e.baseUrl,
3258
3324
  matchUrn: r,
@@ -3314,7 +3380,7 @@ async function fn() {
3314
3380
  a?.retry();
3315
3381
  break;
3316
3382
  case "oddin:load":
3317
- typeof e.matchUrn == "string" && ln.test(e.matchUrn) && s(e.matchUrn);
3383
+ typeof e.matchUrn == "string" && _n.test(e.matchUrn) && s(e.matchUrn);
3318
3384
  break;
3319
3385
  case "oddin:destroy": c();
3320
3386
  }
@@ -3326,18 +3392,18 @@ async function fn() {
3326
3392
  protocol: 1
3327
3393
  });
3328
3394
  }
3329
- function pn(e, t) {
3395
+ function xn(e, t) {
3330
3396
  if (document.getElementById("havik-tap")) return;
3331
3397
  let n = document.createElement("button");
3332
3398
  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", () => {
3333
3399
  n.remove(), t.play();
3334
3400
  }), document.body.appendChild(n);
3335
3401
  }
3336
- function mn() {
3402
+ function Sn() {
3337
3403
  let e = document.createElement("style");
3338
3404
  e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
3339
3405
  }
3340
3406
  //#endregion
3341
- export { Rt as ODDIN_THEME, n as PlaybackError, Z as applyTheme, L as baseUrlForEnv, fn as bootEmbed, be as clearDeviceId, on as createPlayer, D as deriveEventsBaseUrl, Ne as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, pe as fetchCatalog, he as fetchTournament, _e as flattenMatches, A as getDeviceId, Fe as isLowLatencyManifest, $ as isOddinMessage, Se as licenseRequestHeaders, cn as mountEmbed, v as pollToLive, b as resolveStream, E as subscribeLiveState, C as videoFullscreenActive, ve as watchStatus };
3407
+ export { Gt as ODDIN_THEME, n as PlaybackError, qt as applyTheme, U as baseUrlForEnv, bn as bootEmbed, ye as clearDeviceId, mn as createPlayer, O as deriveEventsBaseUrl, Fe as detectDrmSupport, T as enterVideoFullscreen, E as exitVideoFullscreen, fe as fetchCatalog, me as fetchTournament, ge as flattenMatches, j as getDeviceId, Le as isLowLatencyManifest, $ as isOddinMessage, xe as licenseRequestHeaders, gn as mountEmbed, v as pollToLive, b as resolveStream, D as subscribeLiveState, w as videoFullscreenActive, _e as watchStatus };
3342
3408
 
3343
3409
  //# sourceMappingURL=index.js.map