@oddin-gg/havik-player 2.9.0 → 2.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -551,7 +551,7 @@ var N = ["SW_SECURE_DECODE", "SW_SECURE_CRYPTO"];
551
551
  function xe(e) {
552
552
  return e.startsWith("com.widevine");
553
553
  }
554
- function P(e, t) {
554
+ function Se(e, t) {
555
555
  if (!xe(e)) return t;
556
556
  let n = (e, t) => {
557
557
  let n = e.videoCapabilities;
@@ -568,8 +568,8 @@ function P(e, t) {
568
568
  })));
569
569
  return [...t, ...r];
570
570
  }
571
- function Se(e) {
572
- return (t, n) => M() ? navigator.requestMediaKeySystemAccess(t, P(t, n)).then((t) => ({
571
+ function Ce(e) {
572
+ return (t, n) => M() ? navigator.requestMediaKeySystemAccess(t, Se(t, n)).then((t) => ({
573
573
  keySystem: t.keySystem,
574
574
  getConfiguration: () => t.getConfiguration(),
575
575
  createMediaKeys: () => be(e, t)
@@ -577,11 +577,11 @@ function Se(e) {
577
577
  }
578
578
  //#endregion
579
579
  //#region src/core/drm/support.ts
580
- var Ce = 5e3, F = "video/mp4; codecs=\"avc1.42E01E\"", I = "audio/mp4; codecs=\"mp4a.40.2\"", we = {
580
+ var we = 5e3, Te = "video/mp4; codecs=\"avc1.42E01E\"", Ee = "audio/mp4; codecs=\"mp4a.40.2\"", De = {
581
581
  widevine: ["com.widevine.alpha"],
582
582
  fairplay: ["com.apple.fps"]
583
583
  };
584
- function Te(e) {
584
+ function Oe(e) {
585
585
  return e === "fairplay" ? [{
586
586
  initDataTypes: [
587
587
  "sinf",
@@ -589,30 +589,30 @@ function Te(e) {
589
589
  "cenc"
590
590
  ],
591
591
  videoCapabilities: [{
592
- contentType: F,
592
+ contentType: Te,
593
593
  robustness: "",
594
594
  encryptionScheme: "cbcs"
595
595
  }],
596
596
  audioCapabilities: [{
597
- contentType: I,
597
+ contentType: Ee,
598
598
  robustness: "",
599
599
  encryptionScheme: "cbcs"
600
600
  }]
601
- }] : P("com.widevine.alpha", [{
601
+ }] : Se("com.widevine.alpha", [{
602
602
  initDataTypes: ["cenc"],
603
603
  videoCapabilities: [{
604
- contentType: F,
604
+ contentType: Te,
605
605
  robustness: "SW_SECURE_DECODE",
606
606
  encryptionScheme: "cbcs"
607
607
  }],
608
608
  audioCapabilities: [{
609
- contentType: I,
609
+ contentType: Ee,
610
610
  robustness: "SW_SECURE_CRYPTO",
611
611
  encryptionScheme: "cbcs"
612
612
  }]
613
613
  }]);
614
614
  }
615
- function L(e, t) {
615
+ function P(e, t) {
616
616
  return new Promise((n, r) => {
617
617
  let i = setTimeout(() => r(/* @__PURE__ */ Error("probe-timeout")), t);
618
618
  e.then((e) => {
@@ -622,8 +622,8 @@ function L(e, t) {
622
622
  });
623
623
  });
624
624
  }
625
- async function Ee(e = {}) {
626
- let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Ce, r = {};
625
+ async function ke(e = {}) {
626
+ let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? we, r = {};
627
627
  if (typeof window < "u" && window.isSecureContext === !1) return {
628
628
  verdict: "insecure-context",
629
629
  detail: r
@@ -635,7 +635,7 @@ async function Ee(e = {}) {
635
635
  };
636
636
  let a = !1, o = !1, s = Date.now() + n, c = () => Math.max(1, s - Date.now());
637
637
  for (let e of t) {
638
- let t = we[e];
638
+ let t = De[e];
639
639
  if (!t) {
640
640
  r[e] = "unknown system";
641
641
  continue;
@@ -646,7 +646,7 @@ async function Ee(e = {}) {
646
646
  break;
647
647
  }
648
648
  try {
649
- return await L((await L(i(n, Te(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
649
+ return await P((await P(i(n, Oe(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
650
650
  verdict: "supported",
651
651
  system: e,
652
652
  detail: r
@@ -670,49 +670,49 @@ async function Ee(e = {}) {
670
670
  }
671
671
  //#endregion
672
672
  //#region src/core/manifest.ts
673
- var De = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
674
- function Oe(e) {
675
- return De.test(e);
673
+ var Ae = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
674
+ function je(e) {
675
+ return Ae.test(e);
676
676
  }
677
677
  //#endregion
678
678
  //#region src/core/env.ts
679
- var R = {
679
+ var F = {
680
680
  integration: "https://feed-dev.oddin-video.gg",
681
681
  production: "https://feed.oddin-video.gg"
682
682
  };
683
- function z(e) {
684
- let t = Object.prototype.hasOwnProperty.call(R, e) ? R[e] : void 0;
683
+ function I(e) {
684
+ let t = Object.prototype.hasOwnProperty.call(F, e) ? F[e] : void 0;
685
685
  if (!t) throw new n("INTERNAL", 0, `unknown env ${JSON.stringify(e)} — expected 'integration' or 'production'`);
686
686
  return t;
687
687
  }
688
688
  //#endregion
689
689
  //#region src/core/stats.ts
690
- var B = { droppedFrames: 0 };
691
- function V(e) {
690
+ var L = { droppedFrames: 0 };
691
+ function R(e) {
692
692
  try {
693
693
  return new URL(e).host;
694
694
  } catch {
695
695
  return "";
696
696
  }
697
697
  }
698
- var ke = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
699
- function Ae(e) {
698
+ var Me = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
699
+ function Ne(e) {
700
700
  if (typeof performance > "u" || typeof performance.getEntriesByType != "function") return "";
701
701
  let t = "", n = -1, r = performance.getEntriesByType("resource");
702
- for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || ke.test(i.name)) && i.startTime >= n) {
703
- let e = V(i.name);
702
+ for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || Me.test(i.name)) && i.startTime >= n) {
703
+ let e = R(i.name);
704
704
  e && (t = e, n = i.startTime);
705
705
  }
706
706
  return t;
707
707
  }
708
- function H(e) {
708
+ function z(e) {
709
709
  let t = e.getVideoPlaybackQuality?.();
710
710
  return {
711
711
  dropped: t?.droppedVideoFrames ?? 0,
712
712
  totalFrames: t?.totalVideoFrames ?? 0
713
713
  };
714
714
  }
715
- function je(e, t) {
715
+ function Pe(e, t) {
716
716
  let n = [
717
717
  ["playing", () => t("playing")],
718
718
  ["waiting", () => t("buffering")],
@@ -729,7 +729,7 @@ function je(e, t) {
729
729
  }
730
730
  //#endregion
731
731
  //#region src/core/engine/native.ts
732
- function Me(e) {
732
+ function Fe(e) {
733
733
  try {
734
734
  let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
735
735
  return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
@@ -737,15 +737,15 @@ function Me(e) {
737
737
  return;
738
738
  }
739
739
  }
740
- function U(e) {
740
+ function B(e) {
741
741
  return !!(e ?? (typeof document < "u" ? document.createElement("video") : void 0))?.canPlayType("application/vnd.apple.mpegurl");
742
742
  }
743
- function W() {
743
+ function V() {
744
744
  if (typeof window > "u") return !1;
745
745
  let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
746
746
  return e || t;
747
747
  }
748
- var G = class {
748
+ var H = class {
749
749
  name = "native";
750
750
  deps;
751
751
  onLoaded;
@@ -781,7 +781,7 @@ var G = class {
781
781
  type: "error",
782
782
  error: new n("INTERNAL", 0, "native HLS playback error"),
783
783
  fatal: !0
784
- }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = Ne(t.manifestUrl, t.analytics?.sid), e.load();
784
+ }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = Ie(t.manifestUrl, t.analytics?.sid), e.load();
785
785
  }
786
786
  startLoad() {
787
787
  this.loadStarted || (this.loadStarted = !0, this.restorePreload());
@@ -803,7 +803,7 @@ var G = class {
803
803
  });
804
804
  this.onEncrypted = (n) => {
805
805
  let i = n;
806
- i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = Me(i.initData), (async () => {
806
+ i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = Fe(i.initData), (async () => {
807
807
  try {
808
808
  let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
809
809
  initDataTypes: [i.initDataType],
@@ -898,11 +898,11 @@ var G = class {
898
898
  e.seekable.length > 0 && (e.currentTime = e.seekable.end(e.seekable.length - 1));
899
899
  }
900
900
  getStats() {
901
- let e = this.deps.video, t = H(e), n = {
901
+ let e = this.deps.video, t = z(e), n = {
902
902
  droppedFrames: t.dropped,
903
903
  decodedFrames: t.totalFrames
904
904
  };
905
- return this.cdnHost ||= Ae(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;
905
+ return this.cdnHost ||= Ne(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;
906
906
  }
907
907
  stop() {
908
908
  try {
@@ -921,29 +921,29 @@ var G = class {
921
921
  } catch {}
922
922
  }
923
923
  };
924
- function Ne(e, t) {
924
+ function Ie(e, t) {
925
925
  return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
926
926
  }
927
927
  //#endregion
928
928
  //#region src/core/engine/hls.ts
929
- function Pe() {
929
+ function Le() {
930
930
  return e.isSupported();
931
931
  }
932
- var Fe = 3, Ie = 5, Le = 3, Re = 3e4, ze = 12e3, Be = 3e3, K = 6e3, Ve = 5e3, He = 4e3, Ue = 2, We = 5, Ge = 2, Ke = 2, qe = 2e3, Je = 3e4, Ye = 2, Xe = 9, Ze = .5, Qe = 64;
933
- function $e(e) {
932
+ var Re = 3, ze = 5, Be = 3, Ve = 3e4, He = 12e3, Ue = 3e3, U = 6e3, We = 5e3, Ge = 4e3, Ke = 2, qe = 5, Je = 2, Ye = 2, Xe = 2e3, Ze = 3e4, Qe = 2, $e = 9, et = .5, tt = 64;
933
+ function nt(e) {
934
934
  if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
935
935
  delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
936
936
  return;
937
937
  }
938
- e.liveSyncDuration ??= Ye;
939
- let t = Math.max(12, e.liveSyncDuration + Xe);
940
- (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), et(e, e.liveSyncDuration);
938
+ e.liveSyncDuration ??= Qe;
939
+ let t = Math.max(12, e.liveSyncDuration + $e);
940
+ (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), rt(e, e.liveSyncDuration);
941
941
  }
942
- function et(e, t) {
942
+ function rt(e, t) {
943
943
  let n = (e, t, n) => Math.min(n, Math.max(t, e));
944
944
  e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
945
945
  }
946
- var q = class {
946
+ var W = class {
947
947
  name = "hls";
948
948
  hls = null;
949
949
  deps;
@@ -1002,7 +1002,7 @@ var q = class {
1002
1002
  this.deps = e, this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
1003
1003
  }
1004
1004
  async load() {
1005
- let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = U(r) && W(), o = !!e.drm?.widevine?.licenseUrl && !a;
1005
+ let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = B(r) && V(), o = !!e.drm?.widevine?.licenseUrl && !a;
1006
1006
  if (e.drmEnabled && !o) {
1007
1007
  i({
1008
1008
  type: "error",
@@ -1034,7 +1034,7 @@ var q = class {
1034
1034
  }
1035
1035
  this.loadSuspended = !0;
1036
1036
  }
1037
- }, Ve));
1037
+ }, We));
1038
1038
  }
1039
1039
  resumeLoading() {
1040
1040
  if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
@@ -1066,7 +1066,7 @@ var q = class {
1066
1066
  let t = e.liveSyncPosition;
1067
1067
  if (typeof t != "number" || !Number.isFinite(t)) return;
1068
1068
  let { video: n } = this.deps;
1069
- n.currentTime <= t + Ze || (n.currentTime = t);
1069
+ n.currentTime <= t + et || (n.currentTime = t);
1070
1070
  }
1071
1071
  startHls() {
1072
1072
  let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps;
@@ -1090,7 +1090,7 @@ var q = class {
1090
1090
  videoEncryptionScheme: "cbcs",
1091
1091
  audioEncryptionScheme: "cbcs"
1092
1092
  },
1093
- ...M() ? { requestMediaKeySystemAccessFunc: Se(t) } : {},
1093
+ ...M() ? { requestMediaKeySystemAccessFunc: Ce(t) } : {},
1094
1094
  licenseXhrSetup: (e, t) => {
1095
1095
  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;
1096
1096
  let o = performance.now();
@@ -1106,7 +1106,7 @@ var q = class {
1106
1106
  } } : {},
1107
1107
  ...c
1108
1108
  };
1109
- $e(d), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.loadStarted = d.autoStartLoad !== !1;
1109
+ nt(d), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.loadStarted = d.autoStartLoad !== !1;
1110
1110
  let f = new e(d);
1111
1111
  this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
1112
1112
  this.mediaRecoveries = 0, this.networkRecoveries = 0;
@@ -1115,17 +1115,17 @@ var q = class {
1115
1115
  }), f.on(e.Events.FRAG_BUFFERED, (e, t) => {
1116
1116
  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(() => {
1117
1117
  this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
1118
- }, Re)));
1118
+ }, Ve)));
1119
1119
  }), f.on(e.Events.FRAG_LOADING, (e, t) => {
1120
1120
  t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
1121
1121
  }), f.on(e.Events.FRAG_LOADED, (e, t) => {
1122
1122
  let n = t?.frag?.stats, r = n?.loaded;
1123
1123
  typeof r == "number" && (this.bytesLoaded += r);
1124
1124
  let i = n?.loading;
1125
- 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());
1125
+ 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 > tt && this.requestTimesMs.shift());
1126
1126
  let a = t?.frag?.url;
1127
1127
  if (a) {
1128
- let e = V(a);
1128
+ let e = R(a);
1129
1129
  e && (this.cdnHost = e);
1130
1130
  }
1131
1131
  }), f.on(e.Events.LEVEL_LOADED, (e, t) => {
@@ -1138,7 +1138,7 @@ var q = class {
1138
1138
  }));
1139
1139
  }), f.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
1140
1140
  this.checkEndStale(), this.checkStarvation();
1141
- }, Be), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1141
+ }, Ue), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1142
1142
  this.renditionSwitches += 1;
1143
1143
  let n = this.lastLevelIndex >= 0 ? f.levels[this.lastLevelIndex] : void 0, r = f.levels[t.level];
1144
1144
  n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, l({
@@ -1202,7 +1202,7 @@ var q = class {
1202
1202
  return;
1203
1203
  }
1204
1204
  this.capTimer && clearTimeout(this.capTimer);
1205
- let t = e > this.sizeCapLevel ? qe : Je;
1205
+ let t = e > this.sizeCapLevel ? Xe : Ze;
1206
1206
  this.capTimer = setTimeout(() => {
1207
1207
  this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
1208
1208
  }, t);
@@ -1249,7 +1249,7 @@ var q = class {
1249
1249
  e.widevine && (this.licenseUrl = e.widevine);
1250
1250
  }
1251
1251
  getStats() {
1252
- let e = this.hls, t = H(this.deps.video), n = {
1252
+ let e = this.hls, t = z(this.deps.video), n = {
1253
1253
  droppedFrames: t.dropped,
1254
1254
  decodedFrames: t.totalFrames,
1255
1255
  lowLatency: this.detectedLowLatency,
@@ -1295,7 +1295,7 @@ var q = class {
1295
1295
  return;
1296
1296
  }
1297
1297
  let e = Date.now() - this.lastAdvanceMs;
1298
- !this.chaseSuspended && e > K && this.suspendChasing(), e > ze && this.emitEnded("stalled");
1298
+ !this.chaseSuspended && e > U && this.suspendChasing(), e > He && this.emitEnded("stalled");
1299
1299
  }
1300
1300
  checkStarvation() {
1301
1301
  let e = this.hls, { video: t } = this.deps;
@@ -1304,17 +1304,17 @@ var q = class {
1304
1304
  this.starvedTicks = 0;
1305
1305
  return;
1306
1306
  }
1307
- let n = this.lastAdvanceMs !== 0 && Date.now() - this.lastAdvanceMs < K, r = this.lastFragLoadingMs !== 0 && Date.now() - this.lastFragLoadingMs > He;
1307
+ let n = this.lastAdvanceMs !== 0 && Date.now() - this.lastAdvanceMs < U, r = this.lastFragLoadingMs !== 0 && Date.now() - this.lastFragLoadingMs > Ge;
1308
1308
  if (!(t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused && n && r)) {
1309
1309
  this.starvedTicks = 0;
1310
1310
  return;
1311
1311
  }
1312
- if (this.kickPending && (this.kickTicks += 1), !(++this.starvedTicks < Ue)) {
1313
- if (this.starvedTicks = 0, this.kickPending && this.kickTicks >= Ge && (this.kickPending = !1, this.kickTicks = 0, this.starvationRebuilds < Ke)) {
1312
+ if (this.kickPending && (this.kickTicks += 1), !(++this.starvedTicks < Ke)) {
1313
+ if (this.starvedTicks = 0, this.kickPending && this.kickTicks >= Je && (this.kickPending = !1, this.kickTicks = 0, this.starvationRebuilds < Ye)) {
1314
1314
  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");
1315
1315
  return;
1316
1316
  }
1317
- if (!(this.starvationKicks >= We)) {
1317
+ if (!(this.starvationKicks >= qe)) {
1318
1318
  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");
1319
1319
  try {
1320
1320
  e.stopLoad(), e.startLoad(-1);
@@ -1364,7 +1364,7 @@ var q = class {
1364
1364
  scheduleLicenseRetry(t) {
1365
1365
  if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
1366
1366
  let n = t.response?.code ?? 0;
1367
- if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= Le) return !1;
1367
+ if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= Be) return !1;
1368
1368
  this.licenseRecoveries += 1;
1369
1369
  let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
1370
1370
  return this.licenseRetryTimer = setTimeout(() => {
@@ -1396,7 +1396,7 @@ var q = class {
1396
1396
  return;
1397
1397
  }
1398
1398
  if (t.type === e.ErrorTypes.NETWORK_ERROR) {
1399
- if (this.networkRecoveries < Ie) {
1399
+ if (this.networkRecoveries < ze) {
1400
1400
  this.networkRecoveries += 1;
1401
1401
  let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
1402
1402
  this.networkRetryTimer = setTimeout(() => {
@@ -1413,7 +1413,7 @@ var q = class {
1413
1413
  return;
1414
1414
  }
1415
1415
  if (t.type === e.ErrorTypes.MEDIA_ERROR) {
1416
- if (this.mediaRecoveries < Fe) {
1416
+ if (this.mediaRecoveries < Re) {
1417
1417
  this.mediaRecoveries += 1, n.recoverMediaError();
1418
1418
  return;
1419
1419
  }
@@ -1437,19 +1437,19 @@ var q = class {
1437
1437
  let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
1438
1438
  return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
1439
1439
  }
1440
- }, tt = 15e3, nt = 6e5, rt = 3e5, it = 100, J = 1, at = 1e3, ot = 3e4, st = 1e3, ct = {
1440
+ }, it = 15e3, at = 6e5, ot = 3e5, st = 100, G = 1, ct = 1e3, K = 3e4, lt = 1e3, ut = {
1441
1441
  inline: "PRESENTATION_INLINE",
1442
1442
  fullscreen: "PRESENTATION_FULLSCREEN",
1443
1443
  pip: "PRESENTATION_PIP"
1444
- }, lt = {
1444
+ }, dt = {
1445
1445
  widevine: "KEY_SYSTEM_WIDEVINE",
1446
1446
  fairplay: "KEY_SYSTEM_FAIRPLAY",
1447
1447
  none: "KEY_SYSTEM_NONE"
1448
1448
  };
1449
- function ut(e, t) {
1449
+ function q(e, t) {
1450
1450
  return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
1451
1451
  }
1452
- var dt = /* @__PURE__ */ new Set([
1452
+ var ft = /* @__PURE__ */ new Set([
1453
1453
  "INVALID_URN",
1454
1454
  "NOT_FOUND",
1455
1455
  "GONE",
@@ -1459,7 +1459,7 @@ var dt = /* @__PURE__ */ new Set([
1459
1459
  "FORBIDDEN",
1460
1460
  "RATE_LIMITED",
1461
1461
  "TIMEOUT"
1462
- ]), Y = {
1462
+ ]), J = {
1463
1463
  idle: "PLAYER_STATE_IDLE",
1464
1464
  waiting: "PLAYER_STATE_WAITING",
1465
1465
  loading: "PLAYER_STATE_LOADING",
@@ -1469,7 +1469,7 @@ var dt = /* @__PURE__ */ new Set([
1469
1469
  ended: "PLAYER_STATE_ENDED",
1470
1470
  error: "PLAYER_STATE_ERROR"
1471
1471
  };
1472
- function ft(e) {
1472
+ function pt(e) {
1473
1473
  try {
1474
1474
  let t = new URL(e), [n, ...r] = t.hostname.split(".");
1475
1475
  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);
@@ -1477,7 +1477,24 @@ function ft(e) {
1477
1477
  return;
1478
1478
  }
1479
1479
  }
1480
- var pt = class {
1480
+ var Y = /* @__PURE__ */ new Set();
1481
+ function X(e, t) {
1482
+ return Y.has(e) || (Y.add(e), console.warn(`havik-player: ${t}`)), { disabledReason: t };
1483
+ }
1484
+ function mt(e, t) {
1485
+ if (t) return { endpoint: t };
1486
+ if (t !== void 0) return X("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).");
1487
+ let n = pt(e);
1488
+ if (n) return { endpoint: n };
1489
+ let r;
1490
+ try {
1491
+ r = new URL(e).hostname || e;
1492
+ } catch {
1493
+ r = e;
1494
+ }
1495
+ return X(r, `analytics is disabled: no QoE beacons will be sent. The beacons endpoint cannot be derived from the baseUrl host "${r}" — the convention is feed[-dev].<domain> → beacons[-dev].<domain>. Pass an explicit endpoint, analytics: { endpoint: 'https://beacons[-dev].<domain>' }, to createPlayer (or analytics: false to opt out deliberately).`);
1496
+ }
1497
+ var ht = class {
1481
1498
  opts;
1482
1499
  url;
1483
1500
  now;
@@ -1555,8 +1572,8 @@ var pt = class {
1555
1572
  constructor(e) {
1556
1573
  this.opts = {
1557
1574
  ...e,
1558
- heartbeatMs: e.heartbeatMs ?? tt,
1559
- idleMs: e.idleMs ?? nt
1575
+ heartbeatMs: e.heartbeatMs ?? it,
1576
+ idleMs: e.idleMs ?? at
1560
1577
  }, 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;
1561
1578
  }
1562
1579
  start() {
@@ -1566,11 +1583,11 @@ var pt = class {
1566
1583
  sdkVersion: this.opts.sdkVersion,
1567
1584
  ...this.opts.environment
1568
1585
  };
1569
- this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), at), this.lastTickMs = this.now(), this.timer = setInterval(() => this.heartbeat(), this.opts.heartbeatMs), typeof window < "u" && window.addEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.addEventListener("visibilitychange", this.onVisibility), document.addEventListener("freeze", this.onFreeze), document.addEventListener("resume", this.onResume), this.onVisibility());
1586
+ this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), ct), this.lastTickMs = this.now(), this.timer = setInterval(() => this.heartbeat(), this.opts.heartbeatMs), typeof window < "u" && window.addEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.addEventListener("visibilitychange", this.onVisibility), document.addEventListener("freeze", this.onFreeze), document.addEventListener("resume", this.onResume), this.onVisibility());
1570
1587
  }
1571
1588
  checkSuspension(e) {
1572
1589
  if (this.endedFlag || !this.opts.idleMs) return !1;
1573
- let t = Math.max(this.opts.idleMs, rt);
1590
+ let t = Math.max(this.opts.idleMs, ot);
1574
1591
  return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
1575
1592
  }
1576
1593
  syncIdle(e) {
@@ -1584,21 +1601,21 @@ var pt = class {
1584
1601
  noteStateChange(e, t, n, r) {
1585
1602
  if (this.endedFlag || e === t) return;
1586
1603
  let i = this.now();
1587
- if (t === "playing" ? (this.playingSinceMs === null && (this.playingSinceMs = i), this.startupTimeMs === 0 && (this.startupTimeMs = Math.max(J, i - this.startupAnchorMs)), this.firstAudioMs === 0 && !this.isMuted && (this.firstAudioMs = Math.max(J, i - this.startupAnchorMs)), this.isMuted && this.mutedSinceMs === null && (this.mutedSinceMs = i)) : this.playingSinceMs !== null && (this.playingTotalMs += i - this.playingSinceMs, this.playingSinceMs = null, this.mutedSinceMs !== null && (this.mutedTotalMs += i - this.mutedSinceMs, this.mutedSinceMs = null)), this.isPlaying = t === "playing", this.syncActive(), t === "waiting" ? this.waitingSinceMs = i : this.waitingSinceMs !== null && (this.waitingTotalMs += i - this.waitingSinceMs, this.waitingSinceMs = null), t === "buffering" && e === "playing") {
1604
+ if (t === "playing" ? (this.playingSinceMs === null && (this.playingSinceMs = i), this.startupTimeMs === 0 && (this.startupTimeMs = Math.max(G, i - this.startupAnchorMs)), this.firstAudioMs === 0 && !this.isMuted && (this.firstAudioMs = Math.max(G, i - this.startupAnchorMs)), this.isMuted && this.mutedSinceMs === null && (this.mutedSinceMs = i)) : this.playingSinceMs !== null && (this.playingTotalMs += i - this.playingSinceMs, this.playingSinceMs = null, this.mutedSinceMs !== null && (this.mutedTotalMs += i - this.mutedSinceMs, this.mutedSinceMs = null)), this.isPlaying = t === "playing", this.syncActive(), t === "waiting" ? this.waitingSinceMs = i : this.waitingSinceMs !== null && (this.waitingTotalMs += i - this.waitingSinceMs, this.waitingSinceMs = null), t === "buffering" && e === "playing") {
1588
1605
  this.stallIsSeekInduced = this.seekInduced(i);
1589
1606
  let e = !this.isHidden && !this.stallIsSeekInduced;
1590
- e && (this.rebufferCount += 1), this.isBuffering = !0, this.lastStallMs = i, e && this.timeToFirstStallMs === 0 && (this.timeToFirstStallMs = Math.max(J, Math.round(this.playingTotalMs)));
1607
+ e && (this.rebufferCount += 1), this.isBuffering = !0, this.lastStallMs = i, e && this.timeToFirstStallMs === 0 && (this.timeToFirstStallMs = Math.max(G, Math.round(this.playingTotalMs)));
1591
1608
  } else e === "buffering" && (this.isBuffering = !1, this.stallIsSeekInduced = !1);
1592
1609
  this.syncBuffering(), t === "paused" && (this.pauseCount += 1), this.syncIdle(t);
1593
1610
  let a = {
1594
- fromState: Y[e] ?? "PLAYER_STATE_UNSPECIFIED",
1595
- toState: Y[t] ?? "PLAYER_STATE_UNSPECIFIED",
1596
- presentation: ct[this.presentation]
1611
+ fromState: J[e] ?? "PLAYER_STATE_UNSPECIFIED",
1612
+ toState: J[t] ?? "PLAYER_STATE_UNSPECIFIED",
1613
+ presentation: ut[this.presentation]
1597
1614
  }, o = this.causeOf(e, t, i);
1598
1615
  o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
1599
1616
  }
1600
1617
  seekInduced(e) {
1601
- return this.lastSeekMs >= 0 && e - this.lastSeekMs < st;
1618
+ return this.lastSeekMs >= 0 && e - this.lastSeekMs < lt;
1602
1619
  }
1603
1620
  causeOf(e, t, n) {
1604
1621
  if (t === "error") return "TRANSITION_CAUSE_ERROR";
@@ -1635,19 +1652,19 @@ var pt = class {
1635
1652
  }
1636
1653
  this.muteChanges += 1;
1637
1654
  let r = this.now();
1638
- n ? this.isPlaying && this.mutedSinceMs === null && (this.mutedSinceMs = r) : (this.mutedSinceMs !== null && (this.mutedTotalMs += r - this.mutedSinceMs, this.mutedSinceMs = null), this.firstAudioMs === 0 && this.isPlaying && (this.firstAudioMs = Math.max(J, r - this.startupAnchorMs))), this.isMuted = n, this.syncActive();
1655
+ n ? this.isPlaying && this.mutedSinceMs === null && (this.mutedSinceMs = r) : (this.mutedSinceMs !== null && (this.mutedTotalMs += r - this.mutedSinceMs, this.mutedSinceMs = null), this.firstAudioMs === 0 && this.isPlaying && (this.firstAudioMs = Math.max(G, r - this.startupAnchorMs))), this.isMuted = n, this.syncActive();
1639
1656
  }
1640
1657
  notePresentation(e) {
1641
1658
  this.endedFlag || e === this.presentation || (this.closePresentation(), this.presentation = e);
1642
1659
  }
1643
1660
  notePlayIntent() {
1644
- this.endedFlag || this.startupTimeMs > 0 || (this.startupAnchorMs = this.now(), this.manifestLoadMs > 0 && (this.manifestLoadMs = J), this.firstFragLoadMs > 0 && (this.firstFragLoadMs = J));
1661
+ this.endedFlag || this.startupTimeMs > 0 || (this.startupAnchorMs = this.now(), this.manifestLoadMs > 0 && (this.manifestLoadMs = G), this.firstFragLoadMs > 0 && (this.firstFragLoadMs = G));
1645
1662
  }
1646
1663
  noteReady() {
1647
- this.manifestLoadMs === 0 && (this.manifestLoadMs = Math.max(J, this.now() - this.startupAnchorMs));
1664
+ this.manifestLoadMs === 0 && (this.manifestLoadMs = Math.max(G, this.now() - this.startupAnchorMs));
1648
1665
  }
1649
1666
  noteFirstBytes() {
1650
- this.sawFirstBytes = !0, this.firstFragLoadMs === 0 && (this.firstFragLoadMs = Math.max(J, this.now() - this.startupAnchorMs));
1667
+ this.sawFirstBytes = !0, this.firstFragLoadMs === 0 && (this.firstFragLoadMs = Math.max(G, this.now() - this.startupAnchorMs));
1651
1668
  }
1652
1669
  noteSeek() {
1653
1670
  this.endedFlag || (this.seekCount += 1, this.lastSeekMs = this.now());
@@ -1666,7 +1683,7 @@ var pt = class {
1666
1683
  let r = n ?? "";
1667
1684
  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";
1668
1685
  if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
1669
- if (dt.has(e)) return "ERROR_STAGE_RESOLVE";
1686
+ if (ft.has(e)) return "ERROR_STAGE_RESOLVE";
1670
1687
  let i = t ?? "";
1671
1688
  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";
1672
1689
  }
@@ -1698,7 +1715,7 @@ var pt = class {
1698
1715
  let l = t.droppedFrames ?? 0;
1699
1716
  l > this.lastDropped && (o.droppedFramesDelta = l - this.lastDropped), this.lastDropped = l;
1700
1717
  let u = t.renditionSwitches ?? 0;
1701
- u > this.lastSwitches && (o.renditionSwitchesDelta = u - this.lastSwitches), this.lastSwitches = u, n > this.lastHbPlayingMs && (o.playingMsDelta = Math.round(n - this.lastHbPlayingMs)), this.lastHbPlayingMs = n, r > this.lastHbHiddenMs && (o.hiddenMsDelta = Math.round(r - this.lastHbHiddenMs)), this.lastHbHiddenMs = r, i > this.lastHbRebufferMs && (o.rebufferMsDelta = Math.round(i - this.lastHbRebufferMs)), this.lastHbRebufferMs = i, this.rebufferCount > this.lastHbRebufferCount && (o.rebufferCountDelta = this.rebufferCount - this.lastHbRebufferCount), this.lastHbRebufferCount = this.rebufferCount, a > this.lastHbActiveMs && (o.activeMsDelta = Math.round(a - this.lastHbActiveMs)), this.lastHbActiveMs = a, typeof t.latencySeconds == "number" && (o.latencyMs = Math.round(t.latencySeconds * 1e3)), typeof t.targetLatencySeconds == "number" && (o.targetLatencyMs = Math.round(t.targetLatencySeconds * 1e3)), typeof t.bandwidthKbps == "number" && (o.bandwidthEstKbps = t.bandwidthKbps), typeof t.levelHeight == "number" && (o.renditionHeight = t.levelHeight), typeof t.renditionBitrateKbps == "number" && (o.renditionBitrateKbps = t.renditionBitrateKbps), t.atLiveEdge === !0 && (o.atLiveEdge = !0), typeof t.bufferedMs == "number" && t.bufferedMs > 0 && (o.bufferedMs = Math.round(t.bufferedMs)), o.playerState = Y[t.state] ?? "PLAYER_STATE_UNSPECIFIED";
1718
+ u > this.lastSwitches && (o.renditionSwitchesDelta = u - this.lastSwitches), this.lastSwitches = u, n > this.lastHbPlayingMs && (o.playingMsDelta = Math.round(n - this.lastHbPlayingMs)), this.lastHbPlayingMs = n, r > this.lastHbHiddenMs && (o.hiddenMsDelta = Math.round(r - this.lastHbHiddenMs)), this.lastHbHiddenMs = r, i > this.lastHbRebufferMs && (o.rebufferMsDelta = Math.round(i - this.lastHbRebufferMs)), this.lastHbRebufferMs = i, this.rebufferCount > this.lastHbRebufferCount && (o.rebufferCountDelta = this.rebufferCount - this.lastHbRebufferCount), this.lastHbRebufferCount = this.rebufferCount, a > this.lastHbActiveMs && (o.activeMsDelta = Math.round(a - this.lastHbActiveMs)), this.lastHbActiveMs = a, typeof t.latencySeconds == "number" && (o.latencyMs = Math.round(t.latencySeconds * 1e3)), typeof t.targetLatencySeconds == "number" && (o.targetLatencyMs = Math.round(t.targetLatencySeconds * 1e3)), typeof t.bandwidthKbps == "number" && (o.bandwidthEstKbps = t.bandwidthKbps), typeof t.levelHeight == "number" && (o.renditionHeight = t.levelHeight), typeof t.renditionBitrateKbps == "number" && (o.renditionBitrateKbps = t.renditionBitrateKbps), t.atLiveEdge === !0 && (o.atLiveEdge = !0), typeof t.bufferedMs == "number" && t.bufferedMs > 0 && (o.bufferedMs = Math.round(t.bufferedMs)), o.playerState = J[t.state] ?? "PLAYER_STATE_UNSPECIFIED";
1702
1719
  let d = this.mutedTotalMs;
1703
1720
  this.mutedSinceMs !== null && (d += e - this.mutedSinceMs), d > this.lastHbMutedMs && (o.mutedMsDelta = Math.round(d - this.lastHbMutedMs)), this.lastHbMutedMs = d;
1704
1721
  let f = t.upshifts ?? 0;
@@ -1713,14 +1730,14 @@ var pt = class {
1713
1730
  if (this.lastRequestCount = g, _ > 0) {
1714
1731
  o.requestCountDelta = _;
1715
1732
  let e = t.requestTimesMs ?? [], n = e.slice(Math.max(0, e.length - _)).sort((e, t) => e - t);
1716
- n.length > 0 && (o.requestTimeP50Ms = ut(n, 50), o.requestTimeP95Ms = ut(n, 95));
1733
+ n.length > 0 && (o.requestTimeP50Ms = q(n, 50), o.requestTimeP95Ms = q(n, 95));
1717
1734
  }
1718
1735
  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();
1719
1736
  }
1720
1737
  maybeEmitMediaInfo(e) {
1721
1738
  if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
1722
1739
  let t = {};
1723
- e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = lt[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);
1740
+ e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = dt[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);
1724
1741
  let n = JSON.stringify(t);
1725
1742
  n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
1726
1743
  }
@@ -1740,7 +1757,7 @@ var pt = class {
1740
1757
  let c = r?.positionMs ?? 0;
1741
1758
  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));
1742
1759
  let l = e !== "END_REASON_ENDED";
1743
- l && this.lastStallMs > 0 && n - this.lastStallMs <= ot && (i.abandonAfterStallMs = Math.max(J, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= ot && (i.abandonAfterErrorMs = Math.max(J, 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);
1760
+ l && this.lastStallMs > 0 && n - this.lastStallMs <= K && (i.abandonAfterStallMs = Math.max(G, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= K && (i.abandonAfterErrorMs = Math.max(G, 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);
1744
1761
  let u = r?.decodedFrames ?? this.lastDecoded;
1745
1762
  u > 0 && (i.decodedFramesTotal = u), this.startupTimeMs === 0 && (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");
1746
1763
  }
@@ -1760,7 +1777,7 @@ var pt = class {
1760
1777
  };
1761
1778
  }
1762
1779
  enqueue(e) {
1763
- for (this.pending.push(this.wrap(e)); this.pending.length > it;) {
1780
+ for (this.pending.push(this.wrap(e)); this.pending.length > st;) {
1764
1781
  let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
1765
1782
  this.pending.splice(e >= 0 ? e : 0, 1);
1766
1783
  }
@@ -1783,7 +1800,7 @@ var pt = class {
1783
1800
  };
1784
1801
  //#endregion
1785
1802
  //#region src/core/environment.ts
1786
- function mt() {
1803
+ function gt() {
1787
1804
  if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
1788
1805
  let e;
1789
1806
  try {
@@ -1808,14 +1825,14 @@ function mt() {
1808
1825
  integration: "INTEGRATION_KIND_IFRAME"
1809
1826
  };
1810
1827
  }
1811
- function ht() {
1828
+ function _t() {
1812
1829
  if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
1813
1830
  let e = navigator.userAgentData, t = e?.platform ?? "";
1814
1831
  if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
1815
1832
  let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
1816
1833
  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";
1817
1834
  }
1818
- function gt() {
1835
+ function vt() {
1819
1836
  let e = typeof navigator < "u" ? navigator.connection : void 0;
1820
1837
  if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
1821
1838
  let t = {
@@ -1834,17 +1851,17 @@ function gt() {
1834
1851
  }
1835
1852
  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;
1836
1853
  }
1837
- function _t(e) {
1838
- let t = mt(), n = {
1839
- deviceClass: ht(),
1854
+ function yt(e) {
1855
+ let t = gt(), n = {
1856
+ deviceClass: _t(),
1840
1857
  integration: t.integration,
1841
- ...gt()
1858
+ ...vt()
1842
1859
  };
1843
1860
  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);
1844
1861
  let r = e.getBoundingClientRect?.();
1845
1862
  return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
1846
1863
  }
1847
- async function vt() {
1864
+ async function bt() {
1848
1865
  let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
1849
1866
  if (!e?.getHighEntropyValues) return {};
1850
1867
  try {
@@ -1856,7 +1873,7 @@ async function vt() {
1856
1873
  }
1857
1874
  //#endregion
1858
1875
  //#region src/core/version.ts
1859
- var yt = "2.9.0", bt = {
1876
+ var xt = "2.9.1", St = {
1860
1877
  accent: "#E1B600",
1861
1878
  accentText: "#1B1C23",
1862
1879
  background: "#0e0f13",
@@ -1867,7 +1884,7 @@ var yt = "2.9.0", bt = {
1867
1884
  border: "rgba(255, 255, 255, 0.1)",
1868
1885
  radius: "8px",
1869
1886
  fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
1870
- }, xt = {
1887
+ }, Ct = {
1871
1888
  accent: "--havik-accent",
1872
1889
  accentText: "--havik-accent-text",
1873
1890
  background: "--havik-bg",
@@ -1879,25 +1896,25 @@ var yt = "2.9.0", bt = {
1879
1896
  radius: "--havik-radius",
1880
1897
  fontFamily: "--havik-font"
1881
1898
  };
1882
- function St(e, t) {
1899
+ function wt(e, t) {
1883
1900
  let n = {
1884
- ...bt,
1901
+ ...St,
1885
1902
  ...t
1886
1903
  };
1887
- for (let t of Object.keys(xt)) e.style.setProperty(xt[t], n[t]);
1904
+ for (let t of Object.keys(Ct)) e.style.setProperty(Ct[t], n[t]);
1888
1905
  n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
1889
1906
  }
1890
1907
  //#endregion
1891
1908
  //#region src/ui/styles.ts
1892
- var Ct = "havik-player-styles", wt = "\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";
1893
- function Tt(e = document) {
1894
- if (e.getElementById(Ct)) return;
1909
+ var Tt = "havik-player-styles", Et = "\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";
1910
+ function Dt(e = document) {
1911
+ if (e.getElementById(Tt)) return;
1895
1912
  let t = e.createElement("style");
1896
- t.id = Ct, t.textContent = wt, e.head.appendChild(t);
1913
+ t.id = Tt, t.textContent = Et, e.head.appendChild(t);
1897
1914
  }
1898
1915
  //#endregion
1899
1916
  //#region src/ui/icons.ts
1900
- var Et = {
1917
+ var Ot = {
1901
1918
  play: "<path d=\"M8 5v14l11-7z\"/>",
1902
1919
  pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
1903
1920
  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\"/>",
@@ -1910,21 +1927,21 @@ var Et = {
1910
1927
  liveDot: "<circle cx=\"12\" cy=\"12\" r=\"6\"/>",
1911
1928
  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\"/>"
1912
1929
  };
1913
- function X(e) {
1914
- return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Et[e]}</svg>`;
1930
+ function Z(e) {
1931
+ return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Ot[e]}</svg>`;
1915
1932
  }
1916
1933
  //#endregion
1917
1934
  //#region src/ui/controls.ts
1918
- var Dt = 3e3, Ot = /* @__PURE__ */ new Set([
1935
+ var kt = 3e3, At = /* @__PURE__ */ new Set([
1919
1936
  "GONE",
1920
1937
  "NOT_FOUND",
1921
1938
  "INVALID_URN",
1922
1939
  "UNAUTHORIZED"
1923
1940
  ]);
1924
- function kt(e) {
1925
- return new At(e);
1941
+ function jt(e) {
1942
+ return new Mt(e);
1926
1943
  }
1927
- var At = class {
1944
+ var Mt = class {
1928
1945
  root;
1929
1946
  video;
1930
1947
  player;
@@ -1966,7 +1983,7 @@ var At = class {
1966
1983
  scrubbing = !1;
1967
1984
  offFns = [];
1968
1985
  constructor(e) {
1969
- this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Dt, 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, Tt(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");
1986
+ this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? kt, 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, Dt(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");
1970
1987
  let t = (e, t, n) => {
1971
1988
  let r = this.doc.createElement(e);
1972
1989
  if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
@@ -1977,12 +1994,12 @@ var At = class {
1977
1994
  "aria-label": r,
1978
1995
  title: r
1979
1996
  });
1980
- return i.innerHTML = X(n), i;
1997
+ return i.innerHTML = Z(n), i;
1981
1998
  };
1982
1999
  this.overlay = t("div", "havik-overlay"), this.center = t("button", "havik-center", {
1983
2000
  type: "button",
1984
2001
  "aria-label": "Play"
1985
- }), this.center.innerHTML = X("play"), this.spinner = t("div", "havik-spinner"), this.spinner.style.display = "none", this.overlay.append(this.center, this.spinner), this.gradient = t("div", "havik-gradient"), this.bar = t("div", "havik-bar"), this.seek = t("div", "havik-seek", {
2002
+ }), this.center.innerHTML = Z("play"), this.spinner = t("div", "havik-spinner"), this.spinner.style.display = "none", this.overlay.append(this.center, this.spinner), this.gradient = t("div", "havik-gradient"), this.bar = t("div", "havik-bar"), this.seek = t("div", "havik-seek", {
1986
2003
  role: "slider",
1987
2004
  "aria-label": "Seek",
1988
2005
  "aria-valuemin": "0",
@@ -2000,7 +2017,7 @@ var At = class {
2000
2017
  "aria-label": "Volume"
2001
2018
  });
2002
2019
  let a = t("div", "havik-vol");
2003
- a.append(this.muteBtn, this.volSlider), this.live = t("div", "havik-live"), this.live.innerHTML = X("liveDot");
2020
+ a.append(this.muteBtn, this.volSlider), this.live = t("div", "havik-live"), this.live.innerHTML = Z("liveDot");
2004
2021
  let o = this.doc.createElement("span");
2005
2022
  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";
2006
2023
  let s = t("div", "havik-spacer");
@@ -2054,12 +2071,12 @@ var At = class {
2054
2071
  }
2055
2072
  if (e === "preplay") {
2056
2073
  let e = this.doc.createElement("button");
2057
- e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML = X("play"), e.addEventListener("click", () => void this.player.play()), n.append(e);
2074
+ e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML = Z("play"), e.addEventListener("click", () => void this.player.play()), n.append(e);
2058
2075
  } else {
2059
2076
  let r = this.doc.createElement("div");
2060
- if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !Ot.has(this.lastError.code)) {
2077
+ if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !At.has(this.lastError.code)) {
2061
2078
  let e = this.doc.createElement("button");
2062
- e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${X("retry")}<span>Retry</span>`, e.addEventListener("click", () => void this.player.retry()), n.append(e);
2079
+ e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${Z("retry")}<span>Retry</span>`, e.addEventListener("click", () => void this.player.retry()), n.append(e);
2063
2080
  }
2064
2081
  }
2065
2082
  this.root.append(n), this.statusBox = n, this.show();
@@ -2098,7 +2115,7 @@ var At = class {
2098
2115
  let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
2099
2116
  this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
2100
2117
  }
2101
- !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${jt(this.video.currentTime)} / ${jt(this.video.duration)}`);
2118
+ !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Nt(this.video.currentTime)} / ${Nt(this.video.duration)}`);
2102
2119
  }
2103
2120
  syncLive() {
2104
2121
  let e = this.player.getStats(), t = e.isLive !== !1;
@@ -2148,17 +2165,17 @@ var At = class {
2148
2165
  renderQualityMenu() {
2149
2166
  let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
2150
2167
  n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
2151
- for (let n of e) this.menu.append(this.menuItem(Mt(n), t === n.index, () => this.player.setQuality(n.index)));
2168
+ for (let n of e) this.menu.append(this.menuItem(Pt(n), t === n.index, () => this.player.setQuality(n.index)));
2152
2169
  }
2153
2170
  renderAudioMenu() {
2154
2171
  let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
2155
2172
  t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
2156
- for (let t of e) this.menu.append(this.menuItem(Nt(t), t.default, () => this.player.setAudioTrack(t.id)));
2173
+ for (let t of e) this.menu.append(this.menuItem(Ft(t), t.default, () => this.player.setAudioTrack(t.id)));
2157
2174
  }
2158
2175
  renderCcMenu() {
2159
2176
  let e = this.player.getTextTracks(), t = this.doc.createElement("div");
2160
2177
  t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
2161
- for (let t of e) this.menu.append(this.menuItem(Pt(t), !1, () => this.player.setTextTrack(t.id)));
2178
+ for (let t of e) this.menu.append(this.menuItem(It(t), !1, () => this.player.setTextTrack(t.id)));
2162
2179
  }
2163
2180
  onTracksChanged() {
2164
2181
  this.openMenu && this.renderMenu(this.openMenu);
@@ -2241,7 +2258,7 @@ var At = class {
2241
2258
  }
2242
2259
  }
2243
2260
  setIcon(e, t) {
2244
- e.innerHTML = X(t);
2261
+ e.innerHTML = Z(t);
2245
2262
  }
2246
2263
  destroy() {
2247
2264
  this.hideTimer && clearTimeout(this.hideTimer);
@@ -2258,41 +2275,41 @@ var At = class {
2258
2275
  this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
2259
2276
  }
2260
2277
  };
2261
- function jt(e) {
2278
+ function Nt(e) {
2262
2279
  (!Number.isFinite(e) || e < 0) && (e = 0);
2263
2280
  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");
2264
2281
  return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
2265
2282
  }
2266
- function Mt(e) {
2283
+ function Pt(e) {
2267
2284
  return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
2268
2285
  }
2269
- function Nt(e) {
2286
+ function Ft(e) {
2270
2287
  return e.name || e.lang || `Track ${e.id}`;
2271
2288
  }
2272
- function Pt(e) {
2289
+ function It(e) {
2273
2290
  return e.name || e.lang || `Track ${e.id}`;
2274
2291
  }
2275
2292
  //#endregion
2276
2293
  //#region src/managed/index.ts
2277
- var Ft = 6e3, Z = 45e3, It = 2e3, Lt = 3, Rt = 2e3, zt = 48e4;
2278
- function Bt(e) {
2294
+ var Lt = 6e3, Q = 45e3, Rt = 2e3, zt = 3, Bt = 2e3, Vt = 48e4;
2295
+ function Ht(e) {
2279
2296
  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)})`);
2280
- if (e.env !== void 0) return z(e.env);
2297
+ if (e.env !== void 0) return I(e.env);
2281
2298
  if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
2282
2299
  return e.baseUrl;
2283
2300
  }
2284
- async function Q(e) {
2301
+ async function Ut(e) {
2285
2302
  if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
2286
- let t = Bt(e);
2303
+ let t = Ht(e);
2287
2304
  if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
2288
2305
  if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
2289
- let r = new Vt({
2306
+ let r = new Wt({
2290
2307
  ...e,
2291
2308
  baseUrl: t
2292
2309
  });
2293
2310
  return await r.start(), r;
2294
2311
  }
2295
- var Vt = class {
2312
+ var Wt = class {
2296
2313
  opts;
2297
2314
  abort = new AbortController();
2298
2315
  listeners = {};
@@ -2380,7 +2397,7 @@ var Vt = class {
2380
2397
  setTimeout(() => {
2381
2398
  a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
2382
2399
  phase: i ? "unavailable" : "tooEarly",
2383
- retryInMs: Z,
2400
+ retryInMs: Q,
2384
2401
  attempt: 1,
2385
2402
  elapsedMs: 0,
2386
2403
  ...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
@@ -2419,13 +2436,13 @@ var Vt = class {
2419
2436
  !a && !p() && h();
2420
2437
  }, e);
2421
2438
  };
2422
- _(Ft), this.armingSub = E({
2439
+ _(Lt), this.armingSub = E({
2423
2440
  eventsBaseUrl: t,
2424
2441
  matchUrn: this.opts.matchUrn,
2425
2442
  credential: this.opts.credential,
2426
- onAlive: () => _(Z),
2443
+ onAlive: () => _(Q),
2427
2444
  onState: (e) => {
2428
- a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * It);
2445
+ a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Rt);
2429
2446
  },
2430
2447
  onError: () => h()
2431
2448
  });
@@ -2448,7 +2465,7 @@ var Vt = class {
2448
2465
  let n = await s(this.opts.credential);
2449
2466
  if (this.destroyed || t !== this.loadGen) return;
2450
2467
  this.setState("loading");
2451
- let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = je(this.opts.video, (e) => {
2468
+ let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = Pe(this.opts.video, (e) => {
2452
2469
  this._state !== "ended" && this._state !== "error" && this.setState(e);
2453
2470
  });
2454
2471
  if (await i.load(), this.destroyed || t !== this.loadGen) {
@@ -2459,43 +2476,48 @@ var Vt = class {
2459
2476
  a(), i.destroy();
2460
2477
  return;
2461
2478
  }
2462
- this.engine = i, this.detachMedia = a, this.opts.maxBitrate != null && i.setMaxBitrate(this.opts.maxBitrate), this.startStats(), this.scheduleLicenseRefresh(), this.startLiveState(t), this.startAnalytics(e, i), r && (this.pendingStartLoad = !0, this.setState("paused"), i.name === "native" && setTimeout(() => {
2479
+ this.engine = i, this.detachMedia = a, this.opts.maxBitrate != null && i.setMaxBitrate(this.opts.maxBitrate), this.startStats(), this.scheduleLicenseRefresh(), this.startLiveState(t), this.startAnalytics(e, i, t), r && (this.pendingStartLoad = !0, this.setState("paused"), i.name === "native" && setTimeout(() => {
2463
2480
  this.destroyed || t !== this.loadGen || this.engine !== i || (this.analyticsSession?.noteReady(), this.emit("ready"));
2464
2481
  }, 0));
2465
2482
  }
2466
2483
  onAnalyticsIdle(e) {
2467
2484
  this.destroyed || this.engine !== e || (this.idleClosed = !0, this.pendingStartLoad = !1, e.stop());
2468
2485
  }
2469
- startAnalytics(e, t) {
2486
+ startAnalytics(e, t, r) {
2470
2487
  if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
2471
- let n = e.analytics?.sid;
2472
- if (!n) return;
2473
- let r = (typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0) ?? ft(this.opts.baseUrl);
2474
- if (!r) return;
2475
- let i = this.opts.video, a = new pt({
2476
- endpoint: r,
2477
- sid: n,
2488
+ let i = e.analytics?.sid;
2489
+ if (!i) return;
2490
+ let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = mt(this.opts.baseUrl, a);
2491
+ if (!o) {
2492
+ s && setTimeout(() => {
2493
+ this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
2494
+ }, 0);
2495
+ return;
2496
+ }
2497
+ let c = this.opts.video, l = new ht({
2498
+ endpoint: o,
2499
+ sid: i,
2478
2500
  player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
2479
- sdkVersion: yt,
2480
- environment: _t(i),
2501
+ sdkVersion: xt,
2502
+ environment: yt(c),
2481
2503
  idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
2482
2504
  onIdle: () => this.onAnalyticsIdle(t),
2483
2505
  sample: () => {
2484
- let e = this.engine?.getStats() ?? B, t = i.buffered.length ? Math.max(0, i.buffered.end(i.buffered.length - 1) - i.currentTime) : 0;
2506
+ let e = this.engine?.getStats() ?? L, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
2485
2507
  return {
2486
2508
  ...e,
2487
2509
  bufferedMs: Math.round(t * 1e3),
2488
2510
  state: this._state,
2489
- positionMs: Math.round(i.currentTime * 1e3),
2490
- playbackRate: i.playbackRate
2511
+ positionMs: Math.round(c.currentTime * 1e3),
2512
+ playbackRate: c.playbackRate
2491
2513
  };
2492
2514
  }
2493
2515
  });
2494
- this.analyticsSession = a;
2495
- let o = () => a.noteSeek(), s = () => a.noteVolume(i.muted, i.volume);
2496
- i.addEventListener("seeking", o), i.addEventListener("volumechange", s), this.detachMediaListeners = () => {
2497
- i.removeEventListener("seeking", o), i.removeEventListener("volumechange", s);
2498
- }, a.start(), a.seedVolume(i.muted, i.volume), a.notePresentation(this.currentPresentation()), vt().then((e) => a.noteEnvironment(e)), this.opts.autoplay === !1 && a.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
2516
+ this.analyticsSession = l;
2517
+ let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
2518
+ c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
2519
+ c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
2520
+ }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), bt().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
2499
2521
  }
2500
2522
  currentPresentation() {
2501
2523
  let e = this.opts.video;
@@ -2519,11 +2541,11 @@ var Vt = class {
2519
2541
  hlsConfig: i,
2520
2542
  emit: (e) => this.onEngineEvent(e)
2521
2543
  }, o = this.opts.engine ?? "auto";
2522
- if (o === "native") return new G(a);
2523
- if (o === "hls") return new q(a);
2524
- if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && U(this.opts.video) && W()) return new G(a);
2525
- if (Pe()) return new q(a);
2526
- if (U(this.opts.video)) return new G(a);
2544
+ if (o === "native") return new H(a);
2545
+ if (o === "hls") return new W(a);
2546
+ if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && B(this.opts.video) && V()) return new H(a);
2547
+ if (Le()) return new W(a);
2548
+ if (B(this.opts.video)) return new H(a);
2527
2549
  throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
2528
2550
  }
2529
2551
  onEngineEvent(e) {
@@ -2566,7 +2588,7 @@ var Vt = class {
2566
2588
  r = 0, i = !1;
2567
2589
  },
2568
2590
  onError: () => {
2569
- this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= Lt && (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.`))));
2591
+ this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= zt && (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.`))));
2570
2592
  }
2571
2593
  });
2572
2594
  }
@@ -2588,7 +2610,7 @@ var Vt = class {
2588
2610
  scheduleRejoin(e) {
2589
2611
  this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
2590
2612
  this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
2591
- }, Math.random() * It));
2613
+ }, Math.random() * Rt));
2592
2614
  }
2593
2615
  cancelRejoin() {
2594
2616
  this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
@@ -2612,7 +2634,7 @@ var Vt = class {
2612
2634
  }
2613
2635
  t.controls = !1;
2614
2636
  let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
2615
- r && r.insertBefore(n, t), n.appendChild(t), St(n, this.opts.theme), this.container = n, this.controlBar = kt({
2637
+ r && r.insertBefore(n, t), n.appendChild(t), wt(n, this.opts.theme), this.container = n, this.controlBar = jt({
2616
2638
  root: n,
2617
2639
  video: t,
2618
2640
  player: this,
@@ -2642,7 +2664,7 @@ var Vt = class {
2642
2664
  }
2643
2665
  startStats() {
2644
2666
  this.stopStats();
2645
- let e = Math.max(500, this.opts.statsIntervalMs ?? Rt);
2667
+ let e = Math.max(500, this.opts.statsIntervalMs ?? Bt);
2646
2668
  this.statsTimer = setInterval(() => {
2647
2669
  if (!this.engine) return;
2648
2670
  let e = this.engine.getStats();
@@ -2654,7 +2676,7 @@ var Vt = class {
2654
2676
  }
2655
2677
  scheduleLicenseRefresh() {
2656
2678
  this.stopRefresh();
2657
- let e = this.opts.licenseRefreshMs ?? zt;
2679
+ let e = this.opts.licenseRefreshMs ?? Vt;
2658
2680
  e && this._descriptor?.drmEnabled && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
2659
2681
  }
2660
2682
  stopRefresh() {
@@ -2699,7 +2721,7 @@ var Vt = class {
2699
2721
  this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
2700
2722
  }
2701
2723
  getStats() {
2702
- return this.engine?.getStats() ?? B;
2724
+ return this.engine?.getStats() ?? L;
2703
2725
  }
2704
2726
  getQualityLevels() {
2705
2727
  return this.engine?.getQualityLevels() ?? [];
@@ -2809,7 +2831,7 @@ function $(e) {
2809
2831
  }
2810
2832
  //#endregion
2811
2833
  //#region src/embed/host.ts
2812
- function Ht(e) {
2834
+ function Gt(e) {
2813
2835
  if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
2814
2836
  if (!e.src) throw Error("mountEmbed: opts.src is required");
2815
2837
  if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
@@ -2868,15 +2890,15 @@ function Ht(e) {
2868
2890
  }
2869
2891
  //#endregion
2870
2892
  //#region src/embed/page.ts
2871
- var Ut = /^[A-Za-z0-9:_.-]{1,128}$/;
2872
- function Wt(e) {
2893
+ var Kt = /^[A-Za-z0-9:_.-]{1,128}$/;
2894
+ function qt(e) {
2873
2895
  if (typeof e == "boolean") return e;
2874
2896
  if (typeof e == "object" && e) {
2875
2897
  let t = e.endpoint;
2876
2898
  return typeof t == "string" ? { endpoint: t } : {};
2877
2899
  }
2878
2900
  }
2879
- function Gt() {
2901
+ function Jt() {
2880
2902
  let e = window.HAVIK_EMBED_CONFIG;
2881
2903
  if (e) return {
2882
2904
  baseUrl: e.baseUrl ?? "",
@@ -2886,7 +2908,7 @@ function Gt() {
2886
2908
  autoplay: e.autoplay ?? !0,
2887
2909
  muted: e.muted ?? !0,
2888
2910
  waitForLive: e.waitForLive ?? !0,
2889
- analytics: Wt(e.analytics)
2911
+ analytics: qt(e.analytics)
2890
2912
  };
2891
2913
  let t = new URLSearchParams(location.search);
2892
2914
  return {
@@ -2899,9 +2921,9 @@ function Gt() {
2899
2921
  waitForLive: !0
2900
2922
  };
2901
2923
  }
2902
- async function Kt() {
2903
- let e = Gt();
2904
- Jt();
2924
+ async function Yt() {
2925
+ let e = Jt();
2926
+ Zt();
2905
2927
  let t = document.createElement("video");
2906
2928
  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);
2907
2929
  let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
@@ -2956,12 +2978,12 @@ async function Kt() {
2956
2978
  code: e.code,
2957
2979
  message: e.message
2958
2980
  })), e.on("autoplayblocked", () => {
2959
- i({ type: "oddin:autoplayblocked" }), qt(t, e);
2981
+ i({ type: "oddin:autoplayblocked" }), Xt(t, e);
2960
2982
  });
2961
2983
  }, s = async (r) => {
2962
2984
  a?.destroy(), a = null;
2963
2985
  try {
2964
- let n = await Q({
2986
+ let n = await Ut({
2965
2987
  video: t,
2966
2988
  baseUrl: e.baseUrl,
2967
2989
  matchUrn: r,
@@ -3023,7 +3045,7 @@ async function Kt() {
3023
3045
  a?.retry();
3024
3046
  break;
3025
3047
  case "oddin:load":
3026
- typeof e.matchUrn == "string" && Ut.test(e.matchUrn) && s(e.matchUrn);
3048
+ typeof e.matchUrn == "string" && Kt.test(e.matchUrn) && s(e.matchUrn);
3027
3049
  break;
3028
3050
  case "oddin:destroy": c();
3029
3051
  }
@@ -3035,18 +3057,18 @@ async function Kt() {
3035
3057
  protocol: 1
3036
3058
  });
3037
3059
  }
3038
- function qt(e, t) {
3060
+ function Xt(e, t) {
3039
3061
  if (document.getElementById("havik-tap")) return;
3040
3062
  let n = document.createElement("button");
3041
3063
  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", () => {
3042
3064
  n.remove(), t.play();
3043
3065
  }), document.body.appendChild(n);
3044
3066
  }
3045
- function Jt() {
3067
+ function Zt() {
3046
3068
  let e = document.createElement("style");
3047
3069
  e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
3048
3070
  }
3049
3071
  //#endregion
3050
- export { bt as ODDIN_THEME, n as PlaybackError, St as applyTheme, z as baseUrlForEnv, Kt as bootEmbed, _e as clearDeviceId, Q as createPlayer, D as deriveEventsBaseUrl, Ee as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, ue as fetchCatalog, fe as fetchTournament, me as flattenMatches, A as getDeviceId, Oe as isLowLatencyManifest, $ as isOddinMessage, ye as licenseRequestHeaders, Ht as mountEmbed, v as pollToLive, b as resolveStream, E as subscribeLiveState, C as videoFullscreenActive, he as watchStatus };
3072
+ export { St as ODDIN_THEME, n as PlaybackError, wt as applyTheme, I as baseUrlForEnv, Yt as bootEmbed, _e as clearDeviceId, Ut as createPlayer, D as deriveEventsBaseUrl, ke as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, ue as fetchCatalog, fe as fetchTournament, me as flattenMatches, A as getDeviceId, je as isLowLatencyManifest, $ as isOddinMessage, ye as licenseRequestHeaders, Gt as mountEmbed, v as pollToLive, b as resolveStream, E as subscribeLiveState, C as videoFullscreenActive, he as watchStatus };
3051
3073
 
3052
3074
  //# sourceMappingURL=index.js.map