@oddin-gg/havik-player 2.20.0 → 2.21.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,24 @@ 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 = .2, fn = 30, pn = 2, mn = 2, hn = 9, gn = .5, _n = 64;
1488
+ function vn(e) {
1450
1489
  if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
1451
1490
  delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
1452
1491
  return;
1453
1492
  }
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);
1493
+ e.liveSyncDuration ??= mn;
1494
+ let t = Math.max(12, e.liveSyncDuration + hn);
1495
+ (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), yn(e, e.liveSyncDuration);
1457
1496
  }
1458
- function gn(e, t) {
1497
+ function yn(e, t) {
1459
1498
  let n = (e, t, n) => Math.min(n, Math.max(t, e));
1460
1499
  e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
1461
1500
  }
1462
- var _n = class {
1501
+ var bn = class {
1463
1502
  name = "hls";
1464
1503
  hls = null;
1465
1504
  deps;
@@ -1543,7 +1582,7 @@ var _n = class {
1543
1582
  frameCounter;
1544
1583
  detachFrames = null;
1545
1584
  constructor(e) {
1546
- this.deps = e, this.frameCounter = new ct(e.video), this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
1585
+ this.deps = e, this.frameCounter = new lt(e.video), this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
1547
1586
  }
1548
1587
  async load() {
1549
1588
  this.detachFrames ??= this.frameCounter.attach();
@@ -1556,7 +1595,7 @@ var _n = class {
1556
1595
  });
1557
1596
  return;
1558
1597
  }
1559
- e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (He(r), Ke()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1598
+ e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ue(r), qe()), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
1560
1599
  let e = this.hls;
1561
1600
  if (document.visibilityState !== "visible" || !e) return;
1562
1601
  let t = e.liveSyncPosition;
@@ -1579,7 +1618,7 @@ var _n = class {
1579
1618
  }
1580
1619
  this.loadSuspended = !0;
1581
1620
  }
1582
- }, Zt));
1621
+ }, en));
1583
1622
  }
1584
1623
  resumeLoading() {
1585
1624
  if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
@@ -1611,7 +1650,7 @@ var _n = class {
1611
1650
  let t = e.liveSyncPosition;
1612
1651
  if (typeof t != "number" || !Number.isFinite(t)) return;
1613
1652
  let { video: n } = this.deps;
1614
- n.currentTime <= t + pn || (n.currentTime = t);
1653
+ n.currentTime <= t + gn || (n.currentTime = t);
1615
1654
  }
1616
1655
  reanchorPartTimeline(e, t) {
1617
1656
  let { frag: n, part: r } = t;
@@ -1623,7 +1662,7 @@ var _n = class {
1623
1662
  let o = n.sn, s = i.fragments.find((e) => e && e.sn === o) ?? (i.fragmentHint?.sn === o ? i.fragmentHint : void 0);
1624
1663
  if (!s) return;
1625
1664
  let c = a.startPTS - s.start;
1626
- if (!(!Number.isFinite(c) || Math.abs(c) < Wt)) {
1665
+ if (!(!Number.isFinite(c) || Math.abs(c) < qt)) {
1627
1666
  for (let e of i.fragments) e && e.setStart(e.start + c);
1628
1667
  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
1668
  }
@@ -1651,7 +1690,7 @@ var _n = class {
1651
1690
  videoEncryptionScheme: F.scheme,
1652
1691
  audioEncryptionScheme: F.scheme
1653
1692
  },
1654
- ...M() ? { requestMediaKeySystemAccessFunc: Ve(t) } : {},
1693
+ ...M() ? { requestMediaKeySystemAccessFunc: He(t) } : {},
1655
1694
  licenseXhrSetup: (e, t) => {
1656
1695
  let o = performance.now(), s = () => {
1657
1696
  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 +1702,7 @@ var _n = class {
1663
1702
  return;
1664
1703
  }
1665
1704
  let l = this.hls, u, d = new Promise((e) => {
1666
- u = setTimeout(() => e(void 0), Bt);
1705
+ u = setTimeout(() => e(void 0), Ut);
1667
1706
  });
1668
1707
  return Promise.race([c().catch(() => void 0), d]).finally(() => clearTimeout(u)).then((e) => {
1669
1708
  if (!this.hls || this.hls !== l) throw Error("havik-player: engine torn down during refresh");
@@ -1679,20 +1718,20 @@ var _n = class {
1679
1718
  ...c
1680
1719
  };
1681
1720
  if (this.prefetch?.destroy(), this.prefetch = null, u && this.deps.mediaDuringKey !== !1 && !f.fLoader) {
1682
- let e = new Ot({
1721
+ let e = new jt({
1683
1722
  sessionId: n.analytics?.sid,
1684
1723
  contentId: n.matchUrn
1685
- }), t = kt(e);
1724
+ }), t = Mt(e);
1686
1725
  t && (this.prefetch = e, f.fLoader = t);
1687
1726
  }
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;
1727
+ vn(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
1728
  let p = new e(f);
1690
1729
  if (this.hls = p, p.on(e.Events.FRAG_PARSED, (e, t) => this.reanchorPartTimeline(p, t)), p.on(e.Events.MANIFEST_PARSED, () => {
1691
1730
  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
1731
  }), p.on(e.Events.FRAG_BUFFERED, (e, t) => {
1693
1732
  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
1733
  this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
1695
- }, Vt)));
1734
+ }, Wt)));
1696
1735
  }), p.on(e.Events.FRAG_LOADING, (e, t) => {
1697
1736
  t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
1698
1737
  }), p.on(e.Events.FRAG_LOADED, (e, t) => {
@@ -1700,10 +1739,10 @@ var _n = class {
1700
1739
  let n = t?.frag?.stats, r = n?.loaded;
1701
1740
  typeof r == "number" && (this.bytesLoaded += r), !this.reportedFirstBytes && typeof r == "number" && r > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
1702
1741
  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());
1742
+ 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 > _n && this.requestTimesMs.shift());
1704
1743
  let a = t?.frag?.url;
1705
1744
  if (a) {
1706
- let e = at(a);
1745
+ let e = ot(a);
1707
1746
  e && (this.cdnHost = e);
1708
1747
  }
1709
1748
  }), p.on(e.Events.LEVEL_LOADED, (e, t) => {
@@ -1717,15 +1756,15 @@ var _n = class {
1717
1756
  }), p.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.prefetch) {
1718
1757
  let t = this.prefetch;
1719
1758
  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)));
