@oddin-gg/havik-player 2.16.13 → 2.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -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
@@ -470,6 +470,7 @@ function T(e) {
470
470
  clearTimeout(n), t();
471
471
  }, { once: !0 });
472
472
  }), l = (t) => {
473
+ if (o) return;
473
474
  e.onAlive?.();
474
475
  let n = "message", r = [];
475
476
  for (let e of t.split("\n")) {
@@ -671,14 +672,14 @@ function I(e) {
671
672
  function L(e) {
672
673
  return (e ?? "").trim().toLowerCase();
673
674
  }
674
- var je = {
675
+ var R = {
675
676
  hevc: "hvc1.1.6.L93.90",
676
677
  dv: "dvh1.05.06",
677
678
  av1: "av01.0.05M.08",
678
679
  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);
680
+ }, je = /* @__PURE__ */ new Map(), z = /* @__PURE__ */ new Map();
681
+ function Me(e) {
682
+ let t = L(e), n = je.get(t);
682
683
  if (n) return n;
683
684
  let r = {
684
685
  initDataTypes: ["cenc"],
@@ -696,23 +697,23 @@ function Ne(e) {
696
697
  } catch {
697
698
  return !1;
698
699
  }
699
- })().then((e) => (R.set(t, e), e));
700
- return Me.set(t, i), i;
700
+ })().then((e) => (z.set(t, e), e));
701
+ return je.set(t, i), i;
701
702
  }
