@oddin-gg/havik-player 2.18.0 → 2.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -7,8 +7,9 @@ var n = class extends Error {
7
7
  requestId;
8
8
  serverCode;
9
9
  liveStartsAtMs;
10
+ country;
10
11
  constructor(e, t, n, r) {
11
- super(n), this.name = "PlaybackError", this.code = e, this.httpStatus = t, this.retryAfterMs = r?.retryAfterMs, this.requestId = r?.requestId, this.serverCode = r?.serverCode, this.liveStartsAtMs = r?.liveStartsAtMs, r?.cause !== void 0 && (this.cause = r.cause);
12
+ super(n), this.name = "PlaybackError", this.code = e, this.httpStatus = t, this.retryAfterMs = r?.retryAfterMs, this.requestId = r?.requestId, this.serverCode = r?.serverCode, this.liveStartsAtMs = r?.liveStartsAtMs, this.country = r?.country, r?.cause !== void 0 && (this.cause = r.cause);
12
13
  }
13
14
  };
14
15
  function r(e) {
@@ -20,6 +21,7 @@ function r(e) {
20
21
  case 410: return "GONE";
21
22
  case 425: return "TOO_EARLY";
22
23
  case 429: return "RATE_LIMITED";
24
+ case 451: return "GEO_DENIED";
23
25
  case 503: return "UNAVAILABLE";
24
26
  default: return "INTERNAL";
25
27
  }
@@ -215,19 +217,21 @@ function y(e) {
215
217
  return e.waitForLive ? de(t, e.waitForLive, e.signal) : t();
216
218
  }
217
219
  async function fe(e) {
218
- let t = f(e.headers.get("retry-after")), i = e.headers.get("x-request-id") ?? e.headers.get("x-amzn-requestid") ?? void 0, a = e.statusText || `HTTP ${e.status}`, o, s;
220
+ let t = f(e.headers.get("retry-after")), i = e.headers.get("x-request-id") ?? e.headers.get("x-amzn-requestid") ?? void 0, a = e.statusText || `HTTP ${e.status}`, o, s, c;
219
221
  try {
220
222
  let t = await e.json();
221
223
  if (t?.error?.message && (a = t.error.message), t?.error?.code && (o = t.error.code), typeof t?.liveStartsAt == "string") {
222
224
  let e = Date.parse(t.liveStartsAt);
223
225
  Number.isFinite(e) && (s = e);
224
226
  }
227
+ e.status === 451 && typeof t?.country == "string" && /^[A-Z]{2}$/.test(t.country) && (c = t.country);
225
228
  } catch {}
226
229
  return new n(r(e.status), e.status, a, {
227
230
  retryAfterMs: t,
228
231
  requestId: i,
229
232
  serverCode: o,
230
- liveStartsAtMs: s
233
+ liveStartsAtMs: s,
234
+ country: c
231
235
  });
232
236
  }
233
237
  var pe = /* @__PURE__ */ new Set([
@@ -287,35 +291,42 @@ function he(e, t) {
287
291
  }
288
292
  //#endregion
289
293
  //#region src/core/fullscreen.ts
290
- function ge(e) {
294
+ function x(e) {
291
295
  return e.ownerDocument ?? document;
292
296
  }
293
- function _e(e) {
297
+ function ge(e) {
294
298
  return e.fullscreenElement ?? e.webkitFullscreenElement ?? null;
295
299
  }
296
- function x(e, t) {
297
- let n = _e(ge(e));
300
+ function S(e, t) {
301
+ let n = ge(x(e));
298
302
  return n != null && (n === e || t != null && n === t) || e.webkitDisplayingFullscreen === !0;
299
303
  }
300
- async function S(e, t) {
304
+ function C(e, t) {
305
+ let n = t ?? e, r = x(e);
306
+ if (typeof n.requestFullscreen == "function") return r.fullscreenEnabled !== !1;
307
+ if (typeof n.webkitRequestFullscreen == "function") return r.webkitFullscreenEnabled !== !1;
308
+ let i = e;
309
+ return i.webkitSupportsFullscreen === !0 && typeof i.webkitEnterFullscreen == "function" || e.readyState < 1;
310
+ }
311
+ async function w(e, t) {
301
312
  let n = t ?? e;
302
313
  if (typeof n.requestFullscreen == "function") return await n.requestFullscreen(), !0;
303
314
  if (typeof n.webkitRequestFullscreen == "function") return n.webkitRequestFullscreen(), !0;
304
315
  let r = e;
305
316
  return r.webkitSupportsFullscreen && typeof r.webkitEnterFullscreen == "function" ? (r.webkitEnterFullscreen(), !0) : !1;
306
317
  }
307
- async function C(e, t) {
318
+ async function T(e, t) {
308
319
  let n = e;
309
320
  if (n.webkitDisplayingFullscreen) {
310
321
  n.webkitExitFullscreen?.();
311
322
  return;
312
323
  }
313
- let r = ge(e), i = _e(r);
324
+ let r = x(e), i = ge(r);
314
325
  i != null && (i === e || t != null && i === t) && (typeof r.exitFullscreen == "function" ? await r.exitFullscreen() : r.webkitExitFullscreen?.());
315
326
  }
316
327
  //#endregion
317
328
  //#region src/core/catalog.ts
318
- async function ve(e) {
329
+ async function _e(e) {
319
330
  let t = new URLSearchParams();
320
331
  e.status && t.set("status", Array.isArray(e.status) ? e.status.join(",") : e.status), e.sport && t.set("sport", e.sport);
321
332
  let i = t.toString(), a = d(e.baseUrl, "/v1/catalog" + (i ? `?${i}` : "")), o = new Headers();
@@ -333,12 +344,12 @@ async function ve(e) {
333
344
  };
334
345
  if (!s.ok) throw new n(r(s.status), s.status, `catalog request failed (HTTP ${s.status})`);
335
346
  return {
336
- tournaments: ye(await s.json()),
347
+ tournaments: ve(await s.json()),
337
348
  etag: s.headers.get("etag") ?? void 0,
338
349
  notModified: !1
339
350
  };
340
351
  }
341
- function ye(e) {
352
+ function ve(e) {
342
353
  return (e.tournaments ?? []).map((e) => {
343
354
  let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
344
355
  return {
@@ -360,7 +371,7 @@ function ye(e) {
360
371
  };
361
372
  });
362
373
  }
363
- async function be(e) {
374
+ async function ye(e) {
364
375
  let t = d(e.baseUrl, `/v1/tournaments/${encodeURIComponent(e.urn)}`), i = new Headers();
365
376
  e.etag && i.set("If-None-Match", e.etag);
366
377
  let a = await p(t, {
@@ -380,13 +391,13 @@ async function be(e) {
380
391
  };
381
392
  if (!a.ok) throw new n(r(a.status), a.status, `tournament request failed (HTTP ${a.status})`);
382
393
  return {
383
- tournament: xe(await a.json()),
394
+ tournament: be(await a.json()),
384
395
  etag: a.headers.get("etag") ?? void 0,
385
396
  notModified: !1,
386
397
  notFound: !1
387
398
  };
388
399
  }
389
- function xe(e) {
400
+ function be(e) {
390
401
  let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
391
402
  return {
392
403
  urn: t,
@@ -406,17 +417,18 @@ function xe(e) {
406
417
  }))
407
418
  };
408
419
  }
409
- function Se(e) {
420
+ function xe(e) {
410
421
  return e.tournaments.flatMap((e) => e.matches);
411
422
  }
412
423
  //#endregion
413
424
  //#region src/core/poll.ts
414
- var Ce = /* @__PURE__ */ new Set([
425
+ var Se = /* @__PURE__ */ new Set([
415
426
  "NOT_FOUND",
427
+ "GEO_DENIED",
416
428
  "GONE",
417
429
  "INVALID_URN"
418
430
  ]);
419
- function we(e) {
431
+ function Ce(e) {
420
432
  let t = Math.max(2e3, e.intervalMs ?? 1e4), i = new AbortController(), a, o, s, u = !1, f = () => {
421
433
  u || (a = setTimeout(m, t));
422
434
  }, m = async () => {
@@ -449,7 +461,7 @@ function we(e) {
449
461
  } catch (t) {
450
462
  if (!i.signal.aborted) {
451
463
  let r = t instanceof n ? t : new n("NETWORK", 0, String(t));
452
- Ce.has(r.code) && (u = !0), e.onError?.(r);
464
+ Se.has(r.code) && (u = !0), e.onError?.(r);
453
465
  }
454
466
  } finally {
455
467
  f();
@@ -461,9 +473,9 @@ function we(e) {
461
473
  }
462
474
  //#endregion
463
475
  //#region src/core/events.ts
464
- var Te = 45e3;
465
- function w(e) {
466
- let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = e.idleTimeoutMs ?? Te, i = Number.isFinite(r) && r > 0 ? r : 0, a = new AbortController(), o = !1, c = (e) => new Promise((t) => {
476
+ var we = 45e3;
477
+ function E(e) {
478
+ let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = e.idleTimeoutMs ?? we, i = Number.isFinite(r) && r > 0 ? r : 0, a = new AbortController(), o = !1, c = (e) => new Promise((t) => {
467
479
  if (a.signal.aborted) return t();
468
480
  let n = setTimeout(t, e);
469
481
  a.signal.addEventListener("abort", () => {
@@ -545,7 +557,7 @@ function w(e) {
545
557
  o || (o = !0, a.abort());
546
558
  } };
547
559
  }
548
- function T(e) {
560
+ function D(e) {
549
561
  try {
550
562
  let t = new URL(e);
551
563
  return t.hostname = `events.${t.hostname}`, t.pathname = "", t.search = "", t.origin;
@@ -555,27 +567,27 @@ function T(e) {
555
567
  }
556
568
  //#endregion
557
569
  //#region src/core/drm/deviceId.ts
558
- var E = "havik.player.deviceId", D;
559
- function O() {
560
- if (D) return D;
570
+ var O = "havik.player.deviceId", k;
571
+ function A() {
572
+ if (k) return k;
561
573
  try {
562
- let e = globalThis.localStorage?.getItem(E);
563
- if (e) return D = e, e;
574
+ let e = globalThis.localStorage?.getItem(O);
575
+ if (e) return k = e, e;
564
576
  } catch {}
565
- let e = De();
566
- D = e;
577
+ let e = Ee();
578
+ k = e;
567
579
  try {
568
- globalThis.localStorage?.setItem(E, e);
580
+ globalThis.localStorage?.setItem(O, e);
569
581
  } catch {}
570
582
  return e;
571
583
  }
572
- function Ee() {
573
- D = void 0;
584
+ function Te() {
585
+ k = void 0;
574
586
  try {
575
- globalThis.localStorage?.removeItem(E);
587
+ globalThis.localStorage?.removeItem(O);
576
588
  } catch {}
577
589
  }
578
- function De() {
590
+ function Ee() {
579
591
  let e = globalThis.crypto;
580
592
  if (e && typeof e.randomUUID == "function") return e.randomUUID();
581
593
  let t = /* @__PURE__ */ new Uint8Array(16);
@@ -587,32 +599,32 @@ function De() {
587
599
  }
588
600
  //#endregion
589
601
  //#region src/core/drm/headers.ts
590
- function Oe(e, t, n = {}) {
602
+ function De(e, t, n = {}) {
591
603
  let r = {
592
604
  "x-api-key": t.apiKey,
593
605
  "X-Match-Urn": e.matchUrn,
594
- "X-Device-Id": n.deviceId ?? O(),
606
+ "X-Device-Id": n.deviceId ?? A(),
595
607
  "Content-Type": "application/octet-stream"
596
608
  };
597
609
  return n.userId && (r["X-User-Id"] = n.userId), r;
598
610
  }
599
611
  //#endregion
600
612
  //#region src/core/bandwidthMemory.ts
601
- var k = "havik.player.bandwidth", ke = .8, Ae = 2e7, je = 3e5;
602
- function Me() {
613
+ var j = "havik.player.bandwidth", Oe = .8, ke = 2e7, Ae = 3e5;
614
+ function je() {
603
615
  return globalThis.navigator?.connection;
604
616
  }
605
- function Ne() {
606
- let e = Me()?.type;
617
+ function Me() {
618
+ let e = je()?.type;
607
619
  return typeof e == "string" && e !== "" && e !== "unknown" ? e : "any";
608
620
  }
609
- function Pe() {
610
- let e = Me()?.downlink;
621
+ function Ne() {
622
+ let e = je()?.downlink;
611
623
  return typeof e == "number" && Number.isFinite(e) && e > 0 ? e * 1e6 : void 0;
612
624
  }
613
- function Fe() {
625
+ function Pe() {
614
626
  try {
615
- let e = globalThis.localStorage?.getItem(k);
627
+ let e = globalThis.localStorage?.getItem(j);
616
628
  if (!e) return {};
617
629
  let t = JSON.parse(e);
618
630
  return t && typeof t == "object" && !Array.isArray(t) ? t : {};
@@ -620,36 +632,36 @@ function Fe() {
620
632
  return {};
621
633
  }
622
634
  }
623
- function Ie(e = Date.now()) {
624
- let t = Fe()[Ne()];
635
+ function Fe(e = Date.now()) {
636
+ let t = Pe()[Me()];
625
637
  if (!t || typeof t.bps != "number" || typeof t.at != "number" || !Number.isFinite(t.bps) || t.bps <= 0) return;
626
638
  let n = e - t.at;
627
639
  if (n < 0 || n > 2592e5) return;
628
- let r = Pe(), i = r === void 0 ? t.bps : Math.min(t.bps, r);
629
- return Math.round(Math.min(Ae, Math.max(je, i * ke)));
640
+ let r = Ne(), i = r === void 0 ? t.bps : Math.min(t.bps, r);
641
+ return Math.round(Math.min(ke, Math.max(Ae, i * Oe)));
630
642
  }
631
- function Le(e, t = Date.now()) {
643
+ function Ie(e, t = Date.now()) {
632
644
  if (!Number.isFinite(e) || e <= 0) return;
633
- let n = Fe();
634
- n[Ne()] = {
645
+ let n = Pe();
646
+ n[Me()] = {
635
647
  bps: Math.round(e),
636
648
  at: t
637
649
  };
638
650
  try {
639
- globalThis.localStorage?.setItem(k, JSON.stringify(n));
651
+ globalThis.localStorage?.setItem(j, JSON.stringify(n));
640
652
  } catch {}
641
653
  }
642
- function Re() {
654
+ function Le() {
643
655
  try {
644
- globalThis.localStorage?.removeItem(k);
656
+ globalThis.localStorage?.removeItem(j);
645
657
  } catch {}
646
658
  }
647
659
  //#endregion
648
660
  //#region src/core/drm/cdm.ts
649
- var ze = /* @__PURE__ */ new WeakMap();
650
- function Be(e, t) {
651
- let n = ze.get(e);
652
- n || (n = /* @__PURE__ */ new Map(), ze.set(e, n));
661
+ var Re = /* @__PURE__ */ new WeakMap();
662
+ function ze(e, t) {
663
+ let n = Re.get(e);
664
+ n || (n = /* @__PURE__ */ new Map(), Re.set(e, n));
653
665
  let r = n.get(t.keySystem);
654
666
  if (r) return r;
655
667
  let i = t.createMediaKeys().catch((e) => {
@@ -657,22 +669,22 @@ function Be(e, t) {
657
669
  });
658
670
  return n.set(t.keySystem, i), i;
659
671
  }
660
- function A() {
672
+ function M() {
661
673
  return typeof navigator < "u" && typeof navigator.requestMediaKeySystemAccess == "function";
662
674
  }
663
- var j = ["SW_SECURE_DECODE", "SW_SECURE_CRYPTO"];
664
- function Ve(e) {
675
+ var N = ["SW_SECURE_DECODE", "SW_SECURE_CRYPTO"];
676
+ function Be(e) {
665
677
  return e.startsWith("com.widevine");
666
678
  }
667
- function M(e, t) {
668
- if (!Ve(e)) return t;
679
+ function P(e, t) {
680
+ if (!Be(e)) return t;
669
681
  let n = (e, t) => {
670
682
  let n = e.videoCapabilities;
671
683
  return !n?.length || !n.some((e) => e.robustness) ? !1 : n.every((e) => {
672
- let n = j.indexOf(e.robustness);
673
- return n === -1 || j.indexOf(t) > n;
684
+ let n = N.indexOf(e.robustness);
685
+ return n === -1 || N.indexOf(t) > n;
674
686
  });
675
- }, r = j.flatMap((e) => t.filter((t) => n(t, e)).map((t) => ({
687
+ }, r = N.flatMap((e) => t.filter((t) => n(t, e)).map((t) => ({
676
688
  ...t,
677
689
  videoCapabilities: t.videoCapabilities?.map((t) => ({
678
690
  ...t,
@@ -681,53 +693,53 @@ function M(e, t) {
681
693
  })));
682
694
  return [...t, ...r];
683
695
  }
684
- function He(e) {
685
- return (t, n) => A() ? navigator.requestMediaKeySystemAccess(t, M(t, n)).then((t) => ({
696
+ function Ve(e) {
697
+ return (t, n) => M() ? navigator.requestMediaKeySystemAccess(t, P(t, n)).then((t) => ({
686
698
  keySystem: t.keySystem,
687
699
  getConfiguration: () => t.getConfiguration(),
688
- createMediaKeys: () => Be(e, t)
700
+ createMediaKeys: () => ze(e, t)
689
701
  })) : Promise.reject(/* @__PURE__ */ Error("navigator.requestMediaKeySystemAccess is unavailable — EME needs a secure context (https, or localhost)"));
690
702
  }
691
- var N = {
703
+ var F = {
692
704
  video: "SW_SECURE_DECODE",
693
705
  audio: "SW_SECURE_CRYPTO",
694
706
  scheme: "cbcs"
695
707
  };
696
- function Ue(e) {
697
- if (!A()) return;
708
+ function He(e) {
709
+ if (!M()) return;
698
710
  let t = (e, t) => ({
699
711
  contentType: e,
700
712
  robustness: t,
701
- encryptionScheme: N.scheme
713
+ encryptionScheme: F.scheme
702
714
  });
703
- He(e)("com.widevine.alpha", [{
715
+ Ve(e)("com.widevine.alpha", [{
704
716
  initDataTypes: ["cenc"],
705
717
  distinctiveIdentifier: "optional",
706
718
  persistentState: "optional",
707
719
  sessionTypes: ["temporary"],
708
- audioCapabilities: [t("audio/mp4; codecs=\"mp4a.40.2\"", N.audio)],
709
- videoCapabilities: [t("video/mp4; codecs=\"avc1.42e01e\"", N.video)]
720
+ audioCapabilities: [t("audio/mp4; codecs=\"mp4a.40.2\"", F.audio)],
721
+ videoCapabilities: [t("video/mp4; codecs=\"avc1.42e01e\"", F.video)]
710
722
  }]).then((e) => e.createMediaKeys()).catch(() => {});
711
723
  }
712
- function P(e) {
713
- let t = F(e);
724
+ function I(e) {
725
+ let t = L(e);
714
726
  if (/^avc[13]/.test(t)) return "avc";
715
727
  if (/^(hvc1|hev1)/.test(t)) return "hevc";
716
728
  if (/^(dvh1|dvhe)/.test(t)) return "dv";
717
729
  if (t.startsWith("av01")) return "av1";
718
730
  if (/^vp0?9/.test(t)) return "vp9";
719
731
  }
720
- function F(e) {
732
+ function L(e) {
721
733
  return (e ?? "").trim().toLowerCase();
722
734
  }
723
- var We = {
735
+ var Ue = {
724
736
  hevc: "hvc1.1.6.L93.90",
725
737
  dv: "dvh1.05.06",
726
738
  av1: "av01.0.05M.08",
727
739
  vp9: "vp09.00.10.08"
728
- }, Ge = /* @__PURE__ */ new Map(), I = /* @__PURE__ */ new Map();
729
- function Ke(e) {
730
- let t = F(e), n = Ge.get(t);
740
+ }, We = /* @__PURE__ */ new Map(), R = /* @__PURE__ */ new Map();
741
+ function Ge(e) {
742
+ let t = L(e), n = We.get(t);
731
743
  if (n) return n;
732
744
  let r = {
733
745
  initDataTypes: ["cenc"],
@@ -736,32 +748,32 @@ function Ke(e) {
736
748
  sessionTypes: ["temporary"],
737
749
  videoCapabilities: [{
738
750
  contentType: `video/mp4; codecs="${e.trim()}"`,
739
- robustness: N.video,
740
- encryptionScheme: N.scheme
751
+ robustness: F.video,
752
+ encryptionScheme: F.scheme
741
753
  }]
742
754
  }, i = (async () => {
743
755
  try {
744
- return await navigator.requestMediaKeySystemAccess("com.widevine.alpha", M("com.widevine.alpha", [r])), !0;
756
+ return await navigator.requestMediaKeySystemAccess("com.widevine.alpha", P("com.widevine.alpha", [r])), !0;
745
757
  } catch {
746
758
  return !1;
747
759
  }
748
- })().then((e) => (I.set(t, e), e));
749
- return Ge.set(t, i), i;
760
+ })().then((e) => (R.set(t, e), e));
761
+ return We.set(t, i), i;
750
762
  }
751
- function qe() {
752
- if (A()) for (let e of Object.values(We)) Ke(e);
763
+ function Ke() {
764
+ if (M()) for (let e of Object.values(Ue)) Ge(e);
753
765
  }
754
- function Je(e) {
755
- let t = P(e);
756
- if (t) return t === "avc" ? !0 : I.get(F(e)) ?? I.get(F(We[t]));
766
+ function qe(e) {
767
+ let t = I(e);
768
+ if (t) return t === "avc" ? !0 : R.get(L(e)) ?? R.get(L(Ue[t]));
757
769
  }
758
770
  //#endregion
759
771
  //#region src/core/drm/support.ts
760
- var Ye = 5e3, Xe = "video/mp4; codecs=\"avc1.42E01E\"", Ze = "audio/mp4; codecs=\"mp4a.40.2\"", Qe = {
772
+ var Je = 5e3, Ye = "video/mp4; codecs=\"avc1.42E01E\"", Xe = "audio/mp4; codecs=\"mp4a.40.2\"", Ze = {
761
773
  widevine: ["com.widevine.alpha"],
762
774
  fairplay: ["com.apple.fps"]
763
775
  };
764
- function $e(e) {
776
+ function Qe(e) {
765
777
  return e === "fairplay" ? [{
766
778
  initDataTypes: [
767
779
  "sinf",
@@ -769,30 +781,30 @@ function $e(e) {
769
781
  "cenc"
770
782
  ],
771
783
  videoCapabilities: [{
772
- contentType: Xe,
784
+ contentType: Ye,
773
785
  robustness: "",
774
786
  encryptionScheme: "cbcs"
775
787
  }],
776
788
  audioCapabilities: [{
777
- contentType: Ze,
789
+ contentType: Xe,
778
790
  robustness: "",
779
791
  encryptionScheme: "cbcs"
780
792
  }]
781
- }] : M("com.widevine.alpha", [{
793
+ }] : P("com.widevine.alpha", [{
782
794
  initDataTypes: ["cenc"],
783
795
  videoCapabilities: [{
784
- contentType: Xe,
785
- robustness: N.video,
786
- encryptionScheme: N.scheme
796
+ contentType: Ye,
797
+ robustness: F.video,
798
+ encryptionScheme: F.scheme
787
799
  }],
788
800
  audioCapabilities: [{
789
- contentType: Ze,
790
- robustness: N.audio,
791
- encryptionScheme: N.scheme
801
+ contentType: Xe,
802
+ robustness: F.audio,
803
+ encryptionScheme: F.scheme
792
804
  }]
793
805
  }]);
794
806
  }
795
- function et(e, t) {
807
+ function $e(e, t) {
796
808
  return new Promise((n, r) => {
797
809
  let i = setTimeout(() => r(/* @__PURE__ */ Error("probe-timeout")), t);
798
810
  e.then((e) => {
@@ -802,8 +814,8 @@ function et(e, t) {
802
814
  });
803
815
  });
804
816
  }
805
- async function tt(e = {}) {
806
- let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Ye, r = {};
817
+ async function et(e = {}) {
818
+ let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Je, r = {};
807
819
  if (typeof window < "u" && window.isSecureContext === !1) return {
808
820
  verdict: "insecure-context",
809
821
  detail: r
@@ -815,7 +827,7 @@ async function tt(e = {}) {
815
827
  };
816
828
  let a = !1, o = !1, s = Date.now() + n, c = () => Math.max(1, s - Date.now());
817
829
  for (let e of t) {
818
- let t = Qe[e];
830
+ let t = Ze[e];
819
831
  if (!t) {
820
832
  r[e] = "unknown system";
821
833
  continue;
@@ -826,7 +838,7 @@ async function tt(e = {}) {
826
838
  break;
827
839
  }
828
840
  try {
829
- return await et((await et(i(n, $e(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
841
+ return await $e((await $e(i(n, Qe(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
830
842
  verdict: "supported",
831
843
  system: e,
832
844
  detail: r
@@ -850,37 +862,37 @@ async function tt(e = {}) {
850
862
  }
851
863
  //#endregion
852
864
  //#region src/core/manifest.ts
853
- var nt = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
854
- function rt(e) {
855
- return nt.test(e);
865
+ var tt = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
866
+ function nt(e) {
867
+ return tt.test(e);
856
868
  }
857
869
  //#endregion
858
870
  //#region src/core/env.ts
859
- var it = {
871
+ var rt = {
860
872
  integration: "https://feed-dev.oddin-video.gg",
861
873
  production: "https://feed.oddin-video.gg"
862
874
  };
863
- function L(e) {
864
- let t = Object.prototype.hasOwnProperty.call(it, e) ? it[e] : void 0;
875
+ function it(e) {
876
+ let t = Object.prototype.hasOwnProperty.call(rt, e) ? rt[e] : void 0;
865
877
  if (!t) throw new n("INTERNAL", 0, `unknown env ${JSON.stringify(e)} — expected 'integration' or 'production'`);
866
878
  return t;
867
879
  }
868
880
  //#endregion
869
881
  //#region src/core/stats.ts
870
- var R = { droppedFrames: 0 };
871
- function z(e) {
882
+ var z = { droppedFrames: 0 };
883
+ function at(e) {
872
884
  try {
873
885
  return new URL(e).host;
874
886
  } catch {
875
887
  return "";
876
888
  }
877
889
  }
878
- var at = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
879
- function ot(e) {
890
+ var ot = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
891
+ function st(e) {
880
892
  if (typeof performance > "u" || typeof performance.getEntriesByType != "function") return "";
881
893
  let t = "", n = -1, r = performance.getEntriesByType("resource");
882
- for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || at.test(i.name)) && i.startTime >= n) {
883
- let e = z(i.name);
894
+ for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || ot.test(i.name)) && i.startTime >= n) {
895
+ let e = at(i.name);
884
896
  e && (t = e, n = i.startTime);
885
897
  }
886
898
  return t;
@@ -892,7 +904,7 @@ function B(e) {
892
904
  totalFrames: t?.totalVideoFrames ?? 0
893
905
  };
894
906
  }
895
- var st = class {
907
+ var ct = class {
896
908
  video;
897
909
  baseFrames = 0;
898
910
  baseDropped = 0;
@@ -915,7 +927,7 @@ var st = class {
915
927
  };
916
928
  }
917
929
  };
918
- function ct(e, t) {
930
+ function lt(e, t) {
919
931
  let n = [
920
932
  ["playing", () => t("playing")],
921
933
  ["waiting", () => t("buffering")],
@@ -932,8 +944,8 @@ function ct(e, t) {
932
944
  }
933
945
  //#endregion
934
946
  //#region src/core/engine/native.ts
935
- var lt = 2e3, ut = 3, V = 500, dt = 6e3, ft = .25, pt = 250, mt = .05, ht = 4, gt = 12e3, _t = .25, vt = 1e3;
936
- function yt(e) {
947
+ var ut = 2e3, dt = 3, V = 500, ft = 6e3, pt = .25, mt = 250, ht = .05, gt = 4, _t = 12e3, vt = .25, yt = 1e3;
948
+ function bt(e) {
937
949
  try {
938
950
  let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
939
951
  return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
@@ -949,7 +961,7 @@ function U() {
949
961
  let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
950
962
  return e || t;
951
963
  }
952
- function bt() {
964
+ function xt() {
953
965
  if (typeof navigator > "u" || !U()) return !1;
954
966
  let e = navigator.userAgent ?? "";
955
967
  return /iPhone|iPad|iPod/.test(e) ? !0 : /Macintosh/.test(e) && typeof navigator.maxTouchPoints == "number" && navigator.maxTouchPoints > 1;
@@ -984,7 +996,7 @@ var W = class {
984
996
  frameCounter;
985
997
  detachFrames = null;
986
998
  constructor(e) {
987
- this.deps = e, this.frameCounter = new st(e.video), this.loadStarted = e.deferLoad !== !0, this.builtAt = typeof performance < "u" ? performance.now() : 0;
999
+ this.deps = e, this.frameCounter = new ct(e.video), this.loadStarted = e.deferLoad !== !0, this.builtAt = typeof performance < "u" ? performance.now() : 0;
988
1000
  }
989
1001
  async load() {
990
1002
  this.detachFrames ??= this.frameCounter.attach();
@@ -1005,7 +1017,7 @@ var W = class {
1005
1017
  type: "error",
1006
1018
  error: new n("INTERNAL", 0, "native HLS playback error"),
1007
1019
  fatal: !0
1008
- }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = St(t.manifestUrl, t.analytics?.sid), e.load();
1020
+ }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = Ct(t.manifestUrl, t.analytics?.sid), e.load();
1009
1021
  }
1010
1022
  startLoad() {
1011
1023
  this.loadStarted || (this.loadStarted = !0, this.restorePreload());
@@ -1027,7 +1039,7 @@ var W = class {
1027
1039
  });
1028
1040
  this.onEncrypted = (n) => {
1029
1041
  let i = n;
1030
- i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = yt(i.initData), (async () => {
1042
+ i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = bt(i.initData), (async () => {
1031
1043
  try {
1032
1044
  let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
1033
1045
  initDataTypes: [i.initDataType],
@@ -1126,10 +1138,10 @@ var W = class {
1126
1138
  droppedFrames: t.dropped,
1127
1139
  decodedFrames: t.totalFrames
1128
1140
  };
1129
- if (this.cdnHost ||= ot(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity) {
1141
+ if (this.cdnHost ||= st(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity) {
1130
1142
  n.isLive = !0;
1131
1143
  let t = this.liveEdgeEstimate(), r = t == null ? NaN : t - e.currentTime;
1132
- Number.isFinite(r) && (n.atLiveEdge = r <= ht, !e.paused && r >= 0 && (n.latencySeconds = r));
1144
+ Number.isFinite(r) && (n.atLiveEdge = r <= gt, !e.paused && r >= 0 && (n.latencySeconds = r));
1133
1145
  } else Number.isFinite(e.duration) && e.duration > 0 && (n.isLive = !1);
1134
1146
  return n;
1135
1147
  }
@@ -1147,7 +1159,7 @@ var W = class {
1147
1159
  return;
1148
1160
  }
1149
1161
  let t = this.hiddenSince;
1150
- this.hiddenSince = null, t != null && e - t >= lt && this.armRefocus();
1162
+ this.hiddenSince = null, t != null && e - t >= ut && this.armRefocus();
1151
1163
  }, this.onPageShow = (e) => {
1152
1164
  e.persisted && this.armRefocus();
1153
1165
  }, document.addEventListener("visibilitychange", this.onVisibility), typeof window < "u" && window.addEventListener("pageshow", this.onPageShow));
@@ -1157,7 +1169,7 @@ var W = class {
1157
1169
  let e = this.liveEnd(), t = G, n = t(), r = 0, i = () => {
1158
1170
  if (this.refocusTimer = null, Number.isFinite(this.deps.video.duration)) return;
1159
1171
  r += V;
1160
- let a = this.liveEnd(), o = a != null && (e == null || a >= e + ft), s = Math.max(r, t() - n) >= dt;
1172
+ let a = this.liveEnd(), o = a != null && (e == null || a >= e + pt), s = Math.max(r, t() - n) >= ft;
1161
1173
  if (o || s && a != null) {
1162
1174
  this.snapToLive();
1163
1175
  return;
@@ -1177,9 +1189,9 @@ var W = class {
1177
1189
  }, e.addEventListener("seeking", this.onEdgeReset), e.addEventListener("emptied", this.onEdgeReset), this.edgeTimer = setInterval(() => {
1178
1190
  if (e.duration !== Infinity) return;
1179
1191
  this.checkEndStale();
1180
- let t = xt(e, e.currentTime);
1181
- t != null && ((this.lastBufferedEnd == null || Math.abs(t - this.lastBufferedEnd) >= mt) && (this.bufferedAdvancedAt = G()), this.lastBufferedEnd = t);
1182
- }, pt);
1192
+ let t = St(e, e.currentTime);
1193
+ t != null && ((this.lastBufferedEnd == null || Math.abs(t - this.lastBufferedEnd) >= ht) && (this.bufferedAdvancedAt = G()), this.lastBufferedEnd = t);
1194
+ }, mt);
1183
1195
  }
1184
1196
  checkEndStale() {
1185
1197
  if (this.endedEmitted) return;
@@ -1187,14 +1199,14 @@ var W = class {
1187
1199
  this.lastTickAt = e;
1188
1200
  let n = this.liveEnd();
1189
1201
  if (n == null) return;
1190
- let r = this.lastSeekableEnd == null || Math.abs(n - this.lastSeekableEnd) >= _t;
1202
+ let r = this.lastSeekableEnd == null || Math.abs(n - this.lastSeekableEnd) >= vt;
1191
1203
  this.lastSeekableEnd = n;
1192
1204
  let i = this.deps.video, a = typeof document < "u" && document.visibilityState === "hidden";
1193
- if (r || t > vt || a || i.paused) {
1205
+ if (r || t > yt || a || i.paused) {
1194
1206
  this.edgeStampedAt = e;
1195
1207
  return;
1196
1208
  }
1197
- e - (this.edgeStampedAt ?? e) > gt && (this.endedEmitted = !0, this.deps.emit({
1209
+ e - (this.edgeStampedAt ?? e) > _t && (this.endedEmitted = !0, this.deps.emit({
1198
1210
  type: "ended",
1199
1211
  reason: "stalled"
1200
1212
  }));
@@ -1208,7 +1220,7 @@ var W = class {
1208
1220
  liveEdgeEstimate() {
1209
1221
  let e = this.deps.video;
1210
1222
  if (e.duration !== Infinity) return null;
1211
- let t = this.liveEnd(), n = xt(e, e.currentTime) ?? this.lastBufferedEnd;
1223
+ let t = this.liveEnd(), n = St(e, e.currentTime) ?? this.lastBufferedEnd;
1212
1224
  if (n != null) {
1213
1225
  let e = this.bufferedAdvancedAt, r = n + (e == null ? 0 : Math.max(0, (G() - e) / 1e3));
1214
1226
  (t == null || r > t) && (t = r);
@@ -1224,7 +1236,7 @@ var W = class {
1224
1236
  snapToLive() {
1225
1237
  let e = this.deps.video, t = this.liveEnd();
1226
1238
  if (t == null) return;
1227
- let n = e.seekable.start(e.seekable.length - 1), r = Math.min(e.currentTime, t), i = Math.max(n, t - ut, r);
1239
+ let n = e.seekable.start(e.seekable.length - 1), r = Math.min(e.currentTime, t), i = Math.max(n, t - dt, r);
1228
1240
  try {
1229
1241
  e.currentTime = i;
1230
1242
  } catch {}
@@ -1245,7 +1257,7 @@ var W = class {
1245
1257
  function G() {
1246
1258
  return typeof performance < "u" ? performance.now() : Date.now();
1247
1259
  }
1248
- function xt(e, t) {
1260
+ function St(e, t) {
1249
1261
  let n = e.buffered;
1250
1262
  if (!n || !Number.isFinite(t)) return null;
1251
1263
  for (let e = 0; e < n.length; e += 1) if (n.start(e) <= t + .1 && n.end(e) > t) {
@@ -1254,7 +1266,7 @@ function xt(e, t) {
1254
1266
  }
1255
1267
  return null;
1256
1268
  }
1257
- function St(e, t) {
1269
+ function Ct(e, t) {
1258
1270
  return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
1259
1271
  }
1260
1272
  //#endregion
@@ -1271,8 +1283,8 @@ function K(e, t = Date.now()) {
1271
1283
  }
1272
1284
  //#endregion
1273
1285
  //#region src/core/engine/prefetch.ts
1274
- var Ct = 15e3, wt = 5e3, Tt = 6;
1275
- function Et(e) {
1286
+ var wt = 15e3, Tt = 5e3, Et = 6;
1287
+ function Dt(e) {
1276
1288
  try {
1277
1289
  let t = new URL(e);
1278
1290
  return t.searchParams.delete("CMCD"), t.toString();
@@ -1280,7 +1292,7 @@ function Et(e) {
1280
1292
  return e;
1281
1293
  }
1282
1294
  }
1283
- var Dt = class {
1295
+ var Ot = class {
1284
1296
  cmcd;
1285
1297
  entries = /* @__PURE__ */ new Map();
1286
1298
  keyed = /* @__PURE__ */ new Set();
@@ -1303,10 +1315,10 @@ var Dt = class {
1303
1315
  }
1304
1316
  prefetch(e, t, n) {
1305
1317
  if (!this.isActive(t)) return;
1306
- let r = Et(e);
1318
+ let r = Dt(e);
1307
1319
  if (this.entries.has(r)) return;
1308
1320
  let i = this.perTrack.get(t) ?? 0;
1309
- if (i >= Tt) return;
1321
+ if (i >= Et) return;
1310
1322
  this.perTrack.set(t, i + 1);
1311
1323
  let a = new AbortController(), o = {
1312
1324
  started: performance.now(),
@@ -1320,10 +1332,10 @@ var Dt = class {
1320
1332
  signal: a.signal
1321
1333
  }).then(async (e) => (o.first = performance.now(), e.ok ? e.arrayBuffer() : null)).catch(() => null), this.entries.set(r, o), this.stats.started += 1, setTimeout(() => {
1322
1334
  this.entries.get(r) === o && (this.entries.delete(r), a.abort(), this.stats.expired += 1);
1323
- }, Ct);
1335
+ }, wt);
1324
1336
  }
1325
1337
  take(e) {
1326
- let t = Et(e), n = this.entries.get(t);
1338
+ let t = Dt(e), n = this.entries.get(t);
1327
1339
  return n && this.entries.delete(t), n;
1328
1340
  }
1329
1341
  destroy() {
@@ -1343,13 +1355,13 @@ var Dt = class {
1343
1355
  }
1344
1356
  }
1345
1357
  };
1346
- function Ot(t) {
1358
+ function kt(t) {
1347
1359
  let n = e.DefaultConfig?.loader;
1348
1360
  if (typeof n != "function") return;
1349
1361
  class r extends n {
1350
1362
  served = !1;
1351
1363
  cancelled = !1;
1352
- stats = kt();
1364
+ stats = At();
1353
1365
  load(e, n, r) {
1354
1366
  let i = e.rangeEnd ? void 0 : t.take(e.url);
1355
1367
  if (!i) {
@@ -1357,7 +1369,7 @@ function Ot(t) {
1357
1369
  return;
1358
1370
  }
1359
1371
  this.served = !0;
1360
- let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || wt, s = setTimeout(() => {
1372
+ let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || Tt, s = setTimeout(() => {
1361
1373
  !this.cancelled && this.served && (i.abort.abort(), t.stats.failed += 1, this.served = !1, super.load(e, n, r));
1362
1374
  }, o);
1363
1375
  i.bytes.then((o) => {
@@ -1384,7 +1396,7 @@ function Ot(t) {
1384
1396
  }
1385
1397
  return r;
1386
1398
  }
1387
- function kt() {
1399
+ function At() {
1388
1400
  return {
1389
1401
  aborted: !1,
1390
1402
  loaded: 0,
@@ -1408,10 +1420,10 @@ function kt() {
1408
1420
  }
1409
1421
  };
1410
1422
  }
1411
- function At(e) {
1423
+ function jt(e) {
1412
1424
  return e === "audio" ? "audio" : "main";
1413
1425
  }
1414
- function jt(e, t) {
1426
+ function Mt(e, t) {
1415
1427
  let n = [];
1416
1428
  t.initSegment?.url && !t.initSegment.data && n.push({
1417
1429
  url: t.initSegment.url,
@@ -1430,24 +1442,24 @@ function jt(e, t) {
1430
1442
  }
1431
1443
  //#endregion
1432
1444
  //#region src/core/engine/hls.ts
1433
- function Mt() {
1445
+ function Nt() {
1434
1446
  return e.isSupported();
1435
1447
  }
1436
- var Nt = 1e6, Pt = 20, Ft = 1e4, It = 3, Lt = 5, Rt = 3, zt = 1e4, Bt = 3e4, Vt = 12e3, Ht = 3e3, Ut = .02, Wt = 6e3, Gt = .5, Kt = 3, qt = .5, Jt = 1.1, Yt = .25, Xt = 5e3, Zt = 4e3, Qt = 2, $t = 5, en = 2, tn = 2, nn = 4, rn = 4, an = 2e3, on = 3e4, sn = .2, cn = 30, ln = 2, un = 2, dn = 9, fn = .5, pn = 64;
1437
- function mn(e) {
1448
+ var Pt = 1e6, Ft = 20, It = 1e4, Lt = 3, Rt = 5, zt = 3, Bt = 1e4, Vt = 3e4, Ht = 12e3, Ut = 3e3, Wt = .02, Gt = 6e3, Kt = .5, qt = 3, Jt = .5, Yt = 1.1, Xt = .25, Zt = 5e3, Qt = 4e3, $t = 2, en = 5, tn = 2, nn = 2, rn = 4, an = 4, on = 2e3, sn = 3e4, cn = .2, ln = 30, un = 2, dn = 2, fn = 9, pn = .5, mn = 64;
1449
+ function hn(e) {
1438
1450
  if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
1439
1451
  delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
1440
1452
  return;
1441
1453
  }
1442
- e.liveSyncDuration ??= un;
1443
- let t = Math.max(12, e.liveSyncDuration + dn);
1444
- (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), hn(e, e.liveSyncDuration);
1454
+ e.liveSyncDuration ??= dn;
1455
+ let t = Math.max(12, e.liveSyncDuration + fn);
1456
+ (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), gn(e, e.liveSyncDuration);
1445
1457
  }
1446
- function hn(e, t) {
1458
+ function gn(e, t) {
1447
1459
  let n = (e, t, n) => Math.min(n, Math.max(t, e));
1448
1460
  e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
1449
1461
  }
1450
- var gn = class {
1462
+ var _n = class {
1451
1463
  name = "hls";
1452
1464
  hls = null;
1453
1465
  deps;
@@ -1531,7 +1543,7 @@ var gn = class {
1531
1543
  frameCounter;
1532
1544
  detachFrames = null;
1533
1545
  constructor(e) {
1534
- this.deps = e, this.frameCounter = new st(e.video), this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
1546
+ this.deps = e, this.frameCounter = new ct(e.video), this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
1535
1547
  }
1536
1548
  async load() {
1537
1549
  this.detachFrames ??= this.frameCounter.attach();
@@ -1544,7 +1556,7 @@ var gn = class {
1544
1556
  });
1545
1557
  return;
1546
1558
  }
1547
- e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ue(r), qe()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1559
+ e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (He(r), Ke()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1548
1560
  let e = this.hls;
1549
1561
  if (document.visibilityState !== "visible" || !e) return;
1550
1562
  let t = e.liveSyncPosition;
@@ -1567,7 +1579,7 @@ var gn = class {
1567
1579
  }
1568
1580
  this.loadSuspended = !0;
1569
1581
  }
1570
- }, Xt));
1582
+ }, Zt));
1571
1583
  }
1572
1584
  resumeLoading() {
1573
1585
  if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
@@ -1599,7 +1611,7 @@ var gn = class {
1599
1611
  let t = e.liveSyncPosition;
1600
1612
  if (typeof t != "number" || !Number.isFinite(t)) return;
1601
1613
  let { video: n } = this.deps;
1602
- n.currentTime <= t + fn || (n.currentTime = t);
1614
+ n.currentTime <= t + pn || (n.currentTime = t);
1603
1615
  }
1604
1616
  reanchorPartTimeline(e, t) {
1605
1617
  let { frag: n, part: r } = t;
@@ -1611,7 +1623,7 @@ var gn = class {
1611
1623
  let o = n.sn, s = i.fragments.find((e) => e && e.sn === o) ?? (i.fragmentHint?.sn === o ? i.fragmentHint : void 0);
1612
1624
  if (!s) return;
1613
1625
  let c = a.startPTS - s.start;
1614
- if (!(!Number.isFinite(c) || Math.abs(c) < Ut)) {
1626
+ if (!(!Number.isFinite(c) || Math.abs(c) < Wt)) {
1615
1627
  for (let e of i.fragments) e && e.setStart(e.start + c);
1616
1628
  i.fragmentHint?.setStart(i.fragmentHint.start + c), this.deps.debug === !0 && console.info(`havik-player: LL-HLS timeline re-anchored by ${c >= 0 ? "+" : ""}${c.toFixed(3)}s at sn ${n.sn} (level ${n.level})`);
1617
1629
  }
@@ -1634,12 +1646,12 @@ var gn = class {
1634
1646
  emeEnabled: !0,
1635
1647
  drmSystems: { ...this.licenseUrl ? { "com.widevine.alpha": { licenseUrl: this.licenseUrl } } : {} },
1636
1648
  drmSystemOptions: {
1637
- videoRobustness: N.video,
1638
- audioRobustness: N.audio,
1639
- videoEncryptionScheme: N.scheme,
1640
- audioEncryptionScheme: N.scheme
1649
+ videoRobustness: F.video,
1650
+ audioRobustness: F.audio,
1651
+ videoEncryptionScheme: F.scheme,
1652
+ audioEncryptionScheme: F.scheme
1641
1653
  },
1642
- ...A() ? { requestMediaKeySystemAccessFunc: He(t) } : {},
1654
+ ...M() ? { requestMediaKeySystemAccessFunc: Ve(t) } : {},
1643
1655
  licenseXhrSetup: (e, t) => {
1644
1656
  let o = performance.now(), s = () => {
1645
1657
  e.open("POST", this.licenseUrl ?? t, !0), e.setRequestHeader("x-api-key", r.apiKey), e.setRequestHeader("X-Match-Urn", n.matchUrn), e.setRequestHeader("X-Device-Id", i), a && e.setRequestHeader("X-User-Id", a), this.licenseRequested = !0, e.addEventListener("loadend", () => {
@@ -1651,7 +1663,7 @@ var gn = class {
1651
1663
  return;
1652
1664
  }
1653
1665
  let l = this.hls, u, d = new Promise((e) => {
1654
- u = setTimeout(() => e(void 0), zt);
1666
+ u = setTimeout(() => e(void 0), Bt);
1655
1667
  });
1656
1668
  return Promise.race([c().catch(() => void 0), d]).finally(() => clearTimeout(u)).then((e) => {
1657
1669
  if (!this.hls || this.hls !== l) throw Error("havik-player: engine torn down during refresh");
@@ -1667,20 +1679,20 @@ var gn = class {
1667
1679
  ...c
1668
1680
  };
1669
1681
  if (this.prefetch?.destroy(), this.prefetch = null, u && this.deps.mediaDuringKey !== !1 && !f.fLoader) {
1670
- let e = new Dt({
1682
+ let e = new Ot({
1671
1683
  sessionId: n.analytics?.sid,
1672
1684
  contentId: n.matchUrn
1673
- }), t = Ot(e);
1685
+ }), t = kt(e);
1674
1686
  t && (this.prefetch = e, f.fLoader = t);
1675
1687
  }
1676
- mn(f), this.catchUpRate = typeof f.maxLiveSyncPlaybackRate == "number" ? f.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (f.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = f.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = f.autoStartLoad !== !1;
1688
+ hn(f), this.catchUpRate = typeof f.maxLiveSyncPlaybackRate == "number" ? f.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (f.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = f.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = f.autoStartLoad !== !1;
1677
1689
  let p = new e(f);
1678
1690
  if (this.hls = p, p.on(e.Events.FRAG_PARSED, (e, t) => this.reanchorPartTimeline(p, t)), p.on(e.Events.MANIFEST_PARSED, () => {
1679
1691
  this.mediaRecoveries = 0, this.networkRecoveries = 0, u && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && this.dropLevelsWidevineCannotPlay(p), this.measureLadder(p), this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
1680
1692
  }), p.on(e.Events.FRAG_BUFFERED, (e, t) => {
1681
1693
  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(() => {
1682
1694
  this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
1683
- }, Bt)));
1695
+ }, Vt)));
1684
1696
  }), p.on(e.Events.FRAG_LOADING, (e, t) => {
1685
1697
  t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
1686
1698
  }), p.on(e.Events.FRAG_LOADED, (e, t) => {
@@ -1688,10 +1700,10 @@ var gn = class {
1688
1700
  let n = t?.frag?.stats, r = n?.loaded;
1689
1701
  typeof r == "number" && (this.bytesLoaded += r), !this.reportedFirstBytes && typeof r == "number" && r > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
1690
1702
  let i = n?.loading;
1691
- 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 > pn && this.requestTimesMs.shift());
1703
+ 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 > mn && this.requestTimesMs.shift());
1692
1704
  let a = t?.frag?.url;
1693
1705
  if (a) {
1694
- let e = z(a);
1706
+ let e = at(a);
1695
1707
  e && (this.cdnHost = e);
1696
1708
  }
1697
1709
  }), p.on(e.Events.LEVEL_LOADED, (e, t) => {
@@ -1705,15 +1717,15 @@ var gn = class {
1705
1717
  }), p.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.prefetch) {
1706
1718
  let t = this.prefetch;
1707
1719
  p.on(e.Events.KEY_LOADING, (e, n) => {
1708
- let r = n?.frag, i = At(r?.type);
1709
- if (r && t.isActive(i)) for (let e of jt(p, r)) t.prefetch(e.url, i, e.kind);
1710
- }), p.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(At(n?.frag?.type)));
1720
+ let r = n?.frag, i = jt(r?.type);
1721
+ if (r && t.isActive(i)) for (let e of Mt(p, r)) t.prefetch(e.url, i, e.kind);
1722
+ }), p.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(jt(n?.frag?.type)));
1711
1723
  }
1712
1724
  p.on(e.Events.KEY_LOADED, () => {
1713
1725
  u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
1714
1726
  }), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
1715
1727
  this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.checkFrameDrops();
1716
- }, Ht), p.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1728
+ }, Ut), p.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1717
1729
  this.renditionSwitches += 1;
1718
1730
  let n = this.lastLevelIndex >= 0 ? p.levels[this.lastLevelIndex] : void 0, r = p.levels[t.level];
1719
1731
  n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, l({
@@ -1777,7 +1789,7 @@ var gn = class {
1777
1789
  return;
1778
1790
  }
1779
1791
  this.capTimer && clearTimeout(this.capTimer);
1780
- let t = e > this.sizeCapLevel ? an : on;
1792
+ let t = e > this.sizeCapLevel ? on : sn;
1781
1793
  this.capTimer = setTimeout(() => {
1782
1794
  this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
1783
1795
  }, t);
@@ -1787,9 +1799,9 @@ var gn = class {
1787
1799
  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;
1788
1800
  }
1789
1801
  dropLevelsWidevineCannotPlay(e) {
1790
- this.removeLevelsWhere(e, (e) => Je(e) !== !0);
1791
- let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && P(e) !== "avc" && !!P(e)));
1792
- for (let n of t) Ke(n).then((t) => {
1802
+ this.removeLevelsWhere(e, (e) => qe(e) !== !0);
1803
+ let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && I(e) !== "avc" && !!I(e)));
1804
+ for (let n of t) Ge(n).then((t) => {
1793
1805
  t || this.hls !== e || this.removeLevelsWhere(e, (e) => e === n) && (this.measureLadder(e), this.applySizeCap());
1794
1806
  });
1795
1807
  }
@@ -1797,10 +1809,10 @@ var gn = class {
1797
1809
  let n = e.levels ?? [], r = [], i = /* @__PURE__ */ new Set();
1798
1810
  if (n.forEach((e, n) => {
1799
1811
  let a = e.videoCodec;
1800
- a && P(a) && t(a) && (r.push(n), i.add(a));
1812
+ a && I(a) && t(a) && (r.push(n), i.add(a));
1801
1813
  }), !r.length) return !1;
1802
1814
  let a = [...i].join(", ");
1803
- if (!n.some((e, t) => r.includes(t) ? !1 : !P(e.videoCodec) || Je(e.videoCodec) === !0)) return console.warn(`havik-player: every rendition is ${a}, which Widevine may not play on this browser; keeping them`), !1;
1815
+ if (!n.some((e, t) => r.includes(t) ? !1 : !I(e.videoCodec) || qe(e.videoCodec) === !0)) return console.warn(`havik-player: every rendition is ${a}, which Widevine may not play on this browser; keeping them`), !1;
1804
1816
  for (let t = r.length - 1; t >= 0; --t) e.removeLevel(r[t]);
1805
1817
  return console.info(`havik-player: skipped ${r.length} rendition(s) Widevine cannot play on this browser (${a})`), !0;
1806
1818
  }
@@ -1906,7 +1918,7 @@ var gn = class {
1906
1918
  return;
1907
1919
  }
1908
1920
  let e = Date.now() - this.lastAdvanceMs;
1909
- !this.chaseSuspended && e > Wt && this.suspendChasing(), e > Vt && this.emitEnded("stalled");
1921
+ !this.chaseSuspended && e > Gt && this.suspendChasing(), e > Ht && this.emitEnded("stalled");
1910
1922
  }
1911
1923
  resetStarvationWindow() {
1912
1924
  this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
@@ -1921,7 +1933,7 @@ var gn = class {
1921
1933
  this.resetStarvationWindow();
1922
1934
  return;
1923
1935
  }
1924
- let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < Wt, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > Zt, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = B(t), c = o - s, l = c !== this.starvedFrames;
1936
+ let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < Gt, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > Qt, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = B(t), c = o - s, l = c !== this.starvedFrames;
1925
1937
  if (this.starvedFrames = c, !a || l) {
1926
1938
  (t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
1927
1939
  return;
@@ -1930,12 +1942,12 @@ var gn = class {
1930
1942
  this.resetStarvationWindow();
1931
1943
  return;
1932
1944
  }
1933
- 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 > nn && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= en && (this.clearKick(), this.starvationRebuilds < tn)) {
1945
+ 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 > rn && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= tn && (this.clearKick(), this.starvationRebuilds < nn)) {
1934
1946
  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");
1935
1947
  return;
1936
1948
  }
1937
- let u = i && this.starvedTicks >= Qt, d = !i && this.deadTicks >= nn && this.recentMainFrags.reduce((e, t) => e + t, 0) >= rn;
1938
- if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= $t))) {
1949
+ let u = i && this.starvedTicks >= $t, d = !i && this.deadTicks >= rn && this.recentMainFrags.reduce((e, t) => e + t, 0) >= an;
1950
+ if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= en))) {
1939
1951
  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");
1940
1952
  try {
1941
1953
  e.stopLoad(), e.startLoad(-1);
@@ -1950,7 +1962,7 @@ var gn = class {
1950
1962
  let t = e.latency, n = e.targetLatency;
1951
1963
  if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
1952
1964
  let r = t - n;
1953
- !this.catchUpEngaged && r > Gt ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= Gt && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
1965
+ !this.catchUpEngaged && r > Kt ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= Kt && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
1954
1966
  let i = this.catchUpEngaged ? this.catchUpRate : 1;
1955
1967
  e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
1956
1968
  }
@@ -1972,15 +1984,15 @@ var gn = class {
1972
1984
  return;
1973
1985
  }
1974
1986
  let { totalFrames: n, dropped: r } = B(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
1975
- if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < cn || o < 0) {
1987
+ if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < ln || o < 0) {
1976
1988
  this.fpsBadTicks = 0;
1977
1989
  return;
1978
1990
  }
1979
- if (o <= sn * a) {
1991
+ if (o <= cn * a) {
1980
1992
  this.fpsBadTicks = 0;
1981
1993
  return;
1982
1994
  }
1983
- if (this.fpsBadTicks += 1, this.fpsBadTicks < ln) return;
1995
+ if (this.fpsBadTicks += 1, this.fpsBadTicks < un) return;
1984
1996
  this.fpsBadTicks = 0;
1985
1997
  let s = e.levels, c = s[e.currentLevel];
1986
1998
  if (!c) return;
@@ -1997,20 +2009,20 @@ var gn = class {
1997
2009
  return;
1998
2010
  }
1999
2011
  let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
2000
- if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(Jt, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
2012
+ if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(Yt, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
2001
2013
  this.resetChaseWindow();
2002
2014
  return;
2003
2015
  }
2004
- if (this.chaseLatency < 0 || this.chaseLatency - n >= qt) {
2016
+ if (this.chaseLatency < 0 || this.chaseLatency - n >= Jt) {
2005
2017
  this.chaseLatency = n, this.chaseTicks = 0;
2006
2018
  return;
2007
2019
  }
2008
- if (this.chaseTicks += 1, this.chaseTicks < Kt) return;
2020
+ if (this.chaseTicks += 1, this.chaseTicks < qt) return;
2009
2021
  this.resetChaseWindow();
2010
2022
  let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
2011
2023
  if (!(a > 1)) return;
2012
2024
  let o = typeof e.targetLatency == "number" ? e.targetLatency : 0, s = Math.min(n, a - 1);
2013
- s < o + Yt || (console.warn(`havik-player: catch-up at ${r}x not gaining on the live edge (latency ${n.toFixed(1)}s); holding at ${s.toFixed(1)}s`), this.liveRetargets += 1, e.targetLatency = s);
2025
+ s < o + Xt || (console.warn(`havik-player: catch-up at ${r}x not gaining on the live edge (latency ${n.toFixed(1)}s); holding at ${s.toFixed(1)}s`), this.liveRetargets += 1, e.targetLatency = s);
2014
2026
  }
2015
2027
  suspendChasing() {
2016
2028
  let e = this.hls;
@@ -2040,14 +2052,14 @@ var gn = class {
2040
2052
  } catch {}
2041
2053
  }
2042
2054
  startEstimate() {
2043
- return this.deps.rememberBandwidth === !1 ? Nt : Ie() ?? Nt;
2055
+ return this.deps.rememberBandwidth === !1 ? Pt : Fe() ?? Pt;
2044
2056
  }
2045
2057
  maybeRememberBandwidth(e) {
2046
- if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded < Pt) return;
2058
+ if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded < Ft) return;
2047
2059
  let t = Date.now();
2048
- if (!e && t - this.bwSavedAt < Ft) return;
2060
+ if (!e && t - this.bwSavedAt < It) return;
2049
2061
  let n = this.hls?.bandwidthEstimate;
2050
- typeof n != "number" || !Number.isFinite(n) || n <= 0 || (this.bwSavedAt = t, Le(n));
2062
+ typeof n != "number" || !Number.isFinite(n) || n <= 0 || (this.bwSavedAt = t, Ie(n));
2051
2063
  }
2052
2064
  destroy() {
2053
2065
  if (this.maybeRememberBandwidth(!0), this.detachFrames?.(), this.detachFrames = null, this.prefetch?.destroy(), this.prefetch = null, this.clearRecoveryReset(), this.capTimer &&= (clearTimeout(this.capTimer), null), this.capObserver &&= (this.capObserver.disconnect(), null), this.unwatchDprChanges(), this.endWatchdog &&= (clearInterval(this.endWatchdog), null), this.onVisibility && typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), this.onVisibility = null), this.onSeeking &&= (this.deps.video.removeEventListener("seeking", this.onSeeking), null), this.onTimeUpdate &&= (this.deps.video.removeEventListener("timeupdate", this.onTimeUpdate), null), this.onPause &&= (this.deps.video.removeEventListener("pause", this.onPause), null), this.onPlay &&= (this.deps.video.removeEventListener("play", this.onPlay), null), this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null), this.licenseRetryTimer &&= (clearTimeout(this.licenseRetryTimer), null), this.hls) {
@@ -2065,7 +2077,7 @@ var gn = class {
2065
2077
  scheduleLicenseRetry(t) {
2066
2078
  if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
2067
2079
  let n = t.response?.code ?? 0;
2068
- if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= Rt) return !1;
2080
+ if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= zt) return !1;
2069
2081
  this.licenseRecoveries += 1;
2070
2082
  let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
2071
2083
  return this.licenseRetryTimer = setTimeout(() => {
@@ -2097,7 +2109,7 @@ var gn = class {
2097
2109
  return;
2098
2110
  }
2099
2111
  if (t.type === e.ErrorTypes.NETWORK_ERROR) {
2100
- if (this.networkRecoveries < Lt) {
2112
+ if (this.networkRecoveries < Rt) {
2101
2113
  this.networkRecoveries += 1;
2102
2114
  let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
2103
2115
  this.networkRetryTimer = setTimeout(() => {
@@ -2114,7 +2126,7 @@ var gn = class {
2114
2126
  return;
2115
2127
  }
2116
2128
  if (t.type === e.ErrorTypes.MEDIA_ERROR) {
2117
- if (this.mediaRecoveries < It) {
2129
+ if (this.mediaRecoveries < Lt) {
2118
2130
  this.mediaRecoveries += 1, n.recoverMediaError();
2119
2131
  return;
2120
2132
  }
@@ -2138,21 +2150,22 @@ var gn = class {
2138
2150
  let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
2139
2151
  return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
2140
2152
  }
2141
- }, _n = 15e3, vn = 6e5, yn = 3e5, bn = 100, q = 1, xn = 1e3, Sn = 3e4, Cn = 1e3, wn = {
2153
+ }, vn = 15e3, yn = 6e5, bn = 3e5, xn = 100, q = 1, Sn = 1e3, Cn = 3e4, wn = 1e3, Tn = {
2142
2154
  inline: "PRESENTATION_INLINE",
2143
2155
  fullscreen: "PRESENTATION_FULLSCREEN",
2144
2156
  pip: "PRESENTATION_PIP"
2145
- }, Tn = {
2157
+ }, En = {
2146
2158
  widevine: "KEY_SYSTEM_WIDEVINE",
2147
2159
  fairplay: "KEY_SYSTEM_FAIRPLAY",
2148
2160
  none: "KEY_SYSTEM_NONE"
2149
2161
  };
2150
- function En(e, t) {
2162
+ function Dn(e, t) {
2151
2163
  return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
2152
2164
  }
2153
- var Dn = /* @__PURE__ */ new Set([
2165
+ var On = /* @__PURE__ */ new Set([
2154
2166
  "INVALID_URN",
2155
2167
  "NOT_FOUND",
2168
+ "GEO_DENIED",
2156
2169
  "GONE",
2157
2170
  "TOO_EARLY",
2158
2171
  "UNAVAILABLE",
@@ -2170,7 +2183,7 @@ var Dn = /* @__PURE__ */ new Set([
2170
2183
  ended: "PLAYER_STATE_ENDED",
2171
2184
  error: "PLAYER_STATE_ERROR"
2172
2185
  };
2173
- function On(e) {
2186
+ function kn(e) {
2174
2187
  try {
2175
2188
  let t = new URL(e), [n, ...r] = t.hostname.split(".");
2176
2189
  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);
@@ -2178,8 +2191,8 @@ function On(e) {
2178
2191
  return;
2179
2192
  }
2180
2193
  }
2181
- var kn = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), An = /* @__PURE__ */ new Set(), Y = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), jn = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
2182
- function Mn(e) {
2194
+ var An = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), jn = /* @__PURE__ */ new Set(), Y = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), Mn = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
2195
+ function Nn(e) {
2183
2196
  if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
2184
2197
  let t;
2185
2198
  try {
@@ -2188,19 +2201,19 @@ function Mn(e) {
2188
2201
  } catch {
2189
2202
  return;
2190
2203
  }
2191
- if (An.has(t) && !Y.has(t)) {
2192
- Y.add(t), g(jn(new URL(t).origin));
2204
+ if (jn.has(t) && !Y.has(t)) {
2205
+ Y.add(t), g(Mn(new URL(t).origin));
2193
2206
  for (let e of X) e.noteCspBlocked();
2194
2207
  }
2195
2208
  }
2196
- function Nn(e, t) {
2209
+ function Pn(e, t) {
2197
2210
  return g(t, e), { disabledReason: t };
2198
2211
  }
2199
- function Pn(e, t, n) {
2200
- if (n) return t && !kn(t, n) && g(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
2212
+ function Fn(e, t, n) {
2213
+ if (n) return t && !An(t, n) && g(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
2201
2214
  if (t) return { endpoint: t };
2202
- if (t !== void 0) return Nn("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).");
2203
- let r = On(e);
2215
+ if (t !== void 0) return Pn("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).");
2216
+ let r = kn(e);
2204
2217
  if (r) return { endpoint: r };
2205
2218
  let i;
2206
2219
  try {
@@ -2208,9 +2221,9 @@ function Pn(e, t, n) {
2208
2221
  } catch {
2209
2222
  i = e;
2210
2223
  }
2211
- return Nn(i, `analytics is disabled: no QoE beacons will be sent. The beacons endpoint cannot be derived from the baseUrl host "${i}" — the convention is feed[-dev].<domain> → beacons[-dev].<domain>. Pass an explicit endpoint, analytics: { endpoint: 'https://beacons[-dev].<domain>' }, to createPlayer (or analytics: false to opt out deliberately).`);
2224
+ return Pn(i, `analytics is disabled: no QoE beacons will be sent. The beacons endpoint cannot be derived from the baseUrl host "${i}" — the convention is feed[-dev].<domain> → beacons[-dev].<domain>. Pass an explicit endpoint, analytics: { endpoint: 'https://beacons[-dev].<domain>' }, to createPlayer (or analytics: false to opt out deliberately).`);
2212
2225
  }
2213
- var Fn = class {
2226
+ var In = class {
2214
2227
  opts;
2215
2228
  url;
2216
2229
  cspKey;
@@ -2292,8 +2305,8 @@ var Fn = class {
2292
2305
  constructor(e) {
2293
2306
  this.opts = {
2294
2307
  ...e,
2295
- heartbeatMs: e.heartbeatMs ?? _n,
2296
- idleMs: e.idleMs ?? vn
2308
+ heartbeatMs: e.heartbeatMs ?? vn,
2309
+ idleMs: e.idleMs ?? yn
2297
2310
  }, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
2298
2311
  try {
2299
2312
  let e = new URL(this.url);
@@ -2310,11 +2323,11 @@ var Fn = class {
2310
2323
  sdkVersion: this.opts.sdkVersion,
2311
2324
  ...this.opts.environment
2312
2325
  };
2313
- this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), xn), this.lastTickMs = this.now(), this.timer = setInterval(() => this.heartbeat(), this.opts.heartbeatMs), typeof window < "u" && window.addEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.addEventListener("visibilitychange", this.onVisibility), document.addEventListener("freeze", this.onFreeze), document.addEventListener("resume", this.onResume), this.cspKey && An.add(this.cspKey), document.addEventListener("securitypolicyviolation", Mn), X.add(this), this.noteCspBlocked(), this.onVisibility());
2326
+ this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Sn), this.lastTickMs = this.now(), this.timer = setInterval(() => this.heartbeat(), this.opts.heartbeatMs), typeof window < "u" && window.addEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.addEventListener("visibilitychange", this.onVisibility), document.addEventListener("freeze", this.onFreeze), document.addEventListener("resume", this.onResume), this.cspKey && jn.add(this.cspKey), document.addEventListener("securitypolicyviolation", Nn), X.add(this), this.noteCspBlocked(), this.onVisibility());
2314
2327
  }
2315
2328
  checkSuspension(e) {
2316
2329
  if (this.endedFlag || !this.opts.idleMs) return !1;
2317
- let t = Math.max(this.opts.idleMs, yn);
2330
+ let t = Math.max(this.opts.idleMs, bn);
2318
2331
  return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
2319
2332
  }
2320
2333
  syncIdle(e) {
@@ -2337,12 +2350,12 @@ var Fn = class {
2337
2350
  let a = {
2338
2351
  fromState: J[e] ?? "PLAYER_STATE_UNSPECIFIED",
2339
2352
  toState: J[t] ?? "PLAYER_STATE_UNSPECIFIED",
2340
- presentation: wn[this.presentation]
2353
+ presentation: Tn[this.presentation]
2341
2354
  }, o = this.causeOf(e, t, i);
2342
2355
  o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
2343
2356
  }
2344
2357
  seekInduced(e) {
2345
- return this.lastSeekMs >= 0 && e - this.lastSeekMs < Cn;
2358
+ return this.lastSeekMs >= 0 && e - this.lastSeekMs < wn;
2346
2359
  }
2347
2360
  causeOf(e, t, n) {
2348
2361
  if (t === "error") return "TRANSITION_CAUSE_ERROR";
@@ -2416,7 +2429,7 @@ var Fn = class {
2416
2429
  let r = n ?? "";
2417
2430
  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";
2418
2431
  if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
2419
- if (Dn.has(e)) return "ERROR_STAGE_RESOLVE";
2432
+ if (On.has(e)) return "ERROR_STAGE_RESOLVE";
2420
2433
  let i = t ?? "";
2421
2434
  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";
2422
2435
  }
@@ -2463,14 +2476,14 @@ var Fn = class {
2463
2476
  if (this.lastRequestCount = g, _ > 0) {
2464
2477
  o.requestCountDelta = _;
2465
2478
  let e = t.requestTimesMs ?? [], n = e.slice(Math.max(0, e.length - _)).sort((e, t) => e - t);
2466
- n.length > 0 && (o.requestTimeP50Ms = En(n, 50), o.requestTimeP95Ms = En(n, 95));
2479
+ n.length > 0 && (o.requestTimeP50Ms = Dn(n, 50), o.requestTimeP95Ms = Dn(n, 95));
2467
2480
  }
2468
2481
  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();
2469
2482
  }
2470
2483
  maybeEmitMediaInfo(e) {
2471
2484
  if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
2472
2485
  let t = {};
2473
- e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = Tn[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);
2486
+ e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = En[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);
2474
2487
  let n = JSON.stringify(t);
2475
2488
  n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
2476
2489
  }
@@ -2490,7 +2503,7 @@ var Fn = class {
2490
2503
  let c = r?.positionMs ?? 0;
2491
2504
  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));
2492
2505
  let l = e !== "END_REASON_ENDED";
2493
- l && this.lastStallMs > 0 && n - this.lastStallMs <= Sn && (i.abandonAfterStallMs = Math.max(q, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= Sn && (i.abandonAfterErrorMs = Math.max(q, Math.round(n - this.lastErrorMs))), this.fullscreenTotalMs > 0 && (i.fullscreenTimeMs = Math.round(this.fullscreenTotalMs)), this.pipTotalMs > 0 && (i.pipTimeMs = Math.round(this.pipTotalMs)), this.volumeChanges > 0 && (i.volumeChanges = this.volumeChanges), this.muteChanges > 0 && (i.muteChanges = this.muteChanges);
2506
+ l && this.lastStallMs > 0 && n - this.lastStallMs <= Cn && (i.abandonAfterStallMs = Math.max(q, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= Cn && (i.abandonAfterErrorMs = Math.max(q, Math.round(n - this.lastErrorMs))), this.fullscreenTotalMs > 0 && (i.fullscreenTimeMs = Math.round(this.fullscreenTotalMs)), this.pipTotalMs > 0 && (i.pipTimeMs = Math.round(this.pipTotalMs)), this.volumeChanges > 0 && (i.volumeChanges = this.volumeChanges), this.muteChanges > 0 && (i.muteChanges = this.muteChanges);
2494
2507
  let u = r?.decodedFrames ?? this.lastDecoded;
2495
2508
  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");
2496
2509
  }
@@ -2510,13 +2523,13 @@ var Fn = class {
2510
2523
  };
2511
2524
  }
2512
2525
  noteCspBlocked() {
2513
- this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(jn(new URL(this.url).origin)));
2526
+ this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(Mn(new URL(this.url).origin)));
2514
2527
  }
2515
2528
  cspBlocked() {
2516
2529
  return !!this.cspKey && Y.has(this.cspKey);
2517
2530
  }
2518
2531
  enqueue(e) {
2519
- if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > bn;) {
2532
+ if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > xn;) {
2520
2533
  let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
2521
2534
  this.pending.splice(e >= 0 ? e : 0, 1);
2522
2535
  }
@@ -2543,7 +2556,7 @@ var Fn = class {
2543
2556
  };
2544
2557
  //#endregion
2545
2558
  //#region src/core/environment.ts
2546
- function In() {
2559
+ function Ln() {
2547
2560
  if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
2548
2561
  let e;
2549
2562
  try {
@@ -2568,14 +2581,14 @@ function In() {
2568
2581
  integration: "INTEGRATION_KIND_IFRAME"
2569
2582
  };
2570
2583
  }
2571
- function Ln() {
2584
+ function Rn() {
2572
2585
  if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
2573
2586
  let e = navigator.userAgentData, t = e?.platform ?? "";
2574
2587
  if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
2575
2588
  let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
2576
2589
  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";
2577
2590
  }
2578
- function Rn() {
2591
+ function zn() {
2579
2592
  let e = typeof navigator < "u" ? navigator.connection : void 0;
2580
2593
  if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
2581
2594
  let t = {
@@ -2594,17 +2607,17 @@ function Rn() {
2594
2607
  }
2595
2608
  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;
2596
2609
  }
2597
- function zn(e) {
2598
- let t = In(), n = {
2599
- deviceClass: Ln(),
2610
+ function Bn(e) {
2611
+ let t = Ln(), n = {
2612
+ deviceClass: Rn(),
2600
2613
  integration: t.integration,
2601
- ...Rn()
2614
+ ...zn()
2602
2615
  };
2603
2616
  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);
2604
2617
  let r = e.getBoundingClientRect?.();
2605
2618
  return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
2606
2619
  }
2607
- async function Bn() {
2620
+ async function Vn() {
2608
2621
  let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
2609
2622
  if (!e?.getHighEntropyValues) return {};
2610
2623
  try {
@@ -2616,7 +2629,7 @@ async function Bn() {
2616
2629
  }
2617
2630
  //#endregion
2618
2631
  //#region src/core/version.ts
2619
- var Vn = "2.18.0", Hn = {
2632
+ var Hn = "2.20.0", Un = {
2620
2633
  accent: "#E1B600",
2621
2634
  accentText: "#1B1C23",
2622
2635
  background: "#0e0f13",
@@ -2627,7 +2640,7 @@ var Vn = "2.18.0", Hn = {
2627
2640
  border: "rgba(255, 255, 255, 0.1)",
2628
2641
  radius: "8px",
2629
2642
  fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
2630
- }, Un = {
2643
+ }, Wn = {
2631
2644
  accent: "--havik-accent",
2632
2645
  accentText: "--havik-accent-text",
2633
2646
  background: "--havik-bg",
@@ -2639,26 +2652,26 @@ var Vn = "2.18.0", Hn = {
2639
2652
  radius: "--havik-radius",
2640
2653
  fontFamily: "--havik-font"
2641
2654
  };
2642
- function Wn(e, t) {
2655
+ function Gn(e, t) {
2643
2656
  let n = {
2644
- ...Hn,
2657
+ ...Un,
2645
2658
  ...t
2646
2659
  };
2647
- for (let t of Object.keys(Un)) e.style.setProperty(Un[t], n[t]);
2660
+ for (let t of Object.keys(Wn)) e.style.setProperty(Wn[t], n[t]);
2648
2661
  n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
2649
2662
  }
2650
2663
  //#endregion
2651
2664
  //#region src/ui/styles.ts
2652
- var Gn = "havik-player-styles", Kn = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer;\n touch-action:manipulation}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n/* Absolutely centred, NOT a flex sibling of .havik-center: the hidden center\n button (.havik-gone) still occupies its 74px in the row, which pushed an\n in-flow spinner 37px right of centre. */\n.havik-spinner{position:absolute;inset:0;margin:auto;width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n/* A status card carries its own logo — the corner watermark would duplicate it. */\n.havik-player.havik-has-status .havik-watermark{display:none}\n\n.havik-bar{position:absolute;left:0;right:0;bottom:0;padding:0 12px 8px;\n opacity:1;transition:opacity .25s;z-index:2}\n.havik-seek{position:relative;height:16px;display:flex;align-items:center;cursor:pointer;margin-bottom:2px}\n.havik-seek__track{position:relative;width:100%;height:4px;border-radius:3px;background:rgba(255,255,255,.25)}\n.havik-seek__buffered{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:rgba(255,255,255,.4)}\n.havik-seek__played{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-seek__thumb{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;\n background:var(--havik-accent,#E1B600);transform:translate(-50%,-50%) scale(0);transition:transform .1s}\n.havik-seek:hover .havik-seek__thumb{transform:translate(-50%,-50%) scale(1)}\n\n.havik-controls{display:flex;align-items:center;gap:6px;height:40px}\n.havik-spacer{flex:1}\n.havik-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;border-radius:var(--havik-radius,8px);\n padding:0;transition:background .12s,color .12s}\n.havik-btn:hover{background:rgba(255,255,255,.12)}\n.havik-btn:focus-visible{outline:2px solid var(--havik-accent,#E1B600);outline-offset:1px}\n.havik-btn svg{width:22px;height:22px}\n\n/* The volume level is filled in accent up to the thumb, like the seek bar's\n played span — a native range input paints no \"elapsed\" side, which left the\n level readable only from the dot's position. --havik-vol (0..1) is set by\n syncVolume(); the track width and thumb size live here as variables because\n the WebKit fill has to compute the thumb centre from both. */\n.havik-vol{display:flex;align-items:center}\n.havik-vol__slider{--havik-vol-w:70px;--havik-vol-thumb:12px;--havik-vol:1;\n --havik-vol-pos:calc(var(--havik-vol-thumb) / 2 + var(--havik-vol) * (var(--havik-vol-w) - var(--havik-vol-thumb)));\n width:0;opacity:0;transition:width .18s,opacity .18s;height:4px;cursor:pointer;\n appearance:none;-webkit-appearance:none;background:transparent;border-radius:3px;margin:0 4px}\n.havik-vol:hover .havik-vol__slider,.havik-vol:focus-within .havik-vol__slider{width:var(--havik-vol-w);opacity:1}\n/* WebKit/Blink have no progress pseudo-element: paint the fill as a hard-stop\n gradient that ends at the thumb centre. */\n.havik-vol__slider::-webkit-slider-runnable-track{height:4px;border-radius:3px;\n background:linear-gradient(to right,var(--havik-accent,#E1B600) var(--havik-vol-pos),\n rgba(255,255,255,.3) var(--havik-vol-pos))}\n/* Firefox fills natively, and tracks the thumb exactly. */\n.havik-vol__slider::-moz-range-track{height:4px;border-radius:3px;background:rgba(255,255,255,.3)}\n.havik-vol__slider::-moz-range-progress{height:4px;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-vol__slider::-webkit-slider-thumb{-webkit-appearance:none;width:var(--havik-vol-thumb);\n height:var(--havik-vol-thumb);border-radius:50%;background:var(--havik-accent,#E1B600);\n margin-top:calc((4px - var(--havik-vol-thumb)) / 2)}\n.havik-vol__slider::-moz-range-thumb{width:var(--havik-vol-thumb);height:var(--havik-vol-thumb);\n border:0;border-radius:50%;background:var(--havik-accent,#E1B600)}\n\n.havik-time{font-size:12px;color:var(--havik-text-muted,#9aa0ad);\n font-variant-numeric:tabular-nums;padding:0 6px;white-space:nowrap}\n.havik-live{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;\n letter-spacing:.4px;padding:0 8px;color:var(--havik-text,#fff)}\n.havik-live svg{width:9px;height:9px;color:var(--havik-text-muted,#9aa0ad)}\n.havik-live.is-live svg{color:var(--havik-accent,#E1B600)}\n.havik-live__go{margin-left:2px;border:0;cursor:pointer;background:transparent;color:var(--havik-text-muted,#9aa0ad);\n font:inherit;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:6px}\n.havik-live.is-live .havik-live__go{display:none}\n.havik-live__go:hover{color:var(--havik-accent,#E1B600)}\n\n.havik-menu{position:absolute;bottom:54px;right:12px;min-width:170px;max-height:230px;overflow:auto;\n background:var(--havik-surface,#1B1C23);border:1px solid var(--havik-border,rgba(255,255,255,.1));\n border-radius:var(--havik-radius,8px);box-shadow:0 10px 30px rgba(0,0,0,.5);padding:6px;z-index:3}\n.havik-menu[hidden]{display:none}\n.havik-menu__title{font-size:11px;text-transform:uppercase;letter-spacing:.6px;\n color:var(--havik-text-muted,#9aa0ad);padding:6px 8px 4px}\n.havik-menu__item{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;font:inherit;font-size:13px;\n text-align:left;padding:7px 8px;border-radius:6px}\n.havik-menu__item:hover{background:var(--havik-surface-muted,#2a2c36)}\n.havik-menu__item[aria-checked=\"true\"]{color:var(--havik-accent,#E1B600);font-weight:600}\n.havik-menu__item[aria-checked=\"true\"]::after{content:'✓'}\n", Z = /* @__PURE__ */ new WeakMap();
2653
- function qn(e = document, t) {
2654
- let n = e.querySelector(`style#${Gn}`);
2655
- if (n && (!t || Z.get(n) === t)) return;
2665
+ var Z = "havik-player-styles", Kn = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer;\n touch-action:manipulation}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n/* Absolutely centred, NOT a flex sibling of .havik-center: the hidden center\n button (.havik-gone) still occupies its 74px in the row, which pushed an\n in-flow spinner 37px right of centre. */\n.havik-spinner{position:absolute;inset:0;margin:auto;width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n/* A status card carries its own logo — the corner watermark would duplicate it. */\n.havik-player.havik-has-status .havik-watermark{display:none}\n\n.havik-bar{position:absolute;left:0;right:0;bottom:0;padding:0 12px 8px;\n opacity:1;transition:opacity .25s;z-index:2}\n.havik-seek{position:relative;height:16px;display:flex;align-items:center;cursor:pointer;margin-bottom:2px}\n.havik-seek__track{position:relative;width:100%;height:4px;border-radius:3px;background:rgba(255,255,255,.25)}\n.havik-seek__buffered{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:rgba(255,255,255,.4)}\n.havik-seek__played{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-seek__thumb{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;\n background:var(--havik-accent,#E1B600);transform:translate(-50%,-50%) scale(0);transition:transform .1s}\n.havik-seek:hover .havik-seek__thumb{transform:translate(-50%,-50%) scale(1)}\n\n.havik-controls{display:flex;align-items:center;gap:6px;height:40px}\n.havik-spacer{flex:1}\n.havik-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;border-radius:var(--havik-radius,8px);\n padding:0;transition:background .12s,color .12s}\n.havik-btn:hover{background:rgba(255,255,255,.12)}\n.havik-btn:focus-visible{outline:2px solid var(--havik-accent,#E1B600);outline-offset:1px}\n.havik-btn svg{width:22px;height:22px}\n\n/* The volume level is filled in accent up to the thumb, like the seek bar's\n played span — a native range input paints no \"elapsed\" side, which left the\n level readable only from the dot's position. --havik-vol (0..1) is set by\n syncVolume(); the track width and thumb size live here as variables because\n the WebKit fill has to compute the thumb centre from both. */\n.havik-vol{display:flex;align-items:center}\n.havik-vol__slider{--havik-vol-w:70px;--havik-vol-thumb:12px;--havik-vol:1;\n --havik-vol-pos:calc(var(--havik-vol-thumb) / 2 + var(--havik-vol) * (var(--havik-vol-w) - var(--havik-vol-thumb)));\n width:0;opacity:0;transition:width .18s,opacity .18s;height:4px;cursor:pointer;\n appearance:none;-webkit-appearance:none;background:transparent;border-radius:3px;margin:0 4px}\n.havik-vol:hover .havik-vol__slider,.havik-vol:focus-within .havik-vol__slider{width:var(--havik-vol-w);opacity:1}\n/* WebKit/Blink have no progress pseudo-element: paint the fill as a hard-stop\n gradient that ends at the thumb centre. */\n.havik-vol__slider::-webkit-slider-runnable-track{height:4px;border-radius:3px;\n background:linear-gradient(to right,var(--havik-accent,#E1B600) var(--havik-vol-pos),\n rgba(255,255,255,.3) var(--havik-vol-pos))}\n/* Firefox fills natively, and tracks the thumb exactly. */\n.havik-vol__slider::-moz-range-track{height:4px;border-radius:3px;background:rgba(255,255,255,.3)}\n.havik-vol__slider::-moz-range-progress{height:4px;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-vol__slider::-webkit-slider-thumb{-webkit-appearance:none;width:var(--havik-vol-thumb);\n height:var(--havik-vol-thumb);border-radius:50%;background:var(--havik-accent,#E1B600);\n margin-top:calc((4px - var(--havik-vol-thumb)) / 2)}\n.havik-vol__slider::-moz-range-thumb{width:var(--havik-vol-thumb);height:var(--havik-vol-thumb);\n border:0;border-radius:50%;background:var(--havik-accent,#E1B600)}\n\n.havik-time{font-size:12px;color:var(--havik-text-muted,#9aa0ad);\n font-variant-numeric:tabular-nums;padding:0 6px;white-space:nowrap}\n.havik-live{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;\n letter-spacing:.4px;padding:0 8px;color:var(--havik-text,#fff)}\n.havik-live svg{width:9px;height:9px;color:var(--havik-text-muted,#9aa0ad)}\n.havik-live.is-live svg{color:var(--havik-accent,#E1B600)}\n.havik-live__go{margin-left:2px;border:0;cursor:pointer;background:transparent;color:var(--havik-text-muted,#9aa0ad);\n font:inherit;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:6px}\n.havik-live.is-live .havik-live__go{display:none}\n.havik-live__go:hover{color:var(--havik-accent,#E1B600)}\n\n.havik-menu{position:absolute;bottom:54px;right:12px;min-width:170px;max-height:230px;overflow:auto;\n background:var(--havik-surface,#1B1C23);border:1px solid var(--havik-border,rgba(255,255,255,.1));\n border-radius:var(--havik-radius,8px);box-shadow:0 10px 30px rgba(0,0,0,.5);padding:6px;z-index:3}\n.havik-menu[hidden]{display:none}\n.havik-menu__title{font-size:11px;text-transform:uppercase;letter-spacing:.6px;\n color:var(--havik-text-muted,#9aa0ad);padding:6px 8px 4px}\n.havik-menu__item{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;font:inherit;font-size:13px;\n text-align:left;padding:7px 8px;border-radius:6px}\n.havik-menu__item:hover{background:var(--havik-surface-muted,#2a2c36)}\n.havik-menu__item[aria-checked=\"true\"]{color:var(--havik-accent,#E1B600);font-weight:600}\n.havik-menu__item[aria-checked=\"true\"]::after{content:'✓'}\n", qn = /* @__PURE__ */ new WeakMap();
2666
+ function Jn(e = document, t) {
2667
+ let n = e.querySelector(`style#${Z}`);
2668
+ if (n && (!t || qn.get(n) === t)) return;
2656
2669
  let r = e.createElement("style");
2657
- r.id = Gn, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = Kn, Z.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
2670
+ r.id = Z, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = Kn, qn.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
2658
2671
  }
2659
2672
  //#endregion
2660
2673
  //#region src/ui/icons.ts
2661
- var Jn = {
2674
+ var Yn = {
2662
2675
  play: "<path d=\"M8 5v14l11-7z\"/>",
2663
2676
  pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
2664
2677
  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\"/>",
@@ -2672,20 +2685,25 @@ var Jn = {
2672
2685
  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\"/>"
2673
2686
  };
2674
2687
  function Q(e) {
2675
- return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Jn[e]}</svg>`;
2688
+ return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Yn[e]}</svg>`;
2676
2689
  }
2677
2690
  //#endregion
2678
2691
  //#region src/ui/controls.ts
2679
- var Yn = 3e3, Xn = 250, Zn = /* @__PURE__ */ new Set([
2692
+ var Xn = 3e3, Zn = 250, Qn = /* @__PURE__ */ new Set([
2680
2693
  "GONE",
2681
2694
  "NOT_FOUND",
2695
+ "GEO_DENIED",
2682
2696
  "INVALID_URN",
2683
2697
  "UNAUTHORIZED"
2684
2698
  ]);
2685
- function Qn(e) {
2686
- return new $n(e);
2699
+ function $n(e) {
2700
+ let t = "This match isn't available in your country";
2701
+ return e ? `${t} (${e})` : t;
2687
2702
  }
2688
- var $n = class {
2703
+ function er(e) {
2704
+ return new tr(e);
2705
+ }
2706
+ var tr = class {
2689
2707
  root;
2690
2708
  video;
2691
2709
  player;
@@ -2716,6 +2734,7 @@ var $n = class {
2716
2734
  statusKind = null;
2717
2735
  statusMsg = null;
2718
2736
  hasPlayed = !1;
2737
+ fsSupported = !0;
2719
2738
  lastError = null;
2720
2739
  logoUrl;
2721
2740
  statusOverlays;
@@ -2732,7 +2751,7 @@ var $n = class {
2732
2751
  scrubbing = !1;
2733
2752
  offFns = [];
2734
2753
  constructor(e) {
2735
- this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Yn, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.streamEnded = e.streamEnded ?? (() => !1), this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, qn(this.doc, e.cspNonce), this.root.classList.add("havik-player"), this.root.hasAttribute("tabindex") || (this.root.tabIndex = 0), this.root.setAttribute("role", "region"), this.root.setAttribute("aria-label", "Video player");
2754
+ this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Xn, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.streamEnded = e.streamEnded ?? (() => !1), this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, Jn(this.doc, e.cspNonce), this.root.classList.add("havik-player"), this.root.hasAttribute("tabindex") || (this.root.tabIndex = 0), this.root.setAttribute("role", "region"), this.root.setAttribute("aria-label", "Video player");
2736
2755
  let t = (e, t, n) => {
2737
2756
  let r = this.doc.createElement(e);
2738
2757
  if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
@@ -2770,7 +2789,7 @@ var $n = class {
2770
2789
  let o = this.doc.createElement("span");
2771
2790
  o.textContent = "LIVE", this.liveGo = t("button", "havik-live__go", { type: "button" }), this.liveGo.textContent = "Go live", this.live.append(o, this.liveGo), this.time = t("div", "havik-time"), this.time.textContent = "0:00", this.time.style.display = "none";
2772
2791
  let s = t("div", "havik-spacer");
2773
- if (this.ccBtn = n("havik-btn", "cc", "Subtitles"), this.audioBtn = n("havik-btn", "settings", "Audio track"), this.qualityBtn = n("havik-btn", "settings", "Quality"), this.pipBtn = n("havik-btn", "pip", "Picture in picture"), this.fsBtn = n("havik-btn", "fullscreen", "Fullscreen"), this.ccBtn.style.display = "none", this.audioBtn.style.display = "none", this.qualityBtn.style.display = "none", this.pipSupported() || (this.pipBtn.style.display = "none"), i.append(this.playBtn, a, this.live, this.time, s, this.ccBtn, this.audioBtn, this.qualityBtn, this.pipBtn, this.fsBtn), this.bar.append(this.seek, i), this.menu = t("div", "havik-menu", { role: "menu" }), this.menu.hidden = !0, this.root.append(this.gradient, this.overlay, this.bar, this.menu), e.logoUrl) {
2792
+ if (this.ccBtn = n("havik-btn", "cc", "Subtitles"), this.audioBtn = n("havik-btn", "settings", "Audio track"), this.qualityBtn = n("havik-btn", "settings", "Quality"), this.pipBtn = n("havik-btn", "pip", "Picture in picture"), this.fsBtn = n("havik-btn", "fullscreen", "Fullscreen"), this.ccBtn.style.display = "none", this.audioBtn.style.display = "none", this.qualityBtn.style.display = "none", this.pipSupported() || (this.pipBtn.style.display = "none"), this.syncFullscreenSupport(), i.append(this.playBtn, a, this.live, this.time, s, this.ccBtn, this.audioBtn, this.qualityBtn, this.pipBtn, this.fsBtn), this.bar.append(this.seek, i), this.menu = t("div", "havik-menu", { role: "menu" }), this.menu.hidden = !0, this.root.append(this.gradient, this.overlay, this.bar, this.menu), e.logoUrl) {
2774
2793
  let n = t("div", "havik-watermark");
2775
2794
  n.style.backgroundImage = `url("${e.logoUrl}")`, this.root.append(n);
2776
2795
  }
@@ -2788,7 +2807,7 @@ var $n = class {
2788
2807
  }), this.on(this.muteBtn, "click", () => this.player.setMuted(!e.muted)), this.on(this.volSlider, "input", () => {
2789
2808
  let t = Number(this.volSlider.value);
2790
2809
  this.setVolumeFill(t), this.player.setVolume(t), t > 0 && e.muted && this.player.setMuted(!1);
2791
- }), this.on(this.liveGo, "click", () => this.player.seekToLive()), this.on(this.pipBtn, "click", () => void this.togglePip()), this.on(this.fsBtn, "click", () => void this.toggleFullscreen()), this.on(this.ccBtn, "click", () => this.toggleMenu("cc")), this.on(this.audioBtn, "click", () => this.toggleMenu("audio")), this.on(this.qualityBtn, "click", () => this.toggleMenu("quality")), this.on(this.seek, "pointerdown", (e) => this.onSeekDown(e)), this.on(this.seek, "keydown", (e) => this.onSeekKey(e)), this.on(e, "play", () => this.syncPlayPause()), this.on(e, "pause", () => this.syncPlayPause()), this.on(e, "volumechange", () => this.syncVolume()), this.on(e, "timeupdate", () => this.syncProgress()), this.on(e, "progress", () => this.syncProgress()), this.on(e, "durationchange", () => this.syncProgress()), this.offFns.push(this.player.on("statechange", () => this.syncState())), this.offFns.push(this.player.on("ended", () => this.syncState())), this.offFns.push(this.player.on("ready", () => this.refreshTracks())), this.offFns.push(this.player.on("qualitychange", () => this.onTracksChanged())), this.offFns.push(this.player.on("audiotrackchange", () => this.onTracksChanged())), this.offFns.push(this.player.on("texttrackchange", () => this.onTracksChanged())), this.offFns.push(this.player.on("pipchange", (e) => this.syncPip(e))), this.offFns.push(this.player.on("stats", () => this.syncLive())), this.offFns.push(this.player.on("error", (e) => {
2810
+ }), this.on(this.liveGo, "click", () => this.player.seekToLive()), this.on(this.pipBtn, "click", () => void this.togglePip()), this.on(this.fsBtn, "click", () => void this.toggleFullscreen()), this.on(this.ccBtn, "click", () => this.toggleMenu("cc")), this.on(this.audioBtn, "click", () => this.toggleMenu("audio")), this.on(this.qualityBtn, "click", () => this.toggleMenu("quality")), this.on(this.seek, "pointerdown", (e) => this.onSeekDown(e)), this.on(this.seek, "keydown", (e) => this.onSeekKey(e)), this.on(e, "play", () => this.syncPlayPause()), this.on(e, "pause", () => this.syncPlayPause()), this.on(e, "volumechange", () => this.syncVolume()), this.on(e, "timeupdate", () => this.syncProgress()), this.on(e, "progress", () => this.syncProgress()), this.on(e, "durationchange", () => this.syncProgress()), this.on(e, "loadedmetadata", () => this.syncFullscreenSupport()), this.offFns.push(this.player.on("statechange", () => this.syncState())), this.offFns.push(this.player.on("ended", () => this.syncState())), this.offFns.push(this.player.on("ready", () => this.refreshTracks())), this.offFns.push(this.player.on("qualitychange", () => this.onTracksChanged())), this.offFns.push(this.player.on("audiotrackchange", () => this.onTracksChanged())), this.offFns.push(this.player.on("texttrackchange", () => this.onTracksChanged())), this.offFns.push(this.player.on("pipchange", (e) => this.syncPip(e))), this.offFns.push(this.player.on("stats", () => this.syncLive())), this.offFns.push(this.player.on("error", (e) => {
2792
2811
  this.lastError = e, this.statusKind = null, this.syncState();
2793
2812
  }));
2794
2813
  let t = (e) => e.pointerType !== "touch";
@@ -2818,7 +2837,7 @@ var $n = class {
2818
2837
  let t = this.surfaceWasHidden;
2819
2838
  this.tapTimer = setTimeout(() => {
2820
2839
  this.tapTimer = void 0, this.toggleBar(t);
2821
- }, Xn);
2840
+ }, Zn);
2822
2841
  }
2823
2842
  toggleBar(e) {
2824
2843
  e ? this.poke() : this.hideIfIdle();
@@ -2838,7 +2857,7 @@ var $n = class {
2838
2857
  this.statusOverlays && (e === "ended" ? t = "ended" : e === "error" ? t = "error" : e === "waiting" ? t = "waiting" : !this.hasPlayed && (e === "idle" || e === "paused") && (t = "preplay")), this.renderStatus(t);
2839
2858
  }
2840
2859
  statusMessageFor(e) {
2841
- return e === "ended" ? this.player.endedReason === "interrupted" ? this.interruptedMessage : this.endedMessage : e === "waiting" ? this.hasPlayed ? "Reconnecting — please stand by" : "Starting soon…" : e === "error" ? this.errorMessage ?? this.lastError?.message ?? "Playback unavailable" : null;
2860
+ return e === "ended" ? this.player.endedReason === "interrupted" ? this.interruptedMessage : this.endedMessage : e === "waiting" ? this.hasPlayed ? "Reconnecting — please stand by" : "Starting soon…" : e === "error" ? this.errorMessage === void 0 ? this.lastError?.code === "GEO_DENIED" ? $n(this.lastError.country) : this.lastError?.message ?? "Playback unavailable" : this.errorMessage : null;
2842
2861
  }
2843
2862
  renderStatus(e) {
2844
2863
  let t = this.statusMessageFor(e);
@@ -2853,7 +2872,7 @@ var $n = class {
2853
2872
  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);
2854
2873
  } else {
2855
2874
  let r = this.doc.createElement("div");
2856
- if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !Zn.has(this.lastError.code)) {
2875
+ if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !Qn.has(this.lastError.code)) {
2857
2876
  let e = this.doc.createElement("button");
2858
2877
  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);
2859
2878
  }
@@ -2894,7 +2913,7 @@ var $n = class {
2894
2913
  let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
2895
2914
  this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
2896
2915
  }
2897
- !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${er(this.video.currentTime)} / ${er(this.video.duration)}`);
2916
+ !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${nr(this.video.currentTime)} / ${nr(this.video.duration)}`);
2898
2917
  }
2899
2918
  syncLive() {
2900
2919
  let e = this.player.getStats(), t = e.isLive !== !1, n = this.player.state === "ended", r = !t && !this.streamEnded();
@@ -2944,17 +2963,17 @@ var $n = class {
2944
2963
  renderQualityMenu() {
2945
2964
  let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
2946
2965
  n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
2947
- for (let n of e) this.menu.append(this.menuItem(tr(n), t === n.index, () => this.player.setQuality(n.index)));
2966
+ for (let n of e) this.menu.append(this.menuItem(rr(n), t === n.index, () => this.player.setQuality(n.index)));
2948
2967
  }
2949
2968
  renderAudioMenu() {
2950
2969
  let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
2951
2970
  t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
2952
- for (let t of e) this.menu.append(this.menuItem(nr(t), t.default, () => this.player.setAudioTrack(t.id)));
2971
+ for (let t of e) this.menu.append(this.menuItem(ir(t), t.default, () => this.player.setAudioTrack(t.id)));
2953
2972
  }
2954
2973
  renderCcMenu() {
2955
2974
  let e = this.player.getTextTracks(), t = this.doc.createElement("div");
2956
2975
  t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
2957
- for (let t of e) this.menu.append(this.menuItem(rr(t), !1, () => this.player.setTextTrack(t.id)));
2976
+ for (let t of e) this.menu.append(this.menuItem(ar(t), !1, () => this.player.setTextTrack(t.id)));
2958
2977
  }
2959
2978
  onTracksChanged() {
2960
2979
  this.openMenu && this.renderMenu(this.openMenu);
@@ -2974,11 +2993,14 @@ var $n = class {
2974
2993
  }
2975
2994
  async toggleFullscreen() {
2976
2995
  try {
2977
- x(this.video, this.root) ? await C(this.video, this.root) : await S(this.video, this.root);
2996
+ S(this.video, this.root) ? await T(this.video, this.root) : await w(this.video, this.root);
2978
2997
  } catch {}
2979
2998
  }
2999
+ syncFullscreenSupport() {
3000
+ this.fsSupported = C(this.video, this.root), this.fsBtn.style.display = this.fsSupported ? "" : "none";
3001
+ }
2980
3002
  syncFullscreen() {
2981
- let e = x(this.video, this.root);
3003
+ let e = S(this.video, this.root);
2982
3004
  this.setIcon(this.fsBtn, e ? "fullscreenExit" : "fullscreen"), this.fsBtn.setAttribute("aria-label", e ? "Exit fullscreen" : "Fullscreen");
2983
3005
  }
2984
3006
  poke() {
@@ -3012,6 +3034,7 @@ var $n = class {
3012
3034
  this.player.setMuted(!this.video.muted);
3013
3035
  break;
3014
3036
  case "f":
3037
+ if (!this.fsSupported) return;
3015
3038
  this.toggleFullscreen();
3016
3039
  break;
3017
3040
  case "c":
@@ -3055,41 +3078,41 @@ var $n = class {
3055
3078
  this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
3056
3079
  }
3057
3080
  };
3058
- function er(e) {
3081
+ function nr(e) {
3059
3082
  (!Number.isFinite(e) || e < 0) && (e = 0);
3060
3083
  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");
3061
3084
  return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
3062
3085
  }
3063
- function tr(e) {
3086
+ function rr(e) {
3064
3087
  return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
3065
3088
  }
3066
- function nr(e) {
3089
+ function ir(e) {
3067
3090
  return e.name || e.lang || `Track ${e.id}`;
3068
3091
  }
3069
- function rr(e) {
3092
+ function ar(e) {
3070
3093
  return e.name || e.lang || `Track ${e.id}`;
3071
3094
  }
3072
3095
  //#endregion
3073
3096
  //#region src/managed/index.ts
3074
- var ir = 6e3, ar = 45e3, or = 2e3, sr = 3, cr = 5e3, lr = 2e3, ur = 48e4, dr = "keySystemLicenseRequestFailed";
3075
- function fr(e) {
3097
+ var or = 6e3, sr = 45e3, cr = 2e3, lr = 3, ur = 5e3, dr = 2e3, fr = 48e4, pr = "keySystemLicenseRequestFailed";
3098
+ function mr(e) {
3076
3099
  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)})`);
3077
- if (e.env !== void 0) return L(e.env);
3100
+ if (e.env !== void 0) return it(e.env);
3078
3101
  if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
3079
3102
  return e.baseUrl;
3080
3103
  }
3081
- async function pr(e) {
3104
+ async function hr(e) {
3082
3105
  if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
3083
- let t = fr(e);
3106
+ let t = mr(e);
3084
3107
  if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
3085
3108
  if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
3086
- let r = new mr({
3109
+ let r = new gr({
3087
3110
  ...e,
3088
3111
  baseUrl: t
3089
3112
  });
3090
3113
  return await r.start(), r;
3091
3114
  }
3092
- var mr = class {
3115
+ var gr = class {
3093
3116
  opts;
3094
3117
  abort = new AbortController();
3095
3118
  listeners = {};
@@ -3163,7 +3186,7 @@ var mr = class {
3163
3186
  };
3164
3187
  }
3165
3188
  beginArming(e, t, n = !1) {
3166
- let r = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? T(this.opts.baseUrl);
3189
+ let r = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? D(this.opts.baseUrl);
3167
3190
  r ? this.armWithSse(e, r, t, n) : this.beginArmingByPolling(e);
3168
3191
  }
3169
3192
  beginArmingByPolling(e) {
@@ -3184,7 +3207,7 @@ var mr = class {
3184
3207
  setTimeout(() => {
3185
3208
  a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
3186
3209
  phase: i ? "unavailable" : "tooEarly",
3187
- retryInMs: ar,
3210
+ retryInMs: sr,
3188
3211
  attempt: 1,
3189
3212
  elapsedMs: 0,
3190
3213
  ...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
@@ -3223,13 +3246,13 @@ var mr = class {
3223
3246
  !a && !p() && h();
3224
3247
  }, e);
3225
3248
  };
3226
- _(ir), this.armingSub = w({
3249
+ _(or), this.armingSub = E({
3227
3250
  eventsBaseUrl: t,
3228
3251
  matchUrn: this.opts.matchUrn,
3229
3252
  credential: this.opts.credential,
3230
- onAlive: () => _(ar),
3253
+ onAlive: () => _(sr),
3231
3254
  onState: (e) => {
3232
- a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * or);
3255
+ a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * cr);
3233
3256
  },
3234
3257
  onError: () => h()
3235
3258
  });
@@ -3252,7 +3275,7 @@ var mr = class {
3252
3275
  let n = await s(this.opts.credential);
3253
3276
  if (this.destroyed || t !== this.loadGen) return;
3254
3277
  this.setState("loading");
3255
- let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = ct(this.opts.video, (e) => {
3278
+ let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = lt(this.opts.video, (e) => {
3256
3279
  this._state !== "ended" && this._state !== "error" && this.setState(e);
3257
3280
  });
3258
3281
  if (await i.load(), this.destroyed || t !== this.loadGen) {
@@ -3274,26 +3297,26 @@ var mr = class {
3274
3297
  if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
3275
3298
  let i = e.analytics?.sid;
3276
3299
  if (!i) return;
3277
- let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = Pn(this.opts.baseUrl, a, e.analytics?.endpoint);
3300
+ let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = Fn(this.opts.baseUrl, a, e.analytics?.endpoint);
3278
3301
  if (!o) {
3279
3302
  s && setTimeout(() => {
3280
3303
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
3281
3304
  }, 0);
3282
3305
  return;
3283
3306
  }
3284
- let c = this.opts.video, l = new Fn({
3307
+ let c = this.opts.video, l = new In({
3285
3308
  endpoint: o,
3286
3309
  sid: i,
3287
3310
  player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
3288
- sdkVersion: Vn,
3289
- environment: zn(c),
3311
+ sdkVersion: Hn,
3312
+ environment: Bn(c),
3290
3313
  idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
3291
3314
  onIdle: () => this.onAnalyticsIdle(t),
3292
3315
  onBlocked: (e) => setTimeout(() => {
3293
3316
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, e));
3294
3317
  }, 0),
3295
3318
  sample: () => {
3296
- let e = this.engine?.getStats() ?? R, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
3319
+ let e = this.engine?.getStats() ?? z, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
3297
3320
  return {
3298
3321
  ...e,
3299
3322
  bufferedMs: Math.round(t * 1e3),
@@ -3307,7 +3330,7 @@ var mr = class {
3307
3330
  let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
3308
3331
  c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
3309
3332
  c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
3310
- }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), Bn().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
3333
+ }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), Vn().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
3311
3334
  }
3312
3335
  currentPresentation() {
3313
3336
  let e = this.opts.video;
@@ -3322,7 +3345,7 @@ var mr = class {
3322
3345
  video: this.opts.video,
3323
3346
  descriptor: e,
3324
3347
  credential: t,
3325
- deviceId: O(),
3348
+ deviceId: A(),
3326
3349
  userId: this.opts.userId,
3327
3350
  lowLatency: this.opts.lowLatency === void 0 || this.opts.lowLatency === "auto" || this.opts.lowLatency,
3328
3351
  snapToLiveOnRefocus: this.opts.snapToLiveOnRefocus,
@@ -3335,9 +3358,9 @@ var mr = class {
3335
3358
  freshLicenseUrl: () => this.refreshLicense()
3336
3359
  }, o = this.opts.engine ?? "auto";
3337
3360
  if (o === "native") return new W(a);
3338
- if (o === "hls") return new gn(a);
3339
- if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && H(this.opts.video) && U() || !e.drmEnabled && bt() && H(this.opts.video)) return new W(a);
3340
- if (Mt()) return new gn(a);
3361
+ if (o === "hls") return new _n(a);
3362
+ if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && H(this.opts.video) && U() || !e.drmEnabled && xt() && H(this.opts.video)) return new W(a);
3363
+ if (Nt()) return new _n(a);
3341
3364
  if (H(this.opts.video)) return new W(a);
3342
3365
  throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
3343
3366
  }
@@ -3385,11 +3408,11 @@ var mr = class {
3385
3408
  }
3386
3409
  startLiveState(e) {
3387
3410
  if (this.opts.liveStateEvents === !1) return;
3388
- let t = this.opts.eventsBaseUrl ?? T(this.opts.baseUrl);
3411
+ let t = this.opts.eventsBaseUrl ?? D(this.opts.baseUrl);
3389
3412
  if (!t) return;
3390
3413
  this.closeLiveState();
3391
3414
  let r = 0, i = !1;
3392
- this.liveStateSub = w({
3415
+ this.liveStateSub = E({
3393
3416
  eventsBaseUrl: t,
3394
3417
  matchUrn: this.opts.matchUrn,
3395
3418
  credential: this.opts.credential,
@@ -3400,7 +3423,7 @@ var mr = class {
3400
3423
  r = 0, i = !1;
3401
3424
  },
3402
3425
  onError: () => {
3403
- this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= sr && (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.`))));
3426
+ this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= lr && (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.`))));
3404
3427
  }
3405
3428
  });
3406
3429
  }
@@ -3414,7 +3437,7 @@ var mr = class {
3414
3437
  return;
3415
3438
  }
3416
3439
  let e = this.hiddenAtMs;
3417
- this.hiddenAtMs = null, e != null && Date.now() - e >= cr && this.resyncLiveState();
3440
+ this.hiddenAtMs = null, e != null && Date.now() - e >= ur && this.resyncLiveState();
3418
3441
  }, this.onReturnPageShow = (e) => {
3419
3442
  e.persisted && this.resyncLiveState();
3420
3443
  }, document.addEventListener("visibilitychange", this.onReturnVisible), typeof window < "u" && window.addEventListener("pageshow", this.onReturnPageShow));
@@ -3446,7 +3469,7 @@ var mr = class {
3446
3469
  scheduleRejoin(e) {
3447
3470
  this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
3448
3471
  this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
3449
- }, Math.random() * or));
3472
+ }, Math.random() * cr));
3450
3473
  }
3451
3474
  cancelRejoin() {
3452
3475
  this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
@@ -3470,7 +3493,7 @@ var mr = class {
3470
3493
  }
3471
3494
  t.controls = !1;
3472
3495
  let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
3473
- r && r.insertBefore(n, t), n.appendChild(t), Wn(n, this.opts.theme), this.container = n, this.controlBar = Qn({
3496
+ r && r.insertBefore(n, t), n.appendChild(t), Gn(n, this.opts.theme), this.container = n, this.controlBar = er({
3474
3497
  root: n,
3475
3498
  video: t,
3476
3499
  player: this,
@@ -3508,7 +3531,7 @@ var mr = class {
3508
3531
  }
3509
3532
  startStats() {
3510
3533
  this.stopStats();
3511
- let e = Math.max(500, this.opts.statsIntervalMs ?? lr);
3534
+ let e = Math.max(500, this.opts.statsIntervalMs ?? dr);
3512
3535
  this.statsTimer = setInterval(() => {
3513
3536
  if (!this.engine) return;
3514
3537
  let e = this.engine.getStats();
@@ -3519,14 +3542,14 @@ var mr = class {
3519
3542
  this.statsTimer && clearInterval(this.statsTimer), this.statsTimer = void 0;
3520
3543
  }
3521
3544
  isStaleLicenseDenial(e) {
3522
- return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== dr || e.error.httpStatus !== 403 ? !1 : K(this._descriptor?.drm?.widevine?.licenseUrl);
3545
+ return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== pr || e.error.httpStatus !== 403 ? !1 : K(this._descriptor?.drm?.widevine?.licenseUrl);
3523
3546
  }
3524
3547
  scheduleLicenseRefresh() {
3525
3548
  if (this.stopRefresh(), !this._descriptor?.drmEnabled) return;
3526
3549
  typeof document < "u" && this.engine?.name === "hls" && (this.onRefocus = () => {
3527
3550
  document.visibilityState !== "visible" || this.destroyed || K(this._descriptor?.drm?.widevine?.licenseUrl) && this.refreshLicense();
3528
3551
  }, document.addEventListener("visibilitychange", this.onRefocus));
3529
- let e = this.opts.licenseRefreshMs ?? ur;
3552
+ let e = this.opts.licenseRefreshMs ?? fr;
3530
3553
  e && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
3531
3554
  }
3532
3555
  stopRefresh() {
@@ -3583,7 +3606,7 @@ var mr = class {
3583
3606
  this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
3584
3607
  }
3585
3608
  getStats() {
3586
- return this.engine?.getStats() ?? R;
3609
+ return this.engine?.getStats() ?? z;
3587
3610
  }
3588
3611
  getQualityLevels() {
3589
3612
  return this.engine?.getQualityLevels() ?? [];
@@ -3622,10 +3645,13 @@ var mr = class {
3622
3645
  e.pictureInPictureElement === this.opts.video && typeof e.exitPictureInPicture == "function" && await e.exitPictureInPicture();
3623
3646
  }
3624
3647
  async enterFullscreen() {
3625
- return !this.destroyed && S(this.opts.video, this.container ?? void 0);
3648
+ return !this.destroyed && w(this.opts.video, this.container ?? void 0);
3626
3649
  }
3627
3650
  async exitFullscreen() {
3628
- await C(this.opts.video, this.container ?? void 0);
3651
+ await T(this.opts.video, this.container ?? void 0);
3652
+ }
3653
+ fullscreenSupported() {
3654
+ return !this.destroyed && C(this.opts.video, this.container ?? void 0);
3629
3655
  }
3630
3656
  retry() {
3631
3657
  return this.reload();
@@ -3693,7 +3719,7 @@ function $(e) {
3693
3719
  }
3694
3720
  //#endregion
3695
3721
  //#region src/embed/host.ts
3696
- function hr(e) {
3722
+ function _r(e) {
3697
3723
  if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
3698
3724
  if (!e.src) throw Error("mountEmbed: opts.src is required");
3699
3725
  if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
@@ -3752,15 +3778,15 @@ function hr(e) {
3752
3778
  }
3753
3779
  //#endregion
3754
3780
  //#region src/embed/page.ts
3755
- var gr = /^[A-Za-z0-9:_.-]{1,128}$/;
3756
- function _r(e) {
3781
+ var vr = /^[A-Za-z0-9:_.-]{1,128}$/;
3782
+ function yr(e) {
3757
3783
  if (typeof e == "boolean") return e;
3758
3784
  if (typeof e == "object" && e) {
3759
3785
  let t = e.endpoint;
3760
3786
  return typeof t == "string" ? { endpoint: t } : {};
3761
3787
  }
3762
3788
  }
3763
- function vr() {
3789
+ function br() {
3764
3790
  let e = window.HAVIK_EMBED_CONFIG;
3765
3791
  if (e) return {
3766
3792
  baseUrl: e.baseUrl ?? "",
@@ -3770,7 +3796,7 @@ function vr() {
3770
3796
  autoplay: e.autoplay ?? !0,
3771
3797
  muted: e.muted ?? !0,
3772
3798
  waitForLive: e.waitForLive ?? !0,
3773
- analytics: _r(e.analytics)
3799
+ analytics: yr(e.analytics)
3774
3800
  };
3775
3801
  let t = new URLSearchParams(location.search);
3776
3802
  return {
@@ -3783,9 +3809,9 @@ function vr() {
3783
3809
  waitForLive: !0
3784
3810
  };
3785
3811
  }
3786
- async function yr() {
3787
- let e = vr();
3788
- xr();
3812
+ async function xr() {
3813
+ let e = br();
3814
+ Cr();
3789
3815
  let t = document.createElement("video");
3790
3816
  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);
3791
3817
  let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
@@ -3838,14 +3864,15 @@ async function yr() {
3838
3864
  })), e.on("error", (e) => i({
3839
3865
  type: "oddin:error",
3840
3866
  code: e.code,
3841
- message: e.message
3867
+ message: e.message,
3868
+ ...e.country === void 0 ? {} : { country: e.country }
3842
3869
  })), e.on("autoplayblocked", () => {
3843
- i({ type: "oddin:autoplayblocked" }), br(t, e);
3870
+ i({ type: "oddin:autoplayblocked" }), Sr(t, e);
3844
3871
  });
3845
3872
  }, s = async (r) => {
3846
3873
  a?.destroy(), a = null;
3847
3874
  try {
3848
- let n = await pr({
3875
+ let n = await hr({
3849
3876
  video: t,
3850
3877
  baseUrl: e.baseUrl,
3851
3878
  matchUrn: r,
@@ -3859,11 +3886,12 @@ async function yr() {
3859
3886
  let i = t.parentElement;
3860
3887
  i?.classList.contains("havik-player") && (i.style.cssText = "position:absolute;inset:0;width:100%;height:100%;aspect-ratio:auto"), o(n);
3861
3888
  } catch (e) {
3862
- let t = e instanceof n ? e.code : "INTERNAL", r = e instanceof Error ? e.message : String(e);
3889
+ let t = e instanceof n ? e.code : "INTERNAL", r = e instanceof Error ? e.message : String(e), a = e instanceof n ? e.country : void 0;
3863
3890
  i({
3864
3891
  type: "oddin:error",
3865
3892
  code: t,
3866
- message: r
3893
+ message: r,
3894
+ ...a === void 0 ? {} : { country: a }
3867
3895
  });
3868
3896
  }
3869
3897
  }, c = () => {
@@ -3907,7 +3935,7 @@ async function yr() {
3907
3935
  a?.retry();
3908
3936
  break;
3909
3937
  case "oddin:load":
3910
- typeof e.matchUrn == "string" && gr.test(e.matchUrn) && s(e.matchUrn);
3938
+ typeof e.matchUrn == "string" && vr.test(e.matchUrn) && s(e.matchUrn);
3911
3939
  break;
3912
3940
  case "oddin:destroy": c();
3913
3941
  }
@@ -3919,18 +3947,18 @@ async function yr() {
3919
3947
  protocol: 1
3920
3948
  });
3921
3949
  }
3922
- function br(e, t) {
3950
+ function Sr(e, t) {
3923
3951
  if (document.getElementById("havik-tap")) return;
3924
3952
  let n = document.createElement("button");
3925
3953
  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", () => {
3926
3954
  n.remove(), t.play();
3927
3955
  }), document.body.appendChild(n);
3928
3956
  }
3929
- function xr() {
3957
+ function Cr() {
3930
3958
  let e = document.createElement("style");
3931
3959
  e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
3932
3960
  }
3933
3961
  //#endregion
3934
- export { Hn as ODDIN_THEME, n as PlaybackError, Wn as applyTheme, L as baseUrlForEnv, yr as bootEmbed, Ee as clearDeviceId, Re as clearRememberedBandwidth, pr as createPlayer, T as deriveEventsBaseUrl, tt as detectDrmSupport, S as enterVideoFullscreen, C as exitVideoFullscreen, ve as fetchCatalog, be as fetchTournament, Se as flattenMatches, O as getDeviceId, rt as isLowLatencyManifest, $ as isOddinMessage, Oe as licenseRequestHeaders, hr as mountEmbed, de as pollToLive, y as resolveStream, w as subscribeLiveState, x as videoFullscreenActive, we as watchStatus };
3962
+ export { Un as ODDIN_THEME, n as PlaybackError, Gn as applyTheme, it as baseUrlForEnv, xr as bootEmbed, Te as clearDeviceId, Le as clearRememberedBandwidth, hr as createPlayer, D as deriveEventsBaseUrl, et as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, _e as fetchCatalog, ye as fetchTournament, xe as flattenMatches, C as fullscreenSupported, A as getDeviceId, nt as isLowLatencyManifest, $ as isOddinMessage, De as licenseRequestHeaders, _r as mountEmbed, de as pollToLive, y as resolveStream, E as subscribeLiveState, S as videoFullscreenActive, Ce as watchStatus };
3935
3963
 
3936
3964
  //# sourceMappingURL=index.js.map