@oddin-gg/havik-player 2.23.4 → 2.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -700,19 +700,19 @@ function Ve(e, t) {
700
700
  function N() {
701
701
  return typeof navigator < "u" && typeof navigator.requestMediaKeySystemAccess == "function";
702
702
  }
703
- var P = ["SW_SECURE_DECODE", "SW_SECURE_CRYPTO"];
704
- function He(e) {
703
+ var He = ["SW_SECURE_DECODE", "SW_SECURE_CRYPTO"];
704
+ function Ue(e) {
705
705
  return e.startsWith("com.widevine");
706
706
  }
707
- function F(e, t) {
708
- if (!He(e)) return t;
707
+ function P(e, t) {
708
+ if (!Ue(e)) return t;
709
709
  let n = (e, t) => {
710
710
  let n = e.videoCapabilities;
711
711
  return !n?.length || !n.some((e) => e.robustness) ? !1 : n.every((e) => {
712
- let n = P.indexOf(e.robustness);
713
- return n === -1 || P.indexOf(t) > n;
712
+ let n = He.indexOf(e.robustness);
713
+ return n === -1 || He.indexOf(t) > n;
714
714
  });
715
- }, r = P.flatMap((e) => t.filter((t) => n(t, e)).map((t) => ({
715
+ }, r = He.flatMap((e) => t.filter((t) => n(t, e)).map((t) => ({
716
716
  ...t,
717
717
  videoCapabilities: t.videoCapabilities?.map((t) => ({
718
718
  ...t,
@@ -721,53 +721,53 @@ function F(e, t) {
721
721
  })));
722
722
  return [...t, ...r];
723
723
  }
724
- function Ue(e) {
725
- return (t, n) => N() ? navigator.requestMediaKeySystemAccess(t, F(t, n)).then((t) => ({
724
+ function We(e) {
725
+ return (t, n) => N() ? navigator.requestMediaKeySystemAccess(t, P(t, n)).then((t) => ({
726
726
  keySystem: t.keySystem,
727
727
  getConfiguration: () => t.getConfiguration(),
728
728
  createMediaKeys: () => Ve(e, t)
729
729
  })) : Promise.reject(/* @__PURE__ */ Error("navigator.requestMediaKeySystemAccess is unavailable — EME needs a secure context (https, or localhost)"));
730
730
  }
731
- var I = {
731
+ var F = {
732
732
  video: "SW_SECURE_DECODE",
733
733
  audio: "SW_SECURE_CRYPTO",
734
734
  scheme: "cbcs"
735
735
  };
736
- function We(e) {
736
+ function Ge(e) {
737
737
  if (!N()) return;
738
738
  let t = (e, t) => ({
739
739
  contentType: e,
740
740
  robustness: t,
741
- encryptionScheme: I.scheme
741
+ encryptionScheme: F.scheme
742
742
  });
743
- Ue(e)("com.widevine.alpha", [{
743
+ We(e)("com.widevine.alpha", [{
744
744
  initDataTypes: ["cenc"],
745
745
  distinctiveIdentifier: "optional",
746
746
  persistentState: "optional",
747
747
  sessionTypes: ["temporary"],
748
- audioCapabilities: [t("audio/mp4; codecs=\"mp4a.40.2\"", I.audio)],
749
- videoCapabilities: [t("video/mp4; codecs=\"avc1.42e01e\"", I.video)]
748
+ audioCapabilities: [t("audio/mp4; codecs=\"mp4a.40.2\"", F.audio)],
749
+ videoCapabilities: [t("video/mp4; codecs=\"avc1.42e01e\"", F.video)]
750
750
  }]).then((e) => e.createMediaKeys()).catch(() => {});
751
751
  }
752
- function L(e) {
753
- let t = R(e);
752
+ function I(e) {
753
+ let t = L(e);
754
754
  if (/^avc[13]/.test(t)) return "avc";
755
755
  if (/^(hvc1|hev1)/.test(t)) return "hevc";
756
756
  if (/^(dvh1|dvhe)/.test(t)) return "dv";
757
757
  if (t.startsWith("av01")) return "av1";
758
758
  if (/^vp0?9/.test(t)) return "vp9";
759
759
  }
760
- function R(e) {
760
+ function L(e) {
761
761
  return (e ?? "").trim().toLowerCase();
762
762
  }
763
- var Ge = {
763
+ var Ke = {
764
764
  hevc: "hvc1.1.6.L93.90",
765
765
  dv: "dvh1.05.06",
766
766
  av1: "av01.0.05M.08",
767
767
  vp9: "vp09.00.10.08"
768
- }, Ke = /* @__PURE__ */ new Map(), z = /* @__PURE__ */ new Map();
769
- function qe(e) {
770
- let t = R(e), n = Ke.get(t);
768
+ }, qe = /* @__PURE__ */ new Map(), R = /* @__PURE__ */ new Map();
769
+ function Je(e) {
770
+ let t = L(e), n = qe.get(t);
771
771
  if (n) return n;
772
772
  let r = {
773
773
  initDataTypes: ["cenc"],
@@ -776,32 +776,32 @@ function qe(e) {
776
776
  sessionTypes: ["temporary"],
777
777
  videoCapabilities: [{
778
778
  contentType: `video/mp4; codecs="${e.trim()}"`,
779
- robustness: I.video,
780
- encryptionScheme: I.scheme
779
+ robustness: F.video,
780
+ encryptionScheme: F.scheme
781
781
  }]
782
782
  }, i = (async () => {
783
783
  try {
784
- return await navigator.requestMediaKeySystemAccess("com.widevine.alpha", F("com.widevine.alpha", [r])), !0;
784
+ return await navigator.requestMediaKeySystemAccess("com.widevine.alpha", P("com.widevine.alpha", [r])), !0;
785
785
  } catch {
786
786
  return !1;
787
787
  }
788
- })().then((e) => (z.set(t, e), e));
789
- return Ke.set(t, i), i;
788
+ })().then((e) => (R.set(t, e), e));
789
+ return qe.set(t, i), i;
790
790
  }
791
- function Je() {
792
- if (N()) for (let e of Object.values(Ge)) qe(e);
791
+ function Ye() {
792
+ if (N()) for (let e of Object.values(Ke)) Je(e);
793
793
  }
794
- function Ye(e) {
795
- let t = L(e);
796
- if (t) return t === "avc" ? !0 : z.get(R(e)) ?? z.get(R(Ge[t]));
794
+ function Xe(e) {
795
+ let t = I(e);
796
+ if (t) return t === "avc" ? !0 : R.get(L(e)) ?? R.get(L(Ke[t]));
797
797
  }
798
798
  //#endregion
799
799
  //#region src/core/drm/support.ts
800
- var Xe = 5e3, Ze = "video/mp4; codecs=\"avc1.42E01E\"", Qe = "audio/mp4; codecs=\"mp4a.40.2\"", $e = {
800
+ var Ze = 5e3, Qe = "video/mp4; codecs=\"avc1.42E01E\"", $e = "audio/mp4; codecs=\"mp4a.40.2\"", et = {
801
801
  widevine: ["com.widevine.alpha"],
802
802
  fairplay: ["com.apple.fps"]
803
803
  };
804
- function et(e) {
804
+ function tt(e) {
805
805
  return e === "fairplay" ? [{
806
806
  initDataTypes: [
807
807
  "sinf",
@@ -809,30 +809,30 @@ function et(e) {
809
809
  "cenc"
810
810
  ],
811
811
  videoCapabilities: [{
812
- contentType: Ze,
812
+ contentType: Qe,
813
813
  robustness: "",
814
814
  encryptionScheme: "cbcs"
815
815
  }],
816
816
  audioCapabilities: [{
817
- contentType: Qe,
817
+ contentType: $e,
818
818
  robustness: "",
819
819
  encryptionScheme: "cbcs"
820
820
  }]
821
- }] : F("com.widevine.alpha", [{
821
+ }] : P("com.widevine.alpha", [{
822
822
  initDataTypes: ["cenc"],
823
823
  videoCapabilities: [{
824
- contentType: Ze,
825
- robustness: I.video,
826
- encryptionScheme: I.scheme
824
+ contentType: Qe,
825
+ robustness: F.video,
826
+ encryptionScheme: F.scheme
827
827
  }],
828
828
  audioCapabilities: [{
829
- contentType: Qe,
830
- robustness: I.audio,
831
- encryptionScheme: I.scheme
829
+ contentType: $e,
830
+ robustness: F.audio,
831
+ encryptionScheme: F.scheme
832
832
  }]
833
833
  }]);
834
834
  }
835
- function tt(e, t) {
835
+ function nt(e, t) {
836
836
  return new Promise((n, r) => {
837
837
  let i = setTimeout(() => r(/* @__PURE__ */ Error("probe-timeout")), t);
838
838
  e.then((e) => {
@@ -842,8 +842,8 @@ function tt(e, t) {
842
842
  });
843
843
  });
844
844
  }
845
- async function nt(e = {}) {
846
- let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Xe, r = {};
845
+ async function rt(e = {}) {
846
+ let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Ze, r = {};
847
847
  if (typeof window < "u" && window.isSecureContext === !1) return {
848
848
  verdict: "insecure-context",
849
849
  detail: r
@@ -855,7 +855,7 @@ async function nt(e = {}) {
855
855
  };
856
856
  let a = !1, o = !1, s = Date.now() + n, c = () => Math.max(1, s - Date.now());
857
857
  for (let e of t) {
858
- let t = $e[e];
858
+ let t = et[e];
859
859
  if (!t) {
860
860
  r[e] = "unknown system";
861
861
  continue;
@@ -866,7 +866,7 @@ async function nt(e = {}) {
866
866
  break;
867
867
  }
868
868
  try {
869
- return await tt((await tt(i(n, et(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
869
+ return await nt((await nt(i(n, tt(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
870
870
  verdict: "supported",
871
871
  system: e,
872
872
  detail: r
@@ -890,49 +890,49 @@ async function nt(e = {}) {
890
890
  }
891
891
  //#endregion
892
892
  //#region src/core/manifest.ts
893
- var rt = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
894
- function it(e) {
895
- return rt.test(e);
893
+ var it = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
894
+ function at(e) {
895
+ return it.test(e);
896
896
  }
897
897
  //#endregion
898
898
  //#region src/core/env.ts
899
- var at = {
899
+ var ot = {
900
900
  integration: "https://feed-dev.oddin-video.gg",
901
901
  production: "https://feed.oddin-video.gg"
902
902
  };
903
- function ot(e) {
904
- let t = Object.prototype.hasOwnProperty.call(at, e) ? at[e] : void 0;
903
+ function st(e) {
904
+ let t = Object.prototype.hasOwnProperty.call(ot, e) ? ot[e] : void 0;
905
905
  if (!t) throw new n("INTERNAL", 0, `unknown env ${JSON.stringify(e)} — expected 'integration' or 'production'`);
906
906
  return t;
907
907
  }
908
908
  //#endregion
909
909
  //#region src/core/stats.ts
910
- var st = { droppedFrames: 0 };
911
- function ct(e) {
910
+ var ct = { droppedFrames: 0 };
911
+ function lt(e) {
912
912
  try {
913
913
  return new URL(e).host;
914
914
  } catch {
915
915
  return "";
916
916
  }
917
917
  }
918
- var lt = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
919
- function ut(e) {
918
+ var ut = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
919
+ function dt(e) {
920
920
  if (typeof performance > "u" || typeof performance.getEntriesByType != "function") return "";
921
921
  let t = "", n = -1, r = performance.getEntriesByType("resource");
922
- for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || lt.test(i.name)) && i.startTime >= n) {
923
- let e = ct(i.name);
922
+ for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || ut.test(i.name)) && i.startTime >= n) {
923
+ let e = lt(i.name);
924
924
  e && (t = e, n = i.startTime);
925
925
  }
926
926
  return t;
927
927
  }
928
- function B(e) {
928
+ function z(e) {
929
929
  let t = e.getVideoPlaybackQuality?.();
930
930
  return {
931
931
  dropped: t?.droppedVideoFrames ?? 0,
932
932
  totalFrames: t?.totalVideoFrames ?? 0
933
933
  };
934
934
  }
935
- var dt = class {
935
+ var ft = class {
936
936
  video;
937
937
  baseFrames = 0;
938
938
  baseDropped = 0;
@@ -942,7 +942,7 @@ var dt = class {
942
942
  this.video = e;
943
943
  }
944
944
  read() {
945
- let e = B(this.video);
945
+ let e = z(this.video);
946
946
  return e.totalFrames < this.lastFrames && (this.baseFrames += this.lastFrames), e.dropped < this.lastDropped && (this.baseDropped += this.lastDropped), this.lastFrames = e.totalFrames, this.lastDropped = e.dropped, {
947
947
  dropped: this.baseDropped + e.dropped,
948
948
  totalFrames: this.baseFrames + e.totalFrames
@@ -955,7 +955,7 @@ var dt = class {
955
955
  };
956
956
  }
957
957
  };
958
- function ft(e, t) {
958
+ function pt(e, t) {
959
959
  let n = [
960
960
  ["playing", () => t("playing")],
961
961
  ["waiting", () => t("buffering")],
@@ -972,8 +972,8 @@ function ft(e, t) {
972
972
  }
973
973
  //#endregion
974
974
  //#region src/core/engine/native.ts
975
- var pt = 2e3, mt = 3, V = 500, ht = 6e3, gt = .25, _t = 250, vt = .05, yt = 4, bt = 12e3, xt = .25, St = 1e3;
976
- function Ct(e) {
975
+ var mt = 2e3, ht = 3, B = 500, gt = 6e3, _t = .25, vt = 250, yt = .05, bt = 4, xt = 12e3, St = .25, Ct = 1e3;
976
+ function wt(e) {
977
977
  try {
978
978
  let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
979
979
  return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
@@ -981,20 +981,20 @@ function Ct(e) {
981
981
  return;
982
982
  }
983
983
  }
984
- function H(e) {
984
+ function V(e) {
985
985
  return !!(e ?? (typeof document < "u" ? document.createElement("video") : void 0))?.canPlayType("application/vnd.apple.mpegurl");
986
986
  }
987
- function U() {
987
+ function H() {
988
988
  if (typeof window > "u") return !1;
989
989
  let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
990
990
  return e || t;
991
991
  }
992
- function wt() {
993
- if (typeof navigator > "u" || !U()) return !1;
992
+ function Tt() {
993
+ if (typeof navigator > "u" || !H()) return !1;
994
994
  let e = navigator.userAgent ?? "";
995
995
  return /iPhone|iPad|iPod/.test(e) ? !0 : /Macintosh/.test(e) && typeof navigator.maxTouchPoints == "number" && navigator.maxTouchPoints > 1;
996
996
  }
997
- var W = class {
997
+ var U = class {
998
998
  name = "native";
999
999
  deps;
1000
1000
  onLoaded;
@@ -1024,7 +1024,7 @@ var W = class {
1024
1024
  frameCounter;
1025
1025
  detachFrames = null;
1026
1026
  constructor(e) {
1027
- this.deps = e, this.frameCounter = new dt(e.video), this.loadStarted = e.deferLoad !== !0, this.builtAt = typeof performance < "u" ? performance.now() : 0;
1027
+ this.deps = e, this.frameCounter = new ft(e.video), this.loadStarted = e.deferLoad !== !0, this.builtAt = typeof performance < "u" ? performance.now() : 0;
1028
1028
  }
1029
1029
  async load() {
1030
1030
  this.detachFrames ??= this.frameCounter.attach();
@@ -1045,7 +1045,7 @@ var W = class {
1045
1045
  type: "error",
1046
1046
  error: new n("INTERNAL", 0, "native HLS playback error"),
1047
1047
  fatal: !0
1048
- }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = Et(t.manifestUrl, t.analytics?.sid), e.load();
1048
+ }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = Dt(t.manifestUrl, t.analytics?.sid), e.load();
1049
1049
  }
1050
1050
  startLoad() {
1051
1051
  this.loadStarted || (this.loadStarted = !0, this.restorePreload());
@@ -1073,7 +1073,7 @@ var W = class {
1073
1073
  };
1074
1074
  this.onEncrypted = (n) => {
1075
1075
  let a = n;
1076
- a.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = Ct(a.initData), (async () => {
1076
+ a.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = wt(a.initData), (async () => {
1077
1077
  try {
1078
1078
  let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
1079
1079
  initDataTypes: [a.initDataType],
@@ -1173,10 +1173,10 @@ var W = class {
1173
1173
  droppedFrames: t.dropped,
1174
1174
  decodedFrames: t.totalFrames
1175
1175
  };
1176
- if (this.cdnHost ||= ut(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity) {
1176
+ if (this.cdnHost ||= dt(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity) {
1177
1177
  n.isLive = !0;
1178
1178
  let t = this.liveEdgeEstimate(), r = t == null ? NaN : t - e.currentTime;
1179
- Number.isFinite(r) && (n.atLiveEdge = r <= yt, !e.paused && r >= 0 && (n.latencySeconds = r));
1179
+ Number.isFinite(r) && (n.atLiveEdge = r <= bt, !e.paused && r >= 0 && (n.latencySeconds = r));
1180
1180
  } else Number.isFinite(e.duration) && e.duration > 0 && (n.isLive = !1);
1181
1181
  return n;
1182
1182
  }
@@ -1188,30 +1188,30 @@ var W = class {
1188
1188
  }
1189
1189
  watchRefocus() {
1190
1190
  this.deps.snapToLiveOnRefocus === !1 || typeof document > "u" || this.onVisibility || (this.onVisibility = () => {
1191
- let e = G();
1191
+ let e = W();
1192
1192
  if (document.visibilityState === "hidden") {
1193
1193
  this.hiddenSince = e, this.cancelRefocus();
1194
1194
  return;
1195
1195
  }
1196
1196
  let t = this.hiddenSince;
1197
- this.hiddenSince = null, t != null && e - t >= pt && this.armRefocus();
1197
+ this.hiddenSince = null, t != null && e - t >= mt && this.armRefocus();
1198
1198
  }, this.onPageShow = (e) => {
1199
1199
  e.persisted && this.armRefocus();
1200
1200
  }, document.addEventListener("visibilitychange", this.onVisibility), typeof window < "u" && window.addEventListener("pageshow", this.onPageShow));
1201
1201
  }
1202
1202
  armRefocus() {
1203
1203
  if (this.cancelRefocus(), Number.isFinite(this.deps.video.duration)) return;
1204
- let e = this.liveEnd(), t = G, n = t(), r = 0, i = () => {
1204
+ let e = this.liveEnd(), t = W, n = t(), r = 0, i = () => {
1205
1205
  if (this.refocusTimer = null, Number.isFinite(this.deps.video.duration)) return;
1206
- r += V;
1207
- let a = this.liveEnd(), o = a != null && (e == null || a >= e + gt), s = Math.max(r, t() - n) >= ht;
1206
+ r += B;
1207
+ let a = this.liveEnd(), o = a != null && (e == null || a >= e + _t), s = Math.max(r, t() - n) >= gt;
1208
1208
  if (o || s && a != null) {
1209
1209
  this.snapToLive();
1210
1210
  return;
1211
1211
  }
1212
- this.refocusTimer = setTimeout(i, V);
1212
+ this.refocusTimer = setTimeout(i, B);
1213
1213
  };
1214
- this.refocusTimer = setTimeout(i, V);
1214
+ this.refocusTimer = setTimeout(i, B);
1215
1215
  }
1216
1216
  cancelRefocus() {
1217
1217
  this.refocusTimer != null && clearTimeout(this.refocusTimer), this.refocusTimer = null;
@@ -1224,24 +1224,24 @@ var W = class {
1224
1224
  }, e.addEventListener("seeking", this.onEdgeReset), e.addEventListener("emptied", this.onEdgeReset), this.edgeTimer = setInterval(() => {
1225
1225
  if (e.duration !== Infinity) return;
1226
1226
  this.checkEndStale();
1227
- let t = Tt(e, e.currentTime);
1228
- t != null && ((this.lastBufferedEnd == null || Math.abs(t - this.lastBufferedEnd) >= vt) && (this.bufferedAdvancedAt = G()), this.lastBufferedEnd = t);
1229
- }, _t);
1227
+ let t = Et(e, e.currentTime);
1228
+ t != null && ((this.lastBufferedEnd == null || Math.abs(t - this.lastBufferedEnd) >= yt) && (this.bufferedAdvancedAt = W()), this.lastBufferedEnd = t);
1229
+ }, vt);
1230
1230
  }
1231
1231
  checkEndStale() {
1232
1232
  if (this.endedEmitted) return;
1233
- let e = G(), t = this.lastTickAt == null ? 0 : e - this.lastTickAt;
1233
+ let e = W(), t = this.lastTickAt == null ? 0 : e - this.lastTickAt;
1234
1234
  this.lastTickAt = e;
1235
1235
  let n = this.liveEnd();
1236
1236
  if (n == null) return;
1237
- let r = this.lastSeekableEnd == null || Math.abs(n - this.lastSeekableEnd) >= xt;
1237
+ let r = this.lastSeekableEnd == null || Math.abs(n - this.lastSeekableEnd) >= St;
1238
1238
  this.lastSeekableEnd = n;
1239
1239
  let i = this.deps.video, a = typeof document < "u" && document.visibilityState === "hidden";
1240
- if (r || t > St || a || i.paused) {
1240
+ if (r || t > Ct || a || i.paused) {
1241
1241
  this.edgeStampedAt = e;
1242
1242
  return;
1243
1243
  }
1244
- e - (this.edgeStampedAt ?? e) > bt && (this.endedEmitted = !0, this.deps.emit({
1244
+ e - (this.edgeStampedAt ?? e) > xt && (this.endedEmitted = !0, this.deps.emit({
1245
1245
  type: "ended",
1246
1246
  reason: "stalled"
1247
1247
  }));
@@ -1255,9 +1255,9 @@ var W = class {
1255
1255
  liveEdgeEstimate() {
1256
1256
  let e = this.deps.video;
1257
1257
  if (e.duration !== Infinity) return null;
1258
- let t = this.liveEnd(), n = Tt(e, e.currentTime) ?? this.lastBufferedEnd;
1258
+ let t = this.liveEnd(), n = Et(e, e.currentTime) ?? this.lastBufferedEnd;
1259
1259
  if (n != null) {
1260
- let e = this.bufferedAdvancedAt, r = n + (e == null ? 0 : Math.max(0, (G() - e) / 1e3));
1260
+ let e = this.bufferedAdvancedAt, r = n + (e == null ? 0 : Math.max(0, (W() - e) / 1e3));
1261
1261
  (t == null || r > t) && (t = r);
1262
1262
  }
1263
1263
  return t != null && Number.isFinite(t) ? t : null;
@@ -1271,7 +1271,7 @@ var W = class {
1271
1271
  snapToLive() {
1272
1272
  let e = this.deps.video, t = this.liveEnd();
1273
1273
  if (t == null) return;
1274
- let n = e.seekable.start(e.seekable.length - 1), r = Math.min(e.currentTime, t), i = Math.max(n, t - mt, r);
1274
+ let n = e.seekable.start(e.seekable.length - 1), r = Math.min(e.currentTime, t), i = Math.max(n, t - ht, r);
1275
1275
  try {
1276
1276
  e.currentTime = i;
1277
1277
  } catch {}
@@ -1289,10 +1289,10 @@ var W = class {
1289
1289
  } catch {}
1290
1290
  }
1291
1291
  };
1292
- function G() {
1292
+ function W() {
1293
1293
  return typeof performance < "u" ? performance.now() : Date.now();
1294
1294
  }
1295
- function Tt(e, t) {
1295
+ function Et(e, t) {
1296
1296
  let n = e.buffered;
1297
1297
  if (!n || !Number.isFinite(t)) return null;
1298
1298
  for (let e = 0; e < n.length; e += 1) if (n.start(e) <= t + .1 && n.end(e) > t) {
@@ -1301,12 +1301,12 @@ function Tt(e, t) {
1301
1301
  }
1302
1302
  return null;
1303
1303
  }
1304
- function Et(e, t) {
1304
+ function Dt(e, t) {
1305
1305
  return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
1306
1306
  }
1307
1307
  //#endregion
1308
1308
  //#region src/core/drm/signedUrl.ts
1309
- function K(e, t = Date.now()) {
1309
+ function G(e, t = Date.now()) {
1310
1310
  if (!e) return !1;
1311
1311
  let n;
1312
1312
  try {
@@ -1318,13 +1318,13 @@ function K(e, t = Date.now()) {
1318
1318
  }
1319
1319
  //#endregion
1320
1320
  //#region src/core/drm/xhrBody.ts
1321
- var Dt = 4096;
1322
- function Ot(e) {
1321
+ var Ot = 4096;
1322
+ function kt(e) {
1323
1323
  if (!e || typeof e != "object") return;
1324
1324
  let { response: t } = e;
1325
1325
  if (typeof t == "string") return t;
1326
1326
  let n;
1327
- if (Object.prototype.toString.call(t) === "[object ArrayBuffer]" ? n = new Uint8Array(t) : ArrayBuffer.isView(t) && (n = new Uint8Array(t.buffer, t.byteOffset, t.byteLength)), !(!n || n.byteLength === 0 || n.byteLength > Dt)) try {
1327
+ if (Object.prototype.toString.call(t) === "[object ArrayBuffer]" ? n = new Uint8Array(t) : ArrayBuffer.isView(t) && (n = new Uint8Array(t.buffer, t.byteOffset, t.byteLength)), !(!n || n.byteLength === 0 || n.byteLength > Ot)) try {
1328
1328
  return new TextDecoder().decode(n);
1329
1329
  } catch {
1330
1330
  return;
@@ -1332,8 +1332,8 @@ function Ot(e) {
1332
1332
  }
1333
1333
  //#endregion
1334
1334
  //#region src/core/engine/prefetch.ts
1335
- var kt = 15e3, At = 5e3, jt = 6;
1336
- function Mt(e) {
1335
+ var At = 15e3, jt = 5e3, Mt = 6, Nt = 4e3, Pt = 2;
1336
+ function K(e) {
1337
1337
  try {
1338
1338
  let t = new URL(e);
1339
1339
  return t.searchParams.delete("CMCD"), t.toString();
@@ -1341,17 +1341,23 @@ function Mt(e) {
1341
1341
  return e;
1342
1342
  }
1343
1343
  }
1344
- var Nt = class {
1344
+ var Ft = class {
1345
1345
  cmcd;
1346
1346
  entries = /* @__PURE__ */ new Map();
1347
1347
  keyed = /* @__PURE__ */ new Set();
1348
1348
  perTrack = /* @__PURE__ */ new Map();
1349
+ hints = /* @__PURE__ */ new Map();
1349
1350
  stats = {
1350
1351
  started: 0,
1351
1352
  served: 0,
1352
1353
  missed: 0,
1353
1354
  failed: 0,
1354
- expired: 0
1355
+ expired: 0,
1356
+ hintStarted: 0,
1357
+ hintServed: 0,
1358
+ hintFailed: 0,
1359
+ hintExpired: 0,
1360
+ hintDropped: 0
1355
1361
  };
1356
1362
  constructor(e = {}) {
1357
1363
  this.cmcd = e;
@@ -1364,32 +1370,58 @@ var Nt = class {
1364
1370
  }
1365
1371
  prefetch(e, t, n) {
1366
1372
  if (!this.isActive(t)) return;
1367
- let r = Mt(e);
1373
+ let r = K(e);
1368
1374
  if (this.entries.has(r)) return;
1369
1375
  let i = this.perTrack.get(t) ?? 0;
1370
- if (i >= jt) return;
1371
- this.perTrack.set(t, i + 1);
1372
- let a = new AbortController(), o = {
1376
+ i >= Mt || (this.perTrack.set(t, i + 1), this.start(r, this.withCmcd(e, t, n), !1, At), this.stats.started += 1);
1377
+ }
1378
+ prefetchHint(e, t) {
1379
+ let n = K(e);
1380
+ if (this.entries.has(n)) return;
1381
+ let r = this.hints.get(t) ?? [];
1382
+ for (; r.length >= Pt;) {
1383
+ let e = r.shift();
1384
+ e !== void 0 && this.drop(e) && (this.stats.hintDropped += 1);
1385
+ }
1386
+ r.push(n), this.hints.set(t, r), this.start(n, this.withCmcd(e, t, "media"), !0, Nt), this.stats.hintStarted += 1;
1387
+ }
1388
+ dropHints(e) {
1389
+ for (let t of this.hints.get(e) ?? []) this.drop(t) && (this.stats.hintDropped += 1);
1390
+ this.hints.delete(e);
1391
+ }
1392
+ drop(e) {
1393
+ let t = this.entries.get(e);
1394
+ return t ? (this.entries.delete(e), t.abort.abort(), !0) : !1;
1395
+ }
1396
+ start(e, t, n, r) {
1397
+ let i = new AbortController(), a = {
1373
1398
  started: performance.now(),
1374
1399
  first: 0,
1400
+ end: 0,
1401
+ hint: n,
1402
+ headers: Promise.resolve(),
1375
1403
  bytes: Promise.resolve(null),
1376
- abort: a
1377
- };
1378
- o.bytes = fetch(this.withCmcd(e, t, n), {
1404
+ abort: i
1405
+ }, o = () => {};
1406
+ a.headers = new Promise((e) => o = e), a.bytes = fetch(t, {
1379
1407
  credentials: "omit",
1380
1408
  mode: "cors",
1381
- signal: a.signal
1382
- }).then(async (e) => (o.first = performance.now(), e.ok ? e.arrayBuffer() : null)).catch(() => null), this.entries.set(r, o), this.stats.started += 1, setTimeout(() => {
1383
- this.entries.get(r) === o && (this.entries.delete(r), a.abort(), this.stats.expired += 1);
1384
- }, kt);
1409
+ signal: i.signal
1410
+ }).then(async (e) => {
1411
+ if (a.first = performance.now(), o(), !e.ok) return null;
1412
+ let t = await e.arrayBuffer();
1413
+ return a.end = performance.now(), t;
1414
+ }).catch(() => null).finally(o), this.entries.set(e, a), setTimeout(() => {
1415
+ this.entries.get(e) === a && (this.entries.delete(e), i.abort(), n ? this.stats.hintExpired += 1 : this.stats.expired += 1);
1416
+ }, r);
1385
1417
  }
1386
1418
  take(e) {
1387
- let t = Mt(e), n = this.entries.get(t);
1419
+ let t = K(e), n = this.entries.get(t);
1388
1420
  return n && this.entries.delete(t), n;
1389
1421
  }
1390
1422
  destroy() {
1391
1423
  for (let e of this.entries.values()) e.abort.abort();
1392
- this.entries.clear();
1424
+ this.entries.clear(), this.hints.clear();
1393
1425
  }
1394
1426
  withCmcd(e, t, n) {
1395
1427
  let { sessionId: r, contentId: i } = this.cmcd;
@@ -1404,40 +1436,51 @@ var Nt = class {
1404
1436
  }
1405
1437
  }
1406
1438
  };
1407
- function Pt(t) {
1439
+ function It(t) {
1408
1440
  let n = e.DefaultConfig?.loader;
1409
1441
  if (typeof n != "function") return;
1410
1442
  class r extends n {
1411
1443
  served = !1;
1412
1444
  cancelled = !1;
1413
- stats = Ft();
1445
+ entry;
1446
+ stats = Lt();
1414
1447
  load(e, n, r) {
1415
1448
  let i = e.rangeEnd ? void 0 : t.take(e.url);
1416
1449
  if (!i) {
1417
1450
  super.load(e, n, r);
1418
1451
  return;
1419
1452
  }
1420
- this.served = !0;
1421
- let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || At, s = setTimeout(() => {
1422
- !this.cancelled && this.served && (i.abort.abort(), t.stats.failed += 1, this.served = !1, super.load(e, n, r));
1423
- }, o);
1424
- i.bytes.then((o) => {
1425
- if (clearTimeout(s), this.cancelled || !this.served) return;
1426
- if (!o) {
1427
- t.stats.failed += 1, this.served = !1, super.load(e, n, r);
1453
+ this.served = !0, this.entry = i;
1454
+ let a = performance.now(), o = () => {
1455
+ i.hint ? t.stats.hintFailed += 1 : t.stats.failed += 1;
1456
+ }, s = () => {
1457
+ !this.cancelled && this.served && (i.abort.abort(), o(), this.served = !1, this.entry = void 0, super.load(e, n, r));
1458
+ }, c = n?.loadPolicy, l = c?.maxTimeToFirstByteMs || jt, u = setTimeout(s, l);
1459
+ i.headers.then(() => {
1460
+ clearTimeout(u);
1461
+ let e = c?.maxLoadTimeMs;
1462
+ e && (u = setTimeout(s, Math.max(0, e - (performance.now() - a))));
1463
+ }), i.bytes.then((s) => {
1464
+ if (clearTimeout(u), this.cancelled || !this.served) return;
1465
+ if (!s) {
1466
+ o(), this.served = !1, super.load(e, n, r);
1428
1467
  return;
1429
1468
  }
1430
- t.stats.served += 1;
1431
1469
  let c = this.stats;
1432
- c.loading.start = a, c.loading.first = Math.max(a, i.first || a), c.loading.end = performance.now(), c.loaded = c.total = o.byteLength, r.onSuccess({
1470
+ if (i.hint) {
1471
+ t.stats.hintServed += 1;
1472
+ let e = performance.now(), n = Math.max(0, (i.end || e) - (i.first || e)), r = Math.max(0, (i.first || e) - a);
1473
+ c.loading.end = e, c.loading.first = e - n, c.loading.start = c.loading.first - r;
1474
+ } else t.stats.served += 1, c.loading.start = a, c.loading.first = Math.max(a, i.first || a), c.loading.end = performance.now();
1475
+ c.loaded = c.total = s.byteLength, this.entry = void 0, r.onSuccess({
1433
1476
  url: e.url,
1434
- data: o
1477
+ data: s
1435
1478
  }, c, e, null);
1436
1479
  });
1437
1480
  }
1438
1481
  abort() {
1439
1482
  if (this.served) {
1440
- this.cancelled = !0, this.stats.aborted = !0;
1483
+ this.cancelled = !0, this.stats.aborted = !0, this.entry?.abort.abort(), this.entry = void 0;
1441
1484
  return;
1442
1485
  }
1443
1486
  super.abort();
@@ -1445,7 +1488,7 @@ function Pt(t) {
1445
1488
  }
1446
1489
  return r;
1447
1490
  }
1448
- function Ft() {
1491
+ function Lt() {
1449
1492
  return {
1450
1493
  aborted: !1,
1451
1494
  loaded: 0,
@@ -1469,10 +1512,10 @@ function Ft() {
1469
1512
  }
1470
1513
  };
1471
1514
  }
1472
- function It(e) {
1515
+ function Rt(e) {
1473
1516
  return e === "audio" ? "audio" : "main";
1474
1517
  }
1475
- function Lt(e, t) {
1518
+ function zt(e, t) {
1476
1519
  let n = [];
1477
1520
  t.initSegment?.url && !t.initSegment.data && n.push({
1478
1521
  url: t.initSegment.url,
@@ -1489,6 +1532,17 @@ function Lt(e, t) {
1489
1532
  });
1490
1533
  return n;
1491
1534
  }
1535
+ function Bt(e) {
1536
+ let t = e, n = t?.preloadHint;
1537
+ if (!n || !t?.url || n.TYPE !== "PART" || n["BYTERANGE-START"] !== void 0 || n["BYTERANGE-LENGTH"] !== void 0) return null;
1538
+ let r = n.URI;
1539
+ if (typeof r != "string" || !r) return null;
1540
+ try {
1541
+ return new URL(r, t.url).toString();
1542
+ } catch {
1543
+ return null;
1544
+ }
1545
+ }
1492
1546
  //#endregion
1493
1547
  //#region src/core/percentile.ts
1494
1548
  function q(e, t) {
@@ -1496,11 +1550,11 @@ function q(e, t) {
1496
1550
  }
1497
1551
  //#endregion
1498
1552
  //#region src/core/engine/hls.ts
1499
- function Rt() {
1553
+ function Vt() {
1500
1554
  return e.isSupported();
1501
1555
  }
1502
- var zt = 1e6, Bt = 20, Vt = 1e4, Ht = 3, Ut = 5, Wt = 3, Gt = 1e4, Kt = 3e4, qt = 12e3, Jt = 3e3, Yt = .02, Xt = 6e3, Zt = .5, Qt = 3, $t = .5, en = 1.1, tn = .25, nn = 5e3, rn = 4e3, an = 2, on = 5, sn = 2, cn = 2, ln = 4, un = 4, dn = 2e3, fn = 3e4, pn = 1, mn = 2;
1503
- function hn(e, t, n) {
1556
+ var Ht = 3, Ut = 1e6, Wt = 20, Gt = 1e4, Kt = 3, qt = 5, Jt = 3, Yt = 1e4, Xt = 3e4, Zt = 12e3, Qt = 3e3, $t = .02, en = 6e3, tn = .5, nn = 3, rn = .5, an = 1.1, on = .25, sn = 5e3, cn = 4e3, ln = 2, un = 5, dn = 2, fn = 2, pn = 4, mn = 4, hn = 2e3, gn = 3e4, _n = 1, vn = 2;
1557
+ function yn(e, t, n) {
1504
1558
  if (n <= 0 || t < 0 || t >= e.length) return t;
1505
1559
  let r = (t, n) => e[t].width === e[n].width && e[t].height === e[n].height, i = (t) => {
1506
1560
  for (; t + 1 < e.length && r(t + 1, t);) t++;
@@ -1509,11 +1563,11 @@ function hn(e, t, n) {
1509
1563
  for (let t = 0; t < n && a + 1 < e.length; t++) a = i(a + 1);
1510
1564
  return a;
1511
1565
  }
1512
- var gn = .2, _n = 30, vn = 2, yn = 2, bn = 2, xn = 9, Sn = .5, Cn = 64, wn = 1e4, Tn = 8, En = .6, Dn = .4, On = .4, kn = 2, An = 6e4, J = .5, jn = 3.5, Mn = 300;
1513
- function Nn(e) {
1566
+ var bn = .2, xn = 30, Sn = 2, Cn = 2, wn = 2, Tn = 9, En = .5, Dn = 64, On = 1e4, kn = 8, An = .6, jn = .4, Mn = .4, Nn = 2, Pn = 6e4, J = .5, Fn = 3.5, In = 300;
1567
+ function Ln(e) {
1514
1568
  return (e?.part ?? e?.frag)?.stats;
1515
1569
  }
1516
- function Pn() {
1570
+ function Rn() {
1517
1571
  if (typeof navigator > "u") return 0;
1518
1572
  try {
1519
1573
  let e = navigator.connection?.rtt;
@@ -1522,20 +1576,20 @@ function Pn() {
1522
1576
  return 0;
1523
1577
  }
1524
1578
  }
1525
- function Fn(e) {
1579
+ function zn(e) {
1526
1580
  if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
1527
1581
  delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
1528
1582
  return;
1529
1583
  }
1530
- e.liveSyncDuration ??= bn;
1531
- let t = Math.max(12, e.liveSyncDuration + xn);
1532
- (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), In(e, e.liveSyncDuration);
1584
+ e.liveSyncDuration ??= wn;
1585
+ let t = Math.max(12, e.liveSyncDuration + Tn);
1586
+ (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), Bn(e, e.liveSyncDuration);
1533
1587
  }
1534
- function In(e, t) {
1588
+ function Bn(e, t) {
1535
1589
  let n = (e, t, n) => Math.min(n, Math.max(t, e));
1536
1590
  e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
1537
1591
  }
1538
- var Ln = class {
1592
+ var Vn = class {
1539
1593
  name = "hls";
1540
1594
  hls = null;
1541
1595
  deps;
@@ -1629,11 +1683,11 @@ var Ln = class {
1629
1683
  frameCounter;
1630
1684
  detachFrames = null;
1631
1685
  constructor(e) {
1632
- this.deps = e, this.holdBackEnabled = e.adaptiveHoldBack !== !1, this.frameCounter = new dt(e.video), this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
1686
+ this.deps = e, this.holdBackEnabled = e.adaptiveHoldBack !== !1, this.frameCounter = new ft(e.video), this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
1633
1687
  }
1634
1688
  async load() {
1635
1689
  this.detachFrames ??= this.frameCounter.attach();
1636
- let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = H(r) && U(), o = !!e.drm?.widevine?.licenseUrl && !a;
1690
+ let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = V(r) && H(), o = !!e.drm?.widevine?.licenseUrl && !a;
1637
1691
  if (e.drmEnabled && !o) {
1638
1692
  i({
1639
1693
  type: "error",
@@ -1642,7 +1696,7 @@ var Ln = class {
1642
1696
  });
1643
1697
  return;
1644
1698
  }
1645
- e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (We(r), Je()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1699
+ e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ge(r), Ye()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1646
1700
  let e = this.hls;
1647
1701
  if (document.visibilityState !== "visible" || !e) return;
1648
1702
  let t = e.liveSyncPosition;
@@ -1665,7 +1719,7 @@ var Ln = class {
1665
1719
  }
1666
1720
  this.loadSuspended = !0;
1667
1721
  }
1668
- }, nn));
1722
+ }, sn));
1669
1723
  }
1670
1724
  resumeLoading() {
1671
1725
  if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
@@ -1697,7 +1751,7 @@ var Ln = class {
1697
1751
  let t = e.liveSyncPosition;
1698
1752
  if (typeof t != "number" || !Number.isFinite(t)) return;
1699
1753
  let { video: n } = this.deps;
1700
- n.currentTime <= t + Sn || (n.currentTime = t);
1754
+ n.currentTime <= t + En || (n.currentTime = t);
1701
1755
  }
1702
1756
  reanchorPartTimeline(e, t) {
1703
1757
  let { frag: n, part: r } = t;
@@ -1709,7 +1763,7 @@ var Ln = class {
1709
1763
  let o = n.sn, s = i.fragments.find((e) => e && e.sn === o) ?? (i.fragmentHint?.sn === o ? i.fragmentHint : void 0);
1710
1764
  if (!s) return;
1711
1765
  let c = a.startPTS - s.start;
1712
- if (!(!Number.isFinite(c) || Math.abs(c) < Yt)) {
1766
+ if (!(!Number.isFinite(c) || Math.abs(c) < $t)) {
1713
1767
  for (let e of i.fragments) e && e.setStart(e.start + c);
1714
1768
  i.fragmentHint?.setStart(i.fragmentHint.start + c), this.deps.debug === !0 && console.info(`havik-player: LL-HLS timeline re-anchored by ${c >= 0 ? "+" : ""}${c.toFixed(3)}s at sn ${n.sn} (level ${n.level})`);
1715
1769
  }
@@ -1717,7 +1771,7 @@ var Ln = class {
1717
1771
  startHls() {
1718
1772
  let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps;
1719
1773
  this.clearKick(), this.resetStarvationWindow(), this.resetChaseWindow(), this.resetFrameDropWindow(), this.lastFragLoadingMs = 0, this.lastEndSN = -1, this.lastAdvanceMs = 0;
1720
- let u = n.drmEnabled && !!(n.drm?.widevine?.licenseUrl || n.drm?.fairplay?.licenseUrl), d = H(this.deps.video) && U(), f = {
1774
+ let u = n.drmEnabled && !!(n.drm?.widevine?.licenseUrl || n.drm?.fairplay?.licenseUrl), d = V(this.deps.video) && H(), f = {
1721
1775
  debug: s === !0,
1722
1776
  enableWorker: !o,
1723
1777
  lowLatencyMode: o,
@@ -1732,24 +1786,24 @@ var Ln = class {
1732
1786
  emeEnabled: !0,
1733
1787
  drmSystems: { ...this.licenseUrl ? { "com.widevine.alpha": { licenseUrl: this.licenseUrl } } : {} },
1734
1788
  drmSystemOptions: {
1735
- videoRobustness: I.video,
1736
- audioRobustness: I.audio,
1737
- videoEncryptionScheme: I.scheme,
1738
- audioEncryptionScheme: I.scheme
1789
+ videoRobustness: F.video,
1790
+ audioRobustness: F.audio,
1791
+ videoEncryptionScheme: F.scheme,
1792
+ audioEncryptionScheme: F.scheme
1739
1793
  },
1740
- ...N() ? { requestMediaKeySystemAccessFunc: Ue(t) } : {},
1794
+ ...N() ? { requestMediaKeySystemAccessFunc: We(t) } : {},
1741
1795
  licenseXhrSetup: (e, t) => {
1742
1796
  let o = performance.now(), s = () => {
1743
1797
  e.open("POST", this.licenseUrl ?? t, !0), e.setRequestHeader("x-api-key", r.apiKey), e.setRequestHeader("X-Match-Urn", n.matchUrn), e.setRequestHeader("X-Device-Id", i), a && e.setRequestHeader("X-User-Id", a), this.licenseRequested = !0, e.addEventListener("loadend", () => {
1744
1798
  this.licenseTimeMs === 0 && (this.licenseTimeMs = Math.max(1, Math.round(performance.now() - o)));
1745
1799
  });
1746
1800
  }, { freshLicenseUrl: c } = this.deps;
1747
- if (!c || !K(this.licenseUrl)) {
1801
+ if (!c || !G(this.licenseUrl)) {
1748
1802
  s();
1749
1803
  return;
1750
1804
  }
1751
1805
  let l = this.hls, u, d = new Promise((e) => {
1752
- u = setTimeout(() => e(void 0), Gt);
1806
+ u = setTimeout(() => e(void 0), Yt);
1753
1807
  });
1754
1808
  return Promise.race([c().catch(() => void 0), d]).finally(() => clearTimeout(u)).then((e) => {
1755
1809
  if (!this.hls || this.hls !== l) throw Error("havik-player: engine torn down during refresh");
@@ -1764,35 +1818,37 @@ var Ln = class {
1764
1818
  } } : {},
1765
1819
  ...c
1766
1820
  };
1767
- if (this.prefetch?.destroy(), this.prefetch = null, u && this.deps.mediaDuringKey !== !1 && !f.fLoader) {
1768
- let e = new Nt({
1821
+ this.prefetch?.destroy(), this.prefetch = null;
1822
+ let p = !1, m = !1, h = u && this.deps.mediaDuringKey !== !1, g = this.deps.preloadHints === !0;
1823
+ if ((h || g) && !f.fLoader) {
1824
+ let e = new Ft({
1769
1825
  sessionId: n.analytics?.sid,
1770
1826
  contentId: n.matchUrn
1771
- }), t = Pt(e);
1772
- t && (this.prefetch = e, f.fLoader = t);
1827
+ }), t = It(e);
1828
+ t && (this.prefetch = e, p = h, m = g, f.fLoader = t);
1773
1829
  }
1774
- Fn(f), this.catchUpRate = typeof f.maxLiveSyncPlaybackRate == "number" ? f.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (f.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = f.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = f.autoStartLoad !== !1;
1775
- let p = new e(f);
1776
- if (this.hls = p, this.armHoldBack(p, f), p.on(e.Events.FRAG_PARSED, (e, t) => this.reanchorPartTimeline(p, t)), p.on(e.Events.MANIFEST_PARSED, () => {
1777
- this.mediaRecoveries = 0, this.networkRecoveries = 0, u && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && this.dropLevelsWidevineCannotPlay(p), this.measureLadder(p), this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
1778
- }), p.on(e.Events.FRAG_BUFFERED, (e, t) => {
1830
+ zn(f), this.catchUpRate = typeof f.maxLiveSyncPlaybackRate == "number" ? f.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (f.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = f.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = f.autoStartLoad !== !1;
1831
+ let _ = new e(f);
1832
+ if (this.hls = _, this.armHoldBack(_, f), _.on(e.Events.FRAG_PARSED, (e, t) => this.reanchorPartTimeline(_, t)), _.on(e.Events.MANIFEST_PARSED, () => {
1833
+ this.mediaRecoveries = 0, this.networkRecoveries = 0, u && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && this.dropLevelsWidevineCannotPlay(_), this.measureLadder(_), this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
1834
+ }), _.on(e.Events.FRAG_BUFFERED, (e, t) => {
1779
1835
  t?.frag?.type === "main" && (this.kickKind !== "dead" && this.clearKick(), (this.mediaRecoveries > 0 || this.networkRecoveries > 0 || this.licenseRecoveries > 0 || this.starvationKicks > 0 || this.starvationRebuilds > 0) && !this.recoveryResetTimer && (this.recoveryResetTimer = setTimeout(() => {
1780
1836
  this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
1781
- }, Kt)));
1782
- }), p.on(e.Events.FRAG_LOADING, (e, t) => {
1837
+ }, Xt)));
1838
+ }), _.on(e.Events.FRAG_LOADING, (e, t) => {
1783
1839
  t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
1784
- }), p.on(e.Events.FRAG_LOADED, (e, t) => {
1840
+ }), _.on(e.Events.FRAG_LOADED, (e, t) => {
1785
1841
  t?.frag?.type === "main" && (this.mainFragsSinceTick += 1, this.bwFragsLoaded += 1, this.maybeRememberBandwidth(!1));
1786
- let n = t?.frag, r = Nn(t), i = r?.loaded;
1842
+ let n = t?.frag, r = Ln(t), i = r?.loaded;
1787
1843
  typeof i == "number" && (this.bytesLoaded += i), !this.reportedFirstBytes && typeof i == "number" && i > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
1788
1844
  let a = r?.loading;
1789
- a && a.end > 0 && a.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(a.end - a.start))), this.requestTimesMs.length > Cn && this.requestTimesMs.shift()), this.sampleHoldBack(t);
1845
+ a && a.end > 0 && a.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(a.end - a.start))), this.requestTimesMs.length > Dn && this.requestTimesMs.shift()), this.sampleHoldBack(t);
1790
1846
  let o = n?.url;
1791
1847
  if (o) {
1792
- let e = ct(o);
1848
+ let e = lt(o);
1793
1849
  e && (this.cdnHost = e);
1794
1850
  }
1795
- }), p.on(e.Events.LEVEL_LOADED, (e, t) => {
1851
+ }), _.on(e.Events.LEVEL_LOADED, (e, t) => {
1796
1852
  let n = t?.stats?.loaded;
1797
1853
  if (typeof n == "number" && (this.playlistBytesLoaded += n), this.reportedFirstPlaylist || (this.reportedFirstPlaylist = !0, l({ type: "firstPlaylist" })), this.detectedLowLatency) return;
1798
1854
  let r = t.details;
@@ -1800,31 +1856,47 @@ var Ln = class {
1800
1856
  type: "lowLatencyDetected",
1801
1857
  value: !0
1802
1858
  }));
1803
- }), p.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.prefetch) {
1859
+ }), _.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.prefetch && m) {
1860
+ let t = this.prefetch, n = this.deps.video, r = (e, r) => {
1861
+ if (n.paused) return;
1862
+ let i = e;
1863
+ if (!i?.live || !i.partList?.length || typeof i.edge != "number") return;
1864
+ let a = n.buffered, o = a.length ? a.end(a.length - 1) : 0;
1865
+ if (i.edge - o > Ht * (i.partTarget || .5)) return;
1866
+ let s = Bt(e);
1867
+ s && t.prefetchHint(s, r);
1868
+ };
1869
+ _.on(e.Events.LEVEL_LOADED, (e, t) => {
1870
+ t.level === _.loadLevel && r(t.details, "main");
1871
+ }), _.on(e.Events.AUDIO_TRACK_LOADED, (e, t) => {
1872
+ t?.id === _.audioTrack && r(t?.details, "audio");
1873
+ }), _.on(e.Events.LEVEL_SWITCHING, () => t.dropHints("main")), _.on(e.Events.AUDIO_TRACK_SWITCHING, () => t.dropHints("audio"));
1874
+ }
1875
+ if (this.prefetch && p) {
1804
1876
  let t = this.prefetch;
1805
- p.on(e.Events.KEY_LOADING, (e, n) => {
1806
- let r = n?.frag, i = It(r?.type);
1807
- if (r && t.isActive(i)) for (let e of Lt(p, r)) t.prefetch(e.url, i, e.kind);
1808
- }), p.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(It(n?.frag?.type)));
1877
+ _.on(e.Events.KEY_LOADING, (e, n) => {
1878
+ let r = n?.frag, i = Rt(r?.type);
1879
+ if (r && t.isActive(i)) for (let e of zt(_, r)) t.prefetch(e.url, i, e.kind);
1880
+ }), _.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(Rt(n?.frag?.type)));
1809
1881
  }
1810
- p.on(e.Events.KEY_LOADED, () => {
1882
+ _.on(e.Events.KEY_LOADED, () => {
1811
1883
  u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
1812
1884
  }), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
1813
1885
  this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.adaptHoldBack(), this.checkFrameDrops();
1814
- }, Jt), p.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1886
+ }, Qt), _.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1815
1887
  this.renditionSwitches += 1;
1816
- let n = this.lastLevelIndex >= 0 ? p.levels[this.lastLevelIndex] : void 0, r = p.levels[t.level];
1888
+ let n = this.lastLevelIndex >= 0 ? _.levels[this.lastLevelIndex] : void 0, r = _.levels[t.level];
1817
1889
  n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, this.armFrameDropGrace(), l({
1818
1890
  type: "qualitychange",
1819
1891
  index: t.level
1820
1892
  });
1821
- }), p.on(e.Events.AUDIO_TRACK_SWITCHED, (e, t) => l({
1893
+ }), _.on(e.Events.AUDIO_TRACK_SWITCHED, (e, t) => l({
1822
1894
  type: "audiotrackchange",
1823
1895
  id: t.id
1824
- })), p.on(e.Events.SUBTITLE_TRACK_SWITCH, (e, t) => l({
1896
+ })), _.on(e.Events.SUBTITLE_TRACK_SWITCH, (e, t) => l({
1825
1897
  type: "texttrackchange",
1826
1898
  id: t.id
1827
- })), p.on(e.Events.ERROR, (e, t) => this.onError(t)), p.loadSource(n.manifestUrl), p.attachMedia(t);
1899
+ })), _.on(e.Events.ERROR, (e, t) => this.onError(t)), _.loadSource(n.manifestUrl), _.attachMedia(t);
1828
1900
  }
1829
1901
  getQualityLevels() {
1830
1902
  return this.hls ? this.hls.levels.map((e, t) => ({
@@ -1862,9 +1934,9 @@ var Ln = class {
1862
1934
  let o = e.config ?? {}, s = typeof self < "u" && self.devicePixelRatio > 0 ? self.devicePixelRatio : 1, c = o.ignoreDevicePixelRatio ? 1 : s;
1863
1935
  c = Math.min(c, o.maxDevicePixelRatio ?? Infinity);
1864
1936
  let l = t.getMaxLevelByMediaSize(e.levels, i * c, a * c), u = this.deps.sizeCapHeadroom;
1865
- if (u == null && s >= mn) return l;
1866
- let d = u ?? pn, f = Number.isNaN(d) ? pn : d === Infinity ? e.levels.length : Math.max(0, Math.floor(d));
1867
- return hn(e.levels, l, f);
1937
+ if (u == null && s >= vn) return l;
1938
+ let d = u ?? _n, f = Number.isNaN(d) ? _n : d === Infinity ? e.levels.length : Math.max(0, Math.floor(d));
1939
+ return yn(e.levels, l, f);
1868
1940
  }
1869
1941
  onMediaResize() {
1870
1942
  if (!this.sizeCapManaged) return;
@@ -1879,7 +1951,7 @@ var Ln = class {
1879
1951
  return;
1880
1952
  }
1881
1953
  this.capTimer && clearTimeout(this.capTimer);
1882
- let t = e > this.sizeCapLevel ? dn : fn;
1954
+ let t = e > this.sizeCapLevel ? hn : gn;
1883
1955
  this.capTimer = setTimeout(() => {
1884
1956
  this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
1885
1957
  }, t);
@@ -1889,9 +1961,9 @@ var Ln = class {
1889
1961
  this.ladderHeights = t.length ? [...new Set(t)].sort((e, t) => e - t) : void 0, this.ladderTopBitrateKbps = e.levels.length ? Math.round(Math.max(...e.levels.map((e) => e.bitrate)) / 1e3) : 0;
1890
1962
  }
1891
1963
  dropLevelsWidevineCannotPlay(e) {
1892
- this.removeLevelsWhere(e, (e) => Ye(e) !== !0);
1893
- let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && L(e) !== "avc" && !!L(e)));
1894
- for (let n of t) qe(n).then((t) => {
1964
+ this.removeLevelsWhere(e, (e) => Xe(e) !== !0);
1965
+ let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && I(e) !== "avc" && !!I(e)));
1966
+ for (let n of t) Je(n).then((t) => {
1895
1967
  t || this.hls !== e || this.removeLevelsWhere(e, (e) => e === n) && (this.measureLadder(e), this.applySizeCap());
1896
1968
  });
1897
1969
  }
@@ -1899,10 +1971,10 @@ var Ln = class {
1899
1971
  let n = e.levels ?? [], r = [], i = /* @__PURE__ */ new Set();
1900
1972
  if (n.forEach((e, n) => {
1901
1973
  let a = e.videoCodec;
1902
- a && L(a) && t(a) && (r.push(n), i.add(a));
1974
+ a && I(a) && t(a) && (r.push(n), i.add(a));
1903
1975
  }), !r.length) return !1;
1904
1976
  let a = [...i].join(", ");
1905
- if (!n.some((e, t) => r.includes(t) ? !1 : !L(e.videoCodec) || Ye(e.videoCodec) === !0)) return console.warn(`havik-player: every rendition is ${a}, which Widevine may not play on this browser; keeping them`), !1;
1977
+ if (!n.some((e, t) => r.includes(t) ? !1 : !I(e.videoCodec) || Xe(e.videoCodec) === !0)) return console.warn(`havik-player: every rendition is ${a}, which Widevine may not play on this browser; keeping them`), !1;
1906
1978
  for (let t = r.length - 1; t >= 0; --t) e.removeLevel(r[t]);
1907
1979
  return console.info(`havik-player: skipped ${r.length} rendition(s) Widevine cannot play on this browser (${a})`), !0;
1908
1980
  }
@@ -2010,7 +2082,7 @@ var Ln = class {
2010
2082
  return;
2011
2083
  }
2012
2084
  let e = Date.now() - this.lastAdvanceMs;
2013
- !this.chaseSuspended && e > Xt && this.suspendChasing(), e > qt && this.emitEnded("stalled");
2085
+ !this.chaseSuspended && e > en && this.suspendChasing(), e > Zt && this.emitEnded("stalled");
2014
2086
  }
2015
2087
  resetStarvationWindow() {
2016
2088
  this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
@@ -2025,7 +2097,7 @@ var Ln = class {
2025
2097
  this.resetStarvationWindow();
2026
2098
  return;
2027
2099
  }
2028
- let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < Xt, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > rn, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = B(t), c = o - s, l = c !== this.starvedFrames;
2100
+ let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < en, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > cn, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = z(t), c = o - s, l = c !== this.starvedFrames;
2029
2101
  if (this.starvedFrames = c, !a || l) {
2030
2102
  (t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
2031
2103
  return;
@@ -2034,12 +2106,12 @@ var Ln = class {
2034
2106
  this.resetStarvationWindow();
2035
2107
  return;
2036
2108
  }
2037
- if (this.kickPending && (this.kickKind === "dead" || i) && (this.kickTicks += 1), this.starvedTicks = i ? this.starvedTicks + 1 : 0, this.deadTicks += 1, this.recentMainFrags.push(this.mainFragsSinceTick), this.mainFragsSinceTick = 0, this.recentMainFrags.length > ln && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= sn && (this.clearKick(), this.starvationRebuilds < cn)) {
2109
+ if (this.kickPending && (this.kickKind === "dead" || i) && (this.kickTicks += 1), this.starvedTicks = i ? this.starvedTicks + 1 : 0, this.deadTicks += 1, this.recentMainFrags.push(this.mainFragsSinceTick), this.mainFragsSinceTick = 0, this.recentMainFrags.length > pn && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= dn && (this.clearKick(), this.starvationRebuilds < fn)) {
2038
2110
  this.starvationRebuilds += 1, this.resetStarvationWindow(), this.clearRecoveryReset(), console.warn("havik-player: restarting the load did not resume video (the wedge is in hls.js state that only a rebuild clears) — rebuilding the player"), this.rebuildInstance("starvation rebuild");
2039
2111
  return;
2040
2112
  }
2041
- let u = i && this.starvedTicks >= an, d = !i && this.deadTicks >= ln && this.recentMainFrags.reduce((e, t) => e + t, 0) >= un;
2042
- if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= on))) {
2113
+ let u = i && this.starvedTicks >= ln, d = !i && this.deadTicks >= pn && this.recentMainFrags.reduce((e, t) => e + t, 0) >= mn;
2114
+ if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= un))) {
2043
2115
  this.starvationKicks += 1, this.kickPending = !0, this.kickTicks = 0, this.kickKind = d ? "dead" : "quiet", this.clearRecoveryReset(), console.warn(d ? "havik-player: video starved while hls.js keeps loading media it never plays (dead pipeline at the live edge) — restarting the load" : "havik-player: video starved while the live playlist advances (wedged hls.js fragment pipeline) — restarting the load");
2044
2116
  try {
2045
2117
  e.stopLoad(), e.startLoad(-1);
@@ -2054,7 +2126,7 @@ var Ln = class {
2054
2126
  let t = e.latency, n = e.targetLatency;
2055
2127
  if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
2056
2128
  let r = t - n;
2057
- !this.catchUpEngaged && r > Zt ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= Zt && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
2129
+ !this.catchUpEngaged && r > tn ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= tn && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
2058
2130
  let i = this.catchUpEngaged ? this.catchUpRate : 1;
2059
2131
  e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
2060
2132
  }
@@ -2067,7 +2139,7 @@ var Ln = class {
2067
2139
  }), n < 0 ? 0 : n;
2068
2140
  }
2069
2141
  armFrameDropGrace() {
2070
- this.fpsGraceTicks > 0 || (this.fpsGraceTicks = yn, this.fpsBadTicks = 0);
2142
+ this.fpsGraceTicks > 0 || (this.fpsGraceTicks = Cn, this.fpsBadTicks = 0);
2071
2143
  }
2072
2144
  resetFrameDropWindow() {
2073
2145
  this.fpsLastFrames = -1, this.fpsLastDropped = -1, this.fpsBadTicks = 0;
@@ -2078,8 +2150,8 @@ var Ln = class {
2078
2150
  this.resetFrameDropWindow();
2079
2151
  return;
2080
2152
  }
2081
- let { totalFrames: n, dropped: r } = B(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
2082
- if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < _n || o < 0) {
2153
+ let { totalFrames: n, dropped: r } = z(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
2154
+ if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < xn || o < 0) {
2083
2155
  this.fpsBadTicks = 0;
2084
2156
  return;
2085
2157
  }
@@ -2087,11 +2159,11 @@ var Ln = class {
2087
2159
  --this.fpsGraceTicks, this.fpsBadTicks = 0;
2088
2160
  return;
2089
2161
  }
2090
- if (o <= gn * a) {
2162
+ if (o <= bn * a) {
2091
2163
  this.fpsBadTicks = 0;
2092
2164
  return;
2093
2165
  }
2094
- if (this.fpsBadTicks += 1, this.fpsBadTicks < vn) return;
2166
+ if (this.fpsBadTicks += 1, this.fpsBadTicks < Sn) return;
2095
2167
  this.fpsBadTicks = 0;
2096
2168
  let s = e.levels, c = s[e.currentLevel];
2097
2169
  if (!c) return;
@@ -2108,22 +2180,22 @@ var Ln = class {
2108
2180
  return;
2109
2181
  }
2110
2182
  let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
2111
- if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(en, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
2183
+ if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(an, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
2112
2184
  this.resetChaseWindow();
2113
2185
  return;
2114
2186
  }
2115
- if (this.chaseLatency < 0 || this.chaseLatency - n >= $t) {
2187
+ if (this.chaseLatency < 0 || this.chaseLatency - n >= rn) {
2116
2188
  this.chaseLatency = n, this.chaseTicks = 0;
2117
2189
  return;
2118
2190
  }
2119
- if (this.chaseTicks += 1, this.chaseTicks < Qt) return;
2191
+ if (this.chaseTicks += 1, this.chaseTicks < nn) return;
2120
2192
  this.resetChaseWindow();
2121
2193
  let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
2122
2194
  if (!(a > 1)) return;
2123
2195
  let o = e.targetLatency;
2124
2196
  if (typeof o != "number" || !(o > 0)) return;
2125
2197
  let s = Math.min(n, a - 1);
2126
- s < o + tn || (console.warn(`havik-player: catch-up at ${r}x not gaining on the live edge (latency ${n.toFixed(1)}s); holding at ${s.toFixed(1)}s`), this.liveRetargets += 1, e.targetLatency = s, this.deps.emit({
2198
+ s < o + on || (console.warn(`havik-player: catch-up at ${r}x not gaining on the live edge (latency ${n.toFixed(1)}s); holding at ${s.toFixed(1)}s`), this.liveRetargets += 1, e.targetLatency = s, this.deps.emit({
2127
2199
  type: "livetargetchange",
2128
2200
  change: {
2129
2201
  targetSeconds: s,
@@ -2140,13 +2212,13 @@ var Ln = class {
2140
2212
  if (!this.holdBackEnabled || this.holdBackPriorChecked || !e || (this.holdBackPriorChecked = !0, this.holdBackApplied > 0 || this.holdBackStepCount > 0)) return;
2141
2213
  let t = e.targetLatency;
2142
2214
  if (this.holdBackBase < 0 && typeof t == "number" && t > 0 && (this.holdBackBase = t), this.holdBackBase < 0) return;
2143
- let n = Pn();
2144
- if (!(n >= Mn)) return;
2215
+ let n = Rn();
2216
+ if (!(n >= In)) return;
2145
2217
  let r = typeof t == "number" && t > 0 ? t : this.holdBackBase, i = Math.min(this.holdBackCeiling(e), this.holdBackBase + J);
2146
2218
  i > r && (this.holdBackStepCount = 1, this.moveHoldBack(e, r, i, "connection-rtt", `connection rtt ${n} ms`));
2147
2219
  }
2148
2220
  holdBackCeiling(e) {
2149
- let t = this.deps.adaptiveHoldBackCeiling, n = typeof t == "number" && Number.isFinite(t) ? t : jn, r = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
2221
+ let t = this.deps.adaptiveHoldBackCeiling, n = typeof t == "number" && Number.isFinite(t) ? t : Fn, r = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
2150
2222
  return r > 1 ? Math.min(n, r - 1) : n;
2151
2223
  }
2152
2224
  sampleHoldBack(e) {
@@ -2155,7 +2227,7 @@ var Ln = class {
2155
2227
  if (t !== "main" && t !== "audio") return;
2156
2228
  let n = e.part ? e.part.duration : this.detectedLowLatency ? 0 : e.frag?.duration;
2157
2229
  if (typeof n != "number" || !(n > 0)) return;
2158
- let r = Nn(e)?.loading;
2230
+ let r = Ln(e)?.loading;
2159
2231
  if (!r || !(r.start > 0) || !(r.end > 0)) return;
2160
2232
  let i = r.first > r.start ? r.first : r.end, a = Math.max(0, i - r.start) / (n * 1e3);
2161
2233
  this.holdBackSamples.push({
@@ -2170,20 +2242,20 @@ var Ln = class {
2170
2242
  this.holdBackSlowTicks = 0, this.holdBackFastSince = 0, this.holdBackSamples = [];
2171
2243
  return;
2172
2244
  }
2173
- let t = Date.now(), n = t - wn, r = this.holdBackSamples, i = 0;
2245
+ let t = Date.now(), n = t - On, r = this.holdBackSamples, i = 0;
2174
2246
  for (; i < r.length && r[i].t < n;) i += 1;
2175
2247
  i > 0 && r.splice(0, i);
2176
2248
  let a = e.targetLatency;
2177
2249
  if (typeof a != "number" || !(a > 0)) return;
2178
2250
  this.holdBackBase < 0 && (this.holdBackBase = a);
2179
2251
  let o = this.holdBackBase, s = this.holdBackCeiling(e);
2180
- if (r.length < Tn) {
2252
+ if (r.length < kn) {
2181
2253
  this.holdBackSlowTicks = 0;
2182
2254
  return;
2183
2255
  }
2184
2256
  let c = r.map((e) => e.ratio).sort((e, t) => e - t), l = q(c, 95), u = q(c, 50), d = Math.round(l * 1e3);
2185
- if (l >= En && u >= Dn) {
2186
- if (this.holdBackFastSince = 0, this.holdBackSlowTicks += 1, this.holdBackSlowTicks < kn) return;
2257
+ if (l >= An && u >= jn) {
2258
+ if (this.holdBackFastSince = 0, this.holdBackSlowTicks += 1, this.holdBackSlowTicks < Nn) return;
2187
2259
  this.holdBackSlowTicks = 0;
2188
2260
  let t = Math.ceil((s - o) / J), n = Math.ceil((a - o) / J - 1e-9);
2189
2261
  if (n > this.holdBackStepCount && (this.holdBackStepCount = n), this.holdBackStepCount >= t) return;
@@ -2193,7 +2265,7 @@ var Ln = class {
2193
2265
  this.moveHoldBack(e, a, r, "slow-fetches", `part fetches slow (first byte p50 ${Math.round(u * 1e3)} / p95 ${d} ms per 1 s of media)`);
2194
2266
  return;
2195
2267
  }
2196
- if (this.holdBackSlowTicks = 0, l >= On) {
2268
+ if (this.holdBackSlowTicks = 0, l >= Mn) {
2197
2269
  this.holdBackFastSince = 0;
2198
2270
  return;
2199
2271
  }
@@ -2201,7 +2273,7 @@ var Ln = class {
2201
2273
  this.holdBackFastSince = t;
2202
2274
  return;
2203
2275
  }
2204
- if (t - this.holdBackFastSince < An || (this.holdBackFastSince = t, this.holdBackStepCount === 0 || a !== this.holdBackApplied)) return;
2276
+ if (t - this.holdBackFastSince < Pn || (this.holdBackFastSince = t, this.holdBackStepCount === 0 || a !== this.holdBackApplied)) return;
2205
2277
  --this.holdBackStepCount;
2206
2278
  let f = Math.max(o, o + this.holdBackStepCount * J);
2207
2279
  f >= a || this.moveHoldBack(e, a, f, "fast-fetches", `part fetches fast again (p95 first byte ${d} ms per 1 s of media)`);
@@ -2244,12 +2316,12 @@ var Ln = class {
2244
2316
  } catch {}
2245
2317
  }
2246
2318
  startEstimate() {
2247
- return this.deps.rememberBandwidth === !1 ? zt : Le() ?? zt;
2319
+ return this.deps.rememberBandwidth === !1 ? Ut : Le() ?? Ut;
2248
2320
  }
2249
2321
  maybeRememberBandwidth(e) {
2250
- if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded < Bt) return;
2322
+ if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded < Wt) return;
2251
2323
  let t = Date.now();
2252
- if (!e && t - this.bwSavedAt < Vt) return;
2324
+ if (!e && t - this.bwSavedAt < Gt) return;
2253
2325
  let n = this.hls?.bandwidthEstimate;
2254
2326
  typeof n != "number" || !Number.isFinite(n) || n <= 0 || (this.bwSavedAt = t, Re(n));
2255
2327
  }
@@ -2269,7 +2341,7 @@ var Ln = class {
2269
2341
  scheduleLicenseRetry(t) {
2270
2342
  if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
2271
2343
  let n = t.response?.code ?? 0;
2272
- if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= Wt) return !1;
2344
+ if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= Jt) return !1;
2273
2345
  this.licenseRecoveries += 1;
2274
2346
  let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
2275
2347
  return this.licenseRetryTimer = setTimeout(() => {
@@ -2301,7 +2373,7 @@ var Ln = class {
2301
2373
  return;
2302
2374
  }
2303
2375
  if (t.type === e.ErrorTypes.NETWORK_ERROR) {
2304
- if (this.networkRecoveries < Ut) {
2376
+ if (this.networkRecoveries < qt) {
2305
2377
  this.networkRecoveries += 1;
2306
2378
  let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
2307
2379
  this.networkRetryTimer = setTimeout(() => {
@@ -2318,7 +2390,7 @@ var Ln = class {
2318
2390
  return;
2319
2391
  }
2320
2392
  if (t.type === e.ErrorTypes.MEDIA_ERROR) {
2321
- if (this.mediaRecoveries < Ht) {
2393
+ if (this.mediaRecoveries < Kt) {
2322
2394
  this.mediaRecoveries += 1, n.recoverMediaError();
2323
2395
  return;
2324
2396
  }
@@ -2339,18 +2411,18 @@ var Ln = class {
2339
2411
  }
2340
2412
  }
2341
2413
  toError(t, r = "PLAYBACK") {
2342
- let o = t.response?.code ?? 0, s = t.details ?? t.type, c = t.reason ?? t.error?.message ?? "", l = r === "DRM" && o === 403 && t.details === e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED ? i(Ot(t.networkDetails)) : void 0;
2414
+ let o = t.response?.code ?? 0, s = t.details ?? t.type, c = t.reason ?? t.error?.message ?? "", l = r === "DRM" && o === 403 && t.details === e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED ? i(kt(t.networkDetails)) : void 0;
2343
2415
  return new n(r === "DRM" ? a(o, l) : o === 401 ? "UNAUTHORIZED" : o === 403 ? "FORBIDDEN" : "INTERNAL", o, `${r} error: ${s}${c ? ` (${c})` : ""}`, l ? { serverCode: l } : void 0);
2344
2416
  }
2345
- }, Rn = 15e3, zn = 6e5, Bn = 3e5, Vn = 100, Y = 1, Hn = 1e3, Un = 3e4, Wn = 1e3, Gn = {
2417
+ }, Hn = 15e3, Un = 6e5, Wn = 3e5, Gn = 100, Y = 1, Kn = 1e3, qn = 3e4, Jn = 1e3, Yn = {
2346
2418
  inline: "PRESENTATION_INLINE",
2347
2419
  fullscreen: "PRESENTATION_FULLSCREEN",
2348
2420
  pip: "PRESENTATION_PIP"
2349
- }, Kn = {
2421
+ }, Xn = {
2350
2422
  widevine: "KEY_SYSTEM_WIDEVINE",
2351
2423
  fairplay: "KEY_SYSTEM_FAIRPLAY",
2352
2424
  none: "KEY_SYSTEM_NONE"
2353
- }, qn = /* @__PURE__ */ new Set([
2425
+ }, Zn = /* @__PURE__ */ new Set([
2354
2426
  "INVALID_URN",
2355
2427
  "NOT_FOUND",
2356
2428
  "GEO_DENIED",
@@ -2371,7 +2443,7 @@ var Ln = class {
2371
2443
  ended: "PLAYER_STATE_ENDED",
2372
2444
  error: "PLAYER_STATE_ERROR"
2373
2445
  };
2374
- function Jn(e) {
2446
+ function Qn(e) {
2375
2447
  try {
2376
2448
  let t = new URL(e), [n, ...r] = t.hostname.split(".");
2377
2449
  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);
@@ -2379,8 +2451,8 @@ function Jn(e) {
2379
2451
  return;
2380
2452
  }
2381
2453
  }
2382
- var Yn = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), Xn = /* @__PURE__ */ new Set(), Z = /* @__PURE__ */ new Set(), Q = /* @__PURE__ */ new Set(), Zn = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
2383
- function Qn(e) {
2454
+ var $n = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), er = /* @__PURE__ */ new Set(), Z = /* @__PURE__ */ new Set(), Q = /* @__PURE__ */ new Set(), tr = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
2455
+ function nr(e) {
2384
2456
  if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
2385
2457
  let t;
2386
2458
  try {
@@ -2389,19 +2461,19 @@ function Qn(e) {
2389
2461
  } catch {
2390
2462
  return;
2391
2463
  }
2392
- if (Xn.has(t) && !Z.has(t)) {
2393
- Z.add(t), _(Zn(new URL(t).origin));
2464
+ if (er.has(t) && !Z.has(t)) {
2465
+ Z.add(t), _(tr(new URL(t).origin));
2394
2466
  for (let e of Q) e.noteCspBlocked();
2395
2467
  }
2396
2468
  }
2397
- function $n(e, t) {
2469
+ function rr(e, t) {
2398
2470
  return _(t, e), { disabledReason: t };
2399
2471
  }
2400
- function er(e, t, n) {
2401
- if (n) return t && !Yn(t, n) && _(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
2472
+ function ir(e, t, n) {
2473
+ if (n) return t && !$n(t, n) && _(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
2402
2474
  if (t) return { endpoint: t };
2403
- if (t !== void 0) return $n("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).");
2404
- let r = Jn(e);
2475
+ if (t !== void 0) return rr("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).");
2476
+ let r = Qn(e);
2405
2477
  if (r) return { endpoint: r };
2406
2478
  let i;
2407
2479
  try {
@@ -2409,9 +2481,9 @@ function er(e, t, n) {
2409
2481
  } catch {
2410
2482
  i = e;
2411
2483
  }
2412
- return $n(i, `analytics is disabled: no QoE beacons will be sent. The beacons endpoint cannot be derived from the baseUrl host "${i}" — the convention is feed[-dev].<domain> → beacons[-dev].<domain>. Pass an explicit endpoint, analytics: { endpoint: 'https://beacons[-dev].<domain>' }, to createPlayer (or analytics: false to opt out deliberately).`);
2484
+ return rr(i, `analytics is disabled: no QoE beacons will be sent. The beacons endpoint cannot be derived from the baseUrl host "${i}" — the convention is feed[-dev].<domain> → beacons[-dev].<domain>. Pass an explicit endpoint, analytics: { endpoint: 'https://beacons[-dev].<domain>' }, to createPlayer (or analytics: false to opt out deliberately).`);
2413
2485
  }
2414
- var tr = class {
2486
+ var ar = class {
2415
2487
  opts;
2416
2488
  url;
2417
2489
  cspKey;
@@ -2493,8 +2565,8 @@ var tr = class {
2493
2565
  constructor(e) {
2494
2566
  this.opts = {
2495
2567
  ...e,
2496
- heartbeatMs: e.heartbeatMs ?? Rn,
2497
- idleMs: e.idleMs ?? zn
2568
+ heartbeatMs: e.heartbeatMs ?? Hn,
2569
+ idleMs: e.idleMs ?? Un
2498
2570
  }, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
2499
2571
  try {
2500
2572
  let e = new URL(this.url);
@@ -2511,11 +2583,11 @@ var tr = class {
2511
2583
  sdkVersion: this.opts.sdkVersion,
2512
2584
  ...this.opts.environment
2513
2585
  };
2514
- this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Hn), this.lastTickMs = this.now(), this.timer = setInterval(() => this.heartbeat(), this.opts.heartbeatMs), typeof window < "u" && window.addEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.addEventListener("visibilitychange", this.onVisibility), document.addEventListener("freeze", this.onFreeze), document.addEventListener("resume", this.onResume), this.cspKey && Xn.add(this.cspKey), document.addEventListener("securitypolicyviolation", Qn), Q.add(this), this.noteCspBlocked(), this.onVisibility());
2586
+ this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Kn), this.lastTickMs = this.now(), this.timer = setInterval(() => this.heartbeat(), this.opts.heartbeatMs), typeof window < "u" && window.addEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.addEventListener("visibilitychange", this.onVisibility), document.addEventListener("freeze", this.onFreeze), document.addEventListener("resume", this.onResume), this.cspKey && er.add(this.cspKey), document.addEventListener("securitypolicyviolation", nr), Q.add(this), this.noteCspBlocked(), this.onVisibility());
2515
2587
  }
2516
2588
  checkSuspension(e) {
2517
2589
  if (this.endedFlag || !this.opts.idleMs) return !1;
2518
- let t = Math.max(this.opts.idleMs, Bn);
2590
+ let t = Math.max(this.opts.idleMs, Wn);
2519
2591
  return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
2520
2592
  }
2521
2593
  syncIdle(e) {
@@ -2538,12 +2610,12 @@ var tr = class {
2538
2610
  let a = {
2539
2611
  fromState: X[e] ?? "PLAYER_STATE_UNSPECIFIED",
2540
2612
  toState: X[t] ?? "PLAYER_STATE_UNSPECIFIED",
2541
- presentation: Gn[this.presentation]
2613
+ presentation: Yn[this.presentation]
2542
2614
  }, o = this.causeOf(e, t, i);
2543
2615
  o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
2544
2616
  }
2545
2617
  seekInduced(e) {
2546
- return this.lastSeekMs >= 0 && e - this.lastSeekMs < Wn;
2618
+ return this.lastSeekMs >= 0 && e - this.lastSeekMs < Jn;
2547
2619
  }
2548
2620
  causeOf(e, t, n) {
2549
2621
  if (t === "error") return "TRANSITION_CAUSE_ERROR";
@@ -2617,7 +2689,7 @@ var tr = class {
2617
2689
  let r = n ?? "";
2618
2690
  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";
2619
2691
  if (e === "DRM_CLIENT" || e === "DRM_DEVICE_REVOKED") return "ERROR_STAGE_DRM";
2620
- if (qn.has(e)) return "ERROR_STAGE_RESOLVE";
2692
+ if (Zn.has(e)) return "ERROR_STAGE_RESOLVE";
2621
2693
  let i = t ?? "";
2622
2694
  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";
2623
2695
  }
@@ -2671,7 +2743,7 @@ var tr = class {
2671
2743
  maybeEmitMediaInfo(e) {
2672
2744
  if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
2673
2745
  let t = {};
2674
- e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = Kn[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);
2746
+ e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = Xn[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);
2675
2747
  let n = JSON.stringify(t);
2676
2748
  n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
2677
2749
  }
@@ -2691,7 +2763,7 @@ var tr = class {
2691
2763
  let c = r?.positionMs ?? 0;
2692
2764
  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));
2693
2765
  let l = e !== "END_REASON_ENDED";
2694
- l && this.lastStallMs > 0 && n - this.lastStallMs <= Un && (i.abandonAfterStallMs = Math.max(Y, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= Un && (i.abandonAfterErrorMs = Math.max(Y, Math.round(n - this.lastErrorMs))), this.fullscreenTotalMs > 0 && (i.fullscreenTimeMs = Math.round(this.fullscreenTotalMs)), this.pipTotalMs > 0 && (i.pipTimeMs = Math.round(this.pipTotalMs)), this.volumeChanges > 0 && (i.volumeChanges = this.volumeChanges), this.muteChanges > 0 && (i.muteChanges = this.muteChanges);
2766
+ l && this.lastStallMs > 0 && n - this.lastStallMs <= qn && (i.abandonAfterStallMs = Math.max(Y, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= qn && (i.abandonAfterErrorMs = Math.max(Y, Math.round(n - this.lastErrorMs))), this.fullscreenTotalMs > 0 && (i.fullscreenTimeMs = Math.round(this.fullscreenTotalMs)), this.pipTotalMs > 0 && (i.pipTimeMs = Math.round(this.pipTotalMs)), this.volumeChanges > 0 && (i.volumeChanges = this.volumeChanges), this.muteChanges > 0 && (i.muteChanges = this.muteChanges);
2695
2767
  let u = r?.decodedFrames ?? this.lastDecoded;
2696
2768
  u > 0 && (i.decodedFramesTotal = u), e === "END_REASON_STOPPED" && this.startupTimeMs === 0 && this.lastErrorStage === null && (e = "END_REASON_ABORTED", i.reason = e), this.startupTimeMs === 0 && e !== "END_REASON_ABORTED" && (i.failedStage = this.lastErrorStage ?? (this.manifestLoadMs === 0 ? "ERROR_STAGE_MANIFEST" : this.firstFragLoadMs === 0 ? "ERROR_STAGE_FIRST_SEGMENT" : "ERROR_STAGE_OTHER")), this.pending.push(this.wrap({ sessionEnd: i })), this.flush(e === "END_REASON_PAGEHIDE");
2697
2769
  }
@@ -2711,13 +2783,13 @@ var tr = class {
2711
2783
  };
2712
2784
  }
2713
2785
  noteCspBlocked() {
2714
- this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(Zn(new URL(this.url).origin)));
2786
+ this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(tr(new URL(this.url).origin)));
2715
2787
  }
2716
2788
  cspBlocked() {
2717
2789
  return !!this.cspKey && Z.has(this.cspKey);
2718
2790
  }
2719
2791
  enqueue(e) {
2720
- if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > Vn;) {
2792
+ if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > Gn;) {
2721
2793
  let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
2722
2794
  this.pending.splice(e >= 0 ? e : 0, 1);
2723
2795
  }
@@ -2744,7 +2816,7 @@ var tr = class {
2744
2816
  };
2745
2817
  //#endregion
2746
2818
  //#region src/core/environment.ts
2747
- function nr() {
2819
+ function or() {
2748
2820
  if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
2749
2821
  let e;
2750
2822
  try {
@@ -2769,14 +2841,14 @@ function nr() {
2769
2841
  integration: "INTEGRATION_KIND_IFRAME"
2770
2842
  };
2771
2843
  }
2772
- function rr() {
2844
+ function sr() {
2773
2845
  if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
2774
2846
  let e = navigator.userAgentData, t = e?.platform ?? "";
2775
2847
  if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
2776
2848
  let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
2777
2849
  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";
2778
2850
  }
2779
- function ir() {
2851
+ function cr() {
2780
2852
  let e = typeof navigator < "u" ? navigator.connection : void 0;
2781
2853
  if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
2782
2854
  let t = {
@@ -2795,17 +2867,17 @@ function ir() {
2795
2867
  }
2796
2868
  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;
2797
2869
  }
2798
- function ar(e) {
2799
- let t = nr(), n = {
2800
- deviceClass: rr(),
2870
+ function lr(e) {
2871
+ let t = or(), n = {
2872
+ deviceClass: sr(),
2801
2873
  integration: t.integration,
2802
- ...ir()
2874
+ ...cr()
2803
2875
  };
2804
2876
  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);
2805
2877
  let r = e.getBoundingClientRect?.();
2806
2878
  return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
2807
2879
  }
2808
- async function or() {
2880
+ async function ur() {
2809
2881
  let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
2810
2882
  if (!e?.getHighEntropyValues) return {};
2811
2883
  try {
@@ -2817,7 +2889,7 @@ async function or() {
2817
2889
  }
2818
2890
  //#endregion
2819
2891
  //#region src/core/version.ts
2820
- var sr = "2.23.4", cr = {
2892
+ var dr = "2.24.0", fr = {
2821
2893
  accent: "#E1B600",
2822
2894
  accentText: "#1B1C23",
2823
2895
  background: "#0e0f13",
@@ -2828,7 +2900,7 @@ var sr = "2.23.4", cr = {
2828
2900
  border: "rgba(255, 255, 255, 0.1)",
2829
2901
  radius: "8px",
2830
2902
  fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
2831
- }, lr = {
2903
+ }, pr = {
2832
2904
  accent: "--havik-accent",
2833
2905
  accentText: "--havik-accent-text",
2834
2906
  background: "--havik-bg",
@@ -2840,26 +2912,26 @@ var sr = "2.23.4", cr = {
2840
2912
  radius: "--havik-radius",
2841
2913
  fontFamily: "--havik-font"
2842
2914
  };
2843
- function ur(e, t) {
2915
+ function mr(e, t) {
2844
2916
  let n = {
2845
- ...cr,
2917
+ ...fr,
2846
2918
  ...t
2847
2919
  };
2848
- for (let t of Object.keys(lr)) e.style.setProperty(lr[t], n[t]);
2920
+ for (let t of Object.keys(pr)) e.style.setProperty(pr[t], n[t]);
2849
2921
  n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
2850
2922
  }
2851
2923
  //#endregion
2852
2924
  //#region src/ui/styles.ts
2853
- var dr = "havik-player-styles", fr = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer;\n touch-action:manipulation}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n/* Absolutely centred, NOT a flex sibling of .havik-center: the hidden center\n button (.havik-gone) still occupies its 74px in the row, which pushed an\n in-flow spinner 37px right of centre. */\n.havik-spinner{position:absolute;inset:0;margin:auto;width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n/* A status card carries its own logo — the corner watermark would duplicate it. */\n.havik-player.havik-has-status .havik-watermark{display:none}\n\n.havik-bar{position:absolute;left:0;right:0;bottom:0;padding:0 12px 8px;\n opacity:1;transition:opacity .25s;z-index:2}\n.havik-seek{position:relative;height:16px;display:flex;align-items:center;cursor:pointer;margin-bottom:2px}\n.havik-seek__track{position:relative;width:100%;height:4px;border-radius:3px;background:rgba(255,255,255,.25)}\n.havik-seek__buffered{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:rgba(255,255,255,.4)}\n.havik-seek__played{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-seek__thumb{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;\n background:var(--havik-accent,#E1B600);transform:translate(-50%,-50%) scale(0);transition:transform .1s}\n.havik-seek:hover .havik-seek__thumb{transform:translate(-50%,-50%) scale(1)}\n\n.havik-controls{display:flex;align-items:center;gap:6px;height:40px}\n.havik-spacer{flex:1}\n.havik-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;border-radius:var(--havik-radius,8px);\n padding:0;transition:background .12s,color .12s}\n.havik-btn:hover{background:rgba(255,255,255,.12)}\n.havik-btn:focus-visible{outline:2px solid var(--havik-accent,#E1B600);outline-offset:1px}\n.havik-btn svg{width:22px;height:22px}\n\n/* The volume level is filled in accent up to the thumb, like the seek bar's\n played span — a native range input paints no \"elapsed\" side, which left the\n level readable only from the dot's position. --havik-vol (0..1) is set by\n syncVolume(); the track width and thumb size live here as variables because\n the WebKit fill has to compute the thumb centre from both. */\n.havik-vol{display:flex;align-items:center}\n.havik-vol__slider{--havik-vol-w:70px;--havik-vol-thumb:12px;--havik-vol:1;\n --havik-vol-pos:calc(var(--havik-vol-thumb) / 2 + var(--havik-vol) * (var(--havik-vol-w) - var(--havik-vol-thumb)));\n width:0;opacity:0;transition:width .18s,opacity .18s;height:4px;cursor:pointer;\n appearance:none;-webkit-appearance:none;background:transparent;border-radius:3px;margin:0 4px}\n.havik-vol:hover .havik-vol__slider,.havik-vol:focus-within .havik-vol__slider{width:var(--havik-vol-w);opacity:1}\n/* WebKit/Blink have no progress pseudo-element: paint the fill as a hard-stop\n gradient that ends at the thumb centre. */\n.havik-vol__slider::-webkit-slider-runnable-track{height:4px;border-radius:3px;\n background:linear-gradient(to right,var(--havik-accent,#E1B600) var(--havik-vol-pos),\n rgba(255,255,255,.3) var(--havik-vol-pos))}\n/* Firefox fills natively, and tracks the thumb exactly. */\n.havik-vol__slider::-moz-range-track{height:4px;border-radius:3px;background:rgba(255,255,255,.3)}\n.havik-vol__slider::-moz-range-progress{height:4px;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-vol__slider::-webkit-slider-thumb{-webkit-appearance:none;width:var(--havik-vol-thumb);\n height:var(--havik-vol-thumb);border-radius:50%;background:var(--havik-accent,#E1B600);\n margin-top:calc((4px - var(--havik-vol-thumb)) / 2)}\n.havik-vol__slider::-moz-range-thumb{width:var(--havik-vol-thumb);height:var(--havik-vol-thumb);\n border:0;border-radius:50%;background:var(--havik-accent,#E1B600)}\n\n.havik-time{font-size:12px;color:var(--havik-text-muted,#9aa0ad);\n font-variant-numeric:tabular-nums;padding:0 6px;white-space:nowrap}\n.havik-live{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;\n letter-spacing:.4px;padding:0 8px;color:var(--havik-text,#fff)}\n.havik-live svg{width:9px;height:9px;color:var(--havik-text-muted,#9aa0ad)}\n.havik-live.is-live svg{color:var(--havik-accent,#E1B600)}\n.havik-live__go{margin-left:2px;border:0;cursor:pointer;background:transparent;color:var(--havik-text-muted,#9aa0ad);\n font:inherit;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:6px}\n.havik-live.is-live .havik-live__go{display:none}\n.havik-live__go:hover{color:var(--havik-accent,#E1B600)}\n\n.havik-menu{position:absolute;bottom:54px;right:12px;min-width:170px;max-height:230px;overflow:auto;\n background:var(--havik-surface,#1B1C23);border:1px solid var(--havik-border,rgba(255,255,255,.1));\n border-radius:var(--havik-radius,8px);box-shadow:0 10px 30px rgba(0,0,0,.5);padding:6px;z-index:3}\n.havik-menu[hidden]{display:none}\n.havik-menu__title{font-size:11px;text-transform:uppercase;letter-spacing:.6px;\n color:var(--havik-text-muted,#9aa0ad);padding:6px 8px 4px}\n.havik-menu__item{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;font:inherit;font-size:13px;\n text-align:left;padding:7px 8px;border-radius:6px}\n.havik-menu__item:hover{background:var(--havik-surface-muted,#2a2c36)}\n.havik-menu__item[aria-checked=\"true\"]{color:var(--havik-accent,#E1B600);font-weight:600}\n.havik-menu__item[aria-checked=\"true\"]::after{content:'✓'}\n", pr = /* @__PURE__ */ new WeakMap();
2854
- function mr(e = document, t) {
2855
- let n = e.querySelector(`style#${dr}`);
2856
- if (n && (!t || pr.get(n) === t)) return;
2925
+ var hr = "havik-player-styles", gr = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer;\n touch-action:manipulation}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n/* Absolutely centred, NOT a flex sibling of .havik-center: the hidden center\n button (.havik-gone) still occupies its 74px in the row, which pushed an\n in-flow spinner 37px right of centre. */\n.havik-spinner{position:absolute;inset:0;margin:auto;width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n/* A status card carries its own logo — the corner watermark would duplicate it. */\n.havik-player.havik-has-status .havik-watermark{display:none}\n\n.havik-bar{position:absolute;left:0;right:0;bottom:0;padding:0 12px 8px;\n opacity:1;transition:opacity .25s;z-index:2}\n.havik-seek{position:relative;height:16px;display:flex;align-items:center;cursor:pointer;margin-bottom:2px}\n.havik-seek__track{position:relative;width:100%;height:4px;border-radius:3px;background:rgba(255,255,255,.25)}\n.havik-seek__buffered{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:rgba(255,255,255,.4)}\n.havik-seek__played{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-seek__thumb{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;\n background:var(--havik-accent,#E1B600);transform:translate(-50%,-50%) scale(0);transition:transform .1s}\n.havik-seek:hover .havik-seek__thumb{transform:translate(-50%,-50%) scale(1)}\n\n.havik-controls{display:flex;align-items:center;gap:6px;height:40px}\n.havik-spacer{flex:1}\n.havik-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;border-radius:var(--havik-radius,8px);\n padding:0;transition:background .12s,color .12s}\n.havik-btn:hover{background:rgba(255,255,255,.12)}\n.havik-btn:focus-visible{outline:2px solid var(--havik-accent,#E1B600);outline-offset:1px}\n.havik-btn svg{width:22px;height:22px}\n\n/* The volume level is filled in accent up to the thumb, like the seek bar's\n played span — a native range input paints no \"elapsed\" side, which left the\n level readable only from the dot's position. --havik-vol (0..1) is set by\n syncVolume(); the track width and thumb size live here as variables because\n the WebKit fill has to compute the thumb centre from both. */\n.havik-vol{display:flex;align-items:center}\n.havik-vol__slider{--havik-vol-w:70px;--havik-vol-thumb:12px;--havik-vol:1;\n --havik-vol-pos:calc(var(--havik-vol-thumb) / 2 + var(--havik-vol) * (var(--havik-vol-w) - var(--havik-vol-thumb)));\n width:0;opacity:0;transition:width .18s,opacity .18s;height:4px;cursor:pointer;\n appearance:none;-webkit-appearance:none;background:transparent;border-radius:3px;margin:0 4px}\n.havik-vol:hover .havik-vol__slider,.havik-vol:focus-within .havik-vol__slider{width:var(--havik-vol-w);opacity:1}\n/* WebKit/Blink have no progress pseudo-element: paint the fill as a hard-stop\n gradient that ends at the thumb centre. */\n.havik-vol__slider::-webkit-slider-runnable-track{height:4px;border-radius:3px;\n background:linear-gradient(to right,var(--havik-accent,#E1B600) var(--havik-vol-pos),\n rgba(255,255,255,.3) var(--havik-vol-pos))}\n/* Firefox fills natively, and tracks the thumb exactly. */\n.havik-vol__slider::-moz-range-track{height:4px;border-radius:3px;background:rgba(255,255,255,.3)}\n.havik-vol__slider::-moz-range-progress{height:4px;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-vol__slider::-webkit-slider-thumb{-webkit-appearance:none;width:var(--havik-vol-thumb);\n height:var(--havik-vol-thumb);border-radius:50%;background:var(--havik-accent,#E1B600);\n margin-top:calc((4px - var(--havik-vol-thumb)) / 2)}\n.havik-vol__slider::-moz-range-thumb{width:var(--havik-vol-thumb);height:var(--havik-vol-thumb);\n border:0;border-radius:50%;background:var(--havik-accent,#E1B600)}\n\n.havik-time{font-size:12px;color:var(--havik-text-muted,#9aa0ad);\n font-variant-numeric:tabular-nums;padding:0 6px;white-space:nowrap}\n.havik-live{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;\n letter-spacing:.4px;padding:0 8px;color:var(--havik-text,#fff)}\n.havik-live svg{width:9px;height:9px;color:var(--havik-text-muted,#9aa0ad)}\n.havik-live.is-live svg{color:var(--havik-accent,#E1B600)}\n.havik-live__go{margin-left:2px;border:0;cursor:pointer;background:transparent;color:var(--havik-text-muted,#9aa0ad);\n font:inherit;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:6px}\n.havik-live.is-live .havik-live__go{display:none}\n.havik-live__go:hover{color:var(--havik-accent,#E1B600)}\n\n.havik-menu{position:absolute;bottom:54px;right:12px;min-width:170px;max-height:230px;overflow:auto;\n background:var(--havik-surface,#1B1C23);border:1px solid var(--havik-border,rgba(255,255,255,.1));\n border-radius:var(--havik-radius,8px);box-shadow:0 10px 30px rgba(0,0,0,.5);padding:6px;z-index:3}\n.havik-menu[hidden]{display:none}\n.havik-menu__title{font-size:11px;text-transform:uppercase;letter-spacing:.6px;\n color:var(--havik-text-muted,#9aa0ad);padding:6px 8px 4px}\n.havik-menu__item{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;font:inherit;font-size:13px;\n text-align:left;padding:7px 8px;border-radius:6px}\n.havik-menu__item:hover{background:var(--havik-surface-muted,#2a2c36)}\n.havik-menu__item[aria-checked=\"true\"]{color:var(--havik-accent,#E1B600);font-weight:600}\n.havik-menu__item[aria-checked=\"true\"]::after{content:'✓'}\n", _r = /* @__PURE__ */ new WeakMap();
2926
+ function vr(e = document, t) {
2927
+ let n = e.querySelector(`style#${hr}`);
2928
+ if (n && (!t || _r.get(n) === t)) return;
2857
2929
  let r = e.createElement("style");
2858
- r.id = dr, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = fr, pr.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
2930
+ r.id = hr, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = gr, _r.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
2859
2931
  }
2860
2932
  //#endregion
2861
2933
  //#region src/ui/icons.ts
2862
- var hr = {
2934
+ var yr = {
2863
2935
  play: "<path d=\"M8 5v14l11-7z\"/>",
2864
2936
  pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
2865
2937
  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\"/>",
@@ -2873,11 +2945,11 @@ var hr = {
2873
2945
  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\"/>"
2874
2946
  };
2875
2947
  function $(e) {
2876
- return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${hr[e]}</svg>`;
2948
+ return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${yr[e]}</svg>`;
2877
2949
  }
2878
2950
  //#endregion
2879
2951
  //#region src/ui/controls.ts
2880
- var gr = 3e3, _r = 250, vr = /* @__PURE__ */ new Set([
2952
+ var br = 3e3, xr = 250, Sr = /* @__PURE__ */ new Set([
2881
2953
  "GONE",
2882
2954
  "NOT_FOUND",
2883
2955
  "GEO_DENIED",
@@ -2885,15 +2957,15 @@ var gr = 3e3, _r = 250, vr = /* @__PURE__ */ new Set([
2885
2957
  "UNAUTHORIZED",
2886
2958
  "DRM_DEVICE_REVOKED"
2887
2959
  ]);
2888
- function yr(e) {
2960
+ function Cr(e) {
2889
2961
  let t = "This match isn't available in your country";
2890
2962
  return e ? `${t} (${e})` : t;
2891
2963
  }
2892
- var br = "This device can't play protected video";
2893
- function xr(e) {
2894
- return new Sr(e);
2964
+ var wr = "This device can't play protected video";
2965
+ function Tr(e) {
2966
+ return new Er(e);
2895
2967
  }
2896
- var Sr = class {
2968
+ var Er = class {
2897
2969
  root;
2898
2970
  video;
2899
2971
  player;
@@ -2941,7 +3013,7 @@ var Sr = class {
2941
3013
  scrubbing = !1;
2942
3014
  offFns = [];
2943
3015
  constructor(e) {
2944
- this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? gr, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.streamEnded = e.streamEnded ?? (() => !1), this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, mr(this.doc, e.cspNonce), this.root.classList.add("havik-player"), this.root.hasAttribute("tabindex") || (this.root.tabIndex = 0), this.root.setAttribute("role", "region"), this.root.setAttribute("aria-label", "Video player");
3016
+ this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? br, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.streamEnded = e.streamEnded ?? (() => !1), this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, vr(this.doc, e.cspNonce), this.root.classList.add("havik-player"), this.root.hasAttribute("tabindex") || (this.root.tabIndex = 0), this.root.setAttribute("role", "region"), this.root.setAttribute("aria-label", "Video player");
2945
3017
  let t = (e, t, n) => {
2946
3018
  let r = this.doc.createElement(e);
2947
3019
  if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
@@ -3027,7 +3099,7 @@ var Sr = class {
3027
3099
  let t = this.surfaceWasHidden;
3028
3100
  this.tapTimer = setTimeout(() => {
3029
3101
  this.tapTimer = void 0, this.toggleBar(t);
3030
- }, _r);
3102
+ }, xr);
3031
3103
  }
3032
3104
  toggleBar(e) {
3033
3105
  e ? this.poke() : this.hideIfIdle();
@@ -3047,7 +3119,7 @@ var Sr = class {
3047
3119
  this.statusOverlays && (e === "ended" ? t = "ended" : e === "error" ? t = "error" : e === "waiting" ? t = "waiting" : !this.hasPlayed && (e === "idle" || e === "paused") && (t = "preplay")), this.renderStatus(t);
3048
3120
  }
3049
3121
  statusMessageFor(e) {
3050
- return e === "ended" ? this.player.endedReason === "interrupted" ? this.interruptedMessage : this.endedMessage : e === "waiting" ? this.hasPlayed ? "Reconnecting — please stand by" : "Starting soon…" : e === "error" ? this.errorMessage === void 0 ? this.lastError?.code === "GEO_DENIED" ? yr(this.lastError.country) : this.lastError?.code === "DRM_DEVICE_REVOKED" ? br : this.lastError?.message ?? "Playback unavailable" : this.errorMessage : null;
3122
+ return e === "ended" ? this.player.endedReason === "interrupted" ? this.interruptedMessage : this.endedMessage : e === "waiting" ? this.hasPlayed ? "Reconnecting — please stand by" : "Starting soon…" : e === "error" ? this.errorMessage === void 0 ? this.lastError?.code === "GEO_DENIED" ? Cr(this.lastError.country) : this.lastError?.code === "DRM_DEVICE_REVOKED" ? wr : this.lastError?.message ?? "Playback unavailable" : this.errorMessage : null;
3051
3123
  }
3052
3124
  renderStatus(e) {
3053
3125
  let t = this.statusMessageFor(e);
@@ -3062,7 +3134,7 @@ var Sr = class {
3062
3134
  e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML = $("play"), e.addEventListener("click", () => void this.player.play()), n.append(e);
3063
3135
  } else {
3064
3136
  let r = this.doc.createElement("div");
3065
- if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !vr.has(this.lastError.code)) {
3137
+ if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !Sr.has(this.lastError.code)) {
3066
3138
  let e = this.doc.createElement("button");
3067
3139
  e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${$("retry")}<span>Retry</span>`, e.addEventListener("click", () => void this.player.retry()), n.append(e);
3068
3140
  }
@@ -3103,7 +3175,7 @@ var Sr = class {
3103
3175
  let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
3104
3176
  this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
3105
3177
  }
3106
- !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Cr(this.video.currentTime)} / ${Cr(this.video.duration)}`);
3178
+ !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Dr(this.video.currentTime)} / ${Dr(this.video.duration)}`);
3107
3179
  }
3108
3180
  syncLive() {
3109
3181
  let e = this.player.getStats(), t = e.isLive !== !1, n = this.player.state === "ended", r = !t && !this.streamEnded();
@@ -3153,17 +3225,17 @@ var Sr = class {
3153
3225
  renderQualityMenu() {
3154
3226
  let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
3155
3227
  n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
3156
- for (let n of e) this.menu.append(this.menuItem(wr(n), t === n.index, () => this.player.setQuality(n.index)));
3228
+ for (let n of e) this.menu.append(this.menuItem(Or(n), t === n.index, () => this.player.setQuality(n.index)));
3157
3229
  }
3158
3230
  renderAudioMenu() {
3159
3231
  let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
3160
3232
  t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
3161
- for (let t of e) this.menu.append(this.menuItem(Tr(t), t.default, () => this.player.setAudioTrack(t.id)));
3233
+ for (let t of e) this.menu.append(this.menuItem(kr(t), t.default, () => this.player.setAudioTrack(t.id)));
3162
3234
  }
3163
3235
  renderCcMenu() {
3164
3236
  let e = this.player.getTextTracks(), t = this.doc.createElement("div");
3165
3237
  t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
3166
- for (let t of e) this.menu.append(this.menuItem(Er(t), !1, () => this.player.setTextTrack(t.id)));
3238
+ for (let t of e) this.menu.append(this.menuItem(Ar(t), !1, () => this.player.setTextTrack(t.id)));
3167
3239
  }
3168
3240
  onTracksChanged() {
3169
3241
  this.openMenu && this.renderMenu(this.openMenu);
@@ -3268,41 +3340,41 @@ var Sr = class {
3268
3340
  this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
3269
3341
  }
3270
3342
  };
3271
- function Cr(e) {
3343
+ function Dr(e) {
3272
3344
  (!Number.isFinite(e) || e < 0) && (e = 0);
3273
3345
  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");
3274
3346
  return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
3275
3347
  }
3276
- function wr(e) {
3348
+ function Or(e) {
3277
3349
  return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
3278
3350
  }
3279
- function Tr(e) {
3351
+ function kr(e) {
3280
3352
  return e.name || e.lang || `Track ${e.id}`;
3281
3353
  }
3282
- function Er(e) {
3354
+ function Ar(e) {
3283
3355
  return e.name || e.lang || `Track ${e.id}`;
3284
3356
  }
3285
3357
  //#endregion
3286
3358
  //#region src/managed/index.ts
3287
- var Dr = 6e3, Or = 45e3, kr = 2e3, Ar = 3, jr = 5e3, Mr = 2e3, Nr = 48e4, Pr = "keySystemLicenseRequestFailed";
3288
- function Fr(e) {
3359
+ var jr = 6e3, Mr = 45e3, Nr = 2e3, Pr = 3, Fr = 5e3, Ir = 2e3, Lr = 48e4, Rr = "keySystemLicenseRequestFailed";
3360
+ function zr(e) {
3289
3361
  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)})`);
3290
- if (e.env !== void 0) return ot(e.env);
3362
+ if (e.env !== void 0) return st(e.env);
3291
3363
  if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
3292
3364
  return e.baseUrl;
3293
3365
  }
3294
- async function Ir(e) {
3366
+ async function Br(e) {
3295
3367
  if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
3296
- let t = Fr(e);
3368
+ let t = zr(e);
3297
3369
  if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
3298
3370
  if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
3299
- let r = new Lr({
3371
+ let r = new Vr({
3300
3372
  ...e,
3301
3373
  baseUrl: t
3302
3374
  });
3303
3375
  return await r.start(), r;
3304
3376
  }
3305
- var Lr = class {
3377
+ var Vr = class {
3306
3378
  opts;
3307
3379
  abort = new AbortController();
3308
3380
  listeners = {};
@@ -3397,7 +3469,7 @@ var Lr = class {
3397
3469
  setTimeout(() => {
3398
3470
  a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
3399
3471
  phase: i ? "unavailable" : "tooEarly",
3400
- retryInMs: Or,
3472
+ retryInMs: Mr,
3401
3473
  attempt: 1,
3402
3474
  elapsedMs: 0,
3403
3475
  ...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
@@ -3436,13 +3508,13 @@ var Lr = class {
3436
3508
  !a && !p() && h();
3437
3509
  }, e);
3438
3510
  };
3439
- _(Dr), this.armingSub = D({
3511
+ _(jr), this.armingSub = D({
3440
3512
  eventsBaseUrl: t,
3441
3513
  matchUrn: this.opts.matchUrn,
3442
3514
  credential: this.opts.credential,
3443
- onAlive: () => _(Or),
3515
+ onAlive: () => _(Mr),
3444
3516
  onState: (e) => {
3445
- a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * kr);
3517
+ a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Nr);
3446
3518
  },
3447
3519
  onError: () => h()
3448
3520
  });
@@ -3465,7 +3537,7 @@ var Lr = class {
3465
3537
  let n = await c(this.opts.credential);
3466
3538
  if (this.destroyed || t !== this.loadGen) return;
3467
3539
  this.setState("loading");
3468
- let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = ft(this.opts.video, (e) => {
3540
+ let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = pt(this.opts.video, (e) => {
3469
3541
  this._state !== "ended" && this._state !== "error" && this.setState(e);
3470
3542
  });
3471
3543
  if (await i.load(), this.destroyed || t !== this.loadGen) {
@@ -3487,26 +3559,26 @@ var Lr = class {
3487
3559
  if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
3488
3560
  let i = e.analytics?.sid;
3489
3561
  if (!i) return;
3490
- let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = er(this.opts.baseUrl, a, e.analytics?.endpoint);
3562
+ let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = ir(this.opts.baseUrl, a, e.analytics?.endpoint);
3491
3563
  if (!o) {
3492
3564
  s && setTimeout(() => {
3493
3565
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
3494
3566
  }, 0);
3495
3567
  return;
3496
3568
  }
3497
- let c = this.opts.video, l = new tr({
3569
+ let c = this.opts.video, l = new ar({
3498
3570
  endpoint: o,
3499
3571
  sid: i,
3500
3572
  player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
3501
- sdkVersion: sr,
3502
- environment: ar(c),
3573
+ sdkVersion: dr,
3574
+ environment: lr(c),
3503
3575
  idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
3504
3576
  onIdle: () => this.onAnalyticsIdle(t),
3505
3577
  onBlocked: (e) => setTimeout(() => {
3506
3578
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, e));
3507
3579
  }, 0),
3508
3580
  sample: () => {
3509
- let e = this.engine?.getStats() ?? st, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
3581
+ let e = this.engine?.getStats() ?? ct, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
3510
3582
  return {
3511
3583
  ...e,
3512
3584
  bufferedMs: Math.round(t * 1e3),
@@ -3520,7 +3592,7 @@ var Lr = class {
3520
3592
  let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
3521
3593
  c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
3522
3594
  c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
3523
- }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), or().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
3595
+ }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), ur().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
3524
3596
  }
3525
3597
  currentPresentation() {
3526
3598
  let e = this.opts.video;
@@ -3544,17 +3616,18 @@ var Lr = class {
3544
3616
  adaptiveHoldBack: this.opts.adaptiveHoldBack,
3545
3617
  adaptiveHoldBackCeiling: this.opts.adaptiveHoldBackCeiling,
3546
3618
  mediaDuringKey: this.opts.mediaDuringKey,
3619
+ preloadHints: this.opts.preloadHints,
3547
3620
  debug: this.opts.debug,
3548
3621
  deferLoad: r,
3549
3622
  hlsConfig: i,
3550
3623
  emit: (e) => this.onEngineEvent(e),
3551
3624
  freshLicenseUrl: () => this.refreshLicense()
3552
3625
  }, o = this.opts.engine ?? "auto";
3553
- if (o === "native") return new W(a);
3554
- if (o === "hls") return new Ln(a);
3555
- if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && H(this.opts.video) && U() || !e.drmEnabled && wt() && H(this.opts.video)) return new W(a);
3556
- if (Rt()) return new Ln(a);
3557
- if (H(this.opts.video)) return new W(a);
3626
+ if (o === "native") return new U(a);
3627
+ if (o === "hls") return new Vn(a);
3628
+ if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && V(this.opts.video) && H() || !e.drmEnabled && Tt() && V(this.opts.video)) return new U(a);
3629
+ if (Vt()) return new Vn(a);
3630
+ if (V(this.opts.video)) return new U(a);
3558
3631
  throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
3559
3632
  }
3560
3633
  onEngineEvent(e) {
@@ -3624,7 +3697,7 @@ var Lr = class {
3624
3697
  a = !0, this.emit("warning", new n(r(o.status), o.status, `live-state events answered HTTP ${o.status} for ${this.opts.matchUrn}: the match is ` + (o.terminal ? "gone, so the subscription stopped" : "not in the catalog (ended and dropped, or not listed yet), so it retries every 5 min") + " — end-of-stream detection falls back to the HLS staleness watchdog."));
3625
3698
  return;
3626
3699
  }
3627
- i += 1, i >= Ar && (a = !0, this.emit("warning", new n("NETWORK", 0, `live-state events unreachable at ${t} after ${i} 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.`)));
3700
+ i += 1, i >= Pr && (a = !0, this.emit("warning", new n("NETWORK", 0, `live-state events unreachable at ${t} after ${i} 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.`)));
3628
3701
  }
3629
3702
  }
3630
3703
  });
@@ -3639,7 +3712,7 @@ var Lr = class {
3639
3712
  return;
3640
3713
  }
3641
3714
  let e = this.hiddenAtMs;
3642
- this.hiddenAtMs = null, e != null && Date.now() - e >= jr && this.resyncLiveState();
3715
+ this.hiddenAtMs = null, e != null && Date.now() - e >= Fr && this.resyncLiveState();
3643
3716
  }, this.onReturnPageShow = (e) => {
3644
3717
  e.persisted && this.resyncLiveState();
3645
3718
  }, document.addEventListener("visibilitychange", this.onReturnVisible), typeof window < "u" && window.addEventListener("pageshow", this.onReturnPageShow));
@@ -3671,7 +3744,7 @@ var Lr = class {
3671
3744
  scheduleRejoin(e) {
3672
3745
  this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
3673
3746
  this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
3674
- }, Math.random() * kr));
3747
+ }, Math.random() * Nr));
3675
3748
  }
3676
3749
  cancelRejoin() {
3677
3750
  this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
@@ -3695,7 +3768,7 @@ var Lr = class {
3695
3768
  }
3696
3769
  t.controls = !1;
3697
3770
  let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
3698
- r && r.insertBefore(n, t), n.appendChild(t), ur(n, this.opts.theme), this.container = n, this.controlBar = xr({
3771
+ r && r.insertBefore(n, t), n.appendChild(t), mr(n, this.opts.theme), this.container = n, this.controlBar = Tr({
3699
3772
  root: n,
3700
3773
  video: t,
3701
3774
  player: this,
@@ -3733,7 +3806,7 @@ var Lr = class {
3733
3806
  }
3734
3807
  startStats() {
3735
3808
  this.stopStats();
3736
- let e = Math.max(500, this.opts.statsIntervalMs ?? Mr);
3809
+ let e = Math.max(500, this.opts.statsIntervalMs ?? Ir);
3737
3810
  this.statsTimer = setInterval(() => {
3738
3811
  if (!this.engine) return;
3739
3812
  let e = this.engine.getStats();
@@ -3744,14 +3817,14 @@ var Lr = class {
3744
3817
  this.statsTimer && clearInterval(this.statsTimer), this.statsTimer = void 0;
3745
3818
  }
3746
3819
  isStaleLicenseDenial(e) {
3747
- return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== Pr || e.error.httpStatus !== 403 || e.error.code !== "FORBIDDEN" || e.error.serverCode === "license_refused" ? !1 : K(this._descriptor?.drm?.widevine?.licenseUrl);
3820
+ return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== Rr || e.error.httpStatus !== 403 || e.error.code !== "FORBIDDEN" || e.error.serverCode === "license_refused" ? !1 : G(this._descriptor?.drm?.widevine?.licenseUrl);
3748
3821
  }
3749
3822
  scheduleLicenseRefresh() {
3750
3823
  if (this.stopRefresh(), !this._descriptor?.drmEnabled) return;
3751
3824
  typeof document < "u" && this.engine?.name === "hls" && (this.onRefocus = () => {
3752
- document.visibilityState !== "visible" || this.destroyed || K(this._descriptor?.drm?.widevine?.licenseUrl) && this.refreshLicense();
3825
+ document.visibilityState !== "visible" || this.destroyed || G(this._descriptor?.drm?.widevine?.licenseUrl) && this.refreshLicense();
3753
3826
  }, document.addEventListener("visibilitychange", this.onRefocus));
3754
- let e = this.opts.licenseRefreshMs ?? Nr;
3827
+ let e = this.opts.licenseRefreshMs ?? Lr;
3755
3828
  e && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
3756
3829
  }
3757
3830
  stopRefresh() {
@@ -3808,7 +3881,7 @@ var Lr = class {
3808
3881
  this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
3809
3882
  }
3810
3883
  getStats() {
3811
- return this.engine?.getStats() ?? st;
3884
+ return this.engine?.getStats() ?? ct;
3812
3885
  }
3813
3886
  getQualityLevels() {
3814
3887
  return this.engine?.getQualityLevels() ?? [];
@@ -3916,12 +3989,12 @@ var Lr = class {
3916
3989
  };
3917
3990
  //#endregion
3918
3991
  //#region src/embed/protocol.ts
3919
- function Rr(e) {
3992
+ function Hr(e) {
3920
3993
  return !!e && typeof e == "object" && typeof e.type == "string" && e.type.startsWith("oddin:");
3921
3994
  }
3922
3995
  //#endregion
3923
3996
  //#region src/embed/host.ts
3924
- function zr(e) {
3997
+ function Ur(e) {
3925
3998
  if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
3926
3999
  if (!e.src) throw Error("mountEmbed: opts.src is required");
3927
4000
  if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
@@ -3930,7 +4003,7 @@ function zr(e) {
3930
4003
  let r = document.createElement("iframe");
3931
4004
  r.src = t.toString(), r.allow = "autoplay; encrypted-media; fullscreen", r.setAttribute("allowfullscreen", ""), r.referrerPolicy = "no-referrer", r.setAttribute("sandbox", e.sandbox ?? "allow-scripts allow-same-origin allow-presentation"), r.style.cssText = "border:0;width:100%;height:100%;display:block", e.container.appendChild(r);
3932
4005
  let i = /* @__PURE__ */ new Set(), a = (t) => {
3933
- if (t.source !== r.contentWindow || t.origin !== n || !Rr(t.data)) return;
4006
+ if (t.source !== r.contentWindow || t.origin !== n || !Hr(t.data)) return;
3934
4007
  let a = t.data;
3935
4008
  a.type === "oddin:ready" && a.protocol !== 1 && console.warn(`havik-player: embed protocol v${a.protocol} != host v1. Pin the embed page version to the SDK version to avoid skew.`), e.onEvent?.(a), i.forEach((e) => e(a));
3936
4009
  };
@@ -3980,15 +4053,15 @@ function zr(e) {
3980
4053
  }
3981
4054
  //#endregion
3982
4055
  //#region src/embed/page.ts
3983
- var Br = /^[A-Za-z0-9:_.-]{1,128}$/;
3984
- function Vr(e) {
4056
+ var Wr = /^[A-Za-z0-9:_.-]{1,128}$/;
4057
+ function Gr(e) {
3985
4058
  if (typeof e == "boolean") return e;
3986
4059
  if (typeof e == "object" && e) {
3987
4060
  let t = e.endpoint;
3988
4061
  return typeof t == "string" ? { endpoint: t } : {};
3989
4062
  }
3990
4063
  }
3991
- function Hr() {
4064
+ function Kr() {
3992
4065
  let e = window.HAVIK_EMBED_CONFIG;
3993
4066
  if (e) return {
3994
4067
  baseUrl: e.baseUrl ?? "",
@@ -3998,7 +4071,7 @@ function Hr() {
3998
4071
  autoplay: e.autoplay ?? !0,
3999
4072
  muted: e.muted ?? !0,
4000
4073
  waitForLive: e.waitForLive ?? !0,
4001
- analytics: Vr(e.analytics)
4074
+ analytics: Gr(e.analytics)
4002
4075
  };
4003
4076
  let t = new URLSearchParams(location.search);
4004
4077
  return {
@@ -4011,9 +4084,9 @@ function Hr() {
4011
4084
  waitForLive: !0
4012
4085
  };
4013
4086
  }
4014
- async function Ur() {
4015
- let e = Hr();
4016
- Gr();
4087
+ async function qr() {
4088
+ let e = Kr();
4089
+ Yr();
4017
4090
  let t = document.createElement("video");
4018
4091
  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);
4019
4092
  let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
@@ -4069,12 +4142,12 @@ async function Ur() {
4069
4142
  message: e.message,
4070
4143
  ...e.country === void 0 ? {} : { country: e.country }
4071
4144
  })), e.on("autoplayblocked", () => {
4072
- i({ type: "oddin:autoplayblocked" }), Wr(t, e);
4145
+ i({ type: "oddin:autoplayblocked" }), Jr(t, e);
4073
4146
  });
4074
4147
  }, s = async (r) => {
4075
4148
  a?.destroy(), a = null;
4076
4149
  try {
4077
- let n = await Ir({
4150
+ let n = await Br({
4078
4151
  video: t,
4079
4152
  baseUrl: e.baseUrl,
4080
4153
  matchUrn: r,
@@ -4137,30 +4210,30 @@ async function Ur() {
4137
4210
  a?.retry();
4138
4211
  break;
4139
4212
  case "oddin:load":
4140
- typeof e.matchUrn == "string" && Br.test(e.matchUrn) && s(e.matchUrn);
4213
+ typeof e.matchUrn == "string" && Wr.test(e.matchUrn) && s(e.matchUrn);
4141
4214
  break;
4142
4215
  case "oddin:destroy": c();
4143
4216
  }
4144
4217
  }, u = (e) => {
4145
- r && e.origin === r && Rr(e.data) && l(e.data);
4218
+ r && e.origin === r && Hr(e.data) && l(e.data);
4146
4219
  };
4147
4220
  r && window.addEventListener("message", u), window.addEventListener("pagehide", c, { once: !0 }), await s(e.matchUrn), i({
4148
4221
  type: "oddin:ready",
4149
4222
  protocol: 1
4150
4223
  });
4151
4224
  }
4152
- function Wr(e, t) {
4225
+ function Jr(e, t) {
4153
4226
  if (document.getElementById("havik-tap")) return;
4154
4227
  let n = document.createElement("button");
4155
4228
  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", () => {
4156
4229
  n.remove(), t.play();
4157
4230
  }), document.body.appendChild(n);
4158
4231
  }
4159
- function Gr() {
4232
+ function Yr() {
4160
4233
  let e = document.createElement("style");
4161
4234
  e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
4162
4235
  }
4163
4236
  //#endregion
4164
- export { E as LiveStateHttpError, cr as ODDIN_THEME, n as PlaybackError, ur as applyTheme, ot as baseUrlForEnv, Ur as bootEmbed, De as clearDeviceId, ze as clearRememberedBandwidth, Ir as createPlayer, O as deriveEventsBaseUrl, nt as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, ve as fetchCatalog, be as fetchTournament, Se as flattenMatches, C as fullscreenSupported, j as getDeviceId, it as isLowLatencyManifest, Rr as isOddinMessage, ke as licenseRequestHeaders, zr as mountEmbed, fe as pollToLive, y as resolveStream, D as subscribeLiveState, S as videoFullscreenActive, we as watchStatus };
4237
+ export { E as LiveStateHttpError, fr as ODDIN_THEME, n as PlaybackError, mr as applyTheme, st as baseUrlForEnv, qr as bootEmbed, De as clearDeviceId, ze as clearRememberedBandwidth, Br as createPlayer, O as deriveEventsBaseUrl, rt as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, ve as fetchCatalog, be as fetchTournament, Se as flattenMatches, C as fullscreenSupported, j as getDeviceId, at as isLowLatencyManifest, Hr as isOddinMessage, ke as licenseRequestHeaders, Ur as mountEmbed, fe as pollToLive, y as resolveStream, D as subscribeLiveState, S as videoFullscreenActive, we as watchStatus };
4165
4238
 
4166
4239
  //# sourceMappingURL=index.js.map