@oddin-gg/havik-player 2.19.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
@@ -7,8 +7,9 @@ var n = class extends Error {
7
7
  requestId;
8
8
  serverCode;
9
9
  liveStartsAtMs;
10
+ country;
10
11
  constructor(e, t, n, r) {
11
- super(n), this.name = "PlaybackError", this.code = e, this.httpStatus = t, this.retryAfterMs = r?.retryAfterMs, this.requestId = r?.requestId, this.serverCode = r?.serverCode, this.liveStartsAtMs = r?.liveStartsAtMs, r?.cause !== void 0 && (this.cause = r.cause);
12
+ super(n), this.name = "PlaybackError", this.code = e, this.httpStatus = t, this.retryAfterMs = r?.retryAfterMs, this.requestId = r?.requestId, this.serverCode = r?.serverCode, this.liveStartsAtMs = r?.liveStartsAtMs, this.country = r?.country, r?.cause !== void 0 && (this.cause = r.cause);
12
13
  }
13
14
  };
14
15
  function r(e) {
@@ -20,33 +21,52 @@ function r(e) {
20
21
  case 410: return "GONE";
21
22
  case 425: return "TOO_EARLY";
22
23
  case 429: return "RATE_LIMITED";
24
+ case 451: return "GEO_DENIED";
23
25
  case 503: return "UNAVAILABLE";
24
26
  default: return "INTERNAL";
25
27
  }
26
28
  }
27
29
  function i(e) {
28
- 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
+ }
29
46
  }
