@oddin-gg/havik-player 2.6.2 → 2.6.3

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
@@ -397,14 +397,15 @@ function he(e) {
397
397
  }
398
398
  //#endregion
399
399
  //#region src/core/events.ts
400
+ var ge = 45e3;
400
401
  function E(e) {
401
- let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = new AbortController(), i = !1, a = (e) => new Promise((t) => {
402
- if (r.signal.aborted) return t();
402
+ let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = e.idleTimeoutMs ?? ge, i = Number.isFinite(r) && r > 0 ? r : 0, a = new AbortController(), o = !1, l = (e) => new Promise((t) => {
403
+ if (a.signal.aborted) return t();
403
404
  let n = setTimeout(t, e);
404
- r.signal.addEventListener("abort", () => {
405
+ a.signal.addEventListener("abort", () => {
405
406
  clearTimeout(n), t();
406
407
  }, { once: !0 });
407
- }), o = (t) => {
408
+ }), u = (t) => {
408
409
  e.onAlive?.();
409
410
  let n = "message", r = [];
410
411
  for (let e of t.split("\n")) {
@@ -417,51 +418,66 @@ function E(e) {
417
418
  let t = JSON.parse(r.join("\n"));
418
419
  t && typeof t.state == "string" && e.onState(t);
419
420
  } catch {}
420
- }, l = /\r\n\r\n|\n\n|\r\r/, u = async (e, t) => {
421
- let n = e.getReader(), r = new TextDecoder(), a = "", s = !1;
421
+ }, d = /\r\n\r\n|\n\n|\r\r/, f = async (e, t, n) => {
422
+ let r = e.getReader(), a = new TextDecoder(), s = "", c = !1, l, f = () => {
423
+ i && (clearTimeout(l), l = setTimeout(() => {
424
+ n(), r.cancel().catch(() => {});
425
+ }, i));
426
+ };
422
427
  try {
423
- for (;;) {
424
- let { value: e, done: c } = await n.read();
425
- if (c) return;
426
- !s && e && e.length > 0 && (s = !0, t()), a += r.decode(e, { stream: !0 });
427
- let u;
428
- for (; (u = l.exec(a)) !== null;) o(a.slice(0, u.index)), a = a.slice(u.index + u[0].length);
429
- if (i) return;
428
+ for (f();;) {
429
+ let { value: e, done: n } = await r.read();
430
+ if (n) return;
431
+ e && e.length > 0 && (f(), c || (c = !0, t())), s += a.decode(e, { stream: !0 });
432
+ let i;
433
+ for (; (i = d.exec(s)) !== null;) u(s.slice(0, i.index)), s = s.slice(i.index + i[0].length);
434
+ if (o) return;
430
435
  }
431
436
  } finally {
432
- await n.cancel().catch(() => {});
437
+ clearTimeout(l), await r.cancel().catch(() => {});
433
438
  }
434
439
  };
435
440
  return (async () => {
436
- let o = t;
437
- for (; !i;) {
441
+ let r = t;
442
+ for (; !o;) {
443
+ let u = new AbortController(), d = () => u.abort();
444
+ a.signal.addEventListener("abort", d, { once: !0 });
445
+ let p = null, m, h = () => {
446
+ p = `no data for ${i}ms`, u.abort();
447
+ };
438
448
  try {
439
449
  let n = await s(e.credential);
440
- if (i) return;
441
- let a = c(e.eventsBaseUrl, `/v1/events/${encodeURIComponent(e.matchUrn)}`), l = await fetch(a, {
450
+ if (o) return;
451
+ let a = c(e.eventsBaseUrl, `/v1/events/${encodeURIComponent(e.matchUrn)}`);
452
+ i && (m = setTimeout(() => {
453
+ p = `no response headers within ${i}ms`, u.abort();
454
+ }, i));
455
+ let l = await fetch(a, {
442
456
  method: "GET",
443
457
  headers: {
444
458
  "x-api-key": n.apiKey,
445
459
  accept: "text/event-stream"
446
460
  },
447
- signal: r.signal,
461
+ signal: u.signal,
448
462
  cache: "no-store",
449
463
  credentials: "omit",
450
464
  mode: "cors"
451
465
  });
452
- if (i) return;
453
- !l.ok || !l.body ? e.onError?.(/* @__PURE__ */ Error(`live-state subscribe failed: HTTP ${l.status}`)) : await u(l.body, () => {
454
- o = t;
455
- });
466
+ if (clearTimeout(m), o) return;
467
+ !l.ok || !l.body ? e.onError?.(/* @__PURE__ */ Error(`live-state subscribe failed: HTTP ${l.status}`)) : await f(l.body, () => {
468
+ r = t;
469
+ }, h);
456
470
  } catch (t) {
457
- if (i || r.signal.aborted) return;
458
- e.onError?.(t);
471
+ if (o || a.signal.aborted) return;
472
+ p || e.onError?.(t);
473
+ } finally {
474
+ clearTimeout(m), a.signal.removeEventListener("abort", d), u.abort();
459
475
  }
460
- if (i) return;
461
- await a(o), o = Math.min(n, o * 2);
476
+ if (o) return;
477
+ p && e.onError?.(/* @__PURE__ */ Error(`live-state subscribe idle: ${p} — reconnecting`)), await l(r), r = Math.min(n, r * 2);
462
478
  }
463
479
  })(), { close() {
464
- i || (i = !0, r.abort());
480
+ o || (o = !0, a.abort());
465
481
  } };
466
482
  }
467
483
  function D(e) {
@@ -481,20 +497,20 @@ function A() {
481
497
  let e = globalThis.localStorage?.getItem(O);
482
498
  if (e) return k = e, e;
483
499
  } catch {}
484
- let e = _e();
500
+ let e = ve();
485
501
  k = e;
486
502
  try {
487
503
  globalThis.localStorage?.setItem(O, e);
488
504
  } catch {}
489
505
  return e;
490
506
  }
491
- function ge() {
507
+ function _e() {
492
508
  k = void 0;
493
509
  try {
494
510
  globalThis.localStorage?.removeItem(O);
495
511
  } catch {}
496
512
  }
497
- function _e() {
513
+ function ve() {
498
514
  let e = globalThis.crypto;
499
515
  if (e && typeof e.randomUUID == "function") return e.randomUUID();
500
516
  let t = /* @__PURE__ */ new Uint8Array(16);
@@ -506,7 +522,7 @@ function _e() {
506
522
  }
507
523
  //#endregion
508
524
  //#region src/core/drm/headers.ts
509
- function ve(e, t, n = {}) {
525
+ function ye(e, t, n = {}) {
510
526
  let r = {
511
527
  "x-api-key": t.apiKey,
512
528
  "X-Match-Urn": e.matchUrn,
@@ -518,7 +534,7 @@ function ve(e, t, n = {}) {
518
534
  //#endregion
519
535
  //#region src/core/drm/cdm.ts
520
536
  var j = /* @__PURE__ */ new WeakMap();
521
- function ye(e, t) {
537
+ function be(e, t) {
522
538
  let n = j.get(e);
523
539
  n || (n = /* @__PURE__ */ new Map(), j.set(e, n));
524
540
  let r = n.get(t.keySystem);
@@ -532,11 +548,11 @@ function M() {
532
548
  return typeof navigator < "u" && typeof navigator.requestMediaKeySystemAccess == "function";
533
549
  }
534
550
  var N = ["SW_SECURE_DECODE", "SW_SECURE_CRYPTO"];
535
- function be(e) {
551
+ function xe(e) {
536
552
  return e.startsWith("com.widevine");
537
553
  }
538
- function xe(e, t) {
539
- if (!be(e)) return t;
554
+ function Se(e, t) {
555
+ if (!xe(e)) return t;
540
556
  let n = (e, t) => {
541
557
  let n = e.videoCapabilities;
542
558
  return !n?.length || !n.some((e) => e.robustness) ? !1 : n.every((e) => {
@@ -552,20 +568,20 @@ function xe(e, t) {
552
568
  })));
553
569
  return [...t, ...r];
554
570
  }
555
- function Se(e) {
556
- return (t, n) => M() ? navigator.requestMediaKeySystemAccess(t, xe(t, n)).then((t) => ({
571
+ function Ce(e) {
572
+ return (t, n) => M() ? navigator.requestMediaKeySystemAccess(t, Se(t, n)).then((t) => ({
557
573
  keySystem: t.keySystem,
558
574
  getConfiguration: () => t.getConfiguration(),
559
- createMediaKeys: () => ye(e, t)
575
+ createMediaKeys: () => be(e, t)
560
576
  })) : Promise.reject(/* @__PURE__ */ Error("navigator.requestMediaKeySystemAccess is unavailable — EME needs a secure context (https, or localhost)"));
561
577
  }
562
578
  //#endregion
563
579
  //#region src/core/drm/support.ts
564
- var Ce = 5e3, we = "video/mp4; codecs=\"avc1.42E01E\"", P = "audio/mp4; codecs=\"mp4a.40.2\"", Te = {
580
+ var we = 5e3, Te = "video/mp4; codecs=\"avc1.42E01E\"", P = "audio/mp4; codecs=\"mp4a.40.2\"", Ee = {
565
581
  widevine: ["com.widevine.alpha"],
566
582
  fairplay: ["com.apple.fps"]
567
583
  };
568
- function Ee(e) {
584
+ function De(e) {
569
585
  return e === "fairplay" ? [{
570
586
  initDataTypes: [
571
587
  "sinf",
@@ -573,7 +589,7 @@ function Ee(e) {
573
589
  "cenc"
574
590
  ],
575
591
  videoCapabilities: [{
576
- contentType: we,
592
+ contentType: Te,
577
593
  robustness: "",
578
594
  encryptionScheme: "cbcs"
579
595
  }],
@@ -582,10 +598,10 @@ function Ee(e) {
582
598
  robustness: "",
583
599
  encryptionScheme: "cbcs"
584
600
  }]
585
- }] : xe("com.widevine.alpha", [{
601
+ }] : Se("com.widevine.alpha", [{
586
602
  initDataTypes: ["cenc"],
587
603
  videoCapabilities: [{
588
- contentType: we,
604
+ contentType: Te,
589
605
  robustness: "SW_SECURE_DECODE",
590
606
  encryptionScheme: "cbcs"
591
607
  }],
@@ -606,8 +622,8 @@ function F(e, t) {
606
622
  });
607
623
  });
608
624
  }
609
- async function De(e = {}) {
610
- let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Ce, r = {};
625
+ async function Oe(e = {}) {
626
+ let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? we, r = {};
611
627
  if (typeof window < "u" && window.isSecureContext === !1) return {
612
628
  verdict: "insecure-context",
613
629
  detail: r
@@ -619,7 +635,7 @@ async function De(e = {}) {
619
635
  };
620
636
  let a = !1, o = !1, s = Date.now() + n, c = () => Math.max(1, s - Date.now());
621
637
  for (let e of t) {
622
- let t = Te[e];
638
+ let t = Ee[e];
623
639
  if (!t) {
624
640
  r[e] = "unknown system";
625
641
  continue;
@@ -630,7 +646,7 @@ async function De(e = {}) {
630
646
  break;
631
647
  }
632
648
  try {
633
- return await F((await F(i(n, Ee(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
649
+ return await F((await F(i(n, De(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
634
650
  verdict: "supported",
635
651
  system: e,
636
652
  detail: r
@@ -654,9 +670,9 @@ async function De(e = {}) {
654
670
  }
655
671
  //#endregion
656
672
  //#region src/core/manifest.ts
657
- var Oe = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
658
- function ke(e) {
659
- return Oe.test(e);
673
+ var ke = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
674
+ function Ae(e) {
675
+ return ke.test(e);
660
676
  }
661
677
  //#endregion
662
678
  //#region src/core/stats.ts
@@ -668,11 +684,11 @@ function L(e) {
668
684
  return "";
669
685
  }
670
686
  }
671
- var Ae = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
672
- function je(e) {
687
+ var je = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
688
+ function Me(e) {
673
689
  if (typeof performance > "u" || typeof performance.getEntriesByType != "function") return "";
674
690
  let t = "", n = -1, r = performance.getEntriesByType("resource");
675
- for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || Ae.test(i.name)) && i.startTime >= n) {
691
+ for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || je.test(i.name)) && i.startTime >= n) {
676
692
  let e = L(i.name);
677
693
  e && (t = e, n = i.startTime);
678
694
  }
@@ -685,7 +701,7 @@ function R(e) {
685
701
  totalFrames: t?.totalVideoFrames ?? 0
686
702
  };
687
703
  }
688
- function Me(e, t) {
704
+ function Ne(e, t) {
689
705
  let n = [
690
706
  ["playing", () => t("playing")],
691
707
  ["waiting", () => t("buffering")],
@@ -702,7 +718,7 @@ function Me(e, t) {
702
718
  }
703
719
  //#endregion
704
720
  //#region src/core/engine/native.ts
705
- function Ne(e) {
721
+ function Pe(e) {
706
722
  try {
707
723
  let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
708
724
  return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
@@ -754,7 +770,7 @@ var V = class {
754
770
  type: "error",
755
771
  error: new n("INTERNAL", 0, "native HLS playback error"),
756
772
  fatal: !0
757
- }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = Pe(t.manifestUrl, t.analytics?.sid), e.load();
773
+ }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = Fe(t.manifestUrl, t.analytics?.sid), e.load();
758
774
  }
759
775
  startLoad() {
760
776
  this.loadStarted || (this.loadStarted = !0, this.restorePreload());
@@ -776,7 +792,7 @@ var V = class {
776
792
  });
777
793
  this.onEncrypted = (n) => {
778
794
  let i = n;
779
- i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = Ne(i.initData), (async () => {
795
+ i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = Pe(i.initData), (async () => {
780
796
  try {
781
797
  let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
782
798
  initDataTypes: [i.initDataType],
@@ -875,7 +891,7 @@ var V = class {
875
891
  droppedFrames: t.dropped,
876
892
  decodedFrames: t.totalFrames
877
893
  };
878
- return this.cdnHost ||= je(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity && (n.isLive = !0, e.seekable.length > 0 && (n.atLiveEdge = e.currentTime >= e.seekable.end(e.seekable.length - 1) - 2)), n;
894
+ return this.cdnHost ||= Me(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity && (n.isLive = !0, e.seekable.length > 0 && (n.atLiveEdge = e.currentTime >= e.seekable.end(e.seekable.length - 1) - 2)), n;
879
895
  }
880
896
  stop() {
881
897
  try {
@@ -894,25 +910,25 @@ var V = class {
894
910
  } catch {}
895
911
  }
896
912
  };
897
- function Pe(e, t) {
913
+ function Fe(e, t) {
898
914
  return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
899
915
  }
900
916
  //#endregion
901
917
  //#region src/core/engine/hls.ts
902
- function Fe() {
918
+ function Ie() {
903
919
  return e.isSupported();
904
920
  }
905
- var Ie = 3, Le = 5, Re = 3, ze = 3e4, Be = 12e3, Ve = 3e3, H = 6e3, He = 4e3, Ue = 2, We = 5, Ge = 2, Ke = 2, qe = 2e3, Je = 3e4, Ye = 2, Xe = 9, Ze = .5, Qe = 64;
906
- function $e(e) {
921
+ var Le = 3, Re = 5, ze = 3, Be = 3e4, Ve = 12e3, He = 3e3, H = 6e3, Ue = 4e3, We = 2, Ge = 5, Ke = 2, qe = 2, Je = 2e3, Ye = 3e4, Xe = 2, Ze = 9, Qe = .5, $e = 64;
922
+ function et(e) {
907
923
  if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
908
924
  delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
909
925
  return;
910
926
  }
911
- e.liveSyncDuration ??= Ye;
912
- let t = Math.max(12, e.liveSyncDuration + Xe);
913
- (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), et(e, e.liveSyncDuration);
927
+ e.liveSyncDuration ??= Xe;
928
+ let t = Math.max(12, e.liveSyncDuration + Ze);
929
+ (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), tt(e, e.liveSyncDuration);
914
930
  }
915
- function et(e, t) {
931
+ function tt(e, t) {
916
932
  let n = (e, t, n) => Math.min(n, Math.max(t, e));
917
933
  e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
918
934
  }
@@ -1010,7 +1026,7 @@ var U = class {
1010
1026
  let t = e.liveSyncPosition;
1011
1027
  if (typeof t != "number" || !Number.isFinite(t)) return;
1012
1028
  let { video: n } = this.deps;
1013
- n.currentTime <= t + Ze || (n.currentTime = t);
1029
+ n.currentTime <= t + Qe || (n.currentTime = t);
1014
1030
  }
1015
1031
  startHls() {
1016
1032
  let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps;
@@ -1034,7 +1050,7 @@ var U = class {
1034
1050
  videoEncryptionScheme: "cbcs",
1035
1051
  audioEncryptionScheme: "cbcs"
1036
1052
  },
1037
- ...M() ? { requestMediaKeySystemAccessFunc: Se(t) } : {},
1053
+ ...M() ? { requestMediaKeySystemAccessFunc: Ce(t) } : {},
1038
1054
  licenseXhrSetup: (e, t) => {
1039
1055
  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;
1040
1056
  let o = performance.now();
@@ -1050,7 +1066,7 @@ var U = class {
1050
1066
  } } : {},
1051
1067
  ...c
1052
1068
  };
1053
- $e(d), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.loadStarted = d.autoStartLoad !== !1;
1069
+ et(d), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.loadStarted = d.autoStartLoad !== !1;
1054
1070
  let f = new e(d);
1055
1071
  this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
1056
1072
  this.mediaRecoveries = 0, this.networkRecoveries = 0;
@@ -1059,14 +1075,14 @@ var U = class {
1059
1075
  }), f.on(e.Events.FRAG_BUFFERED, (e, t) => {
1060
1076
  t?.frag?.type === "main" && (this.kickPending = !1, this.kickTicks = 0, (this.mediaRecoveries > 0 || this.networkRecoveries > 0 || this.licenseRecoveries > 0 || this.starvationKicks > 0 || this.starvationRebuilds > 0) && !this.recoveryResetTimer && (this.recoveryResetTimer = setTimeout(() => {
1061
1077
  this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
1062
- }, ze)));
1078
+ }, Be)));
1063
1079
  }), f.on(e.Events.FRAG_LOADING, (e, t) => {
1064
1080
  t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
1065
1081
  }), f.on(e.Events.FRAG_LOADED, (e, t) => {
1066
1082
  let n = t?.frag?.stats, r = n?.loaded;
1067
1083
  typeof r == "number" && (this.bytesLoaded += r);
1068
1084
  let i = n?.loading;
1069
- 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 > Qe && this.requestTimesMs.shift());
1085
+ 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 > $e && this.requestTimesMs.shift());
1070
1086
  let a = t?.frag?.url;
1071
1087
  if (a) {
1072
1088
  let e = L(a);
@@ -1082,7 +1098,7 @@ var U = class {
1082
1098
  }));
1083
1099
  }), f.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
1084
1100
  this.checkEndStale(), this.checkStarvation();
1085
- }, Ve), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1101
+ }, He), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1086
1102
  this.renditionSwitches += 1;
1087
1103
  let n = this.lastLevelIndex >= 0 ? f.levels[this.lastLevelIndex] : void 0, r = f.levels[t.level];
1088
1104
  n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, l({
@@ -1146,7 +1162,7 @@ var U = class {
1146
1162
  return;
1147
1163
  }
1148
1164
  this.capTimer && clearTimeout(this.capTimer);
1149
- let t = e > this.sizeCapLevel ? qe : Je;
1165
+ let t = e > this.sizeCapLevel ? Je : Ye;
1150
1166
  this.capTimer = setTimeout(() => {
1151
1167
  this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
1152
1168
  }, t);
@@ -1235,7 +1251,7 @@ var U = class {
1235
1251
  return;
1236
1252
  }
1237
1253
  let e = Date.now() - this.lastAdvanceMs;
1238
- !this.chaseSuspended && e > H && this.suspendChasing(), e > Be && this.emitEnded("stalled");
1254
+ !this.chaseSuspended && e > H && this.suspendChasing(), e > Ve && this.emitEnded("stalled");
1239
1255
  }
1240
1256
  checkStarvation() {
1241
1257
  let e = this.hls, { video: t } = this.deps;
@@ -1244,17 +1260,17 @@ var U = class {
1244
1260
  this.starvedTicks = 0;
1245
1261
  return;
1246
1262
  }
1247
- let n = this.lastAdvanceMs !== 0 && Date.now() - this.lastAdvanceMs < H, r = this.lastFragLoadingMs !== 0 && Date.now() - this.lastFragLoadingMs > He;
1263
+ let n = this.lastAdvanceMs !== 0 && Date.now() - this.lastAdvanceMs < H, r = this.lastFragLoadingMs !== 0 && Date.now() - this.lastFragLoadingMs > Ue;
1248
1264
  if (!(t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused && n && r)) {
1249
1265
  this.starvedTicks = 0;
1250
1266
  return;
1251
1267
  }
1252
- if (this.kickPending && (this.kickTicks += 1), !(++this.starvedTicks < Ue)) {
1253
- if (this.starvedTicks = 0, this.kickPending && this.kickTicks >= Ge && (this.kickPending = !1, this.kickTicks = 0, this.starvationRebuilds < Ke)) {
1268
+ if (this.kickPending && (this.kickTicks += 1), !(++this.starvedTicks < We)) {
1269
+ if (this.starvedTicks = 0, this.kickPending && this.kickTicks >= Ke && (this.kickPending = !1, this.kickTicks = 0, this.starvationRebuilds < qe)) {
1254
1270
  this.starvationRebuilds += 1, 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");
1255
1271
  return;
1256
1272
  }
1257
- if (!(this.starvationKicks >= We)) {
1273
+ if (!(this.starvationKicks >= Ge)) {
1258
1274
  this.starvationKicks += 1, this.kickPending = !0, this.kickTicks = 0, console.warn("havik-player: video starved while the live playlist advances (wedged hls.js fragment pipeline) — restarting the load");
1259
1275
  try {
1260
1276
  e.stopLoad(), e.startLoad(-1);
@@ -1304,7 +1320,7 @@ var U = class {
1304
1320
  scheduleLicenseRetry(t) {
1305
1321
  if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
1306
1322
  let n = t.response?.code ?? 0;
1307
- if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= Re) return !1;
1323
+ if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= ze) return !1;
1308
1324
  this.licenseRecoveries += 1;
1309
1325
  let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
1310
1326
  return this.licenseRetryTimer = setTimeout(() => {
@@ -1336,7 +1352,7 @@ var U = class {
1336
1352
  return;
1337
1353
  }
1338
1354
  if (t.type === e.ErrorTypes.NETWORK_ERROR) {
1339
- if (this.networkRecoveries < Le) {
1355
+ if (this.networkRecoveries < Re) {
1340
1356
  this.networkRecoveries += 1;
1341
1357
  let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
1342
1358
  this.networkRetryTimer = setTimeout(() => {
@@ -1353,7 +1369,7 @@ var U = class {
1353
1369
  return;
1354
1370
  }
1355
1371
  if (t.type === e.ErrorTypes.MEDIA_ERROR) {
1356
- if (this.mediaRecoveries < Ie) {
1372
+ if (this.mediaRecoveries < Le) {
1357
1373
  this.mediaRecoveries += 1, n.recoverMediaError();
1358
1374
  return;
1359
1375
  }
@@ -1377,11 +1393,11 @@ var U = class {
1377
1393
  let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
1378
1394
  return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
1379
1395
  }
1380
- }, tt = 15e3, nt = 100, W = 1, rt = 1e3, G = 3e4, it = 1e3, at = {
1396
+ }, nt = 15e3, rt = 100, W = 1, it = 1e3, G = 3e4, at = 1e3, ot = {
1381
1397
  inline: "PRESENTATION_INLINE",
1382
1398
  fullscreen: "PRESENTATION_FULLSCREEN",
1383
1399
  pip: "PRESENTATION_PIP"
1384
- }, ot = {
1400
+ }, st = {
1385
1401
  widevine: "KEY_SYSTEM_WIDEVINE",
1386
1402
  fairplay: "KEY_SYSTEM_FAIRPLAY",
1387
1403
  none: "KEY_SYSTEM_NONE"
@@ -1389,7 +1405,7 @@ var U = class {
1389
1405
  function K(e, t) {
1390
1406
  return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
1391
1407
  }
1392
- var st = /* @__PURE__ */ new Set([
1408
+ var ct = /* @__PURE__ */ new Set([
1393
1409
  "INVALID_URN",
1394
1410
  "NOT_FOUND",
1395
1411
  "GONE",
@@ -1409,7 +1425,7 @@ var st = /* @__PURE__ */ new Set([
1409
1425
  ended: "PLAYER_STATE_ENDED",
1410
1426
  error: "PLAYER_STATE_ERROR"
1411
1427
  };
1412
- function ct(e) {
1428
+ function lt(e) {
1413
1429
  try {
1414
1430
  let t = new URL(e), [n, ...r] = t.hostname.split(".");
1415
1431
  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);
@@ -1417,7 +1433,7 @@ function ct(e) {
1417
1433
  return;
1418
1434
  }
1419
1435
  }
1420
- var lt = class {
1436
+ var ut = class {
1421
1437
  opts;
1422
1438
  url;
1423
1439
  now;
@@ -1489,7 +1505,7 @@ var lt = class {
1489
1505
  constructor(e) {
1490
1506
  this.opts = {
1491
1507
  ...e,
1492
- heartbeatMs: e.heartbeatMs ?? tt
1508
+ heartbeatMs: e.heartbeatMs ?? nt
1493
1509
  }, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`, this.now = e.now ?? (() => Date.now()), this.bornMs = this.now(), this.presentationSinceMs = this.bornMs, this.startupAnchorMs = this.bornMs;
1494
1510
  }
1495
1511
  start() {
@@ -1499,7 +1515,7 @@ var lt = class {
1499
1515
  sdkVersion: this.opts.sdkVersion,
1500
1516
  ...this.opts.environment
1501
1517
  };
1502
- this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), rt), this.timer = setInterval(() => this.heartbeat(), this.opts.heartbeatMs), typeof window < "u" && window.addEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.addEventListener("visibilitychange", this.onVisibility), this.onVisibility());
1518
+ this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), it), this.timer = setInterval(() => this.heartbeat(), this.opts.heartbeatMs), typeof window < "u" && window.addEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.addEventListener("visibilitychange", this.onVisibility), this.onVisibility());
1503
1519
  }
1504
1520
  noteStateChange(e, t, n, r) {
1505
1521
  if (this.endedFlag || e === t) return;
@@ -1513,12 +1529,12 @@ var lt = class {
1513
1529
  let a = {
1514
1530
  fromState: q[e] ?? "PLAYER_STATE_UNSPECIFIED",
1515
1531
  toState: q[t] ?? "PLAYER_STATE_UNSPECIFIED",
1516
- presentation: at[this.presentation]
1532
+ presentation: ot[this.presentation]
1517
1533
  }, o = this.causeOf(e, t, i);
1518
1534
  o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
1519
1535
  }
1520
1536
  seekInduced(e) {
1521
- return this.lastSeekMs >= 0 && e - this.lastSeekMs < it;
1537
+ return this.lastSeekMs >= 0 && e - this.lastSeekMs < at;
1522
1538
  }
1523
1539
  causeOf(e, t, n) {
1524
1540
  if (t === "error") return "TRANSITION_CAUSE_ERROR";
@@ -1586,7 +1602,7 @@ var lt = class {
1586
1602
  let r = n ?? "";
1587
1603
  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";
1588
1604
  if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
1589
- if (st.has(e)) return "ERROR_STAGE_RESOLVE";
1605
+ if (ct.has(e)) return "ERROR_STAGE_RESOLVE";
1590
1606
  let i = t ?? "";
1591
1607
  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";
1592
1608
  }
@@ -1638,7 +1654,7 @@ var lt = class {
1638
1654
  maybeEmitMediaInfo(e) {
1639
1655
  if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
1640
1656
  let t = {};
1641
- e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = ot[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);
1657
+ e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = st[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);
1642
1658
  let n = JSON.stringify(t);
1643
1659
  n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
1644
1660
  }
@@ -1678,7 +1694,7 @@ var lt = class {
1678
1694
  };
1679
1695
  }
1680
1696
  enqueue(e) {
1681
- for (this.pending.push(this.wrap(e)); this.pending.length > nt;) {
1697
+ for (this.pending.push(this.wrap(e)); this.pending.length > rt;) {
1682
1698
  let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
1683
1699
  this.pending.splice(e >= 0 ? e : 0, 1);
1684
1700
  }
@@ -1701,7 +1717,7 @@ var lt = class {
1701
1717
  };
1702
1718
  //#endregion
1703
1719
  //#region src/core/environment.ts
1704
- function ut() {
1720
+ function dt() {
1705
1721
  if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
1706
1722
  let e;
1707
1723
  try {
@@ -1726,14 +1742,14 @@ function ut() {
1726
1742
  integration: "INTEGRATION_KIND_IFRAME"
1727
1743
  };
1728
1744
  }
1729
- function dt() {
1745
+ function ft() {
1730
1746
  if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
1731
1747
  let e = navigator.userAgentData, t = e?.platform ?? "";
1732
1748
  if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
1733
1749
  let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
1734
1750
  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";
1735
1751
  }
1736
- function ft() {
1752
+ function pt() {
1737
1753
  let e = typeof navigator < "u" ? navigator.connection : void 0;
1738
1754
  if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
1739
1755
  let t = {
@@ -1752,17 +1768,17 @@ function ft() {
1752
1768
  }
1753
1769
  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;
1754
1770
  }
1755
- function pt(e) {
1756
- let t = ut(), n = {
1757
- deviceClass: dt(),
1771
+ function mt(e) {
1772
+ let t = dt(), n = {
1773
+ deviceClass: ft(),
1758
1774
  integration: t.integration,
1759
- ...ft()
1775
+ ...pt()
1760
1776
  };
1761
1777
  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);
1762
1778
  let r = e.getBoundingClientRect?.();
1763
1779
  return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
1764
1780
  }
1765
- async function mt() {
1781
+ async function ht() {
1766
1782
  let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
1767
1783
  if (!e?.getHighEntropyValues) return {};
1768
1784
  try {
@@ -1774,7 +1790,7 @@ async function mt() {
1774
1790
  }
1775
1791
  //#endregion
1776
1792
  //#region src/core/version.ts
1777
- var ht = "2.6.2", J = {
1793
+ var gt = "2.6.3", J = {
1778
1794
  accent: "#E1B600",
1779
1795
  accentText: "#1B1C23",
1780
1796
  background: "#0e0f13",
@@ -1807,15 +1823,15 @@ function X(e, t) {
1807
1823
  }
1808
1824
  //#endregion
1809
1825
  //#region src/ui/styles.ts
1810
- var Z = "havik-player-styles", gt = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n.havik-spinner{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";
1811
- function _t(e = document) {
1826
+ var Z = "havik-player-styles", _t = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n.havik-spinner{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";
1827
+ function vt(e = document) {
1812
1828
  if (e.getElementById(Z)) return;
1813
1829
  let t = e.createElement("style");
1814
- t.id = Z, t.textContent = gt, e.head.appendChild(t);
1830
+ t.id = Z, t.textContent = _t, e.head.appendChild(t);
1815
1831
  }
1816
1832
  //#endregion
1817
1833
  //#region src/ui/icons.ts
1818
- var vt = {
1834
+ var yt = {
1819
1835
  play: "<path d=\"M8 5v14l11-7z\"/>",
1820
1836
  pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
1821
1837
  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\"/>",
@@ -1829,20 +1845,20 @@ var vt = {
1829
1845
  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\"/>"
1830
1846
  };
1831
1847
  function Q(e) {
1832
- return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${vt[e]}</svg>`;
1848
+ return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${yt[e]}</svg>`;
1833
1849
  }
1834
1850
  //#endregion
1835
1851
  //#region src/ui/controls.ts
1836
- var yt = 3e3, bt = /* @__PURE__ */ new Set([
1852
+ var bt = 3e3, xt = /* @__PURE__ */ new Set([
1837
1853
  "GONE",
1838
1854
  "NOT_FOUND",
1839
1855
  "INVALID_URN",
1840
1856
  "UNAUTHORIZED"
1841
1857
  ]);
1842
- function xt(e) {
1843
- return new St(e);
1858
+ function St(e) {
1859
+ return new Ct(e);
1844
1860
  }
1845
- var St = class {
1861
+ var Ct = class {
1846
1862
  root;
1847
1863
  video;
1848
1864
  player;
@@ -1884,7 +1900,7 @@ var St = class {
1884
1900
  scrubbing = !1;
1885
1901
  offFns = [];
1886
1902
  constructor(e) {
1887
- this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? yt, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, _t(this.doc), this.root.classList.add("havik-player"), this.root.hasAttribute("tabindex") || (this.root.tabIndex = 0), this.root.setAttribute("role", "region"), this.root.setAttribute("aria-label", "Video player");
1903
+ this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? bt, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, vt(this.doc), this.root.classList.add("havik-player"), this.root.hasAttribute("tabindex") || (this.root.tabIndex = 0), this.root.setAttribute("role", "region"), this.root.setAttribute("aria-label", "Video player");
1888
1904
  let t = (e, t, n) => {
1889
1905
  let r = this.doc.createElement(e);
1890
1906
  if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
@@ -1975,7 +1991,7 @@ var St = class {
1975
1991
  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);
1976
1992
  } else {
1977
1993
  let r = this.doc.createElement("div");
1978
- if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !bt.has(this.lastError.code)) {
1994
+ if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !xt.has(this.lastError.code)) {
1979
1995
  let e = this.doc.createElement("button");
1980
1996
  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);
1981
1997
  }
@@ -2016,7 +2032,7 @@ var St = class {
2016
2032
  let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
2017
2033
  this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
2018
2034
  }
2019
- !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Ct(this.video.currentTime)} / ${Ct(this.video.duration)}`);
2035
+ !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${wt(this.video.currentTime)} / ${wt(this.video.duration)}`);
2020
2036
  }
2021
2037
  syncLive() {
2022
2038
  let e = this.player.getStats(), t = e.isLive !== !1;
@@ -2066,17 +2082,17 @@ var St = class {
2066
2082
  renderQualityMenu() {
2067
2083
  let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
2068
2084
  n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
2069
- for (let n of e) this.menu.append(this.menuItem(wt(n), t === n.index, () => this.player.setQuality(n.index)));
2085
+ for (let n of e) this.menu.append(this.menuItem(Tt(n), t === n.index, () => this.player.setQuality(n.index)));
2070
2086
  }
2071
2087
  renderAudioMenu() {
2072
2088
  let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
2073
2089
  t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
2074
- for (let t of e) this.menu.append(this.menuItem(Tt(t), t.default, () => this.player.setAudioTrack(t.id)));
2090
+ for (let t of e) this.menu.append(this.menuItem(Et(t), t.default, () => this.player.setAudioTrack(t.id)));
2075
2091
  }
2076
2092
  renderCcMenu() {
2077
2093
  let e = this.player.getTextTracks(), t = this.doc.createElement("div");
2078
2094
  t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
2079
- for (let t of e) this.menu.append(this.menuItem(Et(t), !1, () => this.player.setTextTrack(t.id)));
2095
+ for (let t of e) this.menu.append(this.menuItem(Dt(t), !1, () => this.player.setTextTrack(t.id)));
2080
2096
  }
2081
2097
  onTracksChanged() {
2082
2098
  this.openMenu && this.renderMenu(this.openMenu);
@@ -2176,32 +2192,32 @@ var St = class {
2176
2192
  this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
2177
2193
  }
2178
2194
  };
2179
- function Ct(e) {
2195
+ function wt(e) {
2180
2196
  (!Number.isFinite(e) || e < 0) && (e = 0);
2181
2197
  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");
2182
2198
  return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
2183
2199
  }
2184
- function wt(e) {
2200
+ function Tt(e) {
2185
2201
  return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
2186
2202
  }
2187
- function Tt(e) {
2203
+ function Et(e) {
2188
2204
  return e.name || e.lang || `Track ${e.id}`;
2189
2205
  }
2190
- function Et(e) {
2206
+ function Dt(e) {
2191
2207
  return e.name || e.lang || `Track ${e.id}`;
2192
2208
  }
2193
2209
  //#endregion
2194
2210
  //#region src/managed/index.ts
2195
- var Dt = 6e3, Ot = 45e3, kt = 2e3, At = 3, jt = 2e3, Mt = 48e4;
2196
- async function Nt(e) {
2211
+ var Ot = 6e3, kt = 45e3, At = 2e3, jt = 3, Mt = 2e3, Nt = 48e4;
2212
+ async function Pt(e) {
2197
2213
  if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
2198
2214
  if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: baseUrl is required");
2199
2215
  if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
2200
2216
  if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
2201
- let t = new Pt(e);
2217
+ let t = new Ft(e);
2202
2218
  return await t.start(), t;
2203
2219
  }
2204
- var Pt = class {
2220
+ var Ft = class {
2205
2221
  opts;
2206
2222
  abort = new AbortController();
2207
2223
  listeners = {};
@@ -2288,7 +2304,7 @@ var Pt = class {
2288
2304
  setTimeout(() => {
2289
2305
  a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
2290
2306
  phase: i ? "unavailable" : "tooEarly",
2291
- retryInMs: Ot,
2307
+ retryInMs: kt,
2292
2308
  attempt: 1,
2293
2309
  elapsedMs: 0,
2294
2310
  ...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
@@ -2327,13 +2343,13 @@ var Pt = class {
2327
2343
  !a && !p() && h();
2328
2344
  }, e);
2329
2345
  };
2330
- _(Dt), this.armingSub = E({
2346
+ _(Ot), this.armingSub = E({
2331
2347
  eventsBaseUrl: t,
2332
2348
  matchUrn: this.opts.matchUrn,
2333
2349
  credential: this.opts.credential,
2334
- onAlive: () => _(Ot),
2350
+ onAlive: () => _(kt),
2335
2351
  onState: (e) => {
2336
- a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * kt);
2352
+ a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * At);
2337
2353
  },
2338
2354
  onError: () => h()
2339
2355
  });
@@ -2356,7 +2372,7 @@ var Pt = class {
2356
2372
  let n = await s(this.opts.credential);
2357
2373
  if (this.destroyed || t !== this.loadGen) return;
2358
2374
  this.setState("loading");
2359
- let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = Me(this.opts.video, (e) => {
2375
+ let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = Ne(this.opts.video, (e) => {
2360
2376
  this._state !== "ended" && this._state !== "error" && this.setState(e);
2361
2377
  });
2362
2378
  if (await i.load(), this.destroyed || t !== this.loadGen) {
@@ -2375,14 +2391,14 @@ var Pt = class {
2375
2391
  if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
2376
2392
  let n = e.analytics?.sid;
2377
2393
  if (!n) return;
2378
- let r = (typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0) ?? ct(this.opts.baseUrl);
2394
+ let r = (typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0) ?? lt(this.opts.baseUrl);
2379
2395
  if (!r) return;
2380
- let i = this.opts.video, a = new lt({
2396
+ let i = this.opts.video, a = new ut({
2381
2397
  endpoint: r,
2382
2398
  sid: n,
2383
2399
  player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
2384
- sdkVersion: ht,
2385
- environment: pt(i),
2400
+ sdkVersion: gt,
2401
+ environment: mt(i),
2386
2402
  sample: () => {
2387
2403
  let e = this.engine?.getStats() ?? I, t = i.buffered.length ? Math.max(0, i.buffered.end(i.buffered.length - 1) - i.currentTime) : 0;
2388
2404
  return {
@@ -2398,7 +2414,7 @@ var Pt = class {
2398
2414
  let o = () => a.noteSeek(), s = () => a.noteVolume(i.muted, i.volume);
2399
2415
  i.addEventListener("seeking", o), i.addEventListener("volumechange", s), this.detachMediaListeners = () => {
2400
2416
  i.removeEventListener("seeking", o), i.removeEventListener("volumechange", s);
2401
- }, a.start(), a.seedVolume(i.muted, i.volume), a.notePresentation(this.currentPresentation()), mt().then((e) => a.noteEnvironment(e)), this.opts.autoplay === !1 && a.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
2417
+ }, a.start(), a.seedVolume(i.muted, i.volume), a.notePresentation(this.currentPresentation()), ht().then((e) => a.noteEnvironment(e)), this.opts.autoplay === !1 && a.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
2402
2418
  }
2403
2419
  currentPresentation() {
2404
2420
  let e = this.opts.video;
@@ -2425,7 +2441,7 @@ var Pt = class {
2425
2441
  if (o === "native") return new V(a);
2426
2442
  if (o === "hls") return new U(a);
2427
2443
  if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && z(this.opts.video) && B()) return new V(a);
2428
- if (Fe()) return new U(a);
2444
+ if (Ie()) return new U(a);
2429
2445
  if (z(this.opts.video)) return new V(a);
2430
2446
  throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
2431
2447
  }
@@ -2469,7 +2485,7 @@ var Pt = class {
2469
2485
  r = 0, i = !1;
2470
2486
  },
2471
2487
  onError: () => {
2472
- this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= At && (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.`))));
2488
+ this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= jt && (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.`))));
2473
2489
  }
2474
2490
  });
2475
2491
  }
@@ -2491,7 +2507,7 @@ var Pt = class {
2491
2507
  scheduleRejoin(e) {
2492
2508
  this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
2493
2509
  this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
2494
- }, Math.random() * kt));
2510
+ }, Math.random() * At));
2495
2511
  }
2496
2512
  cancelRejoin() {
2497
2513
  this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
@@ -2515,7 +2531,7 @@ var Pt = class {
2515
2531
  }
2516
2532
  t.controls = !1;
2517
2533
  let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
2518
- r && r.insertBefore(n, t), n.appendChild(t), X(n, this.opts.theme), this.container = n, this.controlBar = xt({
2534
+ r && r.insertBefore(n, t), n.appendChild(t), X(n, this.opts.theme), this.container = n, this.controlBar = St({
2519
2535
  root: n,
2520
2536
  video: t,
2521
2537
  player: this,
@@ -2545,7 +2561,7 @@ var Pt = class {
2545
2561
  }
2546
2562
  startStats() {
2547
2563
  this.stopStats();
2548
- let e = Math.max(500, this.opts.statsIntervalMs ?? jt);
2564
+ let e = Math.max(500, this.opts.statsIntervalMs ?? Mt);
2549
2565
  this.statsTimer = setInterval(() => {
2550
2566
  if (!this.engine) return;
2551
2567
  let e = this.engine.getStats();
@@ -2557,7 +2573,7 @@ var Pt = class {
2557
2573
  }
2558
2574
  scheduleLicenseRefresh() {
2559
2575
  this.stopRefresh();
2560
- let e = this.opts.licenseRefreshMs ?? Mt;
2576
+ let e = this.opts.licenseRefreshMs ?? Nt;
2561
2577
  e && this._descriptor?.drmEnabled && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
2562
2578
  }
2563
2579
  stopRefresh() {
@@ -2709,7 +2725,7 @@ function $(e) {
2709
2725
  }
2710
2726
  //#endregion
2711
2727
  //#region src/embed/host.ts
2712
- function Ft(e) {
2728
+ function It(e) {
2713
2729
  if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
2714
2730
  if (!e.src) throw Error("mountEmbed: opts.src is required");
2715
2731
  if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
@@ -2768,8 +2784,8 @@ function Ft(e) {
2768
2784
  }
2769
2785
  //#endregion
2770
2786
  //#region src/embed/page.ts
2771
- var It = /^[A-Za-z0-9:_.-]{1,128}$/;
2772
- function Lt() {
2787
+ var Lt = /^[A-Za-z0-9:_.-]{1,128}$/;
2788
+ function Rt() {
2773
2789
  let e = window.HAVIK_EMBED_CONFIG;
2774
2790
  if (e) return {
2775
2791
  baseUrl: e.baseUrl ?? "",
@@ -2791,9 +2807,9 @@ function Lt() {
2791
2807
  waitForLive: !0
2792
2808
  };
2793
2809
  }
2794
- async function Rt() {
2795
- let e = Lt();
2796
- Bt();
2810
+ async function zt() {
2811
+ let e = Rt();
2812
+ Vt();
2797
2813
  let t = document.createElement("video");
2798
2814
  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);
2799
2815
  let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
@@ -2848,12 +2864,12 @@ async function Rt() {
2848
2864
  code: e.code,
2849
2865
  message: e.message
2850
2866
  })), e.on("autoplayblocked", () => {
2851
- i({ type: "oddin:autoplayblocked" }), zt(t, e);
2867
+ i({ type: "oddin:autoplayblocked" }), Bt(t, e);
2852
2868
  });
2853
2869
  }, s = async (r) => {
2854
2870
  a?.destroy(), a = null;
2855
2871
  try {
2856
- let n = await Nt({
2872
+ let n = await Pt({
2857
2873
  video: t,
2858
2874
  baseUrl: e.baseUrl,
2859
2875
  matchUrn: r,
@@ -2914,7 +2930,7 @@ async function Rt() {
2914
2930
  a?.retry();
2915
2931
  break;
2916
2932
  case "oddin:load":
2917
- typeof e.matchUrn == "string" && It.test(e.matchUrn) && s(e.matchUrn);
2933
+ typeof e.matchUrn == "string" && Lt.test(e.matchUrn) && s(e.matchUrn);
2918
2934
  break;
2919
2935
  case "oddin:destroy": c();
2920
2936
  }
@@ -2926,18 +2942,18 @@ async function Rt() {
2926
2942
  protocol: 1
2927
2943
  });
2928
2944
  }
2929
- function zt(e, t) {
2945
+ function Bt(e, t) {
2930
2946
  if (document.getElementById("havik-tap")) return;
2931
2947
  let n = document.createElement("button");
2932
2948
  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", () => {
2933
2949
  n.remove(), t.play();
2934
2950
  }), document.body.appendChild(n);
2935
2951
  }
2936
- function Bt() {
2952
+ function Vt() {
2937
2953
  let e = document.createElement("style");
2938
2954
  e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
2939
2955
  }
2940
2956
  //#endregion
2941
- export { J as ODDIN_THEME, n as PlaybackError, X as applyTheme, Rt as bootEmbed, ge as clearDeviceId, Nt as createPlayer, D as deriveEventsBaseUrl, De as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, ue as fetchCatalog, fe as fetchTournament, me as flattenMatches, A as getDeviceId, ke as isLowLatencyManifest, $ as isOddinMessage, ve as licenseRequestHeaders, Ft as mountEmbed, oe as pollToLive, y as resolveStream, E as subscribeLiveState, C as videoFullscreenActive, he as watchStatus };
2957
+ export { J as ODDIN_THEME, n as PlaybackError, X as applyTheme, zt as bootEmbed, _e as clearDeviceId, Pt as createPlayer, D as deriveEventsBaseUrl, Oe as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, ue as fetchCatalog, fe as fetchTournament, me as flattenMatches, A as getDeviceId, Ae as isLowLatencyManifest, $ as isOddinMessage, ye as licenseRequestHeaders, It as mountEmbed, oe as pollToLive, y as resolveStream, E as subscribeLiveState, C as videoFullscreenActive, he as watchStatus };
2942
2958
 
2943
2959
  //# sourceMappingURL=index.js.map