@oddin-gg/havik-player 2.20.0 → 2.22.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
@@ -27,28 +27,46 @@ function r(e) {
27
27
  }
28
28
  }
29
29
  function i(e) {
30
- return e === 401 ? "UNAUTHORIZED" : e === 403 ? "FORBIDDEN" : "DRM_CLIENT";
30
+ let t = e;
31
+ if (typeof e == "string") {
32
+ if (e === "") return;
33
+ try {
34
+ t = JSON.parse(e);
35
+ } catch {
36
+ return;
37
+ }
38
+ }
39
+ if (!t || typeof t != "object") return;
40
+ let n = t.error;
41
+ if (typeof n == "string") return n === "" ? void 0 : n;
42
+ if (n && typeof n == "object") {
43
+ let e = n.code;
44
+ if (typeof e == "string" && e !== "") return e;
45
+ }
46
+ }
47
+ function a(e, t) {
48
+ return e === 401 ? "UNAUTHORIZED" : e === 403 ? t === "cdm_revoked" ? "DRM_DEVICE_REVOKED" : "FORBIDDEN" : "DRM_CLIENT";
31
49
  }
32
- var a = /* @__PURE__ */ new Set([
50
+ var o = /* @__PURE__ */ new Set([
33
51
  "TOO_EARLY",
34
52
  "UNAVAILABLE",
35
53
  "RATE_LIMITED",
36
54
  "NETWORK"
37
55
  ]);
38
- function o(e) {
39
- return a.has(e);
56
+ function s(e) {
57
+ return o.has(e);
40
58
  }
41
59
  //#endregion
42
60
  //#region src/core/types.ts
43
- async function s(e) {
61
+ async function c(e) {
44
62
  let t = typeof e == "function" ? await e() : e;
45
63
  if (!t || !t.apiKey) throw Error("havik-player: credential is missing an apiKey");
46
64
  return t;
47
65
  }
48
- function c(e) {
66
+ function l(e) {
49
67
  return e === "live" || e === "ended" || e === "upcoming" || e === "pending" ? e : "upcoming";
50
68
  }
51
- function l(e) {
69
+ function u(e) {
52
70
  if (!Array.isArray(e)) return;
53
71
  let t = [];
54
72
  for (let n of e) {
@@ -60,11 +78,11 @@ function l(e) {
60
78
  name: r,
61
79
  isHome: n.isHome === !0
62
80
  };
63
- typeof n.logoUrl == "string" && u(n.logoUrl) && (i.logoUrl = n.logoUrl), t.push(i);
81
+ typeof n.logoUrl == "string" && d(n.logoUrl) && (i.logoUrl = n.logoUrl), t.push(i);
64
82
  }
65
83
  return t.length > 0 ? t : void 0;
66
84
  }
67
- function u(e) {
85
+ function d(e) {
68
86
  try {
69
87
  return new URL(e).protocol === "https:";
70
88
  } catch {
@@ -73,7 +91,7 @@ function u(e) {
73
91
  }
74
92
  //#endregion
75
93
  //#region src/core/http.ts
76
- function d(e, t) {
94
+ function f(e, t) {
77
95
  let r = e.replace(/\/+$/, ""), i;
78
96
  try {
79
97
  i = new URL(r + t);
@@ -83,15 +101,15 @@ function d(e, t) {
83
101
  if (i.protocol !== "https:" && i.protocol !== "http:") throw new n("INTERNAL", 0, `baseUrl must be http(s), got: ${JSON.stringify(e)}`);
84
102
  return i.toString();
85
103
  }
86
- function f(e) {
104
+ function p(e) {
87
105
  if (!e) return;
88
106
  let t = Number(e);
89
107
  if (Number.isFinite(t)) return Math.max(0, Math.round(t * 1e3));
90
108
  let n = Date.parse(e);
91
109
  if (!Number.isNaN(n)) return Math.max(0, n - Date.now());
92
110
  }
93
- async function p(e, t) {
94
- let r = await s(t.credential), i = t.headers ?? new Headers();
111
+ async function m(e, t) {
112
+ let r = await c(t.credential), i = t.headers ?? new Headers();
95
113
  if (t.apiHeaders) for (let [e, n] of Object.entries(t.apiHeaders)) i.has(e) || i.set(e, n);
96
114
  i.set("x-api-key", r.apiKey);
97
115
  try {
@@ -105,55 +123,55 @@ async function p(e, t) {
105
123
  mode: "cors"
106
124
  });
107
125
  } catch (e) {
108
- throw t.signal?.aborted ? new n("ABORTED", 0, "request aborted", { cause: e }) : new n("NETWORK", 0, `network request failed: ${m(e)}`, { cause: e });
126
+ throw t.signal?.aborted ? new n("ABORTED", 0, "request aborted", { cause: e }) : new n("NETWORK", 0, `network request failed: ${h(e)}`, { cause: e });
109
127
  }
110
128
  }
111
- function m(e) {
129
+ function h(e) {
112
130
  return e instanceof Error ? e.message : String(e);
113
131
  }
114
132
  //#endregion
115
133
  //#region src/core/warnOnce.ts
116
- var h = /* @__PURE__ */ new Set();
117
- function g(e, t = e) {
118
- h.has(t) || (h.add(t), console.warn(`havik-player: ${e}`));
134
+ var g = /* @__PURE__ */ new Set();
135
+ function _(e, t = e) {
136
+ g.has(t) || (g.add(t), console.warn(`havik-player: ${e}`));
119
137
  }
120
138
  //#endregion
121
139
  //#region src/core/waitForLive.ts
122
- var _ = 1e3, ee = 3e4, te = 6e5, ne = 3e5, re = 1e3, ie = {
140
+ var ee = 1e3, te = 3e4, ne = 6e5, re = 3e5, ie = 1e3, ae = {
123
141
  TOO_EARLY: "tooEarly",
124
142
  UNAVAILABLE: "unavailable",
125
143
  RATE_LIMITED: "rateLimited",
126
144
  NETWORK: "network"
127
145
  };
128
- function ae(e) {
129
- 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);
146
+ function oe(e) {
147
+ let t = e === !0 || e === !1 ? {} : e, n = Math.max(ie, t.floorMs ?? ee), r = Math.max(n, t.ceilMs ?? te), i = Math.max(0, t.imminentMs ?? ne), a = Math.max(r, t.sanityFloorMs ?? re);
130
148
  return {
131
149
  timeoutMs: t.timeoutMs,
132
150
  floorMs: n,
133
151
  ceilMs: r,
134
152
  imminentMs: i,
135
153
  sanityFloorMs: a,
136
- kickoffMs: oe(t.kickoffAt),
154
+ kickoffMs: se(t.kickoffAt),
137
155
  jitter: t.jitter ?? !0,
138
156
  onState: t.onState
139
157
  };
140
158
  }
141
- function oe(e) {
159
+ function se(e) {
142
160
  if (e == null) return;
143
161
  if (typeof e == "number") return Number.isFinite(e) ? e : void 0;
144
162
  let t = Date.parse(e);
145
163
  return Number.isFinite(t) ? t : void 0;
146
164
  }
147
- function se(e, t, n) {
165
+ function ce(e, t, n) {
148
166
  return Math.min(n, Math.max(t, e));
149
167
  }
150
- function ce(e) {
168
+ function le(e) {
151
169
  return Math.round(e * (1 + .15 * Math.random()));
152
170
  }
153
- function le(e, t, n, r) {
171
+ function ue(e, t, n, r) {
154
172
  let i = r ?? n.kickoffMs, a = i == null ? void 0 : Math.max(0, i - t), o = Math.max(n.floorMs, e ?? 0);
155
173
  if (a == null || a <= n.imminentMs) return {
156
- delay: se(e ?? n.floorMs, o, n.ceilMs),
174
+ delay: ce(e ?? n.floorMs, o, n.ceilMs),
157
175
  ttkMs: a
158
176
  };
159
177
  let s = Math.min(Math.floor(a / 10), n.sanityFloorMs, a);
@@ -162,7 +180,7 @@ function le(e, t, n, r) {
162
180
  ttkMs: a
163
181
  };
164
182
  }
165
- function ue(e, t) {
183
+ function de(e, t) {
166
184
  return new Promise((r, i) => {
167
185
  if (t?.aborted) {
168
186
  i(new n("ABORTED", 0, "wait-for-live aborted"));
@@ -176,27 +194,27 @@ function ue(e, t) {
176
194
  t?.addEventListener("abort", a, { once: !0 });
177
195
  });
178
196
  }
179
- async function de(e, t, r) {
180
- let i = ae(t), a = Date.now(), s = i.timeoutMs == null ? Infinity : a + i.timeoutMs, c = 0, l;
197
+ async function fe(e, t, r) {
198
+ let i = oe(t), a = Date.now(), o = i.timeoutMs == null ? Infinity : a + i.timeoutMs, c = 0, l;
181
199
  for (;;) {
182
200
  if (r?.aborted) throw new n("ABORTED", 0, "wait-for-live aborted");
183
201
  try {
184
202
  return await e();
185
203
  } catch (e) {
186
- if (!(e instanceof n) || !o(e.code)) throw e;
204
+ if (!(e instanceof n) || !s(e.code)) throw e;
187
205
  c += 1, e.liveStartsAtMs != null && Number.isFinite(e.liveStartsAtMs) && (l = e.liveStartsAtMs);
188
- let t = Date.now(), u = le(e.retryAfterMs, t, i, l), d = u.ttkMs, f = u.delay;
189
- 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`, {
206
+ let t = Date.now(), u = ue(e.retryAfterMs, t, i, l), d = u.ttkMs, f = u.delay;
207
+ if (i.jitter && (f = le(f)), t + f > o) throw new n("TIMEOUT", e.httpStatus, `timed out after ${i.timeoutMs}ms waiting for the stream to go live`, {
190
208
  retryAfterMs: e.retryAfterMs,
191
209
  cause: e
192
210
  });
193
211
  i.onState?.({
194
- phase: ie[e.code] ?? "unavailable",
212
+ phase: ae[e.code] ?? "unavailable",
195
213
  retryInMs: f,
196
214
  attempt: c,
197
215
  elapsedMs: t - a,
198
216
  ttkMs: d
199
- }), await ue(f, r);
217
+ }), await de(f, r);
200
218
  }
201
219
  }
202
220
  }
@@ -204,20 +222,20 @@ async function de(e, t, r) {
204
222
  //#region src/core/resolve.ts
205
223
  async function v(e) {
206
224
  if (!e.matchUrn || typeof e.matchUrn != "string") throw new n("INVALID_URN", 0, "resolveStream: a non-empty matchUrn is required");
207
- let t = await p(d(e.baseUrl, `/v1/playback/${encodeURIComponent(e.matchUrn)}`), {
225
+ let t = await m(f(e.baseUrl, `/v1/playback/${encodeURIComponent(e.matchUrn)}`), {
208
226
  credential: e.credential,
209
227
  signal: e.signal,
210
228
  apiHeaders: e.apiHeaders
211
229
  });
212
- if (!t.ok) throw await fe(t);
213
- return he(await t.json(), e.matchUrn);
230
+ if (!t.ok) throw await pe(t);
231
+ return ge(await t.json(), e.matchUrn);
214
232
  }
215
233
  function y(e) {
216
234
  let t = () => v(e);
217
- return e.waitForLive ? de(t, e.waitForLive, e.signal) : t();
235
+ return e.waitForLive ? fe(t, e.waitForLive, e.signal) : t();
218
236
  }
219
- async function fe(e) {
220
- 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, c;
237
+ async function pe(e) {
238
+ let t = p(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, c;
221
239
  try {
222
240
  let t = await e.json();
223
241
  if (t?.error?.message && (a = t.error.message), t?.error?.code && (o = t.error.code), typeof t?.liveStartsAt == "string") {
@@ -234,7 +252,7 @@ async function fe(e) {
234
252
  country: c
235
253
  });
236
254
  }
237
- var pe = /* @__PURE__ */ new Set([
255
+ var me = /* @__PURE__ */ new Set([
238
256
  "matchUrn",
239
257
  "protocol",
240
258
  "drmEnabled",
@@ -255,16 +273,16 @@ function b(e, t) {
255
273
  if (r.protocol !== "https:" && r.protocol !== "http:") throw new n("INTERNAL", 0, `playback ${e} has a disallowed scheme: ${r.protocol}`);
256
274
  return t;
257
275
  }
258
- function me(e) {
276
+ function he(e) {
259
277
  if (e !== void 0) {
260
278
  if (typeof e == "string" && !e.endsWith("/")) try {
261
279
  let t = new URL(e);
262
280
  if (t.protocol === "https:" && t.href === `${t.origin}/`) return t.origin;
263
281
  } catch {}
264
- g(`server analytics.endpoint ${JSON.stringify(e)} ignored: not a bare https origin.`);
282
+ _(`server analytics.endpoint ${JSON.stringify(e)} ignored: not a bare https origin.`);
265
283
  }
266
284
  }
267
- function he(e, t) {
285
+ function ge(e, t) {
268
286
  if (!e.manifestUrl) throw new n("INTERNAL", 0, "playback response is missing manifestUrl");
269
287
  let r = e.drmEnabled ?? !!e.drm, i = {
270
288
  matchUrn: e.matchUrn ?? t,
@@ -275,7 +293,7 @@ function he(e, t) {
275
293
  };
276
294
  if (e.liveStartsAt && (i.liveStartsAt = e.liveStartsAt), typeof e.analytics?.sid == "string" && e.analytics.sid) {
277
295
  i.analytics = { sid: e.analytics.sid };
278
- let t = me(e.analytics.endpoint);
296
+ let t = he(e.analytics.endpoint);
279
297
  t && (i.analytics.endpoint = t);
280
298
  }
281
299
  if (r && e.drm) {
@@ -286,7 +304,7 @@ function he(e, t) {
286
304
  }), (t.widevine || t.fairplay) && (i.drm = t);
287
305
  }
288
306
  let a = {};
289
- for (let [t, n] of Object.entries(e)) pe.has(t) || (a[t] = n);
307
+ for (let [t, n] of Object.entries(e)) me.has(t) || (a[t] = n);
290
308
  return Object.keys(a).length > 0 && (i.extensions = a), i;
291
309
  }
292
310
  //#endregion
@@ -294,11 +312,11 @@ function he(e, t) {
294
312
  function x(e) {
295
313
  return e.ownerDocument ?? document;
296
314
  }
297
- function ge(e) {
315
+ function _e(e) {
298
316
  return e.fullscreenElement ?? e.webkitFullscreenElement ?? null;
299
317
  }
300
318
  function S(e, t) {
301
- let n = ge(x(e));
319
+ let n = _e(x(e));
302
320
  return n != null && (n === e || t != null && n === t) || e.webkitDisplayingFullscreen === !0;
303
321
  }
304
322
  function C(e, t) {
@@ -321,17 +339,17 @@ async function T(e, t) {
321
339
  n.webkitExitFullscreen?.();
322
340
  return;
323
341
  }
324
- let r = x(e), i = ge(r);
342
+ let r = x(e), i = _e(r);
325
343
  i != null && (i === e || t != null && i === t) && (typeof r.exitFullscreen == "function" ? await r.exitFullscreen() : r.webkitExitFullscreen?.());
326
344
  }
327
345
  //#endregion
328
346
  //#region src/core/catalog.ts
329
- async function _e(e) {
347
+ async function ve(e) {
330
348
  let t = new URLSearchParams();
331
349
  e.status && t.set("status", Array.isArray(e.status) ? e.status.join(",") : e.status), e.sport && t.set("sport", e.sport);
332
- let i = t.toString(), a = d(e.baseUrl, "/v1/catalog" + (i ? `?${i}` : "")), o = new Headers();
350
+ let i = t.toString(), a = f(e.baseUrl, "/v1/catalog" + (i ? `?${i}` : "")), o = new Headers();
333
351
  e.etag && o.set("If-None-Match", e.etag);
334
- let s = await p(a, {
352
+ let s = await m(a, {
335
353
  credential: e.credential,
336
354
  signal: e.signal,
337
355
  headers: o,
@@ -344,12 +362,12 @@ async function _e(e) {
344
362
  };
345
363
  if (!s.ok) throw new n(r(s.status), s.status, `catalog request failed (HTTP ${s.status})`);
346
364
  return {
347
- tournaments: ve(await s.json()),
365
+ tournaments: ye(await s.json()),
348
366
  etag: s.headers.get("etag") ?? void 0,
349
367
  notModified: !1
350
368
  };
351
369
  }
352
- function ve(e) {
370
+ function ye(e) {
353
371
  return (e.tournaments ?? []).map((e) => {
354
372
  let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
355
373
  return {
@@ -360,21 +378,21 @@ function ve(e) {
360
378
  matches: (e.matches ?? []).map((e) => ({
361
379
  matchUrn: e.matchUrn ?? "",
362
380
  matchName: e.matchName ?? "",
363
- status: c(e.status),
381
+ status: l(e.status),
364
382
  statusRaw: e.status,
365
383
  datePlannedStart: e.datePlannedStart,
366
384
  tournamentUrn: t,
367
385
  tournamentName: n,
368
386
  sport: r,
369
- teams: l(e.teams)
387
+ teams: u(e.teams)
370
388
  }))
371
389
  };
372
390
  });
373
391
  }
374
- async function ye(e) {
375
- let t = d(e.baseUrl, `/v1/tournaments/${encodeURIComponent(e.urn)}`), i = new Headers();
392
+ async function be(e) {
393
+ let t = f(e.baseUrl, `/v1/tournaments/${encodeURIComponent(e.urn)}`), i = new Headers();
376
394
  e.etag && i.set("If-None-Match", e.etag);
377
- let a = await p(t, {
395
+ let a = await m(t, {
378
396
  credential: e.credential,
379
397
  signal: e.signal,
380
398
  headers: i,
@@ -391,13 +409,13 @@ async function ye(e) {
391
409
  };
392
410
  if (!a.ok) throw new n(r(a.status), a.status, `tournament request failed (HTTP ${a.status})`);
393
411
  return {
394
- tournament: be(await a.json()),
412
+ tournament: xe(await a.json()),
395
413
  etag: a.headers.get("etag") ?? void 0,
396
414
  notModified: !1,
397
415
  notFound: !1
398
416
  };
399
417
  }
400
- function be(e) {
418
+ function xe(e) {
401
419
  let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
402
420
  return {
403
421
  urn: t,
@@ -407,44 +425,44 @@ function be(e) {
407
425
  matches: (e.matches ?? []).map((e) => ({
408
426
  matchUrn: e.matchUrn ?? "",
409
427
  matchName: e.matchName ?? "",
410
- status: c(e.status),
428
+ status: l(e.status),
411
429
  statusRaw: e.status,
412
430
  datePlannedStart: e.datePlannedStart,
413
431
  tournamentUrn: t,
414
432
  tournamentName: n,
415
433
  sport: r,
416
- teams: l(e.teams)
434
+ teams: u(e.teams)
417
435
  }))
418
436
  };
419
437
  }
420
- function xe(e) {
438
+ function Se(e) {
421
439
  return e.tournaments.flatMap((e) => e.matches);
422
440
  }
423
441
  //#endregion
424
442
  //#region src/core/poll.ts
425
- var Se = /* @__PURE__ */ new Set([
443
+ var Ce = /* @__PURE__ */ new Set([
426
444
  "NOT_FOUND",
427
445
  "GEO_DENIED",
428
446
  "GONE",
429
447
  "INVALID_URN"
430
448
  ]);
431
- function Ce(e) {
432
- let t = Math.max(2e3, e.intervalMs ?? 1e4), i = new AbortController(), a, o, s, u = !1, f = () => {
433
- u || (a = setTimeout(m, t));
434
- }, m = async () => {
449
+ function we(e) {
450
+ let t = Math.max(2e3, e.intervalMs ?? 1e4), i = new AbortController(), a, o, s, c = !1, d = () => {
451
+ c || (a = setTimeout(p, t));
452
+ }, p = async () => {
435
453
  try {
436
- let t = d(e.baseUrl, `/v1/matches/${encodeURIComponent(e.matchUrn)}`), a = new Headers();
454
+ let t = f(e.baseUrl, `/v1/matches/${encodeURIComponent(e.matchUrn)}`), a = new Headers();
437
455
  o && a.set("If-None-Match", o);
438
- let u = await p(t, {
456
+ let c = await m(t, {
439
457
  credential: e.credential,
440
458
  signal: i.signal,
441
459
  headers: a,
442
460
  apiHeaders: e.apiHeaders
443
461
  });
444
- if (u.status !== 304) {
445
- if (!u.ok) throw new n(r(u.status), u.status, `match status request failed (HTTP ${u.status})`);
446
- o = u.headers.get("etag") ?? o;
447
- let t = await u.json(), i = c(t.status), a = typeof t.status == "string" ? t.status : i, d = l(t.teams), f = JSON.stringify([
462
+ if (c.status !== 304) {
463
+ if (!c.ok) throw new n(r(c.status), c.status, `match status request failed (HTTP ${c.status})`);
464
+ o = c.headers.get("etag") ?? o;
465
+ let t = await c.json(), i = l(t.status), a = typeof t.status == "string" ? t.status : i, d = u(t.teams), f = JSON.stringify([
448
466
  a,
449
467
  t.datePlannedStart ?? null,
450
468
  d ?? null
@@ -461,21 +479,21 @@ function Ce(e) {
461
479
  } catch (t) {
462
480
  if (!i.signal.aborted) {
463
481
  let r = t instanceof n ? t : new n("NETWORK", 0, String(t));
464
- Se.has(r.code) && (u = !0), e.onError?.(r);
482
+ Ce.has(r.code) && (c = !0), e.onError?.(r);
465
483
  }
466
484
  } finally {
467
- f();
485
+ d();
468
486
  }
469
487
  };
470
- return m(), { stop() {
471
- u = !0, i.abort(), a && clearTimeout(a);
488
+ return p(), { stop() {
489
+ c = !0, i.abort(), a && clearTimeout(a);
472
490
  } };
473
491
  }
474
492
  //#endregion
475
493
  //#region src/core/events.ts
476
- var we = 45e3;
494
+ var Te = 45e3;
477
495
  function E(e) {
478
- 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) => {
496
+ let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = e.idleTimeoutMs ?? Te, i = Number.isFinite(r) && r > 0 ? r : 0, a = new AbortController(), o = !1, s = (e) => new Promise((t) => {
479
497
  if (a.signal.aborted) return t();
480
498
  let n = setTimeout(t, e);
481
499
  a.signal.addEventListener("abort", () => {
@@ -495,7 +513,7 @@ function E(e) {
495
513
  let t = JSON.parse(r.join("\n"));
496
514
  t && typeof t.state == "string" && e.onState(t);
497
515
  } catch {}
498
- }, u = /\r\n\r\n|\n\n|\r\r/, f = async (e, t, n) => {
516
+ }, u = /\r\n\r\n|\n\n|\r\r/, d = async (e, t, n) => {
499
517
  let r = e.getReader(), a = new TextDecoder(), s = "", c = !1, d, f = () => {
500
518
  i && (clearTimeout(d), d = setTimeout(() => {
501
519
  n(), r.cancel().catch(() => {});
@@ -523,13 +541,13 @@ function E(e) {
523
541
  p = `no data for ${i}ms`, l.abort();
524
542
  };
525
543
  try {
526
- let n = await s(e.credential);
544
+ let n = await c(e.credential);
527
545
  if (o) return;
528
- let a = d(e.eventsBaseUrl, `/v1/events/${encodeURIComponent(e.matchUrn)}`);
546
+ let a = f(e.eventsBaseUrl, `/v1/events/${encodeURIComponent(e.matchUrn)}`);
529
547
  i && (m = setTimeout(() => {
530
548
  p = `no response headers within ${i}ms`, l.abort();
531
549
  }, i));
532
- let c = await fetch(a, {
550
+ let s = await fetch(a, {
533
551
  method: "GET",
534
552
  headers: {
535
553
  "x-api-key": n.apiKey,
@@ -541,7 +559,7 @@ function E(e) {
541
559
  mode: "cors"
542
560
  });
543
561
  if (clearTimeout(m), o) return;
544
- !c.ok || !c.body ? e.onError?.(/* @__PURE__ */ Error(`live-state subscribe failed: HTTP ${c.status}`)) : await f(c.body, () => {
562
+ !s.ok || !s.body ? e.onError?.(/* @__PURE__ */ Error(`live-state subscribe failed: HTTP ${s.status}`)) : await d(s.body, () => {
545
563
  r = t;
546
564
  }, h);
547
565
  } catch (t) {
@@ -551,7 +569,7 @@ function E(e) {
551
569
  clearTimeout(m), a.signal.removeEventListener("abort", u), l.abort();
552
570
  }
553
571
  if (o) return;
554
- p && e.onError?.(/* @__PURE__ */ Error(`live-state subscribe idle: ${p} — reconnecting`)), await c(r), r = Math.min(n, r * 2);
572
+ p && e.onError?.(/* @__PURE__ */ Error(`live-state subscribe idle: ${p} — reconnecting`)), await s(r), r = Math.min(n, r * 2);
555
573
  }
556
574
  })(), { close() {
557
575
  o || (o = !0, a.abort());
@@ -574,20 +592,20 @@ function A() {
574
592
  let e = globalThis.localStorage?.getItem(O);
575
593
  if (e) return k = e, e;
576
594
  } catch {}
577
- let e = Ee();
595
+ let e = De();
578
596
  k = e;
579
597
  try {
580
598
  globalThis.localStorage?.setItem(O, e);
581
599
  } catch {}
582
600
  return e;
583
601
  }
584
- function Te() {
602
+ function Ee() {
585
603
  k = void 0;
586
604
  try {
587
605
  globalThis.localStorage?.removeItem(O);
588
606
  } catch {}
589
607
  }
590
- function Ee() {
608
+ function De() {
591
609
  let e = globalThis.crypto;
592
610
  if (e && typeof e.randomUUID == "function") return e.randomUUID();
593
611
  let t = /* @__PURE__ */ new Uint8Array(16);
@@ -599,7 +617,7 @@ function Ee() {
599
617
  }
600
618
  //#endregion
601
619
  //#region src/core/drm/headers.ts
602
- function De(e, t, n = {}) {
620
+ function Oe(e, t, n = {}) {
603
621
  let r = {
604
622
  "x-api-key": t.apiKey,
605
623
  "X-Match-Urn": e.matchUrn,
@@ -610,19 +628,19 @@ function De(e, t, n = {}) {
610
628
  }
611
629
  //#endregion
612
630
  //#region src/core/bandwidthMemory.ts
613
- var j = "havik.player.bandwidth", Oe = .8, ke = 2e7, Ae = 3e5;
614
- function je() {
631
+ var j = "havik.player.bandwidth", ke = .8, Ae = 2e7, je = 3e5;
632
+ function Me() {
615
633
  return globalThis.navigator?.connection;
616
634
  }
617
- function Me() {
618
- let e = je()?.type;
635
+ function Ne() {
636
+ let e = Me()?.type;
619
637
  return typeof e == "string" && e !== "" && e !== "unknown" ? e : "any";
620
638
  }
621
- function Ne() {
622
- let e = je()?.downlink;
639
+ function Pe() {
640
+ let e = Me()?.downlink;
623
641
  return typeof e == "number" && Number.isFinite(e) && e > 0 ? e * 1e6 : void 0;
624
642
  }
625
- function Pe() {
643
+ function Fe() {
626
644
  try {
627
645
  let e = globalThis.localStorage?.getItem(j);
628
646
  if (!e) return {};
@@ -632,18 +650,18 @@ function Pe() {
632
650
  return {};
633
651
  }
634
652
  }
635
- function Fe(e = Date.now()) {
636
- let t = Pe()[Me()];
653
+ function Ie(e = Date.now()) {
654
+ let t = Fe()[Ne()];
637
655
  if (!t || typeof t.bps != "number" || typeof t.at != "number" || !Number.isFinite(t.bps) || t.bps <= 0) return;
638
656
  let n = e - t.at;
639
657
  if (n < 0 || n > 2592e5) return;
640
- let r = Ne(), i = r === void 0 ? t.bps : Math.min(t.bps, r);
641
- return Math.round(Math.min(ke, Math.max(Ae, i * Oe)));
658
+ let r = Pe(), i = r === void 0 ? t.bps : Math.min(t.bps, r);
659
+ return Math.round(Math.min(Ae, Math.max(je, i * ke)));
642
660
  }
643
- function Ie(e, t = Date.now()) {
661
+ function Le(e, t = Date.now()) {
644
662
  if (!Number.isFinite(e) || e <= 0) return;
645
- let n = Pe();
646
- n[Me()] = {
663
+ let n = Fe();
664
+ n[Ne()] = {
647
665
  bps: Math.round(e),
648
666
  at: t
649
667
  };
@@ -651,17 +669,17 @@ function Ie(e, t = Date.now()) {
651
669
  globalThis.localStorage?.setItem(j, JSON.stringify(n));
652
670
  } catch {}
653
671
  }
654
- function Le() {
672
+ function Re() {
655
673
  try {
656
674
  globalThis.localStorage?.removeItem(j);
657
675
  } catch {}
658
676
  }
659
677
  //#endregion
660
678
  //#region src/core/drm/cdm.ts
661
- var Re = /* @__PURE__ */ new WeakMap();
662
- function ze(e, t) {
663
- let n = Re.get(e);
664
- n || (n = /* @__PURE__ */ new Map(), Re.set(e, n));
679
+ var ze = /* @__PURE__ */ new WeakMap();
680
+ function Be(e, t) {
681
+ let n = ze.get(e);
682
+ n || (n = /* @__PURE__ */ new Map(), ze.set(e, n));
665
683
  let r = n.get(t.keySystem);
666
684
  if (r) return r;
667
685
  let i = t.createMediaKeys().catch((e) => {
@@ -673,11 +691,11 @@ function M() {
673
691
  return typeof navigator < "u" && typeof navigator.requestMediaKeySystemAccess == "function";
674
692
  }
675
693
  var N = ["SW_SECURE_DECODE", "SW_SECURE_CRYPTO"];
676
- function Be(e) {
694
+ function Ve(e) {
677
695
  return e.startsWith("com.widevine");
678
696
  }
679
697
  function P(e, t) {
680
- if (!Be(e)) return t;
698
+ if (!Ve(e)) return t;
681
699
  let n = (e, t) => {
682
700
  let n = e.videoCapabilities;
683
701
  return !n?.length || !n.some((e) => e.robustness) ? !1 : n.every((e) => {
@@ -693,11 +711,11 @@ function P(e, t) {
693
711
  })));
694
712
  return [...t, ...r];
695
713
  }
696
- function Ve(e) {
714
+ function He(e) {
697
715
  return (t, n) => M() ? navigator.requestMediaKeySystemAccess(t, P(t, n)).then((t) => ({
698
716
  keySystem: t.keySystem,
699
717
  getConfiguration: () => t.getConfiguration(),
700
- createMediaKeys: () => ze(e, t)
718
+ createMediaKeys: () => Be(e, t)
701
719
  })) : Promise.reject(/* @__PURE__ */ Error("navigator.requestMediaKeySystemAccess is unavailable — EME needs a secure context (https, or localhost)"));
702
720
  }
703
721
  var F = {
@@ -705,14 +723,14 @@ var F = {
705
723
  audio: "SW_SECURE_CRYPTO",
706
724
  scheme: "cbcs"
707
725
  };
708
- function He(e) {
726
+ function Ue(e) {
709
727
  if (!M()) return;
710
728
  let t = (e, t) => ({
711
729
  contentType: e,
712
730
  robustness: t,
713
731
  encryptionScheme: F.scheme
714
732
  });
715
- Ve(e)("com.widevine.alpha", [{
733
+ He(e)("com.widevine.alpha", [{
716
734
  initDataTypes: ["cenc"],
717
735
  distinctiveIdentifier: "optional",
718
736
  persistentState: "optional",
@@ -732,14 +750,14 @@ function I(e) {
732
750
  function L(e) {
733
751
  return (e ?? "").trim().toLowerCase();
734
752
  }
735
- var Ue = {
753
+ var We = {
736
754
  hevc: "hvc1.1.6.L93.90",
737
755
  dv: "dvh1.05.06",
738
756
  av1: "av01.0.05M.08",
739
757
  vp9: "vp09.00.10.08"
740
- }, We = /* @__PURE__ */ new Map(), R = /* @__PURE__ */ new Map();
741
- function Ge(e) {
742
- let t = L(e), n = We.get(t);
758
+ }, Ge = /* @__PURE__ */ new Map(), R = /* @__PURE__ */ new Map();
759
+ function Ke(e) {
760
+ let t = L(e), n = Ge.get(t);
743
761
  if (n) return n;
744
762
  let r = {
745
763
  initDataTypes: ["cenc"],
@@ -758,22 +776,22 @@ function Ge(e) {
758
776
  return !1;
759
777
  }
760
778
  })().then((e) => (R.set(t, e), e));
761
- return We.set(t, i), i;
779
+ return Ge.set(t, i), i;
762
780
  }
763
- function Ke() {
764
- if (M()) for (let e of Object.values(Ue)) Ge(e);
781
+ function qe() {
782
+ if (M()) for (let e of Object.values(We)) Ke(e);
765
783
  }
766
- function qe(e) {
784
+ function Je(e) {
767
785
  let t = I(e);
768
- if (t) return t === "avc" ? !0 : R.get(L(e)) ?? R.get(L(Ue[t]));
786
+ if (t) return t === "avc" ? !0 : R.get(L(e)) ?? R.get(L(We[t]));
769
787
  }
770
788
  //#endregion
771
789
  //#region src/core/drm/support.ts
772
- var Je = 5e3, Ye = "video/mp4; codecs=\"avc1.42E01E\"", Xe = "audio/mp4; codecs=\"mp4a.40.2\"", Ze = {
790
+ var Ye = 5e3, Xe = "video/mp4; codecs=\"avc1.42E01E\"", Ze = "audio/mp4; codecs=\"mp4a.40.2\"", Qe = {
773
791
  widevine: ["com.widevine.alpha"],
774
792
  fairplay: ["com.apple.fps"]
775
793
  };
776
- function Qe(e) {
794
+ function $e(e) {
777
795
  return e === "fairplay" ? [{
778
796
  initDataTypes: [
779
797
  "sinf",
@@ -781,30 +799,30 @@ function Qe(e) {
781
799
  "cenc"
782
800
  ],
783
801
  videoCapabilities: [{
784
- contentType: Ye,
802
+ contentType: Xe,
785
803
  robustness: "",
786
804
  encryptionScheme: "cbcs"
787
805
  }],
788
806
  audioCapabilities: [{
789
- contentType: Xe,
807
+ contentType: Ze,
790
808
  robustness: "",
791
809
  encryptionScheme: "cbcs"
792
810
  }]
793
811
  }] : P("com.widevine.alpha", [{
794
812
  initDataTypes: ["cenc"],
795
813
  videoCapabilities: [{
796
- contentType: Ye,
814
+ contentType: Xe,
797
815
  robustness: F.video,
798
816
  encryptionScheme: F.scheme
799
817
  }],
800
818
  audioCapabilities: [{
801
- contentType: Xe,
819
+ contentType: Ze,
802
820
  robustness: F.audio,
803
821
  encryptionScheme: F.scheme
804
822
  }]
805
823
  }]);
806
824
  }
807
- function $e(e, t) {
825
+ function et(e, t) {
808
826
  return new Promise((n, r) => {
809
827
  let i = setTimeout(() => r(/* @__PURE__ */ Error("probe-timeout")), t);
810
828
  e.then((e) => {
@@ -814,8 +832,8 @@ function $e(e, t) {
814
832
  });
815
833
  });
816
834
  }
817
- async function et(e = {}) {
818
- let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Je, r = {};
835
+ async function tt(e = {}) {
836
+ let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Ye, r = {};
819
837
  if (typeof window < "u" && window.isSecureContext === !1) return {
820
838
  verdict: "insecure-context",
821
839
  detail: r
@@ -827,7 +845,7 @@ async function et(e = {}) {
827
845
  };
828
846
  let a = !1, o = !1, s = Date.now() + n, c = () => Math.max(1, s - Date.now());
829
847
  for (let e of t) {
830
- let t = Ze[e];
848
+ let t = Qe[e];
831
849
  if (!t) {
832
850
  r[e] = "unknown system";
833
851
  continue;
@@ -838,7 +856,7 @@ async function et(e = {}) {
838
856
  break;
839
857
  }
840
858
  try {
841
- return await $e((await $e(i(n, Qe(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
859
+ return await et((await et(i(n, $e(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
842
860
  verdict: "supported",
843
861
  system: e,
844
862
  detail: r
@@ -862,37 +880,37 @@ async function et(e = {}) {
862
880
  }
863
881
  //#endregion
864
882
  //#region src/core/manifest.ts
865
- var tt = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
866
- function nt(e) {
867
- return tt.test(e);
883
+ var nt = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
884
+ function rt(e) {
885
+ return nt.test(e);
868
886
  }
869
887
  //#endregion
870
888
  //#region src/core/env.ts
871
- var rt = {
889
+ var it = {
872
890
  integration: "https://feed-dev.oddin-video.gg",
873
891
  production: "https://feed.oddin-video.gg"
874
892
  };
875
- function it(e) {
876
- let t = Object.prototype.hasOwnProperty.call(rt, e) ? rt[e] : void 0;
893
+ function at(e) {
894
+ let t = Object.prototype.hasOwnProperty.call(it, e) ? it[e] : void 0;
877
895
  if (!t) throw new n("INTERNAL", 0, `unknown env ${JSON.stringify(e)} — expected 'integration' or 'production'`);
878
896
  return t;
879
897
  }
880
898
  //#endregion
881
899
  //#region src/core/stats.ts
882
900
  var z = { droppedFrames: 0 };
883
- function at(e) {
901
+ function ot(e) {
884
902
  try {
885
903
  return new URL(e).host;
886
904
  } catch {
887
905
  return "";
888
906
  }
889
907
  }
890
- var ot = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
891
- function st(e) {
908
+ var st = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
909
+ function ct(e) {
892
910
  if (typeof performance > "u" || typeof performance.getEntriesByType != "function") return "";
893
911
  let t = "", n = -1, r = performance.getEntriesByType("resource");
894
- for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || ot.test(i.name)) && i.startTime >= n) {
895
- let e = at(i.name);
912
+ for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || st.test(i.name)) && i.startTime >= n) {
913
+ let e = ot(i.name);
896
914
  e && (t = e, n = i.startTime);
897
915
  }
898
916
  return t;
@@ -904,7 +922,7 @@ function B(e) {
904
922
  totalFrames: t?.totalVideoFrames ?? 0
905
923
  };
906
924
  }
907
- var ct = class {
925
+ var lt = class {
908
926
  video;
909
927
  baseFrames = 0;
910
928
  baseDropped = 0;
@@ -927,7 +945,7 @@ var ct = class {
927
945
  };
928
946
  }
929
947
  };
930
- function lt(e, t) {
948
+ function ut(e, t) {
931
949
  let n = [
932
950
  ["playing", () => t("playing")],
933
951
  ["waiting", () => t("buffering")],
@@ -944,8 +962,8 @@ function lt(e, t) {
944
962
  }
945
963
  //#endregion
946
964
  //#region src/core/engine/native.ts
947
- var ut = 2e3, dt = 3, V = 500, ft = 6e3, pt = .25, mt = 250, ht = .05, gt = 4, _t = 12e3, vt = .25, yt = 1e3;
948
- function bt(e) {
965
+ var dt = 2e3, ft = 3, V = 500, pt = 6e3, mt = .25, ht = 250, gt = .05, _t = 4, vt = 12e3, yt = .25, bt = 1e3;
966
+ function xt(e) {
949
967
  try {
950
968
  let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
951
969
  return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
@@ -961,7 +979,7 @@ function U() {
961
979
  let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
962
980
  return e || t;
963
981
  }
964
- function xt() {
982
+ function St() {
965
983
  if (typeof navigator > "u" || !U()) return !1;
966
984
  let e = navigator.userAgent ?? "";
967
985
  return /iPhone|iPad|iPod/.test(e) ? !0 : /Macintosh/.test(e) && typeof navigator.maxTouchPoints == "number" && navigator.maxTouchPoints > 1;
@@ -996,7 +1014,7 @@ var W = class {
996
1014
  frameCounter;
997
1015
  detachFrames = null;
998
1016
  constructor(e) {
999
- this.deps = e, this.frameCounter = new ct(e.video), this.loadStarted = e.deferLoad !== !0, this.builtAt = typeof performance < "u" ? performance.now() : 0;
1017
+ this.deps = e, this.frameCounter = new lt(e.video), this.loadStarted = e.deferLoad !== !0, this.builtAt = typeof performance < "u" ? performance.now() : 0;
1000
1018
  }
1001
1019
  async load() {
1002
1020
  this.detachFrames ??= this.frameCounter.attach();
@@ -1017,7 +1035,7 @@ var W = class {
1017
1035
  type: "error",
1018
1036
  error: new n("INTERNAL", 0, "native HLS playback error"),
1019
1037
  fatal: !0
1020
- }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = Ct(t.manifestUrl, t.analytics?.sid), e.load();
1038
+ }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = wt(t.manifestUrl, t.analytics?.sid), e.load();
1021
1039
  }
1022
1040
  startLoad() {
1023
1041
  this.loadStarted || (this.loadStarted = !0, this.restorePreload());
@@ -1029,20 +1047,26 @@ var W = class {
1029
1047
  this.savedPreload === null ? e.removeAttribute("preload") : e.setAttribute("preload", this.savedPreload);
1030
1048
  }
1031
1049
  armFairPlay() {
1032
- let { video: e, descriptor: t, credential: r, deviceId: a, userId: o, emit: s } = this.deps, c = t.drm?.fairplay;
1033
- if (!c) return;
1034
- this.fairplayLicenseUrl = c.licenseUrl;
1035
- let l = (e, t, r) => s({
1050
+ let { video: e, descriptor: t, credential: r, deviceId: o, userId: s, emit: c } = this.deps, l = t.drm?.fairplay;
1051
+ if (!l) return;
1052
+ this.fairplayLicenseUrl = l.licenseUrl;
1053
+ let u = (e, t, r, i) => c({
1036
1054
  type: "error",
1037
- error: new n(i(t), t, e),
1055
+ error: new n(a(t, i), t, e, i ? { serverCode: i } : void 0),
1038
1056
  fatal: r
1039
- });
1057
+ }), d = async (e) => {
1058
+ try {
1059
+ return await e.text();
1060
+ } catch {
1061
+ return "";
1062
+ }
1063
+ };
1040
1064
  this.onEncrypted = (n) => {
1041
- let i = n;
1042
- i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = bt(i.initData), (async () => {
1065
+ let a = n;
1066
+ a.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = xt(a.initData), (async () => {
1043
1067
  try {
1044
1068
  let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
1045
- initDataTypes: [i.initDataType],
1069
+ initDataTypes: [a.initDataType],
1046
1070
  videoCapabilities: [{
1047
1071
  contentType: "application/vnd.apple.mpegurl",
1048
1072
  robustness: ""
@@ -1050,39 +1074,40 @@ var W = class {
1050
1074
  distinctiveIdentifier: "not-allowed",
1051
1075
  persistentState: "not-allowed",
1052
1076
  sessionTypes: ["temporary"]
1053
- }])).createMediaKeys(), s = await fetch(c.certificateUrl, { headers: { "x-api-key": r.apiKey } });
1054
- if (!s.ok) {
1055
- this.fairplayArmed = !1, l(`FairPlay certificate request failed: ${s.status}`, s.status, !0);
1077
+ }])).createMediaKeys(), c = await fetch(l.certificateUrl, { headers: { "x-api-key": r.apiKey } });
1078
+ if (!c.ok) {
1079
+ this.fairplayArmed = !1, u(`FairPlay certificate request failed: ${c.status}`, c.status, !0);
1056
1080
  return;
1057
1081
  }
1058
- await n.setServerCertificate(await s.arrayBuffer()), await e.setMediaKeys(n);
1059
- let u = n.createSession();
1060
- this.keySession = u, u.addEventListener("message", (e) => {
1082
+ await n.setServerCertificate(await c.arrayBuffer()), await e.setMediaKeys(n);
1083
+ let f = n.createSession();
1084
+ this.keySession = f, f.addEventListener("message", (e) => {
1061
1085
  (async () => {
1062
1086
  try {
1063
- let n = await fetch(this.fairplayLicenseUrl ?? c.licenseUrl, {
1087
+ let n = await fetch(this.fairplayLicenseUrl ?? l.licenseUrl, {
1064
1088
  method: "POST",
1065
1089
  body: e.message,
1066
1090
  headers: {
1067
1091
  "x-api-key": r.apiKey,
1068
1092
  "X-Match-Urn": t.matchUrn,
1069
- "X-Device-Id": a,
1070
- ...o ? { "X-User-Id": o } : {},
1093
+ "X-Device-Id": o,
1094
+ ...s ? { "X-User-Id": s } : {},
1071
1095
  ...this.fairplayKeyIV ? { "X-Key-Iv": this.fairplayKeyIV } : {}
1072
1096
  }
1073
1097
  });
1074
1098
  if (!n.ok) {
1075
- l(`FairPlay license request failed: ${n.status}`, n.status, !0);
1099
+ let e = n.status === 403 ? i(await d(n)) : void 0;
1100
+ u(`FairPlay license request failed: ${n.status}`, n.status, !0, e);
1076
1101
  return;
1077
1102
  }
1078
- await u.update(new Uint8Array(await n.arrayBuffer()));
1103
+ await f.update(new Uint8Array(await n.arrayBuffer()));
1079
1104
  } catch (e) {
1080
- l(`FairPlay license request failed: ${String(e)}`, 0, !0);
1105
+ u(`FairPlay license request failed: ${String(e)}`, 0, !0);
1081
1106
  }
1082
1107
  })();
1083
- }), await u.generateRequest(i.initDataType, i.initData);
1108
+ }), await f.generateRequest(a.initDataType, a.initData);
1084
1109
  } catch (e) {
1085
- this.fairplayArmed = !1, l(`FairPlay key session failed: ${String(e)}`, 0, !0);
1110
+ this.fairplayArmed = !1, u(`FairPlay key session failed: ${String(e)}`, 0, !0);
1086
1111
  }
1087
1112
  })());
1088
1113
  }, e.addEventListener("encrypted", this.onEncrypted);
@@ -1138,10 +1163,10 @@ var W = class {
1138
1163
  droppedFrames: t.dropped,
1139
1164
  decodedFrames: t.totalFrames
1140
1165
  };
1141
- if (this.cdnHost ||= st(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity) {
1166
+ if (this.cdnHost ||= ct(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity) {
1142
1167
  n.isLive = !0;
1143
1168
  let t = this.liveEdgeEstimate(), r = t == null ? NaN : t - e.currentTime;
1144
- Number.isFinite(r) && (n.atLiveEdge = r <= gt, !e.paused && r >= 0 && (n.latencySeconds = r));
1169
+ Number.isFinite(r) && (n.atLiveEdge = r <= _t, !e.paused && r >= 0 && (n.latencySeconds = r));
1145
1170
  } else Number.isFinite(e.duration) && e.duration > 0 && (n.isLive = !1);
1146
1171
  return n;
1147
1172
  }
@@ -1159,7 +1184,7 @@ var W = class {
1159
1184
  return;
1160
1185
  }
1161
1186
  let t = this.hiddenSince;
1162
- this.hiddenSince = null, t != null && e - t >= ut && this.armRefocus();
1187
+ this.hiddenSince = null, t != null && e - t >= dt && this.armRefocus();
1163
1188
  }, this.onPageShow = (e) => {
1164
1189
  e.persisted && this.armRefocus();
1165
1190
  }, document.addEventListener("visibilitychange", this.onVisibility), typeof window < "u" && window.addEventListener("pageshow", this.onPageShow));
@@ -1169,7 +1194,7 @@ var W = class {
1169
1194
  let e = this.liveEnd(), t = G, n = t(), r = 0, i = () => {
1170
1195
  if (this.refocusTimer = null, Number.isFinite(this.deps.video.duration)) return;
1171
1196
  r += V;
1172
- let a = this.liveEnd(), o = a != null && (e == null || a >= e + pt), s = Math.max(r, t() - n) >= ft;
1197
+ let a = this.liveEnd(), o = a != null && (e == null || a >= e + mt), s = Math.max(r, t() - n) >= pt;
1173
1198
  if (o || s && a != null) {
1174
1199
  this.snapToLive();
1175
1200
  return;
@@ -1189,9 +1214,9 @@ var W = class {
1189
1214
  }, e.addEventListener("seeking", this.onEdgeReset), e.addEventListener("emptied", this.onEdgeReset), this.edgeTimer = setInterval(() => {
1190
1215
  if (e.duration !== Infinity) return;
1191
1216
  this.checkEndStale();
1192
- let t = St(e, e.currentTime);
1193
- t != null && ((this.lastBufferedEnd == null || Math.abs(t - this.lastBufferedEnd) >= ht) && (this.bufferedAdvancedAt = G()), this.lastBufferedEnd = t);
1194
- }, mt);
1217
+ let t = Ct(e, e.currentTime);
1218
+ t != null && ((this.lastBufferedEnd == null || Math.abs(t - this.lastBufferedEnd) >= gt) && (this.bufferedAdvancedAt = G()), this.lastBufferedEnd = t);
1219
+ }, ht);
1195
1220
  }
1196
1221
  checkEndStale() {
1197
1222
  if (this.endedEmitted) return;
@@ -1199,14 +1224,14 @@ var W = class {
1199
1224
  this.lastTickAt = e;
1200
1225
  let n = this.liveEnd();
1201
1226
  if (n == null) return;
1202
- let r = this.lastSeekableEnd == null || Math.abs(n - this.lastSeekableEnd) >= vt;
1227
+ let r = this.lastSeekableEnd == null || Math.abs(n - this.lastSeekableEnd) >= yt;
1203
1228
  this.lastSeekableEnd = n;
1204
1229
  let i = this.deps.video, a = typeof document < "u" && document.visibilityState === "hidden";
1205
- if (r || t > yt || a || i.paused) {
1230
+ if (r || t > bt || a || i.paused) {
1206
1231
  this.edgeStampedAt = e;
1207
1232
  return;
1208
1233
  }
1209
- e - (this.edgeStampedAt ?? e) > _t && (this.endedEmitted = !0, this.deps.emit({
1234
+ e - (this.edgeStampedAt ?? e) > vt && (this.endedEmitted = !0, this.deps.emit({
1210
1235
  type: "ended",
1211
1236
  reason: "stalled"
1212
1237
  }));
@@ -1220,7 +1245,7 @@ var W = class {
1220
1245
  liveEdgeEstimate() {
1221
1246
  let e = this.deps.video;
1222
1247
  if (e.duration !== Infinity) return null;
1223
- let t = this.liveEnd(), n = St(e, e.currentTime) ?? this.lastBufferedEnd;
1248
+ let t = this.liveEnd(), n = Ct(e, e.currentTime) ?? this.lastBufferedEnd;
1224
1249
  if (n != null) {
1225
1250
  let e = this.bufferedAdvancedAt, r = n + (e == null ? 0 : Math.max(0, (G() - e) / 1e3));
1226
1251
  (t == null || r > t) && (t = r);
@@ -1236,7 +1261,7 @@ var W = class {
1236
1261
  snapToLive() {
1237
1262
  let e = this.deps.video, t = this.liveEnd();
1238
1263
  if (t == null) return;
1239
- let n = e.seekable.start(e.seekable.length - 1), r = Math.min(e.currentTime, t), i = Math.max(n, t - dt, r);
1264
+ let n = e.seekable.start(e.seekable.length - 1), r = Math.min(e.currentTime, t), i = Math.max(n, t - ft, r);
1240
1265
  try {
1241
1266
  e.currentTime = i;
1242
1267
  } catch {}
@@ -1257,7 +1282,7 @@ var W = class {
1257
1282
  function G() {
1258
1283
  return typeof performance < "u" ? performance.now() : Date.now();
1259
1284
  }
1260
- function St(e, t) {
1285
+ function Ct(e, t) {
1261
1286
  let n = e.buffered;
1262
1287
  if (!n || !Number.isFinite(t)) return null;
1263
1288
  for (let e = 0; e < n.length; e += 1) if (n.start(e) <= t + .1 && n.end(e) > t) {
@@ -1266,7 +1291,7 @@ function St(e, t) {
1266
1291
  }
1267
1292
  return null;
1268
1293
  }
1269
- function Ct(e, t) {
1294
+ function wt(e, t) {
1270
1295
  return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
1271
1296
  }
1272
1297
  //#endregion
@@ -1282,9 +1307,23 @@ function K(e, t = Date.now()) {
1282
1307
  return !n || !/^\d+$/.test(n) ? !1 : Number(n) * 1e3 <= t;
1283
1308
  }
1284
1309
  //#endregion
1310
+ //#region src/core/drm/xhrBody.ts
1311
+ var Tt = 4096;
1312
+ function Et(e) {
1313
+ if (!e || typeof e != "object") return;
1314
+ let { response: t } = e;
1315
+ if (typeof t == "string") return t;
1316
+ let n;
1317
+ if (Object.prototype.toString.call(t) === "[object ArrayBuffer]" ? n = new Uint8Array(t) : ArrayBuffer.isView(t) && (n = new Uint8Array(t.buffer, t.byteOffset, t.byteLength)), !(!n || n.byteLength === 0 || n.byteLength > Tt)) try {
1318
+ return new TextDecoder().decode(n);
1319
+ } catch {
1320
+ return;
1321
+ }
1322
+ }
1323
+ //#endregion
1285
1324
  //#region src/core/engine/prefetch.ts
1286
- var wt = 15e3, Tt = 5e3, Et = 6;
1287
- function Dt(e) {
1325
+ var Dt = 15e3, Ot = 5e3, kt = 6;
1326
+ function At(e) {
1288
1327
  try {
1289
1328
  let t = new URL(e);
1290
1329
  return t.searchParams.delete("CMCD"), t.toString();
@@ -1292,7 +1331,7 @@ function Dt(e) {
1292
1331
  return e;
1293
1332
  }
1294
1333
  }
1295
- var Ot = class {
1334
+ var jt = class {
1296
1335
  cmcd;
1297
1336
  entries = /* @__PURE__ */ new Map();
1298
1337
  keyed = /* @__PURE__ */ new Set();
@@ -1315,10 +1354,10 @@ var Ot = class {
1315
1354
  }
1316
1355
  prefetch(e, t, n) {
1317
1356
  if (!this.isActive(t)) return;
1318
- let r = Dt(e);
1357
+ let r = At(e);
1319
1358
  if (this.entries.has(r)) return;
1320
1359
  let i = this.perTrack.get(t) ?? 0;
1321
- if (i >= Et) return;
1360
+ if (i >= kt) return;
1322
1361
  this.perTrack.set(t, i + 1);
1323
1362
  let a = new AbortController(), o = {
1324
1363
  started: performance.now(),
@@ -1332,10 +1371,10 @@ var Ot = class {
1332
1371
  signal: a.signal
1333
1372
  }).then(async (e) => (o.first = performance.now(), e.ok ? e.arrayBuffer() : null)).catch(() => null), this.entries.set(r, o), this.stats.started += 1, setTimeout(() => {
1334
1373
  this.entries.get(r) === o && (this.entries.delete(r), a.abort(), this.stats.expired += 1);
1335
- }, wt);
1374
+ }, Dt);
1336
1375
  }
1337
1376
  take(e) {
1338
- let t = Dt(e), n = this.entries.get(t);
1377
+ let t = At(e), n = this.entries.get(t);
1339
1378
  return n && this.entries.delete(t), n;
1340
1379
  }
1341
1380
  destroy() {
@@ -1355,13 +1394,13 @@ var Ot = class {
1355
1394
  }
1356
1395
  }
1357
1396
  };
1358
- function kt(t) {
1397
+ function Mt(t) {
1359
1398
  let n = e.DefaultConfig?.loader;
1360
1399
  if (typeof n != "function") return;
1361
1400
  class r extends n {
1362
1401
  served = !1;
1363
1402
  cancelled = !1;
1364
- stats = At();
1403
+ stats = Nt();
1365
1404
  load(e, n, r) {
1366
1405
  let i = e.rangeEnd ? void 0 : t.take(e.url);
1367
1406
  if (!i) {
@@ -1369,7 +1408,7 @@ function kt(t) {
1369
1408
  return;
1370
1409
  }
1371
1410
  this.served = !0;
1372
- let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || Tt, s = setTimeout(() => {
1411
+ let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || Ot, s = setTimeout(() => {
1373
1412
  !this.cancelled && this.served && (i.abort.abort(), t.stats.failed += 1, this.served = !1, super.load(e, n, r));
1374
1413
  }, o);
1375
1414
  i.bytes.then((o) => {
@@ -1396,7 +1435,7 @@ function kt(t) {
1396
1435
  }
1397
1436
  return r;
1398
1437
  }
1399
- function At() {
1438
+ function Nt() {
1400
1439
  return {
1401
1440
  aborted: !1,
1402
1441
  loaded: 0,
@@ -1420,10 +1459,10 @@ function At() {
1420
1459
  }
1421
1460
  };
1422
1461
  }
1423
- function jt(e) {
1462
+ function Pt(e) {
1424
1463
  return e === "audio" ? "audio" : "main";
1425
1464
  }
1426
- function Mt(e, t) {
1465
+ function Ft(e, t) {
1427
1466
  let n = [];
1428
1467
  t.initSegment?.url && !t.initSegment.data && n.push({
1429
1468
  url: t.initSegment.url,
@@ -1442,24 +1481,34 @@ function Mt(e, t) {
1442
1481
  }
1443
1482
  //#endregion
1444
1483
  //#region src/core/engine/hls.ts
1445
- function Nt() {
1484
+ function It() {
1446
1485
  return e.isSupported();
1447
1486
  }
1448
- var Pt = 1e6, Ft = 20, It = 1e4, Lt = 3, Rt = 5, zt = 3, Bt = 1e4, Vt = 3e4, Ht = 12e3, Ut = 3e3, Wt = .02, Gt = 6e3, Kt = .5, qt = 3, Jt = .5, Yt = 1.1, Xt = .25, Zt = 5e3, Qt = 4e3, $t = 2, en = 5, tn = 2, nn = 2, rn = 4, an = 4, on = 2e3, sn = 3e4, cn = .2, ln = 30, un = 2, dn = 2, fn = 9, pn = .5, mn = 64;
1449
- function hn(e) {
1487
+ var Lt = 1e6, Rt = 20, zt = 1e4, Bt = 3, Vt = 5, Ht = 3, Ut = 1e4, Wt = 3e4, Gt = 12e3, Kt = 3e3, qt = .02, Jt = 6e3, Yt = .5, Xt = 3, Zt = .5, Qt = 1.1, $t = .25, en = 5e3, tn = 4e3, nn = 2, rn = 5, an = 2, on = 2, sn = 4, cn = 4, ln = 2e3, un = 3e4, dn = 1, fn = 2;
1488
+ function pn(e, t, n) {
1489
+ if (n <= 0 || t < 0 || t >= e.length) return t;
1490
+ let r = (t, n) => e[t].width === e[n].width && e[t].height === e[n].height, i = (t) => {
1491
+ for (; t + 1 < e.length && r(t + 1, t);) t++;
1492
+ return t;
1493
+ }, a = i(t);
1494
+ for (let t = 0; t < n && a + 1 < e.length; t++) a = i(a + 1);
1495
+ return a;
1496
+ }
1497
+ var mn = .2, hn = 30, gn = 2, _n = 2, vn = 9, yn = .5, bn = 64;
1498
+ function xn(e) {
1450
1499
  if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
1451
1500
  delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
1452
1501
  return;
1453
1502
  }
1454
- e.liveSyncDuration ??= dn;
1455
- let t = Math.max(12, e.liveSyncDuration + fn);
1456
- (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), gn(e, e.liveSyncDuration);
1503
+ e.liveSyncDuration ??= _n;
1504
+ let t = Math.max(12, e.liveSyncDuration + vn);
1505
+ (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), Sn(e, e.liveSyncDuration);
1457
1506
  }
1458
- function gn(e, t) {
1507
+ function Sn(e, t) {
1459
1508
  let n = (e, t, n) => Math.min(n, Math.max(t, e));
1460
1509
  e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
1461
1510
  }
1462
- var _n = class {
1511
+ var Cn = class {
1463
1512
  name = "hls";
1464
1513
  hls = null;
1465
1514
  deps;
@@ -1543,7 +1592,7 @@ var _n = class {
1543
1592
  frameCounter;
1544
1593
  detachFrames = null;
1545
1594
  constructor(e) {
1546
- this.deps = e, this.frameCounter = new ct(e.video), this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
1595
+ this.deps = e, this.frameCounter = new lt(e.video), this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
1547
1596
  }
1548
1597
  async load() {
1549
1598
  this.detachFrames ??= this.frameCounter.attach();
@@ -1556,7 +1605,7 @@ var _n = class {
1556
1605
  });
1557
1606
  return;
1558
1607
  }
1559
- e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (He(r), Ke()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1608
+ e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ue(r), qe()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1560
1609
  let e = this.hls;
1561
1610
  if (document.visibilityState !== "visible" || !e) return;
1562
1611
  let t = e.liveSyncPosition;
@@ -1579,7 +1628,7 @@ var _n = class {
1579
1628
  }
1580
1629
  this.loadSuspended = !0;
1581
1630
  }
1582
- }, Zt));
1631
+ }, en));
1583
1632
  }
1584
1633
  resumeLoading() {
1585
1634
  if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
@@ -1611,7 +1660,7 @@ var _n = class {
1611
1660
  let t = e.liveSyncPosition;
1612
1661
  if (typeof t != "number" || !Number.isFinite(t)) return;
1613
1662
  let { video: n } = this.deps;
1614
- n.currentTime <= t + pn || (n.currentTime = t);
1663
+ n.currentTime <= t + yn || (n.currentTime = t);
1615
1664
  }
1616
1665
  reanchorPartTimeline(e, t) {
1617
1666
  let { frag: n, part: r } = t;
@@ -1623,7 +1672,7 @@ var _n = class {
1623
1672
  let o = n.sn, s = i.fragments.find((e) => e && e.sn === o) ?? (i.fragmentHint?.sn === o ? i.fragmentHint : void 0);
1624
1673
  if (!s) return;
1625
1674
  let c = a.startPTS - s.start;
1626
- if (!(!Number.isFinite(c) || Math.abs(c) < Wt)) {
1675
+ if (!(!Number.isFinite(c) || Math.abs(c) < qt)) {
1627
1676
  for (let e of i.fragments) e && e.setStart(e.start + c);
1628
1677
  i.fragmentHint?.setStart(i.fragmentHint.start + c), this.deps.debug === !0 && console.info(`havik-player: LL-HLS timeline re-anchored by ${c >= 0 ? "+" : ""}${c.toFixed(3)}s at sn ${n.sn} (level ${n.level})`);
1629
1678
  }
@@ -1651,7 +1700,7 @@ var _n = class {
1651
1700
  videoEncryptionScheme: F.scheme,
1652
1701
  audioEncryptionScheme: F.scheme
1653
1702
  },
1654
- ...M() ? { requestMediaKeySystemAccessFunc: Ve(t) } : {},
1703
+ ...M() ? { requestMediaKeySystemAccessFunc: He(t) } : {},
1655
1704
  licenseXhrSetup: (e, t) => {
1656
1705
  let o = performance.now(), s = () => {
1657
1706
  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, e.addEventListener("loadend", () => {
@@ -1663,7 +1712,7 @@ var _n = class {
1663
1712
  return;
1664
1713
  }
1665
1714
  let l = this.hls, u, d = new Promise((e) => {
1666
- u = setTimeout(() => e(void 0), Bt);
1715
+ u = setTimeout(() => e(void 0), Ut);
1667
1716
  });
1668
1717
  return Promise.race([c().catch(() => void 0), d]).finally(() => clearTimeout(u)).then((e) => {
1669
1718
  if (!this.hls || this.hls !== l) throw Error("havik-player: engine torn down during refresh");
@@ -1679,20 +1728,20 @@ var _n = class {
1679
1728
  ...c
1680
1729
  };
1681
1730
  if (this.prefetch?.destroy(), this.prefetch = null, u && this.deps.mediaDuringKey !== !1 && !f.fLoader) {
1682
- let e = new Ot({
1731
+ let e = new jt({
1683
1732
  sessionId: n.analytics?.sid,
1684
1733
  contentId: n.matchUrn
1685
- }), t = kt(e);
1734
+ }), t = Mt(e);
1686
1735
  t && (this.prefetch = e, f.fLoader = t);
1687
1736
  }
1688
- hn(f), this.catchUpRate = typeof f.maxLiveSyncPlaybackRate == "number" ? f.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (f.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = f.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = f.autoStartLoad !== !1;
1737
+ xn(f), this.catchUpRate = typeof f.maxLiveSyncPlaybackRate == "number" ? f.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (f.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = f.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = f.autoStartLoad !== !1;
1689
1738
  let p = new e(f);
1690
1739
  if (this.hls = p, p.on(e.Events.FRAG_PARSED, (e, t) => this.reanchorPartTimeline(p, t)), p.on(e.Events.MANIFEST_PARSED, () => {
1691
1740
  this.mediaRecoveries = 0, this.networkRecoveries = 0, u && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && this.dropLevelsWidevineCannotPlay(p), this.measureLadder(p), this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
1692
1741
  }), p.on(e.Events.FRAG_BUFFERED, (e, t) => {
1693
1742
  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(() => {
1694
1743
  this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
1695
- }, Vt)));
1744
+ }, Wt)));
1696
1745
  }), p.on(e.Events.FRAG_LOADING, (e, t) => {
1697
1746
  t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
1698
1747
  }), p.on(e.Events.FRAG_LOADED, (e, t) => {
@@ -1700,10 +1749,10 @@ var _n = class {
1700
1749
  let n = t?.frag?.stats, r = n?.loaded;
1701
1750
  typeof r == "number" && (this.bytesLoaded += r), !this.reportedFirstBytes && typeof r == "number" && r > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
1702
1751
  let i = n?.loading;
1703
- 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 > mn && this.requestTimesMs.shift());
1752
+ 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 > bn && this.requestTimesMs.shift());
1704
1753
  let a = t?.frag?.url;
1705
1754
  if (a) {
1706
- let e = at(a);
1755
+ let e = ot(a);
1707
1756
  e && (this.cdnHost = e);
1708
1757
  }
1709
1758
  }), p.on(e.Events.LEVEL_LOADED, (e, t) => {
@@ -1717,15 +1766,15 @@ var _n = class {
1717
1766
  }), p.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.prefetch) {
1718
1767
  let t = this.prefetch;
1719
1768
  p.on(e.Events.KEY_LOADING, (e, n) => {
1720
- let r = n?.frag, i = jt(r?.type);
1721
- if (r && t.isActive(i)) for (let e of Mt(p, r)) t.prefetch(e.url, i, e.kind);
1722
- }), p.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(jt(n?.frag?.type)));
1769
+ let r = n?.frag, i = Pt(r?.type);
1770
+ if (r && t.isActive(i)) for (let e of Ft(p, r)) t.prefetch(e.url, i, e.kind);
1771
+ }), p.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(Pt(n?.frag?.type)));
1723
1772
  }
1724
1773
  p.on(e.Events.KEY_LOADED, () => {
1725
1774
  u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
1726
1775
  }), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
1727
1776
  this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.checkFrameDrops();
1728
- }, Ut), p.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1777
+ }, Kt), p.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1729
1778
  this.renditionSwitches += 1;
1730
1779
  let n = this.lastLevelIndex >= 0 ? p.levels[this.lastLevelIndex] : void 0, r = p.levels[t.level];
1731
1780
  n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, l({
@@ -1773,8 +1822,12 @@ var _n = class {
1773
1822
  if (!e || e.levels.length === 0) return null;
1774
1823
  let { video: n } = this.deps, r = n.getBoundingClientRect(), i = r.width, a = r.height;
1775
1824
  if (!i && !a && (i = n.width || 0, a = n.height || 0), !(i > 0) || !(a > 0)) return null;
1776
- let o = e.config ?? {}, s = 1;
1777
- return !o.ignoreDevicePixelRatio && typeof self < "u" && self.devicePixelRatio > 0 && (s = self.devicePixelRatio), s = Math.min(s, o.maxDevicePixelRatio ?? Infinity), t.getMaxLevelByMediaSize(e.levels, i * s, a * s);
1825
+ let o = e.config ?? {}, s = typeof self < "u" && self.devicePixelRatio > 0 ? self.devicePixelRatio : 1, c = o.ignoreDevicePixelRatio ? 1 : s;
1826
+ c = Math.min(c, o.maxDevicePixelRatio ?? Infinity);
1827
+ let l = t.getMaxLevelByMediaSize(e.levels, i * c, a * c), u = this.deps.sizeCapHeadroom;
1828
+ if (u == null && s >= fn) return l;
1829
+ let d = u ?? dn, f = Number.isNaN(d) ? dn : d === Infinity ? e.levels.length : Math.max(0, Math.floor(d));
1830
+ return pn(e.levels, l, f);
1778
1831
  }
1779
1832
  onMediaResize() {
1780
1833
  if (!this.sizeCapManaged) return;
@@ -1789,7 +1842,7 @@ var _n = class {
1789
1842
  return;
1790
1843
  }
1791
1844
  this.capTimer && clearTimeout(this.capTimer);
1792
- let t = e > this.sizeCapLevel ? on : sn;
1845
+ let t = e > this.sizeCapLevel ? ln : un;
1793
1846
  this.capTimer = setTimeout(() => {
1794
1847
  this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
1795
1848
  }, t);
@@ -1799,9 +1852,9 @@ var _n = class {
1799
1852
  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;
1800
1853
  }
1801
1854
  dropLevelsWidevineCannotPlay(e) {
1802
- this.removeLevelsWhere(e, (e) => qe(e) !== !0);
1855
+ this.removeLevelsWhere(e, (e) => Je(e) !== !0);
1803
1856
  let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && I(e) !== "avc" && !!I(e)));
1804
- for (let n of t) Ge(n).then((t) => {
1857
+ for (let n of t) Ke(n).then((t) => {
1805
1858
  t || this.hls !== e || this.removeLevelsWhere(e, (e) => e === n) && (this.measureLadder(e), this.applySizeCap());
1806
1859
  });
1807
1860
  }
@@ -1812,7 +1865,7 @@ var _n = class {
1812
1865
  a && I(a) && t(a) && (r.push(n), i.add(a));
1813
1866
  }), !r.length) return !1;
1814
1867
  let a = [...i].join(", ");
1815
- if (!n.some((e, t) => r.includes(t) ? !1 : !I(e.videoCodec) || qe(e.videoCodec) === !0)) return console.warn(`havik-player: every rendition is ${a}, which Widevine may not play on this browser; keeping them`), !1;
1868
+ if (!n.some((e, t) => r.includes(t) ? !1 : !I(e.videoCodec) || Je(e.videoCodec) === !0)) return console.warn(`havik-player: every rendition is ${a}, which Widevine may not play on this browser; keeping them`), !1;
1816
1869
  for (let t = r.length - 1; t >= 0; --t) e.removeLevel(r[t]);
1817
1870
  return console.info(`havik-player: skipped ${r.length} rendition(s) Widevine cannot play on this browser (${a})`), !0;
1818
1871
  }
@@ -1918,7 +1971,7 @@ var _n = class {
1918
1971
  return;
1919
1972
  }
1920
1973
  let e = Date.now() - this.lastAdvanceMs;
1921
- !this.chaseSuspended && e > Gt && this.suspendChasing(), e > Ht && this.emitEnded("stalled");
1974
+ !this.chaseSuspended && e > Jt && this.suspendChasing(), e > Gt && this.emitEnded("stalled");
1922
1975
  }
1923
1976
  resetStarvationWindow() {
1924
1977
  this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
@@ -1933,7 +1986,7 @@ var _n = class {
1933
1986
  this.resetStarvationWindow();
1934
1987
  return;
1935
1988
  }
1936
- let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < Gt, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > Qt, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = B(t), c = o - s, l = c !== this.starvedFrames;
1989
+ let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < Jt, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > tn, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = B(t), c = o - s, l = c !== this.starvedFrames;
1937
1990
  if (this.starvedFrames = c, !a || l) {
1938
1991
  (t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
1939
1992
  return;
@@ -1942,12 +1995,12 @@ var _n = class {
1942
1995
  this.resetStarvationWindow();
1943
1996
  return;
1944
1997
  }
1945
- 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 > rn && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= tn && (this.clearKick(), this.starvationRebuilds < nn)) {
1998
+ 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 > sn && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= an && (this.clearKick(), this.starvationRebuilds < on)) {
1946
1999
  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");
1947
2000
  return;
1948
2001
  }
1949
- let u = i && this.starvedTicks >= $t, d = !i && this.deadTicks >= rn && this.recentMainFrags.reduce((e, t) => e + t, 0) >= an;
1950
- if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= en))) {
2002
+ let u = i && this.starvedTicks >= nn, d = !i && this.deadTicks >= sn && this.recentMainFrags.reduce((e, t) => e + t, 0) >= cn;
2003
+ if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= rn))) {
1951
2004
  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");
1952
2005
  try {
1953
2006
  e.stopLoad(), e.startLoad(-1);
@@ -1962,7 +2015,7 @@ var _n = class {
1962
2015
  let t = e.latency, n = e.targetLatency;
1963
2016
  if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
1964
2017
  let r = t - n;
1965
- !this.catchUpEngaged && r > Kt ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= Kt && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
2018
+ !this.catchUpEngaged && r > Yt ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= Yt && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
1966
2019
  let i = this.catchUpEngaged ? this.catchUpRate : 1;
1967
2020
  e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
1968
2021
  }
@@ -1984,15 +2037,15 @@ var _n = class {
1984
2037
  return;
1985
2038
  }
1986
2039
  let { totalFrames: n, dropped: r } = B(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
1987
- if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < ln || o < 0) {
2040
+ if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < hn || o < 0) {
1988
2041
  this.fpsBadTicks = 0;
1989
2042
  return;
1990
2043
  }
1991
- if (o <= cn * a) {
2044
+ if (o <= mn * a) {
1992
2045
  this.fpsBadTicks = 0;
1993
2046
  return;
1994
2047
  }
1995
- if (this.fpsBadTicks += 1, this.fpsBadTicks < un) return;
2048
+ if (this.fpsBadTicks += 1, this.fpsBadTicks < gn) return;
1996
2049
  this.fpsBadTicks = 0;
1997
2050
  let s = e.levels, c = s[e.currentLevel];
1998
2051
  if (!c) return;
@@ -2009,20 +2062,20 @@ var _n = class {
2009
2062
  return;
2010
2063
  }
2011
2064
  let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
2012
- if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(Yt, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
2065
+ if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(Qt, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
2013
2066
  this.resetChaseWindow();
2014
2067
  return;
2015
2068
  }
2016
- if (this.chaseLatency < 0 || this.chaseLatency - n >= Jt) {
2069
+ if (this.chaseLatency < 0 || this.chaseLatency - n >= Zt) {
2017
2070
  this.chaseLatency = n, this.chaseTicks = 0;
2018
2071
  return;
2019
2072
  }
2020
- if (this.chaseTicks += 1, this.chaseTicks < qt) return;
2073
+ if (this.chaseTicks += 1, this.chaseTicks < Xt) return;
2021
2074
  this.resetChaseWindow();
2022
2075
  let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
2023
2076
  if (!(a > 1)) return;
2024
2077
  let o = typeof e.targetLatency == "number" ? e.targetLatency : 0, s = Math.min(n, a - 1);
2025
- s < o + Xt || (console.warn(`havik-player: catch-up at ${r}x not gaining on the live edge (latency ${n.toFixed(1)}s); holding at ${s.toFixed(1)}s`), this.liveRetargets += 1, e.targetLatency = s);
2078
+ s < o + $t || (console.warn(`havik-player: catch-up at ${r}x not gaining on the live edge (latency ${n.toFixed(1)}s); holding at ${s.toFixed(1)}s`), this.liveRetargets += 1, e.targetLatency = s);
2026
2079
  }
2027
2080
  suspendChasing() {
2028
2081
  let e = this.hls;
@@ -2052,14 +2105,14 @@ var _n = class {
2052
2105
  } catch {}
2053
2106
  }
2054
2107
  startEstimate() {
2055
- return this.deps.rememberBandwidth === !1 ? Pt : Fe() ?? Pt;
2108
+ return this.deps.rememberBandwidth === !1 ? Lt : Ie() ?? Lt;
2056
2109
  }
2057
2110
  maybeRememberBandwidth(e) {
2058
- if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded < Ft) return;
2111
+ if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded < Rt) return;
2059
2112
  let t = Date.now();
2060
- if (!e && t - this.bwSavedAt < It) return;
2113
+ if (!e && t - this.bwSavedAt < zt) return;
2061
2114
  let n = this.hls?.bandwidthEstimate;
2062
- typeof n != "number" || !Number.isFinite(n) || n <= 0 || (this.bwSavedAt = t, Ie(n));
2115
+ typeof n != "number" || !Number.isFinite(n) || n <= 0 || (this.bwSavedAt = t, Le(n));
2063
2116
  }
2064
2117
  destroy() {
2065
2118
  if (this.maybeRememberBandwidth(!0), this.detachFrames?.(), this.detachFrames = null, this.prefetch?.destroy(), this.prefetch = null, this.clearRecoveryReset(), this.capTimer &&= (clearTimeout(this.capTimer), null), this.capObserver &&= (this.capObserver.disconnect(), null), this.unwatchDprChanges(), this.endWatchdog &&= (clearInterval(this.endWatchdog), null), this.onVisibility && typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), this.onVisibility = null), this.onSeeking &&= (this.deps.video.removeEventListener("seeking", this.onSeeking), null), this.onTimeUpdate &&= (this.deps.video.removeEventListener("timeupdate", this.onTimeUpdate), null), this.onPause &&= (this.deps.video.removeEventListener("pause", this.onPause), null), this.onPlay &&= (this.deps.video.removeEventListener("play", this.onPlay), null), this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null), this.licenseRetryTimer &&= (clearTimeout(this.licenseRetryTimer), null), this.hls) {
@@ -2077,7 +2130,7 @@ var _n = class {
2077
2130
  scheduleLicenseRetry(t) {
2078
2131
  if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
2079
2132
  let n = t.response?.code ?? 0;
2080
- if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= zt) return !1;
2133
+ if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= Ht) return !1;
2081
2134
  this.licenseRecoveries += 1;
2082
2135
  let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
2083
2136
  return this.licenseRetryTimer = setTimeout(() => {
@@ -2109,7 +2162,7 @@ var _n = class {
2109
2162
  return;
2110
2163
  }
2111
2164
  if (t.type === e.ErrorTypes.NETWORK_ERROR) {
2112
- if (this.networkRecoveries < Rt) {
2165
+ if (this.networkRecoveries < Vt) {
2113
2166
  this.networkRecoveries += 1;
2114
2167
  let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
2115
2168
  this.networkRetryTimer = setTimeout(() => {
@@ -2126,7 +2179,7 @@ var _n = class {
2126
2179
  return;
2127
2180
  }
2128
2181
  if (t.type === e.ErrorTypes.MEDIA_ERROR) {
2129
- if (this.mediaRecoveries < Lt) {
2182
+ if (this.mediaRecoveries < Bt) {
2130
2183
  this.mediaRecoveries += 1, n.recoverMediaError();
2131
2184
  return;
2132
2185
  }
@@ -2146,23 +2199,23 @@ var _n = class {
2146
2199
  });
2147
2200
  }
2148
2201
  }
2149
- toError(e, t = "PLAYBACK") {
2150
- let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
2151
- return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
2202
+ toError(t, r = "PLAYBACK") {
2203
+ let o = t.response?.code ?? 0, s = t.details ?? t.type, c = t.reason ?? t.error?.message ?? "", l = r === "DRM" && o === 403 && t.details === e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED ? i(Et(t.networkDetails)) : void 0;
2204
+ return new n(r === "DRM" ? a(o, l) : o === 401 ? "UNAUTHORIZED" : o === 403 ? "FORBIDDEN" : "INTERNAL", o, `${r} error: ${s}${c ? ` (${c})` : ""}`, l ? { serverCode: l } : void 0);
2152
2205
  }
2153
- }, vn = 15e3, yn = 6e5, bn = 3e5, xn = 100, q = 1, Sn = 1e3, Cn = 3e4, wn = 1e3, Tn = {
2206
+ }, wn = 15e3, Tn = 6e5, En = 3e5, Dn = 100, q = 1, On = 1e3, kn = 3e4, An = 1e3, jn = {
2154
2207
  inline: "PRESENTATION_INLINE",
2155
2208
  fullscreen: "PRESENTATION_FULLSCREEN",
2156
2209
  pip: "PRESENTATION_PIP"
2157
- }, En = {
2210
+ }, Mn = {
2158
2211
  widevine: "KEY_SYSTEM_WIDEVINE",
2159
2212
  fairplay: "KEY_SYSTEM_FAIRPLAY",
2160
2213
  none: "KEY_SYSTEM_NONE"
2161
2214
  };
2162
- function Dn(e, t) {
2215
+ function Nn(e, t) {
2163
2216
  return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
2164
2217
  }
2165
- var On = /* @__PURE__ */ new Set([
2218
+ var Pn = /* @__PURE__ */ new Set([
2166
2219
  "INVALID_URN",
2167
2220
  "NOT_FOUND",
2168
2221
  "GEO_DENIED",
@@ -2183,7 +2236,7 @@ var On = /* @__PURE__ */ new Set([
2183
2236
  ended: "PLAYER_STATE_ENDED",
2184
2237
  error: "PLAYER_STATE_ERROR"
2185
2238
  };
2186
- function kn(e) {
2239
+ function Fn(e) {
2187
2240
  try {
2188
2241
  let t = new URL(e), [n, ...r] = t.hostname.split(".");
2189
2242
  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);
@@ -2191,8 +2244,8 @@ function kn(e) {
2191
2244
  return;
2192
2245
  }
2193
2246
  }
2194
- var An = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), jn = /* @__PURE__ */ new Set(), Y = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), Mn = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
2195
- function Nn(e) {
2247
+ var In = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), Ln = /* @__PURE__ */ new Set(), Y = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), Rn = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
2248
+ function zn(e) {
2196
2249
  if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
2197
2250
  let t;
2198
2251
  try {
@@ -2201,19 +2254,19 @@ function Nn(e) {
2201
2254
  } catch {
2202
2255
  return;
2203
2256
  }
2204
- if (jn.has(t) && !Y.has(t)) {
2205
- Y.add(t), g(Mn(new URL(t).origin));
2257
+ if (Ln.has(t) && !Y.has(t)) {
2258
+ Y.add(t), _(Rn(new URL(t).origin));
2206
2259
  for (let e of X) e.noteCspBlocked();
2207
2260
  }
2208
2261
  }
2209
- function Pn(e, t) {
2210
- return g(t, e), { disabledReason: t };
2262
+ function Z(e, t) {
2263
+ return _(t, e), { disabledReason: t };
2211
2264
  }
2212
- function Fn(e, t, n) {
2213
- if (n) return t && !An(t, n) && g(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
2265
+ function Bn(e, t, n) {
2266
+ if (n) return t && !In(t, n) && _(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
2214
2267
  if (t) return { endpoint: t };
2215
- if (t !== void 0) return Pn("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).");
2216
- let r = kn(e);
2268
+ if (t !== void 0) return Z("empty-endpoint", "analytics is disabled: no QoE beacons will be sent. analytics.endpoint was supplied but empty. Pass a real beacons origin, analytics: { endpoint: 'https://beacons[-dev].<domain>' }, or omit the option to derive it from baseUrl (or analytics: false to opt out).");
2269
+ let r = Fn(e);
2217
2270
  if (r) return { endpoint: r };
2218
2271
  let i;
2219
2272
  try {
@@ -2221,9 +2274,9 @@ function Fn(e, t, n) {
2221
2274
  } catch {
2222
2275
  i = e;
2223
2276
  }
2224
- return Pn(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).`);
2277
+ return Z(i, `analytics is disabled: no QoE beacons will be sent. The beacons endpoint cannot be derived from the baseUrl host "${i}" — the convention is feed[-dev].<domain> → beacons[-dev].<domain>. Pass an explicit endpoint, analytics: { endpoint: 'https://beacons[-dev].<domain>' }, to createPlayer (or analytics: false to opt out deliberately).`);
2225
2278
  }
2226
- var In = class {
2279
+ var Vn = class {
2227
2280
  opts;
2228
2281
  url;
2229
2282
  cspKey;
@@ -2305,8 +2358,8 @@ var In = class {
2305
2358
  constructor(e) {
2306
2359
  this.opts = {
2307
2360
  ...e,
2308
- heartbeatMs: e.heartbeatMs ?? vn,
2309
- idleMs: e.idleMs ?? yn
2361
+ heartbeatMs: e.heartbeatMs ?? wn,
2362
+ idleMs: e.idleMs ?? Tn
2310
2363
  }, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
2311
2364
  try {
2312
2365
  let e = new URL(this.url);
@@ -2323,11 +2376,11 @@ var In = class {
2323
2376
  sdkVersion: this.opts.sdkVersion,
2324
2377
  ...this.opts.environment
2325
2378
  };
2326
- this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Sn), this.lastTickMs = this.now(), this.timer = setInterval(() => this.heartbeat(), this.opts.heartbeatMs), typeof window < "u" && window.addEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.addEventListener("visibilitychange", this.onVisibility), document.addEventListener("freeze", this.onFreeze), document.addEventListener("resume", this.onResume), this.cspKey && jn.add(this.cspKey), document.addEventListener("securitypolicyviolation", Nn), X.add(this), this.noteCspBlocked(), this.onVisibility());
2379
+ this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), On), this.lastTickMs = this.now(), this.timer = setInterval(() => this.heartbeat(), this.opts.heartbeatMs), typeof window < "u" && window.addEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.addEventListener("visibilitychange", this.onVisibility), document.addEventListener("freeze", this.onFreeze), document.addEventListener("resume", this.onResume), this.cspKey && Ln.add(this.cspKey), document.addEventListener("securitypolicyviolation", zn), X.add(this), this.noteCspBlocked(), this.onVisibility());
2327
2380
  }
2328
2381
  checkSuspension(e) {
2329
2382
  if (this.endedFlag || !this.opts.idleMs) return !1;
2330
- let t = Math.max(this.opts.idleMs, bn);
2383
+ let t = Math.max(this.opts.idleMs, En);
2331
2384
  return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
2332
2385
  }
2333
2386
  syncIdle(e) {
@@ -2350,12 +2403,12 @@ var In = class {
2350
2403
  let a = {
2351
2404
  fromState: J[e] ?? "PLAYER_STATE_UNSPECIFIED",
2352
2405
  toState: J[t] ?? "PLAYER_STATE_UNSPECIFIED",
2353
- presentation: Tn[this.presentation]
2406
+ presentation: jn[this.presentation]
2354
2407
  }, o = this.causeOf(e, t, i);
2355
2408
  o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
2356
2409
  }
2357
2410
  seekInduced(e) {
2358
- return this.lastSeekMs >= 0 && e - this.lastSeekMs < wn;
2411
+ return this.lastSeekMs >= 0 && e - this.lastSeekMs < An;
2359
2412
  }
2360
2413
  causeOf(e, t, n) {
2361
2414
  if (t === "error") return "TRANSITION_CAUSE_ERROR";
@@ -2428,8 +2481,8 @@ var In = class {
2428
2481
  stageOf(e, t, n) {
2429
2482
  let r = n ?? "";
2430
2483
  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";
2431
- if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
2432
- if (On.has(e)) return "ERROR_STAGE_RESOLVE";
2484
+ if (e === "DRM_CLIENT" || e === "DRM_DEVICE_REVOKED") return "ERROR_STAGE_DRM";
2485
+ if (Pn.has(e)) return "ERROR_STAGE_RESOLVE";
2433
2486
  let i = t ?? "";
2434
2487
  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";
2435
2488
  }
@@ -2476,14 +2529,14 @@ var In = class {
2476
2529
  if (this.lastRequestCount = g, _ > 0) {
2477
2530
  o.requestCountDelta = _;
2478
2531
  let e = t.requestTimesMs ?? [], n = e.slice(Math.max(0, e.length - _)).sort((e, t) => e - t);
2479
- n.length > 0 && (o.requestTimeP50Ms = Dn(n, 50), o.requestTimeP95Ms = Dn(n, 95));
2532
+ n.length > 0 && (o.requestTimeP50Ms = Nn(n, 50), o.requestTimeP95Ms = Nn(n, 95));
2480
2533
  }
2481
2534
  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();
2482
2535
  }
2483
2536
  maybeEmitMediaInfo(e) {
2484
2537
  if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
2485
2538
  let t = {};
2486
- e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = En[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);
2539
+ e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = Mn[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);
2487
2540
  let n = JSON.stringify(t);
2488
2541
  n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
2489
2542
  }
@@ -2503,7 +2556,7 @@ var In = class {
2503
2556
  let c = r?.positionMs ?? 0;
2504
2557
  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));
2505
2558
  let l = e !== "END_REASON_ENDED";
2506
- l && this.lastStallMs > 0 && n - this.lastStallMs <= Cn && (i.abandonAfterStallMs = Math.max(q, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= Cn && (i.abandonAfterErrorMs = Math.max(q, Math.round(n - this.lastErrorMs))), this.fullscreenTotalMs > 0 && (i.fullscreenTimeMs = Math.round(this.fullscreenTotalMs)), this.pipTotalMs > 0 && (i.pipTimeMs = Math.round(this.pipTotalMs)), this.volumeChanges > 0 && (i.volumeChanges = this.volumeChanges), this.muteChanges > 0 && (i.muteChanges = this.muteChanges);
2559
+ l && this.lastStallMs > 0 && n - this.lastStallMs <= kn && (i.abandonAfterStallMs = Math.max(q, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= kn && (i.abandonAfterErrorMs = Math.max(q, Math.round(n - this.lastErrorMs))), this.fullscreenTotalMs > 0 && (i.fullscreenTimeMs = Math.round(this.fullscreenTotalMs)), this.pipTotalMs > 0 && (i.pipTimeMs = Math.round(this.pipTotalMs)), this.volumeChanges > 0 && (i.volumeChanges = this.volumeChanges), this.muteChanges > 0 && (i.muteChanges = this.muteChanges);
2507
2560
  let u = r?.decodedFrames ?? this.lastDecoded;
2508
2561
  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");
2509
2562
  }
@@ -2523,13 +2576,13 @@ var In = class {
2523
2576
  };
2524
2577
  }
2525
2578
  noteCspBlocked() {
2526
- this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(Mn(new URL(this.url).origin)));
2579
+ this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(Rn(new URL(this.url).origin)));
2527
2580
  }
2528
2581
  cspBlocked() {
2529
2582
  return !!this.cspKey && Y.has(this.cspKey);
2530
2583
  }
2531
2584
  enqueue(e) {
2532
- if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > xn;) {
2585
+ if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > Dn;) {
2533
2586
  let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
2534
2587
  this.pending.splice(e >= 0 ? e : 0, 1);
2535
2588
  }
@@ -2556,7 +2609,7 @@ var In = class {
2556
2609
  };
2557
2610
  //#endregion
2558
2611
  //#region src/core/environment.ts
2559
- function Ln() {
2612
+ function Hn() {
2560
2613
  if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
2561
2614
  let e;
2562
2615
  try {
@@ -2581,14 +2634,14 @@ function Ln() {
2581
2634
  integration: "INTEGRATION_KIND_IFRAME"
2582
2635
  };
2583
2636
  }
2584
- function Rn() {
2637
+ function Un() {
2585
2638
  if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
2586
2639
  let e = navigator.userAgentData, t = e?.platform ?? "";
2587
2640
  if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
2588
2641
  let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
2589
2642
  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";
2590
2643
  }
2591
- function zn() {
2644
+ function Wn() {
2592
2645
  let e = typeof navigator < "u" ? navigator.connection : void 0;
2593
2646
  if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
2594
2647
  let t = {
@@ -2607,17 +2660,17 @@ function zn() {
2607
2660
  }
2608
2661
  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;
2609
2662
  }
2610
- function Bn(e) {
2611
- let t = Ln(), n = {
2612
- deviceClass: Rn(),
2663
+ function Gn(e) {
2664
+ let t = Hn(), n = {
2665
+ deviceClass: Un(),
2613
2666
  integration: t.integration,
2614
- ...zn()
2667
+ ...Wn()
2615
2668
  };
2616
2669
  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);
2617
2670
  let r = e.getBoundingClientRect?.();
2618
2671
  return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
2619
2672
  }
2620
- async function Vn() {
2673
+ async function Kn() {
2621
2674
  let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
2622
2675
  if (!e?.getHighEntropyValues) return {};
2623
2676
  try {
@@ -2629,7 +2682,7 @@ async function Vn() {
2629
2682
  }
2630
2683
  //#endregion
2631
2684
  //#region src/core/version.ts
2632
- var Hn = "2.20.0", Un = {
2685
+ var qn = "2.22.0", Jn = {
2633
2686
  accent: "#E1B600",
2634
2687
  accentText: "#1B1C23",
2635
2688
  background: "#0e0f13",
@@ -2640,7 +2693,7 @@ var Hn = "2.20.0", Un = {
2640
2693
  border: "rgba(255, 255, 255, 0.1)",
2641
2694
  radius: "8px",
2642
2695
  fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
2643
- }, Wn = {
2696
+ }, Yn = {
2644
2697
  accent: "--havik-accent",
2645
2698
  accentText: "--havik-accent-text",
2646
2699
  background: "--havik-bg",
@@ -2652,26 +2705,26 @@ var Hn = "2.20.0", Un = {
2652
2705
  radius: "--havik-radius",
2653
2706
  fontFamily: "--havik-font"
2654
2707
  };
2655
- function Gn(e, t) {
2708
+ function Xn(e, t) {
2656
2709
  let n = {
2657
- ...Un,
2710
+ ...Jn,
2658
2711
  ...t
2659
2712
  };
2660
- for (let t of Object.keys(Wn)) e.style.setProperty(Wn[t], n[t]);
2713
+ for (let t of Object.keys(Yn)) e.style.setProperty(Yn[t], n[t]);
2661
2714
  n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
2662
2715
  }
2663
2716
  //#endregion
2664
2717
  //#region src/ui/styles.ts
2665
- var Z = "havik-player-styles", Kn = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer;\n touch-action:manipulation}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n/* Absolutely centred, NOT a flex sibling of .havik-center: the hidden center\n button (.havik-gone) still occupies its 74px in the row, which pushed an\n in-flow spinner 37px right of centre. */\n.havik-spinner{position:absolute;inset:0;margin:auto;width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n/* A status card carries its own logo — the corner watermark would duplicate it. */\n.havik-player.havik-has-status .havik-watermark{display:none}\n\n.havik-bar{position:absolute;left:0;right:0;bottom:0;padding:0 12px 8px;\n opacity:1;transition:opacity .25s;z-index:2}\n.havik-seek{position:relative;height:16px;display:flex;align-items:center;cursor:pointer;margin-bottom:2px}\n.havik-seek__track{position:relative;width:100%;height:4px;border-radius:3px;background:rgba(255,255,255,.25)}\n.havik-seek__buffered{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:rgba(255,255,255,.4)}\n.havik-seek__played{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-seek__thumb{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;\n background:var(--havik-accent,#E1B600);transform:translate(-50%,-50%) scale(0);transition:transform .1s}\n.havik-seek:hover .havik-seek__thumb{transform:translate(-50%,-50%) scale(1)}\n\n.havik-controls{display:flex;align-items:center;gap:6px;height:40px}\n.havik-spacer{flex:1}\n.havik-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;border-radius:var(--havik-radius,8px);\n padding:0;transition:background .12s,color .12s}\n.havik-btn:hover{background:rgba(255,255,255,.12)}\n.havik-btn:focus-visible{outline:2px solid var(--havik-accent,#E1B600);outline-offset:1px}\n.havik-btn svg{width:22px;height:22px}\n\n/* The volume level is filled in accent up to the thumb, like the seek bar's\n played span — a native range input paints no \"elapsed\" side, which left the\n level readable only from the dot's position. --havik-vol (0..1) is set by\n syncVolume(); the track width and thumb size live here as variables because\n the WebKit fill has to compute the thumb centre from both. */\n.havik-vol{display:flex;align-items:center}\n.havik-vol__slider{--havik-vol-w:70px;--havik-vol-thumb:12px;--havik-vol:1;\n --havik-vol-pos:calc(var(--havik-vol-thumb) / 2 + var(--havik-vol) * (var(--havik-vol-w) - var(--havik-vol-thumb)));\n width:0;opacity:0;transition:width .18s,opacity .18s;height:4px;cursor:pointer;\n appearance:none;-webkit-appearance:none;background:transparent;border-radius:3px;margin:0 4px}\n.havik-vol:hover .havik-vol__slider,.havik-vol:focus-within .havik-vol__slider{width:var(--havik-vol-w);opacity:1}\n/* WebKit/Blink have no progress pseudo-element: paint the fill as a hard-stop\n gradient that ends at the thumb centre. */\n.havik-vol__slider::-webkit-slider-runnable-track{height:4px;border-radius:3px;\n background:linear-gradient(to right,var(--havik-accent,#E1B600) var(--havik-vol-pos),\n rgba(255,255,255,.3) var(--havik-vol-pos))}\n/* Firefox fills natively, and tracks the thumb exactly. */\n.havik-vol__slider::-moz-range-track{height:4px;border-radius:3px;background:rgba(255,255,255,.3)}\n.havik-vol__slider::-moz-range-progress{height:4px;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-vol__slider::-webkit-slider-thumb{-webkit-appearance:none;width:var(--havik-vol-thumb);\n height:var(--havik-vol-thumb);border-radius:50%;background:var(--havik-accent,#E1B600);\n margin-top:calc((4px - var(--havik-vol-thumb)) / 2)}\n.havik-vol__slider::-moz-range-thumb{width:var(--havik-vol-thumb);height:var(--havik-vol-thumb);\n border:0;border-radius:50%;background:var(--havik-accent,#E1B600)}\n\n.havik-time{font-size:12px;color:var(--havik-text-muted,#9aa0ad);\n font-variant-numeric:tabular-nums;padding:0 6px;white-space:nowrap}\n.havik-live{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;\n letter-spacing:.4px;padding:0 8px;color:var(--havik-text,#fff)}\n.havik-live svg{width:9px;height:9px;color:var(--havik-text-muted,#9aa0ad)}\n.havik-live.is-live svg{color:var(--havik-accent,#E1B600)}\n.havik-live__go{margin-left:2px;border:0;cursor:pointer;background:transparent;color:var(--havik-text-muted,#9aa0ad);\n font:inherit;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:6px}\n.havik-live.is-live .havik-live__go{display:none}\n.havik-live__go:hover{color:var(--havik-accent,#E1B600)}\n\n.havik-menu{position:absolute;bottom:54px;right:12px;min-width:170px;max-height:230px;overflow:auto;\n background:var(--havik-surface,#1B1C23);border:1px solid var(--havik-border,rgba(255,255,255,.1));\n border-radius:var(--havik-radius,8px);box-shadow:0 10px 30px rgba(0,0,0,.5);padding:6px;z-index:3}\n.havik-menu[hidden]{display:none}\n.havik-menu__title{font-size:11px;text-transform:uppercase;letter-spacing:.6px;\n color:var(--havik-text-muted,#9aa0ad);padding:6px 8px 4px}\n.havik-menu__item{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;font:inherit;font-size:13px;\n text-align:left;padding:7px 8px;border-radius:6px}\n.havik-menu__item:hover{background:var(--havik-surface-muted,#2a2c36)}\n.havik-menu__item[aria-checked=\"true\"]{color:var(--havik-accent,#E1B600);font-weight:600}\n.havik-menu__item[aria-checked=\"true\"]::after{content:'✓'}\n", qn = /* @__PURE__ */ new WeakMap();
2666
- function Jn(e = document, t) {
2667
- let n = e.querySelector(`style#${Z}`);
2668
- if (n && (!t || qn.get(n) === t)) return;
2718
+ var Zn = "havik-player-styles", Qn = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer;\n touch-action:manipulation}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n/* Absolutely centred, NOT a flex sibling of .havik-center: the hidden center\n button (.havik-gone) still occupies its 74px in the row, which pushed an\n in-flow spinner 37px right of centre. */\n.havik-spinner{position:absolute;inset:0;margin:auto;width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n/* A status card carries its own logo — the corner watermark would duplicate it. */\n.havik-player.havik-has-status .havik-watermark{display:none}\n\n.havik-bar{position:absolute;left:0;right:0;bottom:0;padding:0 12px 8px;\n opacity:1;transition:opacity .25s;z-index:2}\n.havik-seek{position:relative;height:16px;display:flex;align-items:center;cursor:pointer;margin-bottom:2px}\n.havik-seek__track{position:relative;width:100%;height:4px;border-radius:3px;background:rgba(255,255,255,.25)}\n.havik-seek__buffered{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:rgba(255,255,255,.4)}\n.havik-seek__played{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-seek__thumb{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;\n background:var(--havik-accent,#E1B600);transform:translate(-50%,-50%) scale(0);transition:transform .1s}\n.havik-seek:hover .havik-seek__thumb{transform:translate(-50%,-50%) scale(1)}\n\n.havik-controls{display:flex;align-items:center;gap:6px;height:40px}\n.havik-spacer{flex:1}\n.havik-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;border-radius:var(--havik-radius,8px);\n padding:0;transition:background .12s,color .12s}\n.havik-btn:hover{background:rgba(255,255,255,.12)}\n.havik-btn:focus-visible{outline:2px solid var(--havik-accent,#E1B600);outline-offset:1px}\n.havik-btn svg{width:22px;height:22px}\n\n/* The volume level is filled in accent up to the thumb, like the seek bar's\n played span — a native range input paints no \"elapsed\" side, which left the\n level readable only from the dot's position. --havik-vol (0..1) is set by\n syncVolume(); the track width and thumb size live here as variables because\n the WebKit fill has to compute the thumb centre from both. */\n.havik-vol{display:flex;align-items:center}\n.havik-vol__slider{--havik-vol-w:70px;--havik-vol-thumb:12px;--havik-vol:1;\n --havik-vol-pos:calc(var(--havik-vol-thumb) / 2 + var(--havik-vol) * (var(--havik-vol-w) - var(--havik-vol-thumb)));\n width:0;opacity:0;transition:width .18s,opacity .18s;height:4px;cursor:pointer;\n appearance:none;-webkit-appearance:none;background:transparent;border-radius:3px;margin:0 4px}\n.havik-vol:hover .havik-vol__slider,.havik-vol:focus-within .havik-vol__slider{width:var(--havik-vol-w);opacity:1}\n/* WebKit/Blink have no progress pseudo-element: paint the fill as a hard-stop\n gradient that ends at the thumb centre. */\n.havik-vol__slider::-webkit-slider-runnable-track{height:4px;border-radius:3px;\n background:linear-gradient(to right,var(--havik-accent,#E1B600) var(--havik-vol-pos),\n rgba(255,255,255,.3) var(--havik-vol-pos))}\n/* Firefox fills natively, and tracks the thumb exactly. */\n.havik-vol__slider::-moz-range-track{height:4px;border-radius:3px;background:rgba(255,255,255,.3)}\n.havik-vol__slider::-moz-range-progress{height:4px;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-vol__slider::-webkit-slider-thumb{-webkit-appearance:none;width:var(--havik-vol-thumb);\n height:var(--havik-vol-thumb);border-radius:50%;background:var(--havik-accent,#E1B600);\n margin-top:calc((4px - var(--havik-vol-thumb)) / 2)}\n.havik-vol__slider::-moz-range-thumb{width:var(--havik-vol-thumb);height:var(--havik-vol-thumb);\n border:0;border-radius:50%;background:var(--havik-accent,#E1B600)}\n\n.havik-time{font-size:12px;color:var(--havik-text-muted,#9aa0ad);\n font-variant-numeric:tabular-nums;padding:0 6px;white-space:nowrap}\n.havik-live{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;\n letter-spacing:.4px;padding:0 8px;color:var(--havik-text,#fff)}\n.havik-live svg{width:9px;height:9px;color:var(--havik-text-muted,#9aa0ad)}\n.havik-live.is-live svg{color:var(--havik-accent,#E1B600)}\n.havik-live__go{margin-left:2px;border:0;cursor:pointer;background:transparent;color:var(--havik-text-muted,#9aa0ad);\n font:inherit;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:6px}\n.havik-live.is-live .havik-live__go{display:none}\n.havik-live__go:hover{color:var(--havik-accent,#E1B600)}\n\n.havik-menu{position:absolute;bottom:54px;right:12px;min-width:170px;max-height:230px;overflow:auto;\n background:var(--havik-surface,#1B1C23);border:1px solid var(--havik-border,rgba(255,255,255,.1));\n border-radius:var(--havik-radius,8px);box-shadow:0 10px 30px rgba(0,0,0,.5);padding:6px;z-index:3}\n.havik-menu[hidden]{display:none}\n.havik-menu__title{font-size:11px;text-transform:uppercase;letter-spacing:.6px;\n color:var(--havik-text-muted,#9aa0ad);padding:6px 8px 4px}\n.havik-menu__item{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;font:inherit;font-size:13px;\n text-align:left;padding:7px 8px;border-radius:6px}\n.havik-menu__item:hover{background:var(--havik-surface-muted,#2a2c36)}\n.havik-menu__item[aria-checked=\"true\"]{color:var(--havik-accent,#E1B600);font-weight:600}\n.havik-menu__item[aria-checked=\"true\"]::after{content:'✓'}\n", $n = /* @__PURE__ */ new WeakMap();
2719
+ function er(e = document, t) {
2720
+ let n = e.querySelector(`style#${Zn}`);
2721
+ if (n && (!t || $n.get(n) === t)) return;
2669
2722
  let r = e.createElement("style");
2670
- r.id = Z, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = Kn, qn.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
2723
+ r.id = Zn, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = Qn, $n.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
2671
2724
  }
2672
2725
  //#endregion
2673
2726
  //#region src/ui/icons.ts
2674
- var Yn = {
2727
+ var tr = {
2675
2728
  play: "<path d=\"M8 5v14l11-7z\"/>",
2676
2729
  pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
2677
2730
  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\"/>",
@@ -2685,25 +2738,27 @@ var Yn = {
2685
2738
  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\"/>"
2686
2739
  };
2687
2740
  function Q(e) {
2688
- return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Yn[e]}</svg>`;
2741
+ return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${tr[e]}</svg>`;
2689
2742
  }
2690
2743
  //#endregion
2691
2744
  //#region src/ui/controls.ts
2692
- var Xn = 3e3, Zn = 250, Qn = /* @__PURE__ */ new Set([
2745
+ var nr = 3e3, rr = 250, ir = /* @__PURE__ */ new Set([
2693
2746
  "GONE",
2694
2747
  "NOT_FOUND",
2695
2748
  "GEO_DENIED",
2696
2749
  "INVALID_URN",
2697
- "UNAUTHORIZED"
2750
+ "UNAUTHORIZED",
2751
+ "DRM_DEVICE_REVOKED"
2698
2752
  ]);
2699
- function $n(e) {
2753
+ function ar(e) {
2700
2754
  let t = "This match isn't available in your country";
2701
2755
  return e ? `${t} (${e})` : t;
2702
2756
  }
2703
- function er(e) {
2704
- return new tr(e);
2757
+ var or = "This device can't play protected video";
2758
+ function sr(e) {
2759
+ return new cr(e);
2705
2760
  }
2706
- var tr = class {
2761
+ var cr = class {
2707
2762
  root;
2708
2763
  video;
2709
2764
  player;
@@ -2751,7 +2806,7 @@ var tr = class {
2751
2806
  scrubbing = !1;
2752
2807
  offFns = [];
2753
2808
  constructor(e) {
2754
- this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Xn, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.streamEnded = e.streamEnded ?? (() => !1), this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, Jn(this.doc, e.cspNonce), this.root.classList.add("havik-player"), this.root.hasAttribute("tabindex") || (this.root.tabIndex = 0), this.root.setAttribute("role", "region"), this.root.setAttribute("aria-label", "Video player");
2809
+ this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? nr, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.streamEnded = e.streamEnded ?? (() => !1), this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, er(this.doc, e.cspNonce), this.root.classList.add("havik-player"), this.root.hasAttribute("tabindex") || (this.root.tabIndex = 0), this.root.setAttribute("role", "region"), this.root.setAttribute("aria-label", "Video player");
2755
2810
  let t = (e, t, n) => {
2756
2811
  let r = this.doc.createElement(e);
2757
2812
  if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
@@ -2837,7 +2892,7 @@ var tr = class {
2837
2892
  let t = this.surfaceWasHidden;
2838
2893
  this.tapTimer = setTimeout(() => {
2839
2894
  this.tapTimer = void 0, this.toggleBar(t);
2840
- }, Zn);
2895
+ }, rr);
2841
2896
  }
2842
2897
  toggleBar(e) {
2843
2898
  e ? this.poke() : this.hideIfIdle();
@@ -2857,7 +2912,7 @@ var tr = class {
2857
2912
  this.statusOverlays && (e === "ended" ? t = "ended" : e === "error" ? t = "error" : e === "waiting" ? t = "waiting" : !this.hasPlayed && (e === "idle" || e === "paused") && (t = "preplay")), this.renderStatus(t);
2858
2913
  }
2859
2914
  statusMessageFor(e) {
2860
- return e === "ended" ? this.player.endedReason === "interrupted" ? this.interruptedMessage : this.endedMessage : e === "waiting" ? this.hasPlayed ? "Reconnecting — please stand by" : "Starting soon…" : e === "error" ? this.errorMessage === void 0 ? this.lastError?.code === "GEO_DENIED" ? $n(this.lastError.country) : this.lastError?.message ?? "Playback unavailable" : this.errorMessage : null;
2915
+ return e === "ended" ? this.player.endedReason === "interrupted" ? this.interruptedMessage : this.endedMessage : e === "waiting" ? this.hasPlayed ? "Reconnecting — please stand by" : "Starting soon…" : e === "error" ? this.errorMessage === void 0 ? this.lastError?.code === "GEO_DENIED" ? ar(this.lastError.country) : this.lastError?.code === "DRM_DEVICE_REVOKED" ? or : this.lastError?.message ?? "Playback unavailable" : this.errorMessage : null;
2861
2916
  }
2862
2917
  renderStatus(e) {
2863
2918
  let t = this.statusMessageFor(e);
@@ -2872,7 +2927,7 @@ var tr = class {
2872
2927
  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);
2873
2928
  } else {
2874
2929
  let r = this.doc.createElement("div");
2875
- if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !Qn.has(this.lastError.code)) {
2930
+ if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !ir.has(this.lastError.code)) {
2876
2931
  let e = this.doc.createElement("button");
2877
2932
  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);
2878
2933
  }
@@ -2913,7 +2968,7 @@ var tr = class {
2913
2968
  let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
2914
2969
  this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
2915
2970
  }
2916
- !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${nr(this.video.currentTime)} / ${nr(this.video.duration)}`);
2971
+ !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${lr(this.video.currentTime)} / ${lr(this.video.duration)}`);
2917
2972
  }
2918
2973
  syncLive() {
2919
2974
  let e = this.player.getStats(), t = e.isLive !== !1, n = this.player.state === "ended", r = !t && !this.streamEnded();
@@ -2963,17 +3018,17 @@ var tr = class {
2963
3018
  renderQualityMenu() {
2964
3019
  let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
2965
3020
  n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
2966
- for (let n of e) this.menu.append(this.menuItem(rr(n), t === n.index, () => this.player.setQuality(n.index)));
3021
+ for (let n of e) this.menu.append(this.menuItem(ur(n), t === n.index, () => this.player.setQuality(n.index)));
2967
3022
  }
2968
3023
  renderAudioMenu() {
2969
3024
  let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
2970
3025
  t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
2971
- for (let t of e) this.menu.append(this.menuItem(ir(t), t.default, () => this.player.setAudioTrack(t.id)));
3026
+ for (let t of e) this.menu.append(this.menuItem(dr(t), t.default, () => this.player.setAudioTrack(t.id)));
2972
3027
  }
2973
3028
  renderCcMenu() {
2974
3029
  let e = this.player.getTextTracks(), t = this.doc.createElement("div");
2975
3030
  t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
2976
- for (let t of e) this.menu.append(this.menuItem(ar(t), !1, () => this.player.setTextTrack(t.id)));
3031
+ for (let t of e) this.menu.append(this.menuItem(fr(t), !1, () => this.player.setTextTrack(t.id)));
2977
3032
  }
2978
3033
  onTracksChanged() {
2979
3034
  this.openMenu && this.renderMenu(this.openMenu);
@@ -3078,41 +3133,41 @@ var tr = class {
3078
3133
  this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
3079
3134
  }
3080
3135
  };
3081
- function nr(e) {
3136
+ function lr(e) {
3082
3137
  (!Number.isFinite(e) || e < 0) && (e = 0);
3083
3138
  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");
3084
3139
  return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
3085
3140
  }
3086
- function rr(e) {
3141
+ function ur(e) {
3087
3142
  return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
3088
3143
  }
3089
- function ir(e) {
3144
+ function dr(e) {
3090
3145
  return e.name || e.lang || `Track ${e.id}`;
3091
3146
  }
3092
- function ar(e) {
3147
+ function fr(e) {
3093
3148
  return e.name || e.lang || `Track ${e.id}`;
3094
3149
  }
3095
3150
  //#endregion
3096
3151
  //#region src/managed/index.ts
3097
- var or = 6e3, sr = 45e3, cr = 2e3, lr = 3, ur = 5e3, dr = 2e3, fr = 48e4, pr = "keySystemLicenseRequestFailed";
3098
- function mr(e) {
3152
+ var pr = 6e3, mr = 45e3, hr = 2e3, gr = 3, _r = 5e3, vr = 2e3, yr = 48e4, br = "keySystemLicenseRequestFailed";
3153
+ function xr(e) {
3099
3154
  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)})`);
3100
- if (e.env !== void 0) return it(e.env);
3155
+ if (e.env !== void 0) return at(e.env);
3101
3156
  if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
3102
3157
  return e.baseUrl;
3103
3158
  }
3104
- async function hr(e) {
3159
+ async function Sr(e) {
3105
3160
  if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
3106
- let t = mr(e);
3161
+ let t = xr(e);
3107
3162
  if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
3108
3163
  if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
3109
- let r = new gr({
3164
+ let r = new Cr({
3110
3165
  ...e,
3111
3166
  baseUrl: t
3112
3167
  });
3113
3168
  return await r.start(), r;
3114
3169
  }
3115
- var gr = class {
3170
+ var Cr = class {
3116
3171
  opts;
3117
3172
  abort = new AbortController();
3118
3173
  listeners = {};
@@ -3169,7 +3224,7 @@ var gr = class {
3169
3224
  throw this.destroy(), e;
3170
3225
  }
3171
3226
  } catch (t) {
3172
- if (this.opts.waitForLive && t instanceof n && o(t.code)) {
3227
+ if (this.opts.waitForLive && t instanceof n && s(t.code)) {
3173
3228
  this.setState("waiting"), this.beginArming(e, t.liveStartsAtMs);
3174
3229
  return;
3175
3230
  }
@@ -3201,13 +3256,13 @@ var gr = class {
3201
3256
  });
3202
3257
  }
3203
3258
  armWithSse(e, t, r, i = !1) {
3204
- let a = !1, s = !1, c = new AbortController();
3259
+ let a = !1, o = !1, c = new AbortController();
3205
3260
  this.armFallbackCtrl = c, this.setState("waiting");
3206
3261
  let l = this.opts.waitForLive, u = l && l !== !0 ? l.kickoffAt : void 0, d = typeof u == "number" ? u : typeof u == "string" ? Date.parse(u) : NaN, f = r ?? (Number.isFinite(d) ? d : void 0);
3207
3262
  setTimeout(() => {
3208
3263
  a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
3209
3264
  phase: i ? "unavailable" : "tooEarly",
3210
- retryInMs: sr,
3265
+ retryInMs: mr,
3211
3266
  attempt: 1,
3212
3267
  elapsedMs: 0,
3213
3268
  ...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
@@ -3224,7 +3279,7 @@ var gr = class {
3224
3279
  }
3225
3280
  }
3226
3281
  }, h = () => {
3227
- a || s || p() || (s = !0, y({
3282
+ a || o || p() || (o = !0, y({
3228
3283
  ...this.resolveOptions(),
3229
3284
  signal: c.signal,
3230
3285
  waitForLive: this.buildWaitConfig(e)
@@ -3234,7 +3289,7 @@ var gr = class {
3234
3289
  }, g = () => {
3235
3290
  a || p() || v(this.resolveOptions()).then((e) => m(e)).catch((e) => {
3236
3291
  if (!(a || p())) {
3237
- if (e instanceof n && o(e.code)) {
3292
+ if (e instanceof n && s(e.code)) {
3238
3293
  h();
3239
3294
  return;
3240
3295
  }
@@ -3246,13 +3301,13 @@ var gr = class {
3246
3301
  !a && !p() && h();
3247
3302
  }, e);
3248
3303
  };
3249
- _(or), this.armingSub = E({
3304
+ _(pr), this.armingSub = E({
3250
3305
  eventsBaseUrl: t,
3251
3306
  matchUrn: this.opts.matchUrn,
3252
3307
  credential: this.opts.credential,
3253
- onAlive: () => _(sr),
3308
+ onAlive: () => _(mr),
3254
3309
  onState: (e) => {
3255
- a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * cr);
3310
+ a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * hr);
3256
3311
  },
3257
3312
  onError: () => h()
3258
3313
  });
@@ -3272,10 +3327,10 @@ var gr = class {
3272
3327
  async onResolved(e, t) {
3273
3328
  if (this.destroyed || t !== this.loadGen) return;
3274
3329
  this._descriptor = e, this.endedHandled = !1, this._endedReason = null;
3275
- let n = await s(this.opts.credential);
3330
+ let n = await c(this.opts.credential);
3276
3331
  if (this.destroyed || t !== this.loadGen) return;
3277
3332
  this.setState("loading");
3278
- let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = lt(this.opts.video, (e) => {
3333
+ let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = ut(this.opts.video, (e) => {
3279
3334
  this._state !== "ended" && this._state !== "error" && this.setState(e);
3280
3335
  });
3281
3336
  if (await i.load(), this.destroyed || t !== this.loadGen) {
@@ -3297,19 +3352,19 @@ var gr = class {
3297
3352
  if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
3298
3353
  let i = e.analytics?.sid;
3299
3354
  if (!i) return;
3300
- let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = Fn(this.opts.baseUrl, a, e.analytics?.endpoint);
3355
+ let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = Bn(this.opts.baseUrl, a, e.analytics?.endpoint);
3301
3356
  if (!o) {
3302
3357
  s && setTimeout(() => {
3303
3358
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
3304
3359
  }, 0);
3305
3360
  return;
3306
3361
  }
3307
- let c = this.opts.video, l = new In({
3362
+ let c = this.opts.video, l = new Vn({
3308
3363
  endpoint: o,
3309
3364
  sid: i,
3310
3365
  player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
3311
- sdkVersion: Hn,
3312
- environment: Bn(c),
3366
+ sdkVersion: qn,
3367
+ environment: Gn(c),
3313
3368
  idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
3314
3369
  onIdle: () => this.onAnalyticsIdle(t),
3315
3370
  onBlocked: (e) => setTimeout(() => {
@@ -3330,7 +3385,7 @@ var gr = class {
3330
3385
  let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
3331
3386
  c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
3332
3387
  c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
3333
- }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), Vn().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
3388
+ }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), Kn().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
3334
3389
  }
3335
3390
  currentPresentation() {
3336
3391
  let e = this.opts.video;
@@ -3350,6 +3405,7 @@ var gr = class {
3350
3405
  lowLatency: this.opts.lowLatency === void 0 || this.opts.lowLatency === "auto" || this.opts.lowLatency,
3351
3406
  snapToLiveOnRefocus: this.opts.snapToLiveOnRefocus,
3352
3407
  rememberBandwidth: this.opts.rememberBandwidth,
3408
+ sizeCapHeadroom: this.opts.sizeCapHeadroom,
3353
3409
  mediaDuringKey: this.opts.mediaDuringKey,
3354
3410
  debug: this.opts.debug,
3355
3411
  deferLoad: r,
@@ -3358,9 +3414,9 @@ var gr = class {
3358
3414
  freshLicenseUrl: () => this.refreshLicense()
3359
3415
  }, o = this.opts.engine ?? "auto";
3360
3416
  if (o === "native") return new W(a);
3361
- if (o === "hls") return new _n(a);
3362
- if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && H(this.opts.video) && U() || !e.drmEnabled && xt() && H(this.opts.video)) return new W(a);
3363
- if (Nt()) return new _n(a);
3417
+ if (o === "hls") return new Cn(a);
3418
+ if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && H(this.opts.video) && U() || !e.drmEnabled && St() && H(this.opts.video)) return new W(a);
3419
+ if (It()) return new Cn(a);
3364
3420
  if (H(this.opts.video)) return new W(a);
3365
3421
  throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
3366
3422
  }
@@ -3423,7 +3479,7 @@ var gr = class {
3423
3479
  r = 0, i = !1;
3424
3480
  },
3425
3481
  onError: () => {
3426
- this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= lr && (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.`))));
3482
+ this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= gr && (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.`))));
3427
3483
  }
3428
3484
  });
3429
3485
  }
@@ -3437,7 +3493,7 @@ var gr = class {
3437
3493
  return;
3438
3494
  }
3439
3495
  let e = this.hiddenAtMs;
3440
- this.hiddenAtMs = null, e != null && Date.now() - e >= ur && this.resyncLiveState();
3496
+ this.hiddenAtMs = null, e != null && Date.now() - e >= _r && this.resyncLiveState();
3441
3497
  }, this.onReturnPageShow = (e) => {
3442
3498
  e.persisted && this.resyncLiveState();
3443
3499
  }, document.addEventListener("visibilitychange", this.onReturnVisible), typeof window < "u" && window.addEventListener("pageshow", this.onReturnPageShow));
@@ -3469,7 +3525,7 @@ var gr = class {
3469
3525
  scheduleRejoin(e) {
3470
3526
  this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
3471
3527
  this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
3472
- }, Math.random() * cr));
3528
+ }, Math.random() * hr));
3473
3529
  }
3474
3530
  cancelRejoin() {
3475
3531
  this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
@@ -3493,7 +3549,7 @@ var gr = class {
3493
3549
  }
3494
3550
  t.controls = !1;
3495
3551
  let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
3496
- r && r.insertBefore(n, t), n.appendChild(t), Gn(n, this.opts.theme), this.container = n, this.controlBar = er({
3552
+ r && r.insertBefore(n, t), n.appendChild(t), Xn(n, this.opts.theme), this.container = n, this.controlBar = sr({
3497
3553
  root: n,
3498
3554
  video: t,
3499
3555
  player: this,
@@ -3531,7 +3587,7 @@ var gr = class {
3531
3587
  }
3532
3588
  startStats() {
3533
3589
  this.stopStats();
3534
- let e = Math.max(500, this.opts.statsIntervalMs ?? dr);
3590
+ let e = Math.max(500, this.opts.statsIntervalMs ?? vr);
3535
3591
  this.statsTimer = setInterval(() => {
3536
3592
  if (!this.engine) return;
3537
3593
  let e = this.engine.getStats();
@@ -3542,14 +3598,14 @@ var gr = class {
3542
3598
  this.statsTimer && clearInterval(this.statsTimer), this.statsTimer = void 0;
3543
3599
  }
3544
3600
  isStaleLicenseDenial(e) {
3545
- return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== pr || e.error.httpStatus !== 403 ? !1 : K(this._descriptor?.drm?.widevine?.licenseUrl);
3601
+ return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== br || e.error.httpStatus !== 403 || e.error.code !== "FORBIDDEN" || e.error.serverCode === "license_refused" ? !1 : K(this._descriptor?.drm?.widevine?.licenseUrl);
3546
3602
  }
3547
3603
  scheduleLicenseRefresh() {
3548
3604
  if (this.stopRefresh(), !this._descriptor?.drmEnabled) return;
3549
3605
  typeof document < "u" && this.engine?.name === "hls" && (this.onRefocus = () => {
3550
3606
  document.visibilityState !== "visible" || this.destroyed || K(this._descriptor?.drm?.widevine?.licenseUrl) && this.refreshLicense();
3551
3607
  }, document.addEventListener("visibilitychange", this.onRefocus));
3552
- let e = this.opts.licenseRefreshMs ?? fr;
3608
+ let e = this.opts.licenseRefreshMs ?? yr;
3553
3609
  e && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
3554
3610
  }
3555
3611
  stopRefresh() {
@@ -3569,7 +3625,7 @@ var gr = class {
3569
3625
  fairplay: r
3570
3626
  }), this._descriptor = t), n;
3571
3627
  } catch (e) {
3572
- e instanceof n && !o(e.code) && (this.stopRefresh(), this.destroyed || this.emit("warning", e));
3628
+ e instanceof n && !s(e.code) && (this.stopRefresh(), this.destroyed || this.emit("warning", e));
3573
3629
  return;
3574
3630
  } finally {
3575
3631
  this.refreshInFlight?.promise === t && (this.refreshInFlight = void 0);
@@ -3719,7 +3775,7 @@ function $(e) {
3719
3775
  }
3720
3776
  //#endregion
3721
3777
  //#region src/embed/host.ts
3722
- function _r(e) {
3778
+ function wr(e) {
3723
3779
  if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
3724
3780
  if (!e.src) throw Error("mountEmbed: opts.src is required");
3725
3781
  if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
@@ -3778,15 +3834,15 @@ function _r(e) {
3778
3834
  }
3779
3835
  //#endregion
3780
3836
  //#region src/embed/page.ts
3781
- var vr = /^[A-Za-z0-9:_.-]{1,128}$/;
3782
- function yr(e) {
3837
+ var Tr = /^[A-Za-z0-9:_.-]{1,128}$/;
3838
+ function Er(e) {
3783
3839
  if (typeof e == "boolean") return e;
3784
3840
  if (typeof e == "object" && e) {
3785
3841
  let t = e.endpoint;
3786
3842
  return typeof t == "string" ? { endpoint: t } : {};
3787
3843
  }
3788
3844
  }
3789
- function br() {
3845
+ function Dr() {
3790
3846
  let e = window.HAVIK_EMBED_CONFIG;
3791
3847
  if (e) return {
3792
3848
  baseUrl: e.baseUrl ?? "",
@@ -3796,7 +3852,7 @@ function br() {
3796
3852
  autoplay: e.autoplay ?? !0,
3797
3853
  muted: e.muted ?? !0,
3798
3854
  waitForLive: e.waitForLive ?? !0,
3799
- analytics: yr(e.analytics)
3855
+ analytics: Er(e.analytics)
3800
3856
  };
3801
3857
  let t = new URLSearchParams(location.search);
3802
3858
  return {
@@ -3809,9 +3865,9 @@ function br() {
3809
3865
  waitForLive: !0
3810
3866
  };
3811
3867
  }
3812
- async function xr() {
3813
- let e = br();
3814
- Cr();
3868
+ async function Or() {
3869
+ let e = Dr();
3870
+ Ar();
3815
3871
  let t = document.createElement("video");
3816
3872
  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);
3817
3873
  let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
@@ -3867,12 +3923,12 @@ async function xr() {
3867
3923
  message: e.message,
3868
3924
  ...e.country === void 0 ? {} : { country: e.country }
3869
3925
  })), e.on("autoplayblocked", () => {
3870
- i({ type: "oddin:autoplayblocked" }), Sr(t, e);
3926
+ i({ type: "oddin:autoplayblocked" }), kr(t, e);
3871
3927
  });
3872
3928
  }, s = async (r) => {
3873
3929
  a?.destroy(), a = null;
3874
3930
  try {
3875
- let n = await hr({
3931
+ let n = await Sr({
3876
3932
  video: t,
3877
3933
  baseUrl: e.baseUrl,
3878
3934
  matchUrn: r,
@@ -3935,7 +3991,7 @@ async function xr() {
3935
3991
  a?.retry();
3936
3992
  break;
3937
3993
  case "oddin:load":
3938
- typeof e.matchUrn == "string" && vr.test(e.matchUrn) && s(e.matchUrn);
3994
+ typeof e.matchUrn == "string" && Tr.test(e.matchUrn) && s(e.matchUrn);
3939
3995
  break;
3940
3996
  case "oddin:destroy": c();
3941
3997
  }
@@ -3947,18 +4003,18 @@ async function xr() {
3947
4003
  protocol: 1
3948
4004
  });
3949
4005
  }
3950
- function Sr(e, t) {
4006
+ function kr(e, t) {
3951
4007
  if (document.getElementById("havik-tap")) return;
3952
4008
  let n = document.createElement("button");
3953
4009
  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", () => {
3954
4010
  n.remove(), t.play();
3955
4011
  }), document.body.appendChild(n);
3956
4012
  }
3957
- function Cr() {
4013
+ function Ar() {
3958
4014
  let e = document.createElement("style");
3959
4015
  e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
3960
4016
  }
3961
4017
  //#endregion
3962
- export { Un as ODDIN_THEME, n as PlaybackError, Gn as applyTheme, it as baseUrlForEnv, xr as bootEmbed, Te as clearDeviceId, Le as clearRememberedBandwidth, hr as createPlayer, D as deriveEventsBaseUrl, et as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, _e as fetchCatalog, ye as fetchTournament, xe as flattenMatches, C as fullscreenSupported, A as getDeviceId, nt as isLowLatencyManifest, $ as isOddinMessage, De as licenseRequestHeaders, _r as mountEmbed, de as pollToLive, y as resolveStream, E as subscribeLiveState, S as videoFullscreenActive, Ce as watchStatus };
4018
+ export { Jn as ODDIN_THEME, n as PlaybackError, Xn as applyTheme, at as baseUrlForEnv, Or as bootEmbed, Ee as clearDeviceId, Re as clearRememberedBandwidth, Sr as createPlayer, D as deriveEventsBaseUrl, tt as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, ve as fetchCatalog, be as fetchTournament, Se as flattenMatches, C as fullscreenSupported, A as getDeviceId, rt as isLowLatencyManifest, $ as isOddinMessage, Oe as licenseRequestHeaders, wr as mountEmbed, fe as pollToLive, y as resolveStream, E as subscribeLiveState, S as videoFullscreenActive, we as watchStatus };
3963
4019
 
3964
4020
  //# sourceMappingURL=index.js.map