@oddin-gg/havik-player 2.15.3 → 2.15.4

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 v(e, t, r) {
177
+ async function de(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 v(e, t, r) {
200
200
  }
201
201
  //#endregion
202
202
  //#region src/core/resolve.ts
203
- async function y(e) {
203
+ async function v(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 de(t);
211
- return me(await t.json(), e.matchUrn);
210
+ if (!t.ok) throw await fe(t);
211
+ return he(await t.json(), e.matchUrn);
212
212
  }
213
- function b(e) {
214
- let t = () => y(e);
215
- return e.waitForLive ? v(t, e.waitForLive, e.signal) : t();
213
+ function y(e) {
214
+ let t = () => v(e);
215
+ return e.waitForLive ? de(t, e.waitForLive, e.signal) : t();
216
216
  }
217
- async function de(e) {
217
+ async function fe(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 de(e) {
230
230
  liveStartsAtMs: s
231
231
  });
232
232
  }
233
- var fe = /* @__PURE__ */ new Set([
233
+ var pe = /* @__PURE__ */ new Set([
234
234
  "matchUrn",
235
235
  "protocol",
236
236
  "drmEnabled",
@@ -241,7 +241,7 @@ var fe = /* @__PURE__ */ new Set([
241
241
  "expiresAt",
242
242
  "analytics"
243
243
  ]);
244
- function x(e, t) {
244
+ function b(e, t) {
245
245
  let r;
246
246
  try {
247
247
  r = new URL(t);
@@ -251,7 +251,7 @@ function x(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 pe(e) {
254
+ function me(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 pe(e) {
260
260
  g(`server analytics.endpoint ${JSON.stringify(e)} ignored: not a bare https origin.`);
261
261
  }
262
262
  }
263
- function me(e, t) {
263
+ function he(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: x("manifestUrl", e.manifestUrl),
269
+ manifestUrl: b("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 = pe(e.analytics.endpoint);
274
+ let t = me(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: 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)
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)
282
282
  }), (t.widevine || t.fairplay) && (i.drm = t);
283
283
  }
284
284
  let a = {};
285
- for (let [t, n] of Object.entries(e)) fe.has(t) || (a[t] = n);
285
+ for (let [t, n] of Object.entries(e)) pe.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 he(e) {
290
+ function ge(e) {
291
291
  return e.ownerDocument ?? document;
292
292
  }
293
- function ge(e) {
293
+ function x(e) {
294
294
  return e.fullscreenElement ?? e.webkitFullscreenElement ?? null;
295
295
  }
296
296
  function S(e, t) {
297
- let n = ge(he(e));
297
+ let n = x(ge(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 = he(e), i = ge(r);
313
+ let r = ge(e), i = x(r);
314
314
  i != null && (i === e || t != null && i === t) && (typeof r.exitFullscreen == "function" ? await r.exitFullscreen() : r.webkitExitFullscreen?.());
315
315
  }
316
316
  //#endregion
@@ -671,14 +671,14 @@ function I(e) {
671
671
  function L(e) {
672
672
  return (e ?? "").trim().toLowerCase();
673
673
  }
674
- var R = {
674
+ var je = {
675
675
  hevc: "hvc1.1.6.L93.90",
676
676
  dv: "dvh1.05.06",
677
677
  av1: "av01.0.05M.08",
678
678
  vp9: "vp09.00.10.08"
679
- }, z = /* @__PURE__ */ new Map(), B = /* @__PURE__ */ new Map();
680
- function V(e) {
681
- let t = L(e), n = z.get(t);
679
+ }, Me = /* @__PURE__ */ new Map(), R = /* @__PURE__ */ new Map();
680
+ function Ne(e) {
681
+ let t = L(e), n = Me.get(t);
682
682
  if (n) return n;
683
683
  let r = {
684
684
  initDataTypes: ["cenc"],
@@ -696,23 +696,23 @@ function V(e) {
696
696
  } catch {
697
697
  return !1;
698
698
  }
699
- })().then((e) => (B.set(t, e), e));
700
- return z.set(t, i), i;
699
+ })().then((e) => (R.set(t, e), e));
700
+ return Me.set(t, i), i;
701
701
  }
702
- function je() {
703
- if (j()) for (let e of Object.values(R)) V(e);
702
+ function Pe() {
703
+ if (j()) for (let e of Object.values(je)) Ne(e);
704
704
  }
705
- function H(e) {
705
+ function Fe(e) {
706
706
  let t = I(e);
707
- if (t) return t === "avc" ? !0 : B.get(L(e)) ?? B.get(L(R[t]));
707
+ if (t) return t === "avc" ? !0 : R.get(L(e)) ?? R.get(L(je[t]));
708
708
  }
709
709
  //#endregion
710
710
  //#region src/core/drm/support.ts
711
- var Me = 5e3, U = "video/mp4; codecs=\"avc1.42E01E\"", Ne = "audio/mp4; codecs=\"mp4a.40.2\"", Pe = {
711
+ var Ie = 5e3, Le = "video/mp4; codecs=\"avc1.42E01E\"", Re = "audio/mp4; codecs=\"mp4a.40.2\"", ze = {
712
712
  widevine: ["com.widevine.alpha"],
713
713
  fairplay: ["com.apple.fps"]
714
714
  };
715
- function Fe(e) {
715
+ function Be(e) {
716
716
  return e === "fairplay" ? [{
717
717
  initDataTypes: [
718
718
  "sinf",
@@ -720,30 +720,30 @@ function Fe(e) {
720
720
  "cenc"
721
721
  ],
722
722
  videoCapabilities: [{
723
- contentType: U,
723
+ contentType: Le,
724
724
  robustness: "",
725
725
  encryptionScheme: "cbcs"
726
726
  }],
727
727
  audioCapabilities: [{
728
- contentType: Ne,
728
+ contentType: Re,
729
729
  robustness: "",
730
730
  encryptionScheme: "cbcs"
731
731
  }]
732
732
  }] : N("com.widevine.alpha", [{
733
733
  initDataTypes: ["cenc"],
734
734
  videoCapabilities: [{
735
- contentType: U,
735
+ contentType: Le,
736
736
  robustness: F.video,
737
737
  encryptionScheme: F.scheme
738
738
  }],
739
739
  audioCapabilities: [{
740
- contentType: Ne,
740
+ contentType: Re,
741
741
  robustness: F.audio,
742
742
  encryptionScheme: F.scheme
743
743
  }]
744
744
  }]);
745
745
  }
746
- function Ie(e, t) {
746
+ function Ve(e, t) {
747
747
  return new Promise((n, r) => {
748
748
  let i = setTimeout(() => r(/* @__PURE__ */ Error("probe-timeout")), t);
749
749
  e.then((e) => {
@@ -753,8 +753,8 @@ function Ie(e, t) {
753
753
  });
754
754
  });
755
755
  }
756
- async function Le(e = {}) {
757
- let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Me, r = {};
756
+ async function He(e = {}) {
757
+ let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Ie, r = {};
758
758
  if (typeof window < "u" && window.isSecureContext === !1) return {
759
759
  verdict: "insecure-context",
760
760
  detail: r
@@ -766,7 +766,7 @@ async function Le(e = {}) {
766
766
  };
767
767
  let a = !1, o = !1, s = Date.now() + n, c = () => Math.max(1, s - Date.now());
768
768
  for (let e of t) {
769
- let t = Pe[e];
769
+ let t = ze[e];
770
770
  if (!t) {
771
771
  r[e] = "unknown system";
772
772
  continue;
@@ -777,7 +777,7 @@ async function Le(e = {}) {
777
777
  break;
778
778
  }
779
779
  try {
780
- return await Ie((await Ie(i(n, Fe(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
780
+ return await Ve((await Ve(i(n, Be(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
781
781
  verdict: "supported",
782
782
  system: e,
783
783
  detail: r
@@ -801,49 +801,49 @@ async function Le(e = {}) {
801
801
  }
802
802
  //#endregion
803
803
  //#region src/core/manifest.ts
804
- var Re = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
805
- function ze(e) {
806
- return Re.test(e);
804
+ var Ue = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
805
+ function We(e) {
806
+ return Ue.test(e);
807
807
  }
808
808
  //#endregion
809
809
  //#region src/core/env.ts
810
- var Be = {
810
+ var z = {
811
811
  integration: "https://feed-dev.oddin-video.gg",
812
812
  production: "https://feed.oddin-video.gg"
813
813
  };
814
- function Ve(e) {
815
- let t = Object.prototype.hasOwnProperty.call(Be, e) ? Be[e] : void 0;
814
+ function B(e) {
815
+ let t = Object.prototype.hasOwnProperty.call(z, e) ? z[e] : void 0;
816
816
  if (!t) throw new n("INTERNAL", 0, `unknown env ${JSON.stringify(e)} — expected 'integration' or 'production'`);
817
817
  return t;
818
818
  }
819
819
  //#endregion
820
820
  //#region src/core/stats.ts
821
- var He = { droppedFrames: 0 };
822
- function Ue(e) {
821
+ var V = { droppedFrames: 0 };
822
+ function H(e) {
823
823
  try {
824
824
  return new URL(e).host;
825
825
  } catch {
826
826
  return "";
827
827
  }
828
828
  }
829
- var We = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
830
- function Ge(e) {
829
+ var Ge = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
830
+ function Ke(e) {
831
831
  if (typeof performance > "u" || typeof performance.getEntriesByType != "function") return "";
832
832
  let t = "", n = -1, r = performance.getEntriesByType("resource");
833
- for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || We.test(i.name)) && i.startTime >= n) {
834
- let e = Ue(i.name);
833
+ for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || Ge.test(i.name)) && i.startTime >= n) {
834
+ let e = H(i.name);
835
835
  e && (t = e, n = i.startTime);
836
836
  }
837
837
  return t;
838
838
  }
839
- function W(e) {
839
+ function U(e) {
840
840
  let t = e.getVideoPlaybackQuality?.();
841
841
  return {
842
842
  dropped: t?.droppedVideoFrames ?? 0,
843
843
  totalFrames: t?.totalVideoFrames ?? 0
844
844
  };
845
845
  }
846
- function Ke(e, t) {
846
+ function qe(e, t) {
847
847
  let n = [
848
848
  ["playing", () => t("playing")],
849
849
  ["waiting", () => t("buffering")],
@@ -860,7 +860,7 @@ function Ke(e, t) {
860
860
  }
861
861
  //#endregion
862
862
  //#region src/core/engine/native.ts
863
- function qe(e) {
863
+ function Je(e) {
864
864
  try {
865
865
  let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
866
866
  return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
@@ -868,10 +868,10 @@ function qe(e) {
868
868
  return;
869
869
  }
870
870
  }
871
- function G(e) {
871
+ function W(e) {
872
872
  return !!(e ?? (typeof document < "u" ? document.createElement("video") : void 0))?.canPlayType("application/vnd.apple.mpegurl");
873
873
  }
874
- function Je() {
874
+ function G() {
875
875
  if (typeof window > "u") return !1;
876
876
  let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
877
877
  return e || t;
@@ -934,7 +934,7 @@ var K = class {
934
934
  });
935
935
  this.onEncrypted = (n) => {
936
936
  let i = n;
937
- i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = qe(i.initData), (async () => {
937
+ i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = Je(i.initData), (async () => {
938
938
  try {
939
939
  let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
940
940
  initDataTypes: [i.initDataType],
@@ -1029,11 +1029,11 @@ var K = class {
1029
1029
  e.seekable.length > 0 && (e.currentTime = e.seekable.end(e.seekable.length - 1));
1030
1030
  }
1031
1031
  getStats() {
1032
- let e = this.deps.video, t = W(e), n = {
1032
+ let e = this.deps.video, t = U(e), n = {
1033
1033
  droppedFrames: t.dropped,
1034
1034
  decodedFrames: t.totalFrames
1035
1035
  };
1036
- return this.cdnHost ||= Ge(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity ? (n.isLive = !0, e.seekable.length > 0 && (n.atLiveEdge = e.currentTime >= e.seekable.end(e.seekable.length - 1) - 2)) : Number.isFinite(e.duration) && e.duration > 0 && (n.isLive = !1), n;
1036
+ return this.cdnHost ||= Ke(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity ? (n.isLive = !0, e.seekable.length > 0 && (n.atLiveEdge = e.currentTime >= e.seekable.end(e.seekable.length - 1) - 2)) : Number.isFinite(e.duration) && e.duration > 0 && (n.isLive = !1), n;
1037
1037
  }
1038
1038
  stop() {
1039
1039
  try {
@@ -1219,21 +1219,21 @@ function it(e, t) {
1219
1219
  function at() {
1220
1220
  return e.isSupported();
1221
1221
  }
1222
- var ot = 3, st = 5, ct = 3, lt = 3e4, ut = 12e3, dt = 3e3, ft = 6e3, pt = 3, mt = .5, ht = 1.1, gt = .25, _t = 5e3, vt = 4e3, yt = 2, bt = 5, xt = 2, St = 2, Ct = 4, wt = 4, Tt = 2e3, Et = 3e4, Dt = .2, Ot = 30, kt = 2, At = 2, jt = 9, Mt = .5, Nt = 64;
1223
- function Pt(e) {
1222
+ var ot = 3, st = 5, ct = 3, lt = 3e4, ut = 12e3, dt = 3e3, ft = 6e3, pt = .5, mt = 3, ht = .5, gt = 1.1, _t = .25, vt = 5e3, yt = 4e3, bt = 2, xt = 5, St = 2, Ct = 2, wt = 4, Tt = 4, Et = 2e3, Dt = 3e4, Ot = .2, kt = 30, At = 2, jt = 2, Mt = 9, Nt = .5, Pt = 64;
1223
+ function Ft(e) {
1224
1224
  if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
1225
1225
  delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
1226
1226
  return;
1227
1227
  }
1228
- e.liveSyncDuration ??= At;
1229
- let t = Math.max(12, e.liveSyncDuration + jt);
1230
- (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), Ft(e, e.liveSyncDuration);
1228
+ e.liveSyncDuration ??= jt;
1229
+ let t = Math.max(12, e.liveSyncDuration + Mt);
1230
+ (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), It(e, e.liveSyncDuration);
1231
1231
  }
1232
- function Ft(e, t) {
1232
+ function It(e, t) {
1233
1233
  let n = (e, t, n) => Math.min(n, Math.max(t, e));
1234
1234
  e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
1235
1235
  }
1236
- var It = class {
1236
+ var Lt = class {
1237
1237
  name = "hls";
1238
1238
  hls = null;
1239
1239
  deps;
@@ -1290,6 +1290,9 @@ var It = class {
1290
1290
  savedLiveMaxLatency;
1291
1291
  savedMaxSyncRate;
1292
1292
  chaseLatency = -1;
1293
+ catchUpRate = 1;
1294
+ catchUpEngaged = !1;
1295
+ onTimeUpdate = null;
1293
1296
  chaseTicks = 0;
1294
1297
  liveRetargets = 0;
1295
1298
  capObserver = null;
@@ -1311,7 +1314,7 @@ var It = class {
1311
1314
  this.deps = e, this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
1312
1315
  }
1313
1316
  async load() {
1314
- let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = G(r) && Je(), o = !!e.drm?.widevine?.licenseUrl && !a;
1317
+ let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = W(r) && G(), o = !!e.drm?.widevine?.licenseUrl && !a;
1315
1318
  if (e.drmEnabled && !o) {
1316
1319
  i({
1317
1320
  type: "error",
@@ -1320,7 +1323,7 @@ var It = class {
1320
1323
  });
1321
1324
  return;
1322
1325
  }
1323
- e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ae(r), je()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1326
+ e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ae(r), Pe()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1324
1327
  let e = this.hls;
1325
1328
  if (document.visibilityState !== "visible" || !e) return;
1326
1329
  let t = e.liveSyncPosition;
@@ -1329,7 +1332,7 @@ var It = class {
1329
1332
  t - r.currentTime > Math.max(n * 3, 8) && (r.currentTime = t);
1330
1333
  }, document.addEventListener("visibilitychange", this.onVisibility)), this.onSeeking = () => {
1331
1334
  this.clampOverSeek(), this.loadSuspended && (this.resumeLoading(), this.schedulePauseSuspend());
1332
- }, r.addEventListener("seeking", this.onSeeking), this.onPause = () => this.schedulePauseSuspend(), this.onPlay = () => this.resumeLoading(), r.addEventListener("pause", this.onPause), r.addEventListener("play", this.onPlay), this.sizeCapManaged && typeof ResizeObserver < "u" && (this.capObserver = new ResizeObserver(() => this.onMediaResize()), this.capObserver.observe(r), this.watchDprChanges());
1335
+ }, r.addEventListener("seeking", this.onSeeking), this.onTimeUpdate = () => this.updateCatchUpBand(), r.addEventListener("timeupdate", this.onTimeUpdate), this.onPause = () => this.schedulePauseSuspend(), this.onPlay = () => this.resumeLoading(), r.addEventListener("pause", this.onPause), r.addEventListener("play", this.onPlay), this.sizeCapManaged && typeof ResizeObserver < "u" && (this.capObserver = new ResizeObserver(() => this.onMediaResize()), this.capObserver.observe(r), this.watchDprChanges());
1333
1336
  }
1334
1337
  schedulePauseSuspend() {
1335
1338
  this.pauseSuspendTimer || this.loadSuspended || this.stopped || !this.loadStarted || (this.pauseSuspendTimer = setTimeout(() => {
@@ -1343,7 +1346,7 @@ var It = class {
1343
1346
  }
1344
1347
  this.loadSuspended = !0;
1345
1348
  }
1346
- }, _t));
1349
+ }, vt));
1347
1350
  }
1348
1351
  resumeLoading() {
1349
1352
  if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
@@ -1375,7 +1378,7 @@ var It = class {
1375
1378
  let t = e.liveSyncPosition;
1376
1379
  if (typeof t != "number" || !Number.isFinite(t)) return;
1377
1380
  let { video: n } = this.deps;
1378
- n.currentTime <= t + Mt || (n.currentTime = t);
1381
+ n.currentTime <= t + Nt || (n.currentTime = t);
1379
1382
  }
1380
1383
  startHls() {
1381
1384
  let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps;
@@ -1422,7 +1425,7 @@ var It = class {
1422
1425
  }), t = tt(e);
1423
1426
  t && (this.prefetch = e, d.fLoader = t);
1424
1427
  }
1425
- Pt(d), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = d.autoStartLoad !== !1;
1428
+ Ft(d), this.catchUpRate = typeof d.maxLiveSyncPlaybackRate == "number" ? d.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (d.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = d.autoStartLoad !== !1;
1426
1429
  let f = new e(d);
1427
1430
  if (this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
1428
1431
  this.mediaRecoveries = 0, this.networkRecoveries = 0, u && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && this.dropLevelsWidevineCannotPlay(f), this.measureLadder(f), this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
@@ -1437,10 +1440,10 @@ var It = class {
1437
1440
  let n = t?.frag?.stats, r = n?.loaded;
1438
1441
  typeof r == "number" && (this.bytesLoaded += r), !this.reportedFirstBytes && typeof r == "number" && r > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
1439
1442
  let i = n?.loading;
1440
- 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 > Nt && this.requestTimesMs.shift());
1443
+ 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 > Pt && this.requestTimesMs.shift());
1441
1444
  let a = t?.frag?.url;
1442
1445
  if (a) {
1443
- let e = Ue(a);
1446
+ let e = H(a);
1444
1447
  e && (this.cdnHost = e);
1445
1448
  }
1446
1449
  }), f.on(e.Events.LEVEL_LOADED, (e, t) => {
@@ -1461,7 +1464,7 @@ var It = class {
1461
1464
  f.on(e.Events.KEY_LOADED, () => {
1462
1465
  u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
1463
1466
  }), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
1464
- this.checkEndStale(), this.checkStarvation(), this.checkFutileChase(), this.checkFrameDrops();
1467
+ this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.checkFrameDrops();
1465
1468
  }, dt), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1466
1469
  this.renditionSwitches += 1;
1467
1470
  let n = this.lastLevelIndex >= 0 ? f.levels[this.lastLevelIndex] : void 0, r = f.levels[t.level];
@@ -1526,7 +1529,7 @@ var It = class {
1526
1529
  return;
1527
1530
  }
1528
1531
  this.capTimer && clearTimeout(this.capTimer);
1529
- let t = e > this.sizeCapLevel ? Tt : Et;
1532
+ let t = e > this.sizeCapLevel ? Et : Dt;
1530
1533
  this.capTimer = setTimeout(() => {
1531
1534
  this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
1532
1535
  }, t);
@@ -1536,9 +1539,9 @@ var It = class {
1536
1539
  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;
1537
1540
  }
1538
1541
  dropLevelsWidevineCannotPlay(e) {
1539
- this.removeLevelsWhere(e, (e) => H(e) !== !0);
1542
+ this.removeLevelsWhere(e, (e) => Fe(e) !== !0);
1540
1543
  let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && I(e) !== "avc" && !!I(e)));
1541
- for (let n of t) V(n).then((t) => {
1544
+ for (let n of t) Ne(n).then((t) => {
1542
1545
  t || this.hls !== e || this.removeLevelsWhere(e, (e) => e === n) && (this.measureLadder(e), this.applySizeCap());
1543
1546
  });
1544
1547
  }
@@ -1549,7 +1552,7 @@ var It = class {
1549
1552
  a && I(a) && t(a) && (r.push(n), i.add(a));
1550
1553
  }), !r.length) return !1;
1551
1554
  let a = [...i].join(", ");
1552
- if (!n.some((e, t) => r.includes(t) ? !1 : !I(e.videoCodec) || H(e.videoCodec) === !0)) return console.warn(`havik-player: every rendition is ${a}, which Widevine may not play on this browser; keeping them`), !1;
1555
+ 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;
1553
1556
  for (let t = r.length - 1; t >= 0; --t) e.removeLevel(r[t]);
1554
1557
  return console.info(`havik-player: skipped ${r.length} rendition(s) Widevine cannot play on this browser (${a})`), !0;
1555
1558
  }
@@ -1599,7 +1602,7 @@ var It = class {
1599
1602
  e.widevine && (this.licenseUrl = e.widevine);
1600
1603
  }
1601
1604
  getStats() {
1602
- let e = this.hls, t = W(this.deps.video), n = {
1605
+ let e = this.hls, t = U(this.deps.video), n = {
1603
1606
  droppedFrames: t.dropped,
1604
1607
  decodedFrames: t.totalFrames,
1605
1608
  lowLatency: this.detectedLowLatency,
@@ -1662,7 +1665,7 @@ var It = class {
1662
1665
  this.resetStarvationWindow();
1663
1666
  return;
1664
1667
  }
1665
- let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < ft, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > vt, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = W(t), c = o - s, l = c !== this.starvedFrames;
1668
+ let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < ft, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > yt, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = U(t), c = o - s, l = c !== this.starvedFrames;
1666
1669
  if (this.starvedFrames = c, !a || l) {
1667
1670
  (t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
1668
1671
  return;
@@ -1671,12 +1674,12 @@ var It = class {
1671
1674
  this.resetStarvationWindow();
1672
1675
  return;
1673
1676
  }
1674
- 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 > Ct && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= xt && (this.clearKick(), this.starvationRebuilds < St)) {
1677
+ 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 > wt && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= St && (this.clearKick(), this.starvationRebuilds < Ct)) {
1675
1678
  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");
1676
1679
  return;
1677
1680
  }
1678
- let u = i && this.starvedTicks >= yt, d = !i && this.deadTicks >= Ct && this.recentMainFrags.reduce((e, t) => e + t, 0) >= wt;
1679
- if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= bt))) {
1681
+ let u = i && this.starvedTicks >= bt, d = !i && this.deadTicks >= wt && this.recentMainFrags.reduce((e, t) => e + t, 0) >= Tt;
1682
+ if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= xt))) {
1680
1683
  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");
1681
1684
  try {
1682
1685
  e.stopLoad(), e.startLoad(-1);
@@ -1685,6 +1688,16 @@ var It = class {
1685
1688
  }
1686
1689
  }
1687
1690
  }
1691
+ updateCatchUpBand() {
1692
+ let e = this.hls;
1693
+ if (!e || this.catchUpRate <= 1 || this.chaseSuspended || this.loadSuspended) return;
1694
+ let t = e.latency, n = e.targetLatency;
1695
+ if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
1696
+ let r = t - n;
1697
+ !this.catchUpEngaged && r > pt ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= pt && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
1698
+ let i = this.catchUpEngaged ? this.catchUpRate : 1;
1699
+ e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
1700
+ }
1688
1701
  fpsCapLevel(e) {
1689
1702
  if (this.fpsCapBitrate == null) return -1;
1690
1703
  let t = this.fpsCapFailedHeight, n = -1;
@@ -1702,16 +1715,16 @@ var It = class {
1702
1715
  this.resetFrameDropWindow();
1703
1716
  return;
1704
1717
  }
1705
- let { totalFrames: n, dropped: r } = W(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
1706
- if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < Ot || o < 0) {
1718
+ let { totalFrames: n, dropped: r } = U(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
1719
+ if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < kt || o < 0) {
1707
1720
  this.fpsBadTicks = 0;
1708
1721
  return;
1709
1722
  }
1710
- if (o <= Dt * a) {
1723
+ if (o <= Ot * a) {
1711
1724
  this.fpsBadTicks = 0;
1712
1725
  return;
1713
1726
  }
1714
- if (this.fpsBadTicks += 1, this.fpsBadTicks < kt) return;
1727
+ if (this.fpsBadTicks += 1, this.fpsBadTicks < At) return;
1715
1728
  this.fpsBadTicks = 0;
1716
1729
  let s = e.levels, c = s[e.currentLevel];
1717
1730
  if (!c) return;
@@ -1728,24 +1741,27 @@ var It = class {
1728
1741
  return;
1729
1742
  }
1730
1743
  let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
1731
- if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(ht, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
1744
+ if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(gt, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
1732
1745
  this.resetChaseWindow();
1733
1746
  return;
1734
1747
  }
1735
- if (this.chaseLatency < 0 || this.chaseLatency - n >= mt) {
1748
+ if (this.chaseLatency < 0 || this.chaseLatency - n >= ht) {
1736
1749
  this.chaseLatency = n, this.chaseTicks = 0;
1737
1750
  return;
1738
1751
  }
1739
- if (this.chaseTicks += 1, this.chaseTicks < pt) return;
1752
+ if (this.chaseTicks += 1, this.chaseTicks < mt) return;
1740
1753
  this.resetChaseWindow();
1741
1754
  let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
1742
1755
  if (!(a > 1)) return;
1743
1756
  let o = typeof e.targetLatency == "number" ? e.targetLatency : 0, s = Math.min(n, a - 1);
1744
- s < o + gt || (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);
1757
+ s < o + _t || (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);
1745
1758
  }
1746
1759
  suspendChasing() {
1747
1760
  let e = this.hls;
1748
- e && (this.chaseSuspended = !0, this.savedLiveMaxLatency = e.config.liveMaxLatencyDuration, this.savedMaxSyncRate = e.config.maxLiveSyncPlaybackRate, e.config.liveMaxLatencyDuration = 2 ** 53 - 1, e.config.maxLiveSyncPlaybackRate = 1);
1761
+ if (!e) return;
1762
+ this.chaseSuspended = !0, this.savedLiveMaxLatency = e.config.liveMaxLatencyDuration, this.savedMaxSyncRate = e.config.maxLiveSyncPlaybackRate, e.config.liveMaxLatencyDuration = 2 ** 53 - 1, e.config.maxLiveSyncPlaybackRate = 1;
1763
+ let { video: t } = this.deps, n = this.savedMaxSyncRate;
1764
+ t.playbackRate > 1 && typeof n == "number" && t.playbackRate <= n && (t.playbackRate = 1);
1749
1765
  }
1750
1766
  resumeChasing() {
1751
1767
  this.chaseSuspended = !1;
@@ -1768,7 +1784,7 @@ var It = class {
1768
1784
  } catch {}
1769
1785
  }
1770
1786
  destroy() {
1771
- if (this.prefetch?.destroy(), this.prefetch = null, this.clearRecoveryReset(), this.capTimer &&= (clearTimeout(this.capTimer), null), this.capObserver &&= (this.capObserver.disconnect(), null), this.unwatchDprChanges(), this.endWatchdog &&= (clearInterval(this.endWatchdog), null), this.onVisibility && typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), this.onVisibility = null), this.onSeeking &&= (this.deps.video.removeEventListener("seeking", this.onSeeking), null), this.onPause &&= (this.deps.video.removeEventListener("pause", this.onPause), null), this.onPlay &&= (this.deps.video.removeEventListener("play", this.onPlay), null), this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null), this.licenseRetryTimer &&= (clearTimeout(this.licenseRetryTimer), null), this.hls) {
1787
+ if (this.prefetch?.destroy(), this.prefetch = null, this.clearRecoveryReset(), this.capTimer &&= (clearTimeout(this.capTimer), null), this.capObserver &&= (this.capObserver.disconnect(), null), this.unwatchDprChanges(), this.endWatchdog &&= (clearInterval(this.endWatchdog), null), this.onVisibility && typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), this.onVisibility = null), this.onSeeking &&= (this.deps.video.removeEventListener("seeking", this.onSeeking), null), this.onTimeUpdate &&= (this.deps.video.removeEventListener("timeupdate", this.onTimeUpdate), null), this.onPause &&= (this.deps.video.removeEventListener("pause", this.onPause), null), this.onPlay &&= (this.deps.video.removeEventListener("play", this.onPlay), null), this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null), this.licenseRetryTimer &&= (clearTimeout(this.licenseRetryTimer), null), this.hls) {
1772
1788
  try {
1773
1789
  this.hls.destroy();
1774
1790
  } catch (e) {
@@ -1856,19 +1872,19 @@ var It = class {
1856
1872
  let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
1857
1873
  return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
1858
1874
  }
1859
- }, Lt = 15e3, Rt = 6e5, zt = 3e5, Bt = 100, q = 1, Vt = 1e3, Ht = 3e4, Ut = 1e3, Wt = {
1875
+ }, Rt = 15e3, zt = 6e5, Bt = 3e5, Vt = 100, q = 1, Ht = 1e3, Ut = 3e4, Wt = 1e3, Gt = {
1860
1876
  inline: "PRESENTATION_INLINE",
1861
1877
  fullscreen: "PRESENTATION_FULLSCREEN",
1862
1878
  pip: "PRESENTATION_PIP"
1863
- }, Gt = {
1879
+ }, Kt = {
1864
1880
  widevine: "KEY_SYSTEM_WIDEVINE",
1865
1881
  fairplay: "KEY_SYSTEM_FAIRPLAY",
1866
1882
  none: "KEY_SYSTEM_NONE"
1867
1883
  };
1868
- function Kt(e, t) {
1884
+ function qt(e, t) {
1869
1885
  return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
1870
1886
  }
1871
- var qt = /* @__PURE__ */ new Set([
1887
+ var Jt = /* @__PURE__ */ new Set([
1872
1888
  "INVALID_URN",
1873
1889
  "NOT_FOUND",
1874
1890
  "GONE",
@@ -1888,7 +1904,7 @@ var qt = /* @__PURE__ */ new Set([
1888
1904
  ended: "PLAYER_STATE_ENDED",
1889
1905
  error: "PLAYER_STATE_ERROR"
1890
1906
  };
1891
- function Jt(e) {
1907
+ function Yt(e) {
1892
1908
  try {
1893
1909
  let t = new URL(e), [n, ...r] = t.hostname.split(".");
1894
1910
  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);
@@ -1896,8 +1912,8 @@ function Jt(e) {
1896
1912
  return;
1897
1913
  }
1898
1914
  }
1899
- var Yt = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), Xt = /* @__PURE__ */ new Set(), Y = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), Zt = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
1900
- function Qt(e) {
1915
+ var Xt = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), Zt = /* @__PURE__ */ new Set(), Y = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), Qt = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
1916
+ function $t(e) {
1901
1917
  if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
1902
1918
  let t;
1903
1919
  try {
@@ -1906,19 +1922,19 @@ function Qt(e) {
1906
1922
  } catch {
1907
1923
  return;
1908
1924
  }
1909
- if (Xt.has(t) && !Y.has(t)) {
1910
- Y.add(t), g(Zt(new URL(t).origin));
1925
+ if (Zt.has(t) && !Y.has(t)) {
1926
+ Y.add(t), g(Qt(new URL(t).origin));
1911
1927
  for (let e of X) e.noteCspBlocked();
1912
1928
  }
1913
1929
  }
1914
- function $t(e, t) {
1930
+ function en(e, t) {
1915
1931
  return g(t, e), { disabledReason: t };
1916
1932
  }
1917
- function en(e, t, n) {
1918
- if (n) return t && !Yt(t, n) && g(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
1933
+ function tn(e, t, n) {
1934
+ if (n) return t && !Xt(t, n) && g(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
1919
1935
  if (t) return { endpoint: t };
1920
- if (t !== void 0) return $t("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).");
1921
- let r = Jt(e);
1936
+ if (t !== void 0) return en("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).");
1937
+ let r = Yt(e);
1922
1938
  if (r) return { endpoint: r };
1923
1939
  let i;
1924
1940
  try {
@@ -1926,9 +1942,9 @@ function en(e, t, n) {
1926
1942
  } catch {
1927
1943
  i = e;
1928
1944
  }
1929
- return $t(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).`);
1945
+ return en(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).`);
1930
1946
  }
1931
- var tn = class {
1947
+ var nn = class {
1932
1948
  opts;
1933
1949
  url;
1934
1950
  cspKey;
@@ -2010,8 +2026,8 @@ var tn = class {
2010
2026
  constructor(e) {
2011
2027
  this.opts = {
2012
2028
  ...e,
2013
- heartbeatMs: e.heartbeatMs ?? Lt,
2014
- idleMs: e.idleMs ?? Rt
2029
+ heartbeatMs: e.heartbeatMs ?? Rt,
2030
+ idleMs: e.idleMs ?? zt
2015
2031
  }, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
2016
2032
  try {
2017
2033
  let e = new URL(this.url);
@@ -2028,11 +2044,11 @@ var tn = class {
2028
2044
  sdkVersion: this.opts.sdkVersion,
2029
2045
  ...this.opts.environment
2030
2046
  };
2031
- this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Vt), 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 && Xt.add(this.cspKey), document.addEventListener("securitypolicyviolation", Qt), X.add(this), this.noteCspBlocked(), this.onVisibility());
2047
+ this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Ht), 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 && Zt.add(this.cspKey), document.addEventListener("securitypolicyviolation", $t), X.add(this), this.noteCspBlocked(), this.onVisibility());
2032
2048
  }
2033
2049
  checkSuspension(e) {
2034
2050
  if (this.endedFlag || !this.opts.idleMs) return !1;
2035
- let t = Math.max(this.opts.idleMs, zt);
2051
+ let t = Math.max(this.opts.idleMs, Bt);
2036
2052
  return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
2037
2053
  }
2038
2054
  syncIdle(e) {
@@ -2055,12 +2071,12 @@ var tn = class {
2055
2071
  let a = {
2056
2072
  fromState: J[e] ?? "PLAYER_STATE_UNSPECIFIED",
2057
2073
  toState: J[t] ?? "PLAYER_STATE_UNSPECIFIED",
2058
- presentation: Wt[this.presentation]
2074
+ presentation: Gt[this.presentation]
2059
2075
  }, o = this.causeOf(e, t, i);
2060
2076
  o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
2061
2077
  }
2062
2078
  seekInduced(e) {
2063
- return this.lastSeekMs >= 0 && e - this.lastSeekMs < Ut;
2079
+ return this.lastSeekMs >= 0 && e - this.lastSeekMs < Wt;
2064
2080
  }
2065
2081
  causeOf(e, t, n) {
2066
2082
  if (t === "error") return "TRANSITION_CAUSE_ERROR";
@@ -2134,7 +2150,7 @@ var tn = class {
2134
2150
  let r = n ?? "";
2135
2151
  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";
2136
2152
  if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
2137
- if (qt.has(e)) return "ERROR_STAGE_RESOLVE";
2153
+ if (Jt.has(e)) return "ERROR_STAGE_RESOLVE";
2138
2154
  let i = t ?? "";
2139
2155
  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";
2140
2156
  }
@@ -2181,14 +2197,14 @@ var tn = class {
2181
2197
  if (this.lastRequestCount = g, _ > 0) {
2182
2198
  o.requestCountDelta = _;
2183
2199
  let e = t.requestTimesMs ?? [], n = e.slice(Math.max(0, e.length - _)).sort((e, t) => e - t);
2184
- n.length > 0 && (o.requestTimeP50Ms = Kt(n, 50), o.requestTimeP95Ms = Kt(n, 95));
2200
+ n.length > 0 && (o.requestTimeP50Ms = qt(n, 50), o.requestTimeP95Ms = qt(n, 95));
2185
2201
  }
2186
2202
  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();
2187
2203
  }
2188
2204
  maybeEmitMediaInfo(e) {
2189
2205
  if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
2190
2206
  let t = {};
2191
- e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = Gt[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);
2207
+ e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = Kt[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);
2192
2208
  let n = JSON.stringify(t);
2193
2209
  n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
2194
2210
  }
@@ -2208,7 +2224,7 @@ var tn = class {
2208
2224
  let c = r?.positionMs ?? 0;
2209
2225
  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));
2210
2226
  let l = e !== "END_REASON_ENDED";
2211
- l && this.lastStallMs > 0 && n - this.lastStallMs <= Ht && (i.abandonAfterStallMs = Math.max(q, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= Ht && (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);
2227
+ l && this.lastStallMs > 0 && n - this.lastStallMs <= Ut && (i.abandonAfterStallMs = Math.max(q, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= Ut && (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);
2212
2228
  let u = r?.decodedFrames ?? this.lastDecoded;
2213
2229
  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");
2214
2230
  }
@@ -2228,13 +2244,13 @@ var tn = class {
2228
2244
  };
2229
2245
  }
2230
2246
  noteCspBlocked() {
2231
- this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(Zt(new URL(this.url).origin)));
2247
+ this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(Qt(new URL(this.url).origin)));
2232
2248
  }
2233
2249
  cspBlocked() {
2234
2250
  return !!this.cspKey && Y.has(this.cspKey);
2235
2251
  }
2236
2252
  enqueue(e) {
2237
- if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > Bt;) {
2253
+ if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > Vt;) {
2238
2254
  let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
2239
2255
  this.pending.splice(e >= 0 ? e : 0, 1);
2240
2256
  }
@@ -2261,7 +2277,7 @@ var tn = class {
2261
2277
  };
2262
2278
  //#endregion
2263
2279
  //#region src/core/environment.ts
2264
- function nn() {
2280
+ function rn() {
2265
2281
  if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
2266
2282
  let e;
2267
2283
  try {
@@ -2286,14 +2302,14 @@ function nn() {
2286
2302
  integration: "INTEGRATION_KIND_IFRAME"
2287
2303
  };
2288
2304
  }
2289
- function rn() {
2305
+ function an() {
2290
2306
  if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
2291
2307
  let e = navigator.userAgentData, t = e?.platform ?? "";
2292
2308
  if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
2293
2309
  let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
2294
2310
  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";
2295
2311
  }
2296
- function an() {
2312
+ function on() {
2297
2313
  let e = typeof navigator < "u" ? navigator.connection : void 0;
2298
2314
  if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
2299
2315
  let t = {
@@ -2312,17 +2328,17 @@ function an() {
2312
2328
  }
2313
2329
  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;
2314
2330
  }
2315
- function on(e) {
2316
- let t = nn(), n = {
2317
- deviceClass: rn(),
2331
+ function sn(e) {
2332
+ let t = rn(), n = {
2333
+ deviceClass: an(),
2318
2334
  integration: t.integration,
2319
- ...an()
2335
+ ...on()
2320
2336
  };
2321
2337
  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);
2322
2338
  let r = e.getBoundingClientRect?.();
2323
2339
  return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
2324
2340
  }
2325
- async function sn() {
2341
+ async function cn() {
2326
2342
  let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
2327
2343
  if (!e?.getHighEntropyValues) return {};
2328
2344
  try {
@@ -2334,7 +2350,7 @@ async function sn() {
2334
2350
  }
2335
2351
  //#endregion
2336
2352
  //#region src/core/version.ts
2337
- var cn = "2.15.3", ln = {
2353
+ var ln = "2.15.4", un = {
2338
2354
  accent: "#E1B600",
2339
2355
  accentText: "#1B1C23",
2340
2356
  background: "#0e0f13",
@@ -2345,7 +2361,7 @@ var cn = "2.15.3", ln = {
2345
2361
  border: "rgba(255, 255, 255, 0.1)",
2346
2362
  radius: "8px",
2347
2363
  fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
2348
- }, un = {
2364
+ }, dn = {
2349
2365
  accent: "--havik-accent",
2350
2366
  accentText: "--havik-accent-text",
2351
2367
  background: "--havik-bg",
@@ -2357,22 +2373,22 @@ var cn = "2.15.3", ln = {
2357
2373
  radius: "--havik-radius",
2358
2374
  fontFamily: "--havik-font"
2359
2375
  };
2360
- function dn(e, t) {
2376
+ function fn(e, t) {
2361
2377
  let n = {
2362
- ...ln,
2378
+ ...un,
2363
2379
  ...t
2364
2380
  };
2365
- for (let t of Object.keys(un)) e.style.setProperty(un[t], n[t]);
2381
+ for (let t of Object.keys(dn)) e.style.setProperty(dn[t], n[t]);
2366
2382
  n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
2367
2383
  }
2368
2384
  //#endregion
2369
2385
  //#region src/ui/styles.ts
2370
- var fn = "havik-player-styles", pn = "\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();
2386
+ var pn = "havik-player-styles", mn = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer;\n touch-action:manipulation}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n/* Absolutely centred, NOT a flex sibling of .havik-center: the hidden center\n button (.havik-gone) still occupies its 74px in the row, which pushed an\n in-flow spinner 37px right of centre. */\n.havik-spinner{position:absolute;inset:0;margin:auto;width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n/* A status card carries its own logo — the corner watermark would duplicate it. */\n.havik-player.havik-has-status .havik-watermark{display:none}\n\n.havik-bar{position:absolute;left:0;right:0;bottom:0;padding:0 12px 8px;\n opacity:1;transition:opacity .25s;z-index:2}\n.havik-seek{position:relative;height:16px;display:flex;align-items:center;cursor:pointer;margin-bottom:2px}\n.havik-seek__track{position:relative;width:100%;height:4px;border-radius:3px;background:rgba(255,255,255,.25)}\n.havik-seek__buffered{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:rgba(255,255,255,.4)}\n.havik-seek__played{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-seek__thumb{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;\n background:var(--havik-accent,#E1B600);transform:translate(-50%,-50%) scale(0);transition:transform .1s}\n.havik-seek:hover .havik-seek__thumb{transform:translate(-50%,-50%) scale(1)}\n\n.havik-controls{display:flex;align-items:center;gap:6px;height:40px}\n.havik-spacer{flex:1}\n.havik-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;border-radius:var(--havik-radius,8px);\n padding:0;transition:background .12s,color .12s}\n.havik-btn:hover{background:rgba(255,255,255,.12)}\n.havik-btn:focus-visible{outline:2px solid var(--havik-accent,#E1B600);outline-offset:1px}\n.havik-btn svg{width:22px;height:22px}\n\n/* The volume level is filled in accent up to the thumb, like the seek bar's\n played span — a native range input paints no \"elapsed\" side, which left the\n level readable only from the dot's position. --havik-vol (0..1) is set by\n syncVolume(); the track width and thumb size live here as variables because\n the WebKit fill has to compute the thumb centre from both. */\n.havik-vol{display:flex;align-items:center}\n.havik-vol__slider{--havik-vol-w:70px;--havik-vol-thumb:12px;--havik-vol:1;\n --havik-vol-pos:calc(var(--havik-vol-thumb) / 2 + var(--havik-vol) * (var(--havik-vol-w) - var(--havik-vol-thumb)));\n width:0;opacity:0;transition:width .18s,opacity .18s;height:4px;cursor:pointer;\n appearance:none;-webkit-appearance:none;background:transparent;border-radius:3px;margin:0 4px}\n.havik-vol:hover .havik-vol__slider,.havik-vol:focus-within .havik-vol__slider{width:var(--havik-vol-w);opacity:1}\n/* WebKit/Blink have no progress pseudo-element: paint the fill as a hard-stop\n gradient that ends at the thumb centre. */\n.havik-vol__slider::-webkit-slider-runnable-track{height:4px;border-radius:3px;\n background:linear-gradient(to right,var(--havik-accent,#E1B600) var(--havik-vol-pos),\n rgba(255,255,255,.3) var(--havik-vol-pos))}\n/* Firefox fills natively, and tracks the thumb exactly. */\n.havik-vol__slider::-moz-range-track{height:4px;border-radius:3px;background:rgba(255,255,255,.3)}\n.havik-vol__slider::-moz-range-progress{height:4px;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-vol__slider::-webkit-slider-thumb{-webkit-appearance:none;width:var(--havik-vol-thumb);\n height:var(--havik-vol-thumb);border-radius:50%;background:var(--havik-accent,#E1B600);\n margin-top:calc((4px - var(--havik-vol-thumb)) / 2)}\n.havik-vol__slider::-moz-range-thumb{width:var(--havik-vol-thumb);height:var(--havik-vol-thumb);\n border:0;border-radius:50%;background:var(--havik-accent,#E1B600)}\n\n.havik-time{font-size:12px;color:var(--havik-text-muted,#9aa0ad);\n font-variant-numeric:tabular-nums;padding:0 6px;white-space:nowrap}\n.havik-live{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;\n letter-spacing:.4px;padding:0 8px;color:var(--havik-text,#fff)}\n.havik-live svg{width:9px;height:9px;color:var(--havik-text-muted,#9aa0ad)}\n.havik-live.is-live svg{color:var(--havik-accent,#E1B600)}\n.havik-live__go{margin-left:2px;border:0;cursor:pointer;background:transparent;color:var(--havik-text-muted,#9aa0ad);\n font:inherit;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:6px}\n.havik-live.is-live .havik-live__go{display:none}\n.havik-live__go:hover{color:var(--havik-accent,#E1B600)}\n\n.havik-menu{position:absolute;bottom:54px;right:12px;min-width:170px;max-height:230px;overflow:auto;\n background:var(--havik-surface,#1B1C23);border:1px solid var(--havik-border,rgba(255,255,255,.1));\n border-radius:var(--havik-radius,8px);box-shadow:0 10px 30px rgba(0,0,0,.5);padding:6px;z-index:3}\n.havik-menu[hidden]{display:none}\n.havik-menu__title{font-size:11px;text-transform:uppercase;letter-spacing:.6px;\n color:var(--havik-text-muted,#9aa0ad);padding:6px 8px 4px}\n.havik-menu__item{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;font:inherit;font-size:13px;\n text-align:left;padding:7px 8px;border-radius:6px}\n.havik-menu__item:hover{background:var(--havik-surface-muted,#2a2c36)}\n.havik-menu__item[aria-checked=\"true\"]{color:var(--havik-accent,#E1B600);font-weight:600}\n.havik-menu__item[aria-checked=\"true\"]::after{content:'✓'}\n", Z = /* @__PURE__ */ new WeakMap();
2371
2387
  function hn(e = document, t) {
2372
- let n = e.querySelector(`style#${fn}`);
2373
- if (n && (!t || mn.get(n) === t)) return;
2388
+ let n = e.querySelector(`style#${pn}`);
2389
+ if (n && (!t || Z.get(n) === t)) return;
2374
2390
  let r = e.createElement("style");
2375
- r.id = fn, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = pn, mn.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
2391
+ r.id = pn, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = mn, Z.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
2376
2392
  }
2377
2393
  //#endregion
2378
2394
  //#region src/ui/icons.ts
@@ -2389,7 +2405,7 @@ var gn = {
2389
2405
  liveDot: "<circle cx=\"12\" cy=\"12\" r=\"6\"/>",
2390
2406
  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\"/>"
2391
2407
  };
2392
- function Z(e) {
2408
+ function Q(e) {
2393
2409
  return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${gn[e]}</svg>`;
2394
2410
  }
2395
2411
  //#endregion
@@ -2460,12 +2476,12 @@ var xn = class {
2460
2476
  "aria-label": r,
2461
2477
  title: r
2462
2478
  });
2463
- return i.innerHTML = Z(n), i;
2479
+ return i.innerHTML = Q(n), i;
2464
2480
  };
2465
2481
  this.overlay = t("div", "havik-overlay"), this.center = t("button", "havik-center", {
2466
2482
  type: "button",
2467
2483
  "aria-label": "Play"
2468
- }), this.center.innerHTML = Z("play"), this.spinner = t("div", "havik-spinner"), this.spinner.style.display = "none", this.overlay.append(this.center, this.spinner), this.gradient = t("div", "havik-gradient"), this.bar = t("div", "havik-bar"), this.seek = t("div", "havik-seek", {
2484
+ }), this.center.innerHTML = Q("play"), this.spinner = t("div", "havik-spinner"), this.spinner.style.display = "none", this.overlay.append(this.center, this.spinner), this.gradient = t("div", "havik-gradient"), this.bar = t("div", "havik-bar"), this.seek = t("div", "havik-seek", {
2469
2485
  role: "slider",
2470
2486
  "aria-label": "Seek",
2471
2487
  "aria-valuemin": "0",
@@ -2483,7 +2499,7 @@ var xn = class {
2483
2499
  "aria-label": "Volume"
2484
2500
  });
2485
2501
  let a = t("div", "havik-vol");
2486
- a.append(this.muteBtn, this.volSlider), this.live = t("div", "havik-live"), this.live.innerHTML = Z("liveDot");
2502
+ a.append(this.muteBtn, this.volSlider), this.live = t("div", "havik-live"), this.live.innerHTML = Q("liveDot");
2487
2503
  let o = this.doc.createElement("span");
2488
2504
  o.textContent = "LIVE", this.liveGo = t("button", "havik-live__go", { type: "button" }), this.liveGo.textContent = "Go live", this.live.append(o, this.liveGo), this.time = t("div", "havik-time"), this.time.textContent = "0:00", this.time.style.display = "none";
2489
2505
  let s = t("div", "havik-spacer");
@@ -2567,12 +2583,12 @@ var xn = class {
2567
2583
  }
2568
2584
  if (e === "preplay") {
2569
2585
  let e = this.doc.createElement("button");
2570
- e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML = Z("play"), e.addEventListener("click", () => void this.player.play()), n.append(e);
2586
+ 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);
2571
2587
  } else {
2572
2588
  let r = this.doc.createElement("div");
2573
2589
  if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !yn.has(this.lastError.code)) {
2574
2590
  let e = this.doc.createElement("button");
2575
- e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${Z("retry")}<span>Retry</span>`, e.addEventListener("click", () => void this.player.retry()), n.append(e);
2591
+ 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);
2576
2592
  }
2577
2593
  }
2578
2594
  this.root.append(n), this.statusBox = n, this.show();
@@ -2755,7 +2771,7 @@ var xn = class {
2755
2771
  }
2756
2772
  }
2757
2773
  setIcon(e, t) {
2758
- e.innerHTML = Z(t);
2774
+ e.innerHTML = Q(t);
2759
2775
  }
2760
2776
  destroy() {
2761
2777
  this.hideTimer && clearTimeout(this.hideTimer), this.tapTimer && clearTimeout(this.tapTimer);
@@ -2788,25 +2804,25 @@ function Tn(e) {
2788
2804
  }
2789
2805
  //#endregion
2790
2806
  //#region src/managed/index.ts
2791
- var En = 6e3, Dn = 45e3, Q = 2e3, On = 3, kn = 2e3, An = 48e4;
2792
- function jn(e) {
2807
+ var En = 6e3, Dn = 45e3, On = 2e3, kn = 3, An = 2e3, jn = 48e4;
2808
+ function Mn(e) {
2793
2809
  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)})`);
2794
- if (e.env !== void 0) return Ve(e.env);
2810
+ if (e.env !== void 0) return B(e.env);
2795
2811
  if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
2796
2812
  return e.baseUrl;
2797
2813
  }
2798
- async function Mn(e) {
2814
+ async function Nn(e) {
2799
2815
  if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
2800
- let t = jn(e);
2816
+ let t = Mn(e);
2801
2817
  if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
2802
2818
  if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
2803
- let r = new Nn({
2819
+ let r = new Pn({
2804
2820
  ...e,
2805
2821
  baseUrl: t
2806
2822
  });
2807
2823
  return await r.start(), r;
2808
2824
  }
2809
- var Nn = class {
2825
+ var Pn = class {
2810
2826
  opts;
2811
2827
  abort = new AbortController();
2812
2828
  listeners = {};
@@ -2850,7 +2866,7 @@ var Nn = class {
2850
2866
  this.opts.muted && (this.opts.video.muted = !0), this.opts.poster && (this.opts.video.poster = this.opts.poster), this.mountControls(), this.attachPipListeners(), this.setState("loading");
2851
2867
  let e = ++this.loadGen, t = this.resolveOptions();
2852
2868
  try {
2853
- let n = await y(t);
2869
+ let n = await v(t);
2854
2870
  if (await this.onResolved(n, e), e === this.loadGen && this._state === "error" && this._lastError) {
2855
2871
  let e = this._lastError;
2856
2872
  throw this.destroy(), e;
@@ -2877,7 +2893,7 @@ var Nn = class {
2877
2893
  r ? this.armWithSse(e, r, t, n) : this.beginArmingByPolling(e);
2878
2894
  }
2879
2895
  beginArmingByPolling(e) {
2880
- b({
2896
+ y({
2881
2897
  ...this.resolveOptions(),
2882
2898
  signal: this.abort.signal,
2883
2899
  waitForLive: this.buildWaitConfig(e)
@@ -2911,7 +2927,7 @@ var Nn = class {
2911
2927
  }
2912
2928
  }
2913
2929
  }, h = () => {
2914
- a || s || p() || (s = !0, b({
2930
+ a || s || p() || (s = !0, y({
2915
2931
  ...this.resolveOptions(),
2916
2932
  signal: c.signal,
2917
2933
  waitForLive: this.buildWaitConfig(e)
@@ -2919,7 +2935,7 @@ var Nn = class {
2919
2935
  a || p() || c.signal.aborted || (a = !0, this.closeArming(), this.fail(e instanceof n ? e : new n("INTERNAL", 0, String(e))));
2920
2936
  }));
2921
2937
  }, g = () => {
2922
- a || p() || y(this.resolveOptions()).then((e) => m(e)).catch((e) => {
2938
+ a || p() || v(this.resolveOptions()).then((e) => m(e)).catch((e) => {
2923
2939
  if (!(a || p())) {
2924
2940
  if (e instanceof n && o(e.code)) {
2925
2941
  h();
@@ -2939,7 +2955,7 @@ var Nn = class {
2939
2955
  credential: this.opts.credential,
2940
2956
  onAlive: () => _(Dn),
2941
2957
  onState: (e) => {
2942
- a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Q);
2958
+ a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * On);
2943
2959
  },
2944
2960
  onError: () => h()
2945
2961
  });
@@ -2962,7 +2978,7 @@ var Nn = class {
2962
2978
  let n = await s(this.opts.credential);
2963
2979
  if (this.destroyed || t !== this.loadGen) return;
2964
2980
  this.setState("loading");
2965
- let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = Ke(this.opts.video, (e) => {
2981
+ let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = qe(this.opts.video, (e) => {
2966
2982
  this._state !== "ended" && this._state !== "error" && this.setState(e);
2967
2983
  });
2968
2984
  if (await i.load(), this.destroyed || t !== this.loadGen) {
@@ -2984,26 +3000,26 @@ var Nn = class {
2984
3000
  if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
2985
3001
  let i = e.analytics?.sid;
2986
3002
  if (!i) return;
2987
- let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = en(this.opts.baseUrl, a, e.analytics?.endpoint);
3003
+ let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = tn(this.opts.baseUrl, a, e.analytics?.endpoint);
2988
3004
  if (!o) {
2989
3005
  s && setTimeout(() => {
2990
3006
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
2991
3007
  }, 0);
2992
3008
  return;
2993
3009
  }
2994
- let c = this.opts.video, l = new tn({
3010
+ let c = this.opts.video, l = new nn({
2995
3011
  endpoint: o,
2996
3012
  sid: i,
2997
3013
  player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
2998
- sdkVersion: cn,
2999
- environment: on(c),
3014
+ sdkVersion: ln,
3015
+ environment: sn(c),
3000
3016
  idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
3001
3017
  onIdle: () => this.onAnalyticsIdle(t),
3002
3018
  onBlocked: (e) => setTimeout(() => {
3003
3019
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, e));
3004
3020
  }, 0),
3005
3021
  sample: () => {
3006
- let e = this.engine?.getStats() ?? He, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
3022
+ let e = this.engine?.getStats() ?? V, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
3007
3023
  return {
3008
3024
  ...e,
3009
3025
  bufferedMs: Math.round(t * 1e3),
@@ -3017,7 +3033,7 @@ var Nn = class {
3017
3033
  let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
3018
3034
  c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
3019
3035
  c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
3020
- }, 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");
3036
+ }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), cn().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
3021
3037
  }
3022
3038
  currentPresentation() {
3023
3039
  let e = this.opts.video;
@@ -3043,10 +3059,10 @@ var Nn = class {
3043
3059
  emit: (e) => this.onEngineEvent(e)
3044
3060
  }, o = this.opts.engine ?? "auto";
3045
3061
  if (o === "native") return new K(a);
3046
- if (o === "hls") return new It(a);
3047
- if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && G(this.opts.video) && Je()) return new K(a);
3048
- if (at()) return new It(a);
3049
- if (G(this.opts.video)) return new K(a);
3062
+ if (o === "hls") return new Lt(a);
3063
+ if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && W(this.opts.video) && G()) return new K(a);
3064
+ if (at()) return new Lt(a);
3065
+ if (W(this.opts.video)) return new K(a);
3050
3066
  throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
3051
3067
  }
3052
3068
  onEngineEvent(e) {
@@ -3098,7 +3114,7 @@ var Nn = class {
3098
3114
  r = 0, i = !1;
3099
3115
  },
3100
3116
  onError: () => {
3101
- this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= On && (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.`))));
3117
+ this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= kn && (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.`))));
3102
3118
  }
3103
3119
  });
3104
3120
  }
@@ -3120,7 +3136,7 @@ var Nn = class {
3120
3136
  scheduleRejoin(e) {
3121
3137
  this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
3122
3138
  this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
3123
- }, Math.random() * Q));
3139
+ }, Math.random() * On));
3124
3140
  }
3125
3141
  cancelRejoin() {
3126
3142
  this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
@@ -3144,7 +3160,7 @@ var Nn = class {
3144
3160
  }
3145
3161
  t.controls = !1;
3146
3162
  let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
3147
- r && r.insertBefore(n, t), n.appendChild(t), dn(n, this.opts.theme), this.container = n, this.controlBar = bn({
3163
+ r && r.insertBefore(n, t), n.appendChild(t), fn(n, this.opts.theme), this.container = n, this.controlBar = bn({
3148
3164
  root: n,
3149
3165
  video: t,
3150
3166
  player: this,
@@ -3175,7 +3191,7 @@ var Nn = class {
3175
3191
  }
3176
3192
  startStats() {
3177
3193
  this.stopStats();
3178
- let e = Math.max(500, this.opts.statsIntervalMs ?? kn);
3194
+ let e = Math.max(500, this.opts.statsIntervalMs ?? An);
3179
3195
  this.statsTimer = setInterval(() => {
3180
3196
  if (!this.engine) return;
3181
3197
  let e = this.engine.getStats();
@@ -3187,7 +3203,7 @@ var Nn = class {
3187
3203
  }
3188
3204
  scheduleLicenseRefresh() {
3189
3205
  this.stopRefresh();
3190
- let e = this.opts.licenseRefreshMs ?? An;
3206
+ let e = this.opts.licenseRefreshMs ?? jn;
3191
3207
  e && this._descriptor?.drmEnabled && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
3192
3208
  }
3193
3209
  stopRefresh() {
@@ -3196,7 +3212,7 @@ var Nn = class {
3196
3212
  async refreshLicense() {
3197
3213
  let e = this.engine;
3198
3214
  if (!this.destroyed && e) try {
3199
- let t = await y(this.resolveOptions());
3215
+ let t = await v(this.resolveOptions());
3200
3216
  if (this.destroyed || this.engine !== e) return;
3201
3217
  let n = t.drm?.widevine?.licenseUrl, r = t.drm?.fairplay?.licenseUrl;
3202
3218
  (n || r) && (e.setLicenseUrls({
@@ -3232,7 +3248,7 @@ var Nn = class {
3232
3248
  this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
3233
3249
  }
3234
3250
  getStats() {
3235
- return this.engine?.getStats() ?? He;
3251
+ return this.engine?.getStats() ?? V;
3236
3252
  }
3237
3253
  getQualityLevels() {
3238
3254
  return this.engine?.getQualityLevels() ?? [];
@@ -3284,7 +3300,7 @@ var Nn = class {
3284
3300
  let e = ++this.loadGen;
3285
3301
  this.teardownPlayback();
3286
3302
  try {
3287
- let t = await b({
3303
+ let t = await y({
3288
3304
  ...this.resolveOptions(),
3289
3305
  waitForLive: this.opts.waitForLive ? this.buildWaitConfig(e) : void 0
3290
3306
  });
@@ -3342,7 +3358,7 @@ function $(e) {
3342
3358
  }
3343
3359
  //#endregion
3344
3360
  //#region src/embed/host.ts
3345
- function Pn(e) {
3361
+ function Fn(e) {
3346
3362
  if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
3347
3363
  if (!e.src) throw Error("mountEmbed: opts.src is required");
3348
3364
  if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
@@ -3401,15 +3417,15 @@ function Pn(e) {
3401
3417
  }
3402
3418
  //#endregion
3403
3419
  //#region src/embed/page.ts
3404
- var Fn = /^[A-Za-z0-9:_.-]{1,128}$/;
3405
- function In(e) {
3420
+ var In = /^[A-Za-z0-9:_.-]{1,128}$/;
3421
+ function Ln(e) {
3406
3422
  if (typeof e == "boolean") return e;
3407
3423
  if (typeof e == "object" && e) {
3408
3424
  let t = e.endpoint;
3409
3425
  return typeof t == "string" ? { endpoint: t } : {};
3410
3426
  }
3411
3427
  }
3412
- function Ln() {
3428
+ function Rn() {
3413
3429
  let e = window.HAVIK_EMBED_CONFIG;
3414
3430
  if (e) return {
3415
3431
  baseUrl: e.baseUrl ?? "",
@@ -3419,7 +3435,7 @@ function Ln() {
3419
3435
  autoplay: e.autoplay ?? !0,
3420
3436
  muted: e.muted ?? !0,
3421
3437
  waitForLive: e.waitForLive ?? !0,
3422
- analytics: In(e.analytics)
3438
+ analytics: Ln(e.analytics)
3423
3439
  };
3424
3440
  let t = new URLSearchParams(location.search);
3425
3441
  return {
@@ -3432,9 +3448,9 @@ function Ln() {
3432
3448
  waitForLive: !0
3433
3449
  };
3434
3450
  }
3435
- async function Rn() {
3436
- let e = Ln();
3437
- Bn();
3451
+ async function zn() {
3452
+ let e = Rn();
3453
+ Vn();
3438
3454
  let t = document.createElement("video");
3439
3455
  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);
3440
3456
  let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
@@ -3489,12 +3505,12 @@ async function Rn() {
3489
3505
  code: e.code,
3490
3506
  message: e.message
3491
3507
  })), e.on("autoplayblocked", () => {
3492
- i({ type: "oddin:autoplayblocked" }), zn(t, e);
3508
+ i({ type: "oddin:autoplayblocked" }), Bn(t, e);
3493
3509
  });
3494
3510
  }, s = async (r) => {
3495
3511
  a?.destroy(), a = null;
3496
3512
  try {
3497
- let n = await Mn({
3513
+ let n = await Nn({
3498
3514
  video: t,
3499
3515
  baseUrl: e.baseUrl,
3500
3516
  matchUrn: r,
@@ -3556,7 +3572,7 @@ async function Rn() {
3556
3572
  a?.retry();
3557
3573
  break;
3558
3574
  case "oddin:load":
3559
- typeof e.matchUrn == "string" && Fn.test(e.matchUrn) && s(e.matchUrn);
3575
+ typeof e.matchUrn == "string" && In.test(e.matchUrn) && s(e.matchUrn);
3560
3576
  break;
3561
3577
  case "oddin:destroy": c();
3562
3578
  }
@@ -3568,18 +3584,18 @@ async function Rn() {
3568
3584
  protocol: 1
3569
3585
  });
3570
3586
  }
3571
- function zn(e, t) {
3587
+ function Bn(e, t) {
3572
3588
  if (document.getElementById("havik-tap")) return;
3573
3589
  let n = document.createElement("button");
3574
3590
  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", () => {
3575
3591
  n.remove(), t.play();
3576
3592
  }), document.body.appendChild(n);
3577
3593
  }
3578
- function Bn() {
3594
+ function Vn() {
3579
3595
  let e = document.createElement("style");
3580
3596
  e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
3581
3597
  }
3582
3598
  //#endregion
3583
- export { ln as ODDIN_THEME, n as PlaybackError, dn as applyTheme, Ve as baseUrlForEnv, Rn as bootEmbed, Te as clearDeviceId, Mn as createPlayer, E as deriveEventsBaseUrl, Le as detectDrmSupport, C as enterVideoFullscreen, w as exitVideoFullscreen, _e as fetchCatalog, ye as fetchTournament, xe as flattenMatches, k as getDeviceId, ze as isLowLatencyManifest, $ as isOddinMessage, De as licenseRequestHeaders, Pn as mountEmbed, v as pollToLive, b as resolveStream, T as subscribeLiveState, S as videoFullscreenActive, Ce as watchStatus };
3599
+ export { un as ODDIN_THEME, n as PlaybackError, fn as applyTheme, B as baseUrlForEnv, zn as bootEmbed, Te as clearDeviceId, Nn 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, Fn as mountEmbed, de as pollToLive, y as resolveStream, T as subscribeLiveState, S as videoFullscreenActive, Ce as watchStatus };
3584
3600
 
3585
3601
  //# sourceMappingURL=index.js.map