1759
+ let r = n?.frag, i = Pt(r?.type);
1760
+ if (r && t.isActive(i)) for (let e of Ft(p, r)) t.prefetch(e.url, i, e.kind);
1761
+ }), p.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(Pt(n?.frag?.type)));
1723
1762
  }
1724
1763
  p.on(e.Events.KEY_LOADED, () => {
1725
1764
  u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
1726
1765
  }), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
1727
1766
  this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.checkFrameDrops();
1728
- }, Ut), p.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1767
+ }, Kt), p.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1729
1768
  this.renditionSwitches += 1;
1730
1769
  let n = this.lastLevelIndex >= 0 ? p.levels[this.lastLevelIndex] : void 0, r = p.levels[t.level];
1731
1770
  n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, l({
@@ -1789,7 +1828,7 @@ var _n = class {
1789
1828
  return;
1790
1829
  }
1791
1830
  this.capTimer && clearTimeout(this.capTimer);
1792
- let t = e > this.sizeCapLevel ? on : sn;
1831
+ let t = e > this.sizeCapLevel ? ln : un;
1793
1832
  this.capTimer = setTimeout(() => {
1794
1833
  this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
1795
1834
  }, t);
@@ -1799,9 +1838,9 @@ var _n = class {
1799
1838
  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
1839
  }
1801
1840
  dropLevelsWidevineCannotPlay(e) {
1802
- this.removeLevelsWhere(e, (e) => qe(e) !== !0);
1841
+ this.removeLevelsWhere(e, (e) => Je(e) !== !0);
1803
1842
  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) => {
1843
+ for (let n of t) Ke(n).then((t) => {
1805
1844
  t || this.hls !== e || this.removeLevelsWhere(e, (e) => e === n) && (this.measureLadder(e), this.applySizeCap());
1806
1845
  });
1807
1846
  }
@@ -1812,7 +1851,7 @@ var _n = class {
1812
1851
  a && I(a) && t(a) && (r.push(n), i.add(a));
1813
1852
  }), !r.length) return !1;
1814
1853
  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;
1854
+ 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
1855
  for (let t = r.length - 1; t >= 0; --t) e.removeLevel(r[t]);
1817
1856
  return console.info(`havik-player: skipped ${r.length} rendition(s) Widevine cannot play on this browser (${a})`), !0;
1818
1857
  }
@@ -1918,7 +1957,7 @@ var _n = class {
1918
1957
  return;
1919
1958
  }
1920
1959
  let e = Date.now() - this.lastAdvanceMs;
1921
- !this.chaseSuspended && e > Gt && this.suspendChasing(), e > Ht && this.emitEnded("stalled");
1960
+ !this.chaseSuspended && e > Jt && this.suspendChasing(), e > Gt && this.emitEnded("stalled");
1922
1961
  }
1923
1962
  resetStarvationWindow() {
1924
1963
  this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
@@ -1933,7 +1972,7 @@ var _n = class {
1933
1972
  this.resetStarvationWindow();
1934
1973
  return;
1935
1974
  }
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;
1975
+ 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
1976
  if (this.starvedFrames = c, !a || l) {
1938
1977
  (t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
1939
1978
  return;
@@ -1942,12 +1981,12 @@ var _n = class {
1942
1981
  this.resetStarvationWindow();
1943
1982
  return;
1944
1983
  }
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)) {
1984
+ 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
1985
  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
1986
  return;
1948
1987
  }
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))) {
1988
+ let u = i && this.starvedTicks >= nn, d = !i && this.deadTicks >= sn && this.recentMainFrags.reduce((e, t) => e + t, 0) >= cn;
1989
+ if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= rn))) {
1951
1990
  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
1991
  try {
1953
1992
  e.stopLoad(), e.startLoad(-1);
@@ -1962,7 +2001,7 @@ var _n = class {
1962
2001
  let t = e.latency, n = e.targetLatency;
1963
2002
  if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
1964
2003
  let r = t - n;
1965
- !this.catchUpEngaged && r > Kt ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= Kt && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
2004
+ !this.catchUpEngaged && r > Yt ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= Yt && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
1966
2005
  let i = this.catchUpEngaged ? this.catchUpRate : 1;
1967
2006
  e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
1968
2007
  }
@@ -1984,15 +2023,15 @@ var _n = class {
1984
2023
  return;
1985
2024
  }
1986
2025
  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) {
2026
+ if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < fn || o < 0) {
1988
2027
  this.fpsBadTicks = 0;
1989
2028
  return;
1990
2029
  }
1991
- if (o <= cn * a) {
2030
+ if (o <= dn * a) {
1992
2031
  this.fpsBadTicks = 0;
1993
2032
  return;
1994
2033
  }
1995
- if (this.fpsBadTicks += 1, this.fpsBadTicks < un) return;
2034
+ if (this.fpsBadTicks += 1, this.fpsBadTicks < pn) return;
1996
2035
  this.fpsBadTicks = 0;
1997
2036
  let s = e.levels, c = s[e.currentLevel];
1998
2037
  if (!c) return;
@@ -2009,20 +2048,20 @@ var _n = class {
2009
2048
  return;
2010
2049
  }
2011
2050
  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))) {
2051
+ if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(Qt, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
2013
2052
  this.resetChaseWindow();
2014
2053
  return;
2015
2054
  }
2016
- if (this.chaseLatency < 0 || this.chaseLatency - n >= Jt) {
2055
+ if (this.chaseLatency < 0 || this.chaseLatency - n >= Zt) {
2017
2056
  this.chaseLatency = n, this.chaseTicks = 0;
2018
2057
  return;
2019
2058
  }
2020
- if (this.chaseTicks += 1, this.chaseTicks < qt) return;
2059
+ if (this.chaseTicks += 1, this.chaseTicks < Xt) return;
2021
2060
  this.resetChaseWindow();
2022
2061
  let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
2023
2062
  if (!(a > 1)) return;
2024
2063
  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);
2064
+ 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
2065
  }
