@oddin-gg/havik-player 1.8.2 → 1.8.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
@@ -112,7 +112,7 @@ function te(e, t, n) {
112
112
  function ne(e) {
113
113
  return Math.round(e * (1 + .15 * Math.random()));
114
114
  }
115
- function _(e, t, n, r) {
115
+ function re(e, t, n, r) {
116
116
  let i = r ?? n.kickoffMs, a = i == null ? void 0 : Math.max(0, i - t), o = Math.max(n.floorMs, e ?? 0);
117
117
  if (a == null || a <= n.imminentMs) return {
118
118
  delay: te(e ?? n.floorMs, o, n.ceilMs),
@@ -124,7 +124,7 @@ function _(e, t, n, r) {
124
124
  ttkMs: a
125
125
  };
126
126
  }
127
- function re(e, n) {
127
+ function ie(e, n) {
128
128
  return new Promise((r, i) => {
129
129
  if (n?.aborted) {
130
130
  i(new t("ABORTED", 0, "wait-for-live aborted"));
@@ -138,7 +138,7 @@ function re(e, n) {
138
138
  n?.addEventListener("abort", a, { once: !0 });
139
139
  });
140
140
  }
141
- async function v(e, n, r) {
141
+ async function _(e, n, r) {
142
142
  let a = g(n), o = Date.now(), s = a.timeoutMs == null ? Infinity : o + a.timeoutMs, c = 0, l;
143
143
  for (;;) {
144
144
  if (r?.aborted) throw new t("ABORTED", 0, "wait-for-live aborted");
@@ -147,7 +147,7 @@ async function v(e, n, r) {
147
147
  } catch (e) {
148
148
  if (!(e instanceof t) || !i(e.code)) throw e;
149
149
  c += 1, e.liveStartsAtMs != null && Number.isFinite(e.liveStartsAtMs) && (l = e.liveStartsAtMs);
150
- let n = Date.now(), u = _(e.retryAfterMs, n, a, l), d = u.ttkMs, f = u.delay;
150
+ let n = Date.now(), u = re(e.retryAfterMs, n, a, l), d = u.ttkMs, f = u.delay;
151
151
  if (a.jitter && (f = ne(f)), n + f > s) throw new t("TIMEOUT", e.httpStatus, `timed out after ${a.timeoutMs}ms waiting for the stream to go live`, {
152
152
  retryAfterMs: e.retryAfterMs,
153
153
  cause: e
@@ -158,26 +158,26 @@ async function v(e, n, r) {
158
158
  attempt: c,
159
159
  elapsedMs: n - o,
160
160
  ttkMs: d
161
- }), await re(f, r);
161
+ }), await ie(f, r);
162
162
  }
163
163
  }
164
164
  }
165
165
  //#endregion
166
166
  //#region src/core/resolve.ts
167
- async function y(e) {
167
+ async function v(e) {
168
168
  if (!e.matchUrn || typeof e.matchUrn != "string") throw new t("INVALID_URN", 0, "resolveStream: a non-empty matchUrn is required");
169
169
  let n = await c(o(e.baseUrl, `/v1/playback/${encodeURIComponent(e.matchUrn)}`), {
170
170
  credential: e.credential,
171
171
  signal: e.signal
172
172
  });
173
- if (!n.ok) throw await ie(n);
174
- return S(await n.json(), e.matchUrn);
173
+ if (!n.ok) throw await ae(n);
174
+ return x(await n.json(), e.matchUrn);
175
175
  }
176
- function b(e) {
177
- let t = () => y(e);
178
- return e.waitForLive ? v(t, e.waitForLive, e.signal) : t();
176
+ function y(e) {
177
+ let t = () => v(e);
178
+ return e.waitForLive ? _(t, e.waitForLive, e.signal) : t();
179
179
  }
180
- async function ie(e) {
180
+ async function ae(e) {
181
181
  let r = s(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, c;
182
182
  try {
183
183
  let t = await e.json();
@@ -193,7 +193,7 @@ async function ie(e) {
193
193
  liveStartsAtMs: c
194
194
  });
195
195
  }
196
- var ae = /* @__PURE__ */ new Set([
196
+ var oe = /* @__PURE__ */ new Set([
197
197
  "matchUrn",
198
198
  "protocol",
199
199
  "drmEnabled",
@@ -203,7 +203,7 @@ var ae = /* @__PURE__ */ new Set([
203
203
  "liveStartsAt",
204
204
  "expiresAt"
205
205
  ]);
206
- function x(e, n) {
206
+ function b(e, n) {
207
207
  let r;
208
208
  try {
209
209
  r = new URL(n);
@@ -213,29 +213,29 @@ function x(e, n) {
213
213
  if (r.protocol !== "https:" && r.protocol !== "http:") throw new t("INTERNAL", 0, `playback ${e} has a disallowed scheme: ${r.protocol}`);
214
214
  return n;
215
215
  }
216
- function S(e, n) {
216
+ function x(e, n) {
217
217
  if (!e.manifestUrl) throw new t("INTERNAL", 0, "playback response is missing manifestUrl");
218
218
  let r = e.drmEnabled ?? !!e.drm, i = {
219
219
  matchUrn: e.matchUrn ?? n,
220
220
  protocol: "hls",
221
221
  drmEnabled: r,
222
- manifestUrl: x("manifestUrl", e.manifestUrl),
222
+ manifestUrl: b("manifestUrl", e.manifestUrl),
223
223
  serverTime: e.serverTime ?? ""
224
224
  };
225
225
  if (e.liveStartsAt && (i.liveStartsAt = e.liveStartsAt), r && e.drm) {
226
226
  let t = {};
227
- e.drm.widevine?.licenseUrl && (t.widevine = { licenseUrl: x("widevine licenseUrl", e.drm.widevine.licenseUrl) }), e.drm.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && (t.fairplay = {
228
- licenseUrl: x("fairplay licenseUrl", e.drm.fairplay.licenseUrl),
229
- certificateUrl: x("fairplay certificateUrl", e.drm.fairplay.certificateUrl)
227
+ e.drm.widevine?.licenseUrl && (t.widevine = { licenseUrl: b("widevine licenseUrl", e.drm.widevine.licenseUrl) }), e.drm.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && (t.fairplay = {
228
+ licenseUrl: b("fairplay licenseUrl", e.drm.fairplay.licenseUrl),
229
+ certificateUrl: b("fairplay certificateUrl", e.drm.fairplay.certificateUrl)
230
230
  }), (t.widevine || t.fairplay) && (i.drm = t);
231
231
  }
232
232
  let a = {};
233
- for (let [t, n] of Object.entries(e)) ae.has(t) || (a[t] = n);
233
+ for (let [t, n] of Object.entries(e)) oe.has(t) || (a[t] = n);
234
234
  return Object.keys(a).length > 0 && (i.extensions = a), i;
235
235
  }
236
236
  //#endregion
237
237
  //#region src/core/catalog.ts
238
- async function C(e) {
238
+ async function S(e) {
239
239
  let r = new URLSearchParams();
240
240
  e.status && r.set("status", Array.isArray(e.status) ? e.status.join(",") : e.status), e.sport && r.set("sport", e.sport);
241
241
  let i = r.toString(), a = o(e.baseUrl, "/v1/catalog" + (i ? `?${i}` : "")), s = new Headers();
@@ -252,12 +252,12 @@ async function C(e) {
252
252
  };
253
253
  if (!l.ok) throw new t(n(l.status), l.status, `catalog request failed (HTTP ${l.status})`);
254
254
  return {
255
- tournaments: oe(await l.json()),
255
+ tournaments: se(await l.json()),
256
256
  etag: l.headers.get("etag") ?? void 0,
257
257
  notModified: !1
258
258
  };
259
259
  }
260
- function oe(e) {
260
+ function se(e) {
261
261
  return (e.tournaments ?? []).map((e) => {
262
262
  let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
263
263
  return {
@@ -277,7 +277,7 @@ function oe(e) {
277
277
  };
278
278
  });
279
279
  }
280
- async function se(e) {
280
+ async function ce(e) {
281
281
  let r = o(e.baseUrl, `/v1/tournaments/${encodeURIComponent(e.urn)}`), i = new Headers();
282
282
  e.etag && i.set("If-None-Match", e.etag);
283
283
  let a = await c(r, {
@@ -296,13 +296,13 @@ async function se(e) {
296
296
  };
297
297
  if (!a.ok) throw new t(n(a.status), a.status, `tournament request failed (HTTP ${a.status})`);
298
298
  return {
299
- tournament: ce(await a.json()),
299
+ tournament: le(await a.json()),
300
300
  etag: a.headers.get("etag") ?? void 0,
301
301
  notModified: !1,
302
302
  notFound: !1
303
303
  };
304
304
  }
305
- function ce(e) {
305
+ function le(e) {
306
306
  let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
307
307
  return {
308
308
  urn: t,
@@ -320,12 +320,12 @@ function ce(e) {
320
320
  }))
321
321
  };
322
322
  }
323
- function le(e) {
323
+ function ue(e) {
324
324
  return e.tournaments.flatMap((e) => e.matches);
325
325
  }
326
326
  //#endregion
327
327
  //#region src/core/poll.ts
328
- function ue(e) {
328
+ function de(e) {
329
329
  let r = Math.max(2e3, e.intervalMs ?? 1e4), i = new AbortController(), a, s, l, u = !1, d = () => {
330
330
  u || (a = setTimeout(f, r));
331
331
  }, f = async () => {
@@ -360,7 +360,7 @@ function ue(e) {
360
360
  }
361
361
  //#endregion
362
362
  //#region src/core/events.ts
363
- function w(e) {
363
+ function C(e) {
364
364
  let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = new AbortController(), i = !1, s = (e) => new Promise((t) => {
365
365
  if (r.signal.aborted) return t();
366
366
  let n = setTimeout(t, e);
@@ -427,7 +427,7 @@ function w(e) {
427
427
  i || (i = !0, r.abort());
428
428
  } };
429
429
  }
430
- function T(e) {
430
+ function w(e) {
431
431
  try {
432
432
  let t = new URL(e);
433
433
  return t.hostname = `events.${t.hostname}`, t.pathname = "", t.search = "", t.origin;
@@ -437,27 +437,27 @@ function T(e) {
437
437
  }
438
438
  //#endregion
439
439
  //#region src/core/drm/deviceId.ts
440
- var E = "havik.player.deviceId", D;
441
- function O() {
442
- if (D) return D;
440
+ var T = "havik.player.deviceId", E;
441
+ function D() {
442
+ if (E) return E;
443
443
  try {
444
- let e = globalThis.localStorage?.getItem(E);
445
- if (e) return D = e, e;
444
+ let e = globalThis.localStorage?.getItem(T);
445
+ if (e) return E = e, e;
446
446
  } catch {}
447
- let e = fe();
448
- D = e;
447
+ let e = pe();
448
+ E = e;
449
449
  try {
450
- globalThis.localStorage?.setItem(E, e);
450
+ globalThis.localStorage?.setItem(T, e);
451
451
  } catch {}
452
452
  return e;
453
453
  }
454
- function de() {
455
- D = void 0;
454
+ function fe() {
455
+ E = void 0;
456
456
  try {
457
- globalThis.localStorage?.removeItem(E);
457
+ globalThis.localStorage?.removeItem(T);
458
458
  } catch {}
459
459
  }
460
- function fe() {
460
+ function pe() {
461
461
  let e = globalThis.crypto;
462
462
  if (e && typeof e.randomUUID == "function") return e.randomUUID();
463
463
  let t = /* @__PURE__ */ new Uint8Array(16);
@@ -469,22 +469,22 @@ function fe() {
469
469
  }
470
470
  //#endregion
471
471
  //#region src/core/drm/headers.ts
472
- function pe(e, t, n = {}) {
472
+ function me(e, t, n = {}) {
473
473
  let r = {
474
474
  "x-api-key": t.apiKey,
475
475
  "X-Match-Urn": e.matchUrn,
476
- "X-Device-Id": n.deviceId ?? O(),
476
+ "X-Device-Id": n.deviceId ?? D(),
477
477
  "Content-Type": "application/octet-stream"
478
478
  };
479
479
  return n.userId && (r["X-User-Id"] = n.userId), r;
480
480
  }
481
481
  //#endregion
482
482
  //#region src/core/drm/support.ts
483
- var me = 5e3, k = "video/mp4; codecs=\"avc1.42E01E\"", A = "audio/mp4; codecs=\"mp4a.40.2\"", j = {
483
+ var he = 5e3, O = "video/mp4; codecs=\"avc1.42E01E\"", k = "audio/mp4; codecs=\"mp4a.40.2\"", A = {
484
484
  widevine: ["com.widevine.alpha"],
485
485
  fairplay: ["com.apple.fps"]
486
486
  };
487
- function M(e) {
487
+ function j(e) {
488
488
  return e === "fairplay" ? [{
489
489
  initDataTypes: [
490
490
  "sinf",
@@ -492,30 +492,30 @@ function M(e) {
492
492
  "cenc"
493
493
  ],
494
494
  videoCapabilities: [{
495
- contentType: k,
495
+ contentType: O,
496
496
  robustness: "",
497
497
  encryptionScheme: "cbcs"
498
498
  }],
499
499
  audioCapabilities: [{
500
- contentType: A,
500
+ contentType: k,
501
501
  robustness: "",
502
502
  encryptionScheme: "cbcs"
503
503
  }]
504
504
  }] : [{
505
505
  initDataTypes: ["cenc"],
506
506
  videoCapabilities: [{
507
- contentType: k,
507
+ contentType: O,
508
508
  robustness: "SW_SECURE_DECODE",
509
509
  encryptionScheme: "cbcs"
510
510
  }],
511
511
  audioCapabilities: [{
512
- contentType: A,
512
+ contentType: k,
513
513
  robustness: "SW_SECURE_CRYPTO",
514
514
  encryptionScheme: "cbcs"
515
515
  }]
516
516
  }];
517
517
  }
518
- function N(e, t) {
518
+ function M(e, t) {
519
519
  return new Promise((n, r) => {
520
520
  let i = setTimeout(() => r(/* @__PURE__ */ Error("probe-timeout")), t);
521
521
  e.then((e) => {
@@ -525,8 +525,8 @@ function N(e, t) {
525
525
  });
526
526
  });
527
527
  }
528
- async function P(e = {}) {
529
- let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? me, r = {};
528
+ async function N(e = {}) {
529
+ let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? he, r = {};
530
530
  if (typeof window < "u" && window.isSecureContext === !1) return {
531
531
  verdict: "insecure-context",
532
532
  detail: r
@@ -538,7 +538,7 @@ async function P(e = {}) {
538
538
  };
539
539
  let a = !1, o = !1, s = Date.now() + n, c = () => Math.max(1, s - Date.now());
540
540
  for (let e of t) {
541
- let t = j[e];
541
+ let t = A[e];
542
542
  if (!t) {
543
543
  r[e] = "unknown system";
544
544
  continue;
@@ -549,7 +549,7 @@ async function P(e = {}) {
549
549
  break;
550
550
  }
551
551
  try {
552
- return await N((await N(i(n, M(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
552
+ return await M((await M(i(n, j(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
553
553
  verdict: "supported",
554
554
  system: e,
555
555
  detail: r
@@ -573,17 +573,17 @@ async function P(e = {}) {
573
573
  }
574
574
  //#endregion
575
575
  //#region src/core/manifest.ts
576
- var F = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
577
- function I(e) {
578
- return F.test(e);
576
+ var P = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
577
+ function F(e) {
578
+ return P.test(e);
579
579
  }
580
580
  //#endregion
581
581
  //#region src/core/stats.ts
582
- var L = { droppedFrames: 0 };
583
- function R(e) {
582
+ var I = { droppedFrames: 0 };
583
+ function L(e) {
584
584
  return e.getVideoPlaybackQuality?.()?.droppedVideoFrames ?? 0;
585
585
  }
586
- function z(e, t) {
586
+ function R(e, t) {
587
587
  let n = [
588
588
  ["playing", () => t("playing")],
589
589
  ["waiting", () => t("buffering")],
@@ -600,7 +600,7 @@ function z(e, t) {
600
600
  }
601
601
  //#endregion
602
602
  //#region src/core/engine/native.ts
603
- function he(e) {
603
+ function ge(e) {
604
604
  try {
605
605
  let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
606
606
  return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
@@ -608,15 +608,15 @@ function he(e) {
608
608
  return;
609
609
  }
610
610
  }
611
- function B(e) {
611
+ function z(e) {
612
612
  return !!(e ?? (typeof document < "u" ? document.createElement("video") : void 0))?.canPlayType("application/vnd.apple.mpegurl");
613
613
  }
614
- function V() {
614
+ function B() {
615
615
  if (typeof window > "u") return !1;
616
616
  let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
617
617
  return e || t;
618
618
  }
619
- var H = class {
619
+ var V = class {
620
620
  name = "native";
621
621
  deps;
622
622
  onLoaded;
@@ -659,7 +659,7 @@ var H = class {
659
659
  });
660
660
  this.onEncrypted = (t) => {
661
661
  let o = t;
662
- !o.initData || this.fairplayArmed || (this.fairplayArmed = !0, this.fairplayKeyIV = he(o.initData), (async () => {
662
+ !o.initData || this.fairplayArmed || (this.fairplayArmed = !0, this.fairplayKeyIV = ge(o.initData), (async () => {
663
663
  try {
664
664
  let t = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
665
665
  initDataTypes: [o.initDataType],
@@ -751,7 +751,7 @@ var H = class {
751
751
  e.seekable.length > 0 && (e.currentTime = e.seekable.end(e.seekable.length - 1));
752
752
  }
753
753
  getStats() {
754
- let e = this.deps.video, t = { droppedFrames: R(e) };
754
+ let e = this.deps.video, t = { droppedFrames: L(e) };
755
755
  return e.duration === Infinity && (t.isLive = !0, e.seekable.length > 0 && (t.atLiveEdge = e.currentTime >= e.seekable.end(e.seekable.length - 1) - 2)), t;
756
756
  }
757
757
  stop() {
@@ -773,20 +773,20 @@ var H = class {
773
773
  };
774
774
  //#endregion
775
775
  //#region src/core/engine/hls.ts
776
- function ge() {
776
+ function _e() {
777
777
  return e.isSupported();
778
778
  }
779
- var _e = 3, ve = 5, ye = 3, be = 3e4, xe = 12e3, Se = 3e3, Ce = 6e3, we = 2, Te = 9, Ee = .5;
780
- function De(e) {
779
+ var ve = 3, ye = 5, be = 3, xe = 3e4, Se = 12e3, Ce = 3e3, H = 6e3, we = 4e3, Te = 2, Ee = 5, De = 2, Oe = 9, ke = .5;
780
+ function Ae(e) {
781
781
  if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
782
782
  delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
783
783
  return;
784
784
  }
785
- e.liveSyncDuration ??= we;
786
- let t = Math.max(12, e.liveSyncDuration + Te);
787
- (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), Oe(e, e.liveSyncDuration);
785
+ e.liveSyncDuration ??= De;
786
+ let t = Math.max(12, e.liveSyncDuration + Oe);
787
+ (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), je(e, e.liveSyncDuration);
788
788
  }
789
- function Oe(e, t) {
789
+ function je(e, t) {
790
790
  let n = (e, t, n) => Math.min(n, Math.max(t, e));
791
791
  e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
792
792
  }
@@ -809,6 +809,9 @@ var U = class {
809
809
  lastAdvanceMs = 0;
810
810
  endWatchdog = null;
811
811
  endedEmitted = !1;
812
+ lastFragLoadingMs = 0;
813
+ starvedTicks = 0;
814
+ starvationKicks = 0;
812
815
  chaseSuspended = !1;
813
816
  savedLiveMaxLatency;
814
817
  savedMaxSyncRate;
@@ -816,7 +819,7 @@ var U = class {
816
819
  this.deps = e, this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl;
817
820
  }
818
821
  async load() {
819
- let { descriptor: e, snapToLiveOnRefocus: n, video: r, emit: i } = this.deps, a = B(r) && V(), o = !!e.drm?.widevine?.licenseUrl && !a;
822
+ let { descriptor: e, snapToLiveOnRefocus: n, video: r, emit: i } = this.deps, a = z(r) && B(), o = !!e.drm?.widevine?.licenseUrl && !a;
820
823
  if (e.drmEnabled && !o) {
821
824
  i({
822
825
  type: "error",
@@ -840,7 +843,7 @@ var U = class {
840
843
  let t = e.liveSyncPosition;
841
844
  if (typeof t != "number" || !Number.isFinite(t)) return;
842
845
  let { video: n } = this.deps;
843
- n.currentTime <= t + Ee || (n.currentTime = t);
846
+ n.currentTime <= t + ke || (n.currentTime = t);
844
847
  }
845
848
  startHls() {
846
849
  let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps, u = n.drmEnabled && !!(n.drm?.widevine?.licenseUrl || n.drm?.fairplay?.licenseUrl), d = {
@@ -867,14 +870,16 @@ var U = class {
867
870
  } : {},
868
871
  ...c
869
872
  };
870
- De(d);
873
+ Ae(d);
871
874
  let f = new e(d);
872
875
  this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
873
876
  this.mediaRecoveries = 0, this.networkRecoveries = 0, l({ type: "ready" });
874
- }), f.on(e.Events.FRAG_BUFFERED, () => {
875
- (this.mediaRecoveries > 0 || this.networkRecoveries > 0 || this.licenseRecoveries > 0) && !this.recoveryResetTimer && (this.recoveryResetTimer = setTimeout(() => {
876
- this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.recoveryResetTimer = null;
877
- }, be));
877
+ }), f.on(e.Events.FRAG_BUFFERED, (e, t) => {
878
+ t?.frag?.type === "main" && (this.mediaRecoveries > 0 || this.networkRecoveries > 0 || this.licenseRecoveries > 0 || this.starvationKicks > 0) && !this.recoveryResetTimer && (this.recoveryResetTimer = setTimeout(() => {
879
+ this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.recoveryResetTimer = null;
880
+ }, xe));
881
+ }), f.on(e.Events.FRAG_LOADING, (e, t) => {
882
+ t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
878
883
  }), f.on(e.Events.LEVEL_LOADED, (e, t) => {
879
884
  if (this.detectedLowLatency) return;
880
885
  let n = t.details;
@@ -882,7 +887,9 @@ var U = class {
882
887
  type: "lowLatencyDetected",
883
888
  value: !0
884
889
  }));
885
- }), f.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.endWatchdog = setInterval(() => this.checkEndStale(), Se), f.on(e.Events.LEVEL_SWITCHED, (e, t) => l({
890
+ }), f.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.endWatchdog = setInterval(() => {
891
+ this.checkEndStale(), this.checkStarvation();
892
+ }, Ce), f.on(e.Events.LEVEL_SWITCHED, (e, t) => l({
886
893
  type: "qualitychange",
887
894
  index: t.level
888
895
  })), f.on(e.Events.AUDIO_TRACK_SWITCHED, (e, t) => l({
@@ -951,7 +958,7 @@ var U = class {
951
958
  }
952
959
  getStats() {
953
960
  let e = this.hls, t = {
954
- droppedFrames: R(this.deps.video),
961
+ droppedFrames: L(this.deps.video),
955
962
  lowLatency: this.detectedLowLatency
956
963
  };
957
964
  if (e) {
@@ -980,7 +987,28 @@ var U = class {
980
987
  return;
981
988
  }
982
989
  let e = Date.now() - this.lastAdvanceMs;
983
- !this.chaseSuspended && e > Ce && this.suspendChasing(), e > xe && this.emitEnded("stalled");
990
+ !this.chaseSuspended && e > H && this.suspendChasing(), e > Se && this.emitEnded("stalled");
991
+ }
992
+ checkStarvation() {
993
+ let e = this.hls, { video: t } = this.deps;
994
+ if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended) return;
995
+ if (typeof document < "u" && document.hidden) {
996
+ this.starvedTicks = 0;
997
+ return;
998
+ }
999
+ let n = this.lastAdvanceMs !== 0 && Date.now() - this.lastAdvanceMs < H, r = this.lastFragLoadingMs !== 0 && Date.now() - this.lastFragLoadingMs > we;
1000
+ if (!(t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused && n && r)) {
1001
+ this.starvedTicks = 0;
1002
+ return;
1003
+ }
1004
+ if (!(++this.starvedTicks < Te) && (this.starvedTicks = 0, !(this.starvationKicks >= Ee))) {
1005
+ this.starvationKicks += 1, console.warn("havik-player: video starved while the live playlist advances (wedged hls.js fragment pipeline) — restarting load at the live edge");
1006
+ try {
1007
+ e.stopLoad(), e.startLoad(-1);
1008
+ } catch (e) {
1009
+ console.warn("havik-player: starvation kick failed", e);
1010
+ }
1011
+ }
984
1012
  }
985
1013
  suspendChasing() {
986
1014
  let e = this.hls;
@@ -1022,7 +1050,7 @@ var U = class {
1022
1050
  scheduleLicenseRetry(t) {
1023
1051
  if (!(t.details === e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED || t.details === e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED)) return !1;
1024
1052
  let n = t.response?.code ?? 0;
1025
- if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= ye) return !1;
1053
+ if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= be) return !1;
1026
1054
  this.licenseRecoveries += 1;
1027
1055
  let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
1028
1056
  return this.licenseRetryTimer = setTimeout(() => {
@@ -1050,7 +1078,7 @@ var U = class {
1050
1078
  return;
1051
1079
  }
1052
1080
  if (t.type === e.ErrorTypes.NETWORK_ERROR) {
1053
- if (this.networkRecoveries < ve) {
1081
+ if (this.networkRecoveries < ye) {
1054
1082
  this.networkRecoveries += 1;
1055
1083
  let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
1056
1084
  this.networkRetryTimer = setTimeout(() => {
@@ -1066,7 +1094,7 @@ var U = class {
1066
1094
  return;
1067
1095
  }
1068
1096
  if (t.type === e.ErrorTypes.MEDIA_ERROR) {
1069
- if (this.mediaRecoveries < _e) {
1097
+ if (this.mediaRecoveries < ve) {
1070
1098
  this.mediaRecoveries += 1, n.recoverMediaError();
1071
1099
  return;
1072
1100
  }
@@ -1121,15 +1149,15 @@ function K(e, t) {
1121
1149
  }
1122
1150
  //#endregion
1123
1151
  //#region src/ui/styles.ts
1124
- var q = "havik-player-styles", ke = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n.havik-spinner{width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n\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";
1125
- function Ae(e = document) {
1152
+ var q = "havik-player-styles", Me = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n.havik-spinner{width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n/* A status card carries its own logo — the corner watermark would duplicate it. */\n.havik-player.havik-has-status .havik-watermark{display:none}\n\n.havik-bar{position:absolute;left:0;right:0;bottom:0;padding:0 12px 8px;\n opacity:1;transition:opacity .25s;z-index:2}\n.havik-seek{position:relative;height:16px;display:flex;align-items:center;cursor:pointer;margin-bottom:2px}\n.havik-seek__track{position:relative;width:100%;height:4px;border-radius:3px;background:rgba(255,255,255,.25)}\n.havik-seek__buffered{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:rgba(255,255,255,.4)}\n.havik-seek__played{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-seek__thumb{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;\n background:var(--havik-accent,#E1B600);transform:translate(-50%,-50%) scale(0);transition:transform .1s}\n.havik-seek:hover .havik-seek__thumb{transform:translate(-50%,-50%) scale(1)}\n\n.havik-controls{display:flex;align-items:center;gap:6px;height:40px}\n.havik-spacer{flex:1}\n.havik-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;border-radius:var(--havik-radius,8px);\n padding:0;transition:background .12s,color .12s}\n.havik-btn:hover{background:rgba(255,255,255,.12)}\n.havik-btn:focus-visible{outline:2px solid var(--havik-accent,#E1B600);outline-offset:1px}\n.havik-btn svg{width:22px;height:22px}\n\n/* The volume level is filled in accent up to the thumb, like the seek bar's\n played span — a native range input paints no \"elapsed\" side, which left the\n level readable only from the dot's position. --havik-vol (0..1) is set by\n syncVolume(); the track width and thumb size live here as variables because\n the WebKit fill has to compute the thumb centre from both. */\n.havik-vol{display:flex;align-items:center}\n.havik-vol__slider{--havik-vol-w:70px;--havik-vol-thumb:12px;--havik-vol:1;\n --havik-vol-pos:calc(var(--havik-vol-thumb) / 2 + var(--havik-vol) * (var(--havik-vol-w) - var(--havik-vol-thumb)));\n width:0;opacity:0;transition:width .18s,opacity .18s;height:4px;cursor:pointer;\n appearance:none;-webkit-appearance:none;background:transparent;border-radius:3px;margin:0 4px}\n.havik-vol:hover .havik-vol__slider,.havik-vol:focus-within .havik-vol__slider{width:var(--havik-vol-w);opacity:1}\n/* WebKit/Blink have no progress pseudo-element: paint the fill as a hard-stop\n gradient that ends at the thumb centre. */\n.havik-vol__slider::-webkit-slider-runnable-track{height:4px;border-radius:3px;\n background:linear-gradient(to right,var(--havik-accent,#E1B600) var(--havik-vol-pos),\n rgba(255,255,255,.3) var(--havik-vol-pos))}\n/* Firefox fills natively, and tracks the thumb exactly. */\n.havik-vol__slider::-moz-range-track{height:4px;border-radius:3px;background:rgba(255,255,255,.3)}\n.havik-vol__slider::-moz-range-progress{height:4px;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-vol__slider::-webkit-slider-thumb{-webkit-appearance:none;width:var(--havik-vol-thumb);\n height:var(--havik-vol-thumb);border-radius:50%;background:var(--havik-accent,#E1B600);\n margin-top:calc((4px - var(--havik-vol-thumb)) / 2)}\n.havik-vol__slider::-moz-range-thumb{width:var(--havik-vol-thumb);height:var(--havik-vol-thumb);\n border:0;border-radius:50%;background:var(--havik-accent,#E1B600)}\n\n.havik-time{font-size:12px;color:var(--havik-text-muted,#9aa0ad);\n font-variant-numeric:tabular-nums;padding:0 6px;white-space:nowrap}\n.havik-live{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;\n letter-spacing:.4px;padding:0 8px;color:var(--havik-text,#fff)}\n.havik-live svg{width:9px;height:9px;color:var(--havik-text-muted,#9aa0ad)}\n.havik-live.is-live svg{color:var(--havik-accent,#E1B600)}\n.havik-live__go{margin-left:2px;border:0;cursor:pointer;background:transparent;color:var(--havik-text-muted,#9aa0ad);\n font:inherit;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:6px}\n.havik-live.is-live .havik-live__go{display:none}\n.havik-live__go:hover{color:var(--havik-accent,#E1B600)}\n\n.havik-menu{position:absolute;bottom:54px;right:12px;min-width:170px;max-height:230px;overflow:auto;\n background:var(--havik-surface,#1B1C23);border:1px solid var(--havik-border,rgba(255,255,255,.1));\n border-radius:var(--havik-radius,8px);box-shadow:0 10px 30px rgba(0,0,0,.5);padding:6px;z-index:3}\n.havik-menu[hidden]{display:none}\n.havik-menu__title{font-size:11px;text-transform:uppercase;letter-spacing:.6px;\n color:var(--havik-text-muted,#9aa0ad);padding:6px 8px 4px}\n.havik-menu__item{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;font:inherit;font-size:13px;\n text-align:left;padding:7px 8px;border-radius:6px}\n.havik-menu__item:hover{background:var(--havik-surface-muted,#2a2c36)}\n.havik-menu__item[aria-checked=\"true\"]{color:var(--havik-accent,#E1B600);font-weight:600}\n.havik-menu__item[aria-checked=\"true\"]::after{content:'✓'}\n";
1153
+ function Ne(e = document) {
1126
1154
  if (e.getElementById(q)) return;
1127
1155
  let t = e.createElement("style");
1128
- t.id = q, t.textContent = ke, e.head.appendChild(t);
1156
+ t.id = q, t.textContent = Me, e.head.appendChild(t);
1129
1157
  }
1130
1158
  //#endregion
1131
1159
  //#region src/ui/icons.ts
1132
- var je = {
1160
+ var Pe = {
1133
1161
  play: "<path d=\"M8 5v14l11-7z\"/>",
1134
1162
  pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
1135
1163
  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\"/>",
@@ -1143,20 +1171,20 @@ var je = {
1143
1171
  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\"/>"
1144
1172
  };
1145
1173
  function J(e) {
1146
- return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${je[e]}</svg>`;
1174
+ return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Pe[e]}</svg>`;
1147
1175
  }
1148
1176
  //#endregion
1149
1177
  //#region src/ui/controls.ts
1150
- var Me = 3e3, Ne = /* @__PURE__ */ new Set([
1178
+ var Fe = 3e3, Ie = /* @__PURE__ */ new Set([
1151
1179
  "GONE",
1152
1180
  "NOT_FOUND",
1153
1181
  "INVALID_URN",
1154
1182
  "UNAUTHORIZED"
1155
1183
  ]);
1156
- function Pe(e) {
1157
- return new Fe(e);
1184
+ function Le(e) {
1185
+ return new Re(e);
1158
1186
  }
1159
- var Fe = class {
1187
+ var Re = class {
1160
1188
  root;
1161
1189
  video;
1162
1190
  player;
@@ -1196,7 +1224,7 @@ var Fe = class {
1196
1224
  scrubbing = !1;
1197
1225
  offFns = [];
1198
1226
  constructor(e) {
1199
- this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Me, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.errorMessage = e.errorMessage, Ae(this.doc), this.root.classList.add("havik-player"), this.root.hasAttribute("tabindex") || (this.root.tabIndex = 0), this.root.setAttribute("role", "region"), this.root.setAttribute("aria-label", "Video player");
1227
+ this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Fe, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.errorMessage = e.errorMessage, Ne(this.doc), this.root.classList.add("havik-player"), this.root.hasAttribute("tabindex") || (this.root.tabIndex = 0), this.root.setAttribute("role", "region"), this.root.setAttribute("aria-label", "Video player");
1200
1228
  let t = (e, t, n) => {
1201
1229
  let r = this.doc.createElement(e);
1202
1230
  if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
@@ -1272,7 +1300,7 @@ var Fe = class {
1272
1300
  this.statusOverlays && (e === "ended" ? t = "ended" : e === "error" ? t = "error" : e === "waiting" ? t = "waiting" : !this.hasPlayed && (e === "idle" || e === "paused") && (t = "preplay")), this.renderStatus(t);
1273
1301
  }
1274
1302
  renderStatus(e) {
1275
- if (e === this.statusKind || (this.statusKind = e, this.statusBox?.remove(), this.statusBox = null, !e)) return;
1303
+ if (e === this.statusKind || (this.statusKind = e, this.statusBox?.remove(), this.statusBox = null, this.root.classList.toggle("havik-has-status", !!e), !e)) return;
1276
1304
  let t = this.doc.createElement("div");
1277
1305
  if (t.className = `havik-status havik-status--${e}`, this.logoUrl) {
1278
1306
  let e = this.doc.createElement("div");
@@ -1283,7 +1311,7 @@ var Fe = class {
1283
1311
  e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML = J("play"), e.addEventListener("click", () => void this.player.play()), t.append(e);
1284
1312
  } else {
1285
1313
  let n = this.doc.createElement("div");
1286
- if (n.className = "havik-status__msg", n.textContent = e === "ended" ? this.endedMessage : e === "waiting" ? "Starting soon…" : this.errorMessage ?? this.lastError?.message ?? "Playback unavailable", t.append(n), e === "error" && this.lastError && !Ne.has(this.lastError.code)) {
1314
+ if (n.className = "havik-status__msg", n.textContent = e === "ended" ? this.endedMessage : e === "waiting" ? "Starting soon…" : this.errorMessage ?? this.lastError?.message ?? "Playback unavailable", t.append(n), e === "error" && this.lastError && !Ie.has(this.lastError.code)) {
1287
1315
  let e = this.doc.createElement("button");
1288
1316
  e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${J("retry")}<span>Retry</span>`, e.addEventListener("click", () => void this.player.retry()), t.append(e);
1289
1317
  }
@@ -1374,17 +1402,17 @@ var Fe = class {
1374
1402
  renderQualityMenu() {
1375
1403
  let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
1376
1404
  n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
1377
- for (let n of e) this.menu.append(this.menuItem(Ie(n), t === n.index, () => this.player.setQuality(n.index)));
1405
+ for (let n of e) this.menu.append(this.menuItem(ze(n), t === n.index, () => this.player.setQuality(n.index)));
1378
1406
  }
1379
1407
  renderAudioMenu() {
1380
1408
  let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
1381
1409
  t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
1382
- for (let t of e) this.menu.append(this.menuItem(Le(t), t.default, () => this.player.setAudioTrack(t.id)));
1410
+ for (let t of e) this.menu.append(this.menuItem(Be(t), t.default, () => this.player.setAudioTrack(t.id)));
1383
1411
  }
1384
1412
  renderCcMenu() {
1385
1413
  let e = this.player.getTextTracks(), t = this.doc.createElement("div");
1386
1414
  t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
1387
- for (let t of e) this.menu.append(this.menuItem(Re(t), !1, () => this.player.setTextTrack(t.id)));
1415
+ for (let t of e) this.menu.append(this.menuItem(Ve(t), !1, () => this.player.setTextTrack(t.id)));
1388
1416
  }
1389
1417
  onTracksChanged() {
1390
1418
  this.openMenu && this.renderMenu(this.openMenu);
@@ -1482,7 +1510,7 @@ var Fe = class {
1482
1510
  this.bar,
1483
1511
  this.menu
1484
1512
  ]) e.remove();
1485
- this.root.classList.remove("havik-player", "havik-hide");
1513
+ this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
1486
1514
  }
1487
1515
  };
1488
1516
  function Y(e) {
@@ -1490,27 +1518,27 @@ function Y(e) {
1490
1518
  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");
1491
1519
  return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
1492
1520
  }
1493
- function Ie(e) {
1521
+ function ze(e) {
1494
1522
  return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
1495
1523
  }
1496
- function Le(e) {
1524
+ function Be(e) {
1497
1525
  return e.name || e.lang || `Track ${e.id}`;
1498
1526
  }
1499
- function Re(e) {
1527
+ function Ve(e) {
1500
1528
  return e.name || e.lang || `Track ${e.id}`;
1501
1529
  }
1502
1530
  //#endregion
1503
1531
  //#region src/managed/index.ts
1504
- var ze = 6e3, X = 45e3, Be = 2e3, Ve = 3, He = 2e3, Ue = 480 * 1e3;
1505
- async function Z(e) {
1532
+ var He = 6e3, X = 45e3, Ue = 2e3, Z = 3, We = 2e3, Ge = 480 * 1e3;
1533
+ async function Q(e) {
1506
1534
  if (!e.video || typeof e.video.play != "function") throw new t("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
1507
1535
  if (!e.baseUrl) throw new t("INTERNAL", 0, "createPlayer: baseUrl is required");
1508
1536
  if (!e.matchUrn) throw new t("INVALID_URN", 0, "createPlayer: matchUrn is required");
1509
1537
  if (!e.credential) throw new t("INTERNAL", 0, "createPlayer: credential is required");
1510
- let n = new We(e);
1538
+ let n = new Ke(e);
1511
1539
  return await n.start(), n;
1512
1540
  }
1513
- var We = class {
1541
+ var Ke = class {
1514
1542
  opts;
1515
1543
  abort = new AbortController();
1516
1544
  listeners = {};
@@ -1544,7 +1572,7 @@ var We = class {
1544
1572
  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");
1545
1573
  let e = ++this.loadGen, n = this.resolveOptions();
1546
1574
  try {
1547
- let t = await y(n);
1575
+ let t = await v(n);
1548
1576
  if (await this.onResolved(t, e), e === this.loadGen && this._state === "error" && this._lastError) {
1549
1577
  let e = this._lastError;
1550
1578
  throw this.destroy(), e;
@@ -1566,11 +1594,11 @@ var We = class {
1566
1594
  };
1567
1595
  }
1568
1596
  beginArming(e, t) {
1569
- let n = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? T(this.opts.baseUrl);
1597
+ let n = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? w(this.opts.baseUrl);
1570
1598
  n ? this.armWithSse(e, n, t) : this.beginArmingByPolling(e);
1571
1599
  }
1572
1600
  beginArmingByPolling(e) {
1573
- b({
1601
+ y({
1574
1602
  ...this.resolveOptions(),
1575
1603
  signal: this.abort.signal,
1576
1604
  waitForLive: this.buildWaitConfig(e)
@@ -1604,7 +1632,7 @@ var We = class {
1604
1632
  }
1605
1633
  }
1606
1634
  }, m = () => {
1607
- a || o || f() || (o = !0, b({
1635
+ a || o || f() || (o = !0, y({
1608
1636
  ...this.resolveOptions(),
1609
1637
  signal: s.signal,
1610
1638
  waitForLive: this.buildWaitConfig(e)
@@ -1612,7 +1640,7 @@ var We = class {
1612
1640
  a || f() || s.signal.aborted || (a = !0, this.closeArming(), this.fail(e instanceof t ? e : new t("INTERNAL", 0, String(e))));
1613
1641
  }));
1614
1642
  }, h = () => {
1615
- a || f() || y(this.resolveOptions()).then((e) => p(e)).catch((e) => {
1643
+ a || f() || v(this.resolveOptions()).then((e) => p(e)).catch((e) => {
1616
1644
  a || f() || e instanceof t && i(e.code) || (a = !0, this.closeArming(), s.abort(), this.fail(e instanceof t ? e : new t("INTERNAL", 0, String(e))));
1617
1645
  });
1618
1646
  }, g = (e) => {
@@ -1620,13 +1648,13 @@ var We = class {
1620
1648
  !a && !f() && m();
1621
1649
  }, e);
1622
1650
  };
1623
- g(ze), this.armingSub = w({
1651
+ g(He), this.armingSub = C({
1624
1652
  eventsBaseUrl: n,
1625
1653
  matchUrn: this.opts.matchUrn,
1626
1654
  credential: this.opts.credential,
1627
1655
  onAlive: () => g(X),
1628
1656
  onState: (e) => {
1629
- a || f() || (e.state === "live" || e.state === "gone") && setTimeout(h, Math.random() * Be);
1657
+ a || f() || (e.state === "live" || e.state === "gone") && setTimeout(h, Math.random() * Ue);
1630
1658
  },
1631
1659
  onError: () => m()
1632
1660
  });
@@ -1649,7 +1677,7 @@ var We = class {
1649
1677
  let n = await a(this.opts.credential);
1650
1678
  if (this.destroyed || t !== this.loadGen) return;
1651
1679
  this.setState("loading");
1652
- let r = this.createEngine(e, n), i = z(this.opts.video, (e) => {
1680
+ let r = this.createEngine(e, n), i = R(this.opts.video, (e) => {
1653
1681
  this._state === "ended" || this._state === "error" || this.setState(e);
1654
1682
  });
1655
1683
  if (await r.load(), this.destroyed || t !== this.loadGen) {
@@ -1669,7 +1697,7 @@ var We = class {
1669
1697
  video: this.opts.video,
1670
1698
  descriptor: e,
1671
1699
  credential: n,
1672
- deviceId: O(),
1700
+ deviceId: D(),
1673
1701
  userId: this.opts.userId,
1674
1702
  lowLatency: this.opts.lowLatency === void 0 || this.opts.lowLatency === "auto" || this.opts.lowLatency,
1675
1703
  snapToLiveOnRefocus: this.opts.snapToLiveOnRefocus,
@@ -1677,11 +1705,11 @@ var We = class {
1677
1705
  hlsConfig: r,
1678
1706
  emit: (e) => this.onEngineEvent(e)
1679
1707
  }, a = this.opts.engine ?? "auto";
1680
- if (a === "native") return new H(i);
1708
+ if (a === "native") return new V(i);
1681
1709
  if (a === "hls") return new U(i);
1682
- if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && B(this.opts.video) && V()) return new H(i);
1683
- if (ge()) return new U(i);
1684
- if (B(this.opts.video)) return new H(i);
1710
+ if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && z(this.opts.video) && B()) return new V(i);
1711
+ if (_e()) return new U(i);
1712
+ if (z(this.opts.video)) return new V(i);
1685
1713
  throw new t("INTERNAL", 0, "no supported HLS playback engine in this browser");
1686
1714
  }
1687
1715
  onEngineEvent(e) {
@@ -1711,11 +1739,11 @@ var We = class {
1711
1739
  }
1712
1740
  startLiveState(e) {
1713
1741
  if (this.opts.liveStateEvents === !1) return;
1714
- let n = this.opts.eventsBaseUrl ?? T(this.opts.baseUrl);
1742
+ let n = this.opts.eventsBaseUrl ?? w(this.opts.baseUrl);
1715
1743
  if (!n) return;
1716
1744
  this.closeLiveState();
1717
1745
  let r = 0, i = !1;
1718
- this.liveStateSub = w({
1746
+ this.liveStateSub = C({
1719
1747
  eventsBaseUrl: n,
1720
1748
  matchUrn: this.opts.matchUrn,
1721
1749
  credential: this.opts.credential,
@@ -1726,7 +1754,7 @@ var We = class {
1726
1754
  r = 0, i = !1;
1727
1755
  },
1728
1756
  onError: () => {
1729
- this.destroyed || e !== this.loadGen || i || (r += 1, r >= Ve && (i = !0, this.emit("warning", new t("NETWORK", 0, `live-state events unreachable at ${n} 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.`))));
1757
+ this.destroyed || e !== this.loadGen || i || (r += 1, r >= Z && (i = !0, this.emit("warning", new t("NETWORK", 0, `live-state events unreachable at ${n} 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.`))));
1730
1758
  }
1731
1759
  });
1732
1760
  }
@@ -1748,7 +1776,7 @@ var We = class {
1748
1776
  }
1749
1777
  t.controls = !1;
1750
1778
  let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
1751
- r && r.insertBefore(n, t), n.appendChild(t), K(n, this.opts.theme), this.container = n, this.controlBar = Pe({
1779
+ r && r.insertBefore(n, t), n.appendChild(t), K(n, this.opts.theme), this.container = n, this.controlBar = Le({
1752
1780
  root: n,
1753
1781
  video: t,
1754
1782
  player: this,
@@ -1771,7 +1799,7 @@ var We = class {
1771
1799
  }
1772
1800
  startStats() {
1773
1801
  this.stopStats();
1774
- let e = Math.max(500, this.opts.statsIntervalMs ?? He);
1802
+ let e = Math.max(500, this.opts.statsIntervalMs ?? We);
1775
1803
  this.statsTimer = setInterval(() => {
1776
1804
  this.engine && this.emit("stats", this.engine.getStats());
1777
1805
  }, e);
@@ -1781,7 +1809,7 @@ var We = class {
1781
1809
  }
1782
1810
  scheduleLicenseRefresh() {
1783
1811
  this.stopRefresh();
1784
- let e = this.opts.licenseRefreshMs ?? Ue;
1812
+ let e = this.opts.licenseRefreshMs ?? Ge;
1785
1813
  !e || !this._descriptor?.drmEnabled || (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
1786
1814
  }
1787
1815
  stopRefresh() {
@@ -1790,7 +1818,7 @@ var We = class {
1790
1818
  async refreshLicense() {
1791
1819
  let e = this.engine;
1792
1820
  if (!(this.destroyed || !e)) try {
1793
- let t = await y(this.resolveOptions());
1821
+ let t = await v(this.resolveOptions());
1794
1822
  if (this.destroyed || this.engine !== e) return;
1795
1823
  let n = t.drm?.widevine?.licenseUrl, r = t.drm?.fairplay?.licenseUrl;
1796
1824
  (n || r) && (e.setLicenseUrls({
@@ -1818,7 +1846,7 @@ var We = class {
1818
1846
  this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
1819
1847
  }
1820
1848
  getStats() {
1821
- return this.engine?.getStats() ?? L;
1849
+ return this.engine?.getStats() ?? I;
1822
1850
  }
1823
1851
  getQualityLevels() {
1824
1852
  return this.engine?.getQualityLevels() ?? [];
@@ -1864,7 +1892,7 @@ var We = class {
1864
1892
  let e = ++this.loadGen;
1865
1893
  this.stopStats(), this.stopRefresh(), this.closeArming(), this.closeLiveState(), this.detachMedia?.(), this.engine?.destroy(), this.engine = null;
1866
1894
  try {
1867
- let t = await b({
1895
+ let t = await y({
1868
1896
  ...this.resolveOptions(),
1869
1897
  waitForLive: this.opts.waitForLive ? this.buildWaitConfig(e) : void 0
1870
1898
  });
@@ -1914,12 +1942,12 @@ var We = class {
1914
1942
  };
1915
1943
  //#endregion
1916
1944
  //#region src/embed/protocol.ts
1917
- function Q(e) {
1945
+ function $(e) {
1918
1946
  return !!e && typeof e == "object" && typeof e.type == "string" && e.type.startsWith("oddin:");
1919
1947
  }
1920
1948
  //#endregion
1921
1949
  //#region src/embed/host.ts
1922
- function $(e) {
1950
+ function qe(e) {
1923
1951
  if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
1924
1952
  if (!e.src) throw Error("mountEmbed: opts.src is required");
1925
1953
  if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
@@ -1928,7 +1956,7 @@ function $(e) {
1928
1956
  let r = document.createElement("iframe");
1929
1957
  r.src = t.toString(), r.allow = "autoplay; encrypted-media; fullscreen", r.setAttribute("allowfullscreen", ""), r.referrerPolicy = "no-referrer", r.setAttribute("sandbox", e.sandbox ?? "allow-scripts allow-same-origin allow-presentation"), r.style.cssText = "border:0;width:100%;height:100%;display:block", e.container.appendChild(r);
1930
1958
  let i = /* @__PURE__ */ new Set(), a = (t) => {
1931
- if (t.source !== r.contentWindow || t.origin !== n || !Q(t.data)) return;
1959
+ if (t.source !== r.contentWindow || t.origin !== n || !$(t.data)) return;
1932
1960
  let a = t.data;
1933
1961
  a.type === "oddin:ready" && a.protocol !== 1 && console.warn(`havik-player: embed protocol v${a.protocol} != host v1. Pin the embed page version to the SDK version to avoid skew.`), e.onEvent?.(a), i.forEach((e) => e(a));
1934
1962
  };
@@ -1978,8 +2006,8 @@ function $(e) {
1978
2006
  }
1979
2007
  //#endregion
1980
2008
  //#region src/embed/page.ts
1981
- var Ge = /^[A-Za-z0-9:_.-]{1,128}$/;
1982
- function Ke() {
2009
+ var Je = /^[A-Za-z0-9:_.-]{1,128}$/;
2010
+ function Ye() {
1983
2011
  let e = window.HAVIK_EMBED_CONFIG;
1984
2012
  if (e) return {
1985
2013
  baseUrl: e.baseUrl ?? "",
@@ -2001,9 +2029,9 @@ function Ke() {
2001
2029
  waitForLive: !0
2002
2030
  };
2003
2031
  }
2004
- async function qe() {
2005
- let e = Ke();
2006
- Ye();
2032
+ async function Xe() {
2033
+ let e = Ye();
2034
+ Qe();
2007
2035
  let n = document.createElement("video");
2008
2036
  n.setAttribute("playsinline", ""), n.muted = e.muted ?? !0, n.style.cssText = "width:100%;height:100%;object-fit:contain;background:#000;aspect-ratio:auto", document.body.appendChild(n);
2009
2037
  let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
@@ -2058,12 +2086,12 @@ async function qe() {
2058
2086
  code: e.code,
2059
2087
  message: e.message
2060
2088
  })), e.on("autoplayblocked", () => {
2061
- i({ type: "oddin:autoplayblocked" }), Je(n, e);
2089
+ i({ type: "oddin:autoplayblocked" }), Ze(n, e);
2062
2090
  });
2063
2091
  }, s = async (r) => {
2064
2092
  a?.destroy(), a = null;
2065
2093
  try {
2066
- let t = await Z({
2094
+ let t = await Q({
2067
2095
  video: n,
2068
2096
  baseUrl: e.baseUrl,
2069
2097
  matchUrn: r,
@@ -2124,32 +2152,32 @@ async function qe() {
2124
2152
  a?.retry();
2125
2153
  break;
2126
2154
  case "oddin:load":
2127
- typeof e.matchUrn == "string" && Ge.test(e.matchUrn) && s(e.matchUrn);
2155
+ typeof e.matchUrn == "string" && Je.test(e.matchUrn) && s(e.matchUrn);
2128
2156
  break;
2129
2157
  case "oddin:destroy":
2130
2158
  c();
2131
2159
  break;
2132
2160
  }
2133
2161
  }, u = (e) => {
2134
- !r || e.origin !== r || Q(e.data) && l(e.data);
2162
+ !r || e.origin !== r || $(e.data) && l(e.data);
2135
2163
  };
2136
2164
  r && window.addEventListener("message", u), window.addEventListener("pagehide", c, { once: !0 }), await s(e.matchUrn), i({
2137
2165
  type: "oddin:ready",
2138
2166
  protocol: 1
2139
2167
  });
2140
2168
  }
2141
- function Je(e, t) {
2169
+ function Ze(e, t) {
2142
2170
  if (document.getElementById("havik-tap")) return;
2143
2171
  let n = document.createElement("button");
2144
2172
  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", () => {
2145
2173
  n.remove(), t.play();
2146
2174
  }), document.body.appendChild(n);
2147
2175
  }
2148
- function Ye() {
2176
+ function Qe() {
2149
2177
  let e = document.createElement("style");
2150
2178
  e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
2151
2179
  }
2152
2180
  //#endregion
2153
- export { W as ODDIN_THEME, t as PlaybackError, K as applyTheme, qe as bootEmbed, de as clearDeviceId, Z as createPlayer, T as deriveEventsBaseUrl, P as detectDrmSupport, C as fetchCatalog, se as fetchTournament, le as flattenMatches, O as getDeviceId, I as isLowLatencyManifest, Q as isOddinMessage, pe as licenseRequestHeaders, $ as mountEmbed, v as pollToLive, b as resolveStream, w as subscribeLiveState, ue as watchStatus };
2181
+ export { W as ODDIN_THEME, t as PlaybackError, K as applyTheme, Xe as bootEmbed, fe as clearDeviceId, Q as createPlayer, w as deriveEventsBaseUrl, N as detectDrmSupport, S as fetchCatalog, ce as fetchTournament, ue as flattenMatches, D as getDeviceId, F as isLowLatencyManifest, $ as isOddinMessage, me as licenseRequestHeaders, qe as mountEmbed, _ as pollToLive, y as resolveStream, C as subscribeLiveState, de as watchStatus };
2154
2182
 
2155
2183
  //# sourceMappingURL=index.js.map