@oddin-gg/havik-player 2.16.7 → 2.16.8

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
@@ -174,7 +174,7 @@ function ue(e, t) {
174
174
  t?.addEventListener("abort", a, { once: !0 });
175
175
  });
176
176
  }
177
- async function de(e, t, r) {
177
+ async function v(e, t, r) {
178
178
  let i = ae(t), a = Date.now(), s = i.timeoutMs == null ? Infinity : a + i.timeoutMs, c = 0, l;
179
179
  for (;;) {
180
180
  if (r?.aborted) throw new n("ABORTED", 0, "wait-for-live aborted");
@@ -200,21 +200,21 @@ async function de(e, t, r) {
200
200
  }
201
201
  //#endregion
202
202
  //#region src/core/resolve.ts
203
- async function v(e) {
203
+ async function y(e) {
204
204
  if (!e.matchUrn || typeof e.matchUrn != "string") throw new n("INVALID_URN", 0, "resolveStream: a non-empty matchUrn is required");
205
205
  let t = await p(d(e.baseUrl, `/v1/playback/${encodeURIComponent(e.matchUrn)}`), {
206
206
  credential: e.credential,
207
207
  signal: e.signal,
208
208
  apiHeaders: e.apiHeaders
209
209
  });
210
- if (!t.ok) throw await fe(t);
211
- return he(await t.json(), e.matchUrn);
210
+ if (!t.ok) throw await de(t);
211
+ return me(await t.json(), e.matchUrn);
212
212
  }
213
- function y(e) {
214
- let t = () => v(e);
215
- return e.waitForLive ? de(t, e.waitForLive, e.signal) : t();
213
+ function b(e) {
214
+ let t = () => y(e);
215
+ return e.waitForLive ? v(t, e.waitForLive, e.signal) : t();
216
216
  }
217
- async function fe(e) {
217
+ async function de(e) {
218
218
  let t = f(e.headers.get("retry-after")), i = e.headers.get("x-request-id") ?? e.headers.get("x-amzn-requestid") ?? void 0, a = e.statusText || `HTTP ${e.status}`, o, s;
219
219
  try {
220
220
  let t = await e.json();
@@ -230,7 +230,7 @@ async function fe(e) {
230
230
  liveStartsAtMs: s
231
231
  });
232
232
  }
233
- var pe = /* @__PURE__ */ new Set([
233
+ var fe = /* @__PURE__ */ new Set([
234
234
  "matchUrn",
235
235
  "protocol",
236
236
  "drmEnabled",
@@ -241,7 +241,7 @@ var pe = /* @__PURE__ */ new Set([
241
241
  "expiresAt",
242
242
  "analytics"
243
243
  ]);
244
- function b(e, t) {
244
+ function x(e, t) {
245
245
  let r;
246
246
  try {
247
247
  r = new URL(t);
@@ -251,7 +251,7 @@ function b(e, t) {
251
251
  if (r.protocol !== "https:" && r.protocol !== "http:") throw new n("INTERNAL", 0, `playback ${e} has a disallowed scheme: ${r.protocol}`);
252
252
  return t;
253
253
  }
254
- function me(e) {
254
+ function pe(e) {
255
255
  if (e !== void 0) {
256
256
  if (typeof e == "string" && !e.endsWith("/")) try {
257
257
  let t = new URL(e);
@@ -260,41 +260,41 @@ function me(e) {
260
260
  g(`server analytics.endpoint ${JSON.stringify(e)} ignored: not a bare https origin.`);
261
261
  }
262
262
  }
263
- function he(e, t) {
263
+ function me(e, t) {
264
264
  if (!e.manifestUrl) throw new n("INTERNAL", 0, "playback response is missing manifestUrl");
265
265
  let r = e.drmEnabled ?? !!e.drm, i = {
266
266
  matchUrn: e.matchUrn ?? t,
267
267
  protocol: "hls",
268
268
  drmEnabled: r,
269
- manifestUrl: b("manifestUrl", e.manifestUrl),
269
+ manifestUrl: x("manifestUrl", e.manifestUrl),
270
270
  serverTime: e.serverTime ?? ""
271
271
  };
272
272
  if (e.liveStartsAt && (i.liveStartsAt = e.liveStartsAt), typeof e.analytics?.sid == "string" && e.analytics.sid) {
273
273
  i.analytics = { sid: e.analytics.sid };
274
- let t = me(e.analytics.endpoint);
274
+ let t = pe(e.analytics.endpoint);
275
275
  t && (i.analytics.endpoint = t);
276
276
  }
277
277
  if (r && e.drm) {
278
278
  let t = {};
279
- e.drm.widevine?.licenseUrl && (t.widevine = { licenseUrl: b("widevine licenseUrl", e.drm.widevine.licenseUrl) }), e.drm.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && (t.fairplay = {
280
- licenseUrl: b("fairplay licenseUrl", e.drm.fairplay.licenseUrl),
281
- certificateUrl: b("fairplay certificateUrl", e.drm.fairplay.certificateUrl)
279
+ e.drm.widevine?.licenseUrl && (t.widevine = { licenseUrl: x("widevine licenseUrl", e.drm.widevine.licenseUrl) }), e.drm.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && (t.fairplay = {
280
+ licenseUrl: x("fairplay licenseUrl", e.drm.fairplay.licenseUrl),
281
+ certificateUrl: x("fairplay certificateUrl", e.drm.fairplay.certificateUrl)
282
282
  }), (t.widevine || t.fairplay) && (i.drm = t);
283
283
  }
284
284
  let a = {};
285
- for (let [t, n] of Object.entries(e)) pe.has(t) || (a[t] = n);
285
+ for (let [t, n] of Object.entries(e)) fe.has(t) || (a[t] = n);
286
286
  return Object.keys(a).length > 0 && (i.extensions = a), i;
287
287
  }
288
288
  //#endregion
289
289
  //#region src/core/fullscreen.ts
290
- function ge(e) {
290
+ function he(e) {
291
291
  return e.ownerDocument ?? document;
292
292
  }
293
- function x(e) {
293
+ function ge(e) {
294
294
  return e.fullscreenElement ?? e.webkitFullscreenElement ?? null;
295
295
  }
296
296
  function S(e, t) {
297
- let n = x(ge(e));
297
+ let n = ge(he(e));
298
298
  return n != null && (n === e || t != null && n === t) || e.webkitDisplayingFullscreen === !0;
299
299
  }
300
300
  async function C(e, t) {
@@ -310,7 +310,7 @@ async function w(e, t) {
310
310
  n.webkitExitFullscreen?.();
311
311
  return;
312
312
  }
313
- let r = ge(e), i = x(r);
313
+ let r = he(e), i = ge(r);
314
314
  i != null && (i === e || t != null && i === t) && (typeof r.exitFullscreen == "function" ? await r.exitFullscreen() : r.webkitExitFullscreen?.());
315
315
  }
316
316
  //#endregion
@@ -671,14 +671,14 @@ function I(e) {
671
671
  function L(e) {
672
672
  return (e ?? "").trim().toLowerCase();
673
673
  }
674
- var je = {
674
+ var R = {
675
675
  hevc: "hvc1.1.6.L93.90",
676
676
  dv: "dvh1.05.06",
677
677
  av1: "av01.0.05M.08",
678
678
  vp9: "vp09.00.10.08"
679
- }, Me = /* @__PURE__ */ new Map(), R = /* @__PURE__ */ new Map();
680
- function Ne(e) {
681
- let t = L(e), n = Me.get(t);
679
+ }, je = /* @__PURE__ */ new Map(), z = /* @__PURE__ */ new Map();
680
+ function Me(e) {
681
+ let t = L(e), n = je.get(t);
682
682
  if (n) return n;
683
683
  let r = {
684
684
  initDataTypes: ["cenc"],
@@ -696,23 +696,23 @@ function Ne(e) {
696
696
  } catch {
697
697
  return !1;
698
698
  }
699
- })().then((e) => (R.set(t, e), e));
700
- return Me.set(t, i), i;
699
+ })().then((e) => (z.set(t, e), e));
700
+ return je.set(t, i), i;
701
701
  }
702
- function Pe() {
703
- if (j()) for (let e of Object.values(je)) Ne(e);
702
+ function Ne() {
703
+ if (j()) for (let e of Object.values(R)) Me(e);
704
704
  }
705
- function Fe(e) {
705
+ function Pe(e) {
706
706
  let t = I(e);
707
- if (t) return t === "avc" ? !0 : R.get(L(e)) ?? R.get(L(je[t]));
707
+ if (t) return t === "avc" ? !0 : z.get(L(e)) ?? z.get(L(R[t]));
708
708
  }
709
709
  //#endregion
710
710
  //#region src/core/drm/support.ts
711
- var Ie = 5e3, Le = "video/mp4; codecs=\"avc1.42E01E\"", Re = "audio/mp4; codecs=\"mp4a.40.2\"", ze = {
711
+ var Fe = 5e3, Ie = "video/mp4; codecs=\"avc1.42E01E\"", Le = "audio/mp4; codecs=\"mp4a.40.2\"", Re = {
712
712
  widevine: ["com.widevine.alpha"],
713
713
  fairplay: ["com.apple.fps"]
714
714
  };
715
- function Be(e) {
715
+ function ze(e) {
716
716
  return e === "fairplay" ? [{
717
717
  initDataTypes: [
718
718
  "sinf",
@@ -720,30 +720,30 @@ function Be(e) {
720
720
  "cenc"
721
721
  ],
722
722
  videoCapabilities: [{
723
- contentType: Le,
723
+ contentType: Ie,
724
724
  robustness: "",
725
725
  encryptionScheme: "cbcs"
726
726
  }],
727
727
  audioCapabilities: [{
728
- contentType: Re,
728
+ contentType: Le,
729
729
  robustness: "",
730
730
  encryptionScheme: "cbcs"
731
731
  }]
732
732
  }] : N("com.widevine.alpha", [{
733
733
  initDataTypes: ["cenc"],
734
734
  videoCapabilities: [{
735
- contentType: Le,
735
+ contentType: Ie,
736
736
  robustness: F.video,
737
737
  encryptionScheme: F.scheme
738
738
  }],
739
739
  audioCapabilities: [{
740
- contentType: Re,
740
+ contentType: Le,
741
741
  robustness: F.audio,
742
742
  encryptionScheme: F.scheme
743
743
  }]
744
744
  }]);
745
745
  }
746
- function Ve(e, t) {
746
+ function Be(e, t) {
747
747
  return new Promise((n, r) => {
748
748
  let i = setTimeout(() => r(/* @__PURE__ */ Error("probe-timeout")), t);
749
749
  e.then((e) => {
@@ -753,8 +753,8 @@ function Ve(e, t) {
753
753
  });
754
754
  });
755
755
  }
756
- async function He(e = {}) {
757
- let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Ie, r = {};
756
+ async function Ve(e = {}) {
757
+ let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Fe, r = {};
758
758
  if (typeof window < "u" && window.isSecureContext === !1) return {
759
759
  verdict: "insecure-context",
760
760
  detail: r
@@ -766,7 +766,7 @@ async function He(e = {}) {
766
766
  };
767
767
  let a = !1, o = !1, s = Date.now() + n, c = () => Math.max(1, s - Date.now());
768
768
  for (let e of t) {
769
- let t = ze[e];
769
+ let t = Re[e];
770
770
  if (!t) {
771
771
  r[e] = "unknown system";
772
772
  continue;
@@ -777,7 +777,7 @@ async function He(e = {}) {
777
777
  break;
778
778
  }
779
779
  try {
780
- return await Ve((await Ve(i(n, Be(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
780
+ return await Be((await Be(i(n, ze(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
781
781
  verdict: "supported",
782
782
  system: e,
783
783
  detail: r
@@ -801,25 +801,25 @@ async function He(e = {}) {
801
801
  }
802
802
  //#endregion
803
803
  //#region src/core/manifest.ts
804
- var Ue = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
805
- function We(e) {
806
- return Ue.test(e);
804
+ var He = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
805
+ function Ue(e) {
806
+ return He.test(e);
807
807
  }
808
808
  //#endregion
809
809
  //#region src/core/env.ts
810
- var Ge = {
810
+ var We = {
811
811
  integration: "https://feed-dev.oddin-video.gg",
812
812
  production: "https://feed.oddin-video.gg"
813
813
  };
814
- function Ke(e) {
815
- let t = Object.prototype.hasOwnProperty.call(Ge, e) ? Ge[e] : void 0;
814
+ function Ge(e) {
815
+ let t = Object.prototype.hasOwnProperty.call(We, e) ? We[e] : void 0;
816
816
  if (!t) throw new n("INTERNAL", 0, `unknown env ${JSON.stringify(e)} — expected 'integration' or 'production'`);
817
817
  return t;
818
818
  }
819
819
  //#endregion
820
820
  //#region src/core/stats.ts
821
- var qe = { droppedFrames: 0 };
822
- function z(e) {
821
+ var Ke = { droppedFrames: 0 };
822
+ function qe(e) {
823
823
  try {
824
824
  return new URL(e).host;
825
825
  } catch {
@@ -831,7 +831,7 @@ function Ye(e) {
831
831
  if (typeof performance > "u" || typeof performance.getEntriesByType != "function") return "";
832
832
  let t = "", n = -1, r = performance.getEntriesByType("resource");
833
833
  for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || Je.test(i.name)) && i.startTime >= n) {
834
- let e = z(i.name);
834
+ let e = qe(i.name);
835
835
  e && (t = e, n = i.startTime);
836
836
  }
837
837
  return t;
@@ -843,7 +843,7 @@ function B(e) {
843
843
  totalFrames: t?.totalVideoFrames ?? 0
844
844
  };
845
845
  }
846
- var V = class {
846
+ var Xe = class {
847
847
  video;
848
848
  baseFrames = 0;
849
849
  baseDropped = 0;
@@ -866,7 +866,7 @@ var V = class {
866
866
  };
867
867
  }
868
868
  };
869
- function Xe(e, t) {
869
+ function Ze(e, t) {
870
870
  let n = [
871
871
  ["playing", () => t("playing")],
872
872
  ["waiting", () => t("buffering")],
@@ -883,8 +883,8 @@ function Xe(e, t) {
883
883
  }
884
884
  //#endregion
885
885
  //#region src/core/engine/native.ts
886
- var Ze = 2e3, Qe = 3, H = 500, $e = 6e3, et = .25;
887
- function tt(e) {
886
+ var Qe = 2e3, $e = 3, V = 500, et = 6e3, tt = .25, nt = 250, rt = .05;
887
+ function it(e) {
888
888
  try {
889
889
  let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
890
890
  return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
@@ -892,20 +892,20 @@ function tt(e) {
892
892
  return;
893
893
  }
894
894
  }
895
- function U(e) {
895
+ function H(e) {
896
896
  return !!(e ?? (typeof document < "u" ? document.createElement("video") : void 0))?.canPlayType("application/vnd.apple.mpegurl");
897
897
  }
898
- function W() {
898
+ function U() {
899
899
  if (typeof window > "u") return !1;
900
900
  let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
901
901
  return e || t;
902
902
  }
903
- function nt() {
904
- if (typeof navigator > "u" || !W()) return !1;
903
+ function at() {
904
+ if (typeof navigator > "u" || !U()) return !1;
905
905
  let e = navigator.userAgent ?? "";
906
906
  return /iPhone|iPad|iPod/.test(e) ? !0 : /Macintosh/.test(e) && typeof navigator.maxTouchPoints == "number" && navigator.maxTouchPoints > 1;
907
907
  }
908
- var G = class {
908
+ var W = class {
909
909
  name = "native";
910
910
  deps;
911
911
  onLoaded;
@@ -918,6 +918,10 @@ var G = class {
918
918
  onPageShow = null;
919
919
  hiddenSince = null;
920
920
  refocusTimer = null;
921
+ edgeTimer = null;
922
+ onEdgeReset = null;
923
+ lastBufferedEnd = null;
924
+ bufferedAdvancedAt = null;
921
925
  fairplayKeyIV;
922
926
  loadStarted;
923
927
  preloadTouched = !1;
@@ -927,12 +931,12 @@ var G = class {
927
931
  frameCounter;
928
932
  detachFrames = null;
929
933
  constructor(e) {
930
- this.deps = e, this.frameCounter = new V(e.video), this.loadStarted = e.deferLoad !== !0, this.builtAt = typeof performance < "u" ? performance.now() : 0;
934
+ this.deps = e, this.frameCounter = new Xe(e.video), this.loadStarted = e.deferLoad !== !0, this.builtAt = typeof performance < "u" ? performance.now() : 0;
931
935
  }
932
936
  async load() {
933
937
  this.detachFrames ??= this.frameCounter.attach();
934
938
  let { video: e, descriptor: t, emit: r } = this.deps;
935
- if (this.watchRefocus(), this.loadStarted || (this.preloadTouched = !0, this.savedPreload = e.getAttribute("preload"), e.preload = "none"), t.drmEnabled) {
939
+ if (this.watchRefocus(), this.watchBufferedEnd(), this.loadStarted || (this.preloadTouched = !0, this.savedPreload = e.getAttribute("preload"), e.preload = "none"), t.drmEnabled) {
936
940
  if (!t.drm?.fairplay) {
937
941
  r({
938
942
  type: "error",
@@ -948,7 +952,7 @@ var G = class {
948
952
  type: "error",
949
953
  error: new n("INTERNAL", 0, "native HLS playback error"),
950
954
  fatal: !0
951
- }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = rt(t.manifestUrl, t.analytics?.sid), e.load();
955
+ }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = st(t.manifestUrl, t.analytics?.sid), e.load();
952
956
  }
953
957
  startLoad() {
954
958
  this.loadStarted || (this.loadStarted = !0, this.restorePreload());
@@ -970,7 +974,7 @@ var G = class {
970
974
  });
971
975
  this.onEncrypted = (n) => {
972
976
  let i = n;
973
- i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = tt(i.initData), (async () => {
977
+ i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = it(i.initData), (async () => {
974
978
  try {
975
979
  let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
976
980
  initDataTypes: [i.initDataType],
@@ -1070,50 +1074,72 @@ var G = class {
1070
1074
  decodedFrames: t.totalFrames
1071
1075
  };
1072
1076
  if (this.cdnHost ||= Ye(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity) {
1073
- if (n.isLive = !0, e.seekable.length > 0) {
1074
- let t = e.seekable.end(e.seekable.length - 1);
1075
- n.atLiveEdge = e.currentTime >= t - 2;
1076
- let r = t - e.currentTime;
1077
- Number.isFinite(r) && r >= 0 && (n.latencySeconds = r);
1078
- }
1077
+ n.isLive = !0;
1078
+ let t = this.liveEdgeEstimate(), r = t == null ? NaN : t - e.currentTime;
1079
+ Number.isFinite(r) && (n.atLiveEdge = r <= 2, !e.paused && r >= 0 && (n.latencySeconds = r));
1079
1080
  } else Number.isFinite(e.duration) && e.duration > 0 && (n.isLive = !1);
1080
1081
  return n;
1081
1082
  }
1082
1083
  stop() {
1084
+ this.unwatchBufferedEnd();
1083
1085
  try {
1084
1086
  this.deps.video.pause();
1085
1087
  } catch {}
1086
1088
  }
1087
1089
  watchRefocus() {
1088
1090
  this.deps.snapToLiveOnRefocus === !1 || typeof document > "u" || this.onVisibility || (this.onVisibility = () => {
1089
- let e = typeof performance < "u" ? performance.now() : Date.now();
1091
+ let e = G();
1090
1092
  if (document.visibilityState === "hidden") {
1091
1093
  this.hiddenSince = e, this.cancelRefocus();
1092
1094
  return;
1093
1095
  }
1094
1096
  let t = this.hiddenSince;
1095
- this.hiddenSince = null, t != null && e - t >= Ze && this.armRefocus();
1097
+ this.hiddenSince = null, t != null && e - t >= Qe && this.armRefocus();
1096
1098
  }, this.onPageShow = (e) => {
1097
1099
  e.persisted && this.armRefocus();
1098
1100
  }, document.addEventListener("visibilitychange", this.onVisibility), typeof window < "u" && window.addEventListener("pageshow", this.onPageShow));
1099
1101
  }
1100
1102
  armRefocus() {
1101
1103
  if (this.cancelRefocus(), Number.isFinite(this.deps.video.duration)) return;
1102
- let e = this.liveEnd(), t = () => typeof performance < "u" ? performance.now() : Date.now(), n = t(), r = 0, i = () => {
1104
+ let e = this.liveEnd(), t = G, n = t(), r = 0, i = () => {
1103
1105
  if (this.refocusTimer = null, Number.isFinite(this.deps.video.duration)) return;
1104
- r += H;
1105
- let a = this.liveEnd(), o = a != null && (e == null || a >= e + et), s = Math.max(r, t() - n) >= $e;
1106
+ r += V;
1107
+ let a = this.liveEnd(), o = a != null && (e == null || a >= e + tt), s = Math.max(r, t() - n) >= et;
1106
1108
  if (o || s && a != null) {
1107
1109
  this.snapToLive();
1108
1110
  return;
1109
1111
  }
1110
- this.refocusTimer = setTimeout(i, H);
1112
+ this.refocusTimer = setTimeout(i, V);
1111
1113
  };
1112
- this.refocusTimer = setTimeout(i, H);
1114
+ this.refocusTimer = setTimeout(i, V);
1113
1115
  }
1114
1116
  cancelRefocus() {
1115
1117
  this.refocusTimer != null && clearTimeout(this.refocusTimer), this.refocusTimer = null;
1116
1118
  }
1119
+ watchBufferedEnd() {
1120
+ if (this.edgeTimer != null) return;
1121
+ let { video: e } = this.deps;
1122
+ this.onEdgeReset = () => {
1123
+ this.lastBufferedEnd = null, this.bufferedAdvancedAt = null;
1124
+ }, e.addEventListener("seeking", this.onEdgeReset), e.addEventListener("emptied", this.onEdgeReset), this.edgeTimer = setInterval(() => {
1125
+ if (e.duration !== Infinity) return;
1126
+ let t = ot(e, e.currentTime);
1127
+ t != null && ((this.lastBufferedEnd == null || Math.abs(t - this.lastBufferedEnd) >= rt) && (this.bufferedAdvancedAt = G()), this.lastBufferedEnd = t);
1128
+ }, nt);
1129
+ }
1130
+ unwatchBufferedEnd() {
1131
+ this.edgeTimer != null && clearInterval(this.edgeTimer), this.edgeTimer = null, this.onEdgeReset &&= (this.deps.video.removeEventListener("seeking", this.onEdgeReset), this.deps.video.removeEventListener("emptied", this.onEdgeReset), null), this.lastBufferedEnd = null, this.bufferedAdvancedAt = null;
1132
+ }
1133
+ liveEdgeEstimate() {
1134
+ let e = this.deps.video;
1135
+ if (e.duration !== Infinity) return null;
1136
+ let t = this.liveEnd(), n = ot(e, e.currentTime) ?? this.lastBufferedEnd;
1137
+ if (n != null) {
1138
+ let e = this.bufferedAdvancedAt, r = n + (e == null ? 0 : Math.max(0, (G() - e) / 1e3));
1139
+ (t == null || r > t) && (t = r);
1140
+ }
1141
+ return t != null && Number.isFinite(t) ? t : null;
1142
+ }
1117
1143
  liveEnd() {
1118
1144
  let e = this.deps.video;
1119
1145
  if (e.duration !== Infinity || e.seekable.length === 0) return null;
@@ -1123,13 +1149,13 @@ var G = class {
1123
1149
  snapToLive() {
1124
1150
  let e = this.deps.video, t = this.liveEnd();
1125
1151
  if (t == null) return;
1126
- let n = e.seekable.start(e.seekable.length - 1), r = Math.min(e.currentTime, t), i = Math.max(n, t - Qe, r);
1152
+ let n = e.seekable.start(e.seekable.length - 1), r = Math.min(e.currentTime, t), i = Math.max(n, t - $e, r);
1127
1153
  try {
1128
1154
  e.currentTime = i;
1129
1155
  } catch {}
1130
1156
  }
1131
1157
  destroy() {
1132
- this.detachFrames?.(), this.detachFrames = null, this.cancelRefocus(), this.onVisibility && typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), this.onVisibility = null), this.onPageShow && typeof window < "u" && (window.removeEventListener("pageshow", this.onPageShow), this.onPageShow = null);
1158
+ this.detachFrames?.(), this.detachFrames = null, this.cancelRefocus(), this.unwatchBufferedEnd(), this.onVisibility && typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), this.onVisibility = null), this.onPageShow && typeof window < "u" && (window.removeEventListener("pageshow", this.onPageShow), this.onPageShow = null);
1133
1159
  let { video: e } = this.deps;
1134
1160
  this.onLoaded && e.removeEventListener("loadedmetadata", this.onLoaded), this.onError && e.removeEventListener("error", this.onError), this.onEncrypted && e.removeEventListener("encrypted", this.onEncrypted), this.keySession?.close().catch(() => {}), this.keySession = null, this.fairplayArmed = !1, this.fairplayKeyIV = void 0;
1135
1161
  try {
@@ -1141,7 +1167,19 @@ var G = class {
1141
1167
  } catch {}
1142
1168
  }
1143
1169
  };
1144
- function rt(e, t) {
1170
+ function G() {
1171
+ return typeof performance < "u" ? performance.now() : Date.now();
1172
+ }
1173
+ function ot(e, t) {
1174
+ let n = e.buffered;
1175
+ if (!n || !Number.isFinite(t)) return null;
1176
+ for (let e = 0; e < n.length; e += 1) if (n.start(e) <= t + .1 && n.end(e) > t) {
1177
+ let t = n.end(e);
1178
+ return Number.isFinite(t) ? t : null;
1179
+ }
1180
+ return null;
1181
+ }
1182
+ function st(e, t) {
1145
1183
  return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
1146
1184
  }
1147
1185
  //#endregion
@@ -1158,8 +1196,8 @@ function K(e, t = Date.now()) {
1158
1196
  }
1159
1197
  //#endregion
1160
1198
  //#region src/core/engine/prefetch.ts
1161
- var it = 15e3, at = 5e3, ot = 6;
1162
- function st(e) {
1199
+ var ct = 15e3, lt = 5e3, ut = 6;
1200
+ function dt(e) {
1163
1201
  try {
1164
1202
  let t = new URL(e);
1165
1203
  return t.searchParams.delete("CMCD"), t.toString();
@@ -1167,7 +1205,7 @@ function st(e) {
1167
1205
  return e;
1168
1206
  }
1169
1207
  }
1170
- var ct = class {
1208
+ var ft = class {
1171
1209
  cmcd;
1172
1210
  entries = /* @__PURE__ */ new Map();
1173
1211
  keyed = /* @__PURE__ */ new Set();
@@ -1190,10 +1228,10 @@ var ct = class {
1190
1228
  }
1191
1229
  prefetch(e, t, n) {
1192
1230
  if (!this.isActive(t)) return;
1193
- let r = st(e);
1231
+ let r = dt(e);
1194
1232
  if (this.entries.has(r)) return;
1195
1233
  let i = this.perTrack.get(t) ?? 0;
1196
- if (i >= ot) return;
1234
+ if (i >= ut) return;
1197
1235
  this.perTrack.set(t, i + 1);
1198
1236
  let a = new AbortController(), o = {
1199
1237
  started: performance.now(),
@@ -1207,10 +1245,10 @@ var ct = class {
1207
1245
  signal: a.signal
1208
1246
  }).then(async (e) => (o.first = performance.now(), e.ok ? e.arrayBuffer() : null)).catch(() => null), this.entries.set(r, o), this.stats.started += 1, setTimeout(() => {
1209
1247
  this.entries.get(r) === o && (this.entries.delete(r), a.abort(), this.stats.expired += 1);
1210
- }, it);
1248
+ }, ct);
1211
1249
  }
1212
1250
  take(e) {
1213
- let t = st(e), n = this.entries.get(t);
1251
+ let t = dt(e), n = this.entries.get(t);
1214
1252
  return n && this.entries.delete(t), n;
1215
1253
  }
1216
1254
  destroy() {
@@ -1230,13 +1268,13 @@ var ct = class {
1230
1268
  }
1231
1269
  }
1232
1270
  };
1233
- function lt(t) {
1271
+ function pt(t) {
1234
1272
  let n = e.DefaultConfig?.loader;
1235
1273
  if (typeof n != "function") return;
1236
1274
  class r extends n {
1237
1275
  served = !1;
1238
1276
  cancelled = !1;
1239
- stats = ut();
1277
+ stats = mt();
1240
1278
  load(e, n, r) {
1241
1279
  let i = e.rangeEnd ? void 0 : t.take(e.url);
1242
1280
  if (!i) {
@@ -1244,7 +1282,7 @@ function lt(t) {
1244
1282
  return;
1245
1283
  }
1246
1284
  this.served = !0;
1247
- let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || at, s = setTimeout(() => {
1285
+ let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || lt, s = setTimeout(() => {
1248
1286
  !this.cancelled && this.served && (i.abort.abort(), t.stats.failed += 1, this.served = !1, super.load(e, n, r));
1249
1287
  }, o);
1250
1288
  i.bytes.then((o) => {
@@ -1271,7 +1309,7 @@ function lt(t) {
1271
1309
  }
1272
1310
  return r;
1273
1311
  }
1274
- function ut() {
1312
+ function mt() {
1275
1313
  return {
1276
1314
  aborted: !1,
1277
1315
  loaded: 0,
@@ -1295,10 +1333,10 @@ function ut() {
1295
1333
  }
1296
1334
  };
1297
1335
  }
1298
- function dt(e) {
1336
+ function ht(e) {
1299
1337
  return e === "audio" ? "audio" : "main";
1300
1338
  }
1301
- function ft(e, t) {
1339
+ function gt(e, t) {
1302
1340
  let n = [];
1303
1341
  t.initSegment?.url && !t.initSegment.data && n.push({
1304
1342
  url: t.initSegment.url,
@@ -1317,24 +1355,24 @@ function ft(e, t) {
1317
1355
  }
1318
1356
  //#endregion
1319
1357
  //#region src/core/engine/hls.ts
1320
- function pt() {
1358
+ function _t() {
1321
1359
  return e.isSupported();
1322
1360
  }
1323
- var mt = 3, ht = 5, gt = 3, _t = 1e4, vt = 3e4, yt = 12e3, bt = 3e3, xt = .02, St = 6e3, Ct = .5, wt = 3, Tt = .5, Et = 1.1, Dt = .25, Ot = 5e3, kt = 4e3, At = 2, jt = 5, Mt = 2, Nt = 2, Pt = 4, Ft = 4, It = 2e3, Lt = 3e4, Rt = .2, zt = 30, Bt = 2, Vt = 2, Ht = 9, Ut = .5, Wt = 64;
1324
- function Gt(e) {
1361
+ var vt = 3, yt = 5, bt = 3, xt = 1e4, St = 3e4, Ct = 12e3, wt = 3e3, Tt = .02, Et = 6e3, Dt = .5, Ot = 3, kt = .5, At = 1.1, jt = .25, Mt = 5e3, Nt = 4e3, Pt = 2, Ft = 5, It = 2, Lt = 2, Rt = 4, zt = 4, Bt = 2e3, Vt = 3e4, Ht = .2, Ut = 30, Wt = 2, Gt = 2, Kt = 9, qt = .5, Jt = 64;
1362
+ function Yt(e) {
1325
1363
  if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
1326
1364
  delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
1327
1365
  return;
1328
1366
  }
1329
- e.liveSyncDuration ??= Vt;
1330
- let t = Math.max(12, e.liveSyncDuration + Ht);
1331
- (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), Kt(e, e.liveSyncDuration);
1367
+ e.liveSyncDuration ??= Gt;
1368
+ let t = Math.max(12, e.liveSyncDuration + Kt);
1369
+ (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), Xt(e, e.liveSyncDuration);
1332
1370
  }
1333
- function Kt(e, t) {
1371
+ function Xt(e, t) {
1334
1372
  let n = (e, t, n) => Math.min(n, Math.max(t, e));
1335
1373
  e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
1336
1374
  }
1337
- var qt = class {
1375
+ var Zt = class {
1338
1376
  name = "hls";
1339
1377
  hls = null;
1340
1378
  deps;
@@ -1414,11 +1452,11 @@ var qt = class {
1414
1452
  frameCounter;
1415
1453
  detachFrames = null;
1416
1454
  constructor(e) {
1417
- this.deps = e, this.frameCounter = new V(e.video), this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
1455
+ this.deps = e, this.frameCounter = new Xe(e.video), this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
1418
1456
  }
1419
1457
  async load() {
1420
1458
  this.detachFrames ??= this.frameCounter.attach();
1421
- let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = U(r) && W(), o = !!e.drm?.widevine?.licenseUrl && !a;
1459
+ let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = H(r) && U(), o = !!e.drm?.widevine?.licenseUrl && !a;
1422
1460
  if (e.drmEnabled && !o) {
1423
1461
  i({
1424
1462
  type: "error",
@@ -1427,7 +1465,7 @@ var qt = class {
1427
1465
  });
1428
1466
  return;
1429
1467
  }
1430
- e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ae(r), Pe()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1468
+ e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ae(r), Ne()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1431
1469
  let e = this.hls;
1432
1470
  if (document.visibilityState !== "visible" || !e) return;
1433
1471
  let t = e.liveSyncPosition;
@@ -1450,7 +1488,7 @@ var qt = class {
1450
1488
  }
1451
1489
  this.loadSuspended = !0;
1452
1490
  }
1453
- }, Ot));
1491
+ }, Mt));
1454
1492
  }
1455
1493
  resumeLoading() {
1456
1494
  if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
@@ -1482,7 +1520,7 @@ var qt = class {
1482
1520
  let t = e.liveSyncPosition;
1483
1521
  if (typeof t != "number" || !Number.isFinite(t)) return;
1484
1522
  let { video: n } = this.deps;
1485
- n.currentTime <= t + Ut || (n.currentTime = t);
1523
+ n.currentTime <= t + qt || (n.currentTime = t);
1486
1524
  }
1487
1525
  reanchorPartTimeline(e, t) {
1488
1526
  let { frag: n, part: r } = t;
@@ -1494,7 +1532,7 @@ var qt = class {
1494
1532
  let o = n.sn, s = i.fragments.find((e) => e && e.sn === o) ?? (i.fragmentHint?.sn === o ? i.fragmentHint : void 0);
1495
1533
  if (!s) return;
1496
1534
  let c = a.startPTS - s.start;
1497
- if (!(!Number.isFinite(c) || Math.abs(c) < xt)) {
1535
+ if (!(!Number.isFinite(c) || Math.abs(c) < Tt)) {
1498
1536
  for (let e of i.fragments) e && e.setStart(e.start + c);
1499
1537
  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})`);
1500
1538
  }
@@ -1533,7 +1571,7 @@ var qt = class {
1533
1571
  return;
1534
1572
  }
1535
1573
  let l = this.hls, u, d = new Promise((e) => {
1536
- u = setTimeout(() => e(void 0), _t);
1574
+ u = setTimeout(() => e(void 0), xt);
1537
1575
  });
1538
1576
  return Promise.race([c().catch(() => void 0), d]).finally(() => clearTimeout(u)).then((e) => {
1539
1577
  if (!this.hls || this.hls !== l) throw Error("havik-player: engine torn down during refresh");
@@ -1549,20 +1587,20 @@ var qt = class {
1549
1587
  ...c
1550
1588
  };
1551
1589
  if (this.prefetch?.destroy(), this.prefetch = null, u && this.deps.mediaDuringKey !== !1 && !d.fLoader) {
1552
- let e = new ct({
1590
+ let e = new ft({
1553
1591
  sessionId: n.analytics?.sid,
1554
1592
  contentId: n.matchUrn
1555
- }), t = lt(e);
1593
+ }), t = pt(e);
1556
1594
  t && (this.prefetch = e, d.fLoader = t);
1557
1595
  }
1558
- Gt(d), this.catchUpRate = typeof d.maxLiveSyncPlaybackRate == "number" ? d.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (d.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = d.autoStartLoad !== !1;
1596
+ Yt(d), this.catchUpRate = typeof d.maxLiveSyncPlaybackRate == "number" ? d.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (d.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = d.autoStartLoad !== !1;
1559
1597
  let f = new e(d);
1560
1598
  if (this.hls = f, f.on(e.Events.FRAG_PARSED, (e, t) => this.reanchorPartTimeline(f, t)), f.on(e.Events.MANIFEST_PARSED, () => {
1561
1599
  this.mediaRecoveries = 0, this.networkRecoveries = 0, u && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && this.dropLevelsWidevineCannotPlay(f), this.measureLadder(f), this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
1562
1600
  }), f.on(e.Events.FRAG_BUFFERED, (e, t) => {
1563
1601
  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(() => {
1564
1602
  this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
1565
- }, vt)));
1603
+ }, St)));
1566
1604
  }), f.on(e.Events.FRAG_LOADING, (e, t) => {
1567
1605
  t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
1568
1606
  }), f.on(e.Events.FRAG_LOADED, (e, t) => {
@@ -1570,10 +1608,10 @@ var qt = class {
1570
1608
  let n = t?.frag?.stats, r = n?.loaded;
1571
1609
  typeof r == "number" && (this.bytesLoaded += r), !this.reportedFirstBytes && typeof r == "number" && r > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
1572
1610
  let i = n?.loading;
1573
- i && i.end > 0 && i.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(i.end - i.start))), this.requestTimesMs.length > Wt && this.requestTimesMs.shift());
1611
+ i && i.end > 0 && i.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(i.end - i.start))), this.requestTimesMs.length > Jt && this.requestTimesMs.shift());
1574
1612
  let a = t?.frag?.url;
1575
1613
  if (a) {
1576
- let e = z(a);
1614
+ let e = qe(a);
1577
1615
  e && (this.cdnHost = e);
1578
1616
  }
1579
1617
  }), f.on(e.Events.LEVEL_LOADED, (e, t) => {
@@ -1587,15 +1625,15 @@ var qt = class {
1587
1625
  }), f.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.prefetch) {
1588
1626
  let t = this.prefetch;
1589
1627
  f.on(e.Events.KEY_LOADING, (e, n) => {
1590
- let r = n?.frag, i = dt(r?.type);
1591
- if (r && t.isActive(i)) for (let e of ft(f, r)) t.prefetch(e.url, i, e.kind);
1592
- }), f.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(dt(n?.frag?.type)));
1628
+ let r = n?.frag, i = ht(r?.type);
1629
+ if (r && t.isActive(i)) for (let e of gt(f, r)) t.prefetch(e.url, i, e.kind);
1630
+ }), f.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(ht(n?.frag?.type)));
1593
1631
  }
1594
1632
  f.on(e.Events.KEY_LOADED, () => {
1595
1633
  u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
1596
1634
  }), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
1597
1635
  this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.checkFrameDrops();
1598
- }, bt), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1636
+ }, wt), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1599
1637
  this.renditionSwitches += 1;
1600
1638
  let n = this.lastLevelIndex >= 0 ? f.levels[this.lastLevelIndex] : void 0, r = f.levels[t.level];
1601
1639
  n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, l({
@@ -1659,7 +1697,7 @@ var qt = class {
1659
1697
  return;
1660
1698
  }
1661
1699
  this.capTimer && clearTimeout(this.capTimer);
1662
- let t = e > this.sizeCapLevel ? It : Lt;
1700
+ let t = e > this.sizeCapLevel ? Bt : Vt;
1663
1701
  this.capTimer = setTimeout(() => {
1664
1702
  this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
1665
1703
  }, t);
@@ -1669,9 +1707,9 @@ var qt = class {
1669
1707
  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;
1670
1708
  }
1671
1709
  dropLevelsWidevineCannotPlay(e) {
1672
- this.removeLevelsWhere(e, (e) => Fe(e) !== !0);
1710
+ this.removeLevelsWhere(e, (e) => Pe(e) !== !0);
1673
1711
  let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && I(e) !== "avc" && !!I(e)));
1674
- for (let n of t) Ne(n).then((t) => {
1712
+ for (let n of t) Me(n).then((t) => {
1675
1713
  t || this.hls !== e || this.removeLevelsWhere(e, (e) => e === n) && (this.measureLadder(e), this.applySizeCap());
1676
1714
  });
1677
1715
  }
@@ -1682,7 +1720,7 @@ var qt = class {
1682
1720
  a && I(a) && t(a) && (r.push(n), i.add(a));
1683
1721
  }), !r.length) return !1;
1684
1722
  let a = [...i].join(", ");
1685
- if (!n.some((e, t) => r.includes(t) ? !1 : !I(e.videoCodec) || Fe(e.videoCodec) === !0)) return console.warn(`havik-player: every rendition is ${a}, which Widevine may not play on this browser; keeping them`), !1;
1723
+ if (!n.some((e, t) => r.includes(t) ? !1 : !I(e.videoCodec) || Pe(e.videoCodec) === !0)) return console.warn(`havik-player: every rendition is ${a}, which Widevine may not play on this browser; keeping them`), !1;
1686
1724
  for (let t = r.length - 1; t >= 0; --t) e.removeLevel(r[t]);
1687
1725
  return console.info(`havik-player: skipped ${r.length} rendition(s) Widevine cannot play on this browser (${a})`), !0;
1688
1726
  }
@@ -1780,7 +1818,7 @@ var qt = class {
1780
1818
  return;
1781
1819
  }
1782
1820
  let e = Date.now() - this.lastAdvanceMs;
1783
- !this.chaseSuspended && e > St && this.suspendChasing(), e > yt && this.emitEnded("stalled");
1821
+ !this.chaseSuspended && e > Et && this.suspendChasing(), e > Ct && this.emitEnded("stalled");
1784
1822
  }
1785
1823
  resetStarvationWindow() {
1786
1824
  this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
@@ -1795,7 +1833,7 @@ var qt = class {
1795
1833
  this.resetStarvationWindow();
1796
1834
  return;
1797
1835
  }
1798
- let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < St, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > kt, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = B(t), c = o - s, l = c !== this.starvedFrames;
1836
+ let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < Et, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > Nt, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = B(t), c = o - s, l = c !== this.starvedFrames;
1799
1837
  if (this.starvedFrames = c, !a || l) {
1800
1838
  (t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
1801
1839
  return;
@@ -1804,12 +1842,12 @@ var qt = class {
1804
1842
  this.resetStarvationWindow();
1805
1843
  return;
1806
1844
  }
1807
- 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 > Pt && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= Mt && (this.clearKick(), this.starvationRebuilds < Nt)) {
1845
+ 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 > Rt && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= It && (this.clearKick(), this.starvationRebuilds < Lt)) {
1808
1846
  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");
1809
1847
  return;
1810
1848
  }
1811
- let u = i && this.starvedTicks >= At, d = !i && this.deadTicks >= Pt && this.recentMainFrags.reduce((e, t) => e + t, 0) >= Ft;
1812
- if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= jt))) {
1849
+ let u = i && this.starvedTicks >= Pt, d = !i && this.deadTicks >= Rt && this.recentMainFrags.reduce((e, t) => e + t, 0) >= zt;
1850
+ if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= Ft))) {
1813
1851
  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");
1814
1852
  try {
1815
1853
  e.stopLoad(), e.startLoad(-1);
@@ -1824,7 +1862,7 @@ var qt = class {
1824
1862
  let t = e.latency, n = e.targetLatency;
1825
1863
  if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
1826
1864
  let r = t - n;
1827
- !this.catchUpEngaged && r > Ct ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= Ct && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
1865
+ !this.catchUpEngaged && r > Dt ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= Dt && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
1828
1866
  let i = this.catchUpEngaged ? this.catchUpRate : 1;
1829
1867
  e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
1830
1868
  }
@@ -1846,15 +1884,15 @@ var qt = class {
1846
1884
  return;
1847
1885
  }
1848
1886
  let { totalFrames: n, dropped: r } = B(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
1849
- if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < zt || o < 0) {
1887
+ if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < Ut || o < 0) {
1850
1888
  this.fpsBadTicks = 0;
1851
1889
  return;
1852
1890
  }
1853
- if (o <= Rt * a) {
1891
+ if (o <= Ht * a) {
1854
1892
  this.fpsBadTicks = 0;
1855
1893
  return;
1856
1894
  }
1857
- if (this.fpsBadTicks += 1, this.fpsBadTicks < Bt) return;
1895
+ if (this.fpsBadTicks += 1, this.fpsBadTicks < Wt) return;
1858
1896
  this.fpsBadTicks = 0;
1859
1897
  let s = e.levels, c = s[e.currentLevel];
1860
1898
  if (!c) return;
@@ -1871,20 +1909,20 @@ var qt = class {
1871
1909
  return;
1872
1910
  }
1873
1911
  let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
1874
- if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(Et, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
1912
+ if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(At, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
1875
1913
  this.resetChaseWindow();
1876
1914
  return;
1877
1915
  }
1878
- if (this.chaseLatency < 0 || this.chaseLatency - n >= Tt) {
1916
+ if (this.chaseLatency < 0 || this.chaseLatency - n >= kt) {
1879
1917
  this.chaseLatency = n, this.chaseTicks = 0;
1880
1918
  return;
1881
1919
  }
1882
- if (this.chaseTicks += 1, this.chaseTicks < wt) return;
1920
+ if (this.chaseTicks += 1, this.chaseTicks < Ot) return;
1883
1921
  this.resetChaseWindow();
1884
1922
  let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
1885
1923
  if (!(a > 1)) return;
1886
1924
  let o = typeof e.targetLatency == "number" ? e.targetLatency : 0, s = Math.min(n, a - 1);
1887
- s < o + Dt || (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);
1925
+ s < o + jt || (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);
1888
1926
  }
1889
1927
  suspendChasing() {
1890
1928
  let e = this.hls;
@@ -1929,7 +1967,7 @@ var qt = class {
1929
1967
  scheduleLicenseRetry(t) {
1930
1968
  if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
1931
1969
  let n = t.response?.code ?? 0;
1932
- if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= gt) return !1;
1970
+ if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= bt) return !1;
1933
1971
  this.licenseRecoveries += 1;
1934
1972
  let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
1935
1973
  return this.licenseRetryTimer = setTimeout(() => {
@@ -1961,7 +1999,7 @@ var qt = class {
1961
1999
  return;
1962
2000
  }
1963
2001
  if (t.type === e.ErrorTypes.NETWORK_ERROR) {
1964
- if (this.networkRecoveries < ht) {
2002
+ if (this.networkRecoveries < yt) {
1965
2003
  this.networkRecoveries += 1;
1966
2004
  let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
1967
2005
  this.networkRetryTimer = setTimeout(() => {
@@ -1978,7 +2016,7 @@ var qt = class {
1978
2016
  return;
1979
2017
  }
1980
2018
  if (t.type === e.ErrorTypes.MEDIA_ERROR) {
1981
- if (this.mediaRecoveries < mt) {
2019
+ if (this.mediaRecoveries < vt) {
1982
2020
  this.mediaRecoveries += 1, n.recoverMediaError();
1983
2021
  return;
1984
2022
  }
@@ -2002,19 +2040,19 @@ var qt = class {
2002
2040
  let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
2003
2041
  return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
2004
2042
  }
2005
- }, Jt = 15e3, Yt = 6e5, Xt = 3e5, Zt = 100, q = 1, Qt = 1e3, $t = 3e4, en = 1e3, tn = {
2043
+ }, Qt = 15e3, $t = 6e5, en = 3e5, tn = 100, q = 1, nn = 1e3, rn = 3e4, an = 1e3, on = {
2006
2044
  inline: "PRESENTATION_INLINE",
2007
2045
  fullscreen: "PRESENTATION_FULLSCREEN",
2008
2046
  pip: "PRESENTATION_PIP"
2009
- }, nn = {
2047
+ }, sn = {
2010
2048
  widevine: "KEY_SYSTEM_WIDEVINE",
2011
2049
  fairplay: "KEY_SYSTEM_FAIRPLAY",
2012
2050
  none: "KEY_SYSTEM_NONE"
2013
2051
  };
2014
- function rn(e, t) {
2052
+ function cn(e, t) {
2015
2053
  return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
2016
2054
  }
2017
- var an = /* @__PURE__ */ new Set([
2055
+ var ln = /* @__PURE__ */ new Set([
2018
2056
  "INVALID_URN",
2019
2057
  "NOT_FOUND",
2020
2058
  "GONE",
@@ -2034,7 +2072,7 @@ var an = /* @__PURE__ */ new Set([
2034
2072
  ended: "PLAYER_STATE_ENDED",
2035
2073
  error: "PLAYER_STATE_ERROR"
2036
2074
  };
2037
- function on(e) {
2075
+ function un(e) {
2038
2076
  try {
2039
2077
  let t = new URL(e), [n, ...r] = t.hostname.split(".");
2040
2078
  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);
@@ -2042,8 +2080,8 @@ function on(e) {
2042
2080
  return;
2043
2081
  }
2044
2082
  }
2045
- var sn = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), cn = /* @__PURE__ */ new Set(), Y = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), ln = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
2046
- function un(e) {
2083
+ var dn = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), fn = /* @__PURE__ */ new Set(), Y = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), pn = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
2084
+ function mn(e) {
2047
2085
  if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
2048
2086
  let t;
2049
2087
  try {
@@ -2052,19 +2090,19 @@ function un(e) {
2052
2090
  } catch {
2053
2091
  return;
2054
2092
  }
2055
- if (cn.has(t) && !Y.has(t)) {
2056
- Y.add(t), g(ln(new URL(t).origin));
2093
+ if (fn.has(t) && !Y.has(t)) {
2094
+ Y.add(t), g(pn(new URL(t).origin));
2057
2095
  for (let e of X) e.noteCspBlocked();
2058
2096
  }
2059
2097
  }
2060
- function dn(e, t) {
2098
+ function hn(e, t) {
2061
2099
  return g(t, e), { disabledReason: t };
2062
2100
  }
2063
- function fn(e, t, n) {
2064
- if (n) return t && !sn(t, n) && g(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
2101
+ function gn(e, t, n) {
2102
+ if (n) return t && !dn(t, n) && g(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
2065
2103
  if (t) return { endpoint: t };
2066
- if (t !== void 0) return dn("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).");
2067
- let r = on(e);
2104
+ if (t !== void 0) return hn("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).");
2105
+ let r = un(e);
2068
2106
  if (r) return { endpoint: r };
2069
2107
  let i;
2070
2108
  try {
@@ -2072,9 +2110,9 @@ function fn(e, t, n) {
2072
2110
  } catch {
2073
2111
  i = e;
2074
2112
  }
2075
- return dn(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).`);
2113
+ return hn(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).`);
2076
2114
  }
2077
- var pn = class {
2115
+ var _n = class {
2078
2116
  opts;
2079
2117
  url;
2080
2118
  cspKey;
@@ -2156,8 +2194,8 @@ var pn = class {
2156
2194
  constructor(e) {
2157
2195
  this.opts = {
2158
2196
  ...e,
2159
- heartbeatMs: e.heartbeatMs ?? Jt,
2160
- idleMs: e.idleMs ?? Yt
2197
+ heartbeatMs: e.heartbeatMs ?? Qt,
2198
+ idleMs: e.idleMs ?? $t
2161
2199
  }, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
2162
2200
  try {
2163
2201
  let e = new URL(this.url);
@@ -2174,11 +2212,11 @@ var pn = class {
2174
2212
  sdkVersion: this.opts.sdkVersion,
2175
2213
  ...this.opts.environment
2176
2214
  };
2177
- this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Qt), 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 && cn.add(this.cspKey), document.addEventListener("securitypolicyviolation", un), X.add(this), this.noteCspBlocked(), this.onVisibility());
2215
+ this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), nn), 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 && fn.add(this.cspKey), document.addEventListener("securitypolicyviolation", mn), X.add(this), this.noteCspBlocked(), this.onVisibility());
2178
2216
  }
2179
2217
  checkSuspension(e) {
2180
2218
  if (this.endedFlag || !this.opts.idleMs) return !1;
2181
- let t = Math.max(this.opts.idleMs, Xt);
2219
+ let t = Math.max(this.opts.idleMs, en);
2182
2220
  return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
2183
2221
  }
2184
2222
  syncIdle(e) {
@@ -2201,12 +2239,12 @@ var pn = class {
2201
2239
  let a = {
2202
2240
  fromState: J[e] ?? "PLAYER_STATE_UNSPECIFIED",
2203
2241
  toState: J[t] ?? "PLAYER_STATE_UNSPECIFIED",
2204
- presentation: tn[this.presentation]
2242
+ presentation: on[this.presentation]
2205
2243
  }, o = this.causeOf(e, t, i);
2206
2244
  o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
2207
2245
  }
2208
2246
  seekInduced(e) {
2209
- return this.lastSeekMs >= 0 && e - this.lastSeekMs < en;
2247
+ return this.lastSeekMs >= 0 && e - this.lastSeekMs < an;
2210
2248
  }
2211
2249
  causeOf(e, t, n) {
2212
2250
  if (t === "error") return "TRANSITION_CAUSE_ERROR";
@@ -2280,7 +2318,7 @@ var pn = class {
2280
2318
  let r = n ?? "";
2281
2319
  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";
2282
2320
  if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
2283
- if (an.has(e)) return "ERROR_STAGE_RESOLVE";
2321
+ if (ln.has(e)) return "ERROR_STAGE_RESOLVE";
2284
2322
  let i = t ?? "";
2285
2323
  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";
2286
2324
  }
@@ -2327,14 +2365,14 @@ var pn = class {
2327
2365
  if (this.lastRequestCount = g, _ > 0) {
2328
2366
  o.requestCountDelta = _;
2329
2367
  let e = t.requestTimesMs ?? [], n = e.slice(Math.max(0, e.length - _)).sort((e, t) => e - t);
2330
- n.length > 0 && (o.requestTimeP50Ms = rn(n, 50), o.requestTimeP95Ms = rn(n, 95));
2368
+ n.length > 0 && (o.requestTimeP50Ms = cn(n, 50), o.requestTimeP95Ms = cn(n, 95));
2331
2369
  }
2332
2370
  typeof t.latencySeconds == "number" && typeof t.targetLatencySeconds == "number" && (o.driftMs = Math.round((t.latencySeconds - t.targetLatencySeconds) * 1e3)), typeof t.playbackRate == "number" && t.playbackRate > 0 && (o.playbackRate = t.playbackRate), t.qualityPinned === !0 && (o.qualityPinned = !0), t.cdnHost && (o.cdnHost = t.cdnHost), this.maybeEmitMediaInfo(t), this.enqueue({ heartbeat: o }), this.flush(), s > 0 && this.noteFirstBytes();
2333
2371
  }
2334
2372
  maybeEmitMediaInfo(e) {
2335
2373
  if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
2336
2374
  let t = {};
2337
- e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = nn[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);
2375
+ e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = sn[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);
2338
2376
  let n = JSON.stringify(t);
2339
2377
  n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
2340
2378
  }
@@ -2354,7 +2392,7 @@ var pn = class {
2354
2392
  let c = r?.positionMs ?? 0;
2355
2393
  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));
2356
2394
  let l = e !== "END_REASON_ENDED";
2357
- l && this.lastStallMs > 0 && n - this.lastStallMs <= $t && (i.abandonAfterStallMs = Math.max(q, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= $t && (i.abandonAfterErrorMs = Math.max(q, Math.round(n - this.lastErrorMs))), this.fullscreenTotalMs > 0 && (i.fullscreenTimeMs = Math.round(this.fullscreenTotalMs)), this.pipTotalMs > 0 && (i.pipTimeMs = Math.round(this.pipTotalMs)), this.volumeChanges > 0 && (i.volumeChanges = this.volumeChanges), this.muteChanges > 0 && (i.muteChanges = this.muteChanges);
2395
+ l && this.lastStallMs > 0 && n - this.lastStallMs <= rn && (i.abandonAfterStallMs = Math.max(q, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= rn && (i.abandonAfterErrorMs = Math.max(q, Math.round(n - this.lastErrorMs))), this.fullscreenTotalMs > 0 && (i.fullscreenTimeMs = Math.round(this.fullscreenTotalMs)), this.pipTotalMs > 0 && (i.pipTimeMs = Math.round(this.pipTotalMs)), this.volumeChanges > 0 && (i.volumeChanges = this.volumeChanges), this.muteChanges > 0 && (i.muteChanges = this.muteChanges);
2358
2396
  let u = r?.decodedFrames ?? this.lastDecoded;
2359
2397
  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");
2360
2398
  }
@@ -2374,13 +2412,13 @@ var pn = class {
2374
2412
  };
2375
2413
  }
2376
2414
  noteCspBlocked() {
2377
- this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(ln(new URL(this.url).origin)));
2415
+ this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(pn(new URL(this.url).origin)));
2378
2416
  }
2379
2417
  cspBlocked() {
2380
2418
  return !!this.cspKey && Y.has(this.cspKey);
2381
2419
  }
2382
2420
  enqueue(e) {
2383
- if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > Zt;) {
2421
+ if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > tn;) {
2384
2422
  let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
2385
2423
  this.pending.splice(e >= 0 ? e : 0, 1);
2386
2424
  }
@@ -2407,7 +2445,7 @@ var pn = class {
2407
2445
  };
2408
2446
  //#endregion
2409
2447
  //#region src/core/environment.ts
2410
- function mn() {
2448
+ function vn() {
2411
2449
  if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
2412
2450
  let e;
2413
2451
  try {
@@ -2432,14 +2470,14 @@ function mn() {
2432
2470
  integration: "INTEGRATION_KIND_IFRAME"
2433
2471
  };
2434
2472
  }
2435
- function hn() {
2473
+ function yn() {
2436
2474
  if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
2437
2475
  let e = navigator.userAgentData, t = e?.platform ?? "";
2438
2476
  if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
2439
2477
  let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
2440
2478
  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";
2441
2479
  }
2442
- function gn() {
2480
+ function bn() {
2443
2481
  let e = typeof navigator < "u" ? navigator.connection : void 0;
2444
2482
  if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
2445
2483
  let t = {
@@ -2458,17 +2496,17 @@ function gn() {
2458
2496
  }
2459
2497
  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;
2460
2498
  }
2461
- function _n(e) {
2462
- let t = mn(), n = {
2463
- deviceClass: hn(),
2499
+ function xn(e) {
2500
+ let t = vn(), n = {
2501
+ deviceClass: yn(),
2464
2502
  integration: t.integration,
2465
- ...gn()
2503
+ ...bn()
2466
2504
  };
2467
2505
  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);
2468
2506
  let r = e.getBoundingClientRect?.();
2469
2507
  return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
2470
2508
  }
2471
- async function vn() {
2509
+ async function Sn() {
2472
2510
  let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
2473
2511
  if (!e?.getHighEntropyValues) return {};
2474
2512
  try {
@@ -2480,7 +2518,7 @@ async function vn() {
2480
2518
  }
2481
2519
  //#endregion
2482
2520
  //#region src/core/version.ts
2483
- var yn = "2.16.7", bn = {
2521
+ var Cn = "2.16.8", wn = {
2484
2522
  accent: "#E1B600",
2485
2523
  accentText: "#1B1C23",
2486
2524
  background: "#0e0f13",
@@ -2491,7 +2529,7 @@ var yn = "2.16.7", bn = {
2491
2529
  border: "rgba(255, 255, 255, 0.1)",
2492
2530
  radius: "8px",
2493
2531
  fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
2494
- }, xn = {
2532
+ }, Tn = {
2495
2533
  accent: "--havik-accent",
2496
2534
  accentText: "--havik-accent-text",
2497
2535
  background: "--havik-bg",
@@ -2503,26 +2541,26 @@ var yn = "2.16.7", bn = {
2503
2541
  radius: "--havik-radius",
2504
2542
  fontFamily: "--havik-font"
2505
2543
  };
2506
- function Sn(e, t) {
2544
+ function En(e, t) {
2507
2545
  let n = {
2508
- ...bn,
2546
+ ...wn,
2509
2547
  ...t
2510
2548
  };
2511
- for (let t of Object.keys(xn)) e.style.setProperty(xn[t], n[t]);
2549
+ for (let t of Object.keys(Tn)) e.style.setProperty(Tn[t], n[t]);
2512
2550
  n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
2513
2551
  }
2514
2552
  //#endregion
2515
2553
  //#region src/ui/styles.ts
2516
- var Cn = "havik-player-styles", wn = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer;\n touch-action:manipulation}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n/* Absolutely centred, NOT a flex sibling of .havik-center: the hidden center\n button (.havik-gone) still occupies its 74px in the row, which pushed an\n in-flow spinner 37px right of centre. */\n.havik-spinner{position:absolute;inset:0;margin:auto;width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n/* A status card carries its own logo — the corner watermark would duplicate it. */\n.havik-player.havik-has-status .havik-watermark{display:none}\n\n.havik-bar{position:absolute;left:0;right:0;bottom:0;padding:0 12px 8px;\n opacity:1;transition:opacity .25s;z-index:2}\n.havik-seek{position:relative;height:16px;display:flex;align-items:center;cursor:pointer;margin-bottom:2px}\n.havik-seek__track{position:relative;width:100%;height:4px;border-radius:3px;background:rgba(255,255,255,.25)}\n.havik-seek__buffered{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:rgba(255,255,255,.4)}\n.havik-seek__played{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-seek__thumb{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;\n background:var(--havik-accent,#E1B600);transform:translate(-50%,-50%) scale(0);transition:transform .1s}\n.havik-seek:hover .havik-seek__thumb{transform:translate(-50%,-50%) scale(1)}\n\n.havik-controls{display:flex;align-items:center;gap:6px;height:40px}\n.havik-spacer{flex:1}\n.havik-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;border-radius:var(--havik-radius,8px);\n padding:0;transition:background .12s,color .12s}\n.havik-btn:hover{background:rgba(255,255,255,.12)}\n.havik-btn:focus-visible{outline:2px solid var(--havik-accent,#E1B600);outline-offset:1px}\n.havik-btn svg{width:22px;height:22px}\n\n/* The volume level is filled in accent up to the thumb, like the seek bar's\n played span — a native range input paints no \"elapsed\" side, which left the\n level readable only from the dot's position. --havik-vol (0..1) is set by\n syncVolume(); the track width and thumb size live here as variables because\n the WebKit fill has to compute the thumb centre from both. */\n.havik-vol{display:flex;align-items:center}\n.havik-vol__slider{--havik-vol-w:70px;--havik-vol-thumb:12px;--havik-vol:1;\n --havik-vol-pos:calc(var(--havik-vol-thumb) / 2 + var(--havik-vol) * (var(--havik-vol-w) - var(--havik-vol-thumb)));\n width:0;opacity:0;transition:width .18s,opacity .18s;height:4px;cursor:pointer;\n appearance:none;-webkit-appearance:none;background:transparent;border-radius:3px;margin:0 4px}\n.havik-vol:hover .havik-vol__slider,.havik-vol:focus-within .havik-vol__slider{width:var(--havik-vol-w);opacity:1}\n/* WebKit/Blink have no progress pseudo-element: paint the fill as a hard-stop\n gradient that ends at the thumb centre. */\n.havik-vol__slider::-webkit-slider-runnable-track{height:4px;border-radius:3px;\n background:linear-gradient(to right,var(--havik-accent,#E1B600) var(--havik-vol-pos),\n rgba(255,255,255,.3) var(--havik-vol-pos))}\n/* Firefox fills natively, and tracks the thumb exactly. */\n.havik-vol__slider::-moz-range-track{height:4px;border-radius:3px;background:rgba(255,255,255,.3)}\n.havik-vol__slider::-moz-range-progress{height:4px;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-vol__slider::-webkit-slider-thumb{-webkit-appearance:none;width:var(--havik-vol-thumb);\n height:var(--havik-vol-thumb);border-radius:50%;background:var(--havik-accent,#E1B600);\n margin-top:calc((4px - var(--havik-vol-thumb)) / 2)}\n.havik-vol__slider::-moz-range-thumb{width:var(--havik-vol-thumb);height:var(--havik-vol-thumb);\n border:0;border-radius:50%;background:var(--havik-accent,#E1B600)}\n\n.havik-time{font-size:12px;color:var(--havik-text-muted,#9aa0ad);\n font-variant-numeric:tabular-nums;padding:0 6px;white-space:nowrap}\n.havik-live{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;\n letter-spacing:.4px;padding:0 8px;color:var(--havik-text,#fff)}\n.havik-live svg{width:9px;height:9px;color:var(--havik-text-muted,#9aa0ad)}\n.havik-live.is-live svg{color:var(--havik-accent,#E1B600)}\n.havik-live__go{margin-left:2px;border:0;cursor:pointer;background:transparent;color:var(--havik-text-muted,#9aa0ad);\n font:inherit;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:6px}\n.havik-live.is-live .havik-live__go{display:none}\n.havik-live__go:hover{color:var(--havik-accent,#E1B600)}\n\n.havik-menu{position:absolute;bottom:54px;right:12px;min-width:170px;max-height:230px;overflow:auto;\n background:var(--havik-surface,#1B1C23);border:1px solid var(--havik-border,rgba(255,255,255,.1));\n border-radius:var(--havik-radius,8px);box-shadow:0 10px 30px rgba(0,0,0,.5);padding:6px;z-index:3}\n.havik-menu[hidden]{display:none}\n.havik-menu__title{font-size:11px;text-transform:uppercase;letter-spacing:.6px;\n color:var(--havik-text-muted,#9aa0ad);padding:6px 8px 4px}\n.havik-menu__item{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;font:inherit;font-size:13px;\n text-align:left;padding:7px 8px;border-radius:6px}\n.havik-menu__item:hover{background:var(--havik-surface-muted,#2a2c36)}\n.havik-menu__item[aria-checked=\"true\"]{color:var(--havik-accent,#E1B600);font-weight:600}\n.havik-menu__item[aria-checked=\"true\"]::after{content:'✓'}\n", Z = /* @__PURE__ */ new WeakMap();
2517
- function Tn(e = document, t) {
2518
- let n = e.querySelector(`style#${Cn}`);
2519
- if (n && (!t || Z.get(n) === t)) return;
2554
+ var Dn = "havik-player-styles", On = "\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", kn = /* @__PURE__ */ new WeakMap();
2555
+ function An(e = document, t) {
2556
+ let n = e.querySelector(`style#${Dn}`);
2557
+ if (n && (!t || kn.get(n) === t)) return;
2520
2558
  let r = e.createElement("style");
2521
- r.id = Cn, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = wn, Z.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
2559
+ r.id = Dn, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = On, kn.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
2522
2560
  }
2523
2561
  //#endregion
2524
2562
  //#region src/ui/icons.ts
2525
- var En = {
2563
+ var jn = {
2526
2564
  play: "<path d=\"M8 5v14l11-7z\"/>",
2527
2565
  pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
2528
2566
  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\"/>",
@@ -2535,21 +2573,21 @@ var En = {
2535
2573
  liveDot: "<circle cx=\"12\" cy=\"12\" r=\"6\"/>",
2536
2574
  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\"/>"
2537
2575
  };
2538
- function Q(e) {
2539
- return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${En[e]}</svg>`;
2576
+ function Z(e) {
2577
+ return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${jn[e]}</svg>`;
2540
2578
  }
2541
2579
  //#endregion
2542
2580
  //#region src/ui/controls.ts
2543
- var Dn = 3e3, On = 250, kn = /* @__PURE__ */ new Set([
2581
+ var Mn = 3e3, Nn = 250, Pn = /* @__PURE__ */ new Set([
2544
2582
  "GONE",
2545
2583
  "NOT_FOUND",
2546
2584
  "INVALID_URN",
2547
2585
  "UNAUTHORIZED"
2548
2586
  ]);
2549
- function An(e) {
2550
- return new jn(e);
2587
+ function Fn(e) {
2588
+ return new In(e);
2551
2589
  }
2552
- var jn = class {
2590
+ var In = class {
2553
2591
  root;
2554
2592
  video;
2555
2593
  player;
@@ -2595,7 +2633,7 @@ var jn = class {
2595
2633
  scrubbing = !1;
2596
2634
  offFns = [];
2597
2635
  constructor(e) {
2598
- this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Dn, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, Tn(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");
2636
+ this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Mn, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, An(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");
2599
2637
  let t = (e, t, n) => {
2600
2638
  let r = this.doc.createElement(e);
2601
2639
  if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
@@ -2606,12 +2644,12 @@ var jn = class {
2606
2644
  "aria-label": r,
2607
2645
  title: r
2608
2646
  });
2609
- return i.innerHTML = Q(n), i;
2647
+ return i.innerHTML = Z(n), i;
2610
2648
  };
2611
2649
  this.overlay = t("div", "havik-overlay"), this.center = t("button", "havik-center", {
2612
2650
  type: "button",
2613
2651
  "aria-label": "Play"
2614
- }), this.center.innerHTML = Q("play"), this.spinner = t("div", "havik-spinner"), this.spinner.style.display = "none", this.overlay.append(this.center, this.spinner), this.gradient = t("div", "havik-gradient"), this.bar = t("div", "havik-bar"), this.seek = t("div", "havik-seek", {
2652
+ }), this.center.innerHTML = Z("play"), this.spinner = t("div", "havik-spinner"), this.spinner.style.display = "none", this.overlay.append(this.center, this.spinner), this.gradient = t("div", "havik-gradient"), this.bar = t("div", "havik-bar"), this.seek = t("div", "havik-seek", {
2615
2653
  role: "slider",
2616
2654
  "aria-label": "Seek",
2617
2655
  "aria-valuemin": "0",
@@ -2629,7 +2667,7 @@ var jn = class {
2629
2667
  "aria-label": "Volume"
2630
2668
  });
2631
2669
  let a = t("div", "havik-vol");
2632
- a.append(this.muteBtn, this.volSlider), this.live = t("div", "havik-live"), this.live.innerHTML = Q("liveDot");
2670
+ a.append(this.muteBtn, this.volSlider), this.live = t("div", "havik-live"), this.live.innerHTML = Z("liveDot");
2633
2671
  let o = this.doc.createElement("span");
2634
2672
  o.textContent = "LIVE", this.liveGo = t("button", "havik-live__go", { type: "button" }), this.liveGo.textContent = "Go live", this.live.append(o, this.liveGo), this.time = t("div", "havik-time"), this.time.textContent = "0:00", this.time.style.display = "none";
2635
2673
  let s = t("div", "havik-spacer");
@@ -2681,7 +2719,7 @@ var jn = class {
2681
2719
  let t = this.surfaceWasHidden;
2682
2720
  this.tapTimer = setTimeout(() => {
2683
2721
  this.tapTimer = void 0, this.toggleBar(t);
2684
- }, On);
2722
+ }, Nn);
2685
2723
  }
2686
2724
  toggleBar(e) {
2687
2725
  e ? this.poke() : this.hideIfIdle();
@@ -2713,12 +2751,12 @@ var jn = class {
2713
2751
  }
2714
2752
  if (e === "preplay") {
2715
2753
  let e = this.doc.createElement("button");
2716
- e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML = Q("play"), e.addEventListener("click", () => void this.player.play()), n.append(e);
2754
+ e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML = Z("play"), e.addEventListener("click", () => void this.player.play()), n.append(e);
2717
2755
  } else {
2718
2756
  let r = this.doc.createElement("div");
2719
- if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !kn.has(this.lastError.code)) {
2757
+ if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !Pn.has(this.lastError.code)) {
2720
2758
  let e = this.doc.createElement("button");
2721
- e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${Q("retry")}<span>Retry</span>`, e.addEventListener("click", () => void this.player.retry()), n.append(e);
2759
+ e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${Z("retry")}<span>Retry</span>`, e.addEventListener("click", () => void this.player.retry()), n.append(e);
2722
2760
  }
2723
2761
  }
2724
2762
  this.root.append(n), this.statusBox = n, this.show();
@@ -2757,7 +2795,7 @@ var jn = class {
2757
2795
  let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
2758
2796
  this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
2759
2797
  }
2760
- !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Mn(this.video.currentTime)} / ${Mn(this.video.duration)}`);
2798
+ !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Ln(this.video.currentTime)} / ${Ln(this.video.duration)}`);
2761
2799
  }
2762
2800
  syncLive() {
2763
2801
  let e = this.player.getStats(), t = e.isLive !== !1;
@@ -2807,17 +2845,17 @@ var jn = class {
2807
2845
  renderQualityMenu() {
2808
2846
  let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
2809
2847
  n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
2810
- for (let n of e) this.menu.append(this.menuItem(Nn(n), t === n.index, () => this.player.setQuality(n.index)));
2848
+ for (let n of e) this.menu.append(this.menuItem(Rn(n), t === n.index, () => this.player.setQuality(n.index)));
2811
2849
  }
2812
2850
  renderAudioMenu() {
2813
2851
  let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
2814
2852
  t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
2815
- for (let t of e) this.menu.append(this.menuItem(Pn(t), t.default, () => this.player.setAudioTrack(t.id)));
2853
+ for (let t of e) this.menu.append(this.menuItem(zn(t), t.default, () => this.player.setAudioTrack(t.id)));
2816
2854
  }
2817
2855
  renderCcMenu() {
2818
2856
  let e = this.player.getTextTracks(), t = this.doc.createElement("div");
2819
2857
  t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
2820
- for (let t of e) this.menu.append(this.menuItem(Fn(t), !1, () => this.player.setTextTrack(t.id)));
2858
+ for (let t of e) this.menu.append(this.menuItem(Bn(t), !1, () => this.player.setTextTrack(t.id)));
2821
2859
  }
2822
2860
  onTracksChanged() {
2823
2861
  this.openMenu && this.renderMenu(this.openMenu);
@@ -2901,7 +2939,7 @@ var jn = class {
2901
2939
  }
2902
2940
  }
2903
2941
  setIcon(e, t) {
2904
- e.innerHTML = Q(t);
2942
+ e.innerHTML = Z(t);
2905
2943
  }
2906
2944
  destroy() {
2907
2945
  this.hideTimer && clearTimeout(this.hideTimer), this.tapTimer && clearTimeout(this.tapTimer);
@@ -2918,41 +2956,41 @@ var jn = class {
2918
2956
  this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
2919
2957
  }
2920
2958
  };
2921
- function Mn(e) {
2959
+ function Ln(e) {
2922
2960
  (!Number.isFinite(e) || e < 0) && (e = 0);
2923
2961
  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");
2924
2962
  return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
2925
2963
  }
2926
- function Nn(e) {
2964
+ function Rn(e) {
2927
2965
  return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
2928
2966
  }
2929
- function Pn(e) {
2967
+ function zn(e) {
2930
2968
  return e.name || e.lang || `Track ${e.id}`;
2931
2969
  }
2932
- function Fn(e) {
2970
+ function Bn(e) {
2933
2971
  return e.name || e.lang || `Track ${e.id}`;
2934
2972
  }
2935
2973
  //#endregion
2936
2974
  //#region src/managed/index.ts
2937
- var In = 6e3, Ln = 45e3, Rn = 2e3, zn = 3, Bn = 2e3, Vn = 48e4, Hn = "keySystemLicenseRequestFailed";
2938
- function Un(e) {
2975
+ var Vn = 6e3, Q = 45e3, Hn = 2e3, Un = 3, Wn = 2e3, Gn = 48e4, Kn = "keySystemLicenseRequestFailed";
2976
+ function qn(e) {
2939
2977
  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)})`);
2940
- if (e.env !== void 0) return Ke(e.env);
2978
+ if (e.env !== void 0) return Ge(e.env);
2941
2979
  if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
2942
2980
  return e.baseUrl;
2943
2981
  }
2944
- async function Wn(e) {
2982
+ async function Jn(e) {
2945
2983
  if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
2946
- let t = Un(e);
2984
+ let t = qn(e);
2947
2985
  if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
2948
2986
  if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
2949
- let r = new Gn({
2987
+ let r = new Yn({
2950
2988
  ...e,
2951
2989
  baseUrl: t
2952
2990
  });
2953
2991
  return await r.start(), r;
2954
2992
  }
2955
- var Gn = class {
2993
+ var Yn = class {
2956
2994
  opts;
2957
2995
  abort = new AbortController();
2958
2996
  listeners = {};
@@ -2999,7 +3037,7 @@ var Gn = class {
2999
3037
  this.opts.muted && (this.opts.video.muted = !0), this.opts.poster && (this.opts.video.poster = this.opts.poster), this.mountControls(), this.attachPipListeners(), this.setState("loading");
3000
3038
  let e = ++this.loadGen, t = this.resolveOptions();
3001
3039
  try {
3002
- let n = await v(t);
3040
+ let n = await y(t);
3003
3041
  if (await this.onResolved(n, e), e === this.loadGen && this._state === "error" && this._lastError) {
3004
3042
  let e = this._lastError;
3005
3043
  throw this.destroy(), e;
@@ -3026,7 +3064,7 @@ var Gn = class {
3026
3064
  r ? this.armWithSse(e, r, t, n) : this.beginArmingByPolling(e);
3027
3065
  }
3028
3066
  beginArmingByPolling(e) {
3029
- y({
3067
+ b({
3030
3068
  ...this.resolveOptions(),
3031
3069
  signal: this.abort.signal,
3032
3070
  waitForLive: this.buildWaitConfig(e)
@@ -3043,7 +3081,7 @@ var Gn = class {
3043
3081
  setTimeout(() => {
3044
3082
  a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
3045
3083
  phase: i ? "unavailable" : "tooEarly",
3046
- retryInMs: Ln,
3084
+ retryInMs: Q,
3047
3085
  attempt: 1,
3048
3086
  elapsedMs: 0,
3049
3087
  ...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
@@ -3060,7 +3098,7 @@ var Gn = class {
3060
3098
  }
3061
3099
  }
3062
3100
  }, h = () => {
3063
- a || s || p() || (s = !0, y({
3101
+ a || s || p() || (s = !0, b({
3064
3102
  ...this.resolveOptions(),
3065
3103
  signal: c.signal,
3066
3104
  waitForLive: this.buildWaitConfig(e)
@@ -3068,7 +3106,7 @@ var Gn = class {
3068
3106
  a || p() || c.signal.aborted || (a = !0, this.closeArming(), this.fail(e instanceof n ? e : new n("INTERNAL", 0, String(e))));
3069
3107
  }));
3070
3108
  }, g = () => {
3071
- a || p() || v(this.resolveOptions()).then((e) => m(e)).catch((e) => {
3109
+ a || p() || y(this.resolveOptions()).then((e) => m(e)).catch((e) => {
3072
3110
  if (!(a || p())) {
3073
3111
  if (e instanceof n && o(e.code)) {
3074
3112
  h();
@@ -3082,13 +3120,13 @@ var Gn = class {
3082
3120
  !a && !p() && h();
3083
3121
  }, e);
3084
3122
  };
3085
- _(In), this.armingSub = T({
3123
+ _(Vn), this.armingSub = T({
3086
3124
  eventsBaseUrl: t,
3087
3125
  matchUrn: this.opts.matchUrn,
3088
3126
  credential: this.opts.credential,
3089
- onAlive: () => _(Ln),
3127
+ onAlive: () => _(Q),
3090
3128
  onState: (e) => {
3091
- a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Rn);
3129
+ a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Hn);
3092
3130
  },
3093
3131
  onError: () => h()
3094
3132
  });
@@ -3111,7 +3149,7 @@ var Gn = class {
3111
3149
  let n = await s(this.opts.credential);
3112
3150
  if (this.destroyed || t !== this.loadGen) return;
3113
3151
  this.setState("loading");
3114
- let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = Xe(this.opts.video, (e) => {
3152
+ let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = Ze(this.opts.video, (e) => {
3115
3153
  this._state !== "ended" && this._state !== "error" && this.setState(e);
3116
3154
  });
3117
3155
  if (await i.load(), this.destroyed || t !== this.loadGen) {
@@ -3133,26 +3171,26 @@ var Gn = class {
3133
3171
  if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
3134
3172
  let i = e.analytics?.sid;
3135
3173
  if (!i) return;
3136
- let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = fn(this.opts.baseUrl, a, e.analytics?.endpoint);
3174
+ let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = gn(this.opts.baseUrl, a, e.analytics?.endpoint);
3137
3175
  if (!o) {
3138
3176
  s && setTimeout(() => {
3139
3177
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
3140
3178
  }, 0);
3141
3179
  return;
3142
3180
  }
3143
- let c = this.opts.video, l = new pn({
3181
+ let c = this.opts.video, l = new _n({
3144
3182
  endpoint: o,
3145
3183
  sid: i,
3146
3184
  player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
3147
- sdkVersion: yn,
3148
- environment: _n(c),
3185
+ sdkVersion: Cn,
3186
+ environment: xn(c),
3149
3187
  idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
3150
3188
  onIdle: () => this.onAnalyticsIdle(t),
3151
3189
  onBlocked: (e) => setTimeout(() => {
3152
3190
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, e));
3153
3191
  }, 0),
3154
3192
  sample: () => {
3155
- let e = this.engine?.getStats() ?? qe, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
3193
+ let e = this.engine?.getStats() ?? Ke, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
3156
3194
  return {
3157
3195
  ...e,
3158
3196
  bufferedMs: Math.round(t * 1e3),
@@ -3166,7 +3204,7 @@ var Gn = class {
3166
3204
  let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
3167
3205
  c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
3168
3206
  c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
3169
- }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), vn().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
3207
+ }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), Sn().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
3170
3208
  }
3171
3209
  currentPresentation() {
3172
3210
  let e = this.opts.video;
@@ -3192,11 +3230,11 @@ var Gn = class {
3192
3230
  emit: (e) => this.onEngineEvent(e),
3193
3231
  freshLicenseUrl: () => this.refreshLicense()
3194
3232
  }, o = this.opts.engine ?? "auto";
3195
- if (o === "native") return new G(a);
3196
- if (o === "hls") return new qt(a);
3197
- if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && U(this.opts.video) && W() || !e.drmEnabled && nt() && U(this.opts.video)) return new G(a);
3198
- if (pt()) return new qt(a);
3199
- if (U(this.opts.video)) return new G(a);
3233
+ if (o === "native") return new W(a);
3234
+ if (o === "hls") return new Zt(a);
3235
+ if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && H(this.opts.video) && U() || !e.drmEnabled && at() && H(this.opts.video)) return new W(a);
3236
+ if (_t()) return new Zt(a);
3237
+ if (H(this.opts.video)) return new W(a);
3200
3238
  throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
3201
3239
  }
3202
3240
  onEngineEvent(e) {
@@ -3258,7 +3296,7 @@ var Gn = class {
3258
3296
  r = 0, i = !1;
3259
3297
  },
3260
3298
  onError: () => {
3261
- this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= zn && (i = !0, this.emit("warning", new n("NETWORK", 0, `live-state events unreachable at ${t} after ${r} attempts — end-of-stream detection degraded to the HLS staleness watchdog. Check the events host, the api-key's allowed origins, and CSP connect-src.`))));
3299
+ this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= Un && (i = !0, this.emit("warning", new n("NETWORK", 0, `live-state events unreachable at ${t} after ${r} attempts — end-of-stream detection degraded to the HLS staleness watchdog. Check the events host, the api-key's allowed origins, and CSP connect-src.`))));
3262
3300
  }
3263
3301
  });
3264
3302
  }
@@ -3280,7 +3318,7 @@ var Gn = class {
3280
3318
  scheduleRejoin(e) {
3281
3319
  this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
3282
3320
  this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
3283
- }, Math.random() * Rn));
3321
+ }, Math.random() * Hn));
3284
3322
  }
3285
3323
  cancelRejoin() {
3286
3324
  this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
@@ -3304,7 +3342,7 @@ var Gn = class {
3304
3342
  }
3305
3343
  t.controls = !1;
3306
3344
  let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
3307
- r && r.insertBefore(n, t), n.appendChild(t), Sn(n, this.opts.theme), this.container = n, this.controlBar = An({
3345
+ r && r.insertBefore(n, t), n.appendChild(t), En(n, this.opts.theme), this.container = n, this.controlBar = Fn({
3308
3346
  root: n,
3309
3347
  video: t,
3310
3348
  player: this,
@@ -3335,7 +3373,7 @@ var Gn = class {
3335
3373
  }
3336
3374
  startStats() {
3337
3375
  this.stopStats();
3338
- let e = Math.max(500, this.opts.statsIntervalMs ?? Bn);
3376
+ let e = Math.max(500, this.opts.statsIntervalMs ?? Wn);
3339
3377
  this.statsTimer = setInterval(() => {
3340
3378
  if (!this.engine) return;
3341
3379
  let e = this.engine.getStats();
@@ -3346,14 +3384,14 @@ var Gn = class {
3346
3384
  this.statsTimer && clearInterval(this.statsTimer), this.statsTimer = void 0;
3347
3385
  }
3348
3386
  isStaleLicenseDenial(e) {
3349
- return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== Hn || e.error.httpStatus !== 403 ? !1 : K(this._descriptor?.drm?.widevine?.licenseUrl);
3387
+ return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== Kn || e.error.httpStatus !== 403 ? !1 : K(this._descriptor?.drm?.widevine?.licenseUrl);
3350
3388
  }
3351
3389
  scheduleLicenseRefresh() {
3352
3390
  if (this.stopRefresh(), !this._descriptor?.drmEnabled) return;
3353
3391
  typeof document < "u" && this.engine?.name === "hls" && (this.onRefocus = () => {
3354
3392
  document.visibilityState !== "visible" || this.destroyed || K(this._descriptor?.drm?.widevine?.licenseUrl) && this.refreshLicense();
3355
3393
  }, document.addEventListener("visibilitychange", this.onRefocus));
3356
- let e = this.opts.licenseRefreshMs ?? Vn;
3394
+ let e = this.opts.licenseRefreshMs ?? Gn;
3357
3395
  e && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
3358
3396
  }
3359
3397
  stopRefresh() {
@@ -3365,7 +3403,7 @@ var Gn = class {
3365
3403
  if (this.refreshInFlight?.engine === e) return this.refreshInFlight.promise;
3366
3404
  let t = (async () => {
3367
3405
  try {
3368
- let t = await v(this.resolveOptions());
3406
+ let t = await y(this.resolveOptions());
3369
3407
  if (this.destroyed || this.engine !== e) return;
3370
3408
  let n = t.drm?.widevine?.licenseUrl, r = t.drm?.fairplay?.licenseUrl;
3371
3409
  return (n || r) && (e.setLicenseUrls({
@@ -3409,7 +3447,7 @@ var Gn = class {
3409
3447
  this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
3410
3448
  }
3411
3449
  getStats() {
3412
- return this.engine?.getStats() ?? qe;
3450
+ return this.engine?.getStats() ?? Ke;
3413
3451
  }
3414
3452
  getQualityLevels() {
3415
3453
  return this.engine?.getQualityLevels() ?? [];
@@ -3461,7 +3499,7 @@ var Gn = class {
3461
3499
  let e = ++this.loadGen;
3462
3500
  this.teardownPlayback();
3463
3501
  try {
3464
- let t = await y({
3502
+ let t = await b({
3465
3503
  ...this.resolveOptions(),
3466
3504
  waitForLive: this.opts.waitForLive ? this.buildWaitConfig(e) : void 0
3467
3505
  });
@@ -3519,7 +3557,7 @@ function $(e) {
3519
3557
  }
3520
3558
  //#endregion
3521
3559
  //#region src/embed/host.ts
3522
- function Kn(e) {
3560
+ function Xn(e) {
3523
3561
  if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
3524
3562
  if (!e.src) throw Error("mountEmbed: opts.src is required");
3525
3563
  if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
@@ -3578,15 +3616,15 @@ function Kn(e) {
3578
3616
  }
3579
3617
  //#endregion
3580
3618
  //#region src/embed/page.ts
3581
- var qn = /^[A-Za-z0-9:_.-]{1,128}$/;
3582
- function Jn(e) {
3619
+ var Zn = /^[A-Za-z0-9:_.-]{1,128}$/;
3620
+ function Qn(e) {
3583
3621
  if (typeof e == "boolean") return e;
3584
3622
  if (typeof e == "object" && e) {
3585
3623
  let t = e.endpoint;
3586
3624
  return typeof t == "string" ? { endpoint: t } : {};
3587
3625
  }
3588
3626
  }
3589
- function Yn() {
3627
+ function $n() {
3590
3628
  let e = window.HAVIK_EMBED_CONFIG;
3591
3629
  if (e) return {
3592
3630
  baseUrl: e.baseUrl ?? "",
@@ -3596,7 +3634,7 @@ function Yn() {
3596
3634
  autoplay: e.autoplay ?? !0,
3597
3635
  muted: e.muted ?? !0,
3598
3636
  waitForLive: e.waitForLive ?? !0,
3599
- analytics: Jn(e.analytics)
3637
+ analytics: Qn(e.analytics)
3600
3638
  };
3601
3639
  let t = new URLSearchParams(location.search);
3602
3640
  return {
@@ -3609,9 +3647,9 @@ function Yn() {
3609
3647
  waitForLive: !0
3610
3648
  };
3611
3649
  }
3612
- async function Xn() {
3613
- let e = Yn();
3614
- Qn();
3650
+ async function er() {
3651
+ let e = $n();
3652
+ nr();
3615
3653
  let t = document.createElement("video");
3616
3654
  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);
3617
3655
  let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
@@ -3666,12 +3704,12 @@ async function Xn() {
3666
3704
  code: e.code,
3667
3705
  message: e.message
3668
3706
  })), e.on("autoplayblocked", () => {
3669
- i({ type: "oddin:autoplayblocked" }), Zn(t, e);
3707
+ i({ type: "oddin:autoplayblocked" }), tr(t, e);
3670
3708
  });
3671
3709
  }, s = async (r) => {
3672
3710
  a?.destroy(), a = null;
3673
3711
  try {
3674
- let n = await Wn({
3712
+ let n = await Jn({
3675
3713
  video: t,
3676
3714
  baseUrl: e.baseUrl,
3677
3715
  matchUrn: r,
@@ -3733,7 +3771,7 @@ async function Xn() {
3733
3771
  a?.retry();
3734
3772
  break;
3735
3773
  case "oddin:load":
3736
- typeof e.matchUrn == "string" && qn.test(e.matchUrn) && s(e.matchUrn);
3774
+ typeof e.matchUrn == "string" && Zn.test(e.matchUrn) && s(e.matchUrn);
3737
3775
  break;
3738
3776
  case "oddin:destroy": c();
3739
3777
  }
@@ -3745,18 +3783,18 @@ async function Xn() {
3745
3783
  protocol: 1
3746
3784
  });
3747
3785
  }
3748
- function Zn(e, t) {
3786
+ function tr(e, t) {
3749
3787
  if (document.getElementById("havik-tap")) return;
3750
3788
  let n = document.createElement("button");
3751
3789
  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", () => {
3752
3790
  n.remove(), t.play();
3753
3791
  }), document.body.appendChild(n);
3754
3792
  }
3755
- function Qn() {
3793
+ function nr() {
3756
3794
  let e = document.createElement("style");
3757
3795
  e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
3758
3796
  }
3759
3797
  //#endregion
3760
- export { bn as ODDIN_THEME, n as PlaybackError, Sn as applyTheme, Ke as baseUrlForEnv, Xn as bootEmbed, Te as clearDeviceId, Wn as createPlayer, E as deriveEventsBaseUrl, He as detectDrmSupport, C as enterVideoFullscreen, w as exitVideoFullscreen, _e as fetchCatalog, ye as fetchTournament, xe as flattenMatches, k as getDeviceId, We as isLowLatencyManifest, $ as isOddinMessage, De as licenseRequestHeaders, Kn as mountEmbed, de as pollToLive, y as resolveStream, T as subscribeLiveState, S as videoFullscreenActive, Ce as watchStatus };
3798
+ export { wn as ODDIN_THEME, n as PlaybackError, En as applyTheme, Ge as baseUrlForEnv, er as bootEmbed, Te as clearDeviceId, Jn as createPlayer, E as deriveEventsBaseUrl, Ve as detectDrmSupport, C as enterVideoFullscreen, w as exitVideoFullscreen, _e as fetchCatalog, ye as fetchTournament, xe as flattenMatches, k as getDeviceId, Ue as isLowLatencyManifest, $ as isOddinMessage, De as licenseRequestHeaders, Xn as mountEmbed, v as pollToLive, b as resolveStream, T as subscribeLiveState, S as videoFullscreenActive, Ce as watchStatus };
3761
3799
 
3762
3800
  //# sourceMappingURL=index.js.map