30
- var a = /* @__PURE__ */ new Set([
47
+ function a(e, t) {
48
+ return e === 401 ? "UNAUTHORIZED" : e === 403 ? t === "cdm_revoked" ? "DRM_DEVICE_REVOKED" : "FORBIDDEN" : "DRM_CLIENT";
49
+ }
50
+ var o = /* @__PURE__ */ new Set([
31
51
  "TOO_EARLY",
32
52
  "UNAVAILABLE",
33
53
  "RATE_LIMITED",
34
54
  "NETWORK"
35
55
  ]);
36
- function o(e) {
37
- return a.has(e);
56
+ function s(e) {
57
+ return o.has(e);
38
58
  }
39
59
  //#endregion
40
60
  //#region src/core/types.ts
41
- async function s(e) {
61
+ async function c(e) {
42
62
  let t = typeof e == "function" ? await e() : e;
43
63
  if (!t || !t.apiKey) throw Error("havik-player: credential is missing an apiKey");
44
64
  return t;
45
65
  }
46
- function c(e) {
66
+ function l(e) {
47
67
  return e === "live" || e === "ended" || e === "upcoming" || e === "pending" ? e : "upcoming";
48
68
  }
49
- function l(e) {
69
+ function u(e) {
50
70
  if (!Array.isArray(e)) return;
51
71
  let t = [];
52
72
  for (let n of e) {
@@ -58,11 +78,11 @@ function l(e) {
58
78
  name: r,
59
79
  isHome: n.isHome === !0
60
80
  };
61
- 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);
62
82
  }
63
83
  return t.length > 0 ? t : void 0;
64
84
  }
65
- function u(e) {
85
+ function d(e) {
66
86
  try {
67
87
  return new URL(e).protocol === "https:";
68
88
  } catch {
@@ -71,7 +91,7 @@ function u(e) {
71
91
  }
72
92
  //#endregion
73
93
  //#region src/core/http.ts
74
- function d(e, t) {
94
+ function f(e, t) {
75
95
  let r = e.replace(/\/+$/, ""), i;
76
96
  try {
77
97
  i = new URL(r + t);
@@ -81,15 +101,15 @@ function d(e, t) {
81
101
  if (i.protocol !== "https:" && i.protocol !== "http:") throw new n("INTERNAL", 0, `baseUrl must be http(s), got: ${JSON.stringify(e)}`);
82
102
  return i.toString();
83
103
  }
84
- function f(e) {
104
+ function p(e) {
85
105
  if (!e) return;
86
106
  let t = Number(e);
87
107
  if (Number.isFinite(t)) return Math.max(0, Math.round(t * 1e3));
88
108
  let n = Date.parse(e);
89
109
  if (!Number.isNaN(n)) return Math.max(0, n - Date.now());
90
110
  }
91
- async function p(e, t) {
92
- 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();
93
113
  if (t.apiHeaders) for (let [e, n] of Object.entries(t.apiHeaders)) i.has(e) || i.set(e, n);
94
114
  i.set("x-api-key", r.apiKey);
95
115
  try {
@@ -103,55 +123,55 @@ async function p(e, t) {
103
123
  mode: "cors"
104
124
  });
105
125
  } catch (e) {
106
- 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 });
107
127
  }
108
128
  }
109
- function m(e) {
129
+ function h(e) {
110
130
  return e instanceof Error ? e.message : String(e);
111
131
  }
112
132
  //#endregion
113
133
  //#region src/core/warnOnce.ts
114
- var h = /* @__PURE__ */ new Set();
115
- function g(e, t = e) {
116
- h.has(t) || (h.add(t), console.warn(`havik-player: ${e}`));
134
+ var g = /* @__PURE__ */ new Set();
135
+ function _(e, t = e) {
136
+ g.has(t) || (g.add(t), console.warn(`havik-player: ${e}`));
117
137
  }
118
138
  //#endregion
119
139
  //#region src/core/waitForLive.ts
120
- var _ = 1e3, ee = 3e4, te = 6e5, ne = 3e5, re = 1e3, ie = {
140
+ var ee = 1e3, te = 3e4, ne = 6e5, re = 3e5, ie = 1e3, ae = {
121
141
  TOO_EARLY: "tooEarly",
122
142
  UNAVAILABLE: "unavailable",
123
143
  RATE_LIMITED: "rateLimited",
124
144
  NETWORK: "network"
125
145
  };
126
- function ae(e) {
127
- let t = e === !0 || e === !1 ? {} : e, n = Math.max(re, t.floorMs ?? _), r = Math.max(n, t.ceilMs ?? ee), i = Math.max(0, t.imminentMs ?? te), a = Math.max(r, t.sanityFloorMs ?? ne);
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);
128
148
  return {
129
149
  timeoutMs: t.timeoutMs,
130
150
  floorMs: n,
131
151
  ceilMs: r,
132
152
  imminentMs: i,
133
153
  sanityFloorMs: a,
134
- kickoffMs: oe(t.kickoffAt),
154
+ kickoffMs: se(t.kickoffAt),
135
155
  jitter: t.jitter ?? !0,
136
156
  onState: t.onState
137
157
  };
138
158
  }
139
- function oe(e) {
159
+ function se(e) {
140
160
  if (e == null) return;
141
161
  if (typeof e == "number") return Number.isFinite(e) ? e : void 0;
142
162
  let t = Date.parse(e);
143
163
  return Number.isFinite(t) ? t : void 0;
144
164
  }
145
- function se(e, t, n) {
165
+ function ce(e, t, n) {
146
166
  return Math.min(n, Math.max(t, e));
147
167
  }
148
- function ce(e) {
168
+ function le(e) {
149
169
  return Math.round(e * (1 + .15 * Math.random()));
150
170
  }
151
- function le(e, t, n, r) {
171
+ function ue(e, t, n, r) {
152
172
  let i = r ?? n.kickoffMs, a = i == null ? void 0 : Math.max(0, i - t), o = Math.max(n.floorMs, e ?? 0);
153
173
  if (a == null || a <= n.imminentMs) return {
154
- delay: se(e ?? n.floorMs, o, n.ceilMs),
174
+ delay: ce(e ?? n.floorMs, o, n.ceilMs),
155
175
  ttkMs: a
156
176
  };
157
177
  let s = Math.min(Math.floor(a / 10), n.sanityFloorMs, a);
@@ -160,7 +180,7 @@ function le(e, t, n, r) {
160
180
  ttkMs: a
161
181
  };
162
182
  }
163
- function ue(e, t) {
183
+ function de(e, t) {
164
184
  return new Promise((r, i) => {
165
185
  if (t?.aborted) {
166
186
  i(new n("ABORTED", 0, "wait-for-live aborted"));
@@ -174,27 +194,27 @@ function ue(e, t) {
174
194
  t?.addEventListener("abort", a, { once: !0 });
175
195
  });
176
196
  }
177
- async function de(e, t, r) {
178
- let i = ae(t), a = Date.now(), s = i.timeoutMs == null ? Infinity : a + i.timeoutMs, c = 0, l;
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;
179
199
  for (;;) {
180
200
  if (r?.aborted) throw new n("ABORTED", 0, "wait-for-live aborted");
181
201
  try {
182
202
  return await e();
183
203
  } catch (e) {
184
- if (!(e instanceof n) || !o(e.code)) throw e;
204
+ if (!(e instanceof n) || !s(e.code)) throw e;
185
205
  c += 1, e.liveStartsAtMs != null && Number.isFinite(e.liveStartsAtMs) && (l = e.liveStartsAtMs);
186
- let t = Date.now(), u = le(e.retryAfterMs, t, i, l), d = u.ttkMs, f = u.delay;
187
- if (i.jitter && (f = ce(f)), t + f > s) throw new n("TIMEOUT", e.httpStatus, `timed out after ${i.timeoutMs}ms waiting for the stream to go live`, {
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`, {
188
208
  retryAfterMs: e.retryAfterMs,
189
209
  cause: e
190
210
  });
191
211
  i.onState?.({
192
- phase: ie[e.code] ?? "unavailable",
212
+ phase: ae[e.code] ?? "unavailable",
193
213
  retryInMs: f,
194
214
  attempt: c,
195
215
  elapsedMs: t - a,
196
216
  ttkMs: d
197
- }), await ue(f, r);
217
+ }), await de(f, r);
198
218
  }
199
219
  }
200
220
  }
@@ -202,35 +222,37 @@ async function de(e, t, r) {
202
222
  //#region src/core/resolve.ts
203
223
  async function v(e) {
204
224
  if (!e.matchUrn || typeof e.matchUrn != "string") throw new n("INVALID_URN", 0, "resolveStream: a non-empty matchUrn is required");
205
- 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)}`), {
206
226
  credential: e.credential,
207
227
  signal: e.signal,
208
228
  apiHeaders: e.apiHeaders
209
229
  });
210
- if (!t.ok) throw await fe(t);
211
- return he(await t.json(), e.matchUrn);
230
+ if (!t.ok) throw await pe(t);
231
+ return ge(await t.json(), e.matchUrn);
212
232
  }
213
233
  function y(e) {
214
234
  let t = () => v(e);
215
- return e.waitForLive ? de(t, e.waitForLive, e.signal) : t();
235
+ return e.waitForLive ? fe(t, e.waitForLive, e.signal) : t();
216
236
  }
217
- async function fe(e) {
218
- let t = f(e.headers.get("retry-after")), i = e.headers.get("x-request-id") ?? e.headers.get("x-amzn-requestid") ?? void 0, a = e.statusText || `HTTP ${e.status}`, o, s;
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;
219
239
  try {
220
240
  let t = await e.json();
221
241
  if (t?.error?.message && (a = t.error.message), t?.error?.code && (o = t.error.code), typeof t?.liveStartsAt == "string") {
222
242
  let e = Date.parse(t.liveStartsAt);
223
243
  Number.isFinite(e) && (s = e);
224
244
  }
245
+ e.status === 451 && typeof t?.country == "string" && /^[A-Z]{2}$/.test(t.country) && (c = t.country);
225
246
  } catch {}
226
247
  return new n(r(e.status), e.status, a, {
227
248
  retryAfterMs: t,
228
249
  requestId: i,
229
250
  serverCode: o,
230
- liveStartsAtMs: s
251
+ liveStartsAtMs: s,
252
+ country: c
231
253
  });
232
254
  }
233
- var pe = /* @__PURE__ */ new Set([
255
+ var me = /* @__PURE__ */ new Set([
234
256
  "matchUrn",
235
257
  "protocol",
236
258
  "drmEnabled",
@@ -251,16 +273,16 @@ function b(e, t) {
251
273
  if (r.protocol !== "https:" && r.protocol !== "http:") throw new n("INTERNAL", 0, `playback ${e} has a disallowed scheme: ${r.protocol}`);
252
274
  return t;
253
275
  }
254
- function me(e) {
276
+ function he(e) {
255
277
  if (e !== void 0) {
256
278
  if (typeof e == "string" && !e.endsWith("/")) try {
257
279
  let t = new URL(e);
258
280
  if (t.protocol === "https:" && t.href === `${t.origin}/`) return t.origin;
259
281
  } catch {}
260
- 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.`);
261
283
  }
262
284
  }
263
- function he(e, t) {
285
+ function ge(e, t) {
264
286
  if (!e.manifestUrl) throw new n("INTERNAL", 0, "playback response is missing manifestUrl");
265
287
  let r = e.drmEnabled ?? !!e.drm, i = {
266
288
  matchUrn: e.matchUrn ?? t,
@@ -271,7 +293,7 @@ function he(e, t) {
271
293
  };
272
294
  if (e.liveStartsAt && (i.liveStartsAt = e.liveStartsAt), typeof e.analytics?.sid == "string" && e.analytics.sid) {
273
295
  i.analytics = { sid: e.analytics.sid };
274
- let t = me(e.analytics.endpoint);
296
+ let t = he(e.analytics.endpoint);
275
297
  t && (i.analytics.endpoint = t);
276
298
  }
277
299
  if (r && e.drm) {
@@ -282,7 +304,7 @@ function he(e, t) {
282
304
  }), (t.widevine || t.fairplay) && (i.drm = t);
283
305
  }
284
306
  let a = {};
285
- 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);
286
308
  return Object.keys(a).length > 0 && (i.extensions = a), i;
287
309
  }
288
310
  //#endregion
@@ -290,11 +312,11 @@ function he(e, t) {
290
312
  function x(e) {
291
313
  return e.ownerDocument ?? document;
292
314
  }
293
- function ge(e) {
315
+ function _e(e) {
294
316
  return e.fullscreenElement ?? e.webkitFullscreenElement ?? null;
295
317
  }
296
318
  function S(e, t) {
297
- let n = ge(x(e));
319
+ let n = _e(x(e));
298
320
  return n != null && (n === e || t != null && n === t) || e.webkitDisplayingFullscreen === !0;
299
321
  }
300
322
  function C(e, t) {
@@ -317,17 +339,17 @@ async function T(e, t) {
317
339
  n.webkitExitFullscreen?.();
318
340
  return;
319
341
  }
320
- let r = x(e), i = ge(r);
342
+ let r = x(e), i = _e(r);
321
343
  i != null && (i === e || t != null && i === t) && (typeof r.exitFullscreen == "function" ? await r.exitFullscreen() : r.webkitExitFullscreen?.());
322
344
  }
323
345
  //#endregion
324
346
  //#region src/core/catalog.ts
325
- async function _e(e) {
347
+ async function ve(e) {
326
348
  let t = new URLSearchParams();
327
349
  e.status && t.set("status", Array.isArray(e.status) ? e.status.join(",") : e.status), e.sport && t.set("sport", e.sport);
328
- 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();
329
351
  e.etag && o.set("If-None-Match", e.etag);
330
- let s = await p(a, {
352
+ let s = await m(a, {
331
353
  credential: e.credential,
332
354
  signal: e.signal,
333
355
  headers: o,
@@ -340,12 +362,12 @@ async function _e(e) {
340
362
  };
341
363
  if (!s.ok) throw new n(r(s.status), s.status, `catalog request failed (HTTP ${s.status})`);
342
364
  return {
343
- tournaments: ve(await s.json()),
365
+ tournaments: ye(await s.json()),
344
366
  etag: s.headers.get("etag") ?? void 0,
345
367
  notModified: !1
346
368
  };
347
369
  }
348
- function ve(e) {
370
+ function ye(e) {
349
371
  return (e.tournaments ?? []).map((e) => {
350
372
  let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
351
373
  return {
@@ -356,21 +378,21 @@ function ve(e) {
356
378
  matches: (e.matches ?? []).map((e) => ({
357
379
  matchUrn: e.matchUrn ?? "",
358
380
  matchName: e.matchName ?? "",
359
- status: c(e.status),
381
+ status: l(e.status),
360
382
  statusRaw: e.status,
361
383
  datePlannedStart: e.datePlannedStart,
362
384
  tournamentUrn: t,
363
385
  tournamentName: n,
364
386
  sport: r,
365
- teams: l(e.teams)
387
+ teams: u(e.teams)
366
388
  }))
367
389
  };
368
390
  });
369
391
  }
370
- async function ye(e) {
371
- 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();
372
394
  e.etag && i.set("If-None-Match", e.etag);
373
- let a = await p(t, {
395
+ let a = await m(t, {
374
396
  credential: e.credential,
375
397
  signal: e.signal,
376
398
  headers: i,
@@ -387,13 +409,13 @@ async function ye(e) {
387
409
  };
388
410
  if (!a.ok) throw new n(r(a.status), a.status, `tournament request failed (HTTP ${a.status})`);
389
411
  return {
390
- tournament: be(await a.json()),
412
+ tournament: xe(await a.json()),
391
413
  etag: a.headers.get("etag") ?? void 0,
392
414
  notModified: !1,
393
415
  notFound: !1
394
416
  };
395
417
  }
396
- function be(e) {
418
+ function xe(e) {
397
419
  let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
398
420
  return {
399
421
  urn: t,
@@ -403,43 +425,44 @@ function be(e) {
403
425
  matches: (e.matches ?? []).map((e) => ({
404
426
  matchUrn: e.matchUrn ?? "",
405
427
  matchName: e.matchName ?? "",
406
- status: c(e.status),
428
+ status: l(e.status),
407
429
  statusRaw: e.status,
408
430
  datePlannedStart: e.datePlannedStart,
409
431
  tournamentUrn: t,
410
432
  tournamentName: n,
411
433
  sport: r,
412
- teams: l(e.teams)
434
+ teams: u(e.teams)
413
435
  }))
414
436
  };
415
437
  }
416
- function xe(e) {
438
+ function Se(e) {
417
439
  return e.tournaments.flatMap((e) => e.matches);
418
440
  }
419
441
  //#endregion
420
442
  //#region src/core/poll.ts
421
- var Se = /* @__PURE__ */ new Set([
443
+ var Ce = /* @__PURE__ */ new Set([
422
444
  "NOT_FOUND",
445
+ "GEO_DENIED",
423
446
  "GONE",
424
447
  "INVALID_URN"
425
448
  ]);
426
- function Ce(e) {
427
- let t = Math.max(2e3, e.intervalMs ?? 1e4), i = new AbortController(), a, o, s, u = !1, f = () => {
428
- u || (a = setTimeout(m, t));
429
- }, 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 () => {
430
453
  try {
431
- 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();
432
455
  o && a.set("If-None-Match", o);
433
- let u = await p(t, {
456
+ let c = await m(t, {
434
457
  credential: e.credential,
435
458
  signal: i.signal,
436
459
  headers: a,
437
460
  apiHeaders: e.apiHeaders
438
461
  });
439
- if (u.status !== 304) {
440
- if (!u.ok) throw new n(r(u.status), u.status, `match status request failed (HTTP ${u.status})`);
441
- o = u.headers.get("etag") ?? o;
442
- 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([
443
466
  a,
444
467
  t.datePlannedStart ?? null,
445
468
  d ?? null
@@ -456,21 +479,21 @@ function Ce(e) {
456
479
  } catch (t) {
457
480
  if (!i.signal.aborted) {
458
481
  let r = t instanceof n ? t : new n("NETWORK", 0, String(t));
459
- Se.has(r.code) && (u = !0), e.onError?.(r);
482
+ Ce.has(r.code) && (c = !0), e.onError?.(r);
460
483
  }
461
484
  } finally {
462
- f();
485
+ d();
463
486
  }
464
487
  };
465
- return m(), { stop() {
466
- u = !0, i.abort(), a && clearTimeout(a);
488
+ return p(), { stop() {
489
+ c = !0, i.abort(), a && clearTimeout(a);
467
490
  } };
468
491
  }
469
492
  //#endregion
470
493
  //#region src/core/events.ts
471
- var we = 45e3;
494
+ var Te = 45e3;
472
495
  function E(e) {
473
- 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) => {
474
497
  if (a.signal.aborted) return t();
475
498
  let n = setTimeout(t, e);
476
499
  a.signal.addEventListener("abort", () => {
@@ -490,7 +513,7 @@ function E(e) {
490
513
  let t = JSON.parse(r.join("\n"));
491
514
  t && typeof t.state == "string" && e.onState(t);
492
515
  } catch {}
493
- }, 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) => {
494
517
  let r = e.getReader(), a = new TextDecoder(), s = "", c = !1, d, f = () => {
495
518
  i && (clearTimeout(d), d = setTimeout(() => {
496
519
  n(), r.cancel().catch(() => {});
@@ -518,13 +541,13 @@ function E(e) {
518
541
  p = `no data for ${i}ms`, l.abort();
519
542
  };
520
543
  try {
521
- let n = await s(e.credential);
544
+ let n = await c(e.credential);
522
545
  if (o) return;
523
- let a = d(e.eventsBaseUrl, `/v1/events/${encodeURIComponent(e.matchUrn)}`);
546
+ let a = f(e.eventsBaseUrl, `/v1/events/${encodeURIComponent(e.matchUrn)}`);
524
547
  i && (m = setTimeout(() => {
525
548
  p = `no response headers within ${i}ms`, l.abort();
526
549
  }, i));
527
- let c = await fetch(a, {
550
+ let s = await fetch(a, {
528
551
  method: "GET",
529
552
  headers: {
530
553
  "x-api-key": n.apiKey,
@@ -536,7 +559,7 @@ function E(e) {
536
559
  mode: "cors"
537
560
  });
538
561
  if (clearTimeout(m), o) return;
539
- !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, () => {
540
563
  r = t;
541
564
  }, h);
542
565
  } catch (t) {
@@ -546,7 +569,7 @@ function E(e) {
546
569
  clearTimeout(m), a.signal.removeEventListener("abort", u), l.abort();
547
570
  }
548
571
  if (o) return;
549
- 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);
550
573
  }
551
574
  })(), { close() {
552
575
  o || (o = !0, a.abort());
@@ -569,20 +592,20 @@ function A() {
569
592
  let e = globalThis.localStorage?.getItem(O);
570
593
  if (e) return k = e, e;
571
594
  } catch {}
572
- let e = Ee();
595
+ let e = De();
573
596
  k = e;
574
597
  try {
575
598
  globalThis.localStorage?.setItem(O, e);
576
599
  } catch {}
577
600
  return e;
578
601
  }
579
- function Te() {
602
+ function Ee() {
580
603
  k = void 0;
581
604
  try {
582
605
  globalThis.localStorage?.removeItem(O);
583
606
  } catch {}
584
607
  }
585
- function Ee() {
608
+ function De() {
586
609
  let e = globalThis.crypto;
587
610
  if (e && typeof e.randomUUID == "function") return e.randomUUID();
588
611
  let t = /* @__PURE__ */ new Uint8Array(16);
@@ -594,7 +617,7 @@ function Ee() {
594
617
  }
595
618
  //#endregion
596
619
  //#region src/core/drm/headers.ts
597
- function De(e, t, n = {}) {
620
+ function Oe(e, t, n = {}) {
598
621
  let r = {
599
622
  "x-api-key": t.apiKey,
600
623
  "X-Match-Urn": e.matchUrn,
@@ -605,19 +628,19 @@ function De(e, t, n = {}) {
605
628
  }
606
629
  //#endregion
607
630
  //#region src/core/bandwidthMemory.ts
608
- var j = "havik.player.bandwidth", Oe = .8, ke = 2e7, Ae = 3e5;
609
- function M() {
631
+ var j = "havik.player.bandwidth", ke = .8, Ae = 2e7, je = 3e5;
632
+ function Me() {
610
633
  return globalThis.navigator?.connection;
611
634
  }
612
- function je() {
613
- let e = M()?.type;
635
+ function Ne() {
636
+ let e = Me()?.type;
614
637
  return typeof e == "string" && e !== "" && e !== "unknown" ? e : "any";
615
638
  }
616
- function Me() {
617
- let e = M()?.downlink;
639
+ function Pe() {
640
+ let e = Me()?.downlink;
618
641
  return typeof e == "number" && Number.isFinite(e) && e > 0 ? e * 1e6 : void 0;
619
642
  }
620
- function Ne() {
643
+ function Fe() {
621
644
  try {
622
645
  let e = globalThis.localStorage?.getItem(j);
623
646
  if (!e) return {};
@@ -627,18 +650,18 @@ function Ne() {
627
650
  return {};
628
651
  }
629
652
  }
630
- function Pe(e = Date.now()) {
631
- let t = Ne()[je()];
653
+ function Ie(e = Date.now()) {
654
+ let t = Fe()[Ne()];
632
655
  if (!t || typeof t.bps != "number" || typeof t.at != "number" || !Number.isFinite(t.bps) || t.bps <= 0) return;
633
656
  let n = e - t.at;
634
657
  if (n < 0 || n > 2592e5) return;
635
- let r = Me(), i = r === void 0 ? t.bps : Math.min(t.bps, r);
636
- 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)));
637
660
  }
638
- function Fe(e, t = Date.now()) {
661
+ function Le(e, t = Date.now()) {
639
662
  if (!Number.isFinite(e) || e <= 0) return;
640
- let n = Ne();
641
- n[je()] = {
663
+ let n = Fe();
664
+ n[Ne()] = {
642
665
  bps: Math.round(e),
643
666
  at: t
644
667
  };
@@ -646,17 +669,17 @@ function Fe(e, t = Date.now()) {
646
669
  globalThis.localStorage?.setItem(j, JSON.stringify(n));
647
670
  } catch {}
648
671
  }
649
- function Ie() {
672
+ function Re() {
650
673
  try {
651
674
  globalThis.localStorage?.removeItem(j);
652
675
  } catch {}
653
676
  }
654
677
  //#endregion
655
678
  //#region src/core/drm/cdm.ts
656
- var Le = /* @__PURE__ */ new WeakMap();
657
- function Re(e, t) {
658
- let n = Le.get(e);
659
- n || (n = /* @__PURE__ */ new Map(), Le.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));
660
683
  let r = n.get(t.keySystem);
661
684
  if (r) return r;
662
685
  let i = t.createMediaKeys().catch((e) => {
@@ -664,22 +687,22 @@ function Re(e, t) {
664
687
  });
665
688
  return n.set(t.keySystem, i), i;
666
689
  }
667
- function N() {
690
+ function M() {
668
691
  return typeof navigator < "u" && typeof navigator.requestMediaKeySystemAccess == "function";
669
692
  }
670
- var P = ["SW_SECURE_DECODE", "SW_SECURE_CRYPTO"];
671
- function ze(e) {
693
+ var N = ["SW_SECURE_DECODE", "SW_SECURE_CRYPTO"];
694
+ function Ve(e) {
672
695
  return e.startsWith("com.widevine");
673
696
  }
674
- function F(e, t) {
675
- if (!ze(e)) return t;
697
+ function P(e, t) {
698
+ if (!Ve(e)) return t;
676
699
  let n = (e, t) => {
677
700
  let n = e.videoCapabilities;
678
701
  return !n?.length || !n.some((e) => e.robustness) ? !1 : n.every((e) => {
679
- let n = P.indexOf(e.robustness);
680
- return n === -1 || P.indexOf(t) > n;
702
+ let n = N.indexOf(e.robustness);
703
+ return n === -1 || N.indexOf(t) > n;
681
704
  });
682
- }, r = P.flatMap((e) => t.filter((t) => n(t, e)).map((t) => ({
705
+ }, r = N.flatMap((e) => t.filter((t) => n(t, e)).map((t) => ({
683
706
  ...t,
684
707
  videoCapabilities: t.videoCapabilities?.map((t) => ({
685
708
  ...t,
@@ -688,53 +711,53 @@ function F(e, t) {
688
711
  })));
689
712
  return [...t, ...r];
690
713
  }
691
- function Be(e) {
692
- return (t, n) => N() ? navigator.requestMediaKeySystemAccess(t, F(t, n)).then((t) => ({
714
+ function He(e) {
715
+ return (t, n) => M() ? navigator.requestMediaKeySystemAccess(t, P(t, n)).then((t) => ({
693
716
  keySystem: t.keySystem,
694
717
  getConfiguration: () => t.getConfiguration(),
695
- createMediaKeys: () => Re(e, t)
718
+ createMediaKeys: () => Be(e, t)
696
719
  })) : Promise.reject(/* @__PURE__ */ Error("navigator.requestMediaKeySystemAccess is unavailable — EME needs a secure context (https, or localhost)"));
697
720
  }
698
- var I = {
721
+ var F = {
699
722
  video: "SW_SECURE_DECODE",
700
723
  audio: "SW_SECURE_CRYPTO",
701
724
  scheme: "cbcs"
702
725
  };
703
- function Ve(e) {
704
- if (!N()) return;
726
+ function Ue(e) {
727
+ if (!M()) return;
705
728
  let t = (e, t) => ({
706
729
  contentType: e,
707
730
  robustness: t,
708
- encryptionScheme: I.scheme
731
+ encryptionScheme: F.scheme
709
732
  });
710
- Be(e)("com.widevine.alpha", [{
733
+ He(e)("com.widevine.alpha", [{
711
734
  initDataTypes: ["cenc"],
712
735
  distinctiveIdentifier: "optional",
713
736
  persistentState: "optional",
714
737
  sessionTypes: ["temporary"],
715
- audioCapabilities: [t("audio/mp4; codecs=\"mp4a.40.2\"", I.audio)],
716
- videoCapabilities: [t("video/mp4; codecs=\"avc1.42e01e\"", I.video)]
738
+ audioCapabilities: [t("audio/mp4; codecs=\"mp4a.40.2\"", F.audio)],
739
+ videoCapabilities: [t("video/mp4; codecs=\"avc1.42e01e\"", F.video)]
717
740
  }]).then((e) => e.createMediaKeys()).catch(() => {});
718
741
  }
719
- function L(e) {
720
- let t = R(e);
742
+ function I(e) {
743
+ let t = L(e);
721
744
  if (/^avc[13]/.test(t)) return "avc";
722
745
  if (/^(hvc1|hev1)/.test(t)) return "hevc";
723
746
  if (/^(dvh1|dvhe)/.test(t)) return "dv";
724
747
  if (t.startsWith("av01")) return "av1";
725
748
  if (/^vp0?9/.test(t)) return "vp9";
726
749
  }
727
- function R(e) {
750
+ function L(e) {
728
751
  return (e ?? "").trim().toLowerCase();
729
752
  }
730
- var He = {
753
+ var We = {
731
754
  hevc: "hvc1.1.6.L93.90",
732
755
  dv: "dvh1.05.06",
733
756
  av1: "av01.0.05M.08",
734
757
  vp9: "vp09.00.10.08"
735
- }, Ue = /* @__PURE__ */ new Map(), z = /* @__PURE__ */ new Map();
736
- function We(e) {
737
- let t = R(e), n = Ue.get(t);
758
+ }, Ge = /* @__PURE__ */ new Map(), R = /* @__PURE__ */ new Map();
759
+ function Ke(e) {
760
+ let t = L(e), n = Ge.get(t);
738
761
  if (n) return n;
739
762
  let r = {
740
763
  initDataTypes: ["cenc"],
@@ -743,32 +766,32 @@ function We(e) {
743
766
  sessionTypes: ["temporary"],
744
767
  videoCapabilities: [{
745
768
  contentType: `video/mp4; codecs="${e.trim()}"`,
746
- robustness: I.video,
747
- encryptionScheme: I.scheme
769
+ robustness: F.video,
770
+ encryptionScheme: F.scheme
748
771
  }]
749
772
  }, i = (async () => {
750
773
  try {
751
- return await navigator.requestMediaKeySystemAccess("com.widevine.alpha", F("com.widevine.alpha", [r])), !0;
774
+ return await navigator.requestMediaKeySystemAccess("com.widevine.alpha", P("com.widevine.alpha", [r])), !0;
752
775
  } catch {
753
776
  return !1;
754
777
  }
755
- })().then((e) => (z.set(t, e), e));
756
- return Ue.set(t, i), i;
778
+ })().then((e) => (R.set(t, e), e));
779
+ return Ge.set(t, i), i;
757
780
  }
758
- function Ge() {
759
- if (N()) for (let e of Object.values(He)) We(e);
781
+ function qe() {
782
+ if (M()) for (let e of Object.values(We)) Ke(e);
760
783
  }
761
- function Ke(e) {
762
- let t = L(e);
763
- if (t) return t === "avc" ? !0 : z.get(R(e)) ?? z.get(R(He[t]));
784
+ function Je(e) {
785
+ let t = I(e);
786
+ if (t) return t === "avc" ? !0 : R.get(L(e)) ?? R.get(L(We[t]));
764
787
  }
765
788
  //#endregion
766
789
  //#region src/core/drm/support.ts
767
- var qe = 5e3, Je = "video/mp4; codecs=\"avc1.42E01E\"", Ye = "audio/mp4; codecs=\"mp4a.40.2\"", Xe = {
790
+ var Ye = 5e3, Xe = "video/mp4; codecs=\"avc1.42E01E\"", Ze = "audio/mp4; codecs=\"mp4a.40.2\"", Qe = {
768
791
  widevine: ["com.widevine.alpha"],
769
792
  fairplay: ["com.apple.fps"]
770
793
  };
771
- function Ze(e) {
794
+ function $e(e) {
772
795
  return e === "fairplay" ? [{
773
796
  initDataTypes: [
774
797
  "sinf",
@@ -776,30 +799,30 @@ function Ze(e) {
776
799
  "cenc"
777
800
  ],
778
801
  videoCapabilities: [{
779
- contentType: Je,
802
+ contentType: Xe,
780
803
  robustness: "",
781
804
  encryptionScheme: "cbcs"
782
805
  }],
783
806
  audioCapabilities: [{
784
- contentType: Ye,
807
+ contentType: Ze,
785
808
  robustness: "",
786
809
  encryptionScheme: "cbcs"
787
810
  }]
788
- }] : F("com.widevine.alpha", [{
811
+ }] : P("com.widevine.alpha", [{
789
812
  initDataTypes: ["cenc"],
790
813
  videoCapabilities: [{
791
- contentType: Je,
792
- robustness: I.video,
793
- encryptionScheme: I.scheme
814
+ contentType: Xe,
815
+ robustness: F.video,
816
+ encryptionScheme: F.scheme
794
817
  }],
795
818
  audioCapabilities: [{
796
- contentType: Ye,
797
- robustness: I.audio,
798
- encryptionScheme: I.scheme
819
+ contentType: Ze,
820
+ robustness: F.audio,
821
+ encryptionScheme: F.scheme
799
822
  }]
800
823
  }]);
801
824
  }
802
- function Qe(e, t) {
825
+ function et(e, t) {
803
826
  return new Promise((n, r) => {
804
827
  let i = setTimeout(() => r(/* @__PURE__ */ Error("probe-timeout")), t);
805
828
  e.then((e) => {
@@ -809,8 +832,8 @@ function Qe(e, t) {
809
832
  });
810
833
  });
811
834
  }
812
- async function $e(e = {}) {
813
- let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? qe, r = {};
835
+ async function tt(e = {}) {
836
+ let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Ye, r = {};
814
837
  if (typeof window < "u" && window.isSecureContext === !1) return {
815
838
  verdict: "insecure-context",
816
839
  detail: r
@@ -822,7 +845,7 @@ async function $e(e = {}) {
822
845
  };
823
846
  let a = !1, o = !1, s = Date.now() + n, c = () => Math.max(1, s - Date.now());
824
847
  for (let e of t) {
825
- let t = Xe[e];
848
+ let t = Qe[e];
826
849
  if (!t) {
827
850
  r[e] = "unknown system";
828
851
  continue;
@@ -833,7 +856,7 @@ async function $e(e = {}) {
833
856
  break;
834
857
  }
835
858
  try {
836
- return await Qe((await Qe(i(n, Ze(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})`, {
837
860
  verdict: "supported",
838
861
  system: e,
839
862
  detail: r
@@ -857,37 +880,37 @@ async function $e(e = {}) {
857
880
  }
858
881
  //#endregion
859
882
  //#region src/core/manifest.ts
860
- var et = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
861
- function tt(e) {
862
- return et.test(e);
883
+ var nt = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
884
+ function rt(e) {
885
+ return nt.test(e);
863
886
  }
864
887
  //#endregion
865
888
  //#region src/core/env.ts
866
- var nt = {
889
+ var it = {
867
890
  integration: "https://feed-dev.oddin-video.gg",
868
891
  production: "https://feed.oddin-video.gg"
869
892
  };
870
- function rt(e) {
871
- let t = Object.prototype.hasOwnProperty.call(nt, e) ? nt[e] : void 0;
893
+ function at(e) {
894
+ let t = Object.prototype.hasOwnProperty.call(it, e) ? it[e] : void 0;
872
895
  if (!t) throw new n("INTERNAL", 0, `unknown env ${JSON.stringify(e)} — expected 'integration' or 'production'`);
873
896
  return t;
874
897
  }
875
898
  //#endregion
876
899
  //#region src/core/stats.ts
877
- var it = { droppedFrames: 0 };
878
- function at(e) {
900
+ var z = { droppedFrames: 0 };
901
+ function ot(e) {
879
902
  try {
880
903
  return new URL(e).host;
881
904
  } catch {
882
905
  return "";
883
906
  }
884
907
  }
885
- var ot = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
886
- function st(e) {
908
+ var st = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
909
+ function ct(e) {
887
910
  if (typeof performance > "u" || typeof performance.getEntriesByType != "function") return "";
888
911
  let t = "", n = -1, r = performance.getEntriesByType("resource");
889
- for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || ot.test(i.name)) && i.startTime >= n) {
890
- 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);
891
914
  e && (t = e, n = i.startTime);
892
915
  }
893
916
  return t;
@@ -899,7 +922,7 @@ function B(e) {
899
922
  totalFrames: t?.totalVideoFrames ?? 0
900
923
  };
901
924
  }
902
- var ct = class {
925
+ var lt = class {
903
926
  video;
904
927
  baseFrames = 0;
905
928
  baseDropped = 0;
@@ -922,7 +945,7 @@ var ct = class {
922
945
  };
923
946
  }
924
947
  };
925
- function lt(e, t) {
948
+ function ut(e, t) {
926
949
  let n = [
927
950
  ["playing", () => t("playing")],
928
951
  ["waiting", () => t("buffering")],
@@ -939,8 +962,8 @@ function lt(e, t) {
939
962
  }
940
963
  //#endregion
941
964
  //#region src/core/engine/native.ts
942
- var ut = 2e3, dt = 3, V = 500, ft = 6e3, pt = .25, mt = 250, ht = .05, gt = 4, _t = 12e3, vt = .25, yt = 1e3;
943
- 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) {
944
967
  try {
945
968
  let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
946
969
  return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
@@ -956,7 +979,7 @@ function U() {
956
979
  let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
957
980
  return e || t;
958
981
  }
959
- function xt() {
982
+ function St() {
960
983
  if (typeof navigator > "u" || !U()) return !1;
961
984
  let e = navigator.userAgent ?? "";
962
985
  return /iPhone|iPad|iPod/.test(e) ? !0 : /Macintosh/.test(e) && typeof navigator.maxTouchPoints == "number" && navigator.maxTouchPoints > 1;
@@ -991,7 +1014,7 @@ var W = class {
991
1014
  frameCounter;
992
1015
  detachFrames = null;
993
1016
  constructor(e) {
994
- 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;
995
1018
  }
996
1019
  async load() {
997
1020
  this.detachFrames ??= this.frameCounter.attach();
@@ -1012,7 +1035,7 @@ var W = class {
1012
1035
  type: "error",
1013
1036
  error: new n("INTERNAL", 0, "native HLS playback error"),
1014
1037
  fatal: !0
1015
- }), 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();
1016
1039
  }
1017
1040
  startLoad() {
1018
1041
  this.loadStarted || (this.loadStarted = !0, this.restorePreload());
@@ -1024,20 +1047,26 @@ var W = class {
1024
1047
  this.savedPreload === null ? e.removeAttribute("preload") : e.setAttribute("preload", this.savedPreload);
1025
1048
  }
1026
1049
  armFairPlay() {
1027
- let { video: e, descriptor: t, credential: r, deviceId: a, userId: o, emit: s } = this.deps, c = t.drm?.fairplay;
1028
- if (!c) return;
1029
- this.fairplayLicenseUrl = c.licenseUrl;
1030
- 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({
1031
1054
  type: "error",
1032
- error: new n(i(t), t, e),
1055
+ error: new n(a(t, i), t, e, i ? { serverCode: i } : void 0),
1033
1056
  fatal: r
1034
- });
1057
+ }), d = async (e) => {
1058
+ try {
1059
+ return await e.text();
1060
+ } catch {
1061
+ return "";
1062
+ }
1063
+ };
1035
1064
  this.onEncrypted = (n) => {
1036
- let i = n;
1037
- 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 () => {
1038
1067
  try {
1039
1068
  let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
1040
- initDataTypes: [i.initDataType],
1069
+ initDataTypes: [a.initDataType],
1041
1070
  videoCapabilities: [{
1042
1071
  contentType: "application/vnd.apple.mpegurl",
1043
1072
  robustness: ""
@@ -1045,39 +1074,40 @@ var W = class {
1045
1074
  distinctiveIdentifier: "not-allowed",
1046
1075
  persistentState: "not-allowed",
1047
1076
  sessionTypes: ["temporary"]
1048
- }])).createMediaKeys(), s = await fetch(c.certificateUrl, { headers: { "x-api-key": r.apiKey } });
1049
- if (!s.ok) {
1050
- 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);
1051
1080
  return;
1052
1081
  }
1053
- await n.setServerCertificate(await s.arrayBuffer()), await e.setMediaKeys(n);
1054
- let u = n.createSession();
1055
- 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) => {
1056
1085
  (async () => {
1057
1086
  try {
1058
- let n = await fetch(this.fairplayLicenseUrl ?? c.licenseUrl, {
1087
+ let n = await fetch(this.fairplayLicenseUrl ?? l.licenseUrl, {
1059
1088
  method: "POST",
1060
1089
  body: e.message,
1061
1090
  headers: {
1062
1091
  "x-api-key": r.apiKey,
1063
1092
  "X-Match-Urn": t.matchUrn,
1064
- "X-Device-Id": a,
1065
- ...o ? { "X-User-Id": o } : {},
1093
+ "X-Device-Id": o,
1094
+ ...s ? { "X-User-Id": s } : {},
1066
1095
  ...this.fairplayKeyIV ? { "X-Key-Iv": this.fairplayKeyIV } : {}
1067
1096
  }
1068
1097
  });
1069
1098
  if (!n.ok) {
1070
- 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);
1071
1101
  return;
1072
1102
  }
1073
- await u.update(new Uint8Array(await n.arrayBuffer()));
1103
+ await f.update(new Uint8Array(await n.arrayBuffer()));
1074
1104
  } catch (e) {
1075
- l(`FairPlay license request failed: ${String(e)}`, 0, !0);
1105
+ u(`FairPlay license request failed: ${String(e)}`, 0, !0);
1076
1106
  }
1077
1107
  })();
1078
- }), await u.generateRequest(i.initDataType, i.initData);
1108
+ }), await f.generateRequest(a.initDataType, a.initData);
1079
1109
  } catch (e) {
1080
- 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);
1081
1111
  }
1082
1112
  })());
1083
1113
  }, e.addEventListener("encrypted", this.onEncrypted);
@@ -1133,10 +1163,10 @@ var W = class {
1133
1163
  droppedFrames: t.dropped,
1134
1164
  decodedFrames: t.totalFrames
1135
1165
  };
1136
- 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) {
1137
1167
  n.isLive = !0;
1138
1168
  let t = this.liveEdgeEstimate(), r = t == null ? NaN : t - e.currentTime;
1139
- 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));
1140
1170
  } else Number.isFinite(e.duration) && e.duration > 0 && (n.isLive = !1);
1141
1171
  return n;
1142
1172
  }
@@ -1154,7 +1184,7 @@ var W = class {
1154
1184
  return;
1155
1185
  }
1156
1186
  let t = this.hiddenSince;
1157
- this.hiddenSince = null, t != null && e - t >= ut && this.armRefocus();
1187
+ this.hiddenSince = null, t != null && e - t >= dt && this.armRefocus();
1158
1188
  }, this.onPageShow = (e) => {
1159
1189
  e.persisted && this.armRefocus();
1160
1190
  }, document.addEventListener("visibilitychange", this.onVisibility), typeof window < "u" && window.addEventListener("pageshow", this.onPageShow));
@@ -1164,7 +1194,7 @@ var W = class {
1164
1194
  let e = this.liveEnd(), t = G, n = t(), r = 0, i = () => {
1165
1195
  if (this.refocusTimer = null, Number.isFinite(this.deps.video.duration)) return;
1166
1196
  r += V;
1167
- 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;
1168
1198
  if (o || s && a != null) {
1169
1199
  this.snapToLive();
1170
1200
  return;
@@ -1184,9 +1214,9 @@ var W = class {
1184
1214
  }, e.addEventListener("seeking", this.onEdgeReset), e.addEventListener("emptied", this.onEdgeReset), this.edgeTimer = setInterval(() => {
1185
1215
  if (e.duration !== Infinity) return;
1186
1216
  this.checkEndStale();
1187
- let t = St(e, e.currentTime);
1188
- t != null && ((this.lastBufferedEnd == null || Math.abs(t - this.lastBufferedEnd) >= ht) && (this.bufferedAdvancedAt = G()), this.lastBufferedEnd = t);
1189
- }, 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);
1190
1220
  }
1191
1221
  checkEndStale() {
1192
1222
  if (this.endedEmitted) return;
@@ -1194,14 +1224,14 @@ var W = class {
1194
1224
  this.lastTickAt = e;
1195
1225
  let n = this.liveEnd();
1196
1226
  if (n == null) return;
1197
- let r = this.lastSeekableEnd == null || Math.abs(n - this.lastSeekableEnd) >= vt;
1227
+ let r = this.lastSeekableEnd == null || Math.abs(n - this.lastSeekableEnd) >= yt;
1198
1228
  this.lastSeekableEnd = n;
1199
1229
  let i = this.deps.video, a = typeof document < "u" && document.visibilityState === "hidden";
1200
- if (r || t > yt || a || i.paused) {
1230
+ if (r || t > bt || a || i.paused) {
1201
1231
  this.edgeStampedAt = e;
1202
1232
  return;
1203
1233
  }
1204
- e - (this.edgeStampedAt ?? e) > _t && (this.endedEmitted = !0, this.deps.emit({
1234
+ e - (this.edgeStampedAt ?? e) > vt && (this.endedEmitted = !0, this.deps.emit({
1205
1235
  type: "ended",
1206
1236
  reason: "stalled"
1207
1237
  }));
@@ -1215,7 +1245,7 @@ var W = class {
1215
1245
  liveEdgeEstimate() {
1216
1246
  let e = this.deps.video;
1217
1247
  if (e.duration !== Infinity) return null;
1218
- let t = this.liveEnd(), n = St(e, e.currentTime) ?? this.lastBufferedEnd;
1248
+ let t = this.liveEnd(), n = Ct(e, e.currentTime) ?? this.lastBufferedEnd;
1219
1249
  if (n != null) {
1220
1250
  let e = this.bufferedAdvancedAt, r = n + (e == null ? 0 : Math.max(0, (G() - e) / 1e3));
1221
1251
  (t == null || r > t) && (t = r);
@@ -1231,7 +1261,7 @@ var W = class {
1231
1261
  snapToLive() {
1232
1262
  let e = this.deps.video, t = this.liveEnd();
1233
1263
  if (t == null) return;
1234
- 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);
1235
1265
  try {
1236
1266
  e.currentTime = i;
1237
1267
  } catch {}
@@ -1252,7 +1282,7 @@ var W = class {
1252
1282
  function G() {
1253
1283
  return typeof performance < "u" ? performance.now() : Date.now();
1254
1284
  }
1255
- function St(e, t) {
1285
+ function Ct(e, t) {
1256
1286
  let n = e.buffered;
1257
1287
  if (!n || !Number.isFinite(t)) return null;
1258
1288
  for (let e = 0; e < n.length; e += 1) if (n.start(e) <= t + .1 && n.end(e) > t) {
@@ -1261,7 +1291,7 @@ function St(e, t) {
1261
1291
  }
1262
1292
  return null;
1263
1293
  }
1264
- function Ct(e, t) {
1294
+ function wt(e, t) {
1265
1295
  return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
1266
1296
  }
1267
1297
  //#endregion
@@ -1277,9 +1307,23 @@ function K(e, t = Date.now()) {
1277
1307
  return !n || !/^\d+$/.test(n) ? !1 : Number(n) * 1e3 <= t;
1278
1308
  }
1279
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
1280
1324
  //#region src/core/engine/prefetch.ts
1281
- var wt = 15e3, Tt = 5e3, Et = 6;
1282
- function Dt(e) {
1325
+ var Dt = 15e3, Ot = 5e3, kt = 6;
1326
+ function At(e) {
1283
1327
  try {
1284
1328
  let t = new URL(e);
1285
1329
  return t.searchParams.delete("CMCD"), t.toString();
@@ -1287,7 +1331,7 @@ function Dt(e) {
1287
1331
  return e;
1288
1332
  }
1289
1333
  }
1290
- var Ot = class {
1334
+ var jt = class {
1291
1335
  cmcd;
1292
1336
  entries = /* @__PURE__ */ new Map();
1293
1337
  keyed = /* @__PURE__ */ new Set();
@@ -1310,10 +1354,10 @@ var Ot = class {
1310
1354
  }
1311
1355
  prefetch(e, t, n) {
1312
1356
  if (!this.isActive(t)) return;
1313
- let r = Dt(e);
1357
+ let r = At(e);
1314
1358
  if (this.entries.has(r)) return;
1315
1359
  let i = this.perTrack.get(t) ?? 0;
1316
- if (i >= Et) return;
1360
+ if (i >= kt) return;
1317
1361
  this.perTrack.set(t, i + 1);
1318
1362
  let a = new AbortController(), o = {
1319
1363
  started: performance.now(),
@@ -1327,10 +1371,10 @@ var Ot = class {
1327
1371
  signal: a.signal
1328
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(() => {
1329
1373
  this.entries.get(r) === o && (this.entries.delete(r), a.abort(), this.stats.expired += 1);
1330
- }, wt);
1374
+ }, Dt);
1331
1375
  }
1332
1376
  take(e) {
1333
- let t = Dt(e), n = this.entries.get(t);
1377
+ let t = At(e), n = this.entries.get(t);
1334
1378
  return n && this.entries.delete(t), n;
1335
1379
  }
1336
1380
  destroy() {
@@ -1350,13 +1394,13 @@ var Ot = class {
1350
1394
  }
1351
1395
  }
1352
1396
  };
1353
- function kt(t) {
1397
+ function Mt(t) {
1354
1398
  let n = e.DefaultConfig?.loader;
1355
1399
  if (typeof n != "function") return;
1356
1400
  class r extends n {
1357
1401
  served = !1;
1358
1402
  cancelled = !1;
1359
- stats = At();
1403
+ stats = Nt();
1360
1404
  load(e, n, r) {
1361
1405
  let i = e.rangeEnd ? void 0 : t.take(e.url);
1362
1406
  if (!i) {
@@ -1364,7 +1408,7 @@ function kt(t) {
1364
1408
  return;
1365
1409
  }
1366
1410
  this.served = !0;
1367
- let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || Tt, s = setTimeout(() => {
1411
+ let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || Ot, s = setTimeout(() => {
1368
1412
  !this.cancelled && this.served && (i.abort.abort(), t.stats.failed += 1, this.served = !1, super.load(e, n, r));
1369
1413
  }, o);
1370
1414
  i.bytes.then((o) => {
@@ -1391,7 +1435,7 @@ function kt(t) {
1391
1435
  }
1392
1436
  return r;
1393
1437
  }
1394
- function At() {
1438
+ function Nt() {
1395
1439
  return {
1396
1440
  aborted: !1,
1397
1441
  loaded: 0,
@@ -1415,10 +1459,10 @@ function At() {
1415
1459
  }
1416
1460
  };
1417
1461
  }
1418
- function jt(e) {
1462
+ function Pt(e) {
1419
1463
  return e === "audio" ? "audio" : "main";
1420
1464
  }
1421
- function Mt(e, t) {
1465
+ function Ft(e, t) {
1422
1466
  let n = [];
1423
1467
  t.initSegment?.url && !t.initSegment.data && n.push({
1424
1468
  url: t.initSegment.url,
@@ -1437,24 +1481,24 @@ function Mt(e, t) {
1437
1481
  }
1438
1482
  //#endregion
1439
1483
  //#region src/core/engine/hls.ts
1440
- function Nt() {
1484
+ function It() {
1441
1485
  return e.isSupported();
1442
1486
  }
1443
- 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;
1444
- 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) {
1445
1489
  if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
1446
1490
  delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
1447
1491
  return;
1448
1492
  }
1449
- e.liveSyncDuration ??= dn;
1450
- let t = Math.max(12, e.liveSyncDuration + fn);
1451
- (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);
1452
1496
  }
1453
- function gn(e, t) {
1497
+ function yn(e, t) {
1454
1498
  let n = (e, t, n) => Math.min(n, Math.max(t, e));
1455
1499
  e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
1456
1500
  }
1457
- var _n = class {
1501
+ var bn = class {
1458
1502
  name = "hls";
1459
1503
  hls = null;
1460
1504
  deps;
@@ -1538,7 +1582,7 @@ var _n = class {
1538
1582
  frameCounter;
1539
1583
  detachFrames = null;
1540
1584
  constructor(e) {
1541
- 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;
1542
1586
  }
1543
1587
  async load() {
1544
1588
  this.detachFrames ??= this.frameCounter.attach();
@@ -1551,7 +1595,7 @@ var _n = class {
1551
1595
  });
1552
1596
  return;
1553
1597
  }
1554
- e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && (Ve(r), Ge()), 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 = () => {
1555
1599
  let e = this.hls;
1556
1600
  if (document.visibilityState !== "visible" || !e) return;
1557
1601
  let t = e.liveSyncPosition;
@@ -1574,7 +1618,7 @@ var _n = class {
1574
1618
  }
1575
1619
  this.loadSuspended = !0;
1576
1620
  }
1577
- }, Zt));
1621
+ }, en));
1578
1622
  }
1579
1623
  resumeLoading() {
1580
1624
  if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
@@ -1606,7 +1650,7 @@ var _n = class {
1606
1650
  let t = e.liveSyncPosition;
1607
1651
  if (typeof t != "number" || !Number.isFinite(t)) return;
1608
1652
  let { video: n } = this.deps;
1609
- n.currentTime <= t + pn || (n.currentTime = t);
1653
+ n.currentTime <= t + gn || (n.currentTime = t);
1610
1654
  }
1611
1655
  reanchorPartTimeline(e, t) {
1612
1656
  let { frag: n, part: r } = t;
@@ -1618,7 +1662,7 @@ var _n = class {
1618
1662
  let o = n.sn, s = i.fragments.find((e) => e && e.sn === o) ?? (i.fragmentHint?.sn === o ? i.fragmentHint : void 0);
1619
1663
  if (!s) return;
1620
1664
  let c = a.startPTS - s.start;
1621
- if (!(!Number.isFinite(c) || Math.abs(c) < Wt)) {
1665
+ if (!(!Number.isFinite(c) || Math.abs(c) < qt)) {
1622
1666
  for (let e of i.fragments) e && e.setStart(e.start + c);
1623
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})`);
1624
1668
  }
@@ -1641,12 +1685,12 @@ var _n = class {
1641
1685
  emeEnabled: !0,
1642
1686
  drmSystems: { ...this.licenseUrl ? { "com.widevine.alpha": { licenseUrl: this.licenseUrl } } : {} },
1643
1687
  drmSystemOptions: {
1644
- videoRobustness: I.video,
1645
- audioRobustness: I.audio,
1646
- videoEncryptionScheme: I.scheme,
1647
- audioEncryptionScheme: I.scheme
1688
+ videoRobustness: F.video,
1689
+ audioRobustness: F.audio,
1690
+ videoEncryptionScheme: F.scheme,
1691
+ audioEncryptionScheme: F.scheme
1648
1692
  },
1649
- ...N() ? { requestMediaKeySystemAccessFunc: Be(t) } : {},
1693
+ ...M() ? { requestMediaKeySystemAccessFunc: He(t) } : {},
1650
1694
  licenseXhrSetup: (e, t) => {
1651
1695
  let o = performance.now(), s = () => {
1652
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", () => {
@@ -1658,7 +1702,7 @@ var _n = class {
1658
1702
  return;
1659
1703
  }
1660
1704
  let l = this.hls, u, d = new Promise((e) => {
1661
- u = setTimeout(() => e(void 0), Bt);
1705
+ u = setTimeout(() => e(void 0), Ut);
1662
1706
  });
1663
1707
  return Promise.race([c().catch(() => void 0), d]).finally(() => clearTimeout(u)).then((e) => {
1664
1708
  if (!this.hls || this.hls !== l) throw Error("havik-player: engine torn down during refresh");
@@ -1674,20 +1718,20 @@ var _n = class {
1674
1718
  ...c
1675
1719
  };
1676
1720
  if (this.prefetch?.destroy(), this.prefetch = null, u && this.deps.mediaDuringKey !== !1 && !f.fLoader) {
1677
- let e = new Ot({
1721
+ let e = new jt({
1678
1722
  sessionId: n.analytics?.sid,
1679
1723
  contentId: n.matchUrn
1680
- }), t = kt(e);
1724
+ }), t = Mt(e);
1681
1725
  t && (this.prefetch = e, f.fLoader = t);
1682
1726
  }
1683
- 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;
1684
1728
  let p = new e(f);
1685
1729
  if (this.hls = p, p.on(e.Events.FRAG_PARSED, (e, t) => this.reanchorPartTimeline(p, t)), p.on(e.Events.MANIFEST_PARSED, () => {
1686
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" });
1687
1731
  }), p.on(e.Events.FRAG_BUFFERED, (e, t) => {
1688
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(() => {
1689
1733
  this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
1690
- }, Vt)));
1734
+ }, Wt)));
1691
1735
  }), p.on(e.Events.FRAG_LOADING, (e, t) => {
1692
1736
  t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
1693
1737
  }), p.on(e.Events.FRAG_LOADED, (e, t) => {
@@ -1695,10 +1739,10 @@ var _n = class {
1695
1739
  let n = t?.frag?.stats, r = n?.loaded;
1696
1740
  typeof r == "number" && (this.bytesLoaded += r), !this.reportedFirstBytes && typeof r == "number" && r > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
1697
1741
  let i = n?.loading;
1698
- 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());
1699
1743
  let a = t?.frag?.url;
1700
1744
  if (a) {
1701
- let e = at(a);
1745
+ let e = ot(a);
1702
1746
  e && (this.cdnHost = e);
1703
1747
  }
1704
1748
  }), p.on(e.Events.LEVEL_LOADED, (e, t) => {
@@ -1712,15 +1756,15 @@ var _n = class {
1712
1756
  }), p.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.prefetch) {
1713
1757
  let t = this.prefetch;
1714
1758
  p.on(e.Events.KEY_LOADING, (e, n) => {
1715
- let r = n?.frag, i = jt(r?.type);
1716
- if (r && t.isActive(i)) for (let e of Mt(p, r)) t.prefetch(e.url, i, e.kind);
1717
- }), 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)));
1718
1762
  }
1719
1763
  p.on(e.Events.KEY_LOADED, () => {
1720
1764
  u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
1721
1765
  }), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
1722
1766
  this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.checkFrameDrops();
1723
- }, Ut), p.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1767
+ }, Kt), p.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1724
1768
  this.renditionSwitches += 1;
1725
1769
  let n = this.lastLevelIndex >= 0 ? p.levels[this.lastLevelIndex] : void 0, r = p.levels[t.level];
1726
1770
  n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, l({
@@ -1784,7 +1828,7 @@ var _n = class {
1784
1828
  return;
1785
1829
  }
1786
1830
  this.capTimer && clearTimeout(this.capTimer);
1787
- let t = e > this.sizeCapLevel ? on : sn;
1831
+ let t = e > this.sizeCapLevel ? ln : un;
1788
1832
  this.capTimer = setTimeout(() => {
1789
1833
  this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
1790
1834
  }, t);
@@ -1794,9 +1838,9 @@ var _n = class {
1794
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;
1795
1839
  }
1796
1840
  dropLevelsWidevineCannotPlay(e) {
1797
- this.removeLevelsWhere(e, (e) => Ke(e) !== !0);
1798
- let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && L(e) !== "avc" && !!L(e)));
1799
- for (let n of t) We(n).then((t) => {
1841
+ this.removeLevelsWhere(e, (e) => Je(e) !== !0);
1842
+ let t = new Set(e.levels.map((e) => e.videoCodec).filter((e) => !!e && I(e) !== "avc" && !!I(e)));
1843
+ for (let n of t) Ke(n).then((t) => {
1800
1844
  t || this.hls !== e || this.removeLevelsWhere(e, (e) => e === n) && (this.measureLadder(e), this.applySizeCap());
1801
1845
  });
1802
1846
  }
@@ -1804,10 +1848,10 @@ var _n = class {
1804
1848
  let n = e.levels ?? [], r = [], i = /* @__PURE__ */ new Set();
1805
1849
  if (n.forEach((e, n) => {
1806
1850
  let a = e.videoCodec;
1807
- a && L(a) && t(a) && (r.push(n), i.add(a));
1851
+ a && I(a) && t(a) && (r.push(n), i.add(a));
1808
1852
  }), !r.length) return !1;
1809
1853
  let a = [...i].join(", ");
1810
- if (!n.some((e, t) => r.includes(t) ? !1 : !L(e.videoCodec) || Ke(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;
1811
1855
  for (let t = r.length - 1; t >= 0; --t) e.removeLevel(r[t]);
1812
1856
  return console.info(`havik-player: skipped ${r.length} rendition(s) Widevine cannot play on this browser (${a})`), !0;
1813
1857
  }
@@ -1913,7 +1957,7 @@ var _n = class {
1913
1957
  return;
1914
1958
  }
1915
1959
  let e = Date.now() - this.lastAdvanceMs;
1916
- !this.chaseSuspended && e > Gt && this.suspendChasing(), e > Ht && this.emitEnded("stalled");
1960
+ !this.chaseSuspended && e > Jt && this.suspendChasing(), e > Gt && this.emitEnded("stalled");
1917
1961
  }
1918
1962
  resetStarvationWindow() {
1919
1963
  this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
@@ -1928,7 +1972,7 @@ var _n = class {
1928
1972
  this.resetStarvationWindow();
1929
1973
  return;
1930
1974
  }
1931
- 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;
1932
1976
  if (this.starvedFrames = c, !a || l) {
1933
1977
  (t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
1934
1978
  return;
@@ -1937,12 +1981,12 @@ var _n = class {
1937
1981
  this.resetStarvationWindow();
1938
1982
  return;
1939
1983
  }
1940
- 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)) {
1941
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");
1942
1986
  return;
1943
1987
  }
1944
- let u = i && this.starvedTicks >= $t, d = !i && this.deadTicks >= rn && this.recentMainFrags.reduce((e, t) => e + t, 0) >= an;
1945
- 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))) {
1946
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");
1947
1991
  try {
1948
1992
  e.stopLoad(), e.startLoad(-1);
@@ -1957,7 +2001,7 @@ var _n = class {
1957
2001
  let t = e.latency, n = e.targetLatency;
1958
2002
  if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
1959
2003
  let r = t - n;
1960
- !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);
1961
2005
  let i = this.catchUpEngaged ? this.catchUpRate : 1;
1962
2006
  e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
1963
2007
  }
@@ -1979,15 +2023,15 @@ var _n = class {
1979
2023
  return;
1980
2024
  }
1981
2025
  let { totalFrames: n, dropped: r } = B(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
1982
- 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) {
1983
2027
  this.fpsBadTicks = 0;
1984
2028
  return;
1985
2029
  }
1986
- if (o <= cn * a) {
2030
+ if (o <= dn * a) {
1987
2031
  this.fpsBadTicks = 0;
1988
2032
  return;
1989
2033
  }
1990
- if (this.fpsBadTicks += 1, this.fpsBadTicks < un) return;
2034
+ if (this.fpsBadTicks += 1, this.fpsBadTicks < pn) return;
1991
2035
  this.fpsBadTicks = 0;
1992
2036
  let s = e.levels, c = s[e.currentLevel];
1993
2037
  if (!c) return;
@@ -2004,20 +2048,20 @@ var _n = class {
2004
2048
  return;
2005
2049
  }
2006
2050
  let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
2007
- 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))) {
2008
2052
  this.resetChaseWindow();
2009
2053
  return;
2010
2054
  }
2011
- if (this.chaseLatency < 0 || this.chaseLatency - n >= Jt) {
2055
+ if (this.chaseLatency < 0 || this.chaseLatency - n >= Zt) {
2012
2056
  this.chaseLatency = n, this.chaseTicks = 0;
2013
2057
  return;
2014
2058
  }
2015
- if (this.chaseTicks += 1, this.chaseTicks < qt) return;
2059
+ if (this.chaseTicks += 1, this.chaseTicks < Xt) return;
2016
2060
  this.resetChaseWindow();
2017
2061
  let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
2018
2062
  if (!(a > 1)) return;
2019
2063
  let o = typeof e.targetLatency == "number" ? e.targetLatency : 0, s = Math.min(n, a - 1);
2020
- 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);
2021
2065
  }
2022
2066
  suspendChasing() {
2023
2067
  let e = this.hls;
@@ -2047,14 +2091,14 @@ var _n = class {
2047
2091
  } catch {}
2048
2092
  }
2049
2093
  startEstimate() {
2050
- return this.deps.rememberBandwidth === !1 ? Pt : Pe() ?? Pt;
2094
+ return this.deps.rememberBandwidth === !1 ? Lt : Ie() ?? Lt;
2051
2095
  }
2052
2096
  maybeRememberBandwidth(e) {
2053
- if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded < Ft) return;
2097
+ if (this.deps.rememberBandwidth === !1 || this.bwFragsLoaded < Rt) return;
2054
2098
  let t = Date.now();
2055
- if (!e && t - this.bwSavedAt < It) return;
2099
+ if (!e && t - this.bwSavedAt < zt) return;
2056
2100
  let n = this.hls?.bandwidthEstimate;
2057
- typeof n != "number" || !Number.isFinite(n) || n <= 0 || (this.bwSavedAt = t, Fe(n));
2101
+ typeof n != "number" || !Number.isFinite(n) || n <= 0 || (this.bwSavedAt = t, Le(n));
2058
2102
  }
2059
2103
  destroy() {
2060
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) {
@@ -2072,7 +2116,7 @@ var _n = class {
2072
2116
  scheduleLicenseRetry(t) {
2073
2117
  if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
2074
2118
  let n = t.response?.code ?? 0;
2075
- 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;
2076
2120
  this.licenseRecoveries += 1;
2077
2121
  let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
2078
2122
  return this.licenseRetryTimer = setTimeout(() => {
@@ -2104,7 +2148,7 @@ var _n = class {
2104
2148
  return;
2105
2149
  }
2106
2150
  if (t.type === e.ErrorTypes.NETWORK_ERROR) {
2107
- if (this.networkRecoveries < Rt) {
2151
+ if (this.networkRecoveries < Vt) {
2108
2152
  this.networkRecoveries += 1;
2109
2153
  let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
2110
2154
  this.networkRetryTimer = setTimeout(() => {
@@ -2121,7 +2165,7 @@ var _n = class {
2121
2165
  return;
2122
2166
  }
2123
2167
  if (t.type === e.ErrorTypes.MEDIA_ERROR) {
2124
- if (this.mediaRecoveries < Lt) {
2168
+ if (this.mediaRecoveries < Bt) {
2125
2169
  this.mediaRecoveries += 1, n.recoverMediaError();
2126
2170
  return;
2127
2171
  }
@@ -2141,25 +2185,26 @@ var _n = class {
2141
2185
  });
2142
2186
  }
2143
2187
  }
2144
- toError(e, t = "PLAYBACK") {
2145
- let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
2146
- 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);
2147
2191
  }
2148
- }, 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 = {
2149
2193
  inline: "PRESENTATION_INLINE",
2150
2194
  fullscreen: "PRESENTATION_FULLSCREEN",
2151
2195
  pip: "PRESENTATION_PIP"
2152
- }, En = {
2196
+ }, kn = {
2153
2197
  widevine: "KEY_SYSTEM_WIDEVINE",
2154
2198
  fairplay: "KEY_SYSTEM_FAIRPLAY",
2155
2199
  none: "KEY_SYSTEM_NONE"
2156
2200
  };
2157
- function Dn(e, t) {
2201
+ function An(e, t) {
2158
2202
  return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
2159
2203
  }
2160
- var On = /* @__PURE__ */ new Set([
2204
+ var jn = /* @__PURE__ */ new Set([
2161
2205
  "INVALID_URN",
2162
2206
  "NOT_FOUND",
2207
+ "GEO_DENIED",
2163
2208
  "GONE",
2164
2209
  "TOO_EARLY",
2165
2210
  "UNAVAILABLE",
@@ -2177,7 +2222,7 @@ var On = /* @__PURE__ */ new Set([
2177
2222
  ended: "PLAYER_STATE_ENDED",
2178
2223
  error: "PLAYER_STATE_ERROR"
2179
2224
  };
2180
- function kn(e) {
2225
+ function Mn(e) {
2181
2226
  try {
2182
2227
  let t = new URL(e), [n, ...r] = t.hostname.split(".");
2183
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);
@@ -2185,8 +2230,8 @@ function kn(e) {
2185
2230
  return;
2186
2231
  }
2187
2232
  }
2188
- 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.`;
2189
- 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) {
2190
2235
  if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
2191
2236
  let t;
2192
2237
  try {
@@ -2195,19 +2240,19 @@ function Nn(e) {
2195
2240
  } catch {
2196
2241
  return;
2197
2242
  }
2198
- if (jn.has(t) && !Y.has(t)) {
2199
- 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));
2200
2245
  for (let e of X) e.noteCspBlocked();
2201
2246
  }
2202
2247
  }
2203
- function Pn(e, t) {
2204
- return g(t, e), { disabledReason: t };
2248
+ function Ln(e, t) {
2249
+ return _(t, e), { disabledReason: t };
2205
2250
  }
2206
- function Fn(e, t, n) {
2207
- 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 };
2208
2253
  if (t) return { endpoint: t };
2209
- 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).");
2210
- 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);
2211
2256
  if (r) return { endpoint: r };
2212
2257
  let i;
2213
2258
  try {
@@ -2215,9 +2260,9 @@ function Fn(e, t, n) {
2215
2260
  } catch {
2216
2261
  i = e;
2217
2262
  }
2218
- 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).`);
2219
2264
  }
2220
- var In = class {
2265
+ var zn = class {
2221
2266
  opts;
2222
2267
  url;
2223
2268
  cspKey;
@@ -2299,8 +2344,8 @@ var In = class {
2299
2344
  constructor(e) {
2300
2345
  this.opts = {
2301
2346
  ...e,
2302
- heartbeatMs: e.heartbeatMs ?? vn,
2303
- idleMs: e.idleMs ?? yn
2347
+ heartbeatMs: e.heartbeatMs ?? xn,
2348
+ idleMs: e.idleMs ?? Sn
2304
2349
  }, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
2305
2350
  try {
2306
2351
  let e = new URL(this.url);
@@ -2317,11 +2362,11 @@ var In = class {
2317
2362
  sdkVersion: this.opts.sdkVersion,
2318
2363
  ...this.opts.environment
2319
2364
  };
2320
- 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());
2321
2366
  }
2322
2367
  checkSuspension(e) {
2323
2368
  if (this.endedFlag || !this.opts.idleMs) return !1;
2324
- let t = Math.max(this.opts.idleMs, bn);
2369
+ let t = Math.max(this.opts.idleMs, Cn);
2325
2370
  return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
2326
2371
  }
2327
2372
  syncIdle(e) {
@@ -2344,12 +2389,12 @@ var In = class {
2344
2389
  let a = {
2345
2390
  fromState: J[e] ?? "PLAYER_STATE_UNSPECIFIED",
2346
2391
  toState: J[t] ?? "PLAYER_STATE_UNSPECIFIED",
2347
- presentation: Tn[this.presentation]
2392
+ presentation: On[this.presentation]
2348
2393
  }, o = this.causeOf(e, t, i);
2349
2394
  o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
2350
2395
  }
2351
2396
  seekInduced(e) {
2352
- return this.lastSeekMs >= 0 && e - this.lastSeekMs < wn;
2397
+ return this.lastSeekMs >= 0 && e - this.lastSeekMs < Dn;
2353
2398
  }
2354
2399
  causeOf(e, t, n) {
2355
2400
  if (t === "error") return "TRANSITION_CAUSE_ERROR";
@@ -2422,8 +2467,8 @@ var In = class {
2422
2467
  stageOf(e, t, n) {
2423
2468
  let r = n ?? "";
2424
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";
2425
- if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
2426
- 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";
2427
2472
  let i = t ?? "";
2428
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";
2429
2474
  }
@@ -2470,14 +2515,14 @@ var In = class {
2470
2515
  if (this.lastRequestCount = g, _ > 0) {
2471
2516
  o.requestCountDelta = _;
2472
2517
  let e = t.requestTimesMs ?? [], n = e.slice(Math.max(0, e.length - _)).sort((e, t) => e - t);
2473
- 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));
2474
2519
  }
2475
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();
2476
2521
  }
2477
2522
  maybeEmitMediaInfo(e) {
2478
2523
  if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
2479
2524
  let t = {};
2480
- 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);
2481
2526
  let n = JSON.stringify(t);
2482
2527
  n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
2483
2528
  }
@@ -2497,7 +2542,7 @@ var In = class {
2497
2542
  let c = r?.positionMs ?? 0;
2498
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));
2499
2544
  let l = e !== "END_REASON_ENDED";
2500
- 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);
2501
2546
  let u = r?.decodedFrames ?? this.lastDecoded;
2502
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");
2503
2548
  }
@@ -2517,13 +2562,13 @@ var In = class {
2517
2562
  };
2518
2563
  }
2519
2564
  noteCspBlocked() {
2520
- 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)));
2521
2566
  }
2522
2567
  cspBlocked() {
2523
2568
  return !!this.cspKey && Y.has(this.cspKey);
2524
2569
  }
2525
2570
  enqueue(e) {
2526
- 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;) {
2527
2572
  let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
2528
2573
  this.pending.splice(e >= 0 ? e : 0, 1);
2529
2574
  }
@@ -2550,7 +2595,7 @@ var In = class {
2550
2595
  };
2551
2596
  //#endregion
2552
2597
  //#region src/core/environment.ts
2553
- function Ln() {
2598
+ function Bn() {
2554
2599
  if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
2555
2600
  let e;
2556
2601
  try {
@@ -2575,14 +2620,14 @@ function Ln() {
2575
2620
  integration: "INTEGRATION_KIND_IFRAME"
2576
2621
  };
2577
2622
  }
2578
- function Rn() {
2623
+ function Vn() {
2579
2624
  if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
2580
2625
  let e = navigator.userAgentData, t = e?.platform ?? "";
2581
2626
  if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
2582
2627
  let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
2583
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";
2584
2629
  }
2585
- function zn() {
2630
+ function Hn() {
2586
2631
  let e = typeof navigator < "u" ? navigator.connection : void 0;
2587
2632
  if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
2588
2633
  let t = {
@@ -2601,17 +2646,17 @@ function zn() {
2601
2646
  }
2602
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;
2603
2648
  }
2604
- function Bn(e) {
2605
- let t = Ln(), n = {
2606
- deviceClass: Rn(),
2649
+ function Un(e) {
2650
+ let t = Bn(), n = {
2651
+ deviceClass: Vn(),
2607
2652
  integration: t.integration,
2608
- ...zn()
2653
+ ...Hn()
2609
2654
  };
2610
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);
2611
2656
  let r = e.getBoundingClientRect?.();
2612
2657
  return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
2613
2658
  }
2614
- async function Vn() {
2659
+ async function Wn() {
2615
2660
  let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
2616
2661
  if (!e?.getHighEntropyValues) return {};
2617
2662
  try {
@@ -2623,7 +2668,7 @@ async function Vn() {
2623
2668
  }
2624
2669
  //#endregion
2625
2670
  //#region src/core/version.ts
2626
- var Hn = "2.19.0", Un = {
2671
+ var Gn = "2.21.0", Kn = {
2627
2672
  accent: "#E1B600",
2628
2673
  accentText: "#1B1C23",
2629
2674
  background: "#0e0f13",
@@ -2634,7 +2679,7 @@ var Hn = "2.19.0", Un = {
2634
2679
  border: "rgba(255, 255, 255, 0.1)",
2635
2680
  radius: "8px",
2636
2681
  fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
2637
- }, Wn = {
2682
+ }, qn = {
2638
2683
  accent: "--havik-accent",
2639
2684
  accentText: "--havik-accent-text",
2640
2685
  background: "--havik-bg",
@@ -2646,26 +2691,26 @@ var Hn = "2.19.0", Un = {
2646
2691
  radius: "--havik-radius",
2647
2692
  fontFamily: "--havik-font"
2648
2693
  };
2649
- function Z(e, t) {
2694
+ function Jn(e, t) {
2650
2695
  let n = {
2651
- ...Un,
2696
+ ...Kn,
2652
2697
  ...t
2653
2698
  };
2654
- 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]);
2655
2700
  n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
2656
2701
  }
2657
2702
  //#endregion
2658
2703
  //#region src/ui/styles.ts
2659
- var Gn = "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();
2660
- function Jn(e = document, t) {
2661
- let n = e.querySelector(`style#${Gn}`);
2662
- if (n && (!t || qn.get(n) === t)) return;
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) {
2706
+ let n = e.querySelector(`style#${Z}`);
2707
+ if (n && (!t || Xn.get(n) === t)) return;
2663
2708
  let r = e.createElement("style");
2664
- r.id = Gn, 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);
2665
2710
  }
2666
2711
  //#endregion
2667
2712
  //#region src/ui/icons.ts
2668
- var Yn = {
2713
+ var Qn = {
2669
2714
  play: "<path d=\"M8 5v14l11-7z\"/>",
2670
2715
  pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
2671
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\"/>",
@@ -2679,20 +2724,27 @@ var Yn = {
2679
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\"/>"
2680
2725
  };
2681
2726
  function Q(e) {
2682
- 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>`;
2683
2728
  }
2684
2729
  //#endregion
2685
2730
  //#region src/ui/controls.ts
2686
- var Xn = 3e3, Zn = 250, Qn = /* @__PURE__ */ new Set([
2731
+ var $n = 3e3, er = 250, tr = /* @__PURE__ */ new Set([
2687
2732
  "GONE",
2688
2733
  "NOT_FOUND",
2734
+ "GEO_DENIED",
2689
2735
  "INVALID_URN",
2690
- "UNAUTHORIZED"
2736
+ "UNAUTHORIZED",
2737
+ "DRM_DEVICE_REVOKED"
2691
2738
  ]);
2692
- function $n(e) {
2693
- return new er(e);
2739
+ function nr(e) {
2740
+ let t = "This match isn't available in your country";
2741
+ return e ? `${t} (${e})` : t;
2742
+ }
2743
+ var rr = "This device can't play protected video";
2744
+ function ir(e) {
2745
+ return new ar(e);
2694
2746
  }
2695
- var er = class {
2747
+ var ar = class {
2696
2748
  root;
2697
2749
  video;
2698
2750
  player;
@@ -2740,7 +2792,7 @@ var er = class {
2740
2792
  scrubbing = !1;
2741
2793
  offFns = [];
2742
2794
  constructor(e) {
2743
- 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");
2744
2796
  let t = (e, t, n) => {
2745
2797
  let r = this.doc.createElement(e);
2746
2798
  if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
@@ -2826,7 +2878,7 @@ var er = class {
2826
2878
  let t = this.surfaceWasHidden;
2827
2879
  this.tapTimer = setTimeout(() => {
2828
2880
  this.tapTimer = void 0, this.toggleBar(t);
2829
- }, Zn);
2881
+ }, er);
2830
2882
  }
2831
2883
  toggleBar(e) {
2832
2884
  e ? this.poke() : this.hideIfIdle();
@@ -2846,7 +2898,7 @@ var er = class {
2846
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);
2847
2899
  }
2848
2900
  statusMessageFor(e) {
2849
- 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 ?? this.lastError?.message ?? "Playback unavailable" : 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;
2850
2902
  }
2851
2903
  renderStatus(e) {
2852
2904
  let t = this.statusMessageFor(e);
@@ -2861,7 +2913,7 @@ var er = class {
2861
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);
2862
2914
  } else {
2863
2915
  let r = this.doc.createElement("div");
2864
- 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)) {
2865
2917
  let e = this.doc.createElement("button");
2866
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);
2867
2919
  }
@@ -2902,7 +2954,7 @@ var er = class {
2902
2954
  let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
2903
2955
  this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
2904
2956
  }
2905
- !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${tr(this.video.currentTime)} / ${tr(this.video.duration)}`);
2957
+ !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${or(this.video.currentTime)} / ${or(this.video.duration)}`);
2906
2958
  }
2907
2959
  syncLive() {
2908
2960
  let e = this.player.getStats(), t = e.isLive !== !1, n = this.player.state === "ended", r = !t && !this.streamEnded();
@@ -2952,17 +3004,17 @@ var er = class {
2952
3004
  renderQualityMenu() {
2953
3005
  let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
2954
3006
  n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
2955
- for (let n of e) this.menu.append(this.menuItem(nr(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)));
2956
3008
  }
2957
3009
  renderAudioMenu() {
2958
3010
  let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
2959
3011
  t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
2960
- for (let t of e) this.menu.append(this.menuItem(rr(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)));
2961
3013
  }
2962
3014
  renderCcMenu() {
2963
3015
  let e = this.player.getTextTracks(), t = this.doc.createElement("div");
2964
3016
  t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
2965
- for (let t of e) this.menu.append(this.menuItem(ir(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)));
2966
3018
  }
2967
3019
  onTracksChanged() {
2968
3020
  this.openMenu && this.renderMenu(this.openMenu);
@@ -3067,41 +3119,41 @@ var er = class {
3067
3119
  this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
3068
3120
  }
3069
3121
  };
3070
- function tr(e) {
3122
+ function or(e) {
3071
3123
  (!Number.isFinite(e) || e < 0) && (e = 0);
3072
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");
3073
3125
  return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
3074
3126
  }
3075
- function nr(e) {
3127
+ function sr(e) {
3076
3128
  return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
3077
3129
  }
3078
- function rr(e) {
3130
+ function cr(e) {
3079
3131
  return e.name || e.lang || `Track ${e.id}`;
3080
3132
  }
3081
- function ir(e) {
3133
+ function lr(e) {
3082
3134
  return e.name || e.lang || `Track ${e.id}`;
3083
3135
  }
3084
3136
  //#endregion
3085
3137
  //#region src/managed/index.ts
3086
- var ar = 6e3, or = 45e3, sr = 2e3, cr = 3, lr = 5e3, ur = 2e3, dr = 48e4, fr = "keySystemLicenseRequestFailed";
3087
- function pr(e) {
3138
+ var ur = 6e3, dr = 45e3, fr = 2e3, pr = 3, mr = 5e3, hr = 2e3, gr = 48e4, _r = "keySystemLicenseRequestFailed";
3139
+ function vr(e) {
3088
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)})`);
3089
- if (e.env !== void 0) return rt(e.env);
3141
+ if (e.env !== void 0) return at(e.env);
3090
3142
  if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
3091
3143
  return e.baseUrl;
3092
3144
  }
3093
- async function mr(e) {
3145
+ async function yr(e) {
3094
3146
  if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
3095
- let t = pr(e);
3147
+ let t = vr(e);
3096
3148
  if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
3097
3149
  if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
3098
- let r = new hr({
3150
+ let r = new br({
3099
3151
  ...e,
3100
3152
  baseUrl: t
3101
3153
  });
3102
3154
  return await r.start(), r;
3103
3155
  }
3104
- var hr = class {
3156
+ var br = class {
3105
3157
  opts;
3106
3158
  abort = new AbortController();
3107
3159
  listeners = {};
@@ -3158,7 +3210,7 @@ var hr = class {
3158
3210
  throw this.destroy(), e;
3159
3211
  }
3160
3212
  } catch (t) {
3161
- if (this.opts.waitForLive && t instanceof n && o(t.code)) {
3213
+ if (this.opts.waitForLive && t instanceof n && s(t.code)) {
3162
3214
  this.setState("waiting"), this.beginArming(e, t.liveStartsAtMs);
3163
3215
  return;
3164
3216
  }
@@ -3190,13 +3242,13 @@ var hr = class {
3190
3242
  });
3191
3243
  }
3192
3244
  armWithSse(e, t, r, i = !1) {
3193
- let a = !1, s = !1, c = new AbortController();
3245
+ let a = !1, o = !1, c = new AbortController();
3194
3246
  this.armFallbackCtrl = c, this.setState("waiting");
3195
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);
3196
3248
  setTimeout(() => {
3197
3249
  a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
3198
3250
  phase: i ? "unavailable" : "tooEarly",
3199
- retryInMs: or,
3251
+ retryInMs: dr,
3200
3252
  attempt: 1,
3201
3253
  elapsedMs: 0,
3202
3254
  ...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
@@ -3213,7 +3265,7 @@ var hr = class {
3213
3265
  }
3214
3266
  }
3215
3267
  }, h = () => {
3216
- a || s || p() || (s = !0, y({
3268
+ a || o || p() || (o = !0, y({
3217
3269
  ...this.resolveOptions(),
3218
3270
  signal: c.signal,
3219
3271
  waitForLive: this.buildWaitConfig(e)
@@ -3223,7 +3275,7 @@ var hr = class {
3223
3275
  }, g = () => {
3224
3276
  a || p() || v(this.resolveOptions()).then((e) => m(e)).catch((e) => {
3225
3277
  if (!(a || p())) {
3226
- if (e instanceof n && o(e.code)) {
3278
+ if (e instanceof n && s(e.code)) {
3227
3279
  h();
3228
3280
  return;
3229
3281
  }
@@ -3235,13 +3287,13 @@ var hr = class {
3235
3287
  !a && !p() && h();
3236
3288
  }, e);
3237
3289
  };
3238
- _(ar), this.armingSub = E({
3290
+ _(ur), this.armingSub = E({
3239
3291
  eventsBaseUrl: t,
3240
3292
  matchUrn: this.opts.matchUrn,
3241
3293
  credential: this.opts.credential,
3242
- onAlive: () => _(or),
3294
+ onAlive: () => _(dr),
3243
3295
  onState: (e) => {
3244
- a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * sr);
3296
+ a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * fr);
3245
3297
  },
3246
3298
  onError: () => h()
3247
3299
  });
@@ -3261,10 +3313,10 @@ var hr = class {
3261
3313
  async onResolved(e, t) {
3262
3314
  if (this.destroyed || t !== this.loadGen) return;
3263
3315
  this._descriptor = e, this.endedHandled = !1, this._endedReason = null;
3264
- let n = await s(this.opts.credential);
3316
+ let n = await c(this.opts.credential);
3265
3317
  if (this.destroyed || t !== this.loadGen) return;
3266
3318
  this.setState("loading");
3267
- 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) => {
3268
3320
  this._state !== "ended" && this._state !== "error" && this.setState(e);
3269
3321
  });
3270
3322
  if (await i.load(), this.destroyed || t !== this.loadGen) {
@@ -3286,26 +3338,26 @@ var hr = class {
3286
3338
  if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
3287
3339
  let i = e.analytics?.sid;
3288
3340
  if (!i) return;
3289
- 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);
3290
3342
  if (!o) {
3291
3343
  s && setTimeout(() => {
3292
3344
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
3293
3345
  }, 0);
3294
3346
  return;
3295
3347
  }
3296
- let c = this.opts.video, l = new In({
3348
+ let c = this.opts.video, l = new zn({
3297
3349
  endpoint: o,
3298
3350
  sid: i,
3299
3351
  player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
3300
- sdkVersion: Hn,
3301
- environment: Bn(c),
3352
+ sdkVersion: Gn,
3353
+ environment: Un(c),
3302
3354
  idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
3303
3355
  onIdle: () => this.onAnalyticsIdle(t),
3304
3356
  onBlocked: (e) => setTimeout(() => {
3305
3357
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, e));
3306
3358
  }, 0),
3307
3359
  sample: () => {
3308
- let e = this.engine?.getStats() ?? it, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
3360
+ let e = this.engine?.getStats() ?? z, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
3309
3361
  return {
3310
3362
  ...e,
3311
3363
  bufferedMs: Math.round(t * 1e3),
@@ -3319,7 +3371,7 @@ var hr = class {
3319
3371
  let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
3320
3372
  c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
3321
3373
  c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
3322
- }, 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");
3323
3375
  }
3324
3376
  currentPresentation() {
3325
3377
  let e = this.opts.video;
@@ -3347,9 +3399,9 @@ var hr = class {
3347
3399
  freshLicenseUrl: () => this.refreshLicense()
3348
3400
  }, o = this.opts.engine ?? "auto";
3349
3401
  if (o === "native") return new W(a);
3350
- if (o === "hls") return new _n(a);
3351
- 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);
3352
- 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);
3353
3405
  if (H(this.opts.video)) return new W(a);
3354
3406
  throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
3355
3407
  }
@@ -3412,7 +3464,7 @@ var hr = class {
3412
3464
  r = 0, i = !1;
3413
3465
  },
3414
3466
  onError: () => {
3415
- this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= cr && (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.`))));
3416
3468
  }
3417
3469
  });
3418
3470
  }
@@ -3426,7 +3478,7 @@ var hr = class {
3426
3478
  return;
3427
3479
  }
3428
3480
  let e = this.hiddenAtMs;
3429
- this.hiddenAtMs = null, e != null && Date.now() - e >= lr && this.resyncLiveState();
3481
+ this.hiddenAtMs = null, e != null && Date.now() - e >= mr && this.resyncLiveState();
3430
3482
  }, this.onReturnPageShow = (e) => {
3431
3483
  e.persisted && this.resyncLiveState();
3432
3484
  }, document.addEventListener("visibilitychange", this.onReturnVisible), typeof window < "u" && window.addEventListener("pageshow", this.onReturnPageShow));
@@ -3458,7 +3510,7 @@ var hr = class {
3458
3510
  scheduleRejoin(e) {
3459
3511
  this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
3460
3512
  this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
3461
- }, Math.random() * sr));
3513
+ }, Math.random() * fr));
3462
3514
  }
3463
3515
  cancelRejoin() {
3464
3516
  this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
@@ -3482,7 +3534,7 @@ var hr = class {
3482
3534
  }
3483
3535
  t.controls = !1;
3484
3536
  let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
3485
- r && r.insertBefore(n, t), n.appendChild(t), Z(n, this.opts.theme), this.container = n, this.controlBar = $n({
3537
+ r && r.insertBefore(n, t), n.appendChild(t), Jn(n, this.opts.theme), this.container = n, this.controlBar = ir({
3486
3538
  root: n,
3487
3539
  video: t,
3488
3540
  player: this,
@@ -3520,7 +3572,7 @@ var hr = class {
3520
3572
  }
3521
3573
  startStats() {
3522
3574
  this.stopStats();
3523
- let e = Math.max(500, this.opts.statsIntervalMs ?? ur);
3575
+ let e = Math.max(500, this.opts.statsIntervalMs ?? hr);
3524
3576
  this.statsTimer = setInterval(() => {
3525
3577
  if (!this.engine) return;
3526
3578
  let e = this.engine.getStats();
@@ -3531,14 +3583,14 @@ var hr = class {
3531
3583
  this.statsTimer && clearInterval(this.statsTimer), this.statsTimer = void 0;
3532
3584
  }
3533
3585
  isStaleLicenseDenial(e) {
3534
- return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== fr || 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);
3535
3587
  }
3536
3588
  scheduleLicenseRefresh() {
3537
3589
  if (this.stopRefresh(), !this._descriptor?.drmEnabled) return;
3538
3590
  typeof document < "u" && this.engine?.name === "hls" && (this.onRefocus = () => {
3539
3591
  document.visibilityState !== "visible" || this.destroyed || K(this._descriptor?.drm?.widevine?.licenseUrl) && this.refreshLicense();
3540
3592
  }, document.addEventListener("visibilitychange", this.onRefocus));
3541
- let e = this.opts.licenseRefreshMs ?? dr;
3593
+ let e = this.opts.licenseRefreshMs ?? gr;
3542
3594
  e && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
3543
3595
  }
3544
3596
  stopRefresh() {
@@ -3558,7 +3610,7 @@ var hr = class {
3558
3610
  fairplay: r
3559
3611
  }), this._descriptor = t), n;
3560
3612
  } catch (e) {
3561
- 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));
3562
3614
  return;
3563
3615
  } finally {
3564
3616
  this.refreshInFlight?.promise === t && (this.refreshInFlight = void 0);
@@ -3595,7 +3647,7 @@ var hr = class {
3595
3647
  this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
3596
3648
  }
3597
3649
  getStats() {
3598
- return this.engine?.getStats() ?? it;
3650
+ return this.engine?.getStats() ?? z;
3599
3651
  }
3600
3652
  getQualityLevels() {
3601
3653
  return this.engine?.getQualityLevels() ?? [];
@@ -3708,7 +3760,7 @@ function $(e) {
3708
3760
  }
3709
3761
  //#endregion
3710
3762
  //#region src/embed/host.ts
3711
- function gr(e) {
3763
+ function xr(e) {
3712
3764
  if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
3713
3765
  if (!e.src) throw Error("mountEmbed: opts.src is required");
3714
3766
  if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
@@ -3767,15 +3819,15 @@ function gr(e) {
3767
3819
  }
3768
3820
  //#endregion
3769
3821
  //#region src/embed/page.ts
3770
- var _r = /^[A-Za-z0-9:_.-]{1,128}$/;
3771
- function vr(e) {
3822
+ var Sr = /^[A-Za-z0-9:_.-]{1,128}$/;
3823
+ function Cr(e) {
3772
3824
  if (typeof e == "boolean") return e;
3773
3825
  if (typeof e == "object" && e) {
3774
3826
  let t = e.endpoint;
3775
3827
  return typeof t == "string" ? { endpoint: t } : {};
3776
3828
  }
3777
3829
  }
3778
- function yr() {
3830
+ function wr() {
3779
3831
  let e = window.HAVIK_EMBED_CONFIG;
3780
3832
  if (e) return {
3781
3833
  baseUrl: e.baseUrl ?? "",
@@ -3785,7 +3837,7 @@ function yr() {
3785
3837
  autoplay: e.autoplay ?? !0,
3786
3838
  muted: e.muted ?? !0,
3787
3839
  waitForLive: e.waitForLive ?? !0,
3788
- analytics: vr(e.analytics)
3840
+ analytics: Cr(e.analytics)
3789
3841
  };
3790
3842
  let t = new URLSearchParams(location.search);
3791
3843
  return {
@@ -3798,9 +3850,9 @@ function yr() {
3798
3850
  waitForLive: !0
3799
3851
  };
3800
3852
  }
3801
- async function br() {
3802
- let e = yr();
3803
- Sr();
3853
+ async function Tr() {
3854
+ let e = wr();
3855
+ Dr();
3804
3856
  let t = document.createElement("video");
3805
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);
3806
3858
  let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
@@ -3853,14 +3905,15 @@ async function br() {
3853
3905
  })), e.on("error", (e) => i({
3854
3906
  type: "oddin:error",
3855
3907
  code: e.code,
3856
- message: e.message
3908
+ message: e.message,
3909
+ ...e.country === void 0 ? {} : { country: e.country }
3857
3910
  })), e.on("autoplayblocked", () => {
3858
- i({ type: "oddin:autoplayblocked" }), xr(t, e);
3911
+ i({ type: "oddin:autoplayblocked" }), Er(t, e);
3859
3912
  });
3860
3913
  }, s = async (r) => {
3861
3914
  a?.destroy(), a = null;
3862
3915
  try {
3863
- let n = await mr({
3916
+ let n = await yr({
3864
3917
  video: t,
3865
3918
  baseUrl: e.baseUrl,
3866
3919
  matchUrn: r,
@@ -3874,11 +3927,12 @@ async function br() {
3874
3927
  let i = t.parentElement;
3875
3928
  i?.classList.contains("havik-player") && (i.style.cssText = "position:absolute;inset:0;width:100%;height:100%;aspect-ratio:auto"), o(n);
3876
3929
  } catch (e) {
3877
- let t = e instanceof n ? e.code : "INTERNAL", r = e instanceof Error ? e.message : String(e);
3930
+ let t = e instanceof n ? e.code : "INTERNAL", r = e instanceof Error ? e.message : String(e), a = e instanceof n ? e.country : void 0;
3878
3931
  i({
3879
3932
  type: "oddin:error",
3880
3933
  code: t,
3881
- message: r
3934
+ message: r,
3935
+ ...a === void 0 ? {} : { country: a }
3882
3936
  });
3883
3937
  }
3884
3938
  }, c = () => {
@@ -3922,7 +3976,7 @@ async function br() {
3922
3976
  a?.retry();
3923
3977
  break;
3924
3978
  case "oddin:load":
3925
- typeof e.matchUrn == "string" && _r.test(e.matchUrn) && s(e.matchUrn);
3979
+ typeof e.matchUrn == "string" && Sr.test(e.matchUrn) && s(e.matchUrn);
3926
3980
  break;
3927
3981
  case "oddin:destroy": c();
3928
3982
  }
@@ -3934,18 +3988,18 @@ async function br() {
3934
3988
  protocol: 1
3935
3989
  });
3936
3990
  }
3937
- function xr(e, t) {
3991
+ function Er(e, t) {
3938
3992
  if (document.getElementById("havik-tap")) return;
3939
3993
  let n = document.createElement("button");
3940
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", () => {
3941
3995
  n.remove(), t.play();
3942
3996
  }), document.body.appendChild(n);
3943
3997
  }
3944
- function Sr() {
3998
+ function Dr() {
3945
3999
  let e = document.createElement("style");
3946
4000
  e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
3947
4001
  }
3948
4002
  //#endregion
3949
- export { Un as ODDIN_THEME, n as PlaybackError, Z as applyTheme, rt as baseUrlForEnv, br as bootEmbed, Te as clearDeviceId, Ie as clearRememberedBandwidth, mr as createPlayer, D as deriveEventsBaseUrl, $e as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, _e as fetchCatalog, ye as fetchTournament, xe as flattenMatches, C as fullscreenSupported, A as getDeviceId, tt as isLowLatencyManifest, $ as isOddinMessage, De as licenseRequestHeaders, gr 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 };
3950
4004
 
3951
4005
  //# sourceMappingURL=index.js.map