@oddin-gg/havik-player 1.2.0 → 1.3.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/havik-player.global.js +16 -16
- package/dist/havik-player.global.js.map +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +41 -1
- package/dist/index.d.ts +41 -1
- package/dist/index.js +463 -283
- package/dist/index.js.map +1 -1
- package/docs/API.md +89 -39
- package/embed/index.html +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -81,41 +81,41 @@ function l(e) {
|
|
|
81
81
|
}
|
|
82
82
|
//#endregion
|
|
83
83
|
//#region src/core/waitForLive.ts
|
|
84
|
-
var u = 1e3, d = 3e4, f = 600 * 1e3, p = 300 * 1e3,
|
|
84
|
+
var u = 1e3, d = 3e4, f = 600 * 1e3, p = 300 * 1e3, m = 1e3, h = {
|
|
85
85
|
TOO_EARLY: "tooEarly",
|
|
86
86
|
UNAVAILABLE: "unavailable",
|
|
87
87
|
RATE_LIMITED: "rateLimited",
|
|
88
88
|
NETWORK: "network"
|
|
89
89
|
};
|
|
90
|
-
function
|
|
91
|
-
let t = e === !0 || e === !1 ? {} : e, n = Math.max(
|
|
90
|
+
function g(e) {
|
|
91
|
+
let t = e === !0 || e === !1 ? {} : e, n = Math.max(m, t.floorMs ?? u), r = Math.max(n, t.ceilMs ?? d), i = Math.max(0, t.imminentMs ?? f), a = Math.max(r, t.sanityFloorMs ?? p);
|
|
92
92
|
return {
|
|
93
93
|
timeoutMs: t.timeoutMs,
|
|
94
94
|
floorMs: n,
|
|
95
95
|
ceilMs: r,
|
|
96
96
|
imminentMs: i,
|
|
97
97
|
sanityFloorMs: a,
|
|
98
|
-
kickoffMs:
|
|
98
|
+
kickoffMs: _(t.kickoffAt),
|
|
99
99
|
jitter: t.jitter ?? !0,
|
|
100
100
|
onState: t.onState
|
|
101
101
|
};
|
|
102
102
|
}
|
|
103
|
-
function
|
|
103
|
+
function _(e) {
|
|
104
104
|
if (e == null) return;
|
|
105
105
|
if (typeof e == "number") return Number.isFinite(e) ? e : void 0;
|
|
106
106
|
let t = Date.parse(e);
|
|
107
107
|
return Number.isFinite(t) ? t : void 0;
|
|
108
108
|
}
|
|
109
|
-
function
|
|
109
|
+
function ee(e, t, n) {
|
|
110
110
|
return Math.min(n, Math.max(t, e));
|
|
111
111
|
}
|
|
112
|
-
function
|
|
112
|
+
function te(e) {
|
|
113
113
|
return Math.round(e * (1 + .15 * Math.random()));
|
|
114
114
|
}
|
|
115
|
-
function
|
|
115
|
+
function ne(e, t, n, r) {
|
|
116
116
|
let i = r ?? n.kickoffMs, a = i == null ? void 0 : Math.max(0, i - t), o = Math.max(n.floorMs, e ?? 0);
|
|
117
117
|
if (a == null || a <= n.imminentMs) return {
|
|
118
|
-
delay:
|
|
118
|
+
delay: ee(e ?? n.floorMs, o, n.ceilMs),
|
|
119
119
|
ttkMs: a
|
|
120
120
|
};
|
|
121
121
|
let s = Math.min(Math.floor(a / 10), n.sanityFloorMs, a);
|
|
@@ -124,7 +124,7 @@ function _(e, t, n, r) {
|
|
|
124
124
|
ttkMs: a
|
|
125
125
|
};
|
|
126
126
|
}
|
|
127
|
-
function
|
|
127
|
+
function re(e, n) {
|
|
128
128
|
return new Promise((r, i) => {
|
|
129
129
|
if (n?.aborted) {
|
|
130
130
|
i(new t("ABORTED", 0, "wait-for-live aborted"));
|
|
@@ -138,8 +138,8 @@ function v(e, n) {
|
|
|
138
138
|
n?.addEventListener("abort", a, { once: !0 });
|
|
139
139
|
});
|
|
140
140
|
}
|
|
141
|
-
async function
|
|
142
|
-
let a =
|
|
141
|
+
async function v(e, n, r) {
|
|
142
|
+
let a = g(n), o = Date.now(), s = a.timeoutMs == null ? Infinity : o + a.timeoutMs, c = 0, l;
|
|
143
143
|
for (;;) {
|
|
144
144
|
if (r?.aborted) throw new t("ABORTED", 0, "wait-for-live aborted");
|
|
145
145
|
try {
|
|
@@ -147,37 +147,37 @@ async function y(e, n, r) {
|
|
|
147
147
|
} catch (e) {
|
|
148
148
|
if (!(e instanceof t) || !i(e.code)) throw e;
|
|
149
149
|
c += 1, e.liveStartsAtMs != null && Number.isFinite(e.liveStartsAtMs) && (l = e.liveStartsAtMs);
|
|
150
|
-
let n = Date.now(), u =
|
|
151
|
-
if (a.jitter && (f =
|
|
150
|
+
let n = Date.now(), u = ne(e.retryAfterMs, n, a, l), d = u.ttkMs, f = u.delay;
|
|
151
|
+
if (a.jitter && (f = te(f)), n + f > s) throw new t("TIMEOUT", e.httpStatus, `timed out after ${a.timeoutMs}ms waiting for the stream to go live`, {
|
|
152
152
|
retryAfterMs: e.retryAfterMs,
|
|
153
153
|
cause: e
|
|
154
154
|
});
|
|
155
155
|
a.onState?.({
|
|
156
|
-
phase:
|
|
156
|
+
phase: h[e.code] ?? "unavailable",
|
|
157
157
|
retryInMs: f,
|
|
158
158
|
attempt: c,
|
|
159
159
|
elapsedMs: n - o,
|
|
160
160
|
ttkMs: d
|
|
161
|
-
}), await
|
|
161
|
+
}), await re(f, r);
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
165
|
//#endregion
|
|
166
166
|
//#region src/core/resolve.ts
|
|
167
|
-
async function
|
|
167
|
+
async function y(e) {
|
|
168
168
|
if (!e.matchUrn || typeof e.matchUrn != "string") throw new t("INVALID_URN", 0, "resolveStream: a non-empty matchUrn is required");
|
|
169
169
|
let n = await c(o(e.baseUrl, `/v1/playback/${encodeURIComponent(e.matchUrn)}`), {
|
|
170
170
|
credential: e.credential,
|
|
171
171
|
signal: e.signal
|
|
172
172
|
});
|
|
173
|
-
if (!n.ok) throw await
|
|
174
|
-
return
|
|
173
|
+
if (!n.ok) throw await ie(n);
|
|
174
|
+
return oe(await n.json(), e.matchUrn);
|
|
175
175
|
}
|
|
176
|
-
function
|
|
177
|
-
let t = () =>
|
|
178
|
-
return e.waitForLive ?
|
|
176
|
+
function b(e) {
|
|
177
|
+
let t = () => y(e);
|
|
178
|
+
return e.waitForLive ? v(t, e.waitForLive, e.signal) : t();
|
|
179
179
|
}
|
|
180
|
-
async function
|
|
180
|
+
async function ie(e) {
|
|
181
181
|
let r = s(e.headers.get("retry-after")), i = e.headers.get("x-request-id") ?? e.headers.get("x-amzn-requestid") ?? void 0, a = e.statusText || `HTTP ${e.status}`, o, c;
|
|
182
182
|
try {
|
|
183
183
|
let t = await e.json();
|
|
@@ -193,7 +193,7 @@ async function re(e) {
|
|
|
193
193
|
liveStartsAtMs: c
|
|
194
194
|
});
|
|
195
195
|
}
|
|
196
|
-
var
|
|
196
|
+
var ae = /* @__PURE__ */ new Set([
|
|
197
197
|
"matchUrn",
|
|
198
198
|
"protocol",
|
|
199
199
|
"drmEnabled",
|
|
@@ -203,7 +203,7 @@ var ie = /* @__PURE__ */ new Set([
|
|
|
203
203
|
"liveStartsAt",
|
|
204
204
|
"expiresAt"
|
|
205
205
|
]);
|
|
206
|
-
function
|
|
206
|
+
function x(e, n) {
|
|
207
207
|
let r;
|
|
208
208
|
try {
|
|
209
209
|
r = new URL(n);
|
|
@@ -213,29 +213,29 @@ function S(e, n) {
|
|
|
213
213
|
if (r.protocol !== "https:" && r.protocol !== "http:") throw new t("INTERNAL", 0, `playback ${e} has a disallowed scheme: ${r.protocol}`);
|
|
214
214
|
return n;
|
|
215
215
|
}
|
|
216
|
-
function
|
|
216
|
+
function oe(e, n) {
|
|
217
217
|
if (!e.manifestUrl) throw new t("INTERNAL", 0, "playback response is missing manifestUrl");
|
|
218
218
|
let r = e.drmEnabled ?? !!e.drm, i = {
|
|
219
219
|
matchUrn: e.matchUrn ?? n,
|
|
220
220
|
protocol: "hls",
|
|
221
221
|
drmEnabled: r,
|
|
222
|
-
manifestUrl:
|
|
222
|
+
manifestUrl: x("manifestUrl", e.manifestUrl),
|
|
223
223
|
serverTime: e.serverTime ?? ""
|
|
224
224
|
};
|
|
225
225
|
if (e.liveStartsAt && (i.liveStartsAt = e.liveStartsAt), r && e.drm) {
|
|
226
226
|
let t = {};
|
|
227
|
-
e.drm.widevine?.licenseUrl && (t.widevine = { licenseUrl:
|
|
228
|
-
licenseUrl:
|
|
229
|
-
certificateUrl:
|
|
227
|
+
e.drm.widevine?.licenseUrl && (t.widevine = { licenseUrl: x("widevine licenseUrl", e.drm.widevine.licenseUrl) }), e.drm.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && (t.fairplay = {
|
|
228
|
+
licenseUrl: x("fairplay licenseUrl", e.drm.fairplay.licenseUrl),
|
|
229
|
+
certificateUrl: x("fairplay certificateUrl", e.drm.fairplay.certificateUrl)
|
|
230
230
|
}), (t.widevine || t.fairplay) && (i.drm = t);
|
|
231
231
|
}
|
|
232
232
|
let a = {};
|
|
233
|
-
for (let [t, n] of Object.entries(e))
|
|
233
|
+
for (let [t, n] of Object.entries(e)) ae.has(t) || (a[t] = n);
|
|
234
234
|
return Object.keys(a).length > 0 && (i.extensions = a), i;
|
|
235
235
|
}
|
|
236
236
|
//#endregion
|
|
237
237
|
//#region src/core/catalog.ts
|
|
238
|
-
async function
|
|
238
|
+
async function se(e) {
|
|
239
239
|
let r = new URLSearchParams();
|
|
240
240
|
e.status && r.set("status", Array.isArray(e.status) ? e.status.join(",") : e.status), e.sport && r.set("sport", e.sport);
|
|
241
241
|
let i = r.toString(), a = o(e.baseUrl, "/v1/catalog" + (i ? `?${i}` : "")), s = new Headers();
|
|
@@ -252,12 +252,12 @@ async function oe(e) {
|
|
|
252
252
|
};
|
|
253
253
|
if (!l.ok) throw new t(n(l.status), l.status, `catalog request failed (HTTP ${l.status})`);
|
|
254
254
|
return {
|
|
255
|
-
tournaments:
|
|
255
|
+
tournaments: ce(await l.json()),
|
|
256
256
|
etag: l.headers.get("etag") ?? void 0,
|
|
257
257
|
notModified: !1
|
|
258
258
|
};
|
|
259
259
|
}
|
|
260
|
-
function
|
|
260
|
+
function ce(e) {
|
|
261
261
|
return (e.tournaments ?? []).map((e) => {
|
|
262
262
|
let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
|
|
263
263
|
return {
|
|
@@ -277,7 +277,7 @@ function se(e) {
|
|
|
277
277
|
};
|
|
278
278
|
});
|
|
279
279
|
}
|
|
280
|
-
async function
|
|
280
|
+
async function le(e) {
|
|
281
281
|
let r = o(e.baseUrl, `/v1/tournaments/${encodeURIComponent(e.urn)}`), i = new Headers();
|
|
282
282
|
e.etag && i.set("If-None-Match", e.etag);
|
|
283
283
|
let a = await c(r, {
|
|
@@ -296,13 +296,13 @@ async function ce(e) {
|
|
|
296
296
|
};
|
|
297
297
|
if (!a.ok) throw new t(n(a.status), a.status, `tournament request failed (HTTP ${a.status})`);
|
|
298
298
|
return {
|
|
299
|
-
tournament:
|
|
299
|
+
tournament: S(await a.json()),
|
|
300
300
|
etag: a.headers.get("etag") ?? void 0,
|
|
301
301
|
notModified: !1,
|
|
302
302
|
notFound: !1
|
|
303
303
|
};
|
|
304
304
|
}
|
|
305
|
-
function
|
|
305
|
+
function S(e) {
|
|
306
306
|
let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
|
|
307
307
|
return {
|
|
308
308
|
urn: t,
|
|
@@ -320,12 +320,12 @@ function le(e) {
|
|
|
320
320
|
}))
|
|
321
321
|
};
|
|
322
322
|
}
|
|
323
|
-
function
|
|
323
|
+
function C(e) {
|
|
324
324
|
return e.tournaments.flatMap((e) => e.matches);
|
|
325
325
|
}
|
|
326
326
|
//#endregion
|
|
327
327
|
//#region src/core/poll.ts
|
|
328
|
-
function
|
|
328
|
+
function w(e) {
|
|
329
329
|
let r = Math.max(2e3, e.intervalMs ?? 1e4), i = new AbortController(), a, s, l, u = !1, d = () => {
|
|
330
330
|
u || (a = setTimeout(f, r));
|
|
331
331
|
}, f = async () => {
|
|
@@ -360,7 +360,7 @@ function C(e) {
|
|
|
360
360
|
}
|
|
361
361
|
//#endregion
|
|
362
362
|
//#region src/core/events.ts
|
|
363
|
-
function
|
|
363
|
+
function T(e) {
|
|
364
364
|
let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = new AbortController(), i = !1, s = (e) => new Promise((t) => {
|
|
365
365
|
if (r.signal.aborted) return t();
|
|
366
366
|
let n = setTimeout(t, e);
|
|
@@ -427,7 +427,7 @@ function w(e) {
|
|
|
427
427
|
i || (i = !0, r.abort());
|
|
428
428
|
} };
|
|
429
429
|
}
|
|
430
|
-
function
|
|
430
|
+
function E(e) {
|
|
431
431
|
try {
|
|
432
432
|
let t = new URL(e);
|
|
433
433
|
return t.hostname = `events.${t.hostname}`, t.pathname = "", t.search = "", t.origin;
|
|
@@ -437,27 +437,27 @@ function T(e) {
|
|
|
437
437
|
}
|
|
438
438
|
//#endregion
|
|
439
439
|
//#region src/core/drm/deviceId.ts
|
|
440
|
-
var
|
|
441
|
-
function
|
|
442
|
-
if (
|
|
440
|
+
var D = "havik.player.deviceId", O;
|
|
441
|
+
function k() {
|
|
442
|
+
if (O) return O;
|
|
443
443
|
try {
|
|
444
|
-
let e = globalThis.localStorage?.getItem(
|
|
445
|
-
if (e) return
|
|
444
|
+
let e = globalThis.localStorage?.getItem(D);
|
|
445
|
+
if (e) return O = e, e;
|
|
446
446
|
} catch {}
|
|
447
|
-
let e =
|
|
448
|
-
|
|
447
|
+
let e = de();
|
|
448
|
+
O = e;
|
|
449
449
|
try {
|
|
450
|
-
globalThis.localStorage?.setItem(
|
|
450
|
+
globalThis.localStorage?.setItem(D, e);
|
|
451
451
|
} catch {}
|
|
452
452
|
return e;
|
|
453
453
|
}
|
|
454
|
-
function
|
|
455
|
-
|
|
454
|
+
function ue() {
|
|
455
|
+
O = void 0;
|
|
456
456
|
try {
|
|
457
|
-
globalThis.localStorage?.removeItem(
|
|
457
|
+
globalThis.localStorage?.removeItem(D);
|
|
458
458
|
} catch {}
|
|
459
459
|
}
|
|
460
|
-
function
|
|
460
|
+
function de() {
|
|
461
461
|
let e = globalThis.crypto;
|
|
462
462
|
if (e && typeof e.randomUUID == "function") return e.randomUUID();
|
|
463
463
|
let t = /* @__PURE__ */ new Uint8Array(16);
|
|
@@ -469,28 +469,121 @@ function A() {
|
|
|
469
469
|
}
|
|
470
470
|
//#endregion
|
|
471
471
|
//#region src/core/drm/headers.ts
|
|
472
|
-
function
|
|
472
|
+
function fe(e, t, n = {}) {
|
|
473
473
|
let r = {
|
|
474
474
|
"x-api-key": t.apiKey,
|
|
475
475
|
"X-Match-Urn": e.matchUrn,
|
|
476
|
-
"X-Device-Id": n.deviceId ??
|
|
476
|
+
"X-Device-Id": n.deviceId ?? k(),
|
|
477
477
|
"Content-Type": "application/octet-stream"
|
|
478
478
|
};
|
|
479
479
|
return n.userId && (r["X-User-Id"] = n.userId), r;
|
|
480
480
|
}
|
|
481
481
|
//#endregion
|
|
482
|
+
//#region src/core/drm/support.ts
|
|
483
|
+
var A = 5e3, j = "video/mp4; codecs=\"avc1.42E01E\"", M = "audio/mp4; codecs=\"mp4a.40.2\"", N = {
|
|
484
|
+
widevine: ["com.widevine.alpha"],
|
|
485
|
+
fairplay: ["com.apple.fps"]
|
|
486
|
+
};
|
|
487
|
+
function P(e) {
|
|
488
|
+
return e === "fairplay" ? [{
|
|
489
|
+
initDataTypes: [
|
|
490
|
+
"sinf",
|
|
491
|
+
"skd",
|
|
492
|
+
"cenc"
|
|
493
|
+
],
|
|
494
|
+
videoCapabilities: [{
|
|
495
|
+
contentType: j,
|
|
496
|
+
robustness: "",
|
|
497
|
+
encryptionScheme: "cbcs"
|
|
498
|
+
}],
|
|
499
|
+
audioCapabilities: [{
|
|
500
|
+
contentType: M,
|
|
501
|
+
robustness: "",
|
|
502
|
+
encryptionScheme: "cbcs"
|
|
503
|
+
}]
|
|
504
|
+
}] : [{
|
|
505
|
+
initDataTypes: ["cenc"],
|
|
506
|
+
videoCapabilities: [{
|
|
507
|
+
contentType: j,
|
|
508
|
+
robustness: "SW_SECURE_DECODE",
|
|
509
|
+
encryptionScheme: "cbcs"
|
|
510
|
+
}],
|
|
511
|
+
audioCapabilities: [{
|
|
512
|
+
contentType: M,
|
|
513
|
+
robustness: "SW_SECURE_CRYPTO",
|
|
514
|
+
encryptionScheme: "cbcs"
|
|
515
|
+
}]
|
|
516
|
+
}];
|
|
517
|
+
}
|
|
518
|
+
function F(e, t) {
|
|
519
|
+
return new Promise((n, r) => {
|
|
520
|
+
let i = setTimeout(() => r(/* @__PURE__ */ Error("probe-timeout")), t);
|
|
521
|
+
e.then((e) => {
|
|
522
|
+
clearTimeout(i), n(e);
|
|
523
|
+
}, (e) => {
|
|
524
|
+
clearTimeout(i), r(e);
|
|
525
|
+
});
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
async function I(e = {}) {
|
|
529
|
+
let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? A, r = {};
|
|
530
|
+
if (typeof window < "u" && window.isSecureContext === !1) return {
|
|
531
|
+
verdict: "insecure-context",
|
|
532
|
+
detail: r
|
|
533
|
+
};
|
|
534
|
+
let i = typeof navigator < "u" ? navigator.requestMediaKeySystemAccess?.bind(navigator) : void 0;
|
|
535
|
+
if (!i) return {
|
|
536
|
+
verdict: "no-cdm",
|
|
537
|
+
detail: r
|
|
538
|
+
};
|
|
539
|
+
let a = !1, o = !1, s = Date.now() + n, c = () => Math.max(1, s - Date.now());
|
|
540
|
+
for (let e of t) {
|
|
541
|
+
let t = N[e];
|
|
542
|
+
if (!t) {
|
|
543
|
+
r[e] = "unknown system";
|
|
544
|
+
continue;
|
|
545
|
+
}
|
|
546
|
+
for (let n of t) {
|
|
547
|
+
if (Date.now() >= s) {
|
|
548
|
+
a = !0, r[e] ??= `${n}: probe-timeout`;
|
|
549
|
+
break;
|
|
550
|
+
}
|
|
551
|
+
try {
|
|
552
|
+
return await F((await F(i(n, P(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
|
|
553
|
+
verdict: "supported",
|
|
554
|
+
system: e,
|
|
555
|
+
detail: r
|
|
556
|
+
};
|
|
557
|
+
} catch (t) {
|
|
558
|
+
let i = t;
|
|
559
|
+
r[e] = `${n}: ${(i?.name && i.name !== "Error" ? i.name : i?.message) || String(t)}`, i?.message === "probe-timeout" && (a = !0), i?.name === "SecurityError" && (o = !0);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
return o ? {
|
|
564
|
+
verdict: "blocked-by-policy",
|
|
565
|
+
detail: r
|
|
566
|
+
} : a ? {
|
|
567
|
+
verdict: "probe-timeout",
|
|
568
|
+
detail: r
|
|
569
|
+
} : {
|
|
570
|
+
verdict: "no-cdm",
|
|
571
|
+
detail: r
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
//#endregion
|
|
482
575
|
//#region src/core/manifest.ts
|
|
483
|
-
var
|
|
484
|
-
function
|
|
485
|
-
return
|
|
576
|
+
var L = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
|
|
577
|
+
function R(e) {
|
|
578
|
+
return L.test(e);
|
|
486
579
|
}
|
|
487
580
|
//#endregion
|
|
488
581
|
//#region src/core/stats.ts
|
|
489
|
-
var
|
|
490
|
-
function
|
|
582
|
+
var z = { droppedFrames: 0 };
|
|
583
|
+
function B(e) {
|
|
491
584
|
return e.getVideoPlaybackQuality?.()?.droppedVideoFrames ?? 0;
|
|
492
585
|
}
|
|
493
|
-
function
|
|
586
|
+
function V(e, t) {
|
|
494
587
|
let n = [
|
|
495
588
|
["playing", () => t("playing")],
|
|
496
589
|
["waiting", () => t("buffering")],
|
|
@@ -506,29 +599,132 @@ function I(e, t) {
|
|
|
506
599
|
};
|
|
507
600
|
}
|
|
508
601
|
//#endregion
|
|
602
|
+
//#region src/core/engine/native.ts
|
|
603
|
+
function H(e) {
|
|
604
|
+
return !!(e ?? (typeof document < "u" ? document.createElement("video") : void 0))?.canPlayType("application/vnd.apple.mpegurl");
|
|
605
|
+
}
|
|
606
|
+
var U = class {
|
|
607
|
+
name = "native";
|
|
608
|
+
deps;
|
|
609
|
+
onLoaded;
|
|
610
|
+
onError;
|
|
611
|
+
constructor(e) {
|
|
612
|
+
this.deps = e;
|
|
613
|
+
}
|
|
614
|
+
async load() {
|
|
615
|
+
let { video: e, descriptor: n, emit: r } = this.deps;
|
|
616
|
+
if (n.drmEnabled) {
|
|
617
|
+
if (!n.drm?.fairplay) {
|
|
618
|
+
r({
|
|
619
|
+
type: "error",
|
|
620
|
+
error: new t("INTERNAL", 0, "native HLS engine cannot satisfy this DRM (Widevine requires the hls.js engine); use engine \"auto\"/\"hls\" on a Widevine-capable browser"),
|
|
621
|
+
fatal: !0
|
|
622
|
+
});
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
r({
|
|
626
|
+
type: "error",
|
|
627
|
+
error: new t("INTERNAL", 0, "the native HLS fallback engine does not drive FairPlay EME; relying on OS-trusted passthrough"),
|
|
628
|
+
fatal: !1
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
this.onLoaded = () => r({ type: "ready" }), this.onError = () => r({
|
|
632
|
+
type: "error",
|
|
633
|
+
error: new t("INTERNAL", 0, "native HLS playback error"),
|
|
634
|
+
fatal: !0
|
|
635
|
+
}), e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = n.manifestUrl, e.load();
|
|
636
|
+
}
|
|
637
|
+
setLicenseUrls(e) {}
|
|
638
|
+
getQualityLevels() {
|
|
639
|
+
return [];
|
|
640
|
+
}
|
|
641
|
+
getCurrentQuality() {
|
|
642
|
+
return -1;
|
|
643
|
+
}
|
|
644
|
+
setQuality(e) {}
|
|
645
|
+
setMaxBitrate(e) {}
|
|
646
|
+
getAudioTracks() {
|
|
647
|
+
let e = this.deps.video.audioTracks;
|
|
648
|
+
return e ? Array.from({ length: e.length }, (t, n) => {
|
|
649
|
+
let r = e[n];
|
|
650
|
+
return {
|
|
651
|
+
id: n,
|
|
652
|
+
name: r.label || r.language || `Audio ${n + 1}`,
|
|
653
|
+
lang: r.language || void 0,
|
|
654
|
+
default: r.enabled
|
|
655
|
+
};
|
|
656
|
+
}) : [];
|
|
657
|
+
}
|
|
658
|
+
setAudioTrack(e) {
|
|
659
|
+
let t = this.deps.video.audioTracks;
|
|
660
|
+
if (t) for (let n = 0; n < t.length; n += 1) t[n].enabled = n === e;
|
|
661
|
+
}
|
|
662
|
+
getTextTracks() {
|
|
663
|
+
let e = this.deps.video.textTracks;
|
|
664
|
+
return Array.from({ length: e.length }, (t, n) => {
|
|
665
|
+
let r = e[n];
|
|
666
|
+
return {
|
|
667
|
+
id: n,
|
|
668
|
+
name: r.label || r.language || `Text ${n + 1}`,
|
|
669
|
+
lang: r.language || void 0
|
|
670
|
+
};
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
setTextTrack(e) {
|
|
674
|
+
let t = this.deps.video.textTracks;
|
|
675
|
+
for (let n = 0; n < t.length; n += 1) t[n].mode = n === e ? "showing" : "disabled";
|
|
676
|
+
}
|
|
677
|
+
seekToLive() {
|
|
678
|
+
let e = this.deps.video;
|
|
679
|
+
e.seekable.length > 0 && (e.currentTime = e.seekable.end(e.seekable.length - 1));
|
|
680
|
+
}
|
|
681
|
+
getStats() {
|
|
682
|
+
let e = this.deps.video, t = { droppedFrames: B(e) };
|
|
683
|
+
return e.duration === Infinity && (t.isLive = !0, e.seekable.length > 0 && (t.atLiveEdge = e.currentTime >= e.seekable.end(e.seekable.length - 1) - 2)), t;
|
|
684
|
+
}
|
|
685
|
+
stop() {
|
|
686
|
+
try {
|
|
687
|
+
this.deps.video.pause();
|
|
688
|
+
} catch {}
|
|
689
|
+
}
|
|
690
|
+
destroy() {
|
|
691
|
+
let { video: e } = this.deps;
|
|
692
|
+
this.onLoaded && e.removeEventListener("loadedmetadata", this.onLoaded), this.onError && e.removeEventListener("error", this.onError);
|
|
693
|
+
try {
|
|
694
|
+
e.pause();
|
|
695
|
+
} catch {}
|
|
696
|
+
e.removeAttribute("src");
|
|
697
|
+
try {
|
|
698
|
+
e.load();
|
|
699
|
+
} catch {}
|
|
700
|
+
}
|
|
701
|
+
};
|
|
702
|
+
//#endregion
|
|
509
703
|
//#region src/core/engine/hls.ts
|
|
510
|
-
function
|
|
704
|
+
function pe() {
|
|
511
705
|
return e.isSupported();
|
|
512
706
|
}
|
|
513
|
-
var
|
|
514
|
-
function
|
|
707
|
+
var me = 3, he = 5, ge = 3, _e = 3e4, ve = 12e3, ye = 3e3, be = 6e3, xe = 2, Se = 9, Ce = .5;
|
|
708
|
+
function W(e) {
|
|
515
709
|
if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
|
|
516
710
|
delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
|
|
517
711
|
return;
|
|
518
712
|
}
|
|
519
|
-
e.liveSyncDuration ??=
|
|
520
|
-
let t = Math.max(12, e.liveSyncDuration +
|
|
521
|
-
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t),
|
|
713
|
+
e.liveSyncDuration ??= xe;
|
|
714
|
+
let t = Math.max(12, e.liveSyncDuration + Se);
|
|
715
|
+
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), we(e, e.liveSyncDuration);
|
|
522
716
|
}
|
|
523
|
-
function
|
|
717
|
+
function we(e, t) {
|
|
524
718
|
let n = (e, t, n) => Math.min(n, Math.max(t, e));
|
|
525
719
|
e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
|
|
526
720
|
}
|
|
527
|
-
var
|
|
721
|
+
var Te = class {
|
|
528
722
|
name = "hls";
|
|
529
723
|
hls = null;
|
|
530
724
|
deps;
|
|
531
725
|
licenseUrl;
|
|
726
|
+
fairplayLicenseUrl;
|
|
727
|
+
fairplayCertUrl;
|
|
532
728
|
detectedLowLatency = !1;
|
|
533
729
|
mediaRecoveries = 0;
|
|
534
730
|
networkRecoveries = 0;
|
|
@@ -547,14 +743,14 @@ var _e = class {
|
|
|
547
743
|
savedLiveMaxLatency;
|
|
548
744
|
savedMaxSyncRate;
|
|
549
745
|
constructor(e) {
|
|
550
|
-
this.deps = e, this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl;
|
|
746
|
+
this.deps = e, this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.fairplayLicenseUrl = e.descriptor.drm?.fairplay?.licenseUrl, this.fairplayCertUrl = e.descriptor.drm?.fairplay?.certificateUrl;
|
|
551
747
|
}
|
|
552
748
|
async load() {
|
|
553
|
-
let { descriptor: e, snapToLiveOnRefocus: n, video: r, emit: i } = this.deps;
|
|
554
|
-
if (e.drmEnabled && !
|
|
749
|
+
let { descriptor: e, snapToLiveOnRefocus: n, video: r, emit: i } = this.deps, a = H(r), o = !!e.drm?.widevine?.licenseUrl && !a, s = !!(e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && a);
|
|
750
|
+
if (e.drmEnabled && !o && !s) {
|
|
555
751
|
i({
|
|
556
752
|
type: "error",
|
|
557
|
-
error: new t("INTERNAL", 0, "DRM is required but
|
|
753
|
+
error: new t("INTERNAL", 0, "DRM is required but none of the stream’s key systems is usable on this platform (WebKit takes FairPlay only; other browsers take Widevine only)"),
|
|
558
754
|
fatal: !0
|
|
559
755
|
});
|
|
560
756
|
return;
|
|
@@ -574,10 +770,10 @@ var _e = class {
|
|
|
574
770
|
let t = e.liveSyncPosition;
|
|
575
771
|
if (typeof t != "number" || !Number.isFinite(t)) return;
|
|
576
772
|
let { video: n } = this.deps;
|
|
577
|
-
n.currentTime <= t +
|
|
773
|
+
n.currentTime <= t + Ce || (n.currentTime = t);
|
|
578
774
|
}
|
|
579
775
|
startHls() {
|
|
580
|
-
let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps, u = n.drmEnabled && !!n.drm?.widevine?.licenseUrl, d = {
|
|
776
|
+
let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps, u = n.drmEnabled && !!(n.drm?.widevine?.licenseUrl || n.drm?.fairplay?.licenseUrl), d = !!(this.fairplayLicenseUrl && this.fairplayCertUrl && H(t)), f = {
|
|
581
777
|
debug: s === !0,
|
|
582
778
|
enableWorker: !o,
|
|
583
779
|
lowLatencyMode: o,
|
|
@@ -588,44 +784,89 @@ var _e = class {
|
|
|
588
784
|
capLevelToPlayerSize: !0,
|
|
589
785
|
...u ? {
|
|
590
786
|
emeEnabled: !0,
|
|
591
|
-
drmSystems: {
|
|
592
|
-
|
|
787
|
+
drmSystems: {
|
|
788
|
+
...this.licenseUrl ? { "com.widevine.alpha": { licenseUrl: this.licenseUrl } } : {},
|
|
789
|
+
...d ? { "com.apple.fps": {
|
|
790
|
+
licenseUrl: this.fairplayLicenseUrl,
|
|
791
|
+
serverCertificateUrl: this.fairplayCertUrl,
|
|
792
|
+
generateRequest(e, t, n) {
|
|
793
|
+
if (t) return {
|
|
794
|
+
initDataType: e,
|
|
795
|
+
initData: t
|
|
796
|
+
};
|
|
797
|
+
let r = n.decryptdata?.uri;
|
|
798
|
+
if (r?.startsWith("skd://")) {
|
|
799
|
+
let e = /* @__PURE__ */ new ArrayBuffer(r.length * 2), t = new DataView(e);
|
|
800
|
+
for (let e = 0; e < r.length; e++) t.setUint16(e * 2, r.charCodeAt(e), !0);
|
|
801
|
+
return {
|
|
802
|
+
initDataType: "skd",
|
|
803
|
+
initData: e
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
return {
|
|
807
|
+
initDataType: e,
|
|
808
|
+
initData: t
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
} } : {}
|
|
812
|
+
},
|
|
813
|
+
drmSystemOptions: d ? {
|
|
814
|
+
videoEncryptionScheme: "cbcs",
|
|
815
|
+
audioEncryptionScheme: "cbcs"
|
|
816
|
+
} : {
|
|
593
817
|
videoRobustness: "SW_SECURE_DECODE",
|
|
594
818
|
audioRobustness: "SW_SECURE_CRYPTO",
|
|
595
819
|
videoEncryptionScheme: "cbcs",
|
|
596
820
|
audioEncryptionScheme: "cbcs"
|
|
597
821
|
},
|
|
822
|
+
...d ? { requestMediaKeySystemAccessFunc: (e, t) => {
|
|
823
|
+
let n = e === "com.apple.fps" ? t.map((e) => ({
|
|
824
|
+
...e,
|
|
825
|
+
initDataTypes: [.../* @__PURE__ */ new Set([...e.initDataTypes ?? [], "skd"])]
|
|
826
|
+
})) : t;
|
|
827
|
+
return navigator.requestMediaKeySystemAccess(e, n);
|
|
828
|
+
} } : {},
|
|
598
829
|
licenseXhrSetup: (e, t) => {
|
|
599
|
-
|
|
830
|
+
let o = t.includes("/license/fairplay") ? this.fairplayLicenseUrl ?? t : this.licenseUrl ?? t;
|
|
831
|
+
e.open("POST", o, !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);
|
|
600
832
|
}
|
|
601
833
|
} : {},
|
|
602
834
|
...c
|
|
603
835
|
};
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
836
|
+
if (d) {
|
|
837
|
+
let e = f.xhrSetup, t = () => this.fairplayCertUrl;
|
|
838
|
+
f.xhrSetup = (n, i) => {
|
|
839
|
+
let a = e?.(n, i), o = () => {
|
|
840
|
+
i === t() && (n.readyState === XMLHttpRequest.UNSENT && n.open("GET", i, !0), n.setRequestHeader("x-api-key", r.apiKey));
|
|
841
|
+
};
|
|
842
|
+
return a && typeof a.then == "function" ? a.then(() => o()) : (o(), a);
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
W(f);
|
|
846
|
+
let p = new e(f);
|
|
847
|
+
this.hls = p, p.on(e.Events.MANIFEST_PARSED, () => {
|
|
607
848
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, l({ type: "ready" });
|
|
608
|
-
}),
|
|
849
|
+
}), p.on(e.Events.FRAG_BUFFERED, () => {
|
|
609
850
|
(this.mediaRecoveries > 0 || this.networkRecoveries > 0 || this.licenseRecoveries > 0) && !this.recoveryResetTimer && (this.recoveryResetTimer = setTimeout(() => {
|
|
610
851
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.recoveryResetTimer = null;
|
|
611
|
-
},
|
|
612
|
-
}),
|
|
852
|
+
}, _e));
|
|
853
|
+
}), p.on(e.Events.LEVEL_LOADED, (e, t) => {
|
|
613
854
|
if (this.detectedLowLatency) return;
|
|
614
855
|
let n = t.details;
|
|
615
856
|
(n?.partList?.length || (n?.partTarget ?? 0) > 0) && (this.detectedLowLatency = !0, l({
|
|
616
857
|
type: "lowLatencyDetected",
|
|
617
858
|
value: !0
|
|
618
859
|
}));
|
|
619
|
-
}),
|
|
860
|
+
}), p.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.endWatchdog = setInterval(() => this.checkEndStale(), ye), p.on(e.Events.LEVEL_SWITCHED, (e, t) => l({
|
|
620
861
|
type: "qualitychange",
|
|
621
862
|
index: t.level
|
|
622
|
-
})),
|
|
863
|
+
})), p.on(e.Events.AUDIO_TRACK_SWITCHED, (e, t) => l({
|
|
623
864
|
type: "audiotrackchange",
|
|
624
865
|
id: t.id
|
|
625
|
-
})),
|
|
866
|
+
})), p.on(e.Events.SUBTITLE_TRACK_SWITCH, (e, t) => l({
|
|
626
867
|
type: "texttrackchange",
|
|
627
868
|
id: t.id
|
|
628
|
-
})),
|
|
869
|
+
})), p.on(e.Events.ERROR, (e, t) => this.onError(t)), p.loadSource(n.manifestUrl), p.attachMedia(t);
|
|
629
870
|
}
|
|
630
871
|
getQualityLevels() {
|
|
631
872
|
return this.hls ? this.hls.levels.map((e, t) => ({
|
|
@@ -680,12 +921,12 @@ var _e = class {
|
|
|
680
921
|
let e = this.hls;
|
|
681
922
|
e && typeof e.liveSyncPosition == "number" && (this.deps.video.currentTime = e.liveSyncPosition);
|
|
682
923
|
}
|
|
683
|
-
|
|
684
|
-
this.licenseUrl = e;
|
|
924
|
+
setLicenseUrls(e) {
|
|
925
|
+
e.widevine && (this.licenseUrl = e.widevine), e.fairplay && (this.fairplayLicenseUrl = e.fairplay);
|
|
685
926
|
}
|
|
686
927
|
getStats() {
|
|
687
928
|
let e = this.hls, t = {
|
|
688
|
-
droppedFrames:
|
|
929
|
+
droppedFrames: B(this.deps.video),
|
|
689
930
|
lowLatency: this.detectedLowLatency
|
|
690
931
|
};
|
|
691
932
|
if (e) {
|
|
@@ -714,7 +955,7 @@ var _e = class {
|
|
|
714
955
|
return;
|
|
715
956
|
}
|
|
716
957
|
let e = Date.now() - this.lastAdvanceMs;
|
|
717
|
-
!this.chaseSuspended && e >
|
|
958
|
+
!this.chaseSuspended && e > be && this.suspendChasing(), e > ve && this.emitEnded("stalled");
|
|
718
959
|
}
|
|
719
960
|
suspendChasing() {
|
|
720
961
|
let e = this.hls;
|
|
@@ -756,7 +997,7 @@ var _e = class {
|
|
|
756
997
|
scheduleLicenseRetry(t) {
|
|
757
998
|
if (!(t.details === e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED || t.details === e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED)) return !1;
|
|
758
999
|
let n = t.response?.code ?? 0;
|
|
759
|
-
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >=
|
|
1000
|
+
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= ge) return !1;
|
|
760
1001
|
this.licenseRecoveries += 1;
|
|
761
1002
|
let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
|
|
762
1003
|
return this.licenseRetryTimer = setTimeout(() => {
|
|
@@ -784,7 +1025,7 @@ var _e = class {
|
|
|
784
1025
|
return;
|
|
785
1026
|
}
|
|
786
1027
|
if (t.type === e.ErrorTypes.NETWORK_ERROR) {
|
|
787
|
-
if (this.networkRecoveries <
|
|
1028
|
+
if (this.networkRecoveries < he) {
|
|
788
1029
|
this.networkRecoveries += 1;
|
|
789
1030
|
let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
|
|
790
1031
|
this.networkRetryTimer = setTimeout(() => {
|
|
@@ -800,7 +1041,7 @@ var _e = class {
|
|
|
800
1041
|
return;
|
|
801
1042
|
}
|
|
802
1043
|
if (t.type === e.ErrorTypes.MEDIA_ERROR) {
|
|
803
|
-
if (this.mediaRecoveries <
|
|
1044
|
+
if (this.mediaRecoveries < me) {
|
|
804
1045
|
this.mediaRecoveries += 1, n.recoverMediaError();
|
|
805
1046
|
return;
|
|
806
1047
|
}
|
|
@@ -822,107 +1063,6 @@ var _e = class {
|
|
|
822
1063
|
let r = e.response?.code ?? 0, i = e.details ?? e.type, a = e.reason ?? e.error?.message ?? "";
|
|
823
1064
|
return new t(r === 401 ? "UNAUTHORIZED" : r === 403 || n === "DRM" ? "FORBIDDEN" : "INTERNAL", r, `${n} error: ${i}${a ? ` (${a})` : ""}`);
|
|
824
1065
|
}
|
|
825
|
-
};
|
|
826
|
-
//#endregion
|
|
827
|
-
//#region src/core/engine/native.ts
|
|
828
|
-
function ve(e) {
|
|
829
|
-
return !!(e ?? (typeof document < "u" ? document.createElement("video") : void 0))?.canPlayType("application/vnd.apple.mpegurl");
|
|
830
|
-
}
|
|
831
|
-
var W = class {
|
|
832
|
-
name = "native";
|
|
833
|
-
deps;
|
|
834
|
-
onLoaded;
|
|
835
|
-
onError;
|
|
836
|
-
constructor(e) {
|
|
837
|
-
this.deps = e;
|
|
838
|
-
}
|
|
839
|
-
async load() {
|
|
840
|
-
let { video: e, descriptor: n, emit: r } = this.deps;
|
|
841
|
-
if (n.drmEnabled) {
|
|
842
|
-
if (!n.drm?.fairplay) {
|
|
843
|
-
r({
|
|
844
|
-
type: "error",
|
|
845
|
-
error: new t("INTERNAL", 0, "native HLS engine cannot satisfy this DRM (Widevine requires the hls.js engine); use engine \"auto\"/\"hls\" on a Widevine-capable browser"),
|
|
846
|
-
fatal: !0
|
|
847
|
-
});
|
|
848
|
-
return;
|
|
849
|
-
}
|
|
850
|
-
r({
|
|
851
|
-
type: "error",
|
|
852
|
-
error: new t("INTERNAL", 0, "FairPlay EME is not implemented in this SDK version; relying on native passthrough"),
|
|
853
|
-
fatal: !1
|
|
854
|
-
});
|
|
855
|
-
}
|
|
856
|
-
this.onLoaded = () => r({ type: "ready" }), this.onError = () => r({
|
|
857
|
-
type: "error",
|
|
858
|
-
error: new t("INTERNAL", 0, "native HLS playback error"),
|
|
859
|
-
fatal: !0
|
|
860
|
-
}), e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = n.manifestUrl, e.load();
|
|
861
|
-
}
|
|
862
|
-
setLicenseUrl(e) {}
|
|
863
|
-
getQualityLevels() {
|
|
864
|
-
return [];
|
|
865
|
-
}
|
|
866
|
-
getCurrentQuality() {
|
|
867
|
-
return -1;
|
|
868
|
-
}
|
|
869
|
-
setQuality(e) {}
|
|
870
|
-
setMaxBitrate(e) {}
|
|
871
|
-
getAudioTracks() {
|
|
872
|
-
let e = this.deps.video.audioTracks;
|
|
873
|
-
return e ? Array.from({ length: e.length }, (t, n) => {
|
|
874
|
-
let r = e[n];
|
|
875
|
-
return {
|
|
876
|
-
id: n,
|
|
877
|
-
name: r.label || r.language || `Audio ${n + 1}`,
|
|
878
|
-
lang: r.language || void 0,
|
|
879
|
-
default: r.enabled
|
|
880
|
-
};
|
|
881
|
-
}) : [];
|
|
882
|
-
}
|
|
883
|
-
setAudioTrack(e) {
|
|
884
|
-
let t = this.deps.video.audioTracks;
|
|
885
|
-
if (t) for (let n = 0; n < t.length; n += 1) t[n].enabled = n === e;
|
|
886
|
-
}
|
|
887
|
-
getTextTracks() {
|
|
888
|
-
let e = this.deps.video.textTracks;
|
|
889
|
-
return Array.from({ length: e.length }, (t, n) => {
|
|
890
|
-
let r = e[n];
|
|
891
|
-
return {
|
|
892
|
-
id: n,
|
|
893
|
-
name: r.label || r.language || `Text ${n + 1}`,
|
|
894
|
-
lang: r.language || void 0
|
|
895
|
-
};
|
|
896
|
-
});
|
|
897
|
-
}
|
|
898
|
-
setTextTrack(e) {
|
|
899
|
-
let t = this.deps.video.textTracks;
|
|
900
|
-
for (let n = 0; n < t.length; n += 1) t[n].mode = n === e ? "showing" : "disabled";
|
|
901
|
-
}
|
|
902
|
-
seekToLive() {
|
|
903
|
-
let e = this.deps.video;
|
|
904
|
-
e.seekable.length > 0 && (e.currentTime = e.seekable.end(e.seekable.length - 1));
|
|
905
|
-
}
|
|
906
|
-
getStats() {
|
|
907
|
-
let e = this.deps.video, t = { droppedFrames: F(e) };
|
|
908
|
-
return e.duration === Infinity && (t.isLive = !0, e.seekable.length > 0 && (t.atLiveEdge = e.currentTime >= e.seekable.end(e.seekable.length - 1) - 2)), t;
|
|
909
|
-
}
|
|
910
|
-
stop() {
|
|
911
|
-
try {
|
|
912
|
-
this.deps.video.pause();
|
|
913
|
-
} catch {}
|
|
914
|
-
}
|
|
915
|
-
destroy() {
|
|
916
|
-
let { video: e } = this.deps;
|
|
917
|
-
this.onLoaded && e.removeEventListener("loadedmetadata", this.onLoaded), this.onError && e.removeEventListener("error", this.onError);
|
|
918
|
-
try {
|
|
919
|
-
e.pause();
|
|
920
|
-
} catch {}
|
|
921
|
-
e.removeAttribute("src");
|
|
922
|
-
try {
|
|
923
|
-
e.load();
|
|
924
|
-
} catch {}
|
|
925
|
-
}
|
|
926
1066
|
}, G = {
|
|
927
1067
|
accent: "#E1B600",
|
|
928
1068
|
accentText: "#1B1C23",
|
|
@@ -956,21 +1096,21 @@ function q(e, t) {
|
|
|
956
1096
|
}
|
|
957
1097
|
//#endregion
|
|
958
1098
|
//#region src/ui/styles.ts
|
|
959
|
-
var J = "havik-player-styles",
|
|
960
|
-
function
|
|
1099
|
+
var J = "havik-player-styles", Ee = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n.havik-spinner{width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n\n.havik-bar{position:absolute;left:0;right:0;bottom:0;padding:0 12px 8px;\n opacity:1;transition:opacity .25s;z-index:2}\n.havik-seek{position:relative;height:16px;display:flex;align-items:center;cursor:pointer;margin-bottom:2px}\n.havik-seek__track{position:relative;width:100%;height:4px;border-radius:3px;background:rgba(255,255,255,.25)}\n.havik-seek__buffered{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:rgba(255,255,255,.4)}\n.havik-seek__played{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-seek__thumb{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;\n background:var(--havik-accent,#E1B600);transform:translate(-50%,-50%) scale(0);transition:transform .1s}\n.havik-seek:hover .havik-seek__thumb{transform:translate(-50%,-50%) scale(1)}\n\n.havik-controls{display:flex;align-items:center;gap:6px;height:40px}\n.havik-spacer{flex:1}\n.havik-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;border-radius:var(--havik-radius,8px);\n padding:0;transition:background .12s,color .12s}\n.havik-btn:hover{background:rgba(255,255,255,.12)}\n.havik-btn:focus-visible{outline:2px solid var(--havik-accent,#E1B600);outline-offset:1px}\n.havik-btn svg{width:22px;height:22px}\n\n.havik-vol{display:flex;align-items:center}\n.havik-vol__slider{width:0;opacity:0;transition:width .18s,opacity .18s;height:4px;cursor:pointer;\n appearance:none;-webkit-appearance:none;background:rgba(255,255,255,.3);border-radius:3px;margin:0 4px}\n.havik-vol:hover .havik-vol__slider,.havik-vol:focus-within .havik-vol__slider{width:70px;opacity:1}\n.havik-vol__slider::-webkit-slider-thumb{-webkit-appearance:none;width:12px;height:12px;border-radius:50%;background:var(--havik-accent,#E1B600)}\n.havik-vol__slider::-moz-range-thumb{width:12px;height:12px;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";
|
|
1100
|
+
function De(e = document) {
|
|
961
1101
|
if (e.getElementById(J)) return;
|
|
962
1102
|
let t = e.createElement("style");
|
|
963
|
-
t.id = J, t.textContent =
|
|
1103
|
+
t.id = J, t.textContent = Ee, e.head.appendChild(t);
|
|
964
1104
|
}
|
|
965
1105
|
//#endregion
|
|
966
1106
|
//#region src/ui/icons.ts
|
|
967
|
-
var
|
|
1107
|
+
var Oe = {
|
|
968
1108
|
play: "<path d=\"M8 5v14l11-7z\"/>",
|
|
969
1109
|
pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
|
|
970
1110
|
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\"/>",
|
|
971
1111
|
volumeMute: "<path d=\"M3 10v4h4l5 5V5L7 10H3zm16.5 2 2.5-2.5-1.4-1.4L18 10.6 15.4 8 14 9.4l2.6 2.6L14 14.6l1.4 1.4 2.6-2.6 2.6 2.6 1.4-1.4z\"/>",
|
|
972
1112
|
cc: "<path d=\"M19 4H5a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2zM10 11H8.5v-.5h-2v3h2V13H10v1a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1h3a1 1 0 0 1 1 1v1zm7 0h-1.5v-.5h-2v3h2V13H17v1a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1h3a1 1 0 0 1 1 1v1z\"/>",
|
|
973
|
-
settings: "<path d=\"
|
|
1113
|
+
settings: "<path d=\"M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.11-.2.06-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z\"/>",
|
|
974
1114
|
pip: "<path d=\"M19 7h-8v6h8V7zm4 12V5a2 2 0 0 0-2-2H3a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h18a2 2 0 0 0 2-2zm-2 .02H3V4.98h18v14.04z\"/>",
|
|
975
1115
|
fullscreen: "<path d=\"M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z\"/>",
|
|
976
1116
|
fullscreenExit: "<path d=\"M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z\"/>",
|
|
@@ -978,20 +1118,20 @@ var xe = {
|
|
|
978
1118
|
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\"/>"
|
|
979
1119
|
};
|
|
980
1120
|
function Y(e) {
|
|
981
|
-
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${
|
|
1121
|
+
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Oe[e]}</svg>`;
|
|
982
1122
|
}
|
|
983
1123
|
//#endregion
|
|
984
1124
|
//#region src/ui/controls.ts
|
|
985
|
-
var
|
|
1125
|
+
var ke = 3e3, Ae = /* @__PURE__ */ new Set([
|
|
986
1126
|
"GONE",
|
|
987
1127
|
"NOT_FOUND",
|
|
988
1128
|
"INVALID_URN",
|
|
989
1129
|
"UNAUTHORIZED"
|
|
990
1130
|
]);
|
|
991
|
-
function
|
|
992
|
-
return new
|
|
1131
|
+
function je(e) {
|
|
1132
|
+
return new Me(e);
|
|
993
1133
|
}
|
|
994
|
-
var
|
|
1134
|
+
var Me = class {
|
|
995
1135
|
root;
|
|
996
1136
|
video;
|
|
997
1137
|
player;
|
|
@@ -1031,7 +1171,7 @@ var Te = class {
|
|
|
1031
1171
|
scrubbing = !1;
|
|
1032
1172
|
offFns = [];
|
|
1033
1173
|
constructor(e) {
|
|
1034
|
-
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ??
|
|
1174
|
+
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? ke, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.errorMessage = e.errorMessage, De(this.doc), this.root.classList.add("havik-player"), this.root.hasAttribute("tabindex") || (this.root.tabIndex = 0), this.root.setAttribute("role", "region"), this.root.setAttribute("aria-label", "Video player");
|
|
1035
1175
|
let t = (e, t, n) => {
|
|
1036
1176
|
let r = this.doc.createElement(e);
|
|
1037
1177
|
if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
|
|
@@ -1118,7 +1258,7 @@ var Te = class {
|
|
|
1118
1258
|
e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML = Y("play"), e.addEventListener("click", () => void this.player.play()), t.append(e);
|
|
1119
1259
|
} else {
|
|
1120
1260
|
let n = this.doc.createElement("div");
|
|
1121
|
-
if (n.className = "havik-status__msg", n.textContent = e === "ended" ? this.endedMessage : e === "waiting" ? "Starting soon…" : this.errorMessage ?? this.lastError?.message ?? "Playback unavailable", t.append(n), e === "error" && this.lastError && !
|
|
1261
|
+
if (n.className = "havik-status__msg", n.textContent = e === "ended" ? this.endedMessage : e === "waiting" ? "Starting soon…" : this.errorMessage ?? this.lastError?.message ?? "Playback unavailable", t.append(n), e === "error" && this.lastError && !Ae.has(this.lastError.code)) {
|
|
1122
1262
|
let e = this.doc.createElement("button");
|
|
1123
1263
|
e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${Y("retry")}<span>Retry</span>`, e.addEventListener("click", () => void this.player.retry()), t.append(e);
|
|
1124
1264
|
}
|
|
@@ -1204,17 +1344,17 @@ var Te = class {
|
|
|
1204
1344
|
renderQualityMenu() {
|
|
1205
1345
|
let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
|
|
1206
1346
|
n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
|
|
1207
|
-
for (let n of e) this.menu.append(this.menuItem(
|
|
1347
|
+
for (let n of e) this.menu.append(this.menuItem(Ne(n), t === n.index, () => this.player.setQuality(n.index)));
|
|
1208
1348
|
}
|
|
1209
1349
|
renderAudioMenu() {
|
|
1210
1350
|
let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
|
|
1211
1351
|
t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
|
|
1212
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
1352
|
+
for (let t of e) this.menu.append(this.menuItem(Pe(t), t.default, () => this.player.setAudioTrack(t.id)));
|
|
1213
1353
|
}
|
|
1214
1354
|
renderCcMenu() {
|
|
1215
1355
|
let e = this.player.getTextTracks(), t = this.doc.createElement("div");
|
|
1216
1356
|
t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
|
|
1217
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
1357
|
+
for (let t of e) this.menu.append(this.menuItem(Fe(t), !1, () => this.player.setTextTrack(t.id)));
|
|
1218
1358
|
}
|
|
1219
1359
|
onTracksChanged() {
|
|
1220
1360
|
this.openMenu && this.renderMenu(this.openMenu);
|
|
@@ -1320,27 +1460,27 @@ function X(e) {
|
|
|
1320
1460
|
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");
|
|
1321
1461
|
return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
|
|
1322
1462
|
}
|
|
1323
|
-
function
|
|
1463
|
+
function Ne(e) {
|
|
1324
1464
|
return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
|
|
1325
1465
|
}
|
|
1326
|
-
function
|
|
1466
|
+
function Pe(e) {
|
|
1327
1467
|
return e.name || e.lang || `Track ${e.id}`;
|
|
1328
1468
|
}
|
|
1329
|
-
function
|
|
1469
|
+
function Fe(e) {
|
|
1330
1470
|
return e.name || e.lang || `Track ${e.id}`;
|
|
1331
1471
|
}
|
|
1332
1472
|
//#endregion
|
|
1333
1473
|
//#region src/managed/index.ts
|
|
1334
|
-
var
|
|
1474
|
+
var Ie = 6e3, Z = 45e3, Le = 2e3, Re = 3, ze = 2e3, Be = 480 * 1e3;
|
|
1335
1475
|
async function Q(e) {
|
|
1336
1476
|
if (!e.video || typeof e.video.play != "function") throw new t("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
1337
1477
|
if (!e.baseUrl) throw new t("INTERNAL", 0, "createPlayer: baseUrl is required");
|
|
1338
1478
|
if (!e.matchUrn) throw new t("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
1339
1479
|
if (!e.credential) throw new t("INTERNAL", 0, "createPlayer: credential is required");
|
|
1340
|
-
let n = new
|
|
1480
|
+
let n = new Ve(e);
|
|
1341
1481
|
return await n.start(), n;
|
|
1342
1482
|
}
|
|
1343
|
-
var
|
|
1483
|
+
var Ve = class {
|
|
1344
1484
|
opts;
|
|
1345
1485
|
abort = new AbortController();
|
|
1346
1486
|
listeners = {};
|
|
@@ -1359,6 +1499,8 @@ var Pe = class {
|
|
|
1359
1499
|
endedHandled = !1;
|
|
1360
1500
|
armingSub = null;
|
|
1361
1501
|
armSseTimer = null;
|
|
1502
|
+
armFallbackCtrl = null;
|
|
1503
|
+
_lastError = null;
|
|
1362
1504
|
constructor(e) {
|
|
1363
1505
|
this.opts = e;
|
|
1364
1506
|
}
|
|
@@ -1372,11 +1514,14 @@ var Pe = class {
|
|
|
1372
1514
|
this.opts.muted && (this.opts.video.muted = !0), this.opts.poster && (this.opts.video.poster = this.opts.poster), this.mountControls(), this.attachPipListeners(), this.setState("loading");
|
|
1373
1515
|
let e = ++this.loadGen, n = this.resolveOptions();
|
|
1374
1516
|
try {
|
|
1375
|
-
let t = await
|
|
1376
|
-
await this.onResolved(t, e)
|
|
1517
|
+
let t = await y(n);
|
|
1518
|
+
if (await this.onResolved(t, e), e === this.loadGen && this._state === "error" && this._lastError) {
|
|
1519
|
+
let e = this._lastError;
|
|
1520
|
+
throw this.destroy(), e;
|
|
1521
|
+
}
|
|
1377
1522
|
} catch (n) {
|
|
1378
1523
|
if (this.opts.waitForLive && n instanceof t && i(n.code)) {
|
|
1379
|
-
this.setState("waiting"), this.beginArming(e);
|
|
1524
|
+
this.setState("waiting"), this.beginArming(e, n.liveStartsAtMs);
|
|
1380
1525
|
return;
|
|
1381
1526
|
}
|
|
1382
1527
|
throw n;
|
|
@@ -1390,55 +1535,81 @@ var Pe = class {
|
|
|
1390
1535
|
signal: this.abort.signal
|
|
1391
1536
|
};
|
|
1392
1537
|
}
|
|
1393
|
-
beginArming(e) {
|
|
1394
|
-
let
|
|
1395
|
-
|
|
1538
|
+
beginArming(e, t) {
|
|
1539
|
+
let n = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? E(this.opts.baseUrl);
|
|
1540
|
+
n ? this.armWithSse(e, n, t) : this.beginArmingByPolling(e);
|
|
1396
1541
|
}
|
|
1397
|
-
beginArmingByPolling(e
|
|
1398
|
-
|
|
1542
|
+
beginArmingByPolling(e) {
|
|
1543
|
+
b({
|
|
1399
1544
|
...this.resolveOptions(),
|
|
1400
|
-
signal:
|
|
1401
|
-
waitForLive: this.buildWaitConfig()
|
|
1402
|
-
}).then((t) =>
|
|
1403
|
-
this.destroyed || this.abort.signal.aborted ||
|
|
1545
|
+
signal: this.abort.signal,
|
|
1546
|
+
waitForLive: this.buildWaitConfig(e)
|
|
1547
|
+
}).then((t) => {
|
|
1548
|
+
if (!(this.destroyed || this.abort.signal.aborted || e !== this.loadGen)) return this.onResolved(t, e);
|
|
1549
|
+
}).catch((n) => {
|
|
1550
|
+
this.destroyed || this.abort.signal.aborted || e !== this.loadGen || this.fail(n instanceof t ? n : new t("INTERNAL", 0, String(n)));
|
|
1404
1551
|
});
|
|
1405
1552
|
}
|
|
1406
|
-
armWithSse(e, n) {
|
|
1407
|
-
let
|
|
1408
|
-
this.
|
|
1409
|
-
let
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1553
|
+
armWithSse(e, n, r) {
|
|
1554
|
+
let a = !1, o = !1, s = new AbortController();
|
|
1555
|
+
this.armFallbackCtrl = s, this.setState("waiting");
|
|
1556
|
+
let c = this.opts.waitForLive, l = c && c !== !0 ? c.kickoffAt : void 0, u = typeof l == "number" ? l : typeof l == "string" ? Date.parse(l) : NaN, d = r ?? (Number.isFinite(u) ? u : void 0);
|
|
1557
|
+
setTimeout(() => {
|
|
1558
|
+
a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
|
|
1559
|
+
phase: "tooEarly",
|
|
1560
|
+
retryInMs: Z,
|
|
1561
|
+
attempt: 1,
|
|
1562
|
+
elapsedMs: 0,
|
|
1563
|
+
...d !== void 0 && d > Date.now() ? { ttkMs: d - Date.now() } : {}
|
|
1416
1564
|
});
|
|
1417
|
-
},
|
|
1565
|
+
}, 0);
|
|
1566
|
+
let f = () => this.destroyed || this.abort.signal.aborted || e !== this.loadGen, p = async (n) => {
|
|
1567
|
+
if (!(a || f())) {
|
|
1568
|
+
a = !0, this.closeArming(), s.abort();
|
|
1569
|
+
try {
|
|
1570
|
+
await this.onResolved(n, e);
|
|
1571
|
+
} catch (e) {
|
|
1572
|
+
if (f()) return;
|
|
1573
|
+
this.fail(e instanceof t ? e : new t("INTERNAL", 0, String(e)));
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
}, m = () => {
|
|
1577
|
+
a || o || f() || (o = !0, b({
|
|
1578
|
+
...this.resolveOptions(),
|
|
1579
|
+
signal: s.signal,
|
|
1580
|
+
waitForLive: this.buildWaitConfig(e)
|
|
1581
|
+
}).then((e) => p(e)).catch((e) => {
|
|
1582
|
+
a || f() || s.signal.aborted || (a = !0, this.closeArming(), this.fail(e instanceof t ? e : new t("INTERNAL", 0, String(e))));
|
|
1583
|
+
}));
|
|
1584
|
+
}, h = () => {
|
|
1585
|
+
a || f() || y(this.resolveOptions()).then((e) => p(e)).catch((e) => {
|
|
1586
|
+
a || f() || e instanceof t && i(e.code) || (a = !0, this.closeArming(), s.abort(), this.fail(e instanceof t ? e : new t("INTERNAL", 0, String(e))));
|
|
1587
|
+
});
|
|
1588
|
+
}, g = (e) => {
|
|
1418
1589
|
this.armSseTimer && clearTimeout(this.armSseTimer), this.armSseTimer = setTimeout(() => {
|
|
1419
|
-
!
|
|
1590
|
+
!a && !f() && m();
|
|
1420
1591
|
}, e);
|
|
1421
1592
|
};
|
|
1422
|
-
|
|
1593
|
+
g(Ie), this.armingSub = T({
|
|
1423
1594
|
eventsBaseUrl: n,
|
|
1424
1595
|
matchUrn: this.opts.matchUrn,
|
|
1425
1596
|
credential: this.opts.credential,
|
|
1426
|
-
onAlive: () =>
|
|
1597
|
+
onAlive: () => g(Z),
|
|
1427
1598
|
onState: (e) => {
|
|
1428
|
-
|
|
1599
|
+
a || f() || (e.state === "live" || e.state === "gone") && setTimeout(h, Math.random() * Le);
|
|
1429
1600
|
},
|
|
1430
|
-
onError: () =>
|
|
1601
|
+
onError: () => m()
|
|
1431
1602
|
});
|
|
1432
1603
|
}
|
|
1433
1604
|
closeArming() {
|
|
1434
|
-
this.armSseTimer &&= (clearTimeout(this.armSseTimer), null), this.armingSub?.close(), this.armingSub = null;
|
|
1605
|
+
this.armSseTimer &&= (clearTimeout(this.armSseTimer), null), this.armFallbackCtrl?.abort(), this.armFallbackCtrl = null, this.armingSub?.close(), this.armingSub = null;
|
|
1435
1606
|
}
|
|
1436
|
-
buildWaitConfig() {
|
|
1437
|
-
let
|
|
1607
|
+
buildWaitConfig(e) {
|
|
1608
|
+
let t = this.opts.waitForLive && this.opts.waitForLive !== !0 ? this.opts.waitForLive : {};
|
|
1438
1609
|
return {
|
|
1439
|
-
...
|
|
1440
|
-
onState: (
|
|
1441
|
-
this.setState("waiting"), this.emit("waiting",
|
|
1610
|
+
...t,
|
|
1611
|
+
onState: (n) => {
|
|
1612
|
+
this.destroyed || e !== this.loadGen || (this.setState("waiting"), this.emit("waiting", n), t.onState?.(n));
|
|
1442
1613
|
}
|
|
1443
1614
|
};
|
|
1444
1615
|
}
|
|
@@ -1448,11 +1619,17 @@ var Pe = class {
|
|
|
1448
1619
|
let n = await a(this.opts.credential);
|
|
1449
1620
|
if (this.destroyed || t !== this.loadGen) return;
|
|
1450
1621
|
this.setState("loading");
|
|
1451
|
-
let r = this.createEngine(e, n), i =
|
|
1622
|
+
let r = this.createEngine(e, n), i = V(this.opts.video, (e) => {
|
|
1623
|
+
this._state === "ended" || this._state === "error" || this.setState(e);
|
|
1624
|
+
});
|
|
1452
1625
|
if (await r.load(), this.destroyed || t !== this.loadGen) {
|
|
1453
1626
|
i(), r.destroy();
|
|
1454
1627
|
return;
|
|
1455
1628
|
}
|
|
1629
|
+
if (this._state === "error") {
|
|
1630
|
+
i(), r.destroy();
|
|
1631
|
+
return;
|
|
1632
|
+
}
|
|
1456
1633
|
this.engine = r, this.detachMedia = i, this.opts.maxBitrate != null && r.setMaxBitrate(this.opts.maxBitrate), this.startStats(), this.scheduleLicenseRefresh(), this.startLiveState(t);
|
|
1457
1634
|
}
|
|
1458
1635
|
createEngine(e, n) {
|
|
@@ -1462,7 +1639,7 @@ var Pe = class {
|
|
|
1462
1639
|
video: this.opts.video,
|
|
1463
1640
|
descriptor: e,
|
|
1464
1641
|
credential: n,
|
|
1465
|
-
deviceId:
|
|
1642
|
+
deviceId: k(),
|
|
1466
1643
|
userId: this.opts.userId,
|
|
1467
1644
|
lowLatency: this.opts.lowLatency === void 0 || this.opts.lowLatency === "auto" || this.opts.lowLatency,
|
|
1468
1645
|
snapToLiveOnRefocus: this.opts.snapToLiveOnRefocus,
|
|
@@ -1470,9 +1647,9 @@ var Pe = class {
|
|
|
1470
1647
|
hlsConfig: r,
|
|
1471
1648
|
emit: (e) => this.onEngineEvent(e)
|
|
1472
1649
|
}, a = this.opts.engine ?? "auto";
|
|
1473
|
-
if (a === "native") return new
|
|
1474
|
-
if (a === "hls" ||
|
|
1475
|
-
if (
|
|
1650
|
+
if (a === "native") return new U(i);
|
|
1651
|
+
if (a === "hls" || pe()) return new Te(i);
|
|
1652
|
+
if (H(this.opts.video)) return new U(i);
|
|
1476
1653
|
throw new t("INTERNAL", 0, "no supported HLS playback engine in this browser");
|
|
1477
1654
|
}
|
|
1478
1655
|
onEngineEvent(e) {
|
|
@@ -1502,11 +1679,11 @@ var Pe = class {
|
|
|
1502
1679
|
}
|
|
1503
1680
|
startLiveState(e) {
|
|
1504
1681
|
if (this.opts.liveStateEvents === !1) return;
|
|
1505
|
-
let n = this.opts.eventsBaseUrl ??
|
|
1682
|
+
let n = this.opts.eventsBaseUrl ?? E(this.opts.baseUrl);
|
|
1506
1683
|
if (!n) return;
|
|
1507
1684
|
this.closeLiveState();
|
|
1508
1685
|
let r = 0, i = !1;
|
|
1509
|
-
this.liveStateSub =
|
|
1686
|
+
this.liveStateSub = T({
|
|
1510
1687
|
eventsBaseUrl: n,
|
|
1511
1688
|
matchUrn: this.opts.matchUrn,
|
|
1512
1689
|
credential: this.opts.credential,
|
|
@@ -1517,7 +1694,7 @@ var Pe = class {
|
|
|
1517
1694
|
r = 0, i = !1;
|
|
1518
1695
|
},
|
|
1519
1696
|
onError: () => {
|
|
1520
|
-
this.destroyed || e !== this.loadGen || i || (r += 1, r >=
|
|
1697
|
+
this.destroyed || e !== this.loadGen || i || (r += 1, r >= Re && (i = !0, this.emit("warning", new t("NETWORK", 0, `live-state events unreachable at ${n} after ${r} attempts — end-of-stream detection degraded to the HLS staleness watchdog. Check the events host, the api-key's allowed origins, and CSP connect-src.`))));
|
|
1521
1698
|
}
|
|
1522
1699
|
});
|
|
1523
1700
|
}
|
|
@@ -1539,7 +1716,7 @@ var Pe = class {
|
|
|
1539
1716
|
}
|
|
1540
1717
|
t.controls = !1;
|
|
1541
1718
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
1542
|
-
r && r.insertBefore(n, t), n.appendChild(t), q(n, this.opts.theme), this.container = n, this.controlBar =
|
|
1719
|
+
r && r.insertBefore(n, t), n.appendChild(t), q(n, this.opts.theme), this.container = n, this.controlBar = je({
|
|
1543
1720
|
root: n,
|
|
1544
1721
|
video: t,
|
|
1545
1722
|
player: this,
|
|
@@ -1552,7 +1729,7 @@ var Pe = class {
|
|
|
1552
1729
|
unmountControls() {
|
|
1553
1730
|
this.controlBar?.destroy(), this.controlBar = null;
|
|
1554
1731
|
let e = this.container;
|
|
1555
|
-
e
|
|
1732
|
+
e && (e.parentNode ? (e.parentNode.insertBefore(this.opts.video, e), e.remove()) : this.opts.video.parentNode === e && e.removeChild(this.opts.video)), this.container = null;
|
|
1556
1733
|
}
|
|
1557
1734
|
attachPipListeners() {
|
|
1558
1735
|
let e = this.opts.video, t = () => this.emit("pipchange", !0), n = () => this.emit("pipchange", !1);
|
|
@@ -1562,7 +1739,7 @@ var Pe = class {
|
|
|
1562
1739
|
}
|
|
1563
1740
|
startStats() {
|
|
1564
1741
|
this.stopStats();
|
|
1565
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
1742
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? ze);
|
|
1566
1743
|
this.statsTimer = setInterval(() => {
|
|
1567
1744
|
this.engine && this.emit("stats", this.engine.getStats());
|
|
1568
1745
|
}, e);
|
|
@@ -1572,7 +1749,7 @@ var Pe = class {
|
|
|
1572
1749
|
}
|
|
1573
1750
|
scheduleLicenseRefresh() {
|
|
1574
1751
|
this.stopRefresh();
|
|
1575
|
-
let e = this.opts.licenseRefreshMs ??
|
|
1752
|
+
let e = this.opts.licenseRefreshMs ?? Be;
|
|
1576
1753
|
!e || !this._descriptor?.drmEnabled || (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
1577
1754
|
}
|
|
1578
1755
|
stopRefresh() {
|
|
@@ -1581,10 +1758,13 @@ var Pe = class {
|
|
|
1581
1758
|
async refreshLicense() {
|
|
1582
1759
|
let e = this.engine;
|
|
1583
1760
|
if (!(this.destroyed || !e)) try {
|
|
1584
|
-
let t = await
|
|
1761
|
+
let t = await y(this.resolveOptions());
|
|
1585
1762
|
if (this.destroyed || this.engine !== e) return;
|
|
1586
|
-
let n = t.drm?.widevine?.licenseUrl;
|
|
1587
|
-
n && (e.
|
|
1763
|
+
let n = t.drm?.widevine?.licenseUrl, r = t.drm?.fairplay?.licenseUrl;
|
|
1764
|
+
(n || r) && (e.setLicenseUrls({
|
|
1765
|
+
widevine: n,
|
|
1766
|
+
fairplay: r
|
|
1767
|
+
}), this._descriptor = t);
|
|
1588
1768
|
} catch (e) {
|
|
1589
1769
|
e instanceof t && !i(e.code) && (this.stopRefresh(), this.destroyed || this.emit("warning", e));
|
|
1590
1770
|
}
|
|
@@ -1606,7 +1786,7 @@ var Pe = class {
|
|
|
1606
1786
|
this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
|
|
1607
1787
|
}
|
|
1608
1788
|
getStats() {
|
|
1609
|
-
return this.engine?.getStats() ??
|
|
1789
|
+
return this.engine?.getStats() ?? z;
|
|
1610
1790
|
}
|
|
1611
1791
|
getQualityLevels() {
|
|
1612
1792
|
return this.engine?.getQualityLevels() ?? [];
|
|
@@ -1652,14 +1832,14 @@ var Pe = class {
|
|
|
1652
1832
|
let e = ++this.loadGen;
|
|
1653
1833
|
this.stopStats(), this.stopRefresh(), this.closeArming(), this.closeLiveState(), this.detachMedia?.(), this.engine?.destroy(), this.engine = null;
|
|
1654
1834
|
try {
|
|
1655
|
-
let t = await
|
|
1835
|
+
let t = await b({
|
|
1656
1836
|
...this.resolveOptions(),
|
|
1657
|
-
waitForLive: this.opts.waitForLive ? this.buildWaitConfig() : void 0
|
|
1837
|
+
waitForLive: this.opts.waitForLive ? this.buildWaitConfig(e) : void 0
|
|
1658
1838
|
});
|
|
1659
|
-
await this.onResolved(t, e);
|
|
1839
|
+
if (await this.onResolved(t, e), e === this.loadGen && this._state === "error" && this._lastError) throw this._lastError;
|
|
1660
1840
|
} catch (n) {
|
|
1661
1841
|
if (this.destroyed || this.abort.signal.aborted || e !== this.loadGen) return;
|
|
1662
|
-
throw this.fail(n instanceof t ? n : new t("INTERNAL", 0, String(n))), n;
|
|
1842
|
+
throw n !== this._lastError && this.fail(n instanceof t ? n : new t("INTERNAL", 0, String(n))), n;
|
|
1663
1843
|
}
|
|
1664
1844
|
}
|
|
1665
1845
|
on(e, t) {
|
|
@@ -1673,7 +1853,7 @@ var Pe = class {
|
|
|
1673
1853
|
for (let e of Object.keys(this.listeners)) this.listeners[e]?.clear();
|
|
1674
1854
|
}
|
|
1675
1855
|
fail(e) {
|
|
1676
|
-
this.setState("error"), this.emit("error", e);
|
|
1856
|
+
this._lastError = e, this.setState("error"), this.emit("error", e);
|
|
1677
1857
|
}
|
|
1678
1858
|
setState(e) {
|
|
1679
1859
|
if (e !== this._state) switch (this._state = e, this.emit("statechange", e), e) {
|
|
@@ -1707,7 +1887,7 @@ function $(e) {
|
|
|
1707
1887
|
}
|
|
1708
1888
|
//#endregion
|
|
1709
1889
|
//#region src/embed/host.ts
|
|
1710
|
-
function
|
|
1890
|
+
function He(e) {
|
|
1711
1891
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
1712
1892
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
1713
1893
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -1766,8 +1946,8 @@ function Fe(e) {
|
|
|
1766
1946
|
}
|
|
1767
1947
|
//#endregion
|
|
1768
1948
|
//#region src/embed/page.ts
|
|
1769
|
-
var
|
|
1770
|
-
function
|
|
1949
|
+
var Ue = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
1950
|
+
function We() {
|
|
1771
1951
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
1772
1952
|
if (e) return {
|
|
1773
1953
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -1789,9 +1969,9 @@ function Le() {
|
|
|
1789
1969
|
waitForLive: !0
|
|
1790
1970
|
};
|
|
1791
1971
|
}
|
|
1792
|
-
async function
|
|
1793
|
-
let e =
|
|
1794
|
-
|
|
1972
|
+
async function Ge() {
|
|
1973
|
+
let e = We();
|
|
1974
|
+
qe();
|
|
1795
1975
|
let n = document.createElement("video");
|
|
1796
1976
|
n.setAttribute("playsinline", ""), n.muted = e.muted ?? !0, n.style.cssText = "width:100%;height:100%;object-fit:contain;background:#000;aspect-ratio:auto", document.body.appendChild(n);
|
|
1797
1977
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
@@ -1846,7 +2026,7 @@ async function Re() {
|
|
|
1846
2026
|
code: e.code,
|
|
1847
2027
|
message: e.message
|
|
1848
2028
|
})), e.on("autoplayblocked", () => {
|
|
1849
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
2029
|
+
i({ type: "oddin:autoplayblocked" }), Ke(n, e);
|
|
1850
2030
|
});
|
|
1851
2031
|
}, s = async (r) => {
|
|
1852
2032
|
a?.destroy(), a = null;
|
|
@@ -1912,7 +2092,7 @@ async function Re() {
|
|
|
1912
2092
|
a?.retry();
|
|
1913
2093
|
break;
|
|
1914
2094
|
case "oddin:load":
|
|
1915
|
-
typeof e.matchUrn == "string" &&
|
|
2095
|
+
typeof e.matchUrn == "string" && Ue.test(e.matchUrn) && s(e.matchUrn);
|
|
1916
2096
|
break;
|
|
1917
2097
|
case "oddin:destroy":
|
|
1918
2098
|
c();
|
|
@@ -1926,18 +2106,18 @@ async function Re() {
|
|
|
1926
2106
|
protocol: 1
|
|
1927
2107
|
});
|
|
1928
2108
|
}
|
|
1929
|
-
function
|
|
2109
|
+
function Ke(e, t) {
|
|
1930
2110
|
if (document.getElementById("havik-tap")) return;
|
|
1931
2111
|
let n = document.createElement("button");
|
|
1932
2112
|
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", () => {
|
|
1933
2113
|
n.remove(), t.play();
|
|
1934
2114
|
}), document.body.appendChild(n);
|
|
1935
2115
|
}
|
|
1936
|
-
function
|
|
2116
|
+
function qe() {
|
|
1937
2117
|
let e = document.createElement("style");
|
|
1938
2118
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
1939
2119
|
}
|
|
1940
2120
|
//#endregion
|
|
1941
|
-
export { G as ODDIN_THEME, t as PlaybackError, q as applyTheme,
|
|
2121
|
+
export { G as ODDIN_THEME, t as PlaybackError, q as applyTheme, Ge as bootEmbed, ue as clearDeviceId, Q as createPlayer, E as deriveEventsBaseUrl, I as detectDrmSupport, se as fetchCatalog, le as fetchTournament, C as flattenMatches, k as getDeviceId, R as isLowLatencyManifest, $ as isOddinMessage, fe as licenseRequestHeaders, He as mountEmbed, v as pollToLive, b as resolveStream, T as subscribeLiveState, w as watchStatus };
|
|
1942
2122
|
|
|
1943
2123
|
//# sourceMappingURL=index.js.map
|