@oddin-gg/havik-player 2.11.0 → 2.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -110,42 +110,48 @@ function m(e) {
110
110
  return e instanceof Error ? e.message : String(e);
111
111
  }
112
112
  //#endregion
113
+ //#region src/core/warnOnce.ts
114
+ var h = /* @__PURE__ */ new Set();
115
+ function g(e, t = e) {
116
+ h.has(t) || (h.add(t), console.warn(`havik-player: ${e}`));
117
+ }
118
+ //#endregion
113
119
  //#region src/core/waitForLive.ts
114
- var h = 1e3, g = 3e4, _ = 6e5, ee = 3e5, te = 1e3, ne = {
120
+ var _ = 1e3, ee = 3e4, te = 6e5, ne = 3e5, re = 1e3, ie = {
115
121
  TOO_EARLY: "tooEarly",
116
122
  UNAVAILABLE: "unavailable",
117
123
  RATE_LIMITED: "rateLimited",
118
124
  NETWORK: "network"
119
125
  };
120
- function re(e) {
121
- let t = e === !0 || e === !1 ? {} : e, n = Math.max(te, t.floorMs ?? h), r = Math.max(n, t.ceilMs ?? g), i = Math.max(0, t.imminentMs ?? _), a = Math.max(r, t.sanityFloorMs ?? ee);
126
+ function ae(e) {
127
+ let t = e === !0 || e === !1 ? {} : e, n = Math.max(re, t.floorMs ?? _), r = Math.max(n, t.ceilMs ?? ee), i = Math.max(0, t.imminentMs ?? te), a = Math.max(r, t.sanityFloorMs ?? ne);
122
128
  return {
123
129
  timeoutMs: t.timeoutMs,
124
130
  floorMs: n,
125
131
  ceilMs: r,
126
132
  imminentMs: i,
127
133
  sanityFloorMs: a,
128
- kickoffMs: ie(t.kickoffAt),
134
+ kickoffMs: oe(t.kickoffAt),
129
135
  jitter: t.jitter ?? !0,
130
136
  onState: t.onState
131
137
  };
132
138
  }
133
- function ie(e) {
139
+ function oe(e) {
134
140
  if (e == null) return;
135
141
  if (typeof e == "number") return Number.isFinite(e) ? e : void 0;
136
142
  let t = Date.parse(e);
137
143
  return Number.isFinite(t) ? t : void 0;
138
144
  }
139
- function ae(e, t, n) {
145
+ function se(e, t, n) {
140
146
  return Math.min(n, Math.max(t, e));
141
147
  }
142
- function oe(e) {
148
+ function ce(e) {
143
149
  return Math.round(e * (1 + .15 * Math.random()));
144
150
  }
145
- function se(e, t, n, r) {
151
+ function le(e, t, n, r) {
146
152
  let i = r ?? n.kickoffMs, a = i == null ? void 0 : Math.max(0, i - t), o = Math.max(n.floorMs, e ?? 0);
147
153
  if (a == null || a <= n.imminentMs) return {
148
- delay: ae(e ?? n.floorMs, o, n.ceilMs),
154
+ delay: se(e ?? n.floorMs, o, n.ceilMs),
149
155
  ttkMs: a
150
156
  };
151
157
  let s = Math.min(Math.floor(a / 10), n.sanityFloorMs, a);
@@ -154,7 +160,7 @@ function se(e, t, n, r) {
154
160
  ttkMs: a
155
161
  };
156
162
  }
157
- function ce(e, t) {
163
+ function ue(e, t) {
158
164
  return new Promise((r, i) => {
159
165
  if (t?.aborted) {
160
166
  i(new n("ABORTED", 0, "wait-for-live aborted"));
@@ -168,8 +174,8 @@ function ce(e, t) {
168
174
  t?.addEventListener("abort", a, { once: !0 });
169
175
  });
170
176
  }
171
- async function v(e, t, r) {
172
- let i = re(t), a = Date.now(), s = i.timeoutMs == null ? Infinity : a + i.timeoutMs, c = 0, l;
177
+ async function de(e, t, r) {
178
+ let i = ae(t), a = Date.now(), s = i.timeoutMs == null ? Infinity : a + i.timeoutMs, c = 0, l;
173
179
  for (;;) {
174
180
  if (r?.aborted) throw new n("ABORTED", 0, "wait-for-live aborted");
175
181
  try {
@@ -177,38 +183,38 @@ async function v(e, t, r) {
177
183
  } catch (e) {
178
184
  if (!(e instanceof n) || !o(e.code)) throw e;
179
185
  c += 1, e.liveStartsAtMs != null && Number.isFinite(e.liveStartsAtMs) && (l = e.liveStartsAtMs);
180
- let t = Date.now(), u = se(e.retryAfterMs, t, i, l), d = u.ttkMs, f = u.delay;
181
- if (i.jitter && (f = oe(f)), t + f > s) throw new n("TIMEOUT", e.httpStatus, `timed out after ${i.timeoutMs}ms waiting for the stream to go live`, {
186
+ let t = Date.now(), u = le(e.retryAfterMs, t, i, l), d = u.ttkMs, f = u.delay;
187
+ if (i.jitter && (f = ce(f)), t + f > s) throw new n("TIMEOUT", e.httpStatus, `timed out after ${i.timeoutMs}ms waiting for the stream to go live`, {
182
188
  retryAfterMs: e.retryAfterMs,
183
189
  cause: e
184
190
  });
185
191
  i.onState?.({
186
- phase: ne[e.code] ?? "unavailable",
192
+ phase: ie[e.code] ?? "unavailable",
187
193
  retryInMs: f,
188
194
  attempt: c,
189
195
  elapsedMs: t - a,
190
196
  ttkMs: d
191
- }), await ce(f, r);
197
+ }), await ue(f, r);
192
198
  }
193
199
  }
194
200
  }
195
201
  //#endregion
196
202
  //#region src/core/resolve.ts
197
- async function y(e) {
203
+ async function v(e) {
198
204
  if (!e.matchUrn || typeof e.matchUrn != "string") throw new n("INVALID_URN", 0, "resolveStream: a non-empty matchUrn is required");
199
205
  let t = await p(d(e.baseUrl, `/v1/playback/${encodeURIComponent(e.matchUrn)}`), {
200
206
  credential: e.credential,
201
207
  signal: e.signal,
202
208
  apiHeaders: e.apiHeaders
203
209
  });
204
- if (!t.ok) throw await le(t);
205
- return de(await t.json(), e.matchUrn);
210
+ if (!t.ok) throw await fe(t);
211
+ return he(await t.json(), e.matchUrn);
206
212
  }
207
- function b(e) {
208
- let t = () => y(e);
209
- 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();
210
216
  }
211
- async function le(e) {
217
+ async function fe(e) {
212
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;
213
219
  try {
214
220
  let t = await e.json();
@@ -224,7 +230,7 @@ async function le(e) {
224
230
  liveStartsAtMs: s
225
231
  });
226
232
  }
227
- var ue = /* @__PURE__ */ new Set([
233
+ var pe = /* @__PURE__ */ new Set([
228
234
  "matchUrn",
229
235
  "protocol",
230
236
  "drmEnabled",
@@ -235,7 +241,7 @@ var ue = /* @__PURE__ */ new Set([
235
241
  "expiresAt",
236
242
  "analytics"
237
243
  ]);
238
- function x(e, t) {
244
+ function b(e, t) {
239
245
  let r;
240
246
  try {
241
247
  r = new URL(t);
@@ -245,57 +251,71 @@ function x(e, t) {
245
251
  if (r.protocol !== "https:" && r.protocol !== "http:") throw new n("INTERNAL", 0, `playback ${e} has a disallowed scheme: ${r.protocol}`);
246
252
  return t;
247
253
  }
248
- function de(e, t) {
254
+ function me(e) {
255
+ if (e !== void 0) {
256
+ if (typeof e == "string" && !e.endsWith("/")) try {
257
+ let t = new URL(e);
258
+ if (t.protocol === "https:" && t.href === `${t.origin}/`) return t.origin;
259
+ } catch {}
260
+ g(`server analytics.endpoint ${JSON.stringify(e)} ignored: not a bare https origin.`);
261
+ }
262
+ }
263
+ function he(e, t) {
249
264
  if (!e.manifestUrl) throw new n("INTERNAL", 0, "playback response is missing manifestUrl");
250
265
  let r = e.drmEnabled ?? !!e.drm, i = {
251
266
  matchUrn: e.matchUrn ?? t,
252
267
  protocol: "hls",
253
268
  drmEnabled: r,
254
- manifestUrl: x("manifestUrl", e.manifestUrl),
269
+ manifestUrl: b("manifestUrl", e.manifestUrl),
255
270
  serverTime: e.serverTime ?? ""
256
271
  };
257
- if (e.liveStartsAt && (i.liveStartsAt = e.liveStartsAt), typeof e.analytics?.sid == "string" && e.analytics.sid && (i.analytics = { sid: e.analytics.sid }), r && e.drm) {
272
+ if (e.liveStartsAt && (i.liveStartsAt = e.liveStartsAt), typeof e.analytics?.sid == "string" && e.analytics.sid) {
273
+ i.analytics = { sid: e.analytics.sid };
274
+ let t = me(e.analytics.endpoint);
275
+ t && (i.analytics.endpoint = t);
276
+ }
277
+ if (r && e.drm) {
258
278
  let t = {};
259
- e.drm.widevine?.licenseUrl && (t.widevine = { licenseUrl: x("widevine licenseUrl", e.drm.widevine.licenseUrl) }), e.drm.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && (t.fairplay = {
260
- licenseUrl: x("fairplay licenseUrl", e.drm.fairplay.licenseUrl),
261
- 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)
262
282
  }), (t.widevine || t.fairplay) && (i.drm = t);
263
283
  }
264
284
  let a = {};
265
- for (let [t, n] of Object.entries(e)) ue.has(t) || (a[t] = n);
285
+ for (let [t, n] of Object.entries(e)) pe.has(t) || (a[t] = n);
266
286
  return Object.keys(a).length > 0 && (i.extensions = a), i;
267
287
  }
268
288
  //#endregion
269
289
  //#region src/core/fullscreen.ts
270
- function fe(e) {
290
+ function ge(e) {
271
291
  return e.ownerDocument ?? document;
272
292
  }
273
- function S(e) {
293
+ function _e(e) {
274
294
  return e.fullscreenElement ?? e.webkitFullscreenElement ?? null;
275
295
  }
276
- function C(e, t) {
277
- let n = S(fe(e));
296
+ function x(e, t) {
297
+ let n = _e(ge(e));
278
298
  return n != null && (n === e || t != null && n === t) || e.webkitDisplayingFullscreen === !0;
279
299
  }
280
- async function w(e, t) {
300
+ async function S(e, t) {
281
301
  let n = t ?? e;
282
302
  if (typeof n.requestFullscreen == "function") return await n.requestFullscreen(), !0;
283
303
  if (typeof n.webkitRequestFullscreen == "function") return n.webkitRequestFullscreen(), !0;
284
304
  let r = e;
285
305
  return r.webkitSupportsFullscreen && typeof r.webkitEnterFullscreen == "function" ? (r.webkitEnterFullscreen(), !0) : !1;
286
306
  }
287
- async function T(e, t) {
307
+ async function C(e, t) {
288
308
  let n = e;
289
309
  if (n.webkitDisplayingFullscreen) {
290
310
  n.webkitExitFullscreen?.();
291
311
  return;
292
312
  }
293
- let r = fe(e), i = S(r);
313
+ let r = ge(e), i = _e(r);
294
314
  i != null && (i === e || t != null && i === t) && (typeof r.exitFullscreen == "function" ? await r.exitFullscreen() : r.webkitExitFullscreen?.());
295
315
  }
296
316
  //#endregion
297
317
  //#region src/core/catalog.ts
298
- async function pe(e) {
318
+ async function ve(e) {
299
319
  let t = new URLSearchParams();
300
320
  e.status && t.set("status", Array.isArray(e.status) ? e.status.join(",") : e.status), e.sport && t.set("sport", e.sport);
301
321
  let i = t.toString(), a = d(e.baseUrl, "/v1/catalog" + (i ? `?${i}` : "")), o = new Headers();
@@ -313,12 +333,12 @@ async function pe(e) {
313
333
  };
314
334
  if (!s.ok) throw new n(r(s.status), s.status, `catalog request failed (HTTP ${s.status})`);
315
335
  return {
316
- tournaments: me(await s.json()),
336
+ tournaments: ye(await s.json()),
317
337
  etag: s.headers.get("etag") ?? void 0,
318
338
  notModified: !1
319
339
  };
320
340
  }
321
- function me(e) {
341
+ function ye(e) {
322
342
  return (e.tournaments ?? []).map((e) => {
323
343
  let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
324
344
  return {
@@ -340,7 +360,7 @@ function me(e) {
340
360
  };
341
361
  });
342
362
  }
343
- async function he(e) {
363
+ async function be(e) {
344
364
  let t = d(e.baseUrl, `/v1/tournaments/${encodeURIComponent(e.urn)}`), i = new Headers();
345
365
  e.etag && i.set("If-None-Match", e.etag);
346
366
  let a = await p(t, {
@@ -360,13 +380,13 @@ async function he(e) {
360
380
  };
361
381
  if (!a.ok) throw new n(r(a.status), a.status, `tournament request failed (HTTP ${a.status})`);
362
382
  return {
363
- tournament: ge(await a.json()),
383
+ tournament: xe(await a.json()),
364
384
  etag: a.headers.get("etag") ?? void 0,
365
385
  notModified: !1,
366
386
  notFound: !1
367
387
  };
368
388
  }
369
- function ge(e) {
389
+ function xe(e) {
370
390
  let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
371
391
  return {
372
392
  urn: t,
@@ -386,12 +406,12 @@ function ge(e) {
386
406
  }))
387
407
  };
388
408
  }
389
- function _e(e) {
409
+ function Se(e) {
390
410
  return e.tournaments.flatMap((e) => e.matches);
391
411
  }
392
412
  //#endregion
393
413
  //#region src/core/poll.ts
394
- function ve(e) {
414
+ function Ce(e) {
395
415
  let t = Math.max(2e3, e.intervalMs ?? 1e4), i = new AbortController(), a, o, s, u = !1, f = () => {
396
416
  u || (a = setTimeout(m, t));
397
417
  }, m = async () => {
@@ -433,9 +453,9 @@ function ve(e) {
433
453
  }
434
454
  //#endregion
435
455
  //#region src/core/events.ts
436
- var ye = 45e3;
437
- function E(e) {
438
- let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = e.idleTimeoutMs ?? ye, i = Number.isFinite(r) && r > 0 ? r : 0, a = new AbortController(), o = !1, c = (e) => new Promise((t) => {
456
+ var we = 45e3;
457
+ function w(e) {
458
+ let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = e.idleTimeoutMs ?? we, i = Number.isFinite(r) && r > 0 ? r : 0, a = new AbortController(), o = !1, c = (e) => new Promise((t) => {
439
459
  if (a.signal.aborted) return t();
440
460
  let n = setTimeout(t, e);
441
461
  a.signal.addEventListener("abort", () => {
@@ -516,7 +536,7 @@ function E(e) {
516
536
  o || (o = !0, a.abort());
517
537
  } };
518
538
  }
519
- function D(e) {
539
+ function T(e) {
520
540
  try {
521
541
  let t = new URL(e);
522
542
  return t.hostname = `events.${t.hostname}`, t.pathname = "", t.search = "", t.origin;
@@ -526,27 +546,27 @@ function D(e) {
526
546
  }
527
547
  //#endregion
528
548
  //#region src/core/drm/deviceId.ts
529
- var O = "havik.player.deviceId", k;
530
- function A() {
531
- if (k) return k;
549
+ var E = "havik.player.deviceId", D;
550
+ function O() {
551
+ if (D) return D;
532
552
  try {
533
- let e = globalThis.localStorage?.getItem(O);
534
- if (e) return k = e, e;
553
+ let e = globalThis.localStorage?.getItem(E);
554
+ if (e) return D = e, e;
535
555
  } catch {}
536
- let e = xe();
537
- k = e;
556
+ let e = Ee();
557
+ D = e;
538
558
  try {
539
- globalThis.localStorage?.setItem(O, e);
559
+ globalThis.localStorage?.setItem(E, e);
540
560
  } catch {}
541
561
  return e;
542
562
  }
543
- function be() {
544
- k = void 0;
563
+ function Te() {
564
+ D = void 0;
545
565
  try {
546
- globalThis.localStorage?.removeItem(O);
566
+ globalThis.localStorage?.removeItem(E);
547
567
  } catch {}
548
568
  }
549
- function xe() {
569
+ function Ee() {
550
570
  let e = globalThis.crypto;
551
571
  if (e && typeof e.randomUUID == "function") return e.randomUUID();
552
572
  let t = /* @__PURE__ */ new Uint8Array(16);
@@ -558,21 +578,21 @@ function xe() {
558
578
  }
559
579
  //#endregion
560
580
  //#region src/core/drm/headers.ts
561
- function Se(e, t, n = {}) {
581
+ function De(e, t, n = {}) {
562
582
  let r = {
563
583
  "x-api-key": t.apiKey,
564
584
  "X-Match-Urn": e.matchUrn,
565
- "X-Device-Id": n.deviceId ?? A(),
585
+ "X-Device-Id": n.deviceId ?? O(),
566
586
  "Content-Type": "application/octet-stream"
567
587
  };
568
588
  return n.userId && (r["X-User-Id"] = n.userId), r;
569
589
  }
570
590
  //#endregion
571
591
  //#region src/core/drm/cdm.ts
572
- var j = /* @__PURE__ */ new WeakMap();
573
- function Ce(e, t) {
574
- let n = j.get(e);
575
- n || (n = /* @__PURE__ */ new Map(), j.set(e, n));
592
+ var k = /* @__PURE__ */ new WeakMap();
593
+ function Oe(e, t) {
594
+ let n = k.get(e);
595
+ n || (n = /* @__PURE__ */ new Map(), k.set(e, n));
576
596
  let r = n.get(t.keySystem);
577
597
  if (r) return r;
578
598
  let i = t.createMediaKeys().catch((e) => {
@@ -580,22 +600,22 @@ function Ce(e, t) {
580
600
  });
581
601
  return n.set(t.keySystem, i), i;
582
602
  }
583
- function M() {
603
+ function A() {
584
604
  return typeof navigator < "u" && typeof navigator.requestMediaKeySystemAccess == "function";
585
605
  }
586
- var N = ["SW_SECURE_DECODE", "SW_SECURE_CRYPTO"];
587
- function we(e) {
606
+ var j = ["SW_SECURE_DECODE", "SW_SECURE_CRYPTO"];
607
+ function ke(e) {
588
608
  return e.startsWith("com.widevine");
589
609
  }
590
- function P(e, t) {
591
- if (!we(e)) return t;
610
+ function M(e, t) {
611
+ if (!ke(e)) return t;
592
612
  let n = (e, t) => {
593
613
  let n = e.videoCapabilities;
594
614
  return !n?.length || !n.some((e) => e.robustness) ? !1 : n.every((e) => {
595
- let n = N.indexOf(e.robustness);
596
- return n === -1 || N.indexOf(t) > n;
615
+ let n = j.indexOf(e.robustness);
616
+ return n === -1 || j.indexOf(t) > n;
597
617
  });
598
- }, r = N.flatMap((e) => t.filter((t) => n(t, e)).map((t) => ({
618
+ }, r = j.flatMap((e) => t.filter((t) => n(t, e)).map((t) => ({
599
619
  ...t,
600
620
  videoCapabilities: t.videoCapabilities?.map((t) => ({
601
621
  ...t,
@@ -604,41 +624,87 @@ function P(e, t) {
604
624
  })));
605
625
  return [...t, ...r];
606
626
  }
607
- function Te(e) {
608
- return (t, n) => M() ? navigator.requestMediaKeySystemAccess(t, P(t, n)).then((t) => ({
627
+ function N(e) {
628
+ return (t, n) => A() ? navigator.requestMediaKeySystemAccess(t, M(t, n)).then((t) => ({
609
629
  keySystem: t.keySystem,
610
630
  getConfiguration: () => t.getConfiguration(),
611
- createMediaKeys: () => Ce(e, t)
631
+ createMediaKeys: () => Oe(e, t)
612
632
  })) : Promise.reject(/* @__PURE__ */ Error("navigator.requestMediaKeySystemAccess is unavailable — EME needs a secure context (https, or localhost)"));
613
633
  }
614
- var F = {
634
+ var P = {
615
635
  video: "SW_SECURE_DECODE",
616
636
  audio: "SW_SECURE_CRYPTO",
617
637
  scheme: "cbcs"
618
638
  };
619
- function Ee(e) {
620
- if (!M()) return;
639
+ function Ae(e) {
640
+ if (!A()) return;
621
641
  let t = (e, t) => ({
622
642
  contentType: e,
623
643
  robustness: t,
624
- encryptionScheme: F.scheme
644
+ encryptionScheme: P.scheme
625
645
  });
626
- Te(e)("com.widevine.alpha", [{
646
+ N(e)("com.widevine.alpha", [{
627
647
  initDataTypes: ["cenc"],
628
648
  distinctiveIdentifier: "optional",
629
649
  persistentState: "optional",
630
650
  sessionTypes: ["temporary"],
631
- audioCapabilities: [t("audio/mp4; codecs=\"mp4a.40.2\"", F.audio)],
632
- videoCapabilities: [t("video/mp4; codecs=\"avc1.42e01e\"", F.video)]
651
+ audioCapabilities: [t("audio/mp4; codecs=\"mp4a.40.2\"", P.audio)],
652
+ videoCapabilities: [t("video/mp4; codecs=\"avc1.42e01e\"", P.video)]
633
653
  }]).then((e) => e.createMediaKeys()).catch(() => {});
634
654
  }
655
+ function F(e) {
656
+ let t = I(e);
657
+ if (/^avc[13]/.test(t)) return "avc";
658
+ if (/^(hvc1|hev1)/.test(t)) return "hevc";
659
+ if (/^(dvh1|dvhe)/.test(t)) return "dv";
660
+ if (t.startsWith("av01")) return "av1";
661
+ if (/^vp0?9/.test(t)) return "vp9";
662
+ }
663
+ function I(e) {
664
+ return (e ?? "").trim().toLowerCase();
665
+ }
666
+ var je = {
667
+ hevc: "hvc1.1.6.L93.90",
668
+ dv: "dvh1.05.06",
669
+ av1: "av01.0.05M.08",
670
+ vp9: "vp09.00.10.08"
671
+ }, Me = /* @__PURE__ */ new Map(), L = /* @__PURE__ */ new Map();
672
+ function Ne(e) {
673
+ let t = I(e), n = Me.get(t);
674
+ if (n) return n;
675
+ let r = {
676
+ initDataTypes: ["cenc"],
677
+ distinctiveIdentifier: "optional",
678
+ persistentState: "optional",
679
+ sessionTypes: ["temporary"],
680
+ videoCapabilities: [{
681
+ contentType: `video/mp4; codecs="${e.trim()}"`,
682
+ robustness: P.video,
683
+ encryptionScheme: P.scheme
684
+ }]
685
+ }, i = (async () => {
686
+ try {
687
+ return await navigator.requestMediaKeySystemAccess("com.widevine.alpha", M("com.widevine.alpha", [r])), !0;
688
+ } catch {
689
+ return !1;
690
+ }
691
+ })().then((e) => (L.set(t, e), e));
692
+ return Me.set(t, i), i;
693
+ }
694
+ function Pe() {
695
+ if (A()) for (let e of Object.values(je)) Ne(e);
696
+ }
697
+ function Fe(e) {
698
+ let t = F(e);
699
+ if (t) return t === "avc" ? !0 : L.get(I(e)) ?? L.get(I(je[t]));
700
+ }
635
701
  //#endregion
636
702
  //#region src/core/drm/support.ts
637
- var De = 5e3, Oe = "video/mp4; codecs=\"avc1.42E01E\"", ke = "audio/mp4; codecs=\"mp4a.40.2\"", Ae = {
703
+ var Ie = 5e3, R = "video/mp4; codecs=\"avc1.42E01E\"", z = "audio/mp4; codecs=\"mp4a.40.2\"", Le = {
638
704
  widevine: ["com.widevine.alpha"],
639
705
  fairplay: ["com.apple.fps"]
640
706
  };
641
- function je(e) {
707
+ function Re(e) {
642
708
  return e === "fairplay" ? [{
643
709
  initDataTypes: [
644
710
  "sinf",
@@ -646,30 +712,30 @@ function je(e) {
646
712
  "cenc"
647
713
  ],
648
714
  videoCapabilities: [{
649
- contentType: Oe,
715
+ contentType: R,
650
716
  robustness: "",
651
717
  encryptionScheme: "cbcs"
652
718
  }],
653
719
  audioCapabilities: [{
654
- contentType: ke,
720
+ contentType: z,
655
721
  robustness: "",
656
722
  encryptionScheme: "cbcs"
657
723
  }]
658
- }] : P("com.widevine.alpha", [{
724
+ }] : M("com.widevine.alpha", [{
659
725
  initDataTypes: ["cenc"],
660
726
  videoCapabilities: [{
661
- contentType: Oe,
662
- robustness: F.video,
663
- encryptionScheme: F.scheme
727
+ contentType: R,
728
+ robustness: P.video,
729
+ encryptionScheme: P.scheme
664
730
  }],
665
731
  audioCapabilities: [{
666
- contentType: ke,
667
- robustness: F.audio,
668
- encryptionScheme: F.scheme
732
+ contentType: z,
733
+ robustness: P.audio,
734
+ encryptionScheme: P.scheme
669
735
  }]
670
736
  }]);
671
737
  }
672
- function Me(e, t) {
738
+ function B(e, t) {
673
739
  return new Promise((n, r) => {
674
740
  let i = setTimeout(() => r(/* @__PURE__ */ Error("probe-timeout")), t);
675
741
  e.then((e) => {
@@ -679,8 +745,8 @@ function Me(e, t) {
679
745
  });
680
746
  });
681
747
  }
682
- async function Ne(e = {}) {
683
- let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? De, r = {};
748
+ async function ze(e = {}) {
749
+ let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Ie, r = {};
684
750
  if (typeof window < "u" && window.isSecureContext === !1) return {
685
751
  verdict: "insecure-context",
686
752
  detail: r
@@ -692,7 +758,7 @@ async function Ne(e = {}) {
692
758
  };
693
759
  let a = !1, o = !1, s = Date.now() + n, c = () => Math.max(1, s - Date.now());
694
760
  for (let e of t) {
695
- let t = Ae[e];
761
+ let t = Le[e];
696
762
  if (!t) {
697
763
  r[e] = "unknown system";
698
764
  continue;
@@ -703,7 +769,7 @@ async function Ne(e = {}) {
703
769
  break;
704
770
  }
705
771
  try {
706
- return await Me((await Me(i(n, je(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
772
+ return await B((await B(i(n, Re(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
707
773
  verdict: "supported",
708
774
  system: e,
709
775
  detail: r
@@ -727,49 +793,49 @@ async function Ne(e = {}) {
727
793
  }
728
794
  //#endregion
729
795
  //#region src/core/manifest.ts
730
- var Pe = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
731
- function Fe(e) {
732
- return Pe.test(e);
796
+ var Be = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
797
+ function Ve(e) {
798
+ return Be.test(e);
733
799
  }
734
800
  //#endregion
735
801
  //#region src/core/env.ts
736
- var I = {
802
+ var V = {
737
803
  integration: "https://feed-dev.oddin-video.gg",
738
804
  production: "https://feed.oddin-video.gg"
739
805
  };
740
- function L(e) {
741
- let t = Object.prototype.hasOwnProperty.call(I, e) ? I[e] : void 0;
806
+ function H(e) {
807
+ let t = Object.prototype.hasOwnProperty.call(V, e) ? V[e] : void 0;
742
808
  if (!t) throw new n("INTERNAL", 0, `unknown env ${JSON.stringify(e)} — expected 'integration' or 'production'`);
743
809
  return t;
744
810
  }
745
811
  //#endregion
746
812
  //#region src/core/stats.ts
747
- var R = { droppedFrames: 0 };
748
- function z(e) {
813
+ var U = { droppedFrames: 0 };
814
+ function W(e) {
749
815
  try {
750
816
  return new URL(e).host;
751
817
  } catch {
752
818
  return "";
753
819
  }
754
820
  }
755
- var Ie = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
756
- function Le(e) {
821
+ var He = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
822
+ function Ue(e) {
757
823
  if (typeof performance > "u" || typeof performance.getEntriesByType != "function") return "";
758
824
  let t = "", n = -1, r = performance.getEntriesByType("resource");
759
- for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || Ie.test(i.name)) && i.startTime >= n) {
760
- let e = z(i.name);
825
+ for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || He.test(i.name)) && i.startTime >= n) {
826
+ let e = W(i.name);
761
827
  e && (t = e, n = i.startTime);
762
828
  }
763
829
  return t;
764
830
  }
765
- function B(e) {
831
+ function G(e) {
766
832
  let t = e.getVideoPlaybackQuality?.();
767
833
  return {
768
834
  dropped: t?.droppedVideoFrames ?? 0,
769
835
  totalFrames: t?.totalVideoFrames ?? 0
770
836
  };
771
837
  }
772
- function Re(e, t) {
838
+ function We(e, t) {
773
839
  let n = [
774
840
  ["playing", () => t("playing")],
775
841
  ["waiting", () => t("buffering")],
@@ -786,7 +852,7 @@ function Re(e, t) {
786
852
  }
787
853
  //#endregion
788
854
  //#region src/core/engine/native.ts
789
- function ze(e) {
855
+ function Ge(e) {
790
856
  try {
791
857
  let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
792
858
  return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
@@ -794,15 +860,15 @@ function ze(e) {
794
860
  return;
795
861
  }
796
862
  }
797
- function V(e) {
863
+ function K(e) {
798
864
  return !!(e ?? (typeof document < "u" ? document.createElement("video") : void 0))?.canPlayType("application/vnd.apple.mpegurl");
799
865
  }
800
- function H() {
866
+ function q() {
801
867
  if (typeof window > "u") return !1;
802
868
  let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
803
869
  return e || t;
804
870
  }
805
- var U = class {
871
+ var J = class {
806
872
  name = "native";
807
873
  deps;
808
874
  onLoaded;
@@ -838,7 +904,7 @@ var U = class {
838
904
  type: "error",
839
905
  error: new n("INTERNAL", 0, "native HLS playback error"),
840
906
  fatal: !0
841
- }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = Be(t.manifestUrl, t.analytics?.sid), e.load();
907
+ }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = Ke(t.manifestUrl, t.analytics?.sid), e.load();
842
908
  }
843
909
  startLoad() {
844
910
  this.loadStarted || (this.loadStarted = !0, this.restorePreload());
@@ -860,7 +926,7 @@ var U = class {
860
926
  });
861
927
  this.onEncrypted = (n) => {
862
928
  let i = n;
863
- i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = ze(i.initData), (async () => {
929
+ i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = Ge(i.initData), (async () => {
864
930
  try {
865
931
  let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
866
932
  initDataTypes: [i.initDataType],
@@ -955,11 +1021,11 @@ var U = class {
955
1021
  e.seekable.length > 0 && (e.currentTime = e.seekable.end(e.seekable.length - 1));
956
1022
  }
957
1023
  getStats() {
958
- let e = this.deps.video, t = B(e), n = {
1024
+ let e = this.deps.video, t = G(e), n = {
959
1025
  droppedFrames: t.dropped,
960
1026
  decodedFrames: t.totalFrames
961
1027
  };
962
- return this.cdnHost ||= Le(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;
1028
+ return this.cdnHost ||= Ue(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;
963
1029
  }
964
1030
  stop() {
965
1031
  try {
@@ -978,13 +1044,13 @@ var U = class {
978
1044
  } catch {}
979
1045
  }
980
1046
  };
981
- function Be(e, t) {
1047
+ function Ke(e, t) {
982
1048
  return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
983
1049
  }
984
1050
  //#endregion
985
1051
  //#region src/core/engine/prefetch.ts
986
- var Ve = 15e3, He = 5e3, Ue = 6;
987
- function W(e) {
1052
+ var qe = 15e3, Je = 5e3, Ye = 6;
1053
+ function Xe(e) {
988
1054
  try {
989
1055
  let t = new URL(e);
990
1056
  return t.searchParams.delete("CMCD"), t.toString();
@@ -992,7 +1058,7 @@ function W(e) {
992
1058
  return e;
993
1059
  }
994
1060
  }
995
- var We = class {
1061
+ var Ze = class {
996
1062
  cmcd;
997
1063
  entries = /* @__PURE__ */ new Map();
998
1064
  keyed = /* @__PURE__ */ new Set();
@@ -1015,10 +1081,10 @@ var We = class {
1015
1081
  }
1016
1082
  prefetch(e, t, n) {
1017
1083
  if (!this.isActive(t)) return;
1018
- let r = W(e);
1084
+ let r = Xe(e);
1019
1085
  if (this.entries.has(r)) return;
1020
1086
  let i = this.perTrack.get(t) ?? 0;
1021
- if (i >= Ue) return;
1087
+ if (i >= Ye) return;
1022
1088
  this.perTrack.set(t, i + 1);
1023
1089
  let a = new AbortController(), o = {
1024
1090
  started: performance.now(),
@@ -1032,10 +1098,10 @@ var We = class {
1032
1098
  signal: a.signal
1033
1099
  }).then(async (e) => (o.first = performance.now(), e.ok ? e.arrayBuffer() : null)).catch(() => null), this.entries.set(r, o), this.stats.started += 1, setTimeout(() => {
1034
1100
  this.entries.get(r) === o && (this.entries.delete(r), a.abort(), this.stats.expired += 1);
1035
- }, Ve);
1101
+ }, qe);
1036
1102
  }
1037
1103
  take(e) {
1038
- let t = W(e), n = this.entries.get(t);
1104
+ let t = Xe(e), n = this.entries.get(t);
1039
1105
  return n && this.entries.delete(t), n;
1040
1106
  }
1041
1107
  destroy() {
@@ -1055,13 +1121,13 @@ var We = class {
1055
1121
  }
1056
1122
  }
1057
1123
  };
1058
- function Ge(t) {
1124
+ function Qe(t) {
1059
1125
  let n = e.DefaultConfig?.loader;
1060
1126
  if (typeof n != "function") return;
1061
1127
  class r extends n {
1062
1128
  served = !1;
1063
1129
  cancelled = !1;
1064
- stats = Ke();
1130
+ stats = $e();
1065
1131
  load(e, n, r) {
1066
1132
  let i = e.rangeEnd ? void 0 : t.take(e.url);
1067
1133
  if (!i) {
@@ -1069,7 +1135,7 @@ function Ge(t) {
1069
1135
  return;
1070
1136
  }
1071
1137
  this.served = !0;
1072
- let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || He, s = setTimeout(() => {
1138
+ let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || Je, s = setTimeout(() => {
1073
1139
  !this.cancelled && this.served && (i.abort.abort(), t.stats.failed += 1, this.served = !1, super.load(e, n, r));
1074
1140
  }, o);
1075
1141
  i.bytes.then((o) => {
@@ -1096,7 +1162,7 @@ function Ge(t) {
1096
1162
  }
1097
1163
  return r;
1098
1164
  }
1099
- function Ke() {
1165
+ function $e() {
1100
1166
  return {
1101
1167
  aborted: !1,
1102
1168
  loaded: 0,
@@ -1120,10 +1186,10 @@ function Ke() {
1120
1186
  }
1121
1187
  };
1122
1188
  }
1123
- function G(e) {
1189
+ function et(e) {
1124
1190
  return e === "audio" ? "audio" : "main";
1125
1191
  }
1126
- function qe(e, t) {
1192
+ function tt(e, t) {
1127
1193
  let n = [];
1128
1194
  t.initSegment?.url && !t.initSegment.data && n.push({
1129
1195
  url: t.initSegment.url,
@@ -1142,24 +1208,24 @@ function qe(e, t) {
1142
1208
  }
1143
1209
  //#endregion
1144
1210
  //#region src/core/engine/hls.ts
1145
- function Je() {
1211
+ function nt() {
1146
1212
  return e.isSupported();
1147
1213
  }
1148
- var Ye = 3, Xe = 5, Ze = 3, Qe = 3e4, $e = 12e3, et = 3e3, K = 6e3, tt = 5e3, nt = 4e3, rt = 2, it = 5, at = 2, ot = 2, q = 4, st = 4, ct = 2e3, lt = 3e4, ut = 2, dt = 9, ft = .5, pt = 64;
1149
- function mt(e) {
1214
+ var rt = 3, it = 5, at = 3, ot = 3e4, st = 12e3, ct = 3e3, lt = 6e3, ut = 5e3, dt = 4e3, ft = 2, pt = 5, mt = 2, ht = 2, gt = 4, _t = 4, vt = 2e3, yt = 3e4, bt = 2, xt = 9, St = .5, Ct = 64;
1215
+ function wt(e) {
1150
1216
  if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
1151
1217
  delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
1152
1218
  return;
1153
1219
  }
1154
- e.liveSyncDuration ??= ut;
1155
- let t = Math.max(12, e.liveSyncDuration + dt);
1156
- (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), ht(e, e.liveSyncDuration);
1220
+ e.liveSyncDuration ??= bt;
1221
+ let t = Math.max(12, e.liveSyncDuration + xt);
1222
+ (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), Tt(e, e.liveSyncDuration);
1157
1223
  }
1158
- function ht(e, t) {
1224
+ function Tt(e, t) {
1159
1225
  let n = (e, t, n) => Math.min(n, Math.max(t, e));
1160
1226
  e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
1161
1227
  }
1162
- var J = class {
1228
+ var Et = class {
1163
1229
  name = "hls";
1164
1230
  hls = null;
1165
1231
  deps;
@@ -1227,7 +1293,7 @@ var J = class {
1227
1293
  this.deps = e, this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
1228
1294
  }
1229
1295
  async load() {
1230
- let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = V(r) && H(), o = !!e.drm?.widevine?.licenseUrl && !a;
1296
+ let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = K(r) && q(), o = !!e.drm?.widevine?.licenseUrl && !a;
1231
1297
  if (e.drmEnabled && !o) {
1232
1298
  i({
1233
1299
  type: "error",
@@ -1236,7 +1302,7 @@ var J = class {
1236
1302
  });
1237
1303
  return;
1238
1304
  }
1239
- e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && Ee(r), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1305
+ e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ae(r), Pe()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1240
1306
  let e = this.hls;
1241
1307
  if (document.visibilityState !== "visible" || !e) return;
1242
1308
  let t = e.liveSyncPosition;
@@ -1259,7 +1325,7 @@ var J = class {
1259
1325
  }
1260
1326
  this.loadSuspended = !0;
1261
1327
  }
1262
- }, tt));
1328
+ }, ut));
1263
1329
  }
1264
1330
  resumeLoading() {
1265
1331
  if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
@@ -1291,7 +1357,7 @@ var J = class {
1291
1357
  let t = e.liveSyncPosition;
1292
1358
  if (typeof t != "number" || !Number.isFinite(t)) return;
1293
1359
  let { video: n } = this.deps;
1294
- n.currentTime <= t + ft || (n.currentTime = t);
1360
+ n.currentTime <= t + St || (n.currentTime = t);
1295
1361
  }
1296
1362
  startHls() {
1297
1363
  let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps;
@@ -1310,12 +1376,12 @@ var J = class {
1310
1376
  emeEnabled: !0,
1311
1377
  drmSystems: { ...this.licenseUrl ? { "com.widevine.alpha": { licenseUrl: this.licenseUrl } } : {} },
1312
1378
  drmSystemOptions: {
1313
- videoRobustness: F.video,
1314
- audioRobustness: F.audio,
1315
- videoEncryptionScheme: F.scheme,
1316
- audioEncryptionScheme: F.scheme
1379
+ videoRobustness: P.video,
1380
+ audioRobustness: P.audio,
1381
+ videoEncryptionScheme: P.scheme,
1382
+ audioEncryptionScheme: P.scheme
1317
1383
  },
1318
- ...M() ? { requestMediaKeySystemAccessFunc: Te(t) } : {},
1384
+ ...A() ? { requestMediaKeySystemAccessFunc: N(t) } : {},
1319
1385
  licenseXhrSetup: (e, t) => {
1320
1386
  e.open("POST", this.licenseUrl ?? t, !0), e.setRequestHeader("x-api-key", r.apiKey), e.setRequestHeader("X-Match-Urn", n.matchUrn), e.setRequestHeader("X-Device-Id", i), a && e.setRequestHeader("X-User-Id", a), this.licenseRequested = !0;
1321
1387
  let o = performance.now();
@@ -1332,22 +1398,20 @@ var J = class {
1332
1398
  ...c
1333
1399
  };
1334
1400
  if (this.prefetch?.destroy(), this.prefetch = null, u && this.deps.mediaDuringKey !== !1 && !d.fLoader) {
1335
- let e = new We({
1401
+ let e = new Ze({
1336
1402
  sessionId: n.analytics?.sid,
1337
1403
  contentId: n.matchUrn
1338
- }), t = Ge(e);
1404
+ }), t = Qe(e);
1339
1405
  t && (this.prefetch = e, d.fLoader = t);
1340
1406
  }
1341
- mt(d), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.loadStarted = d.autoStartLoad !== !1;
1407
+ wt(d), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.loadStarted = d.autoStartLoad !== !1;
1342
1408
  let f = new e(d);
1343
1409
  if (this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
1344
- this.mediaRecoveries = 0, this.networkRecoveries = 0;
1345
- let e = f.levels.map((e) => e.height).filter((e) => !!e);
1346
- this.ladderHeights = e.length ? [...new Set(e)].sort((e, t) => e - t) : void 0, this.ladderTopBitrateKbps = f.levels.length ? Math.round(Math.max(...f.levels.map((e) => e.bitrate)) / 1e3) : 0, this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
1410
+ 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" });
1347
1411
  }), f.on(e.Events.FRAG_BUFFERED, (e, t) => {
1348
1412
  t?.frag?.type === "main" && (this.kickKind !== "dead" && this.clearKick(), (this.mediaRecoveries > 0 || this.networkRecoveries > 0 || this.licenseRecoveries > 0 || this.starvationKicks > 0 || this.starvationRebuilds > 0) && !this.recoveryResetTimer && (this.recoveryResetTimer = setTimeout(() => {
1349
1413
  this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
1350
- }, Qe)));
1414
+ }, ot)));
1351
1415
  }), f.on(e.Events.FRAG_LOADING, (e, t) => {
1352
1416
  t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
1353
1417
  }), f.on(e.Events.FRAG_LOADED, (e, t) => {
@@ -1355,10 +1419,10 @@ var J = class {
1355
1419
  let n = t?.frag?.stats, r = n?.loaded;
1356
1420
  typeof r == "number" && (this.bytesLoaded += r), !this.reportedFirstBytes && typeof r == "number" && r > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
1357
1421
  let i = n?.loading;
1358
- 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());
1422
+ 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 > Ct && this.requestTimesMs.shift());
1359
1423
  let a = t?.frag?.url;
1360
1424
  if (a) {
1361
- let e = z(a);
1425
+ let e = W(a);
1362
1426
  e && (this.cdnHost = e);
1363
1427
  }
1364
1428
  }), f.on(e.Events.LEVEL_LOADED, (e, t) => {
@@ -1372,15 +1436,15 @@ var J = class {
1372
1436
  }), f.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.prefetch) {
1373
1437
  let t = this.prefetch;
1374
1438
  f.on(e.Events.KEY_LOADING, (e, n) => {
1375
- let r = n?.frag, i = G(r?.type);
1376
- if (r && t.isActive(i)) for (let e of qe(f, r)) t.prefetch(e.url, i, e.kind);
1377
- }), f.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(G(n?.frag?.type)));
1439
+ let r = n?.frag, i = et(r?.type);
1440
+ if (r && t.isActive(i)) for (let e of tt(f, r)) t.prefetch(e.url, i, e.kind);
1441
+ }), f.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(et(n?.frag?.type)));
1378
1442
  }
1379
1443
  f.on(e.Events.KEY_LOADED, () => {
1380
1444
  u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
1381
1445
  }), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
1382
1446
  this.checkEndStale(), this.checkStarvation();
1383
- }, et), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1447
+ }, ct), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1384
1448
  this.renditionSwitches += 1;
1385
1449
  let n = this.lastLevelIndex >= 0 ? f.levels[this.lastLevelIndex] : void 0, r = f.levels[t.level];
1386
1450
  n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, l({
@@ -1444,11 +1508,33 @@ var J = class {
1444
1508
  return;
1445
1509
  }
1446
1510
  this.capTimer && clearTimeout(this.capTimer);
1447
- let t = e > this.sizeCapLevel ? ct : lt;
1511
+ let t = e > this.sizeCapLevel ? vt : yt;
1448
1512
  this.capTimer = setTimeout(() => {
1449
1513
  this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
1450
1514
  }, t);
1451
1515
  }
1516
+ measureLadder(e) {
1517
+ let t = e.levels.map((e) => e.height).filter((e) => !!e);
1518
+ 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;
1519
+ }
1520
+ dropLevelsWidevineCannotPlay(e) {
1521
+ this.removeLevelsWhere(e, (e) => Fe(e) !== !0);
1522
+ let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && F(e) !== "avc" && !!F(e)));
1523
+ for (let n of t) Ne(n).then((t) => {
1524
+ t || this.hls !== e || this.removeLevelsWhere(e, (e) => e === n) && (this.measureLadder(e), this.applySizeCap());
1525
+ });
1526
+ }
1527
+ removeLevelsWhere(e, t) {
1528
+ let n = e.levels ?? [], r = [], i = /* @__PURE__ */ new Set();
1529
+ if (n.forEach((e, n) => {
1530
+ let a = e.videoCodec;
1531
+ a && F(a) && t(a) && (r.push(n), i.add(a));
1532
+ }), !r.length) return !1;
1533
+ let a = [...i].join(", ");
1534
+ if (!n.some((e, t) => r.includes(t) ? !1 : !F(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;
1535
+ for (let t = r.length - 1; t >= 0; --t) e.removeLevel(r[t]);
1536
+ return console.info(`havik-player: skipped ${r.length} rendition(s) Widevine cannot play on this browser (${a})`), !0;
1537
+ }
1452
1538
  applySizeCap() {
1453
1539
  if (!this.sizeCapManaged) return;
1454
1540
  this.capTimer &&= (clearTimeout(this.capTimer), null);
@@ -1491,7 +1577,7 @@ var J = class {
1491
1577
  e.widevine && (this.licenseUrl = e.widevine);
1492
1578
  }
1493
1579
  getStats() {
1494
- let e = this.hls, t = B(this.deps.video), n = {
1580
+ let e = this.hls, t = G(this.deps.video), n = {
1495
1581
  droppedFrames: t.dropped,
1496
1582
  decodedFrames: t.totalFrames,
1497
1583
  lowLatency: this.detectedLowLatency,
@@ -1537,7 +1623,7 @@ var J = class {
1537
1623
  return;
1538
1624
  }
1539
1625
  let e = Date.now() - this.lastAdvanceMs;
1540
- !this.chaseSuspended && e > K && this.suspendChasing(), e > $e && this.emitEnded("stalled");
1626
+ !this.chaseSuspended && e > lt && this.suspendChasing(), e > st && this.emitEnded("stalled");
1541
1627
  }
1542
1628
  resetStarvationWindow() {
1543
1629
  this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
@@ -1552,7 +1638,7 @@ var J = class {
1552
1638
  this.resetStarvationWindow();
1553
1639
  return;
1554
1640
  }
1555
- let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < K, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > nt, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = B(t), c = o - s, l = c !== this.starvedFrames;
1641
+ let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < lt, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > dt, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = G(t), c = o - s, l = c !== this.starvedFrames;
1556
1642
  if (this.starvedFrames = c, !a || l) {
1557
1643
  (t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
1558
1644
  return;
@@ -1561,12 +1647,12 @@ var J = class {
1561
1647
  this.resetStarvationWindow();
1562
1648
  return;
1563
1649
  }
1564
- 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 > q && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= at && (this.clearKick(), this.starvationRebuilds < ot)) {
1650
+ 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 > gt && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= mt && (this.clearKick(), this.starvationRebuilds < ht)) {
1565
1651
  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");
1566
1652
  return;
1567
1653
  }
1568
- let u = i && this.starvedTicks >= rt, d = !i && this.deadTicks >= q && this.recentMainFrags.reduce((e, t) => e + t, 0) >= st;
1569
- if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= it))) {
1654
+ let u = i && this.starvedTicks >= ft, d = !i && this.deadTicks >= gt && this.recentMainFrags.reduce((e, t) => e + t, 0) >= _t;
1655
+ if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= pt))) {
1570
1656
  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");
1571
1657
  try {
1572
1658
  e.stopLoad(), e.startLoad(-1);
@@ -1615,7 +1701,7 @@ var J = class {
1615
1701
  scheduleLicenseRetry(t) {
1616
1702
  if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
1617
1703
  let n = t.response?.code ?? 0;
1618
- if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= Ze) return !1;
1704
+ if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= at) return !1;
1619
1705
  this.licenseRecoveries += 1;
1620
1706
  let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
1621
1707
  return this.licenseRetryTimer = setTimeout(() => {
@@ -1647,7 +1733,7 @@ var J = class {
1647
1733
  return;
1648
1734
  }
1649
1735
  if (t.type === e.ErrorTypes.NETWORK_ERROR) {
1650
- if (this.networkRecoveries < Xe) {
1736
+ if (this.networkRecoveries < it) {
1651
1737
  this.networkRecoveries += 1;
1652
1738
  let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
1653
1739
  this.networkRetryTimer = setTimeout(() => {
@@ -1664,7 +1750,7 @@ var J = class {
1664
1750
  return;
1665
1751
  }
1666
1752
  if (t.type === e.ErrorTypes.MEDIA_ERROR) {
1667
- if (this.mediaRecoveries < Ye) {
1753
+ if (this.mediaRecoveries < rt) {
1668
1754
  this.mediaRecoveries += 1, n.recoverMediaError();
1669
1755
  return;
1670
1756
  }
@@ -1688,19 +1774,19 @@ var J = class {
1688
1774
  let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
1689
1775
  return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
1690
1776
  }
1691
- }, gt = 15e3, _t = 6e5, vt = 3e5, yt = 100, Y = 1, bt = 1e3, xt = 3e4, St = 1e3, Ct = {
1777
+ }, Dt = 15e3, Ot = 6e5, kt = 3e5, At = 100, Y = 1, jt = 1e3, Mt = 3e4, Nt = 1e3, Pt = {
1692
1778
  inline: "PRESENTATION_INLINE",
1693
1779
  fullscreen: "PRESENTATION_FULLSCREEN",
1694
1780
  pip: "PRESENTATION_PIP"
1695
- }, wt = {
1781
+ }, Ft = {
1696
1782
  widevine: "KEY_SYSTEM_WIDEVINE",
1697
1783
  fairplay: "KEY_SYSTEM_FAIRPLAY",
1698
1784
  none: "KEY_SYSTEM_NONE"
1699
1785
  };
1700
- function Tt(e, t) {
1786
+ function It(e, t) {
1701
1787
  return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
1702
1788
  }
1703
- var Et = /* @__PURE__ */ new Set([
1789
+ var Lt = /* @__PURE__ */ new Set([
1704
1790
  "INVALID_URN",
1705
1791
  "NOT_FOUND",
1706
1792
  "GONE",
@@ -1720,7 +1806,7 @@ var Et = /* @__PURE__ */ new Set([
1720
1806
  ended: "PLAYER_STATE_ENDED",
1721
1807
  error: "PLAYER_STATE_ERROR"
1722
1808
  };
1723
- function Dt(e) {
1809
+ function Rt(e) {
1724
1810
  try {
1725
1811
  let t = new URL(e), [n, ...r] = t.hostname.split(".");
1726
1812
  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);
@@ -1728,24 +1814,25 @@ function Dt(e) {
1728
1814
  return;
1729
1815
  }
1730
1816
  }
1731
- var Ot = /* @__PURE__ */ new Set();
1732
- function kt(e, t) {
1733
- return Ot.has(e) || (Ot.add(e), console.warn(`havik-player: ${t}`)), { disabledReason: t };
1817
+ var zt = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase();
1818
+ function Bt(e, t) {
1819
+ return g(t, e), { disabledReason: t };
1734
1820
  }
1735
- function At(e, t) {
1821
+ function Vt(e, t, n) {
1822
+ if (n) return t && !zt(t, n) && g(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
1736
1823
  if (t) return { endpoint: t };
1737
- if (t !== void 0) return kt("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).");
1738
- let n = Dt(e);
1739
- if (n) return { endpoint: n };
1740
- let r;
1824
+ if (t !== void 0) return Bt("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).");
1825
+ let r = Rt(e);
1826
+ if (r) return { endpoint: r };
1827
+ let i;
1741
1828
  try {
1742
- r = new URL(e).hostname || e;
1829
+ i = new URL(e).hostname || e;
1743
1830
  } catch {
1744
- r = e;
1831
+ i = e;
1745
1832
  }
1746
- return kt(r, `analytics is disabled: no QoE beacons will be sent. The beacons endpoint cannot be derived from the baseUrl host "${r}" — 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).`);
1833
+ return Bt(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).`);
1747
1834
  }
1748
- var jt = class {
1835
+ var Ht = class {
1749
1836
  opts;
1750
1837
  url;
1751
1838
  now;
@@ -1825,8 +1912,8 @@ var jt = class {
1825
1912
  constructor(e) {
1826
1913
  this.opts = {
1827
1914
  ...e,
1828
- heartbeatMs: e.heartbeatMs ?? gt,
1829
- idleMs: e.idleMs ?? _t
1915
+ heartbeatMs: e.heartbeatMs ?? Dt,
1916
+ idleMs: e.idleMs ?? Ot
1830
1917
  }, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`, this.now = e.now ?? (() => Date.now()), this.bornMs = this.now(), this.presentationSinceMs = this.bornMs, this.startupAnchorMs = this.bornMs;
1831
1918
  }
1832
1919
  start() {
@@ -1836,11 +1923,11 @@ var jt = class {
1836
1923
  sdkVersion: this.opts.sdkVersion,
1837
1924
  ...this.opts.environment
1838
1925
  };
1839
- this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), bt), 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.onVisibility());
1926
+ this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), jt), 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.onVisibility());
1840
1927
  }
1841
1928
  checkSuspension(e) {
1842
1929
  if (this.endedFlag || !this.opts.idleMs) return !1;
1843
- let t = Math.max(this.opts.idleMs, vt);
1930
+ let t = Math.max(this.opts.idleMs, kt);
1844
1931
  return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
1845
1932
  }
1846
1933
  syncIdle(e) {
@@ -1863,12 +1950,12 @@ var jt = class {
1863
1950
  let a = {
1864
1951
  fromState: X[e] ?? "PLAYER_STATE_UNSPECIFIED",
1865
1952
  toState: X[t] ?? "PLAYER_STATE_UNSPECIFIED",
1866
- presentation: Ct[this.presentation]
1953
+ presentation: Pt[this.presentation]
1867
1954
  }, o = this.causeOf(e, t, i);
1868
1955
  o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
1869
1956
  }
1870
1957
  seekInduced(e) {
1871
- return this.lastSeekMs >= 0 && e - this.lastSeekMs < St;
1958
+ return this.lastSeekMs >= 0 && e - this.lastSeekMs < Nt;
1872
1959
  }
1873
1960
  causeOf(e, t, n) {
1874
1961
  if (t === "error") return "TRANSITION_CAUSE_ERROR";
@@ -1942,7 +2029,7 @@ var jt = class {
1942
2029
  let r = n ?? "";
1943
2030
  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";
1944
2031
  if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
1945
- if (Et.has(e)) return "ERROR_STAGE_RESOLVE";
2032
+ if (Lt.has(e)) return "ERROR_STAGE_RESOLVE";
1946
2033
  let i = t ?? "";
1947
2034
  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";
1948
2035
  }
@@ -1989,14 +2076,14 @@ var jt = class {
1989
2076
  if (this.lastRequestCount = g, _ > 0) {
1990
2077
  o.requestCountDelta = _;
1991
2078
  let e = t.requestTimesMs ?? [], n = e.slice(Math.max(0, e.length - _)).sort((e, t) => e - t);
1992
- n.length > 0 && (o.requestTimeP50Ms = Tt(n, 50), o.requestTimeP95Ms = Tt(n, 95));
2079
+ n.length > 0 && (o.requestTimeP50Ms = It(n, 50), o.requestTimeP95Ms = It(n, 95));
1993
2080
  }
1994
2081
  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();
1995
2082
  }
1996
2083
  maybeEmitMediaInfo(e) {
1997
2084
  if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
1998
2085
  let t = {};
1999
- e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = wt[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);
2086
+ e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = Ft[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);
2000
2087
  let n = JSON.stringify(t);
2001
2088
  n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
2002
2089
  }
@@ -2016,7 +2103,7 @@ var jt = class {
2016
2103
  let c = r?.positionMs ?? 0;
2017
2104
  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));
2018
2105
  let l = e !== "END_REASON_ENDED";
2019
- l && this.lastStallMs > 0 && n - this.lastStallMs <= xt && (i.abandonAfterStallMs = Math.max(Y, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= xt && (i.abandonAfterErrorMs = Math.max(Y, Math.round(n - this.lastErrorMs))), this.fullscreenTotalMs > 0 && (i.fullscreenTimeMs = Math.round(this.fullscreenTotalMs)), this.pipTotalMs > 0 && (i.pipTimeMs = Math.round(this.pipTotalMs)), this.volumeChanges > 0 && (i.volumeChanges = this.volumeChanges), this.muteChanges > 0 && (i.muteChanges = this.muteChanges);
2106
+ l && this.lastStallMs > 0 && n - this.lastStallMs <= Mt && (i.abandonAfterStallMs = Math.max(Y, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= Mt && (i.abandonAfterErrorMs = Math.max(Y, Math.round(n - this.lastErrorMs))), this.fullscreenTotalMs > 0 && (i.fullscreenTimeMs = Math.round(this.fullscreenTotalMs)), this.pipTotalMs > 0 && (i.pipTimeMs = Math.round(this.pipTotalMs)), this.volumeChanges > 0 && (i.volumeChanges = this.volumeChanges), this.muteChanges > 0 && (i.muteChanges = this.muteChanges);
2020
2107
  let u = r?.decodedFrames ?? this.lastDecoded;
2021
2108
  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");
2022
2109
  }
@@ -2036,7 +2123,7 @@ var jt = class {
2036
2123
  };
2037
2124
  }
2038
2125
  enqueue(e) {
2039
- for (this.pending.push(this.wrap(e)); this.pending.length > yt;) {
2126
+ for (this.pending.push(this.wrap(e)); this.pending.length > At;) {
2040
2127
  let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
2041
2128
  this.pending.splice(e >= 0 ? e : 0, 1);
2042
2129
  }
@@ -2059,7 +2146,7 @@ var jt = class {
2059
2146
  };
2060
2147
  //#endregion
2061
2148
  //#region src/core/environment.ts
2062
- function Mt() {
2149
+ function Ut() {
2063
2150
  if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
2064
2151
  let e;
2065
2152
  try {
@@ -2084,14 +2171,14 @@ function Mt() {
2084
2171
  integration: "INTEGRATION_KIND_IFRAME"
2085
2172
  };
2086
2173
  }
2087
- function Nt() {
2174
+ function Wt() {
2088
2175
  if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
2089
2176
  let e = navigator.userAgentData, t = e?.platform ?? "";
2090
2177
  if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
2091
2178
  let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
2092
2179
  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";
2093
2180
  }
2094
- function Pt() {
2181
+ function Gt() {
2095
2182
  let e = typeof navigator < "u" ? navigator.connection : void 0;
2096
2183
  if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
2097
2184
  let t = {
@@ -2110,17 +2197,17 @@ function Pt() {
2110
2197
  }
2111
2198
  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;
2112
2199
  }
2113
- function Ft(e) {
2114
- let t = Mt(), n = {
2115
- deviceClass: Nt(),
2200
+ function Kt(e) {
2201
+ let t = Ut(), n = {
2202
+ deviceClass: Wt(),
2116
2203
  integration: t.integration,
2117
- ...Pt()
2204
+ ...Gt()
2118
2205
  };
2119
2206
  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);
2120
2207
  let r = e.getBoundingClientRect?.();
2121
2208
  return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
2122
2209
  }
2123
- async function It() {
2210
+ async function qt() {
2124
2211
  let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
2125
2212
  if (!e?.getHighEntropyValues) return {};
2126
2213
  try {
@@ -2132,7 +2219,7 @@ async function It() {
2132
2219
  }
2133
2220
  //#endregion
2134
2221
  //#region src/core/version.ts
2135
- var Lt = "2.11.0", Rt = {
2222
+ var Jt = "2.12.0", Yt = {
2136
2223
  accent: "#E1B600",
2137
2224
  accentText: "#1B1C23",
2138
2225
  background: "#0e0f13",
@@ -2143,7 +2230,7 @@ var Lt = "2.11.0", Rt = {
2143
2230
  border: "rgba(255, 255, 255, 0.1)",
2144
2231
  radius: "8px",
2145
2232
  fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
2146
- }, zt = {
2233
+ }, Xt = {
2147
2234
  accent: "--havik-accent",
2148
2235
  accentText: "--havik-accent-text",
2149
2236
  background: "--havik-bg",
@@ -2155,25 +2242,25 @@ var Lt = "2.11.0", Rt = {
2155
2242
  radius: "--havik-radius",
2156
2243
  fontFamily: "--havik-font"
2157
2244
  };
2158
- function Z(e, t) {
2245
+ function Zt(e, t) {
2159
2246
  let n = {
2160
- ...Rt,
2247
+ ...Yt,
2161
2248
  ...t
2162
2249
  };
2163
- for (let t of Object.keys(zt)) e.style.setProperty(zt[t], n[t]);
2250
+ for (let t of Object.keys(Xt)) e.style.setProperty(Xt[t], n[t]);
2164
2251
  n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
2165
2252
  }
2166
2253
  //#endregion
2167
2254
  //#region src/ui/styles.ts
2168
- var Bt = "havik-player-styles", Vt = "\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/* 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";
2169
- function Ht(e = document) {
2170
- if (e.getElementById(Bt)) return;
2255
+ var Qt = "havik-player-styles", $t = "\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/* 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";
2256
+ function en(e = document) {
2257
+ if (e.getElementById(Qt)) return;
2171
2258
  let t = e.createElement("style");
2172
- t.id = Bt, t.textContent = Vt, e.head.appendChild(t);
2259
+ t.id = Qt, t.textContent = $t, e.head.appendChild(t);
2173
2260
  }
2174
2261
  //#endregion
2175
2262
  //#region src/ui/icons.ts
2176
- var Ut = {
2263
+ var tn = {
2177
2264
  play: "<path d=\"M8 5v14l11-7z\"/>",
2178
2265
  pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
2179
2266
  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\"/>",
@@ -2186,21 +2273,21 @@ var Ut = {
2186
2273
  liveDot: "<circle cx=\"12\" cy=\"12\" r=\"6\"/>",
2187
2274
  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\"/>"
2188
2275
  };
2189
- function Q(e) {
2190
- return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Ut[e]}</svg>`;
2276
+ function Z(e) {
2277
+ return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${tn[e]}</svg>`;
2191
2278
  }
2192
2279
  //#endregion
2193
2280
  //#region src/ui/controls.ts
2194
- var Wt = 3e3, Gt = /* @__PURE__ */ new Set([
2281
+ var nn = 3e3, rn = /* @__PURE__ */ new Set([
2195
2282
  "GONE",
2196
2283
  "NOT_FOUND",
2197
2284
  "INVALID_URN",
2198
2285
  "UNAUTHORIZED"
2199
2286
  ]);
2200
- function Kt(e) {
2201
- return new qt(e);
2287
+ function an(e) {
2288
+ return new on(e);
2202
2289
  }
2203
- var qt = class {
2290
+ var on = class {
2204
2291
  root;
2205
2292
  video;
2206
2293
  player;
@@ -2242,7 +2329,7 @@ var qt = class {
2242
2329
  scrubbing = !1;
2243
2330
  offFns = [];
2244
2331
  constructor(e) {
2245
- this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Wt, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, Ht(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");
2332
+ this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? nn, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, en(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");
2246
2333
  let t = (e, t, n) => {
2247
2334
  let r = this.doc.createElement(e);
2248
2335
  if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
@@ -2253,12 +2340,12 @@ var qt = class {
2253
2340
  "aria-label": r,
2254
2341
  title: r
2255
2342
  });
2256
- return i.innerHTML = Q(n), i;
2343
+ return i.innerHTML = Z(n), i;
2257
2344
  };
2258
2345
  this.overlay = t("div", "havik-overlay"), this.center = t("button", "havik-center", {
2259
2346
  type: "button",
2260
2347
  "aria-label": "Play"
2261
- }), 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", {
2348
+ }), 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", {
2262
2349
  role: "slider",
2263
2350
  "aria-label": "Seek",
2264
2351
  "aria-valuemin": "0",
@@ -2276,7 +2363,7 @@ var qt = class {
2276
2363
  "aria-label": "Volume"
2277
2364
  });
2278
2365
  let a = t("div", "havik-vol");
2279
- a.append(this.muteBtn, this.volSlider), this.live = t("div", "havik-live"), this.live.innerHTML = Q("liveDot");
2366
+ a.append(this.muteBtn, this.volSlider), this.live = t("div", "havik-live"), this.live.innerHTML = Z("liveDot");
2280
2367
  let o = this.doc.createElement("span");
2281
2368
  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";
2282
2369
  let s = t("div", "havik-spacer");
@@ -2330,12 +2417,12 @@ var qt = class {
2330
2417
  }
2331
2418
  if (e === "preplay") {
2332
2419
  let e = this.doc.createElement("button");
2333
- 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);
2420
+ 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);
2334
2421
  } else {
2335
2422
  let r = this.doc.createElement("div");
2336
- if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !Gt.has(this.lastError.code)) {
2423
+ if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !rn.has(this.lastError.code)) {
2337
2424
  let e = this.doc.createElement("button");
2338
- 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);
2425
+ 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);
2339
2426
  }
2340
2427
  }
2341
2428
  this.root.append(n), this.statusBox = n, this.show();
@@ -2374,7 +2461,7 @@ var qt = class {
2374
2461
  let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
2375
2462
  this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
2376
2463
  }
2377
- !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Jt(this.video.currentTime)} / ${Jt(this.video.duration)}`);
2464
+ !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Q(this.video.currentTime)} / ${Q(this.video.duration)}`);
2378
2465
  }
2379
2466
  syncLive() {
2380
2467
  let e = this.player.getStats(), t = e.isLive !== !1;
@@ -2424,17 +2511,17 @@ var qt = class {
2424
2511
  renderQualityMenu() {
2425
2512
  let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
2426
2513
  n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
2427
- for (let n of e) this.menu.append(this.menuItem(Yt(n), t === n.index, () => this.player.setQuality(n.index)));
2514
+ for (let n of e) this.menu.append(this.menuItem(sn(n), t === n.index, () => this.player.setQuality(n.index)));
2428
2515
  }
2429
2516
  renderAudioMenu() {
2430
2517
  let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
2431
2518
  t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
2432
- for (let t of e) this.menu.append(this.menuItem(Xt(t), t.default, () => this.player.setAudioTrack(t.id)));
2519
+ for (let t of e) this.menu.append(this.menuItem(cn(t), t.default, () => this.player.setAudioTrack(t.id)));
2433
2520
  }
2434
2521
  renderCcMenu() {
2435
2522
  let e = this.player.getTextTracks(), t = this.doc.createElement("div");
2436
2523
  t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
2437
- for (let t of e) this.menu.append(this.menuItem(Zt(t), !1, () => this.player.setTextTrack(t.id)));
2524
+ for (let t of e) this.menu.append(this.menuItem(ln(t), !1, () => this.player.setTextTrack(t.id)));
2438
2525
  }
2439
2526
  onTracksChanged() {
2440
2527
  this.openMenu && this.renderMenu(this.openMenu);
@@ -2454,11 +2541,11 @@ var qt = class {
2454
2541
  }
2455
2542
  async toggleFullscreen() {
2456
2543
  try {
2457
- C(this.video, this.root) ? await T(this.video, this.root) : await w(this.video, this.root);
2544
+ x(this.video, this.root) ? await C(this.video, this.root) : await S(this.video, this.root);
2458
2545
  } catch {}
2459
2546
  }
2460
2547
  syncFullscreen() {
2461
- let e = C(this.video, this.root);
2548
+ let e = x(this.video, this.root);
2462
2549
  this.setIcon(this.fsBtn, e ? "fullscreenExit" : "fullscreen"), this.fsBtn.setAttribute("aria-label", e ? "Exit fullscreen" : "Fullscreen");
2463
2550
  }
2464
2551
  poke() {
@@ -2517,7 +2604,7 @@ var qt = class {
2517
2604
  }
2518
2605
  }
2519
2606
  setIcon(e, t) {
2520
- e.innerHTML = Q(t);
2607
+ e.innerHTML = Z(t);
2521
2608
  }
2522
2609
  destroy() {
2523
2610
  this.hideTimer && clearTimeout(this.hideTimer);
@@ -2534,41 +2621,41 @@ var qt = class {
2534
2621
  this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
2535
2622
  }
2536
2623
  };
2537
- function Jt(e) {
2624
+ function Q(e) {
2538
2625
  (!Number.isFinite(e) || e < 0) && (e = 0);
2539
2626
  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");
2540
2627
  return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
2541
2628
  }
2542
- function Yt(e) {
2629
+ function sn(e) {
2543
2630
  return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
2544
2631
  }
2545
- function Xt(e) {
2632
+ function cn(e) {
2546
2633
  return e.name || e.lang || `Track ${e.id}`;
2547
2634
  }
2548
- function Zt(e) {
2635
+ function ln(e) {
2549
2636
  return e.name || e.lang || `Track ${e.id}`;
2550
2637
  }
2551
2638
  //#endregion
2552
2639
  //#region src/managed/index.ts
2553
- var Qt = 6e3, $t = 45e3, en = 2e3, tn = 3, nn = 2e3, rn = 48e4;
2554
- function an(e) {
2640
+ var un = 6e3, dn = 45e3, fn = 2e3, pn = 3, mn = 2e3, hn = 48e4;
2641
+ function gn(e) {
2555
2642
  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)})`);
2556
- if (e.env !== void 0) return L(e.env);
2643
+ if (e.env !== void 0) return H(e.env);
2557
2644
  if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
2558
2645
  return e.baseUrl;
2559
2646
  }
2560
- async function on(e) {
2647
+ async function _n(e) {
2561
2648
  if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
2562
- let t = an(e);
2649
+ let t = gn(e);
2563
2650
  if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
2564
2651
  if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
2565
- let r = new sn({
2652
+ let r = new vn({
2566
2653
  ...e,
2567
2654
  baseUrl: t
2568
2655
  });
2569
2656
  return await r.start(), r;
2570
2657
  }
2571
- var sn = class {
2658
+ var vn = class {
2572
2659
  opts;
2573
2660
  abort = new AbortController();
2574
2661
  listeners = {};
@@ -2612,7 +2699,7 @@ var sn = class {
2612
2699
  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");
2613
2700
  let e = ++this.loadGen, t = this.resolveOptions();
2614
2701
  try {
2615
- let n = await y(t);
2702
+ let n = await v(t);
2616
2703
  if (await this.onResolved(n, e), e === this.loadGen && this._state === "error" && this._lastError) {
2617
2704
  let e = this._lastError;
2618
2705
  throw this.destroy(), e;
@@ -2635,11 +2722,11 @@ var sn = class {
2635
2722
  };
2636
2723
  }
2637
2724
  beginArming(e, t, n = !1) {
2638
- let r = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? D(this.opts.baseUrl);
2725
+ let r = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? T(this.opts.baseUrl);
2639
2726
  r ? this.armWithSse(e, r, t, n) : this.beginArmingByPolling(e);
2640
2727
  }
2641
2728
  beginArmingByPolling(e) {
2642
- b({
2729
+ y({
2643
2730
  ...this.resolveOptions(),
2644
2731
  signal: this.abort.signal,
2645
2732
  waitForLive: this.buildWaitConfig(e)
@@ -2656,7 +2743,7 @@ var sn = class {
2656
2743
  setTimeout(() => {
2657
2744
  a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
2658
2745
  phase: i ? "unavailable" : "tooEarly",
2659
- retryInMs: $t,
2746
+ retryInMs: dn,
2660
2747
  attempt: 1,
2661
2748
  elapsedMs: 0,
2662
2749
  ...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
@@ -2673,7 +2760,7 @@ var sn = class {
2673
2760
  }
2674
2761
  }
2675
2762
  }, h = () => {
2676
- a || s || p() || (s = !0, b({
2763
+ a || s || p() || (s = !0, y({
2677
2764
  ...this.resolveOptions(),
2678
2765
  signal: c.signal,
2679
2766
  waitForLive: this.buildWaitConfig(e)
@@ -2681,7 +2768,7 @@ var sn = class {
2681
2768
  a || p() || c.signal.aborted || (a = !0, this.closeArming(), this.fail(e instanceof n ? e : new n("INTERNAL", 0, String(e))));
2682
2769
  }));
2683
2770
  }, g = () => {
2684
- a || p() || y(this.resolveOptions()).then((e) => m(e)).catch((e) => {
2771
+ a || p() || v(this.resolveOptions()).then((e) => m(e)).catch((e) => {
2685
2772
  if (!(a || p())) {
2686
2773
  if (e instanceof n && o(e.code)) {
2687
2774
  h();
@@ -2695,13 +2782,13 @@ var sn = class {
2695
2782
  !a && !p() && h();
2696
2783
  }, e);
2697
2784
  };
2698
- _(Qt), this.armingSub = E({
2785
+ _(un), this.armingSub = w({
2699
2786
  eventsBaseUrl: t,
2700
2787
  matchUrn: this.opts.matchUrn,
2701
2788
  credential: this.opts.credential,
2702
- onAlive: () => _($t),
2789
+ onAlive: () => _(dn),
2703
2790
  onState: (e) => {
2704
- a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * en);
2791
+ a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * fn);
2705
2792
  },
2706
2793
  onError: () => h()
2707
2794
  });
@@ -2724,7 +2811,7 @@ var sn = class {
2724
2811
  let n = await s(this.opts.credential);
2725
2812
  if (this.destroyed || t !== this.loadGen) return;
2726
2813
  this.setState("loading");
2727
- let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = Re(this.opts.video, (e) => {
2814
+ let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = We(this.opts.video, (e) => {
2728
2815
  this._state !== "ended" && this._state !== "error" && this.setState(e);
2729
2816
  });
2730
2817
  if (await i.load(), this.destroyed || t !== this.loadGen) {
@@ -2746,23 +2833,23 @@ var sn = class {
2746
2833
  if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
2747
2834
  let i = e.analytics?.sid;
2748
2835
  if (!i) return;
2749
- let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = At(this.opts.baseUrl, a);
2836
+ let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = Vt(this.opts.baseUrl, a, e.analytics?.endpoint);
2750
2837
  if (!o) {
2751
2838
  s && setTimeout(() => {
2752
2839
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
2753
2840
  }, 0);
2754
2841
  return;
2755
2842
  }
2756
- let c = this.opts.video, l = new jt({
2843
+ let c = this.opts.video, l = new Ht({
2757
2844
  endpoint: o,
2758
2845
  sid: i,
2759
2846
  player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
2760
- sdkVersion: Lt,
2761
- environment: Ft(c),
2847
+ sdkVersion: Jt,
2848
+ environment: Kt(c),
2762
2849
  idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
2763
2850
  onIdle: () => this.onAnalyticsIdle(t),
2764
2851
  sample: () => {
2765
- let e = this.engine?.getStats() ?? R, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
2852
+ let e = this.engine?.getStats() ?? U, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
2766
2853
  return {
2767
2854
  ...e,
2768
2855
  bufferedMs: Math.round(t * 1e3),
@@ -2776,7 +2863,7 @@ var sn = class {
2776
2863
  let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
2777
2864
  c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
2778
2865
  c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
2779
- }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), It().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
2866
+ }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), qt().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
2780
2867
  }
2781
2868
  currentPresentation() {
2782
2869
  let e = this.opts.video;
@@ -2791,7 +2878,7 @@ var sn = class {
2791
2878
  video: this.opts.video,
2792
2879
  descriptor: e,
2793
2880
  credential: t,
2794
- deviceId: A(),
2881
+ deviceId: O(),
2795
2882
  userId: this.opts.userId,
2796
2883
  lowLatency: this.opts.lowLatency === void 0 || this.opts.lowLatency === "auto" || this.opts.lowLatency,
2797
2884
  snapToLiveOnRefocus: this.opts.snapToLiveOnRefocus,
@@ -2801,11 +2888,11 @@ var sn = class {
2801
2888
  hlsConfig: i,
2802
2889
  emit: (e) => this.onEngineEvent(e)
2803
2890
  }, o = this.opts.engine ?? "auto";
2804
- if (o === "native") return new U(a);
2805
- if (o === "hls") return new J(a);
2806
- if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && V(this.opts.video) && H()) return new U(a);
2807
- if (Je()) return new J(a);
2808
- if (V(this.opts.video)) return new U(a);
2891
+ if (o === "native") return new J(a);
2892
+ if (o === "hls") return new Et(a);
2893
+ if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && K(this.opts.video) && q()) return new J(a);
2894
+ if (nt()) return new Et(a);
2895
+ if (K(this.opts.video)) return new J(a);
2809
2896
  throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
2810
2897
  }
2811
2898
  onEngineEvent(e) {
@@ -2842,11 +2929,11 @@ var sn = class {
2842
2929
  }
2843
2930
  startLiveState(e) {
2844
2931
  if (this.opts.liveStateEvents === !1) return;
2845
- let t = this.opts.eventsBaseUrl ?? D(this.opts.baseUrl);
2932
+ let t = this.opts.eventsBaseUrl ?? T(this.opts.baseUrl);
2846
2933
  if (!t) return;
2847
2934
  this.closeLiveState();
2848
2935
  let r = 0, i = !1;
2849
- this.liveStateSub = E({
2936
+ this.liveStateSub = w({
2850
2937
  eventsBaseUrl: t,
2851
2938
  matchUrn: this.opts.matchUrn,
2852
2939
  credential: this.opts.credential,
@@ -2857,7 +2944,7 @@ var sn = class {
2857
2944
  r = 0, i = !1;
2858
2945
  },
2859
2946
  onError: () => {
2860
- this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= tn && (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.`))));
2947
+ this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= pn && (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.`))));
2861
2948
  }
2862
2949
  });
2863
2950
  }
@@ -2879,7 +2966,7 @@ var sn = class {
2879
2966
  scheduleRejoin(e) {
2880
2967
  this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
2881
2968
  this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
2882
- }, Math.random() * en));
2969
+ }, Math.random() * fn));
2883
2970
  }
2884
2971
  cancelRejoin() {
2885
2972
  this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
@@ -2903,7 +2990,7 @@ var sn = class {
2903
2990
  }
2904
2991
  t.controls = !1;
2905
2992
  let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
2906
- r && r.insertBefore(n, t), n.appendChild(t), Z(n, this.opts.theme), this.container = n, this.controlBar = Kt({
2993
+ r && r.insertBefore(n, t), n.appendChild(t), Zt(n, this.opts.theme), this.container = n, this.controlBar = an({
2907
2994
  root: n,
2908
2995
  video: t,
2909
2996
  player: this,
@@ -2933,7 +3020,7 @@ var sn = class {
2933
3020
  }
2934
3021
  startStats() {
2935
3022
  this.stopStats();
2936
- let e = Math.max(500, this.opts.statsIntervalMs ?? nn);
3023
+ let e = Math.max(500, this.opts.statsIntervalMs ?? mn);
2937
3024
  this.statsTimer = setInterval(() => {
2938
3025
  if (!this.engine) return;
2939
3026
  let e = this.engine.getStats();
@@ -2945,7 +3032,7 @@ var sn = class {
2945
3032
  }
2946
3033
  scheduleLicenseRefresh() {
2947
3034
  this.stopRefresh();
2948
- let e = this.opts.licenseRefreshMs ?? rn;
3035
+ let e = this.opts.licenseRefreshMs ?? hn;
2949
3036
  e && this._descriptor?.drmEnabled && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
2950
3037
  }
2951
3038
  stopRefresh() {
@@ -2954,7 +3041,7 @@ var sn = class {
2954
3041
  async refreshLicense() {
2955
3042
  let e = this.engine;
2956
3043
  if (!this.destroyed && e) try {
2957
- let t = await y(this.resolveOptions());
3044
+ let t = await v(this.resolveOptions());
2958
3045
  if (this.destroyed || this.engine !== e) return;
2959
3046
  let n = t.drm?.widevine?.licenseUrl, r = t.drm?.fairplay?.licenseUrl;
2960
3047
  (n || r) && (e.setLicenseUrls({
@@ -2990,7 +3077,7 @@ var sn = class {
2990
3077
  this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
2991
3078
  }
2992
3079
  getStats() {
2993
- return this.engine?.getStats() ?? R;
3080
+ return this.engine?.getStats() ?? U;
2994
3081
  }
2995
3082
  getQualityLevels() {
2996
3083
  return this.engine?.getQualityLevels() ?? [];
@@ -3029,10 +3116,10 @@ var sn = class {
3029
3116
  e.pictureInPictureElement === this.opts.video && typeof e.exitPictureInPicture == "function" && await e.exitPictureInPicture();
3030
3117
  }
3031
3118
  async enterFullscreen() {
3032
- return !this.destroyed && w(this.opts.video, this.container ?? void 0);
3119
+ return !this.destroyed && S(this.opts.video, this.container ?? void 0);
3033
3120
  }
3034
3121
  async exitFullscreen() {
3035
- await T(this.opts.video, this.container ?? void 0);
3122
+ await C(this.opts.video, this.container ?? void 0);
3036
3123
  }
3037
3124
  retry() {
3038
3125
  return this.reload();
@@ -3042,7 +3129,7 @@ var sn = class {
3042
3129
  let e = ++this.loadGen;
3043
3130
  this.teardownPlayback();
3044
3131
  try {
3045
- let t = await b({
3132
+ let t = await y({
3046
3133
  ...this.resolveOptions(),
3047
3134
  waitForLive: this.opts.waitForLive ? this.buildWaitConfig(e) : void 0
3048
3135
  });
@@ -3100,7 +3187,7 @@ function $(e) {
3100
3187
  }
3101
3188
  //#endregion
3102
3189
  //#region src/embed/host.ts
3103
- function cn(e) {
3190
+ function yn(e) {
3104
3191
  if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
3105
3192
  if (!e.src) throw Error("mountEmbed: opts.src is required");
3106
3193
  if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
@@ -3159,15 +3246,15 @@ function cn(e) {
3159
3246
  }
3160
3247
  //#endregion
3161
3248
  //#region src/embed/page.ts
3162
- var ln = /^[A-Za-z0-9:_.-]{1,128}$/;
3163
- function un(e) {
3249
+ var bn = /^[A-Za-z0-9:_.-]{1,128}$/;
3250
+ function xn(e) {
3164
3251
  if (typeof e == "boolean") return e;
3165
3252
  if (typeof e == "object" && e) {
3166
3253
  let t = e.endpoint;
3167
3254
  return typeof t == "string" ? { endpoint: t } : {};
3168
3255
  }
3169
3256
  }
3170
- function dn() {
3257
+ function Sn() {
3171
3258
  let e = window.HAVIK_EMBED_CONFIG;
3172
3259
  if (e) return {
3173
3260
  baseUrl: e.baseUrl ?? "",
@@ -3177,7 +3264,7 @@ function dn() {
3177
3264
  autoplay: e.autoplay ?? !0,
3178
3265
  muted: e.muted ?? !0,
3179
3266
  waitForLive: e.waitForLive ?? !0,
3180
- analytics: un(e.analytics)
3267
+ analytics: xn(e.analytics)
3181
3268
  };
3182
3269
  let t = new URLSearchParams(location.search);
3183
3270
  return {
@@ -3190,9 +3277,9 @@ function dn() {
3190
3277
  waitForLive: !0
3191
3278
  };
3192
3279
  }
3193
- async function fn() {
3194
- let e = dn();
3195
- mn();
3280
+ async function Cn() {
3281
+ let e = Sn();
3282
+ Tn();
3196
3283
  let t = document.createElement("video");
3197
3284
  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);
3198
3285
  let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
@@ -3247,12 +3334,12 @@ async function fn() {
3247
3334
  code: e.code,
3248
3335
  message: e.message
3249
3336
  })), e.on("autoplayblocked", () => {
3250
- i({ type: "oddin:autoplayblocked" }), pn(t, e);
3337
+ i({ type: "oddin:autoplayblocked" }), wn(t, e);
3251
3338
  });
3252
3339
  }, s = async (r) => {
3253
3340
  a?.destroy(), a = null;
3254
3341
  try {
3255
- let n = await on({
3342
+ let n = await _n({
3256
3343
  video: t,
3257
3344
  baseUrl: e.baseUrl,
3258
3345
  matchUrn: r,
@@ -3314,7 +3401,7 @@ async function fn() {
3314
3401
  a?.retry();
3315
3402
  break;
3316
3403
  case "oddin:load":
3317
- typeof e.matchUrn == "string" && ln.test(e.matchUrn) && s(e.matchUrn);
3404
+ typeof e.matchUrn == "string" && bn.test(e.matchUrn) && s(e.matchUrn);
3318
3405
  break;
3319
3406
  case "oddin:destroy": c();
3320
3407
  }
@@ -3326,18 +3413,18 @@ async function fn() {
3326
3413
  protocol: 1
3327
3414
  });
3328
3415
  }
3329
- function pn(e, t) {
3416
+ function wn(e, t) {
3330
3417
  if (document.getElementById("havik-tap")) return;
3331
3418
  let n = document.createElement("button");
3332
3419
  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", () => {
3333
3420
  n.remove(), t.play();
3334
3421
  }), document.body.appendChild(n);
3335
3422
  }
3336
- function mn() {
3423
+ function Tn() {
3337
3424
  let e = document.createElement("style");
3338
3425
  e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
3339
3426
  }
3340
3427
  //#endregion
3341
- export { Rt as ODDIN_THEME, n as PlaybackError, Z as applyTheme, L as baseUrlForEnv, fn as bootEmbed, be as clearDeviceId, on as createPlayer, D as deriveEventsBaseUrl, Ne as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, pe as fetchCatalog, he as fetchTournament, _e as flattenMatches, A as getDeviceId, Fe as isLowLatencyManifest, $ as isOddinMessage, Se as licenseRequestHeaders, cn as mountEmbed, v as pollToLive, b as resolveStream, E as subscribeLiveState, C as videoFullscreenActive, ve as watchStatus };
3428
+ export { Yt as ODDIN_THEME, n as PlaybackError, Zt as applyTheme, H as baseUrlForEnv, Cn as bootEmbed, Te as clearDeviceId, _n as createPlayer, T as deriveEventsBaseUrl, ze as detectDrmSupport, S as enterVideoFullscreen, C as exitVideoFullscreen, ve as fetchCatalog, be as fetchTournament, Se as flattenMatches, O as getDeviceId, Ve as isLowLatencyManifest, $ as isOddinMessage, De as licenseRequestHeaders, yn as mountEmbed, de as pollToLive, y as resolveStream, w as subscribeLiveState, x as videoFullscreenActive, Ce as watchStatus };
3342
3429
 
3343
3430
  //# sourceMappingURL=index.js.map