702
- function Pe() {
703
- if (j()) for (let e of Object.values(je)) Ne(e);
703
+ function Ne() {
704
+ if (j()) for (let e of Object.values(R)) Me(e);
704
705
  }
705
- function Fe(e) {
706
+ function Pe(e) {
706
707
  let t = I(e);
707
- if (t) return t === "avc" ? !0 : R.get(L(e)) ?? R.get(L(je[t]));
708
+ if (t) return t === "avc" ? !0 : z.get(L(e)) ?? z.get(L(R[t]));
708
709
  }
709
710
  //#endregion
710
711
  //#region src/core/drm/support.ts
711
- var Ie = 5e3, Le = "video/mp4; codecs=\"avc1.42E01E\"", Re = "audio/mp4; codecs=\"mp4a.40.2\"", ze = {
712
+ var Fe = 5e3, Ie = "video/mp4; codecs=\"avc1.42E01E\"", Le = "audio/mp4; codecs=\"mp4a.40.2\"", Re = {
712
713
  widevine: ["com.widevine.alpha"],
713
714
  fairplay: ["com.apple.fps"]
714
715
  };
715
- function Be(e) {
716
+ function ze(e) {
716
717
  return e === "fairplay" ? [{
717
718
  initDataTypes: [
718
719
  "sinf",
@@ -720,30 +721,30 @@ function Be(e) {
720
721
  "cenc"
721
722
  ],
722
723
  videoCapabilities: [{
723
- contentType: Le,
724
+ contentType: Ie,
724
725
  robustness: "",
725
726
  encryptionScheme: "cbcs"
726
727
  }],
727
728
  audioCapabilities: [{
728
- contentType: Re,
729
+ contentType: Le,
729
730
  robustness: "",
730
731
  encryptionScheme: "cbcs"
731
732
  }]
732
733
  }] : N("com.widevine.alpha", [{
733
734
  initDataTypes: ["cenc"],
734
735
  videoCapabilities: [{
735
- contentType: Le,
736
+ contentType: Ie,
736
737
  robustness: F.video,
737
738
  encryptionScheme: F.scheme
738
739
  }],
739
740
  audioCapabilities: [{
740
- contentType: Re,
741
+ contentType: Le,
741
742
  robustness: F.audio,
742
743
  encryptionScheme: F.scheme
743
744
  }]
744
745
  }]);
745
746
  }
746
- function Ve(e, t) {
747
+ function Be(e, t) {
747
748
  return new Promise((n, r) => {
748
749
  let i = setTimeout(() => r(/* @__PURE__ */ Error("probe-timeout")), t);
749
750
  e.then((e) => {
@@ -753,8 +754,8 @@ function Ve(e, t) {
753
754
  });
754
755
  });
755
756
  }
756
- async function He(e = {}) {
757
- let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Ie, r = {};
757
+ async function Ve(e = {}) {
758
+ let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Fe, r = {};
758
759
  if (typeof window < "u" && window.isSecureContext === !1) return {
759
760
  verdict: "insecure-context",
760
761
  detail: r
@@ -766,7 +767,7 @@ async function He(e = {}) {
766
767
  };
767
768
  let a = !1, o = !1, s = Date.now() + n, c = () => Math.max(1, s - Date.now());
768
769
  for (let e of t) {
769
- let t = ze[e];
770
+ let t = Re[e];
770
771
  if (!t) {
771
772
  r[e] = "unknown system";
772
773
  continue;
@@ -777,7 +778,7 @@ async function He(e = {}) {
777
778
  break;
778
779
  }
779
780
  try {
780
- return await Ve((await Ve(i(n, Be(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
781
+ return await Be((await Be(i(n, ze(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
781
782
  verdict: "supported",
782
783
  system: e,
783
784
  detail: r
@@ -801,49 +802,49 @@ async function He(e = {}) {
801
802
  }
802
803
  //#endregion
803
804
  //#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);
805
+ var He = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
806
+ function Ue(e) {
807
+ return He.test(e);
807
808
  }
808
809
  //#endregion
809
810
  //#region src/core/env.ts
810
- var Ge = {
811
+ var We = {
811
812
  integration: "https://feed-dev.oddin-video.gg",
812
813
  production: "https://feed.oddin-video.gg"
813
814
  };
814
- function Ke(e) {
815
- let t = Object.prototype.hasOwnProperty.call(Ge, e) ? Ge[e] : void 0;
815
+ function Ge(e) {
816
+ let t = Object.prototype.hasOwnProperty.call(We, e) ? We[e] : void 0;
816
817
  if (!t) throw new n("INTERNAL", 0, `unknown env ${JSON.stringify(e)} — expected 'integration' or 'production'`);
817
818
  return t;
818
819
  }
819
820
  //#endregion
820
821
  //#region src/core/stats.ts
821
- var qe = { droppedFrames: 0 };
822
- function Je(e) {
822
+ var Ke = { droppedFrames: 0 };
823
+ function qe(e) {
823
824
  try {
824
825
  return new URL(e).host;
825
826
  } catch {
826
827
  return "";
827
828
  }
828
829
  }
829
- var Ye = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
830
- function Xe(e) {
830
+ var Je = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
831
+ function Ye(e) {
831
832
  if (typeof performance > "u" || typeof performance.getEntriesByType != "function") return "";
832
833
  let t = "", n = -1, r = performance.getEntriesByType("resource");
833
- for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || Ye.test(i.name)) && i.startTime >= n) {
834
- let e = Je(i.name);
834
+ for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || Je.test(i.name)) && i.startTime >= n) {
835
+ let e = qe(i.name);
835
836
  e && (t = e, n = i.startTime);
836
837
  }
837
838
  return t;
838
839
  }
839
- function z(e) {
840
+ function B(e) {
840
841
  let t = e.getVideoPlaybackQuality?.();
841
842
  return {
842
843
  dropped: t?.droppedVideoFrames ?? 0,
843
844
  totalFrames: t?.totalVideoFrames ?? 0
844
845
  };
845
846
  }
846
- var B = class {
847
+ var Xe = class {
847
848
  video;
848
849
  baseFrames = 0;
849
850
  baseDropped = 0;
@@ -853,7 +854,7 @@ var B = class {
853
854
  this.video = e;
854
855
  }
855
856
  read() {
856
- let e = z(this.video);
857
+ let e = B(this.video);
857
858
  return e.totalFrames < this.lastFrames && (this.baseFrames += this.lastFrames), e.dropped < this.lastDropped && (this.baseDropped += this.lastDropped), this.lastFrames = e.totalFrames, this.lastDropped = e.dropped, {
858
859
  dropped: this.baseDropped + e.dropped,
859
860
  totalFrames: this.baseFrames + e.totalFrames
@@ -883,8 +884,8 @@ function Ze(e, t) {
883
884
  }
884
885
  //#endregion
885
886
  //#region src/core/engine/native.ts
886
- var Qe = 2e3, $e = 3, V = 500, et = 6e3, tt = .25, nt = 250, rt = .05, it = 4;
887
- function at(e) {
887
+ var Qe = 2e3, $e = 3, V = 500, et = 6e3, tt = .25, nt = 250, rt = .05, it = 4, at = 12e3, ot = .25, st = 1e3;
888
+ function ct(e) {
888
889
  try {
889
890
  let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
890
891
  return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
@@ -900,7 +901,7 @@ function U() {
900
901
  let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
901
902
  return e || t;
902
903
  }
903
- function ot() {
904
+ function lt() {
904
905
  if (typeof navigator > "u" || !U()) return !1;
905
906
  let e = navigator.userAgent ?? "";
906
907
  return /iPhone|iPad|iPod/.test(e) ? !0 : /Macintosh/.test(e) && typeof navigator.maxTouchPoints == "number" && navigator.maxTouchPoints > 1;
@@ -922,6 +923,10 @@ var W = class {
922
923
  onEdgeReset = null;
923
924
  lastBufferedEnd = null;
924
925
  bufferedAdvancedAt = null;
926
+ lastSeekableEnd = null;
927
+ edgeStampedAt = null;
928
+ lastTickAt = null;
929
+ endedEmitted = !1;
925
930
  fairplayKeyIV;
926
931
  loadStarted;
927
932
  preloadTouched = !1;
@@ -931,12 +936,12 @@ var W = class {
931
936
  frameCounter;
932
937
  detachFrames = null;
933
938
  constructor(e) {
934
- this.deps = e, this.frameCounter = new B(e.video), this.loadStarted = e.deferLoad !== !0, this.builtAt = typeof performance < "u" ? performance.now() : 0;
939
+ this.deps = e, this.frameCounter = new Xe(e.video), this.loadStarted = e.deferLoad !== !0, this.builtAt = typeof performance < "u" ? performance.now() : 0;
935
940
  }
936
941
  async load() {
937
942
  this.detachFrames ??= this.frameCounter.attach();
938
943
  let { video: e, descriptor: t, emit: r } = this.deps;
939
- if (this.watchRefocus(), this.watchBufferedEnd(), this.loadStarted || (this.preloadTouched = !0, this.savedPreload = e.getAttribute("preload"), e.preload = "none"), t.drmEnabled) {
944
+ if (this.endedEmitted = !1, this.watchRefocus(), this.watchBufferedEnd(), this.loadStarted || (this.preloadTouched = !0, this.savedPreload = e.getAttribute("preload"), e.preload = "none"), t.drmEnabled) {
940
945
  if (!t.drm?.fairplay) {
941
946
  r({
942
947
  type: "error",
@@ -952,7 +957,7 @@ var W = class {
952
957
  type: "error",
953
958
  error: new n("INTERNAL", 0, "native HLS playback error"),
954
959
  fatal: !0
955
- }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = ct(t.manifestUrl, t.analytics?.sid), e.load();
960
+ }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = dt(t.manifestUrl, t.analytics?.sid), e.load();
956
961
  }
957
962
  startLoad() {
958
963
  this.loadStarted || (this.loadStarted = !0, this.restorePreload());
@@ -974,7 +979,7 @@ var W = class {
974
979
  });
975
980
  this.onEncrypted = (n) => {
976
981
  let i = n;
977
- i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = at(i.initData), (async () => {
982
+ i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = ct(i.initData), (async () => {
978
983
  try {
979
984
  let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
980
985
  initDataTypes: [i.initDataType],
@@ -1073,7 +1078,7 @@ var W = class {
1073
1078
  droppedFrames: t.dropped,
1074
1079
  decodedFrames: t.totalFrames
1075
1080
  };
1076
- if (this.cdnHost ||= Xe(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity) {
1081
+ if (this.cdnHost ||= Ye(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity) {
1077
1082
  n.isLive = !0;
1078
1083
  let t = this.liveEdgeEstimate(), r = t == null ? NaN : t - e.currentTime;
1079
1084
  Number.isFinite(r) && (n.atLiveEdge = r <= it, !e.paused && r >= 0 && (n.latencySeconds = r));
@@ -1119,21 +1124,43 @@ var W = class {
1119
1124
  watchBufferedEnd() {
1120
1125
  if (this.edgeTimer != null) return;
1121
1126
  let { video: e } = this.deps;
1122
- this.onEdgeReset = () => {
1123
- this.lastBufferedEnd = null, this.bufferedAdvancedAt = null;
1127
+ this.onEdgeReset = (e) => {
1128
+ this.lastBufferedEnd = null, this.bufferedAdvancedAt = null, e.type === "emptied" && this.resetEndStale();
1124
1129
  }, e.addEventListener("seeking", this.onEdgeReset), e.addEventListener("emptied", this.onEdgeReset), this.edgeTimer = setInterval(() => {
1125
1130
  if (e.duration !== Infinity) return;
1126
- let t = st(e, e.currentTime);
1131
+ this.checkEndStale();
1132
+ let t = ut(e, e.currentTime);
1127
1133
  t != null && ((this.lastBufferedEnd == null || Math.abs(t - this.lastBufferedEnd) >= rt) && (this.bufferedAdvancedAt = G()), this.lastBufferedEnd = t);
1128
1134
  }, nt);
1129
1135
  }
1136
+ checkEndStale() {
1137
+ if (this.endedEmitted) return;
1138
+ let e = G(), t = this.lastTickAt == null ? 0 : e - this.lastTickAt;
1139
+ this.lastTickAt = e;
1140
+ let n = this.liveEnd();
1141
+ if (n == null) return;
1142
+ let r = this.lastSeekableEnd == null || Math.abs(n - this.lastSeekableEnd) >= ot;
1143
+ this.lastSeekableEnd = n;
1144
+ let i = this.deps.video, a = typeof document < "u" && document.visibilityState === "hidden";
1145
+ if (r || t > st || a || i.paused) {
1146
+ this.edgeStampedAt = e;
1147
+ return;
1148
+ }
1149
+ e - (this.edgeStampedAt ?? e) > at && (this.endedEmitted = !0, this.deps.emit({
1150
+ type: "ended",
1151
+ reason: "stalled"
1152
+ }));
1153
+ }
1154
+ resetEndStale() {
1155
+ this.lastSeekableEnd = null, this.edgeStampedAt = null, this.lastTickAt = null;
1156
+ }
1130
1157
  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;
1158
+ 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.resetEndStale(), this.lastBufferedEnd = null, this.bufferedAdvancedAt = null;
1132
1159
  }
1133
1160
  liveEdgeEstimate() {
1134
1161
  let e = this.deps.video;
1135
1162
  if (e.duration !== Infinity) return null;
1136
- let t = this.liveEnd(), n = st(e, e.currentTime) ?? this.lastBufferedEnd;
1163
+ let t = this.liveEnd(), n = ut(e, e.currentTime) ?? this.lastBufferedEnd;
1137
1164
  if (n != null) {
1138
1165
  let e = this.bufferedAdvancedAt, r = n + (e == null ? 0 : Math.max(0, (G() - e) / 1e3));
1139
1166
  (t == null || r > t) && (t = r);
@@ -1170,7 +1197,7 @@ var W = class {
1170
1197
  function G() {
1171
1198
  return typeof performance < "u" ? performance.now() : Date.now();
1172
1199
  }
1173
- function st(e, t) {
1200
+ function ut(e, t) {
1174
1201
  let n = e.buffered;
1175
1202
  if (!n || !Number.isFinite(t)) return null;
1176
1203
  for (let e = 0; e < n.length; e += 1) if (n.start(e) <= t + .1 && n.end(e) > t) {
@@ -1179,7 +1206,7 @@ function st(e, t) {
1179
1206
  }
1180
1207
  return null;
1181
1208
  }
1182
- function ct(e, t) {
1209
+ function dt(e, t) {
1183
1210
  return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
1184
1211
  }
1185
1212
  //#endregion
@@ -1196,8 +1223,8 @@ function K(e, t = Date.now()) {
1196
1223
  }
1197
1224
  //#endregion
1198
1225
  //#region src/core/engine/prefetch.ts
1199
- var lt = 15e3, ut = 5e3, dt = 6;
1200
- function ft(e) {
1226
+ var ft = 15e3, pt = 5e3, mt = 6;
1227
+ function ht(e) {
1201
1228
  try {
1202
1229
  let t = new URL(e);
1203
1230
  return t.searchParams.delete("CMCD"), t.toString();
@@ -1205,7 +1232,7 @@ function ft(e) {
1205
1232
  return e;
1206
1233
  }
1207
1234
  }
1208
- var pt = class {
1235
+ var gt = class {
1209
1236
  cmcd;
1210
1237
  entries = /* @__PURE__ */ new Map();
1211
1238
  keyed = /* @__PURE__ */ new Set();
@@ -1228,10 +1255,10 @@ var pt = class {
1228
1255
  }
1229
1256
  prefetch(e, t, n) {
1230
1257
  if (!this.isActive(t)) return;
1231
- let r = ft(e);
1258
+ let r = ht(e);
1232
1259
  if (this.entries.has(r)) return;
1233
1260
  let i = this.perTrack.get(t) ?? 0;
1234
- if (i >= dt) return;
1261
+ if (i >= mt) return;
1235
1262
  this.perTrack.set(t, i + 1);
1236
1263
  let a = new AbortController(), o = {
1237
1264
  started: performance.now(),
@@ -1245,10 +1272,10 @@ var pt = class {
1245
1272
  signal: a.signal
1246
1273
  }).then(async (e) => (o.first = performance.now(), e.ok ? e.arrayBuffer() : null)).catch(() => null), this.entries.set(r, o), this.stats.started += 1, setTimeout(() => {
1247
1274
  this.entries.get(r) === o && (this.entries.delete(r), a.abort(), this.stats.expired += 1);
1248
- }, lt);
1275
+ }, ft);
1249
1276
  }
1250
1277
  take(e) {
1251
- let t = ft(e), n = this.entries.get(t);
1278
+ let t = ht(e), n = this.entries.get(t);
1252
1279
  return n && this.entries.delete(t), n;
1253
1280
  }
1254
1281
  destroy() {
@@ -1268,13 +1295,13 @@ var pt = class {
1268
1295
  }
1269
1296
  }
1270
1297
  };
1271
- function mt(t) {
1298
+ function _t(t) {
1272
1299
  let n = e.DefaultConfig?.loader;
1273
1300
  if (typeof n != "function") return;
1274
1301
  class r extends n {
1275
1302
  served = !1;
1276
1303
  cancelled = !1;
1277
- stats = ht();
1304
+ stats = vt();
1278
1305
  load(e, n, r) {
1279
1306
  let i = e.rangeEnd ? void 0 : t.take(e.url);
1280
1307
  if (!i) {
@@ -1282,7 +1309,7 @@ function mt(t) {
1282
1309
  return;
1283
1310
  }
1284
1311
  this.served = !0;
1285
- let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || ut, s = setTimeout(() => {
1312
+ let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || pt, s = setTimeout(() => {
1286
1313
  !this.cancelled && this.served && (i.abort.abort(), t.stats.failed += 1, this.served = !1, super.load(e, n, r));
1287
1314
  }, o);
1288
1315
  i.bytes.then((o) => {
@@ -1309,7 +1336,7 @@ function mt(t) {
1309
1336
  }
1310
1337
  return r;
1311
1338
  }
1312
- function ht() {
1339
+ function vt() {
1313
1340
  return {
1314
1341
  aborted: !1,
1315
1342
  loaded: 0,
@@ -1333,10 +1360,10 @@ function ht() {
1333
1360
  }
1334
1361
  };
1335
1362
  }
1336
- function gt(e) {
1363
+ function q(e) {
1337
1364
  return e === "audio" ? "audio" : "main";
1338
1365
  }
1339
- function _t(e, t) {
1366
+ function yt(e, t) {
1340
1367
  let n = [];
1341
1368
  t.initSegment?.url && !t.initSegment.data && n.push({
1342
1369
  url: t.initSegment.url,
@@ -1355,24 +1382,24 @@ function _t(e, t) {
1355
1382
  }
1356
1383
  //#endregion
1357
1384
  //#region src/core/engine/hls.ts
1358
- function vt() {
1385
+ function bt() {
1359
1386
  return e.isSupported();
1360
1387
  }
1361
- var yt = 3, bt = 5, xt = 3, St = 1e4, Ct = 3e4, wt = 12e3, Tt = 3e3, Et = .02, Dt = 6e3, Ot = .5, kt = 3, At = .5, jt = 1.1, Mt = .25, Nt = 5e3, Pt = 4e3, Ft = 2, It = 5, Lt = 2, Rt = 2, zt = 4, Bt = 4, Vt = 2e3, Ht = 3e4, Ut = .2, Wt = 30, Gt = 2, Kt = 2, qt = 9, Jt = .5, Yt = 64;
1362
- function Xt(e) {
1388
+ var xt = 3, St = 5, Ct = 3, wt = 1e4, Tt = 3e4, Et = 12e3, Dt = 3e3, Ot = .02, kt = 6e3, At = .5, jt = 3, Mt = .5, Nt = 1.1, Pt = .25, Ft = 5e3, It = 4e3, Lt = 2, Rt = 5, zt = 2, Bt = 2, Vt = 4, Ht = 4, Ut = 2e3, Wt = 3e4, Gt = .2, Kt = 30, qt = 2, Jt = 2, Yt = 9, Xt = .5, Zt = 64;
1389
+ function Qt(e) {
1363
1390
  if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
1364
1391
  delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
1365
1392
  return;
1366
1393
  }
1367
- e.liveSyncDuration ??= Kt;
1368
- let t = Math.max(12, e.liveSyncDuration + qt);
1369
- (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), Zt(e, e.liveSyncDuration);
1394
+ e.liveSyncDuration ??= Jt;
1395
+ let t = Math.max(12, e.liveSyncDuration + Yt);
1396
+ (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), $t(e, e.liveSyncDuration);
1370
1397
  }
1371
- function Zt(e, t) {
1398
+ function $t(e, t) {
1372
1399
  let n = (e, t, n) => Math.min(n, Math.max(t, e));
1373
1400
  e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
1374
1401
  }
1375
- var Qt = class {
1402
+ var en = class {
1376
1403
  name = "hls";
1377
1404
  hls = null;
1378
1405
  deps;
@@ -1438,6 +1465,8 @@ var Qt = class {
1438
1465
  capTimer = null;
1439
1466
  sizeCapLevel = null;
1440
1467
  bitrateCapLevel = -1;
1468
+ pushedCapLevel = -1;
1469
+ pushedCapReason = null;
1441
1470
  fpsCapBitrate = null;
1442
1471
  fpsCapFailedHeight = null;
1443
1472
  fpsCapManaged = !0;
@@ -1452,7 +1481,7 @@ var Qt = class {
1452
1481
  frameCounter;
1453
1482
  detachFrames = null;
1454
1483
  constructor(e) {
1455
- this.deps = e, this.frameCounter = new B(e.video), this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
1484
+ this.deps = e, this.frameCounter = new Xe(e.video), this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
1456
1485
  }
1457
1486
  async load() {
1458
1487
  this.detachFrames ??= this.frameCounter.attach();
@@ -1465,7 +1494,7 @@ var Qt = class {
1465
1494
  });
1466
1495
  return;
1467
1496
  }
1468
- e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ae(r), Pe()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1497
+ e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ae(r), Ne()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1469
1498
  let e = this.hls;
1470
1499
  if (document.visibilityState !== "visible" || !e) return;
1471
1500
  let t = e.liveSyncPosition;
@@ -1488,7 +1517,7 @@ var Qt = class {
1488
1517
  }
1489
1518
  this.loadSuspended = !0;
1490
1519
  }
1491
- }, Nt));
1520
+ }, Ft));
1492
1521
  }
1493
1522
  resumeLoading() {
1494
1523
  if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
@@ -1520,7 +1549,7 @@ var Qt = class {
1520
1549
  let t = e.liveSyncPosition;
1521
1550
  if (typeof t != "number" || !Number.isFinite(t)) return;
1522
1551
  let { video: n } = this.deps;
1523
- n.currentTime <= t + Jt || (n.currentTime = t);
1552
+ n.currentTime <= t + Xt || (n.currentTime = t);
1524
1553
  }
1525
1554
  reanchorPartTimeline(e, t) {
1526
1555
  let { frag: n, part: r } = t;
@@ -1532,7 +1561,7 @@ var Qt = class {
1532
1561
  let o = n.sn, s = i.fragments.find((e) => e && e.sn === o) ?? (i.fragmentHint?.sn === o ? i.fragmentHint : void 0);
1533
1562
  if (!s) return;
1534
1563
  let c = a.startPTS - s.start;
1535
- if (!(!Number.isFinite(c) || Math.abs(c) < Et)) {
1564
+ if (!(!Number.isFinite(c) || Math.abs(c) < Ot)) {
1536
1565
  for (let e of i.fragments) e && e.setStart(e.start + c);
1537
1566
  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})`);
1538
1567
  }
@@ -1572,7 +1601,7 @@ var Qt = class {
1572
1601
  return;
1573
1602
  }
1574
1603
  let l = this.hls, u, d = new Promise((e) => {
1575
- u = setTimeout(() => e(void 0), St);
1604
+ u = setTimeout(() => e(void 0), wt);
1576
1605
  });
1577
1606
  return Promise.race([c().catch(() => void 0), d]).finally(() => clearTimeout(u)).then((e) => {
1578
1607
  if (!this.hls || this.hls !== l) throw Error("havik-player: engine torn down during refresh");
@@ -1588,20 +1617,20 @@ var Qt = class {
1588
1617
  ...c
1589
1618
  };
1590
1619
  if (this.prefetch?.destroy(), this.prefetch = null, u && this.deps.mediaDuringKey !== !1 && !f.fLoader) {
1591
- let e = new pt({
1620
+ let e = new gt({
1592
1621
  sessionId: n.analytics?.sid,
1593
1622
  contentId: n.matchUrn
1594
- }), t = mt(e);
1623
+ }), t = _t(e);
1595
1624
  t && (this.prefetch = e, f.fLoader = t);
1596
1625
  }
1597
- Xt(f), this.catchUpRate = typeof f.maxLiveSyncPlaybackRate == "number" ? f.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (f.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = f.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = f.autoStartLoad !== !1;
1626
+ Qt(f), this.catchUpRate = typeof f.maxLiveSyncPlaybackRate == "number" ? f.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (f.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = f.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = f.autoStartLoad !== !1;
1598
1627
  let p = new e(f);
1599
1628
  if (this.hls = p, p.on(e.Events.FRAG_PARSED, (e, t) => this.reanchorPartTimeline(p, t)), p.on(e.Events.MANIFEST_PARSED, () => {
1600
1629
  this.mediaRecoveries = 0, this.networkRecoveries = 0, u && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && this.dropLevelsWidevineCannotPlay(p), this.measureLadder(p), this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
1601
1630
  }), p.on(e.Events.FRAG_BUFFERED, (e, t) => {
1602
1631
  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(() => {
1603
1632
  this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
1604
- }, Ct)));
1633
+ }, Tt)));
1605
1634
  }), p.on(e.Events.FRAG_LOADING, (e, t) => {
1606
1635
  t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
1607
1636
  }), p.on(e.Events.FRAG_LOADED, (e, t) => {
@@ -1609,10 +1638,10 @@ var Qt = class {
1609
1638
  let n = t?.frag?.stats, r = n?.loaded;
1610
1639
  typeof r == "number" && (this.bytesLoaded += r), !this.reportedFirstBytes && typeof r == "number" && r > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
1611
1640
  let i = n?.loading;
1612
- 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 > Yt && this.requestTimesMs.shift());
1641
+ 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 > Zt && this.requestTimesMs.shift());
1613
1642
  let a = t?.frag?.url;
1614
1643
  if (a) {
1615
- let e = Je(a);
1644
+ let e = qe(a);
1616
1645
  e && (this.cdnHost = e);
1617
1646
  }
1618
1647
  }), p.on(e.Events.LEVEL_LOADED, (e, t) => {
@@ -1626,15 +1655,15 @@ var Qt = class {
1626
1655
  }), p.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.prefetch) {
1627
1656
  let t = this.prefetch;
1628
1657
  p.on(e.Events.KEY_LOADING, (e, n) => {
1629
- let r = n?.frag, i = gt(r?.type);
1630
- if (r && t.isActive(i)) for (let e of _t(p, r)) t.prefetch(e.url, i, e.kind);
1631
- }), p.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(gt(n?.frag?.type)));
1658
+ let r = n?.frag, i = q(r?.type);
1659
+ if (r && t.isActive(i)) for (let e of yt(p, r)) t.prefetch(e.url, i, e.kind);
1660
+ }), p.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(q(n?.frag?.type)));
1632
1661
  }
1633
1662
  p.on(e.Events.KEY_LOADED, () => {
1634
1663
  u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
1635
1664
  }), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
1636
1665
  this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.checkFrameDrops();
1637
- }, Tt), p.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1666
+ }, Dt), p.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1638
1667
  this.renditionSwitches += 1;
1639
1668
  let n = this.lastLevelIndex >= 0 ? p.levels[this.lastLevelIndex] : void 0, r = p.levels[t.level];
1640
1669
  n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, l({
@@ -1698,7 +1727,7 @@ var Qt = class {
1698
1727
  return;
1699
1728
  }
1700
1729
  this.capTimer && clearTimeout(this.capTimer);
1701
- let t = e > this.sizeCapLevel ? Vt : Ht;
1730
+ let t = e > this.sizeCapLevel ? Ut : Wt;
1702
1731
  this.capTimer = setTimeout(() => {
1703
1732
  this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
1704
1733
  }, t);
@@ -1708,9 +1737,9 @@ var Qt = class {
1708
1737
  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;
1709
1738
  }
1710
1739
  dropLevelsWidevineCannotPlay(e) {
1711
- this.removeLevelsWhere(e, (e) => Fe(e) !== !0);
1740
+ this.removeLevelsWhere(e, (e) => Pe(e) !== !0);
1712
1741
  let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && I(e) !== "avc" && !!I(e)));
1713
- for (let n of t) Ne(n).then((t) => {
1742
+ for (let n of t) Me(n).then((t) => {
1714
1743
  t || this.hls !== e || this.removeLevelsWhere(e, (e) => e === n) && (this.measureLadder(e), this.applySizeCap());
1715
1744
  });
1716
1745
  }
@@ -1721,7 +1750,7 @@ var Qt = class {
1721
1750
  a && I(a) && t(a) && (r.push(n), i.add(a));
1722
1751
  }), !r.length) return !1;
1723
1752
  let a = [...i].join(", ");
1724
- 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;
1753
+ 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;
1725
1754
  for (let t = r.length - 1; t >= 0; --t) e.removeLevel(r[t]);
1726
1755
  return console.info(`havik-player: skipped ${r.length} rendition(s) Widevine cannot play on this browser (${a})`), !0;
1727
1756
  }
@@ -1735,11 +1764,12 @@ var Qt = class {
1735
1764
  let e = this.hls;
1736
1765
  if (!e) return;
1737
1766
  let t = [
1738
- this.sizeCapLevel ?? -1,
1739
- this.bitrateCapLevel,
1740
- this.fpsCapLevel(e)
1741
- ].filter((e) => e >= 0);
1742
- e.autoLevelCapping = t.length ? Math.min(...t) : -1;
1767
+ ["size", this.sizeCapLevel ?? -1],
1768
+ ["bitrate", this.bitrateCapLevel],
1769
+ ["fps", this.fpsCapLevel(e)]
1770
+ ], n = -1, r = null;
1771
+ for (let [e, i] of t) i >= 0 && (n < 0 || i < n) && (n = i, r = e);
1772
+ e.autoLevelCapping = n, this.pushedCapLevel = n, this.pushedCapReason = r;
1743
1773
  }
1744
1774
  getAudioTracks() {
1745
1775
  return this.hls ? this.hls.audioTracks.map((e) => ({
@@ -1792,7 +1822,14 @@ var Qt = class {
1792
1822
  if (this.cdnHost && (n.cdnHost = this.cdnHost), this.licenseRequested && (n.keySystem = "widevine", n.drmSecurityLevel = "L3"), e) {
1793
1823
  n.qualityPinned = !e.autoLevelEnabled, typeof e.latency == "number" && (n.latencySeconds = e.latency), typeof e.targetLatency == "number" && e.targetLatency > 0 && (n.targetLatencySeconds = e.targetLatency), typeof e.bandwidthEstimate == "number" && (n.bandwidthKbps = Math.round(e.bandwidthEstimate / 1e3));
1794
1824
  let t = e.currentLevel >= 0 ? e.levels[e.currentLevel] : void 0;
1795
- t && (n.levelHeight = t.height), t?.videoCodec && (n.videoCodec = t.videoCodec), t?.audioCodec && (n.audioCodec = t.audioCodec), t && typeof t.bitrate == "number" && (n.renditionBitrateKbps = Math.round(t.bitrate / 1e3)), typeof t?.details?.live == "boolean" && (n.isLive = t.details.live, typeof e.liveSyncPosition == "number" && (n.atLiveEdge = this.deps.video.currentTime >= e.liveSyncPosition - 1.5));
1825
+ t && (n.levelHeight = t.height);
1826
+ let r = e.autoLevelCapping, i = r >= 0 ? e.levels[r] : void 0;
1827
+ if (i && i.height > 0) {
1828
+ n.maxLevelHeight = i.height;
1829
+ let t = e.config ?? {};
1830
+ t.capLevelToPlayerSize !== !0 && t.capLevelOnFPSDrop !== !0 && r === this.pushedCapLevel && this.pushedCapReason && (n.capReason = this.pushedCapReason);
1831
+ }
1832
+ t?.videoCodec && (n.videoCodec = t.videoCodec), t?.audioCodec && (n.audioCodec = t.audioCodec), t && typeof t.bitrate == "number" && (n.renditionBitrateKbps = Math.round(t.bitrate / 1e3)), typeof t?.details?.live == "boolean" && (n.isLive = t.details.live, typeof e.liveSyncPosition == "number" && (n.atLiveEdge = this.deps.video.currentTime >= e.liveSyncPosition - 1.5));
1796
1833
  }
1797
1834
  return n;
1798
1835
  }
@@ -1819,7 +1856,7 @@ var Qt = class {
1819
1856
  return;
1820
1857
  }
1821
1858
  let e = Date.now() - this.lastAdvanceMs;
1822
- !this.chaseSuspended && e > Dt && this.suspendChasing(), e > wt && this.emitEnded("stalled");
1859
+ !this.chaseSuspended && e > kt && this.suspendChasing(), e > Et && this.emitEnded("stalled");
1823
1860
  }
1824
1861
  resetStarvationWindow() {
1825
1862
  this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
@@ -1834,7 +1871,7 @@ var Qt = class {
1834
1871
  this.resetStarvationWindow();
1835
1872
  return;
1836
1873
  }
1837
- let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < Dt, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > Pt, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = z(t), c = o - s, l = c !== this.starvedFrames;
1874
+ let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < kt, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > It, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = B(t), c = o - s, l = c !== this.starvedFrames;
1838
1875
  if (this.starvedFrames = c, !a || l) {
1839
1876
  (t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
1840
1877
  return;
@@ -1843,12 +1880,12 @@ var Qt = class {
1843
1880
  this.resetStarvationWindow();
1844
1881
  return;
1845
1882
  }
1846
- 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 > zt && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= Lt && (this.clearKick(), this.starvationRebuilds < Rt)) {
1883
+ 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 > Vt && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= zt && (this.clearKick(), this.starvationRebuilds < Bt)) {
1847
1884
  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");
1848
1885
  return;
1849
1886
  }
1850
- let u = i && this.starvedTicks >= Ft, d = !i && this.deadTicks >= zt && this.recentMainFrags.reduce((e, t) => e + t, 0) >= Bt;
1851
- if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= It))) {
1887
+ let u = i && this.starvedTicks >= Lt, d = !i && this.deadTicks >= Vt && this.recentMainFrags.reduce((e, t) => e + t, 0) >= Ht;
1888
+ if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= Rt))) {
1852
1889
  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");
1853
1890
  try {
1854
1891
  e.stopLoad(), e.startLoad(-1);
@@ -1863,7 +1900,7 @@ var Qt = class {
1863
1900
  let t = e.latency, n = e.targetLatency;
1864
1901
  if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
1865
1902
  let r = t - n;
1866
- !this.catchUpEngaged && r > Ot ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= Ot && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
1903
+ !this.catchUpEngaged && r > At ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= At && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
1867
1904
  let i = this.catchUpEngaged ? this.catchUpRate : 1;
1868
1905
  e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
1869
1906
  }
@@ -1884,16 +1921,16 @@ var Qt = class {
1884
1921
  this.resetFrameDropWindow();
1885
1922
  return;
1886
1923
  }
1887
- let { totalFrames: n, dropped: r } = z(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
1888
- if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < Wt || o < 0) {
1924
+ let { totalFrames: n, dropped: r } = B(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
1925
+ if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < Kt || o < 0) {
1889
1926
  this.fpsBadTicks = 0;
1890
1927
  return;
1891
1928
  }
1892
- if (o <= Ut * a) {
1929
+ if (o <= Gt * a) {
1893
1930
  this.fpsBadTicks = 0;
1894
1931
  return;
1895
1932
  }
1896
- if (this.fpsBadTicks += 1, this.fpsBadTicks < Gt) return;
1933
+ if (this.fpsBadTicks += 1, this.fpsBadTicks < qt) return;
1897
1934
  this.fpsBadTicks = 0;
1898
1935
  let s = e.levels, c = s[e.currentLevel];
1899
1936
  if (!c) return;
@@ -1910,20 +1947,20 @@ var Qt = class {
1910
1947
  return;
1911
1948
  }
1912
1949
  let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
1913
- if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(jt, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
1950
+ if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(Nt, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
1914
1951
  this.resetChaseWindow();
1915
1952
  return;
1916
1953
  }
1917
- if (this.chaseLatency < 0 || this.chaseLatency - n >= At) {
1954
+ if (this.chaseLatency < 0 || this.chaseLatency - n >= Mt) {
1918
1955
  this.chaseLatency = n, this.chaseTicks = 0;
1919
1956
  return;
1920
1957
  }
1921
- if (this.chaseTicks += 1, this.chaseTicks < kt) return;
1958
+ if (this.chaseTicks += 1, this.chaseTicks < jt) return;
1922
1959
  this.resetChaseWindow();
1923
1960
  let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
1924
1961
  if (!(a > 1)) return;
1925
1962
  let o = typeof e.targetLatency == "number" ? e.targetLatency : 0, s = Math.min(n, a - 1);
1926
- s < o + Mt || (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);
1963
+ s < o + Pt || (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);
1927
1964
  }
1928
1965
  suspendChasing() {
1929
1966
  let e = this.hls;
@@ -1968,7 +2005,7 @@ var Qt = class {
1968
2005
  scheduleLicenseRetry(t) {
1969
2006
  if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
1970
2007
  let n = t.response?.code ?? 0;
1971
- if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= xt) return !1;
2008
+ if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= Ct) return !1;
1972
2009
  this.licenseRecoveries += 1;
1973
2010
  let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
1974
2011
  return this.licenseRetryTimer = setTimeout(() => {
@@ -2000,7 +2037,7 @@ var Qt = class {
2000
2037
  return;
2001
2038
  }
2002
2039
  if (t.type === e.ErrorTypes.NETWORK_ERROR) {
2003
- if (this.networkRecoveries < bt) {
2040
+ if (this.networkRecoveries < St) {
2004
2041
  this.networkRecoveries += 1;
2005
2042
  let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
2006
2043
  this.networkRetryTimer = setTimeout(() => {
@@ -2017,7 +2054,7 @@ var Qt = class {
2017
2054
  return;
2018
2055
  }
2019
2056
  if (t.type === e.ErrorTypes.MEDIA_ERROR) {
2020
- if (this.mediaRecoveries < yt) {
2057
+ if (this.mediaRecoveries < xt) {
2021
2058
  this.mediaRecoveries += 1, n.recoverMediaError();
2022
2059
  return;
2023
2060
  }
@@ -2041,19 +2078,19 @@ var Qt = class {
2041
2078
  let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
2042
2079
  return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
2043
2080
  }
2044
- }, $t = 15e3, en = 6e5, tn = 3e5, nn = 100, q = 1, rn = 1e3, an = 3e4, on = 1e3, sn = {
2081
+ }, tn = 15e3, nn = 6e5, rn = 3e5, an = 100, J = 1, on = 1e3, sn = 3e4, cn = 1e3, ln = {
2045
2082
  inline: "PRESENTATION_INLINE",
2046
2083
  fullscreen: "PRESENTATION_FULLSCREEN",
2047
2084
  pip: "PRESENTATION_PIP"
2048
- }, cn = {
2085
+ }, un = {
2049
2086
  widevine: "KEY_SYSTEM_WIDEVINE",
2050
2087
  fairplay: "KEY_SYSTEM_FAIRPLAY",
2051
2088
  none: "KEY_SYSTEM_NONE"
2052
2089
  };
2053
- function ln(e, t) {
2090
+ function dn(e, t) {
2054
2091
  return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
2055
2092
  }
2056
- var un = /* @__PURE__ */ new Set([
2093
+ var fn = /* @__PURE__ */ new Set([
2057
2094
  "INVALID_URN",
2058
2095
  "NOT_FOUND",
2059
2096
  "GONE",
@@ -2063,7 +2100,7 @@ var un = /* @__PURE__ */ new Set([
2063
2100
  "FORBIDDEN",
2064
2101
  "RATE_LIMITED",
2065
2102
  "TIMEOUT"
2066
- ]), J = {
2103
+ ]), Y = {
2067
2104
  idle: "PLAYER_STATE_IDLE",
2068
2105
  waiting: "PLAYER_STATE_WAITING",
2069
2106
  loading: "PLAYER_STATE_LOADING",
@@ -2073,7 +2110,7 @@ var un = /* @__PURE__ */ new Set([
2073
2110
  ended: "PLAYER_STATE_ENDED",
2074
2111
  error: "PLAYER_STATE_ERROR"
2075
2112
  };
2076
- function dn(e) {
2113
+ function pn(e) {
2077
2114
  try {
2078
2115
  let t = new URL(e), [n, ...r] = t.hostname.split(".");
2079
2116
  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);
@@ -2081,8 +2118,8 @@ function dn(e) {
2081
2118
  return;
2082
2119
  }
2083
2120
  }
2084
- var fn = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), pn = /* @__PURE__ */ new Set(), Y = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), mn = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
2085
- function hn(e) {
2121
+ var mn = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), hn = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), Z = /* @__PURE__ */ new Set(), gn = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
2122
+ function _n(e) {
2086
2123
  if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
2087
2124
  let t;
2088
2125
  try {
@@ -2091,19 +2128,19 @@ function hn(e) {
2091
2128
  } catch {
2092
2129
  return;
2093
2130
  }
2094
- if (pn.has(t) && !Y.has(t)) {
2095
- Y.add(t), g(mn(new URL(t).origin));
2096
- for (let e of X) e.noteCspBlocked();
2131
+ if (hn.has(t) && !X.has(t)) {
2132
+ X.add(t), g(gn(new URL(t).origin));
2133
+ for (let e of Z) e.noteCspBlocked();
2097
2134
  }
2098
2135
  }
2099
- function Z(e, t) {
2136
+ function vn(e, t) {
2100
2137
  return g(t, e), { disabledReason: t };
2101
2138
  }
2102
- function gn(e, t, n) {
2103
- if (n) return t && !fn(t, n) && g(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
2139
+ function yn(e, t, n) {
2140
+ if (n) return t && !mn(t, n) && g(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
2104
2141
  if (t) return { endpoint: t };
2105
- if (t !== void 0) return Z("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).");
2106
- let r = dn(e);
2142
+ if (t !== void 0) return vn("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).");
2143
+ let r = pn(e);
2107
2144
  if (r) return { endpoint: r };
2108
2145
  let i;
2109
2146
  try {
@@ -2111,9 +2148,9 @@ function gn(e, t, n) {
2111
2148
  } catch {
2112
2149
  i = e;
2113
2150
  }
2114
- return Z(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).`);
2151
+ return vn(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).`);
2115
2152
  }
2116
- var _n = class {
2153
+ var bn = class {
2117
2154
  opts;
2118
2155
  url;
2119
2156
  cspKey;
@@ -2195,8 +2232,8 @@ var _n = class {
2195
2232
  constructor(e) {
2196
2233
  this.opts = {
2197
2234
  ...e,
2198
- heartbeatMs: e.heartbeatMs ?? $t,
2199
- idleMs: e.idleMs ?? en
2235
+ heartbeatMs: e.heartbeatMs ?? tn,
2236
+ idleMs: e.idleMs ?? nn
2200
2237
  }, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
2201
2238
  try {
2202
2239
  let e = new URL(this.url);
@@ -2213,11 +2250,11 @@ var _n = class {
2213
2250
  sdkVersion: this.opts.sdkVersion,
2214
2251
  ...this.opts.environment
2215
2252
  };
2216
- this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), rn), 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 && pn.add(this.cspKey), document.addEventListener("securitypolicyviolation", hn), X.add(this), this.noteCspBlocked(), this.onVisibility());
2253
+ this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), on), 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 && hn.add(this.cspKey), document.addEventListener("securitypolicyviolation", _n), Z.add(this), this.noteCspBlocked(), this.onVisibility());
2217
2254
  }
2218
2255
  checkSuspension(e) {
2219
2256
  if (this.endedFlag || !this.opts.idleMs) return !1;
2220
- let t = Math.max(this.opts.idleMs, tn);
2257
+ let t = Math.max(this.opts.idleMs, rn);
2221
2258
  return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
2222
2259
  }
2223
2260
  syncIdle(e) {
@@ -2231,21 +2268,21 @@ var _n = class {
2231
2268
  noteStateChange(e, t, n, r) {
2232
2269
  if (this.endedFlag || e === t) return;
2233
2270
  let i = this.now();
2234
- if (t === "playing" ? (this.playingSinceMs === null && (this.playingSinceMs = i), this.startupTimeMs === 0 && (this.startupTimeMs = Math.max(q, i - this.startupAnchorMs)), this.firstAudioMs === 0 && !this.isMuted && (this.firstAudioMs = Math.max(q, i - this.startupAnchorMs)), this.isMuted && this.mutedSinceMs === null && (this.mutedSinceMs = i)) : this.playingSinceMs !== null && (this.playingTotalMs += i - this.playingSinceMs, this.playingSinceMs = null, this.mutedSinceMs !== null && (this.mutedTotalMs += i - this.mutedSinceMs, this.mutedSinceMs = null)), this.isPlaying = t === "playing", this.syncActive(), t === "waiting" ? this.waitingSinceMs = i : this.waitingSinceMs !== null && (this.waitingTotalMs += i - this.waitingSinceMs, this.waitingSinceMs = null), t === "buffering" && e === "playing") {
2271
+ if (t === "playing" ? (this.playingSinceMs === null && (this.playingSinceMs = i), this.startupTimeMs === 0 && (this.startupTimeMs = Math.max(J, i - this.startupAnchorMs)), this.firstAudioMs === 0 && !this.isMuted && (this.firstAudioMs = Math.max(J, i - this.startupAnchorMs)), this.isMuted && this.mutedSinceMs === null && (this.mutedSinceMs = i)) : this.playingSinceMs !== null && (this.playingTotalMs += i - this.playingSinceMs, this.playingSinceMs = null, this.mutedSinceMs !== null && (this.mutedTotalMs += i - this.mutedSinceMs, this.mutedSinceMs = null)), this.isPlaying = t === "playing", this.syncActive(), t === "waiting" ? this.waitingSinceMs = i : this.waitingSinceMs !== null && (this.waitingTotalMs += i - this.waitingSinceMs, this.waitingSinceMs = null), t === "buffering" && e === "playing") {
2235
2272
  this.stallIsSeekInduced = this.seekInduced(i);
2236
2273
  let e = !this.isHidden && !this.stallIsSeekInduced;
2237
- e && (this.rebufferCount += 1), this.isBuffering = !0, this.lastStallMs = i, e && this.timeToFirstStallMs === 0 && (this.timeToFirstStallMs = Math.max(q, Math.round(this.playingTotalMs)));
2274
+ e && (this.rebufferCount += 1), this.isBuffering = !0, this.lastStallMs = i, e && this.timeToFirstStallMs === 0 && (this.timeToFirstStallMs = Math.max(J, Math.round(this.playingTotalMs)));
2238
2275
  } else e === "buffering" && (this.isBuffering = !1, this.stallIsSeekInduced = !1);
2239
2276
  this.syncBuffering(), t === "paused" && (this.pauseCount += 1), this.syncIdle(t);
2240
2277
  let a = {
2241
- fromState: J[e] ?? "PLAYER_STATE_UNSPECIFIED",
2242
- toState: J[t] ?? "PLAYER_STATE_UNSPECIFIED",
2243
- presentation: sn[this.presentation]
2278
+ fromState: Y[e] ?? "PLAYER_STATE_UNSPECIFIED",
2279
+ toState: Y[t] ?? "PLAYER_STATE_UNSPECIFIED",
2280
+ presentation: ln[this.presentation]
2244
2281
  }, o = this.causeOf(e, t, i);
2245
2282
  o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
2246
2283
  }
2247
2284
  seekInduced(e) {
2248
- return this.lastSeekMs >= 0 && e - this.lastSeekMs < on;
2285
+ return this.lastSeekMs >= 0 && e - this.lastSeekMs < cn;
2249
2286
  }
2250
2287
  causeOf(e, t, n) {
2251
2288
  if (t === "error") return "TRANSITION_CAUSE_ERROR";
@@ -2282,25 +2319,25 @@ var _n = class {
2282
2319
  }
2283
2320
  this.muteChanges += 1;
2284
2321
  let r = this.now();
2285
- n ? this.isPlaying && this.mutedSinceMs === null && (this.mutedSinceMs = r) : (this.mutedSinceMs !== null && (this.mutedTotalMs += r - this.mutedSinceMs, this.mutedSinceMs = null), this.firstAudioMs === 0 && this.isPlaying && (this.firstAudioMs = Math.max(q, r - this.startupAnchorMs))), this.isMuted = n, this.syncActive();
2322
+ n ? this.isPlaying && this.mutedSinceMs === null && (this.mutedSinceMs = r) : (this.mutedSinceMs !== null && (this.mutedTotalMs += r - this.mutedSinceMs, this.mutedSinceMs = null), this.firstAudioMs === 0 && this.isPlaying && (this.firstAudioMs = Math.max(J, r - this.startupAnchorMs))), this.isMuted = n, this.syncActive();
2286
2323
  }
2287
2324
  notePresentation(e) {
2288
2325
  this.endedFlag || e === this.presentation || (this.closePresentation(), this.presentation = e);
2289
2326
  }
2290
2327
  notePlayIntent() {
2291
- this.endedFlag || this.startupTimeMs > 0 || (this.startupAnchorMs = this.now(), this.manifestLoadMs > 0 && (this.manifestLoadMs = q), this.firstPlaylistMs > 0 && (this.firstPlaylistMs = q), this.firstFragLoadMs > 0 && (this.firstFragLoadMs = q), this.drmSetupMs > 0 && (this.drmSetupMs = q));
2328
+ this.endedFlag || this.startupTimeMs > 0 || (this.startupAnchorMs = this.now(), this.manifestLoadMs > 0 && (this.manifestLoadMs = J), this.firstPlaylistMs > 0 && (this.firstPlaylistMs = J), this.firstFragLoadMs > 0 && (this.firstFragLoadMs = J), this.drmSetupMs > 0 && (this.drmSetupMs = J));
2292
2329
  }
2293
2330
  noteReady() {
2294
- this.manifestLoadMs === 0 && (this.manifestLoadMs = Math.max(q, this.now() - this.startupAnchorMs));
2331
+ this.manifestLoadMs === 0 && (this.manifestLoadMs = Math.max(J, this.now() - this.startupAnchorMs));
2295
2332
  }
2296
2333
  noteFirstPlaylist() {
2297
- this.firstPlaylistMs === 0 && (this.firstPlaylistMs = Math.max(q, this.now() - this.startupAnchorMs));
2334
+ this.firstPlaylistMs === 0 && (this.firstPlaylistMs = Math.max(J, this.now() - this.startupAnchorMs));
2298
2335
  }
2299
2336
  noteDrmReady() {
2300
- this.drmSetupMs === 0 && (this.drmSetupMs = Math.max(q, this.now() - this.startupAnchorMs));
2337
+ this.drmSetupMs === 0 && (this.drmSetupMs = Math.max(J, this.now() - this.startupAnchorMs));
2301
2338
  }
2302
2339
  noteFirstBytes() {
2303
- this.sawFirstBytes = !0, this.firstFragLoadMs === 0 && (this.firstFragLoadMs = Math.max(q, this.now() - this.startupAnchorMs));
2340
+ this.sawFirstBytes = !0, this.firstFragLoadMs === 0 && (this.firstFragLoadMs = Math.max(J, this.now() - this.startupAnchorMs));
2304
2341
  }
2305
2342
  noteSeek() {
2306
2343
  this.endedFlag || (this.seekCount += 1, this.lastSeekMs = this.now());
@@ -2319,7 +2356,7 @@ var _n = class {
2319
2356
  let r = n ?? "";
2320
2357
  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";
2321
2358
  if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
2322
- if (un.has(e)) return "ERROR_STAGE_RESOLVE";
2359
+ if (fn.has(e)) return "ERROR_STAGE_RESOLVE";
2323
2360
  let i = t ?? "";
2324
2361
  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";
2325
2362
  }
@@ -2351,7 +2388,7 @@ var _n = class {
2351
2388
  let l = t.droppedFrames ?? 0;
2352
2389
  l > this.lastDropped && (o.droppedFramesDelta = l - this.lastDropped), this.lastDropped = l;
2353
2390
  let u = t.renditionSwitches ?? 0;
2354
- u > this.lastSwitches && (o.renditionSwitchesDelta = u - this.lastSwitches), this.lastSwitches = u, n > this.lastHbPlayingMs && (o.playingMsDelta = Math.round(n - this.lastHbPlayingMs)), this.lastHbPlayingMs = n, r > this.lastHbHiddenMs && (o.hiddenMsDelta = Math.round(r - this.lastHbHiddenMs)), this.lastHbHiddenMs = r, i > this.lastHbRebufferMs && (o.rebufferMsDelta = Math.round(i - this.lastHbRebufferMs)), this.lastHbRebufferMs = i, this.rebufferCount > this.lastHbRebufferCount && (o.rebufferCountDelta = this.rebufferCount - this.lastHbRebufferCount), this.lastHbRebufferCount = this.rebufferCount, a > this.lastHbActiveMs && (o.activeMsDelta = Math.round(a - this.lastHbActiveMs)), this.lastHbActiveMs = a, typeof t.latencySeconds == "number" && (o.latencyMs = Math.round(t.latencySeconds * 1e3)), typeof t.targetLatencySeconds == "number" && (o.targetLatencyMs = Math.round(t.targetLatencySeconds * 1e3)), typeof t.bandwidthKbps == "number" && (o.bandwidthEstKbps = t.bandwidthKbps), typeof t.levelHeight == "number" && (o.renditionHeight = t.levelHeight), typeof t.renditionBitrateKbps == "number" && (o.renditionBitrateKbps = t.renditionBitrateKbps), t.atLiveEdge === !0 && (o.atLiveEdge = !0), typeof t.bufferedMs == "number" && t.bufferedMs > 0 && (o.bufferedMs = Math.round(t.bufferedMs)), o.playerState = J[t.state] ?? "PLAYER_STATE_UNSPECIFIED";
2391
+ u > this.lastSwitches && (o.renditionSwitchesDelta = u - this.lastSwitches), this.lastSwitches = u, n > this.lastHbPlayingMs && (o.playingMsDelta = Math.round(n - this.lastHbPlayingMs)), this.lastHbPlayingMs = n, r > this.lastHbHiddenMs && (o.hiddenMsDelta = Math.round(r - this.lastHbHiddenMs)), this.lastHbHiddenMs = r, i > this.lastHbRebufferMs && (o.rebufferMsDelta = Math.round(i - this.lastHbRebufferMs)), this.lastHbRebufferMs = i, this.rebufferCount > this.lastHbRebufferCount && (o.rebufferCountDelta = this.rebufferCount - this.lastHbRebufferCount), this.lastHbRebufferCount = this.rebufferCount, a > this.lastHbActiveMs && (o.activeMsDelta = Math.round(a - this.lastHbActiveMs)), this.lastHbActiveMs = a, typeof t.latencySeconds == "number" && (o.latencyMs = Math.round(t.latencySeconds * 1e3)), typeof t.targetLatencySeconds == "number" && (o.targetLatencyMs = Math.round(t.targetLatencySeconds * 1e3)), typeof t.bandwidthKbps == "number" && (o.bandwidthEstKbps = t.bandwidthKbps), typeof t.levelHeight == "number" && (o.renditionHeight = t.levelHeight), typeof t.renditionBitrateKbps == "number" && (o.renditionBitrateKbps = t.renditionBitrateKbps), t.atLiveEdge === !0 && (o.atLiveEdge = !0), typeof t.bufferedMs == "number" && t.bufferedMs > 0 && (o.bufferedMs = Math.round(t.bufferedMs)), o.playerState = Y[t.state] ?? "PLAYER_STATE_UNSPECIFIED";
2355
2392
  let d = this.mutedTotalMs;
2356
2393
  this.mutedSinceMs !== null && (d += e - this.mutedSinceMs), d > this.lastHbMutedMs && (o.mutedMsDelta = Math.round(d - this.lastHbMutedMs)), this.lastHbMutedMs = d;
2357
2394
  let f = t.upshifts ?? 0;
@@ -2366,20 +2403,20 @@ var _n = class {
2366
2403
  if (this.lastRequestCount = g, _ > 0) {
2367
2404
  o.requestCountDelta = _;
2368
2405
  let e = t.requestTimesMs ?? [], n = e.slice(Math.max(0, e.length - _)).sort((e, t) => e - t);
2369
- n.length > 0 && (o.requestTimeP50Ms = ln(n, 50), o.requestTimeP95Ms = ln(n, 95));
2406
+ n.length > 0 && (o.requestTimeP50Ms = dn(n, 50), o.requestTimeP95Ms = dn(n, 95));
2370
2407
  }
2371
2408
  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();
2372
2409
  }
2373
2410
  maybeEmitMediaInfo(e) {
2374
2411
  if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
2375
2412
  let t = {};
2376
- e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = cn[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);
2413
+ e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = un[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);
2377
2414
  let n = JSON.stringify(t);
2378
2415
  n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
2379
2416
  }
2380
2417
  end(e, t) {
2381
2418
  if (this.endedFlag) return;
2382
- this.endedFlag = !0, X.delete(this);
2419
+ this.endedFlag = !0, Z.delete(this);
2383
2420
  let n = t ?? this.now();
2384
2421
  this.playingSinceMs !== null && (this.playingTotalMs += n - this.playingSinceMs, this.playingSinceMs = null), this.hiddenSinceMs !== null && (this.hiddenTotalMs += n - this.hiddenSinceMs, this.hiddenSinceMs = null), this.bufferingSinceMs !== null && (this.rebufferTotalMs += n - this.bufferingSinceMs, this.bufferingSinceMs = null), this.mutedSinceMs !== null && (this.mutedTotalMs += n - this.mutedSinceMs, this.mutedSinceMs = null), this.waitingSinceMs !== null && (this.waitingTotalMs += n - this.waitingSinceMs, this.waitingSinceMs = null), this.isPlaying = !1, this.syncActive(n), this.closePresentation(n), this.firstFlushTimer &&= (clearTimeout(this.firstFlushTimer), null), this.timer &&= (clearInterval(this.timer), null), this.idleTimer &&= (clearTimeout(this.idleTimer), null), typeof window < "u" && window.removeEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), document.removeEventListener("freeze", this.onFreeze), document.removeEventListener("resume", this.onResume));
2385
2422
  let r = this.safeSample();
@@ -2393,7 +2430,7 @@ var _n = class {
2393
2430
  let c = r?.positionMs ?? 0;
2394
2431
  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));
2395
2432
  let l = e !== "END_REASON_ENDED";
2396
- l && this.lastStallMs > 0 && n - this.lastStallMs <= an && (i.abandonAfterStallMs = Math.max(q, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= an && (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);
2433
+ l && this.lastStallMs > 0 && n - this.lastStallMs <= sn && (i.abandonAfterStallMs = Math.max(J, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= sn && (i.abandonAfterErrorMs = Math.max(J, Math.round(n - this.lastErrorMs))), this.fullscreenTotalMs > 0 && (i.fullscreenTimeMs = Math.round(this.fullscreenTotalMs)), this.pipTotalMs > 0 && (i.pipTimeMs = Math.round(this.pipTotalMs)), this.volumeChanges > 0 && (i.volumeChanges = this.volumeChanges), this.muteChanges > 0 && (i.muteChanges = this.muteChanges);
2397
2434
  let u = r?.decodedFrames ?? this.lastDecoded;
2398
2435
  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");
2399
2436
  }
@@ -2413,13 +2450,13 @@ var _n = class {
2413
2450
  };
2414
2451
  }
2415
2452
  noteCspBlocked() {
2416
- this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(mn(new URL(this.url).origin)));
2453
+ this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(gn(new URL(this.url).origin)));
2417
2454
  }
2418
2455
  cspBlocked() {
2419
- return !!this.cspKey && Y.has(this.cspKey);
2456
+ return !!this.cspKey && X.has(this.cspKey);
2420
2457
  }
2421
2458
  enqueue(e) {
2422
- if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > nn;) {
2459
+ if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > an;) {
2423
2460
  let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
2424
2461
  this.pending.splice(e >= 0 ? e : 0, 1);
2425
2462
  }
@@ -2446,7 +2483,7 @@ var _n = class {
2446
2483
  };
2447
2484
  //#endregion
2448
2485
  //#region src/core/environment.ts
2449
- function vn() {
2486
+ function xn() {
2450
2487
  if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
2451
2488
  let e;
2452
2489
  try {
@@ -2471,14 +2508,14 @@ function vn() {
2471
2508
  integration: "INTEGRATION_KIND_IFRAME"
2472
2509
  };
2473
2510
  }
2474
- function yn() {
2511
+ function Sn() {
2475
2512
  if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
2476
2513
  let e = navigator.userAgentData, t = e?.platform ?? "";
2477
2514
  if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
2478
2515
  let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
2479
2516
  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";
2480
2517
  }
2481
- function bn() {
2518
+ function Cn() {
2482
2519
  let e = typeof navigator < "u" ? navigator.connection : void 0;
2483
2520
  if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
2484
2521
  let t = {
@@ -2497,17 +2534,17 @@ function bn() {
2497
2534
  }
2498
2535
  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;
2499
2536
  }
2500
- function xn(e) {
2501
- let t = vn(), n = {
2502
- deviceClass: yn(),
2537
+ function wn(e) {
2538
+ let t = xn(), n = {
2539
+ deviceClass: Sn(),
2503
2540
  integration: t.integration,
2504
- ...bn()
2541
+ ...Cn()
2505
2542
  };
2506
2543
  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);
2507
2544
  let r = e.getBoundingClientRect?.();
2508
2545
  return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
2509
2546
  }
2510
- async function Sn() {
2547
+ async function Tn() {
2511
2548
  let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
2512
2549
  if (!e?.getHighEntropyValues) return {};
2513
2550
  try {
@@ -2519,7 +2556,7 @@ async function Sn() {
2519
2556
  }
2520
2557
  //#endregion
2521
2558
  //#region src/core/version.ts
2522
- var Cn = "2.16.13", wn = {
2559
+ var En = "2.17.0", Dn = {
2523
2560
  accent: "#E1B600",
2524
2561
  accentText: "#1B1C23",
2525
2562
  background: "#0e0f13",
@@ -2530,7 +2567,7 @@ var Cn = "2.16.13", wn = {
2530
2567
  border: "rgba(255, 255, 255, 0.1)",
2531
2568
  radius: "8px",
2532
2569
  fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
2533
- }, Tn = {
2570
+ }, On = {
2534
2571
  accent: "--havik-accent",
2535
2572
  accentText: "--havik-accent-text",
2536
2573
  background: "--havik-bg",
@@ -2542,26 +2579,26 @@ var Cn = "2.16.13", wn = {
2542
2579
  radius: "--havik-radius",
2543
2580
  fontFamily: "--havik-font"
2544
2581
  };
2545
- function En(e, t) {
2582
+ function kn(e, t) {
2546
2583
  let n = {
2547
- ...wn,
2584
+ ...Dn,
2548
2585
  ...t
2549
2586
  };
2550
- for (let t of Object.keys(Tn)) e.style.setProperty(Tn[t], n[t]);
2587
+ for (let t of Object.keys(On)) e.style.setProperty(On[t], n[t]);
2551
2588
  n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
2552
2589
  }
2553
2590
  //#endregion
2554
2591
  //#region src/ui/styles.ts
2555
- 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();
2556
- function An(e = document, t) {
2557
- let n = e.querySelector(`style#${Dn}`);
2558
- if (n && (!t || kn.get(n) === t)) return;
2592
+ var An = "havik-player-styles", jn = "\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", Mn = /* @__PURE__ */ new WeakMap();
2593
+ function Nn(e = document, t) {
2594
+ let n = e.querySelector(`style#${An}`);
2595
+ if (n && (!t || Mn.get(n) === t)) return;
2559
2596
  let r = e.createElement("style");
2560
- 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);
2597
+ r.id = An, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = jn, Mn.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
2561
2598
  }
2562
2599
  //#endregion
2563
2600
  //#region src/ui/icons.ts
2564
- var jn = {
2601
+ var Pn = {
2565
2602
  play: "<path d=\"M8 5v14l11-7z\"/>",
2566
2603
  pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
2567
2604
  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\"/>",
@@ -2575,20 +2612,20 @@ var jn = {
2575
2612
  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\"/>"
2576
2613
  };
2577
2614
  function Q(e) {
2578
- return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${jn[e]}</svg>`;
2615
+ return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Pn[e]}</svg>`;
2579
2616
  }
2580
2617
  //#endregion
2581
2618
  //#region src/ui/controls.ts
2582
- var Mn = 3e3, Nn = 250, Pn = /* @__PURE__ */ new Set([
2619
+ var Fn = 3e3, In = 250, Ln = /* @__PURE__ */ new Set([
2583
2620
  "GONE",
2584
2621
  "NOT_FOUND",
2585
2622
  "INVALID_URN",
2586
2623
  "UNAUTHORIZED"
2587
2624
  ]);
2588
- function Fn(e) {
2589
- return new In(e);
2625
+ function Rn(e) {
2626
+ return new zn(e);
2590
2627
  }
2591
- var In = class {
2628
+ var zn = class {
2592
2629
  root;
2593
2630
  video;
2594
2631
  player;
@@ -2635,7 +2672,7 @@ var In = class {
2635
2672
  scrubbing = !1;
2636
2673
  offFns = [];
2637
2674
  constructor(e) {
2638
- 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.streamEnded = e.streamEnded ?? (() => !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");
2675
+ this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Fn, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.streamEnded = e.streamEnded ?? (() => !1), this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, Nn(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");
2639
2676
  let t = (e, t, n) => {
2640
2677
  let r = this.doc.createElement(e);
2641
2678
  if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
@@ -2721,7 +2758,7 @@ var In = class {
2721
2758
  let t = this.surfaceWasHidden;
2722
2759
  this.tapTimer = setTimeout(() => {
2723
2760
  this.tapTimer = void 0, this.toggleBar(t);
2724
- }, Nn);
2761
+ }, In);
2725
2762
  }
2726
2763
  toggleBar(e) {
2727
2764
  e ? this.poke() : this.hideIfIdle();
@@ -2756,7 +2793,7 @@ var In = class {
2756
2793
  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);
2757
2794
  } else {
2758
2795
  let r = this.doc.createElement("div");
2759
- if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !Pn.has(this.lastError.code)) {
2796
+ if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !Ln.has(this.lastError.code)) {
2760
2797
  let e = this.doc.createElement("button");
2761
2798
  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);
2762
2799
  }
@@ -2797,7 +2834,7 @@ var In = class {
2797
2834
  let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
2798
2835
  this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
2799
2836
  }
2800
- !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Ln(this.video.currentTime)} / ${Ln(this.video.duration)}`);
2837
+ !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Bn(this.video.currentTime)} / ${Bn(this.video.duration)}`);
2801
2838
  }
2802
2839
  syncLive() {
2803
2840
  let e = this.player.getStats(), t = e.isLive !== !1, n = this.player.state === "ended", r = !t && !this.streamEnded();
@@ -2847,17 +2884,17 @@ var In = class {
2847
2884
  renderQualityMenu() {
2848
2885
  let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
2849
2886
  n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
2850
- for (let n of e) this.menu.append(this.menuItem(Rn(n), t === n.index, () => this.player.setQuality(n.index)));
2887
+ for (let n of e) this.menu.append(this.menuItem(Vn(n), t === n.index, () => this.player.setQuality(n.index)));
2851
2888
  }
2852
2889
  renderAudioMenu() {
2853
2890
  let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
2854
2891
  t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
2855
- for (let t of e) this.menu.append(this.menuItem(zn(t), t.default, () => this.player.setAudioTrack(t.id)));
2892
+ for (let t of e) this.menu.append(this.menuItem(Hn(t), t.default, () => this.player.setAudioTrack(t.id)));
2856
2893
  }
2857
2894
  renderCcMenu() {
2858
2895
  let e = this.player.getTextTracks(), t = this.doc.createElement("div");
2859
2896
  t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
2860
- for (let t of e) this.menu.append(this.menuItem(Bn(t), !1, () => this.player.setTextTrack(t.id)));
2897
+ for (let t of e) this.menu.append(this.menuItem(Un(t), !1, () => this.player.setTextTrack(t.id)));
2861
2898
  }
2862
2899
  onTracksChanged() {
2863
2900
  this.openMenu && this.renderMenu(this.openMenu);
@@ -2958,41 +2995,41 @@ var In = class {
2958
2995
  this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
2959
2996
  }
2960
2997
  };
2961
- function Ln(e) {
2998
+ function Bn(e) {
2962
2999
  (!Number.isFinite(e) || e < 0) && (e = 0);
2963
3000
  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");
2964
3001
  return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
2965
3002
  }
2966
- function Rn(e) {
3003
+ function Vn(e) {
2967
3004
  return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
2968
3005
  }
2969
- function zn(e) {
3006
+ function Hn(e) {
2970
3007
  return e.name || e.lang || `Track ${e.id}`;
2971
3008
  }
2972
- function Bn(e) {
3009
+ function Un(e) {
2973
3010
  return e.name || e.lang || `Track ${e.id}`;
2974
3011
  }
2975
3012
  //#endregion
2976
3013
  //#region src/managed/index.ts
2977
- var Vn = 6e3, Hn = 45e3, Un = 2e3, Wn = 3, Gn = 2e3, Kn = 48e4, qn = "keySystemLicenseRequestFailed";
2978
- function Jn(e) {
3014
+ var Wn = 6e3, Gn = 45e3, Kn = 2e3, qn = 3, Jn = 5e3, Yn = 2e3, Xn = 48e4, Zn = "keySystemLicenseRequestFailed";
3015
+ function Qn(e) {
2979
3016
  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)})`);
2980
- if (e.env !== void 0) return Ke(e.env);
3017
+ if (e.env !== void 0) return Ge(e.env);
2981
3018
  if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
2982
3019
  return e.baseUrl;
2983
3020
  }
2984
- async function Yn(e) {
3021
+ async function $n(e) {
2985
3022
  if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
2986
- let t = Jn(e);
3023
+ let t = Qn(e);
2987
3024
  if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
2988
3025
  if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
2989
- let r = new Xn({
3026
+ let r = new er({
2990
3027
  ...e,
2991
3028
  baseUrl: t
2992
3029
  });
2993
3030
  return await r.start(), r;
2994
3031
  }
2995
- var Xn = class {
3032
+ var er = class {
2996
3033
  opts;
2997
3034
  abort = new AbortController();
2998
3035
  listeners = {};
@@ -3006,6 +3043,9 @@ var Xn = class {
3006
3043
  refreshTimer;
3007
3044
  refreshInFlight;
3008
3045
  onRefocus;
3046
+ onReturnVisible = null;
3047
+ onReturnPageShow = null;
3048
+ hiddenAtMs = null;
3009
3049
  staleLicenseReloaded = !1;
3010
3050
  _state = "idle";
3011
3051
  _descriptor = null;
@@ -3040,7 +3080,7 @@ var Xn = class {
3040
3080
  this.opts.muted && (this.opts.video.muted = !0), this.opts.poster && (this.opts.video.poster = this.opts.poster), this.mountControls(), this.attachPipListeners(), this.attachEndedPlayGuard(), this.setState("loading");
3041
3081
  let e = ++this.loadGen, t = this.resolveOptions();
3042
3082
  try {
3043
- let n = await v(t);
3083
+ let n = await y(t);
3044
3084
  if (await this.onResolved(n, e), e === this.loadGen && this._state === "error" && this._lastError) {
3045
3085
  let e = this._lastError;
3046
3086
  throw this.destroy(), e;
@@ -3067,7 +3107,7 @@ var Xn = class {
3067
3107
  r ? this.armWithSse(e, r, t, n) : this.beginArmingByPolling(e);
3068
3108
  }
3069
3109
  beginArmingByPolling(e) {
3070
- y({
3110
+ b({
3071
3111
  ...this.resolveOptions(),
3072
3112
  signal: this.abort.signal,
3073
3113
  waitForLive: this.buildWaitConfig(e)
@@ -3084,7 +3124,7 @@ var Xn = class {
3084
3124
  setTimeout(() => {
3085
3125
  a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
3086
3126
  phase: i ? "unavailable" : "tooEarly",
3087
- retryInMs: Hn,
3127
+ retryInMs: Gn,
3088
3128
  attempt: 1,
3089
3129
  elapsedMs: 0,
3090
3130
  ...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
@@ -3101,7 +3141,7 @@ var Xn = class {
3101
3141
  }
3102
3142
  }
3103
3143
  }, h = () => {
3104
- a || s || p() || (s = !0, y({
3144
+ a || s || p() || (s = !0, b({
3105
3145
  ...this.resolveOptions(),
3106
3146
  signal: c.signal,
3107
3147
  waitForLive: this.buildWaitConfig(e)
@@ -3109,7 +3149,7 @@ var Xn = class {
3109
3149
  a || p() || c.signal.aborted || (a = !0, this.closeArming(), this.fail(e instanceof n ? e : new n("INTERNAL", 0, String(e))));
3110
3150
  }));
3111
3151
  }, g = () => {
3112
- a || p() || v(this.resolveOptions()).then((e) => m(e)).catch((e) => {
3152
+ a || p() || y(this.resolveOptions()).then((e) => m(e)).catch((e) => {
3113
3153
  if (!(a || p())) {
3114
3154
  if (e instanceof n && o(e.code)) {
3115
3155
  h();
@@ -3123,13 +3163,13 @@ var Xn = class {
3123
3163
  !a && !p() && h();
3124
3164
  }, e);
3125
3165
  };
3126
- _(Vn), this.armingSub = T({
3166
+ _(Wn), this.armingSub = T({
3127
3167
  eventsBaseUrl: t,
3128
3168
  matchUrn: this.opts.matchUrn,
3129
3169
  credential: this.opts.credential,
3130
- onAlive: () => _(Hn),
3170
+ onAlive: () => _(Gn),
3131
3171
  onState: (e) => {
3132
- a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Un);
3172
+ a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Kn);
3133
3173
  },
3134
3174
  onError: () => h()
3135
3175
  });
@@ -3163,7 +3203,7 @@ var Xn = class {
3163
3203
  a(), i.destroy();
3164
3204
  return;
3165
3205
  }
3166
- this.engine = i, this.detachMedia = a, this.opts.maxBitrate != null && i.setMaxBitrate(this.opts.maxBitrate), this.startStats(), this.scheduleLicenseRefresh(), this.startLiveState(t), this.startAnalytics(e, i, t), r && (this.pendingStartLoad = !0, this.setState("paused"), i.name === "native" && setTimeout(() => {
3206
+ this.engine = i, this.detachMedia = a, this.opts.maxBitrate != null && i.setMaxBitrate(this.opts.maxBitrate), this.startStats(), this.scheduleLicenseRefresh(), this.startLiveState(t), this.watchReturn(), this.startAnalytics(e, i, t), r && (this.pendingStartLoad = !0, this.setState("paused"), i.name === "native" && setTimeout(() => {
3167
3207
  this.destroyed || t !== this.loadGen || this.engine !== i || (this.analyticsSession?.noteReady(), this.emit("ready"));
3168
3208
  }, 0));
3169
3209
  }
@@ -3174,26 +3214,26 @@ var Xn = class {
3174
3214
  if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
3175
3215
  let i = e.analytics?.sid;
3176
3216
  if (!i) return;
3177
- 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);
3217
+ let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = yn(this.opts.baseUrl, a, e.analytics?.endpoint);
3178
3218
  if (!o) {
3179
3219
  s && setTimeout(() => {
3180
3220
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
3181
3221
  }, 0);
3182
3222
  return;
3183
3223
  }
3184
- let c = this.opts.video, l = new _n({
3224
+ let c = this.opts.video, l = new bn({
3185
3225
  endpoint: o,
3186
3226
  sid: i,
3187
3227
  player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
3188
- sdkVersion: Cn,
3189
- environment: xn(c),
3228
+ sdkVersion: En,
3229
+ environment: wn(c),
3190
3230
  idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
3191
3231
  onIdle: () => this.onAnalyticsIdle(t),
3192
3232
  onBlocked: (e) => setTimeout(() => {
3193
3233
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, e));
3194
3234
  }, 0),
3195
3235
  sample: () => {
3196
- let e = this.engine?.getStats() ?? qe, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
3236
+ let e = this.engine?.getStats() ?? Ke, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
3197
3237
  return {
3198
3238
  ...e,
3199
3239
  bufferedMs: Math.round(t * 1e3),
@@ -3207,7 +3247,7 @@ var Xn = class {
3207
3247
  let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
3208
3248
  c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
3209
3249
  c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
3210
- }, 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");
3250
+ }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), Tn().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
3211
3251
  }
3212
3252
  currentPresentation() {
3213
3253
  let e = this.opts.video;
@@ -3234,9 +3274,9 @@ var Xn = class {
3234
3274
  freshLicenseUrl: () => this.refreshLicense()
3235
3275
  }, o = this.opts.engine ?? "auto";
3236
3276
  if (o === "native") return new W(a);
3237
- if (o === "hls") return new Qt(a);
3238
- if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && H(this.opts.video) && U() || !e.drmEnabled && ot() && H(this.opts.video)) return new W(a);
3239
- if (vt()) return new Qt(a);
3277
+ if (o === "hls") return new en(a);
3278
+ if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && H(this.opts.video) && U() || !e.drmEnabled && lt() && H(this.opts.video)) return new W(a);
3279
+ if (bt()) return new en(a);
3240
3280
  if (H(this.opts.video)) return new W(a);
3241
3281
  throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
3242
3282
  }
@@ -3299,13 +3339,31 @@ var Xn = class {
3299
3339
  r = 0, i = !1;
3300
3340
  },
3301
3341
  onError: () => {
3302
- this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= Wn && (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.`))));
3342
+ this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= qn && (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.`))));
3303
3343
  }
3304
3344
  });
3305
3345
  }
3306
3346
  closeLiveState() {
3307
3347
  this.liveStateSub?.close(), this.liveStateSub = null;
3308
3348
  }
3349
+ watchReturn() {
3350
+ this.onReturnVisible || typeof document > "u" || this.opts.liveStateEvents !== !1 && (document.visibilityState === "hidden" && (this.hiddenAtMs = Date.now()), this.onReturnVisible = () => {
3351
+ if (document.visibilityState === "hidden") {
3352
+ this.hiddenAtMs ??= Date.now();
3353
+ return;
3354
+ }
3355
+ let e = this.hiddenAtMs;
3356
+ this.hiddenAtMs = null, e != null && Date.now() - e >= Jn && this.resyncLiveState();
3357
+ }, this.onReturnPageShow = (e) => {
3358
+ e.persisted && this.resyncLiveState();
3359
+ }, document.addEventListener("visibilitychange", this.onReturnVisible), typeof window < "u" && window.addEventListener("pageshow", this.onReturnPageShow));
3360
+ }
3361
+ unwatchReturn() {
3362
+ this.onReturnVisible && typeof document < "u" && document.removeEventListener("visibilitychange", this.onReturnVisible), this.onReturnPageShow && typeof window < "u" && window.removeEventListener("pageshow", this.onReturnPageShow), this.onReturnVisible = null, this.onReturnPageShow = null, this.hiddenAtMs = null;
3363
+ }
3364
+ resyncLiveState() {
3365
+ !this.destroyed && this.liveStateSub && this.startLiveState(this.loadGen);
3366
+ }
3309
3367
  onStreamEnded(e = !1, t) {
3310
3368
  if (!this.destroyed) {
3311
3369
  if ((e || !this.rejoinEnabled()) && (this.cancelRejoin(), this.closeLiveState()), this.endedHandled) {
@@ -3327,7 +3385,7 @@ var Xn = class {
3327
3385
  scheduleRejoin(e) {
3328
3386
  this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
3329
3387
  this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
3330
- }, Math.random() * Un));
3388
+ }, Math.random() * Kn));
3331
3389
  }
3332
3390
  cancelRejoin() {
3333
3391
  this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
@@ -3351,7 +3409,7 @@ var Xn = class {
3351
3409
  }
3352
3410
  t.controls = !1;
3353
3411
  let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
3354
- r && r.insertBefore(n, t), n.appendChild(t), En(n, this.opts.theme), this.container = n, this.controlBar = Fn({
3412
+ r && r.insertBefore(n, t), n.appendChild(t), kn(n, this.opts.theme), this.container = n, this.controlBar = Rn({
3355
3413
  root: n,
3356
3414
  video: t,
3357
3415
  player: this,
@@ -3389,7 +3447,7 @@ var Xn = class {
3389
3447
  }
3390
3448
  startStats() {
3391
3449
  this.stopStats();
3392
- let e = Math.max(500, this.opts.statsIntervalMs ?? Gn);
3450
+ let e = Math.max(500, this.opts.statsIntervalMs ?? Yn);
3393
3451
  this.statsTimer = setInterval(() => {
3394
3452
  if (!this.engine) return;
3395
3453
  let e = this.engine.getStats();
@@ -3400,14 +3458,14 @@ var Xn = class {
3400
3458
  this.statsTimer && clearInterval(this.statsTimer), this.statsTimer = void 0;
3401
3459
  }
3402
3460
  isStaleLicenseDenial(e) {
3403
- return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== qn || e.error.httpStatus !== 403 ? !1 : K(this._descriptor?.drm?.widevine?.licenseUrl);
3461
+ return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== Zn || e.error.httpStatus !== 403 ? !1 : K(this._descriptor?.drm?.widevine?.licenseUrl);
3404
3462
  }
3405
3463
  scheduleLicenseRefresh() {
3406
3464
  if (this.stopRefresh(), !this._descriptor?.drmEnabled) return;
3407
3465
  typeof document < "u" && this.engine?.name === "hls" && (this.onRefocus = () => {
3408
3466
  document.visibilityState !== "visible" || this.destroyed || K(this._descriptor?.drm?.widevine?.licenseUrl) && this.refreshLicense();
3409
3467
  }, document.addEventListener("visibilitychange", this.onRefocus));
3410
- let e = this.opts.licenseRefreshMs ?? Kn;
3468
+ let e = this.opts.licenseRefreshMs ?? Xn;
3411
3469
  e && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
3412
3470
  }
3413
3471
  stopRefresh() {
@@ -3419,7 +3477,7 @@ var Xn = class {
3419
3477
  if (this.refreshInFlight?.engine === e) return this.refreshInFlight.promise;
3420
3478
  let t = (async () => {
3421
3479
  try {
3422
- let t = await v(this.resolveOptions());
3480
+ let t = await y(this.resolveOptions());
3423
3481
  if (this.destroyed || this.engine !== e) return;
3424
3482
  let n = t.drm?.widevine?.licenseUrl, r = t.drm?.fairplay?.licenseUrl;
3425
3483
  return (n || r) && (e.setLicenseUrls({
@@ -3464,7 +3522,7 @@ var Xn = class {
3464
3522
  this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
3465
3523
  }
3466
3524
  getStats() {
3467
- return this.engine?.getStats() ?? qe;
3525
+ return this.engine?.getStats() ?? Ke;
3468
3526
  }
3469
3527
  getQualityLevels() {
3470
3528
  return this.engine?.getQualityLevels() ?? [];
@@ -3516,7 +3574,7 @@ var Xn = class {
3516
3574
  let e = ++this.loadGen;
3517
3575
  this.teardownPlayback();
3518
3576
  try {
3519
- let t = await y({
3577
+ let t = await b({
3520
3578
  ...this.resolveOptions(),
3521
3579
  waitForLive: this.opts.waitForLive ? this.buildWaitConfig(e) : void 0
3522
3580
  });
@@ -3531,7 +3589,7 @@ var Xn = class {
3531
3589
  return n.add(t), () => n.delete(t);
3532
3590
  }
3533
3591
  destroy() {
3534
- this.destroyed || (this.destroyed = !0, this.loadGen += 1, this.abort.abort(), this.stopStats(), this.stopRefresh(), this.unmountControls(), this.cancelRejoin(), this.closeArming(), this.closeLiveState(), this.detachMedia?.(), this.detachPip?.(), this.detachEndedPlayGuard?.(), this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.engine?.destroy(), this.engine = null, this.setState("idle"), this.clearListeners());
3592
+ this.destroyed || (this.destroyed = !0, this.loadGen += 1, this.abort.abort(), this.stopStats(), this.stopRefresh(), this.unmountControls(), this.cancelRejoin(), this.closeArming(), this.closeLiveState(), this.unwatchReturn(), this.detachMedia?.(), this.detachPip?.(), this.detachEndedPlayGuard?.(), this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.engine?.destroy(), this.engine = null, this.setState("idle"), this.clearListeners());
3535
3593
  }
3536
3594
  clearListeners() {
3537
3595
  for (let e of Object.keys(this.listeners)) this.listeners[e]?.clear();
@@ -3574,7 +3632,7 @@ function $(e) {
3574
3632
  }
3575
3633
  //#endregion
3576
3634
  //#region src/embed/host.ts
3577
- function Zn(e) {
3635
+ function tr(e) {
3578
3636
  if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
3579
3637
  if (!e.src) throw Error("mountEmbed: opts.src is required");
3580
3638
  if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
@@ -3633,15 +3691,15 @@ function Zn(e) {
3633
3691
  }
3634
3692
  //#endregion
3635
3693
  //#region src/embed/page.ts
3636
- var Qn = /^[A-Za-z0-9:_.-]{1,128}$/;
3637
- function $n(e) {
3694
+ var nr = /^[A-Za-z0-9:_.-]{1,128}$/;
3695
+ function rr(e) {
3638
3696
  if (typeof e == "boolean") return e;
3639
3697
  if (typeof e == "object" && e) {
3640
3698
  let t = e.endpoint;
3641
3699
  return typeof t == "string" ? { endpoint: t } : {};
3642
3700
  }
3643
3701
  }
3644
- function er() {
3702
+ function ir() {
3645
3703
  let e = window.HAVIK_EMBED_CONFIG;
3646
3704
  if (e) return {
3647
3705
  baseUrl: e.baseUrl ?? "",
@@ -3651,7 +3709,7 @@ function er() {
3651
3709
  autoplay: e.autoplay ?? !0,
3652
3710
  muted: e.muted ?? !0,
3653
3711
  waitForLive: e.waitForLive ?? !0,
3654
- analytics: $n(e.analytics)
3712
+ analytics: rr(e.analytics)
3655
3713
  };
3656
3714
  let t = new URLSearchParams(location.search);
3657
3715
  return {
@@ -3664,9 +3722,9 @@ function er() {
3664
3722
  waitForLive: !0
3665
3723
  };
3666
3724
  }
3667
- async function tr() {
3668
- let e = er();
3669
- rr();
3725
+ async function ar() {
3726
+ let e = ir();
3727
+ sr();
3670
3728
  let t = document.createElement("video");
3671
3729
  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);
3672
3730
  let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
@@ -3721,12 +3779,12 @@ async function tr() {
3721
3779
  code: e.code,
3722
3780
  message: e.message
3723
3781
  })), e.on("autoplayblocked", () => {
3724
- i({ type: "oddin:autoplayblocked" }), nr(t, e);
3782
+ i({ type: "oddin:autoplayblocked" }), or(t, e);
3725
3783
  });
3726
3784
  }, s = async (r) => {
3727
3785
  a?.destroy(), a = null;
3728
3786
  try {
3729
- let n = await Yn({
3787
+ let n = await $n({
3730
3788
  video: t,
3731
3789
  baseUrl: e.baseUrl,
3732
3790
  matchUrn: r,
@@ -3788,7 +3846,7 @@ async function tr() {
3788
3846
  a?.retry();
3789
3847
  break;
3790
3848
  case "oddin:load":
3791
- typeof e.matchUrn == "string" && Qn.test(e.matchUrn) && s(e.matchUrn);
3849
+ typeof e.matchUrn == "string" && nr.test(e.matchUrn) && s(e.matchUrn);
3792
3850
  break;
3793
3851
  case "oddin:destroy": c();
3794
3852
  }
@@ -3800,18 +3858,18 @@ async function tr() {
3800
3858
  protocol: 1
3801
3859
  });
3802
3860
  }
3803
- function nr(e, t) {
3861
+ function or(e, t) {
3804
3862
  if (document.getElementById("havik-tap")) return;
3805
3863
  let n = document.createElement("button");
3806
3864
  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", () => {
3807
3865
  n.remove(), t.play();
3808
3866
  }), document.body.appendChild(n);
3809
3867
  }
3810
- function rr() {
3868
+ function sr() {
3811
3869
  let e = document.createElement("style");
3812
3870
  e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
3813
3871
  }
3814
3872
  //#endregion
3815
- export { wn as ODDIN_THEME, n as PlaybackError, En as applyTheme, Ke as baseUrlForEnv, tr as bootEmbed, Te as clearDeviceId, Yn 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, Zn as mountEmbed, de as pollToLive, y as resolveStream, T as subscribeLiveState, S as videoFullscreenActive, Ce as watchStatus };
3873
+ export { Dn as ODDIN_THEME, n as PlaybackError, kn as applyTheme, Ge as baseUrlForEnv, ar as bootEmbed, Te as clearDeviceId, $n 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, tr as mountEmbed, v as pollToLive, b as resolveStream, T as subscribeLiveState, S as videoFullscreenActive, Ce as watchStatus };
3816
3874
 
3817
3875
  //# sourceMappingURL=index.js.map