2027
2066
  suspendChasing() {
2028
2067
  let e = this.hls;
@@ -2052,14 +2091,14 @@ var _n = class {
2052
2091
  } catch {}
2053
2092
  }
2054
2093
  startEstimate() {
2055
- return this.deps.rememberBandwidth === !1 ? Pt : Fe() ?? Pt;
2094
+ return this.deps.rememberBandwidth === !1 ? Lt : Ie() ?? Lt;
2056
2095
  }
2057
2096
  maybeRememberBandwidth(e) {
2058
- if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded < Ft) return;
2097
+ if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded < Rt) return;
2059
2098
  let t = Date.now();
2060
- if (!e && t - this.bwSavedAt < It) return;
2099
+ if (!e && t - this.bwSavedAt < zt) return;
2061
2100
  let n = this.hls?.bandwidthEstimate;
2062
- typeof n != "number" || !Number.isFinite(n) || n <= 0 || (this.bwSavedAt = t, Ie(n));
2101
+ typeof n != "number" || !Number.isFinite(n) || n <= 0 || (this.bwSavedAt = t, Le(n));
2063
2102
  }
2064
2103
  destroy() {
2065
2104
  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 +2116,7 @@ var _n = class {
2077
2116
  scheduleLicenseRetry(t) {
2078
2117
  if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
2079
2118
  let n = t.response?.code ?? 0;
2080
- if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= zt) return !1;
2119
+ if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= Ht) return !1;
2081
2120
  this.licenseRecoveries += 1;
2082
2121
  let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
2083
2122
  return this.licenseRetryTimer = setTimeout(() => {
@@ -2109,7 +2148,7 @@ var _n = class {
2109
2148
  return;
2110
2149
  }
2111
2150
  if (t.type === e.ErrorTypes.NETWORK_ERROR) {
2112
- if (this.networkRecoveries < Rt) {
2151
+ if (this.networkRecoveries < Vt) {
2113
2152
  this.networkRecoveries += 1;
2114
2153
  let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
2115
2154
  this.networkRetryTimer = setTimeout(() => {
@@ -2126,7 +2165,7 @@ var _n = class {
2126
2165
  return;
2127
2166
  }
2128
2167
  if (t.type === e.ErrorTypes.MEDIA_ERROR) {
2129
- if (this.mediaRecoveries < Lt) {
2168
+ if (this.mediaRecoveries < Bt) {
2130
2169
  this.mediaRecoveries += 1, n.recoverMediaError();
2131
2170
  return;
2132
2171
  }
@@ -2146,23 +2185,23 @@ var _n = class {
2146
2185
  });
2147
2186
  }
2148
2187
  }
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})` : ""}`);
2188
+ toError(t, r = "PLAYBACK") {
2189
+ 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;
2190
+ 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
2191
  }
2153
- }, vn = 15e3, yn = 6e5, bn = 3e5, xn = 100, q = 1, Sn = 1e3, Cn = 3e4, wn = 1e3, Tn = {
2192
+ }, xn = 15e3, Sn = 6e5, Cn = 3e5, wn = 100, q = 1, Tn = 1e3, En = 3e4, Dn = 1e3, On = {
2154
2193
  inline: "PRESENTATION_INLINE",
2155
2194
  fullscreen: "PRESENTATION_FULLSCREEN",
2156
2195
  pip: "PRESENTATION_PIP"
2157
- }, En = {
2196
+ }, kn = {
2158
2197
  widevine: "KEY_SYSTEM_WIDEVINE",
2159
2198
  fairplay: "KEY_SYSTEM_FAIRPLAY",
2160
2199
  none: "KEY_SYSTEM_NONE"
2161
2200
  };
2162
- function Dn(e, t) {
2201
+ function An(e, t) {
2163
2202
  return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
2164
2203
  }
2165
- var On = /* @__PURE__ */ new Set([
2204
+ var jn = /* @__PURE__ */ new Set([
2166
2205
  "INVALID_URN",
2167
2206
  "NOT_FOUND",
2168
2207
  "GEO_DENIED",
@@ -2183,7 +2222,7 @@ var On = /* @__PURE__ */ new Set([
2183
2222
  ended: "PLAYER_STATE_ENDED",
2184
2223
  error: "PLAYER_STATE_ERROR"
2185
2224
  };
2186
- function kn(e) {
2225
+ function Mn(e) {
2187
2226
  try {
2188
2227
  let t = new URL(e), [n, ...r] = t.hostname.split(".");
2189
2228
  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 +2230,8 @@ function kn(e) {
2191
2230
  return;
2192
2231
  }
2193
2232
  }
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) {
2233
+ var Nn = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), Pn = /* @__PURE__ */ new Set(), Y = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), Fn = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
2234
+ function In(e) {
2196
2235
  if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
2197
2236
  let t;
2198
2237
  try {
@@ -2201,19 +2240,19 @@ function Nn(e) {
2201
2240
  } catch {
2202
2241
  return;
2203
2242
  }
2204
- if (jn.has(t) && !Y.has(t)) {
2205
- Y.add(t), g(Mn(new URL(t).origin));
2243
+ if (Pn.has(t) && !Y.has(t)) {
2244
+ Y.add(t), _(Fn(new URL(t).origin));
2206
2245
  for (let e of X) e.noteCspBlocked();
2207
2246
  }
2208
2247
  }
2209
- function Pn(e, t) {
2210
- return g(t, e), { disabledReason: t };
2248
+ function Ln(e, t) {
2249
+ return _(t, e), { disabledReason: t };
2211
2250
  }
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 };
2251
+ function Rn(e, t, n) {
2252
+ if (n) return t && !Nn(t, n) && _(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
2214
2253
  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);
2254
+ if (t !== void 0) return Ln("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).");
2255
+ let r = Mn(e);
2217
2256
  if (r) return { endpoint: r };
2218
2257
  let i;
2219
2258
  try {
@@ -2221,9 +2260,9 @@ function Fn(e, t, n) {
2221
2260
  } catch {
2222
2261
  i = e;
2223
2262
  }
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).`);
2263
+ return Ln(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
2264
  }
2226
- var In = class {
2265
+ var zn = class {
2227
2266
  opts;
2228
2267
  url;
2229
2268
  cspKey;
@@ -2305,8 +2344,8 @@ var In = class {
2305
2344
  constructor(e) {
2306
2345
  this.opts = {
2307
2346
  ...e,
2308
- heartbeatMs: e.heartbeatMs ?? vn,
2309
- idleMs: e.idleMs ?? yn
2347
+ heartbeatMs: e.heartbeatMs ?? xn,
2348
+ idleMs: e.idleMs ?? Sn
2310
2349
  }, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
2311
2350
  try {
2312
2351
  let e = new URL(this.url);
@@ -2323,11 +2362,11 @@ var In = class {
2323
2362
  sdkVersion: this.opts.sdkVersion,
2324
2363
  ...this.opts.environment
2325
2364
  };
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());
2365
+ this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Tn), this.lastTickMs = this.now(), this.timer = setInterval(() => this.heartbeat(), this.opts.heartbeatMs), typeof window < "u" && window.addEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.addEventListener("visibilitychange", this.onVisibility), document.addEventListener("freeze", this.onFreeze), document.addEventListener("resume", this.onResume), this.cspKey && Pn.add(this.cspKey), document.addEventListener("securitypolicyviolation", In), X.add(this), this.noteCspBlocked(), this.onVisibility());
2327
2366
  }
2328
2367
  checkSuspension(e) {
2329
2368
  if (this.endedFlag || !this.opts.idleMs) return !1;
2330
- let t = Math.max(this.opts.idleMs, bn);
2369
+ let t = Math.max(this.opts.idleMs, Cn);
2331
2370
  return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
2332
2371
  }
2333
2372
  syncIdle(e) {
@@ -2350,12 +2389,12 @@ var In = class {
2350
2389
  let a = {
2351
2390
  fromState: J[e] ?? "PLAYER_STATE_UNSPECIFIED",
2352
2391
  toState: J[t] ?? "PLAYER_STATE_UNSPECIFIED",
2353
- presentation: Tn[this.presentation]
2392
+ presentation: On[this.presentation]
2354
2393
  }, o = this.causeOf(e, t, i);
2355
2394
  o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
2356
2395
  }
2357
2396
  seekInduced(e) {
2358
- return this.lastSeekMs >= 0 && e - this.lastSeekMs < wn;
2397
+ return this.lastSeekMs >= 0 && e - this.lastSeekMs < Dn;
2359
2398
  }
2360
2399
  causeOf(e, t, n) {
2361
2400
  if (t === "error") return "TRANSITION_CAUSE_ERROR";
@@ -2428,8 +2467,8 @@ var In = class {
2428
2467
  stageOf(e, t, n) {
2429
2468
  let r = n ?? "";
2430
2469
  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";
2470
+ if (e === "DRM_CLIENT" || e === "DRM_DEVICE_REVOKED") return "ERROR_STAGE_DRM";
2471
+ if (jn.has(e)) return "ERROR_STAGE_RESOLVE";
2433
2472
  let i = t ?? "";
2434
2473
  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
2474
  }
@@ -2476,14 +2515,14 @@ var In = class {
2476
2515
  if (this.lastRequestCount = g, _ > 0) {
2477
2516
  o.requestCountDelta = _;
2478
2517
  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));
2518
+ n.length > 0 && (o.requestTimeP50Ms = An(n, 50), o.requestTimeP95Ms = An(n, 95));
2480
2519
  }
2481
2520
  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
2521
  }
2483
2522
  maybeEmitMediaInfo(e) {
2484
2523
  if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
2485
2524
  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);
2525
+ e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = kn[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
2526
  let n = JSON.stringify(t);
2488
2527
  n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
2489
2528
  }
@@ -2503,7 +2542,7 @@ var In = class {
2503
2542
  let c = r?.positionMs ?? 0;
2504
2543
  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
2544
  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);
2545
+ l && this.lastStallMs > 0 && n - this.lastStallMs <= En && (i.abandonAfterStallMs = Math.max(q, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= En && (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
2546
  let u = r?.decodedFrames ?? this.lastDecoded;
2508
2547
  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
2548
  }
@@ -2523,13 +2562,13 @@ var In = class {
2523
2562
  };
2524
2563
  }
2525
2564
  noteCspBlocked() {
2526
- this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(Mn(new URL(this.url).origin)));
2565
+ this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(Fn(new URL(this.url).origin)));
2527
2566
  }
2528
2567
  cspBlocked() {
2529
2568
  return !!this.cspKey && Y.has(this.cspKey);
2530
2569
  }
2531
2570
  enqueue(e) {
2532
- if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > xn;) {
2571
+ if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > wn;) {
2533
2572
  let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
2534
2573
  this.pending.splice(e >= 0 ? e : 0, 1);
2535
2574
  }
@@ -2556,7 +2595,7 @@ var In = class {
2556
2595
  };
2557
2596
  //#endregion
2558
2597
  //#region src/core/environment.ts
2559
- function Ln() {
2598
+ function Bn() {
2560
2599
  if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
2561
2600
  let e;
2562
2601
  try {
@@ -2581,14 +2620,14 @@ function Ln() {
2581
2620
  integration: "INTEGRATION_KIND_IFRAME"
2582
2621
  };
2583
2622
  }
2584
- function Rn() {
2623
+ function Vn() {
2585
2624
  if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
2586
2625
  let e = navigator.userAgentData, t = e?.platform ?? "";
2587
2626
  if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
2588
2627
  let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
2589
2628
  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
2629
  }
2591
- function zn() {
2630
+ function Hn() {
2592
2631
  let e = typeof navigator < "u" ? navigator.connection : void 0;
2593
2632
  if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
2594
2633
  let t = {
@@ -2607,17 +2646,17 @@ function zn() {
2607
2646
  }
2608
2647
  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
2648
  }
2610
- function Bn(e) {
2611
- let t = Ln(), n = {
2612
- deviceClass: Rn(),
2649
+ function Un(e) {
2650
+ let t = Bn(), n = {
2651
+ deviceClass: Vn(),
2613
2652
  integration: t.integration,
2614
- ...zn()
2653
+ ...Hn()
2615
2654
  };
2616
2655
  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
2656
  let r = e.getBoundingClientRect?.();
2618
2657
  return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
2619
2658
  }
2620
- async function Vn() {
2659
+ async function Wn() {
2621
2660
  let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
2622
2661
  if (!e?.getHighEntropyValues) return {};
2623
2662
  try {
@@ -2629,7 +2668,7 @@ async function Vn() {
2629
2668
  }
2630
2669
  //#endregion
2631
2670
  //#region src/core/version.ts
2632
- var Hn = "2.20.0", Un = {
2671
+ var Gn = "2.21.0", Kn = {
2633
2672
  accent: "#E1B600",
2634
2673
  accentText: "#1B1C23",
2635
2674
  background: "#0e0f13",
@@ -2640,7 +2679,7 @@ var Hn = "2.20.0", Un = {
2640
2679
  border: "rgba(255, 255, 255, 0.1)",
2641
2680
  radius: "8px",
2642
2681
  fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
2643
- }, Wn = {
2682
+ }, qn = {
2644
2683
  accent: "--havik-accent",
2645
2684
  accentText: "--havik-accent-text",
2646
2685
  background: "--havik-bg",
@@ -2652,26 +2691,26 @@ var Hn = "2.20.0", Un = {
2652
2691
  radius: "--havik-radius",
2653
2692
  fontFamily: "--havik-font"
2654
2693
  };
2655
- function Gn(e, t) {
2694
+ function Jn(e, t) {
2656
2695
  let n = {
2657
- ...Un,
2696
+ ...Kn,
2658
2697
  ...t
2659
2698
  };
2660
- for (let t of Object.keys(Wn)) e.style.setProperty(Wn[t], n[t]);
2699
+ for (let t of Object.keys(qn)) e.style.setProperty(qn[t], n[t]);
2661
2700
  n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
2662
2701
  }
2663
2702
  //#endregion
2664
2703
  //#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) {
2704
+ var Z = "havik-player-styles", Yn = "\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", Xn = /* @__PURE__ */ new WeakMap();
2705
+ function Zn(e = document, t) {
2667
2706
  let n = e.querySelector(`style#${Z}`);
2668
- if (n && (!t || qn.get(n) === t)) return;
2707
+ if (n && (!t || Xn.get(n) === t)) return;
2669
2708
  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);
2709
+ r.id = Z, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = Yn, Xn.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
2671
2710
  }
2672
2711
  //#endregion
2673
2712
  //#region src/ui/icons.ts
2674
- var Yn = {
2713
+ var Qn = {
2675
2714
  play: "<path d=\"M8 5v14l11-7z\"/>",
2676
2715
  pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
2677
2716
  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 +2724,27 @@ var Yn = {
2685
2724
  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
2725
  };
2687
2726
  function Q(e) {
2688
- return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Yn[e]}</svg>`;
2727
+ return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Qn[e]}</svg>`;
2689
2728
  }
2690
2729
  //#endregion
2691
2730
  //#region src/ui/controls.ts
2692
- var Xn = 3e3, Zn = 250, Qn = /* @__PURE__ */ new Set([
2731
+ var $n = 3e3, er = 250, tr = /* @__PURE__ */ new Set([
2693
2732
  "GONE",
2694
2733
  "NOT_FOUND",
2695
2734
  "GEO_DENIED",
2696
2735
  "INVALID_URN",
2697
- "UNAUTHORIZED"
2736
+ "UNAUTHORIZED",
2737
+ "DRM_DEVICE_REVOKED"
2698
2738
  ]);
2699
- function $n(e) {
2739
+ function nr(e) {
2700
2740
  let t = "This match isn't available in your country";
2701
2741
  return e ? `${t} (${e})` : t;
2702
2742
  }
2703
- function er(e) {
2704
- return new tr(e);
2743
+ var rr = "This device can't play protected video";
2744
+ function ir(e) {
2745
+ return new ar(e);
2705
2746
  }
2706
- var tr = class {
2747
+ var ar = class {
2707
2748
  root;
2708
2749
  video;
2709
2750
  player;
@@ -2751,7 +2792,7 @@ var tr = class {
2751
2792
  scrubbing = !1;
2752
2793
  offFns = [];
2753
2794
  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");
2795
+ this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? $n, 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, Zn(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
2796
  let t = (e, t, n) => {
2756
2797
  let r = this.doc.createElement(e);
2757
2798
  if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
@@ -2837,7 +2878,7 @@ var tr = class {
2837
2878
  let t = this.surfaceWasHidden;
2838
2879
  this.tapTimer = setTimeout(() => {
2839
2880
  this.tapTimer = void 0, this.toggleBar(t);
2840
- }, Zn);
2881
+ }, er);
2841
2882
  }
2842
2883
  toggleBar(e) {
2843
2884
  e ? this.poke() : this.hideIfIdle();
@@ -2857,7 +2898,7 @@ var tr = class {
2857
2898
  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
2899
  }
2859
2900
  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;
2901
+ 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" ? nr(this.lastError.country) : this.lastError?.code === "DRM_DEVICE_REVOKED" ? rr : this.lastError?.message ?? "Playback unavailable" : this.errorMessage : null;
2861
2902
  }
2862
2903
  renderStatus(e) {
2863
2904
  let t = this.statusMessageFor(e);
@@ -2872,7 +2913,7 @@ var tr = class {
2872
2913
  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
2914
  } else {
2874
2915
  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)) {
2916
+ if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !tr.has(this.lastError.code)) {
2876
2917
  let e = this.doc.createElement("button");
2877
2918
  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
2919
  }
@@ -2913,7 +2954,7 @@ var tr = class {
2913
2954
  let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
2914
2955
  this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
2915
2956
  }
2916
- !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${nr(this.video.currentTime)} / ${nr(this.video.duration)}`);
2957
+ !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${or(this.video.currentTime)} / ${or(this.video.duration)}`);
2917
2958
  }
2918
2959
  syncLive() {
2919
2960
  let e = this.player.getStats(), t = e.isLive !== !1, n = this.player.state === "ended", r = !t && !this.streamEnded();
@@ -2963,17 +3004,17 @@ var tr = class {
2963
3004
  renderQualityMenu() {
2964
3005
  let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
2965
3006
  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)));
3007
+ for (let n of e) this.menu.append(this.menuItem(sr(n), t === n.index, () => this.player.setQuality(n.index)));
2967
3008
  }
2968
3009
  renderAudioMenu() {
2969
3010
  let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
2970
3011
  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)));
3012
+ for (let t of e) this.menu.append(this.menuItem(cr(t), t.default, () => this.player.setAudioTrack(t.id)));
2972
3013
  }
2973
3014
  renderCcMenu() {
2974
3015
  let e = this.player.getTextTracks(), t = this.doc.createElement("div");
2975
3016
  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)));
3017
+ for (let t of e) this.menu.append(this.menuItem(lr(t), !1, () => this.player.setTextTrack(t.id)));
2977
3018
  }
2978
3019
  onTracksChanged() {
2979
3020
  this.openMenu && this.renderMenu(this.openMenu);
@@ -3078,41 +3119,41 @@ var tr = class {
3078
3119
  this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
3079
3120
  }
3080
3121
  };
3081
- function nr(e) {
3122
+ function or(e) {
3082
3123
  (!Number.isFinite(e) || e < 0) && (e = 0);
3083
3124
  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
3125
  return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
3085
3126
  }
3086
- function rr(e) {
3127
+ function sr(e) {
3087
3128
  return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
3088
3129
  }
3089
- function ir(e) {
3130
+ function cr(e) {
3090
3131
  return e.name || e.lang || `Track ${e.id}`;
3091
3132
  }
3092
- function ar(e) {
3133
+ function lr(e) {
3093
3134
  return e.name || e.lang || `Track ${e.id}`;
3094
3135
  }
3095
3136
  //#endregion
3096
3137
  //#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) {
3138
+ var ur = 6e3, dr = 45e3, fr = 2e3, pr = 3, mr = 5e3, hr = 2e3, gr = 48e4, _r = "keySystemLicenseRequestFailed";
3139
+ function vr(e) {
3099
3140
  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);
3141
+ if (e.env !== void 0) return at(e.env);
3101
3142
  if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
3102
3143
  return e.baseUrl;
3103
3144
  }
3104
- async function hr(e) {
3145
+ async function yr(e) {
3105
3146
  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);
3147
+ let t = vr(e);
3107
3148
  if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
3108
3149
  if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
3109
- let r = new gr({
3150
+ let r = new br({
3110
3151
  ...e,
3111
3152
  baseUrl: t
3112
3153
  });
3113
3154
  return await r.start(), r;
3114
3155
  }
3115
- var gr = class {
3156
+ var br = class {
3116
3157
  opts;
3117
3158
  abort = new AbortController();
3118
3159
  listeners = {};
@@ -3169,7 +3210,7 @@ var gr = class {
3169
3210
  throw this.destroy(), e;
3170
3211
  }
3171
3212
  } catch (t) {
3172
- if (this.opts.waitForLive && t instanceof n && o(t.code)) {
3213
+ if (this.opts.waitForLive && t instanceof n && s(t.code)) {
3173
3214
  this.setState("waiting"), this.beginArming(e, t.liveStartsAtMs);
3174
3215
  return;
3175
3216
  }
@@ -3201,13 +3242,13 @@ var gr = class {
3201
3242
  });
3202
3243
  }
3203
3244
  armWithSse(e, t, r, i = !1) {
3204
- let a = !1, s = !1, c = new AbortController();
3245
+ let a = !1, o = !1, c = new AbortController();
3205
3246
  this.armFallbackCtrl = c, this.setState("waiting");
3206
3247
  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
3248
  setTimeout(() => {
3208
3249
  a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
3209
3250
  phase: i ? "unavailable" : "tooEarly",
3210
- retryInMs: sr,
3251
+ retryInMs: dr,
3211
3252
  attempt: 1,
3212
3253
  elapsedMs: 0,
3213
3254
  ...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
@@ -3224,7 +3265,7 @@ var gr = class {
3224
3265
  }
3225
3266
  }
3226
3267
  }, h = () => {
3227
- a || s || p() || (s = !0, y({
3268
+ a || o || p() || (o = !0, y({
3228
3269
  ...this.resolveOptions(),
3229
3270
  signal: c.signal,
3230
3271
  waitForLive: this.buildWaitConfig(e)
@@ -3234,7 +3275,7 @@ var gr = class {
3234
3275
  }, g = () => {
3235
3276
  a || p() || v(this.resolveOptions()).then((e) => m(e)).catch((e) => {
3236
3277
  if (!(a || p())) {
3237
- if (e instanceof n && o(e.code)) {
3278
+ if (e instanceof n && s(e.code)) {
3238
3279
  h();
3239
3280
  return;
3240
3281
  }
@@ -3246,13 +3287,13 @@ var gr = class {
3246
3287
  !a && !p() && h();
3247
3288
  }, e);
3248
3289
  };
3249
- _(or), this.armingSub = E({
3290
+ _(ur), this.armingSub = E({
3250
3291
  eventsBaseUrl: t,
3251
3292
  matchUrn: this.opts.matchUrn,
3252
3293
  credential: this.opts.credential,
3253
- onAlive: () => _(sr),
3294
+ onAlive: () => _(dr),
3254
3295
  onState: (e) => {
3255
- a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * cr);
3296
+ a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * fr);
3256
3297
  },
3257
3298
  onError: () => h()
3258
3299
  });
@@ -3272,10 +3313,10 @@ var gr = class {
3272
3313
  async onResolved(e, t) {
3273
3314
  if (this.destroyed || t !== this.loadGen) return;
3274
3315
  this._descriptor = e, this.endedHandled = !1, this._endedReason = null;
3275
- let n = await s(this.opts.credential);
3316
+ let n = await c(this.opts.credential);
3276
3317
  if (this.destroyed || t !== this.loadGen) return;
3277
3318
  this.setState("loading");
3278
- let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = lt(this.opts.video, (e) => {
3319
+ let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = ut(this.opts.video, (e) => {
3279
3320
  this._state !== "ended" && this._state !== "error" && this.setState(e);
3280
3321
  });
3281
3322
  if (await i.load(), this.destroyed || t !== this.loadGen) {
@@ -3297,19 +3338,19 @@ var gr = class {
3297
3338
  if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
3298
3339
  let i = e.analytics?.sid;
3299
3340
  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);
3341
+ let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = Rn(this.opts.baseUrl, a, e.analytics?.endpoint);
3301
3342
  if (!o) {
3302
3343
  s && setTimeout(() => {
3303
3344
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
3304
3345
  }, 0);
3305
3346
  return;
3306
3347
  }
3307
- let c = this.opts.video, l = new In({
3348
+ let c = this.opts.video, l = new zn({
3308
3349
  endpoint: o,
3309
3350
  sid: i,
3310
3351
  player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
3311
- sdkVersion: Hn,
3312
- environment: Bn(c),
3352
+ sdkVersion: Gn,
3353
+ environment: Un(c),
3313
3354
  idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
3314
3355
  onIdle: () => this.onAnalyticsIdle(t),
3315
3356
  onBlocked: (e) => setTimeout(() => {
@@ -3330,7 +3371,7 @@ var gr = class {
3330
3371
  let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
3331
3372
  c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
3332
3373
  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");
3374
+ }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), Wn().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
3334
3375
  }
3335
3376
  currentPresentation() {
3336
3377
  let e = this.opts.video;
@@ -3358,9 +3399,9 @@ var gr = class {
3358
3399
  freshLicenseUrl: () => this.refreshLicense()
3359
3400
  }, o = this.opts.engine ?? "auto";
3360
3401
  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);
3402
+ if (o === "hls") return new bn(a);
3403
+ 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);
3404
+ if (It()) return new bn(a);
3364
3405
  if (H(this.opts.video)) return new W(a);
3365
3406
  throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
3366
3407
  }
@@ -3423,7 +3464,7 @@ var gr = class {
3423
3464
  r = 0, i = !1;
3424
3465
  },
3425
3466
  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.`))));
3467
+ this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= pr && (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
3468
  }
3428
3469
  });
3429
3470
  }
@@ -3437,7 +3478,7 @@ var gr = class {
3437
3478
  return;
3438
3479
  }
3439
3480
  let e = this.hiddenAtMs;
3440
- this.hiddenAtMs = null, e != null && Date.now() - e >= ur && this.resyncLiveState();
3481
+ this.hiddenAtMs = null, e != null && Date.now() - e >= mr && this.resyncLiveState();
3441
3482
  }, this.onReturnPageShow = (e) => {
3442
3483
  e.persisted && this.resyncLiveState();
3443
3484
  }, document.addEventListener("visibilitychange", this.onReturnVisible), typeof window < "u" && window.addEventListener("pageshow", this.onReturnPageShow));
@@ -3469,7 +3510,7 @@ var gr = class {
3469
3510
  scheduleRejoin(e) {
3470
3511
  this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
3471
3512
  this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
3472
- }, Math.random() * cr));
3513
+ }, Math.random() * fr));
3473
3514
  }
3474
3515
  cancelRejoin() {
3475
3516
  this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
@@ -3493,7 +3534,7 @@ var gr = class {
3493
3534
  }
3494
3535
  t.controls = !1;
3495
3536
  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({
3537
+ r && r.insertBefore(n, t), n.appendChild(t), Jn(n, this.opts.theme), this.container = n, this.controlBar = ir({
3497
3538
  root: n,
3498
3539
  video: t,
3499
3540
  player: this,
@@ -3531,7 +3572,7 @@ var gr = class {
3531
3572
  }
3532
3573
  startStats() {
3533
3574
  this.stopStats();
3534
- let e = Math.max(500, this.opts.statsIntervalMs ?? dr);
3575
+ let e = Math.max(500, this.opts.statsIntervalMs ?? hr);
3535
3576
  this.statsTimer = setInterval(() => {
3536
3577
  if (!this.engine) return;
3537
3578
  let e = this.engine.getStats();
@@ -3542,14 +3583,14 @@ var gr = class {
3542
3583
  this.statsTimer && clearInterval(this.statsTimer), this.statsTimer = void 0;
3543
3584
  }
3544
3585
  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);
3586
+ return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== _r || e.error.httpStatus !== 403 || e.error.code !== "FORBIDDEN" || e.error.serverCode === "license_refused" ? !1 : K(this._descriptor?.drm?.widevine?.licenseUrl);
3546
3587
  }
3547
3588
  scheduleLicenseRefresh() {
3548
3589
  if (this.stopRefresh(), !this._descriptor?.drmEnabled) return;
3549
3590
  typeof document < "u" && this.engine?.name === "hls" && (this.onRefocus = () => {
3550
3591
  document.visibilityState !== "visible" || this.destroyed || K(this._descriptor?.drm?.widevine?.licenseUrl) && this.refreshLicense();
3551
3592
  }, document.addEventListener("visibilitychange", this.onRefocus));
3552
- let e = this.opts.licenseRefreshMs ?? fr;
3593
+ let e = this.opts.licenseRefreshMs ?? gr;
3553
3594
  e && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
3554
3595
  }
3555
3596
  stopRefresh() {
@@ -3569,7 +3610,7 @@ var gr = class {
3569
3610
  fairplay: r
3570
3611
  }), this._descriptor = t), n;
3571
3612
  } catch (e) {
3572
- e instanceof n && !o(e.code) && (this.stopRefresh(), this.destroyed || this.emit("warning", e));
3613
+ e instanceof n && !s(e.code) && (this.stopRefresh(), this.destroyed || this.emit("warning", e));
3573
3614
  return;
3574
3615
  } finally {
3575
3616
  this.refreshInFlight?.promise === t && (this.refreshInFlight = void 0);
@@ -3719,7 +3760,7 @@ function $(e) {
3719
3760
  }
3720
3761
  //#endregion
3721
3762
  //#region src/embed/host.ts
3722
- function _r(e) {
3763
+ function xr(e) {
3723
3764
  if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
3724
3765
  if (!e.src) throw Error("mountEmbed: opts.src is required");
3725
3766
  if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
@@ -3778,15 +3819,15 @@ function _r(e) {
3778
3819
  }
3779
3820
  //#endregion
3780
3821
  //#region src/embed/page.ts
3781
- var vr = /^[A-Za-z0-9:_.-]{1,128}$/;
3782
- function yr(e) {
3822
+ var Sr = /^[A-Za-z0-9:_.-]{1,128}$/;
3823
+ function Cr(e) {
3783
3824
  if (typeof e == "boolean") return e;
3784
3825
  if (typeof e == "object" && e) {
3785
3826
  let t = e.endpoint;
3786
3827
  return typeof t == "string" ? { endpoint: t } : {};
3787
3828
  }
3788
3829
  }
3789
- function br() {
3830
+ function wr() {
3790
3831
  let e = window.HAVIK_EMBED_CONFIG;
3791
3832
  if (e) return {
3792
3833
  baseUrl: e.baseUrl ?? "",
@@ -3796,7 +3837,7 @@ function br() {
3796
3837
  autoplay: e.autoplay ?? !0,
3797
3838
  muted: e.muted ?? !0,
3798
3839
  waitForLive: e.waitForLive ?? !0,
3799
- analytics: yr(e.analytics)
3840
+ analytics: Cr(e.analytics)
3800
3841
  };
3801
3842
  let t = new URLSearchParams(location.search);
3802
3843
  return {
@@ -3809,9 +3850,9 @@ function br() {
3809
3850
  waitForLive: !0
3810
3851
  };
3811
3852
  }
3812
- async function xr() {
3813
- let e = br();
3814
- Cr();
3853
+ async function Tr() {
3854
+ let e = wr();
3855
+ Dr();
3815
3856
  let t = document.createElement("video");
3816
3857
  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
3858
  let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
@@ -3867,12 +3908,12 @@ async function xr() {
3867
3908
  message: e.message,
3868
3909
  ...e.country === void 0 ? {} : { country: e.country }
3869
3910
  })), e.on("autoplayblocked", () => {
3870
- i({ type: "oddin:autoplayblocked" }), Sr(t, e);
3911
+ i({ type: "oddin:autoplayblocked" }), Er(t, e);
3871
3912
  });
3872
3913
  }, s = async (r) => {
3873
3914
  a?.destroy(), a = null;
3874
3915
  try {
3875
- let n = await hr({
3916
+ let n = await yr({
3876
3917
  video: t,
3877
3918
  baseUrl: e.baseUrl,
3878
3919
  matchUrn: r,
@@ -3935,7 +3976,7 @@ async function xr() {
3935
3976
  a?.retry();
3936
3977
  break;
3937
3978
  case "oddin:load":
3938
- typeof e.matchUrn == "string" && vr.test(e.matchUrn) && s(e.matchUrn);
3979
+ typeof e.matchUrn == "string" && Sr.test(e.matchUrn) && s(e.matchUrn);
3939
3980
  break;
3940
3981
  case "oddin:destroy": c();
3941
3982
  }
@@ -3947,18 +3988,18 @@ async function xr() {
3947
3988
  protocol: 1
3948
3989
  });
3949
3990
  }
3950
- function Sr(e, t) {
3991
+ function Er(e, t) {
3951
3992
  if (document.getElementById("havik-tap")) return;
3952
3993
  let n = document.createElement("button");
3953
3994
  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
3995
  n.remove(), t.play();
3955
3996
  }), document.body.appendChild(n);
3956
3997
  }
3957
- function Cr() {
3998
+ function Dr() {
3958
3999
  let e = document.createElement("style");
3959
4000
  e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
3960
4001
  }
3961
4002
  //#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 };
4003
+ export { Kn as ODDIN_THEME, n as PlaybackError, Jn as applyTheme, at as baseUrlForEnv, Tr as bootEmbed, Ee as clearDeviceId, Re as clearRememberedBandwidth, yr 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, xr as mountEmbed, fe as pollToLive, y as resolveStream, E as subscribeLiveState, S as videoFullscreenActive, we as watchStatus };
3963
4004
 
3964
4005
  //# sourceMappingURL=index.js.map