@oddin-gg/havik-player 1.8.3 → 1.9.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 +13 -13
- 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 +35 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.js +421 -166
- package/dist/index.js.map +1 -1
- package/embed/index.html +1 -1
- package/examples/vanilla.html +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -112,7 +112,7 @@ function te(e, t, n) {
|
|
|
112
112
|
function ne(e) {
|
|
113
113
|
return Math.round(e * (1 + .15 * Math.random()));
|
|
114
114
|
}
|
|
115
|
-
function
|
|
115
|
+
function re(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
118
|
delay: te(e ?? n.floorMs, o, n.ceilMs),
|
|
@@ -124,7 +124,7 @@ function _(e, t, n, r) {
|
|
|
124
124
|
ttkMs: a
|
|
125
125
|
};
|
|
126
126
|
}
|
|
127
|
-
function
|
|
127
|
+
function ie(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,7 +138,7 @@ function re(e, n) {
|
|
|
138
138
|
n?.addEventListener("abort", a, { once: !0 });
|
|
139
139
|
});
|
|
140
140
|
}
|
|
141
|
-
async function
|
|
141
|
+
async function _(e, n, r) {
|
|
142
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");
|
|
@@ -147,7 +147,7 @@ async function v(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 =
|
|
150
|
+
let n = Date.now(), u = re(e.retryAfterMs, n, a, l), d = u.ttkMs, f = u.delay;
|
|
151
151
|
if (a.jitter && (f = ne(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
|
|
@@ -158,26 +158,26 @@ async function v(e, n, r) {
|
|
|
158
158
|
attempt: c,
|
|
159
159
|
elapsedMs: n - o,
|
|
160
160
|
ttkMs: d
|
|
161
|
-
}), await
|
|
161
|
+
}), await ie(f, r);
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
165
|
//#endregion
|
|
166
166
|
//#region src/core/resolve.ts
|
|
167
|
-
async function
|
|
167
|
+
async function v(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 ae(n);
|
|
174
|
+
return se(await n.json(), e.matchUrn);
|
|
175
175
|
}
|
|
176
|
-
function
|
|
177
|
-
let t = () =>
|
|
178
|
-
return e.waitForLive ?
|
|
176
|
+
function y(e) {
|
|
177
|
+
let t = () => v(e);
|
|
178
|
+
return e.waitForLive ? _(t, e.waitForLive, e.signal) : t();
|
|
179
179
|
}
|
|
180
|
-
async function
|
|
180
|
+
async function ae(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 ie(e) {
|
|
|
193
193
|
liveStartsAtMs: c
|
|
194
194
|
});
|
|
195
195
|
}
|
|
196
|
-
var
|
|
196
|
+
var oe = /* @__PURE__ */ new Set([
|
|
197
197
|
"matchUrn",
|
|
198
198
|
"protocol",
|
|
199
199
|
"drmEnabled",
|
|
@@ -201,9 +201,10 @@ var ae = /* @__PURE__ */ new Set([
|
|
|
201
201
|
"drm",
|
|
202
202
|
"serverTime",
|
|
203
203
|
"liveStartsAt",
|
|
204
|
-
"expiresAt"
|
|
204
|
+
"expiresAt",
|
|
205
|
+
"analytics"
|
|
205
206
|
]);
|
|
206
|
-
function
|
|
207
|
+
function b(e, n) {
|
|
207
208
|
let r;
|
|
208
209
|
try {
|
|
209
210
|
r = new URL(n);
|
|
@@ -213,29 +214,29 @@ function x(e, n) {
|
|
|
213
214
|
if (r.protocol !== "https:" && r.protocol !== "http:") throw new t("INTERNAL", 0, `playback ${e} has a disallowed scheme: ${r.protocol}`);
|
|
214
215
|
return n;
|
|
215
216
|
}
|
|
216
|
-
function
|
|
217
|
+
function se(e, n) {
|
|
217
218
|
if (!e.manifestUrl) throw new t("INTERNAL", 0, "playback response is missing manifestUrl");
|
|
218
219
|
let r = e.drmEnabled ?? !!e.drm, i = {
|
|
219
220
|
matchUrn: e.matchUrn ?? n,
|
|
220
221
|
protocol: "hls",
|
|
221
222
|
drmEnabled: r,
|
|
222
|
-
manifestUrl:
|
|
223
|
+
manifestUrl: b("manifestUrl", e.manifestUrl),
|
|
223
224
|
serverTime: e.serverTime ?? ""
|
|
224
225
|
};
|
|
225
|
-
if (e.liveStartsAt && (i.liveStartsAt = e.liveStartsAt), r && e.drm) {
|
|
226
|
+
if (e.liveStartsAt && (i.liveStartsAt = e.liveStartsAt), typeof e.analytics?.sid == "string" && e.analytics.sid && (i.analytics = { sid: e.analytics.sid }), r && e.drm) {
|
|
226
227
|
let t = {};
|
|
227
|
-
e.drm.widevine?.licenseUrl && (t.widevine = { licenseUrl:
|
|
228
|
-
licenseUrl:
|
|
229
|
-
certificateUrl:
|
|
228
|
+
e.drm.widevine?.licenseUrl && (t.widevine = { licenseUrl: b("widevine licenseUrl", e.drm.widevine.licenseUrl) }), e.drm.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && (t.fairplay = {
|
|
229
|
+
licenseUrl: b("fairplay licenseUrl", e.drm.fairplay.licenseUrl),
|
|
230
|
+
certificateUrl: b("fairplay certificateUrl", e.drm.fairplay.certificateUrl)
|
|
230
231
|
}), (t.widevine || t.fairplay) && (i.drm = t);
|
|
231
232
|
}
|
|
232
233
|
let a = {};
|
|
233
|
-
for (let [t, n] of Object.entries(e))
|
|
234
|
+
for (let [t, n] of Object.entries(e)) oe.has(t) || (a[t] = n);
|
|
234
235
|
return Object.keys(a).length > 0 && (i.extensions = a), i;
|
|
235
236
|
}
|
|
236
237
|
//#endregion
|
|
237
238
|
//#region src/core/catalog.ts
|
|
238
|
-
async function
|
|
239
|
+
async function x(e) {
|
|
239
240
|
let r = new URLSearchParams();
|
|
240
241
|
e.status && r.set("status", Array.isArray(e.status) ? e.status.join(",") : e.status), e.sport && r.set("sport", e.sport);
|
|
241
242
|
let i = r.toString(), a = o(e.baseUrl, "/v1/catalog" + (i ? `?${i}` : "")), s = new Headers();
|
|
@@ -252,12 +253,12 @@ async function C(e) {
|
|
|
252
253
|
};
|
|
253
254
|
if (!l.ok) throw new t(n(l.status), l.status, `catalog request failed (HTTP ${l.status})`);
|
|
254
255
|
return {
|
|
255
|
-
tournaments:
|
|
256
|
+
tournaments: S(await l.json()),
|
|
256
257
|
etag: l.headers.get("etag") ?? void 0,
|
|
257
258
|
notModified: !1
|
|
258
259
|
};
|
|
259
260
|
}
|
|
260
|
-
function
|
|
261
|
+
function S(e) {
|
|
261
262
|
return (e.tournaments ?? []).map((e) => {
|
|
262
263
|
let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
|
|
263
264
|
return {
|
|
@@ -277,7 +278,7 @@ function oe(e) {
|
|
|
277
278
|
};
|
|
278
279
|
});
|
|
279
280
|
}
|
|
280
|
-
async function
|
|
281
|
+
async function ce(e) {
|
|
281
282
|
let r = o(e.baseUrl, `/v1/tournaments/${encodeURIComponent(e.urn)}`), i = new Headers();
|
|
282
283
|
e.etag && i.set("If-None-Match", e.etag);
|
|
283
284
|
let a = await c(r, {
|
|
@@ -296,13 +297,13 @@ async function se(e) {
|
|
|
296
297
|
};
|
|
297
298
|
if (!a.ok) throw new t(n(a.status), a.status, `tournament request failed (HTTP ${a.status})`);
|
|
298
299
|
return {
|
|
299
|
-
tournament:
|
|
300
|
+
tournament: le(await a.json()),
|
|
300
301
|
etag: a.headers.get("etag") ?? void 0,
|
|
301
302
|
notModified: !1,
|
|
302
303
|
notFound: !1
|
|
303
304
|
};
|
|
304
305
|
}
|
|
305
|
-
function
|
|
306
|
+
function le(e) {
|
|
306
307
|
let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
|
|
307
308
|
return {
|
|
308
309
|
urn: t,
|
|
@@ -320,12 +321,12 @@ function ce(e) {
|
|
|
320
321
|
}))
|
|
321
322
|
};
|
|
322
323
|
}
|
|
323
|
-
function
|
|
324
|
+
function ue(e) {
|
|
324
325
|
return e.tournaments.flatMap((e) => e.matches);
|
|
325
326
|
}
|
|
326
327
|
//#endregion
|
|
327
328
|
//#region src/core/poll.ts
|
|
328
|
-
function
|
|
329
|
+
function de(e) {
|
|
329
330
|
let r = Math.max(2e3, e.intervalMs ?? 1e4), i = new AbortController(), a, s, l, u = !1, d = () => {
|
|
330
331
|
u || (a = setTimeout(f, r));
|
|
331
332
|
}, f = async () => {
|
|
@@ -360,7 +361,7 @@ function ue(e) {
|
|
|
360
361
|
}
|
|
361
362
|
//#endregion
|
|
362
363
|
//#region src/core/events.ts
|
|
363
|
-
function
|
|
364
|
+
function C(e) {
|
|
364
365
|
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
366
|
if (r.signal.aborted) return t();
|
|
366
367
|
let n = setTimeout(t, e);
|
|
@@ -427,7 +428,7 @@ function w(e) {
|
|
|
427
428
|
i || (i = !0, r.abort());
|
|
428
429
|
} };
|
|
429
430
|
}
|
|
430
|
-
function
|
|
431
|
+
function w(e) {
|
|
431
432
|
try {
|
|
432
433
|
let t = new URL(e);
|
|
433
434
|
return t.hostname = `events.${t.hostname}`, t.pathname = "", t.search = "", t.origin;
|
|
@@ -437,27 +438,27 @@ function T(e) {
|
|
|
437
438
|
}
|
|
438
439
|
//#endregion
|
|
439
440
|
//#region src/core/drm/deviceId.ts
|
|
440
|
-
var
|
|
441
|
-
function
|
|
442
|
-
if (
|
|
441
|
+
var T = "havik.player.deviceId", E;
|
|
442
|
+
function D() {
|
|
443
|
+
if (E) return E;
|
|
443
444
|
try {
|
|
444
|
-
let e = globalThis.localStorage?.getItem(
|
|
445
|
-
if (e) return
|
|
445
|
+
let e = globalThis.localStorage?.getItem(T);
|
|
446
|
+
if (e) return E = e, e;
|
|
446
447
|
} catch {}
|
|
447
|
-
let e =
|
|
448
|
-
|
|
448
|
+
let e = pe();
|
|
449
|
+
E = e;
|
|
449
450
|
try {
|
|
450
|
-
globalThis.localStorage?.setItem(
|
|
451
|
+
globalThis.localStorage?.setItem(T, e);
|
|
451
452
|
} catch {}
|
|
452
453
|
return e;
|
|
453
454
|
}
|
|
454
|
-
function
|
|
455
|
-
|
|
455
|
+
function fe() {
|
|
456
|
+
E = void 0;
|
|
456
457
|
try {
|
|
457
|
-
globalThis.localStorage?.removeItem(
|
|
458
|
+
globalThis.localStorage?.removeItem(T);
|
|
458
459
|
} catch {}
|
|
459
460
|
}
|
|
460
|
-
function
|
|
461
|
+
function pe() {
|
|
461
462
|
let e = globalThis.crypto;
|
|
462
463
|
if (e && typeof e.randomUUID == "function") return e.randomUUID();
|
|
463
464
|
let t = /* @__PURE__ */ new Uint8Array(16);
|
|
@@ -469,22 +470,22 @@ function fe() {
|
|
|
469
470
|
}
|
|
470
471
|
//#endregion
|
|
471
472
|
//#region src/core/drm/headers.ts
|
|
472
|
-
function
|
|
473
|
+
function me(e, t, n = {}) {
|
|
473
474
|
let r = {
|
|
474
475
|
"x-api-key": t.apiKey,
|
|
475
476
|
"X-Match-Urn": e.matchUrn,
|
|
476
|
-
"X-Device-Id": n.deviceId ??
|
|
477
|
+
"X-Device-Id": n.deviceId ?? D(),
|
|
477
478
|
"Content-Type": "application/octet-stream"
|
|
478
479
|
};
|
|
479
480
|
return n.userId && (r["X-User-Id"] = n.userId), r;
|
|
480
481
|
}
|
|
481
482
|
//#endregion
|
|
482
483
|
//#region src/core/drm/support.ts
|
|
483
|
-
var
|
|
484
|
+
var he = 5e3, O = "video/mp4; codecs=\"avc1.42E01E\"", k = "audio/mp4; codecs=\"mp4a.40.2\"", ge = {
|
|
484
485
|
widevine: ["com.widevine.alpha"],
|
|
485
486
|
fairplay: ["com.apple.fps"]
|
|
486
487
|
};
|
|
487
|
-
function
|
|
488
|
+
function _e(e) {
|
|
488
489
|
return e === "fairplay" ? [{
|
|
489
490
|
initDataTypes: [
|
|
490
491
|
"sinf",
|
|
@@ -492,30 +493,30 @@ function M(e) {
|
|
|
492
493
|
"cenc"
|
|
493
494
|
],
|
|
494
495
|
videoCapabilities: [{
|
|
495
|
-
contentType:
|
|
496
|
+
contentType: O,
|
|
496
497
|
robustness: "",
|
|
497
498
|
encryptionScheme: "cbcs"
|
|
498
499
|
}],
|
|
499
500
|
audioCapabilities: [{
|
|
500
|
-
contentType:
|
|
501
|
+
contentType: k,
|
|
501
502
|
robustness: "",
|
|
502
503
|
encryptionScheme: "cbcs"
|
|
503
504
|
}]
|
|
504
505
|
}] : [{
|
|
505
506
|
initDataTypes: ["cenc"],
|
|
506
507
|
videoCapabilities: [{
|
|
507
|
-
contentType:
|
|
508
|
+
contentType: O,
|
|
508
509
|
robustness: "SW_SECURE_DECODE",
|
|
509
510
|
encryptionScheme: "cbcs"
|
|
510
511
|
}],
|
|
511
512
|
audioCapabilities: [{
|
|
512
|
-
contentType:
|
|
513
|
+
contentType: k,
|
|
513
514
|
robustness: "SW_SECURE_CRYPTO",
|
|
514
515
|
encryptionScheme: "cbcs"
|
|
515
516
|
}]
|
|
516
517
|
}];
|
|
517
518
|
}
|
|
518
|
-
function
|
|
519
|
+
function A(e, t) {
|
|
519
520
|
return new Promise((n, r) => {
|
|
520
521
|
let i = setTimeout(() => r(/* @__PURE__ */ Error("probe-timeout")), t);
|
|
521
522
|
e.then((e) => {
|
|
@@ -525,8 +526,8 @@ function N(e, t) {
|
|
|
525
526
|
});
|
|
526
527
|
});
|
|
527
528
|
}
|
|
528
|
-
async function
|
|
529
|
-
let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ??
|
|
529
|
+
async function j(e = {}) {
|
|
530
|
+
let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? he, r = {};
|
|
530
531
|
if (typeof window < "u" && window.isSecureContext === !1) return {
|
|
531
532
|
verdict: "insecure-context",
|
|
532
533
|
detail: r
|
|
@@ -538,7 +539,7 @@ async function P(e = {}) {
|
|
|
538
539
|
};
|
|
539
540
|
let a = !1, o = !1, s = Date.now() + n, c = () => Math.max(1, s - Date.now());
|
|
540
541
|
for (let e of t) {
|
|
541
|
-
let t =
|
|
542
|
+
let t = ge[e];
|
|
542
543
|
if (!t) {
|
|
543
544
|
r[e] = "unknown system";
|
|
544
545
|
continue;
|
|
@@ -549,7 +550,7 @@ async function P(e = {}) {
|
|
|
549
550
|
break;
|
|
550
551
|
}
|
|
551
552
|
try {
|
|
552
|
-
return await
|
|
553
|
+
return await A((await A(i(n, _e(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
|
|
553
554
|
verdict: "supported",
|
|
554
555
|
system: e,
|
|
555
556
|
detail: r
|
|
@@ -573,17 +574,17 @@ async function P(e = {}) {
|
|
|
573
574
|
}
|
|
574
575
|
//#endregion
|
|
575
576
|
//#region src/core/manifest.ts
|
|
576
|
-
var
|
|
577
|
-
function
|
|
578
|
-
return
|
|
577
|
+
var M = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
|
|
578
|
+
function N(e) {
|
|
579
|
+
return M.test(e);
|
|
579
580
|
}
|
|
580
581
|
//#endregion
|
|
581
582
|
//#region src/core/stats.ts
|
|
582
|
-
var
|
|
583
|
-
function
|
|
583
|
+
var P = { droppedFrames: 0 };
|
|
584
|
+
function F(e) {
|
|
584
585
|
return e.getVideoPlaybackQuality?.()?.droppedVideoFrames ?? 0;
|
|
585
586
|
}
|
|
586
|
-
function
|
|
587
|
+
function I(e, t) {
|
|
587
588
|
let n = [
|
|
588
589
|
["playing", () => t("playing")],
|
|
589
590
|
["waiting", () => t("buffering")],
|
|
@@ -600,7 +601,7 @@ function z(e, t) {
|
|
|
600
601
|
}
|
|
601
602
|
//#endregion
|
|
602
603
|
//#region src/core/engine/native.ts
|
|
603
|
-
function
|
|
604
|
+
function ve(e) {
|
|
604
605
|
try {
|
|
605
606
|
let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
|
|
606
607
|
return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
|
|
@@ -608,15 +609,15 @@ function he(e) {
|
|
|
608
609
|
return;
|
|
609
610
|
}
|
|
610
611
|
}
|
|
611
|
-
function
|
|
612
|
+
function L(e) {
|
|
612
613
|
return !!(e ?? (typeof document < "u" ? document.createElement("video") : void 0))?.canPlayType("application/vnd.apple.mpegurl");
|
|
613
614
|
}
|
|
614
|
-
function
|
|
615
|
+
function R() {
|
|
615
616
|
if (typeof window > "u") return !1;
|
|
616
617
|
let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
|
|
617
618
|
return e || t;
|
|
618
619
|
}
|
|
619
|
-
var
|
|
620
|
+
var z = class {
|
|
620
621
|
name = "native";
|
|
621
622
|
deps;
|
|
622
623
|
onLoaded;
|
|
@@ -646,7 +647,7 @@ var H = class {
|
|
|
646
647
|
type: "error",
|
|
647
648
|
error: new t("INTERNAL", 0, "native HLS playback error"),
|
|
648
649
|
fatal: !0
|
|
649
|
-
}), e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = n.manifestUrl, e.load();
|
|
650
|
+
}), e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = ye(n.manifestUrl, n.analytics?.sid), e.load();
|
|
650
651
|
}
|
|
651
652
|
armFairPlay() {
|
|
652
653
|
let { video: e, descriptor: n, credential: r, deviceId: i, userId: a, emit: o } = this.deps, s = n.drm?.fairplay;
|
|
@@ -659,7 +660,7 @@ var H = class {
|
|
|
659
660
|
});
|
|
660
661
|
this.onEncrypted = (t) => {
|
|
661
662
|
let o = t;
|
|
662
|
-
!o.initData || this.fairplayArmed || (this.fairplayArmed = !0, this.fairplayKeyIV =
|
|
663
|
+
!o.initData || this.fairplayArmed || (this.fairplayArmed = !0, this.fairplayKeyIV = ve(o.initData), (async () => {
|
|
663
664
|
try {
|
|
664
665
|
let t = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
|
|
665
666
|
initDataTypes: [o.initDataType],
|
|
@@ -751,7 +752,7 @@ var H = class {
|
|
|
751
752
|
e.seekable.length > 0 && (e.currentTime = e.seekable.end(e.seekable.length - 1));
|
|
752
753
|
}
|
|
753
754
|
getStats() {
|
|
754
|
-
let e = this.deps.video, t = { droppedFrames:
|
|
755
|
+
let e = this.deps.video, t = { droppedFrames: F(e) };
|
|
755
756
|
return e.duration === Infinity && (t.isLive = !0, e.seekable.length > 0 && (t.atLiveEdge = e.currentTime >= e.seekable.end(e.seekable.length - 1) - 2)), t;
|
|
756
757
|
}
|
|
757
758
|
stop() {
|
|
@@ -771,31 +772,38 @@ var H = class {
|
|
|
771
772
|
} catch {}
|
|
772
773
|
}
|
|
773
774
|
};
|
|
775
|
+
function ye(e, t) {
|
|
776
|
+
return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
|
|
777
|
+
}
|
|
774
778
|
//#endregion
|
|
775
779
|
//#region src/core/engine/hls.ts
|
|
776
|
-
function
|
|
780
|
+
function be() {
|
|
777
781
|
return e.isSupported();
|
|
778
782
|
}
|
|
779
|
-
var
|
|
780
|
-
function
|
|
783
|
+
var xe = 3, Se = 5, Ce = 3, we = 3e4, Te = 12e3, Ee = 3e3, B = 6e3, De = 4e3, Oe = 2, ke = 5, Ae = 2, je = 9, Me = .5;
|
|
784
|
+
function Ne(e) {
|
|
781
785
|
if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
|
|
782
786
|
delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
|
|
783
787
|
return;
|
|
784
788
|
}
|
|
785
|
-
e.liveSyncDuration ??=
|
|
786
|
-
let t = Math.max(12, e.liveSyncDuration +
|
|
787
|
-
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t),
|
|
789
|
+
e.liveSyncDuration ??= Ae;
|
|
790
|
+
let t = Math.max(12, e.liveSyncDuration + je);
|
|
791
|
+
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), Pe(e, e.liveSyncDuration);
|
|
788
792
|
}
|
|
789
|
-
function
|
|
793
|
+
function Pe(e, t) {
|
|
790
794
|
let n = (e, t, n) => Math.min(n, Math.max(t, e));
|
|
791
795
|
e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
|
|
792
796
|
}
|
|
793
|
-
var
|
|
797
|
+
var V = class {
|
|
794
798
|
name = "hls";
|
|
795
799
|
hls = null;
|
|
796
800
|
deps;
|
|
797
801
|
licenseUrl;
|
|
798
802
|
detectedLowLatency = !1;
|
|
803
|
+
bytesLoaded = 0;
|
|
804
|
+
playlistBytesLoaded = 0;
|
|
805
|
+
renditionSwitches = 0;
|
|
806
|
+
licenseTimeMs = 0;
|
|
799
807
|
mediaRecoveries = 0;
|
|
800
808
|
networkRecoveries = 0;
|
|
801
809
|
licenseRecoveries = 0;
|
|
@@ -809,6 +817,9 @@ var U = class {
|
|
|
809
817
|
lastAdvanceMs = 0;
|
|
810
818
|
endWatchdog = null;
|
|
811
819
|
endedEmitted = !1;
|
|
820
|
+
lastFragLoadingMs = 0;
|
|
821
|
+
starvedTicks = 0;
|
|
822
|
+
starvationKicks = 0;
|
|
812
823
|
chaseSuspended = !1;
|
|
813
824
|
savedLiveMaxLatency;
|
|
814
825
|
savedMaxSyncRate;
|
|
@@ -816,7 +827,7 @@ var U = class {
|
|
|
816
827
|
this.deps = e, this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl;
|
|
817
828
|
}
|
|
818
829
|
async load() {
|
|
819
|
-
let { descriptor: e, snapToLiveOnRefocus: n, video: r, emit: i } = this.deps, a =
|
|
830
|
+
let { descriptor: e, snapToLiveOnRefocus: n, video: r, emit: i } = this.deps, a = L(r) && R(), o = !!e.drm?.widevine?.licenseUrl && !a;
|
|
820
831
|
if (e.drmEnabled && !o) {
|
|
821
832
|
i({
|
|
822
833
|
type: "error",
|
|
@@ -840,7 +851,7 @@ var U = class {
|
|
|
840
851
|
let t = e.liveSyncPosition;
|
|
841
852
|
if (typeof t != "number" || !Number.isFinite(t)) return;
|
|
842
853
|
let { video: n } = this.deps;
|
|
843
|
-
n.currentTime <= t +
|
|
854
|
+
n.currentTime <= t + Me || (n.currentTime = t);
|
|
844
855
|
}
|
|
845
856
|
startHls() {
|
|
846
857
|
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 = {
|
|
@@ -863,29 +874,48 @@ var U = class {
|
|
|
863
874
|
},
|
|
864
875
|
licenseXhrSetup: (e, t) => {
|
|
865
876
|
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);
|
|
877
|
+
let o = performance.now();
|
|
878
|
+
e.addEventListener("loadend", () => {
|
|
879
|
+
this.licenseTimeMs = Math.max(1, Math.round(performance.now() - o));
|
|
880
|
+
});
|
|
866
881
|
}
|
|
867
882
|
} : {},
|
|
883
|
+
...n.analytics?.sid ? { cmcd: {
|
|
884
|
+
sessionId: n.analytics.sid,
|
|
885
|
+
contentId: n.matchUrn,
|
|
886
|
+
useHeaders: !1
|
|
887
|
+
} } : {},
|
|
868
888
|
...c
|
|
869
889
|
};
|
|
870
|
-
|
|
890
|
+
Ne(d);
|
|
871
891
|
let f = new e(d);
|
|
872
892
|
this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
|
|
873
893
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, l({ type: "ready" });
|
|
874
|
-
}), f.on(e.Events.FRAG_BUFFERED, () => {
|
|
875
|
-
(this.mediaRecoveries > 0 || this.networkRecoveries > 0 || this.licenseRecoveries > 0) && !this.recoveryResetTimer && (this.recoveryResetTimer = setTimeout(() => {
|
|
876
|
-
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.recoveryResetTimer = null;
|
|
877
|
-
},
|
|
894
|
+
}), f.on(e.Events.FRAG_BUFFERED, (e, t) => {
|
|
895
|
+
t?.frag?.type === "main" && (this.mediaRecoveries > 0 || this.networkRecoveries > 0 || this.licenseRecoveries > 0 || this.starvationKicks > 0) && !this.recoveryResetTimer && (this.recoveryResetTimer = setTimeout(() => {
|
|
896
|
+
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.recoveryResetTimer = null;
|
|
897
|
+
}, we));
|
|
898
|
+
}), f.on(e.Events.FRAG_LOADING, (e, t) => {
|
|
899
|
+
t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
|
|
900
|
+
}), f.on(e.Events.FRAG_LOADED, (e, t) => {
|
|
901
|
+
let n = t?.frag?.stats?.loaded;
|
|
902
|
+
typeof n == "number" && (this.bytesLoaded += n);
|
|
878
903
|
}), f.on(e.Events.LEVEL_LOADED, (e, t) => {
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
904
|
+
let n = t?.stats?.loaded;
|
|
905
|
+
if (typeof n == "number" && (this.playlistBytesLoaded += n), this.detectedLowLatency) return;
|
|
906
|
+
let r = t.details;
|
|
907
|
+
(r?.partList?.length || (r?.partTarget ?? 0) > 0) && (this.detectedLowLatency = !0, l({
|
|
882
908
|
type: "lowLatencyDetected",
|
|
883
909
|
value: !0
|
|
884
910
|
}));
|
|
885
|
-
}), f.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.endWatchdog = setInterval(() =>
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
911
|
+
}), f.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.endWatchdog = setInterval(() => {
|
|
912
|
+
this.checkEndStale(), this.checkStarvation();
|
|
913
|
+
}, Ee), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
|
|
914
|
+
this.renditionSwitches += 1, l({
|
|
915
|
+
type: "qualitychange",
|
|
916
|
+
index: t.level
|
|
917
|
+
});
|
|
918
|
+
}), f.on(e.Events.AUDIO_TRACK_SWITCHED, (e, t) => l({
|
|
889
919
|
type: "audiotrackchange",
|
|
890
920
|
id: t.id
|
|
891
921
|
})), f.on(e.Events.SUBTITLE_TRACK_SWITCH, (e, t) => l({
|
|
@@ -951,13 +981,17 @@ var U = class {
|
|
|
951
981
|
}
|
|
952
982
|
getStats() {
|
|
953
983
|
let e = this.hls, t = {
|
|
954
|
-
droppedFrames:
|
|
955
|
-
lowLatency: this.detectedLowLatency
|
|
984
|
+
droppedFrames: F(this.deps.video),
|
|
985
|
+
lowLatency: this.detectedLowLatency,
|
|
986
|
+
bytesLoaded: this.bytesLoaded,
|
|
987
|
+
playlistBytesLoaded: this.playlistBytesLoaded,
|
|
988
|
+
renditionSwitches: this.renditionSwitches,
|
|
989
|
+
licenseTimeMs: this.licenseTimeMs
|
|
956
990
|
};
|
|
957
991
|
if (e) {
|
|
958
992
|
typeof e.latency == "number" && (t.latencySeconds = e.latency), typeof e.targetLatency == "number" && e.targetLatency > 0 && (t.targetLatencySeconds = e.targetLatency), typeof e.bandwidthEstimate == "number" && (t.bandwidthKbps = Math.round(e.bandwidthEstimate / 1e3));
|
|
959
993
|
let n = e.currentLevel >= 0 ? e.levels[e.currentLevel] : void 0;
|
|
960
|
-
n && (t.levelHeight = n.height), typeof n?.details?.live == "boolean" && (t.isLive = n.details.live, typeof e.liveSyncPosition == "number" && (t.atLiveEdge = this.deps.video.currentTime >= e.liveSyncPosition - 1.5));
|
|
994
|
+
n && (t.levelHeight = n.height), n && typeof n.bitrate == "number" && (t.renditionBitrateKbps = Math.round(n.bitrate / 1e3)), typeof n?.details?.live == "boolean" && (t.isLive = n.details.live, typeof e.liveSyncPosition == "number" && (t.atLiveEdge = this.deps.video.currentTime >= e.liveSyncPosition - 1.5));
|
|
961
995
|
}
|
|
962
996
|
return t;
|
|
963
997
|
}
|
|
@@ -980,7 +1014,28 @@ var U = class {
|
|
|
980
1014
|
return;
|
|
981
1015
|
}
|
|
982
1016
|
let e = Date.now() - this.lastAdvanceMs;
|
|
983
|
-
!this.chaseSuspended && e >
|
|
1017
|
+
!this.chaseSuspended && e > B && this.suspendChasing(), e > Te && this.emitEnded("stalled");
|
|
1018
|
+
}
|
|
1019
|
+
checkStarvation() {
|
|
1020
|
+
let e = this.hls, { video: t } = this.deps;
|
|
1021
|
+
if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended) return;
|
|
1022
|
+
if (typeof document < "u" && document.hidden) {
|
|
1023
|
+
this.starvedTicks = 0;
|
|
1024
|
+
return;
|
|
1025
|
+
}
|
|
1026
|
+
let n = this.lastAdvanceMs !== 0 && Date.now() - this.lastAdvanceMs < B, r = this.lastFragLoadingMs !== 0 && Date.now() - this.lastFragLoadingMs > De;
|
|
1027
|
+
if (!(t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused && n && r)) {
|
|
1028
|
+
this.starvedTicks = 0;
|
|
1029
|
+
return;
|
|
1030
|
+
}
|
|
1031
|
+
if (!(++this.starvedTicks < Oe) && (this.starvedTicks = 0, !(this.starvationKicks >= ke))) {
|
|
1032
|
+
this.starvationKicks += 1, console.warn("havik-player: video starved while the live playlist advances (wedged hls.js fragment pipeline) — restarting load at the live edge");
|
|
1033
|
+
try {
|
|
1034
|
+
e.stopLoad(), e.startLoad(-1);
|
|
1035
|
+
} catch (e) {
|
|
1036
|
+
console.warn("havik-player: starvation kick failed", e);
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
984
1039
|
}
|
|
985
1040
|
suspendChasing() {
|
|
986
1041
|
let e = this.hls;
|
|
@@ -1022,7 +1077,7 @@ var U = class {
|
|
|
1022
1077
|
scheduleLicenseRetry(t) {
|
|
1023
1078
|
if (!(t.details === e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED || t.details === e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED)) return !1;
|
|
1024
1079
|
let n = t.response?.code ?? 0;
|
|
1025
|
-
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >=
|
|
1080
|
+
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= Ce) return !1;
|
|
1026
1081
|
this.licenseRecoveries += 1;
|
|
1027
1082
|
let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
|
|
1028
1083
|
return this.licenseRetryTimer = setTimeout(() => {
|
|
@@ -1050,7 +1105,7 @@ var U = class {
|
|
|
1050
1105
|
return;
|
|
1051
1106
|
}
|
|
1052
1107
|
if (t.type === e.ErrorTypes.NETWORK_ERROR) {
|
|
1053
|
-
if (this.networkRecoveries <
|
|
1108
|
+
if (this.networkRecoveries < Se) {
|
|
1054
1109
|
this.networkRecoveries += 1;
|
|
1055
1110
|
let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
|
|
1056
1111
|
this.networkRetryTimer = setTimeout(() => {
|
|
@@ -1066,7 +1121,7 @@ var U = class {
|
|
|
1066
1121
|
return;
|
|
1067
1122
|
}
|
|
1068
1123
|
if (t.type === e.ErrorTypes.MEDIA_ERROR) {
|
|
1069
|
-
if (this.mediaRecoveries <
|
|
1124
|
+
if (this.mediaRecoveries < xe) {
|
|
1070
1125
|
this.mediaRecoveries += 1, n.recoverMediaError();
|
|
1071
1126
|
return;
|
|
1072
1127
|
}
|
|
@@ -1088,7 +1143,172 @@ var U = class {
|
|
|
1088
1143
|
let r = e.response?.code ?? 0, i = e.details ?? e.type, a = e.reason ?? e.error?.message ?? "";
|
|
1089
1144
|
return new t(r === 401 ? "UNAUTHORIZED" : r === 403 || n === "DRM" ? "FORBIDDEN" : "INTERNAL", r, `${n} error: ${i}${a ? ` (${a})` : ""}`);
|
|
1090
1145
|
}
|
|
1091
|
-
},
|
|
1146
|
+
}, Fe = 15e3, Ie = 100, H = 1, U = {
|
|
1147
|
+
idle: "PLAYER_STATE_IDLE",
|
|
1148
|
+
waiting: "PLAYER_STATE_WAITING",
|
|
1149
|
+
loading: "PLAYER_STATE_LOADING",
|
|
1150
|
+
playing: "PLAYER_STATE_PLAYING",
|
|
1151
|
+
buffering: "PLAYER_STATE_BUFFERING",
|
|
1152
|
+
paused: "PLAYER_STATE_PAUSED",
|
|
1153
|
+
ended: "PLAYER_STATE_ENDED",
|
|
1154
|
+
error: "PLAYER_STATE_ERROR"
|
|
1155
|
+
};
|
|
1156
|
+
function Le(e) {
|
|
1157
|
+
try {
|
|
1158
|
+
let t = new URL(e), [n, ...r] = t.hostname.split(".");
|
|
1159
|
+
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);
|
|
1160
|
+
} catch {
|
|
1161
|
+
return;
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
var Re = class {
|
|
1165
|
+
opts;
|
|
1166
|
+
url;
|
|
1167
|
+
now;
|
|
1168
|
+
seq = 0;
|
|
1169
|
+
pending = [];
|
|
1170
|
+
timer = null;
|
|
1171
|
+
endedFlag = !1;
|
|
1172
|
+
lastBytes = 0;
|
|
1173
|
+
lastPlaylistBytes = 0;
|
|
1174
|
+
lastDropped = 0;
|
|
1175
|
+
lastSwitches = 0;
|
|
1176
|
+
playingSinceMs = null;
|
|
1177
|
+
hiddenSinceMs = null;
|
|
1178
|
+
playingTotalMs = 0;
|
|
1179
|
+
hiddenTotalMs = 0;
|
|
1180
|
+
lastHbPlayingMs = 0;
|
|
1181
|
+
lastHbHiddenMs = 0;
|
|
1182
|
+
rebufferCount = 0;
|
|
1183
|
+
rebufferTotalMs = 0;
|
|
1184
|
+
bufferingSinceMs = null;
|
|
1185
|
+
errorCount = 0;
|
|
1186
|
+
seekCount = 0;
|
|
1187
|
+
pauseCount = 0;
|
|
1188
|
+
bornMs;
|
|
1189
|
+
startupTimeMs = 0;
|
|
1190
|
+
manifestLoadMs = 0;
|
|
1191
|
+
firstFragLoadMs = 0;
|
|
1192
|
+
onPagehide = () => this.end("END_REASON_PAGEHIDE");
|
|
1193
|
+
onVisibility = () => {
|
|
1194
|
+
typeof document > "u" || (document.visibilityState === "hidden" ? this.hiddenSinceMs === null && (this.hiddenSinceMs = this.now()) : this.hiddenSinceMs !== null && (this.hiddenTotalMs += this.now() - this.hiddenSinceMs, this.hiddenSinceMs = null));
|
|
1195
|
+
};
|
|
1196
|
+
constructor(e) {
|
|
1197
|
+
this.opts = {
|
|
1198
|
+
...e,
|
|
1199
|
+
heartbeatMs: e.heartbeatMs ?? Fe
|
|
1200
|
+
}, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`, this.now = e.now ?? (() => Date.now()), this.bornMs = this.now();
|
|
1201
|
+
}
|
|
1202
|
+
start() {
|
|
1203
|
+
this.endedFlag || (this.enqueue({ sessionStart: {
|
|
1204
|
+
player: this.opts.player,
|
|
1205
|
+
sdkVersion: this.opts.sdkVersion
|
|
1206
|
+
} }), this.flush(), this.timer = setInterval(() => this.heartbeat(), this.opts.heartbeatMs), typeof window < "u" && window.addEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.addEventListener("visibilitychange", this.onVisibility), this.onVisibility()));
|
|
1207
|
+
}
|
|
1208
|
+
noteStateChange(e, t, n, r) {
|
|
1209
|
+
if (this.endedFlag || e === t) return;
|
|
1210
|
+
let i = this.now();
|
|
1211
|
+
t === "playing" ? (this.playingSinceMs === null && (this.playingSinceMs = i), this.startupTimeMs === 0 && (this.startupTimeMs = Math.max(H, i - this.bornMs))) : this.playingSinceMs !== null && (this.playingTotalMs += i - this.playingSinceMs, this.playingSinceMs = null), t === "buffering" && e === "playing" ? (this.rebufferCount += 1, this.bufferingSinceMs = i) : e === "buffering" && this.bufferingSinceMs !== null && (this.rebufferTotalMs += i - this.bufferingSinceMs, this.bufferingSinceMs = null), t === "paused" && (this.pauseCount += 1);
|
|
1212
|
+
let a = {
|
|
1213
|
+
fromState: U[e] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
1214
|
+
toState: U[t] ?? "PLAYER_STATE_UNSPECIFIED"
|
|
1215
|
+
};
|
|
1216
|
+
n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
|
|
1217
|
+
}
|
|
1218
|
+
noteReady() {
|
|
1219
|
+
this.manifestLoadMs === 0 && (this.manifestLoadMs = Math.max(H, this.now() - this.bornMs));
|
|
1220
|
+
}
|
|
1221
|
+
noteFirstBytes() {
|
|
1222
|
+
this.firstFragLoadMs === 0 && (this.firstFragLoadMs = Math.max(H, this.now() - this.bornMs));
|
|
1223
|
+
}
|
|
1224
|
+
noteSeek() {
|
|
1225
|
+
this.endedFlag || (this.seekCount += 1);
|
|
1226
|
+
}
|
|
1227
|
+
noteError(e, t, n, r, i) {
|
|
1228
|
+
if (this.endedFlag) return;
|
|
1229
|
+
this.errorCount += 1;
|
|
1230
|
+
let a = { code: e };
|
|
1231
|
+
t && (a.detail = t), n && (a.fatal = !0), r > 0 && (a.httpStatus = r), i > 0 && (a.positionMs = Math.round(i)), this.enqueue({ error: a }), this.flush();
|
|
1232
|
+
}
|
|
1233
|
+
noteEnded() {
|
|
1234
|
+
this.end("END_REASON_ENDED");
|
|
1235
|
+
}
|
|
1236
|
+
noteDestroyed() {
|
|
1237
|
+
this.end("END_REASON_STOPPED");
|
|
1238
|
+
}
|
|
1239
|
+
noteFatal() {
|
|
1240
|
+
this.end("END_REASON_FATAL_ERROR");
|
|
1241
|
+
}
|
|
1242
|
+
heartbeat() {
|
|
1243
|
+
if (this.endedFlag) return;
|
|
1244
|
+
let e = this.opts.sample(), t = this.now(), n = this.playingTotalMs;
|
|
1245
|
+
this.playingSinceMs !== null && (n += t - this.playingSinceMs);
|
|
1246
|
+
let r = this.hiddenTotalMs;
|
|
1247
|
+
this.hiddenSinceMs !== null && (r += t - this.hiddenSinceMs);
|
|
1248
|
+
let i = {}, a = e.bytesLoaded ?? 0;
|
|
1249
|
+
a > this.lastBytes && (i.bytesDownloadedDelta = a - this.lastBytes), this.lastBytes = a;
|
|
1250
|
+
let o = e.playlistBytesLoaded ?? 0;
|
|
1251
|
+
o > this.lastPlaylistBytes && (i.playlistBytesDelta = o - this.lastPlaylistBytes), this.lastPlaylistBytes = o;
|
|
1252
|
+
let s = e.droppedFrames ?? 0;
|
|
1253
|
+
s > this.lastDropped && (i.droppedFramesDelta = s - this.lastDropped), this.lastDropped = s;
|
|
1254
|
+
let c = e.renditionSwitches ?? 0;
|
|
1255
|
+
c > this.lastSwitches && (i.renditionSwitchesDelta = c - this.lastSwitches), this.lastSwitches = c, n > this.lastHbPlayingMs && (i.playingMsDelta = Math.round(n - this.lastHbPlayingMs)), this.lastHbPlayingMs = n, r > this.lastHbHiddenMs && (i.hiddenMsDelta = Math.round(r - this.lastHbHiddenMs)), this.lastHbHiddenMs = r, typeof e.latencySeconds == "number" && (i.latencyMs = Math.round(e.latencySeconds * 1e3)), typeof e.targetLatencySeconds == "number" && (i.targetLatencyMs = Math.round(e.targetLatencySeconds * 1e3)), typeof e.bandwidthKbps == "number" && (i.bandwidthEstKbps = e.bandwidthKbps), typeof e.levelHeight == "number" && (i.renditionHeight = e.levelHeight), typeof e.renditionBitrateKbps == "number" && (i.renditionBitrateKbps = e.renditionBitrateKbps), e.atLiveEdge === !0 && (i.atLiveEdge = !0);
|
|
1256
|
+
let l = this.bufferedMsFrom(e);
|
|
1257
|
+
l > 0 && (i.bufferedMs = l), i.playerState = U[e.state] ?? "PLAYER_STATE_UNSPECIFIED", this.enqueue({ heartbeat: i }), this.flush(), a > 0 && this.noteFirstBytes();
|
|
1258
|
+
}
|
|
1259
|
+
bufferedMsFrom(e) {
|
|
1260
|
+
let t = e;
|
|
1261
|
+
return typeof t.bufferedMs == "number" ? Math.round(t.bufferedMs) : 0;
|
|
1262
|
+
}
|
|
1263
|
+
end(e) {
|
|
1264
|
+
if (this.endedFlag) return;
|
|
1265
|
+
this.endedFlag = !0;
|
|
1266
|
+
let t = this.now();
|
|
1267
|
+
this.playingSinceMs !== null && (this.playingTotalMs += t - this.playingSinceMs, this.playingSinceMs = null), this.hiddenSinceMs !== null && (this.hiddenTotalMs += t - this.hiddenSinceMs, this.hiddenSinceMs = null), this.bufferingSinceMs !== null && (this.rebufferTotalMs += t - this.bufferingSinceMs, this.bufferingSinceMs = null), this.timer &&= (clearInterval(this.timer), null), typeof window < "u" && window.removeEventListener("pagehide", this.onPagehide), typeof document < "u" && document.removeEventListener("visibilitychange", this.onVisibility);
|
|
1268
|
+
let n = this.safeSample(), r = { reason: e }, i = n?.bytesLoaded ?? this.lastBytes;
|
|
1269
|
+
i > 0 && (r.bytesDownloadedTotal = i), this.playingTotalMs > 0 && (r.watchTimeMs = Math.round(this.playingTotalMs)), this.rebufferCount > 0 && (r.rebufferCount = this.rebufferCount), this.rebufferTotalMs > 0 && (r.rebufferTimeMs = Math.round(this.rebufferTotalMs)), this.startupTimeMs > 0 && (r.startupTimeMs = Math.round(this.startupTimeMs)), this.manifestLoadMs > 0 && (r.manifestLoadMs = Math.round(this.manifestLoadMs)), this.firstFragLoadMs > 0 && (r.firstFragLoadMs = Math.round(this.firstFragLoadMs));
|
|
1270
|
+
let a = n?.licenseTimeMs ?? 0;
|
|
1271
|
+
a > 0 && (r.licenseTimeMs = Math.round(a));
|
|
1272
|
+
let o = n?.droppedFrames ?? this.lastDropped;
|
|
1273
|
+
o > 0 && (r.droppedFramesTotal = o), this.errorCount > 0 && (r.errorCount = this.errorCount), this.hiddenTotalMs > 0 && (r.hiddenTimeMs = Math.round(this.hiddenTotalMs)), this.seekCount > 0 && (r.seekCount = this.seekCount), this.pauseCount > 0 && (r.pauseCount = this.pauseCount), this.pending.push(this.wrap({ sessionEnd: r })), this.flush(e === "END_REASON_PAGEHIDE");
|
|
1274
|
+
}
|
|
1275
|
+
safeSample() {
|
|
1276
|
+
try {
|
|
1277
|
+
return this.opts.sample();
|
|
1278
|
+
} catch {
|
|
1279
|
+
return null;
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
wrap(e) {
|
|
1283
|
+
return this.seq += 1, {
|
|
1284
|
+
sid: this.opts.sid,
|
|
1285
|
+
clientTime: new Date(this.now()).toISOString(),
|
|
1286
|
+
seq: this.seq,
|
|
1287
|
+
...e
|
|
1288
|
+
};
|
|
1289
|
+
}
|
|
1290
|
+
enqueue(e) {
|
|
1291
|
+
for (this.pending.push(this.wrap(e)); this.pending.length > Ie;) {
|
|
1292
|
+
let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
|
|
1293
|
+
this.pending.splice(e >= 0 ? e : 0, 1);
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
flush(e = !1) {
|
|
1297
|
+
if (this.pending.length === 0) return;
|
|
1298
|
+
let t = JSON.stringify({ beacons: this.pending });
|
|
1299
|
+
if (this.pending = [], e) {
|
|
1300
|
+
let e = this.opts.sendBeacon ?? (typeof navigator < "u" && navigator.sendBeacon ? navigator.sendBeacon.bind(navigator) : void 0);
|
|
1301
|
+
if (e && e(this.url, t)) return;
|
|
1302
|
+
}
|
|
1303
|
+
let n = this.opts.fetchFn ?? (typeof fetch < "u" ? fetch : void 0);
|
|
1304
|
+
n && n(this.url, {
|
|
1305
|
+
method: "POST",
|
|
1306
|
+
headers: { "content-type": "application/json" },
|
|
1307
|
+
body: t,
|
|
1308
|
+
keepalive: !0
|
|
1309
|
+
}).catch(() => {});
|
|
1310
|
+
}
|
|
1311
|
+
}, ze = "1.9.0", W = {
|
|
1092
1312
|
accent: "#E1B600",
|
|
1093
1313
|
accentText: "#1B1C23",
|
|
1094
1314
|
background: "#0e0f13",
|
|
@@ -1121,15 +1341,15 @@ function K(e, t) {
|
|
|
1121
1341
|
}
|
|
1122
1342
|
//#endregion
|
|
1123
1343
|
//#region src/ui/styles.ts
|
|
1124
|
-
var q = "havik-player-styles",
|
|
1125
|
-
function
|
|
1344
|
+
var q = "havik-player-styles", Be = "\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/* 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";
|
|
1345
|
+
function Ve(e = document) {
|
|
1126
1346
|
if (e.getElementById(q)) return;
|
|
1127
1347
|
let t = e.createElement("style");
|
|
1128
|
-
t.id = q, t.textContent =
|
|
1348
|
+
t.id = q, t.textContent = Be, e.head.appendChild(t);
|
|
1129
1349
|
}
|
|
1130
1350
|
//#endregion
|
|
1131
1351
|
//#region src/ui/icons.ts
|
|
1132
|
-
var
|
|
1352
|
+
var He = {
|
|
1133
1353
|
play: "<path d=\"M8 5v14l11-7z\"/>",
|
|
1134
1354
|
pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
|
|
1135
1355
|
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\"/>",
|
|
@@ -1143,20 +1363,20 @@ var je = {
|
|
|
1143
1363
|
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\"/>"
|
|
1144
1364
|
};
|
|
1145
1365
|
function J(e) {
|
|
1146
|
-
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${
|
|
1366
|
+
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${He[e]}</svg>`;
|
|
1147
1367
|
}
|
|
1148
1368
|
//#endregion
|
|
1149
1369
|
//#region src/ui/controls.ts
|
|
1150
|
-
var
|
|
1370
|
+
var Ue = 3e3, We = /* @__PURE__ */ new Set([
|
|
1151
1371
|
"GONE",
|
|
1152
1372
|
"NOT_FOUND",
|
|
1153
1373
|
"INVALID_URN",
|
|
1154
1374
|
"UNAUTHORIZED"
|
|
1155
1375
|
]);
|
|
1156
|
-
function
|
|
1157
|
-
return new
|
|
1376
|
+
function Ge(e) {
|
|
1377
|
+
return new Ke(e);
|
|
1158
1378
|
}
|
|
1159
|
-
var
|
|
1379
|
+
var Ke = class {
|
|
1160
1380
|
root;
|
|
1161
1381
|
video;
|
|
1162
1382
|
player;
|
|
@@ -1196,7 +1416,7 @@ var Fe = class {
|
|
|
1196
1416
|
scrubbing = !1;
|
|
1197
1417
|
offFns = [];
|
|
1198
1418
|
constructor(e) {
|
|
1199
|
-
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ??
|
|
1419
|
+
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Ue, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.errorMessage = e.errorMessage, Ve(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");
|
|
1200
1420
|
let t = (e, t, n) => {
|
|
1201
1421
|
let r = this.doc.createElement(e);
|
|
1202
1422
|
if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
|
|
@@ -1283,7 +1503,7 @@ var Fe = class {
|
|
|
1283
1503
|
e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML = J("play"), e.addEventListener("click", () => void this.player.play()), t.append(e);
|
|
1284
1504
|
} else {
|
|
1285
1505
|
let n = this.doc.createElement("div");
|
|
1286
|
-
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 && !
|
|
1506
|
+
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 && !We.has(this.lastError.code)) {
|
|
1287
1507
|
let e = this.doc.createElement("button");
|
|
1288
1508
|
e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${J("retry")}<span>Retry</span>`, e.addEventListener("click", () => void this.player.retry()), t.append(e);
|
|
1289
1509
|
}
|
|
@@ -1374,17 +1594,17 @@ var Fe = class {
|
|
|
1374
1594
|
renderQualityMenu() {
|
|
1375
1595
|
let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
|
|
1376
1596
|
n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
|
|
1377
|
-
for (let n of e) this.menu.append(this.menuItem(
|
|
1597
|
+
for (let n of e) this.menu.append(this.menuItem(qe(n), t === n.index, () => this.player.setQuality(n.index)));
|
|
1378
1598
|
}
|
|
1379
1599
|
renderAudioMenu() {
|
|
1380
1600
|
let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
|
|
1381
1601
|
t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
|
|
1382
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
1602
|
+
for (let t of e) this.menu.append(this.menuItem(Je(t), t.default, () => this.player.setAudioTrack(t.id)));
|
|
1383
1603
|
}
|
|
1384
1604
|
renderCcMenu() {
|
|
1385
1605
|
let e = this.player.getTextTracks(), t = this.doc.createElement("div");
|
|
1386
1606
|
t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
|
|
1387
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
1607
|
+
for (let t of e) this.menu.append(this.menuItem(Ye(t), !1, () => this.player.setTextTrack(t.id)));
|
|
1388
1608
|
}
|
|
1389
1609
|
onTracksChanged() {
|
|
1390
1610
|
this.openMenu && this.renderMenu(this.openMenu);
|
|
@@ -1490,27 +1710,27 @@ function Y(e) {
|
|
|
1490
1710
|
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");
|
|
1491
1711
|
return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
|
|
1492
1712
|
}
|
|
1493
|
-
function
|
|
1713
|
+
function qe(e) {
|
|
1494
1714
|
return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
|
|
1495
1715
|
}
|
|
1496
|
-
function
|
|
1716
|
+
function Je(e) {
|
|
1497
1717
|
return e.name || e.lang || `Track ${e.id}`;
|
|
1498
1718
|
}
|
|
1499
|
-
function
|
|
1719
|
+
function Ye(e) {
|
|
1500
1720
|
return e.name || e.lang || `Track ${e.id}`;
|
|
1501
1721
|
}
|
|
1502
1722
|
//#endregion
|
|
1503
1723
|
//#region src/managed/index.ts
|
|
1504
|
-
var
|
|
1505
|
-
async function
|
|
1724
|
+
var Xe = 6e3, X = 45e3, Z = 2e3, Ze = 3, Qe = 2e3, $e = 480 * 1e3;
|
|
1725
|
+
async function Q(e) {
|
|
1506
1726
|
if (!e.video || typeof e.video.play != "function") throw new t("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
1507
1727
|
if (!e.baseUrl) throw new t("INTERNAL", 0, "createPlayer: baseUrl is required");
|
|
1508
1728
|
if (!e.matchUrn) throw new t("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
1509
1729
|
if (!e.credential) throw new t("INTERNAL", 0, "createPlayer: credential is required");
|
|
1510
|
-
let n = new
|
|
1730
|
+
let n = new et(e);
|
|
1511
1731
|
return await n.start(), n;
|
|
1512
1732
|
}
|
|
1513
|
-
var
|
|
1733
|
+
var et = class {
|
|
1514
1734
|
opts;
|
|
1515
1735
|
abort = new AbortController();
|
|
1516
1736
|
listeners = {};
|
|
@@ -1531,6 +1751,8 @@ var We = class {
|
|
|
1531
1751
|
armSseTimer = null;
|
|
1532
1752
|
armFallbackCtrl = null;
|
|
1533
1753
|
_lastError = null;
|
|
1754
|
+
analyticsSession = null;
|
|
1755
|
+
detachSeekListener;
|
|
1534
1756
|
constructor(e) {
|
|
1535
1757
|
this.opts = e;
|
|
1536
1758
|
}
|
|
@@ -1544,7 +1766,7 @@ var We = class {
|
|
|
1544
1766
|
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");
|
|
1545
1767
|
let e = ++this.loadGen, n = this.resolveOptions();
|
|
1546
1768
|
try {
|
|
1547
|
-
let t = await
|
|
1769
|
+
let t = await v(n);
|
|
1548
1770
|
if (await this.onResolved(t, e), e === this.loadGen && this._state === "error" && this._lastError) {
|
|
1549
1771
|
let e = this._lastError;
|
|
1550
1772
|
throw this.destroy(), e;
|
|
@@ -1566,11 +1788,11 @@ var We = class {
|
|
|
1566
1788
|
};
|
|
1567
1789
|
}
|
|
1568
1790
|
beginArming(e, t) {
|
|
1569
|
-
let n = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ??
|
|
1791
|
+
let n = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? w(this.opts.baseUrl);
|
|
1570
1792
|
n ? this.armWithSse(e, n, t) : this.beginArmingByPolling(e);
|
|
1571
1793
|
}
|
|
1572
1794
|
beginArmingByPolling(e) {
|
|
1573
|
-
|
|
1795
|
+
y({
|
|
1574
1796
|
...this.resolveOptions(),
|
|
1575
1797
|
signal: this.abort.signal,
|
|
1576
1798
|
waitForLive: this.buildWaitConfig(e)
|
|
@@ -1604,7 +1826,7 @@ var We = class {
|
|
|
1604
1826
|
}
|
|
1605
1827
|
}
|
|
1606
1828
|
}, m = () => {
|
|
1607
|
-
a || o || f() || (o = !0,
|
|
1829
|
+
a || o || f() || (o = !0, y({
|
|
1608
1830
|
...this.resolveOptions(),
|
|
1609
1831
|
signal: s.signal,
|
|
1610
1832
|
waitForLive: this.buildWaitConfig(e)
|
|
@@ -1612,7 +1834,7 @@ var We = class {
|
|
|
1612
1834
|
a || f() || s.signal.aborted || (a = !0, this.closeArming(), this.fail(e instanceof t ? e : new t("INTERNAL", 0, String(e))));
|
|
1613
1835
|
}));
|
|
1614
1836
|
}, h = () => {
|
|
1615
|
-
a || f() ||
|
|
1837
|
+
a || f() || v(this.resolveOptions()).then((e) => p(e)).catch((e) => {
|
|
1616
1838
|
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))));
|
|
1617
1839
|
});
|
|
1618
1840
|
}, g = (e) => {
|
|
@@ -1620,13 +1842,13 @@ var We = class {
|
|
|
1620
1842
|
!a && !f() && m();
|
|
1621
1843
|
}, e);
|
|
1622
1844
|
};
|
|
1623
|
-
g(
|
|
1845
|
+
g(Xe), this.armingSub = C({
|
|
1624
1846
|
eventsBaseUrl: n,
|
|
1625
1847
|
matchUrn: this.opts.matchUrn,
|
|
1626
1848
|
credential: this.opts.credential,
|
|
1627
1849
|
onAlive: () => g(X),
|
|
1628
1850
|
onState: (e) => {
|
|
1629
|
-
a || f() || (e.state === "live" || e.state === "gone") && setTimeout(h, Math.random() *
|
|
1851
|
+
a || f() || (e.state === "live" || e.state === "gone") && setTimeout(h, Math.random() * Z);
|
|
1630
1852
|
},
|
|
1631
1853
|
onError: () => m()
|
|
1632
1854
|
});
|
|
@@ -1649,7 +1871,7 @@ var We = class {
|
|
|
1649
1871
|
let n = await a(this.opts.credential);
|
|
1650
1872
|
if (this.destroyed || t !== this.loadGen) return;
|
|
1651
1873
|
this.setState("loading");
|
|
1652
|
-
let r = this.createEngine(e, n), i =
|
|
1874
|
+
let r = this.createEngine(e, n), i = I(this.opts.video, (e) => {
|
|
1653
1875
|
this._state === "ended" || this._state === "error" || this.setState(e);
|
|
1654
1876
|
});
|
|
1655
1877
|
if (await r.load(), this.destroyed || t !== this.loadGen) {
|
|
@@ -1660,7 +1882,32 @@ var We = class {
|
|
|
1660
1882
|
i(), r.destroy();
|
|
1661
1883
|
return;
|
|
1662
1884
|
}
|
|
1663
|
-
this.engine = r, this.detachMedia = i, this.opts.maxBitrate != null && r.setMaxBitrate(this.opts.maxBitrate), this.startStats(), this.scheduleLicenseRefresh(), this.startLiveState(t);
|
|
1885
|
+
this.engine = r, this.detachMedia = i, this.opts.maxBitrate != null && r.setMaxBitrate(this.opts.maxBitrate), this.startStats(), this.scheduleLicenseRefresh(), this.startLiveState(t), this.startAnalytics(e, r);
|
|
1886
|
+
}
|
|
1887
|
+
startAnalytics(e, t) {
|
|
1888
|
+
if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachSeekListener?.(), this.opts.analytics === !1) return;
|
|
1889
|
+
let n = e.analytics?.sid;
|
|
1890
|
+
if (!n) return;
|
|
1891
|
+
let r = (typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0) ?? Le(this.opts.baseUrl);
|
|
1892
|
+
if (!r) return;
|
|
1893
|
+
let i = this.opts.video, a = new Re({
|
|
1894
|
+
endpoint: r,
|
|
1895
|
+
sid: n,
|
|
1896
|
+
player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
|
|
1897
|
+
sdkVersion: ze,
|
|
1898
|
+
sample: () => {
|
|
1899
|
+
let e = this.engine?.getStats() ?? P, t = i.buffered.length ? Math.max(0, i.buffered.end(i.buffered.length - 1) - i.currentTime) : 0;
|
|
1900
|
+
return {
|
|
1901
|
+
...e,
|
|
1902
|
+
bufferedMs: Math.round(t * 1e3),
|
|
1903
|
+
state: this._state,
|
|
1904
|
+
positionMs: Math.round(i.currentTime * 1e3)
|
|
1905
|
+
};
|
|
1906
|
+
}
|
|
1907
|
+
});
|
|
1908
|
+
this.analyticsSession = a;
|
|
1909
|
+
let o = () => a.noteSeek();
|
|
1910
|
+
i.addEventListener("seeking", o), this.detachSeekListener = () => i.removeEventListener("seeking", o), a.start();
|
|
1664
1911
|
}
|
|
1665
1912
|
createEngine(e, n) {
|
|
1666
1913
|
let r = { ...this.opts.hlsConfig };
|
|
@@ -1669,7 +1916,7 @@ var We = class {
|
|
|
1669
1916
|
video: this.opts.video,
|
|
1670
1917
|
descriptor: e,
|
|
1671
1918
|
credential: n,
|
|
1672
|
-
deviceId:
|
|
1919
|
+
deviceId: D(),
|
|
1673
1920
|
userId: this.opts.userId,
|
|
1674
1921
|
lowLatency: this.opts.lowLatency === void 0 || this.opts.lowLatency === "auto" || this.opts.lowLatency,
|
|
1675
1922
|
snapToLiveOnRefocus: this.opts.snapToLiveOnRefocus,
|
|
@@ -1677,17 +1924,17 @@ var We = class {
|
|
|
1677
1924
|
hlsConfig: r,
|
|
1678
1925
|
emit: (e) => this.onEngineEvent(e)
|
|
1679
1926
|
}, a = this.opts.engine ?? "auto";
|
|
1680
|
-
if (a === "native") return new
|
|
1681
|
-
if (a === "hls") return new
|
|
1682
|
-
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl &&
|
|
1683
|
-
if (
|
|
1684
|
-
if (
|
|
1927
|
+
if (a === "native") return new z(i);
|
|
1928
|
+
if (a === "hls") return new V(i);
|
|
1929
|
+
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && L(this.opts.video) && R()) return new z(i);
|
|
1930
|
+
if (be()) return new V(i);
|
|
1931
|
+
if (L(this.opts.video)) return new z(i);
|
|
1685
1932
|
throw new t("INTERNAL", 0, "no supported HLS playback engine in this browser");
|
|
1686
1933
|
}
|
|
1687
1934
|
onEngineEvent(e) {
|
|
1688
1935
|
if (!this.destroyed) switch (e.type) {
|
|
1689
1936
|
case "ready":
|
|
1690
|
-
this.emit("ready"), this.opts.autoplay !== !1 && this.play();
|
|
1937
|
+
this.analyticsSession?.noteReady(), this.emit("ready"), this.opts.autoplay !== !1 && this.play();
|
|
1691
1938
|
break;
|
|
1692
1939
|
case "lowLatencyDetected":
|
|
1693
1940
|
this._descriptor && (this._descriptor.isLowLatency = e.value);
|
|
@@ -1705,17 +1952,17 @@ var We = class {
|
|
|
1705
1952
|
this.onStreamEnded();
|
|
1706
1953
|
break;
|
|
1707
1954
|
case "error":
|
|
1708
|
-
e.fatal ? this.fail(e.error) : this.emit("warning", e.error);
|
|
1955
|
+
this.analyticsSession?.noteError(e.error.code, e.error.message, e.fatal, e.error.httpStatus ?? 0, Math.round(this.opts.video.currentTime * 1e3)), e.fatal ? this.fail(e.error) : this.emit("warning", e.error);
|
|
1709
1956
|
break;
|
|
1710
1957
|
}
|
|
1711
1958
|
}
|
|
1712
1959
|
startLiveState(e) {
|
|
1713
1960
|
if (this.opts.liveStateEvents === !1) return;
|
|
1714
|
-
let n = this.opts.eventsBaseUrl ??
|
|
1961
|
+
let n = this.opts.eventsBaseUrl ?? w(this.opts.baseUrl);
|
|
1715
1962
|
if (!n) return;
|
|
1716
1963
|
this.closeLiveState();
|
|
1717
1964
|
let r = 0, i = !1;
|
|
1718
|
-
this.liveStateSub =
|
|
1965
|
+
this.liveStateSub = C({
|
|
1719
1966
|
eventsBaseUrl: n,
|
|
1720
1967
|
matchUrn: this.opts.matchUrn,
|
|
1721
1968
|
credential: this.opts.credential,
|
|
@@ -1726,7 +1973,7 @@ var We = class {
|
|
|
1726
1973
|
r = 0, i = !1;
|
|
1727
1974
|
},
|
|
1728
1975
|
onError: () => {
|
|
1729
|
-
this.destroyed || e !== this.loadGen || i || (r += 1, r >=
|
|
1976
|
+
this.destroyed || e !== this.loadGen || i || (r += 1, r >= Ze && (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.`))));
|
|
1730
1977
|
}
|
|
1731
1978
|
});
|
|
1732
1979
|
}
|
|
@@ -1748,7 +1995,7 @@ var We = class {
|
|
|
1748
1995
|
}
|
|
1749
1996
|
t.controls = !1;
|
|
1750
1997
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
1751
|
-
r && r.insertBefore(n, t), n.appendChild(t), K(n, this.opts.theme), this.container = n, this.controlBar =
|
|
1998
|
+
r && r.insertBefore(n, t), n.appendChild(t), K(n, this.opts.theme), this.container = n, this.controlBar = Ge({
|
|
1752
1999
|
root: n,
|
|
1753
2000
|
video: t,
|
|
1754
2001
|
player: this,
|
|
@@ -1771,9 +2018,11 @@ var We = class {
|
|
|
1771
2018
|
}
|
|
1772
2019
|
startStats() {
|
|
1773
2020
|
this.stopStats();
|
|
1774
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
2021
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? Qe);
|
|
1775
2022
|
this.statsTimer = setInterval(() => {
|
|
1776
|
-
|
|
2023
|
+
if (!this.engine) return;
|
|
2024
|
+
let e = this.engine.getStats();
|
|
2025
|
+
(e.bytesLoaded ?? 0) > 0 && this.analyticsSession?.noteFirstBytes(), this.emit("stats", e);
|
|
1777
2026
|
}, e);
|
|
1778
2027
|
}
|
|
1779
2028
|
stopStats() {
|
|
@@ -1781,7 +2030,7 @@ var We = class {
|
|
|
1781
2030
|
}
|
|
1782
2031
|
scheduleLicenseRefresh() {
|
|
1783
2032
|
this.stopRefresh();
|
|
1784
|
-
let e = this.opts.licenseRefreshMs ??
|
|
2033
|
+
let e = this.opts.licenseRefreshMs ?? $e;
|
|
1785
2034
|
!e || !this._descriptor?.drmEnabled || (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
1786
2035
|
}
|
|
1787
2036
|
stopRefresh() {
|
|
@@ -1790,7 +2039,7 @@ var We = class {
|
|
|
1790
2039
|
async refreshLicense() {
|
|
1791
2040
|
let e = this.engine;
|
|
1792
2041
|
if (!(this.destroyed || !e)) try {
|
|
1793
|
-
let t = await
|
|
2042
|
+
let t = await v(this.resolveOptions());
|
|
1794
2043
|
if (this.destroyed || this.engine !== e) return;
|
|
1795
2044
|
let n = t.drm?.widevine?.licenseUrl, r = t.drm?.fairplay?.licenseUrl;
|
|
1796
2045
|
(n || r) && (e.setLicenseUrls({
|
|
@@ -1818,7 +2067,7 @@ var We = class {
|
|
|
1818
2067
|
this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
|
|
1819
2068
|
}
|
|
1820
2069
|
getStats() {
|
|
1821
|
-
return this.engine?.getStats() ??
|
|
2070
|
+
return this.engine?.getStats() ?? P;
|
|
1822
2071
|
}
|
|
1823
2072
|
getQualityLevels() {
|
|
1824
2073
|
return this.engine?.getQualityLevels() ?? [];
|
|
@@ -1864,7 +2113,7 @@ var We = class {
|
|
|
1864
2113
|
let e = ++this.loadGen;
|
|
1865
2114
|
this.stopStats(), this.stopRefresh(), this.closeArming(), this.closeLiveState(), this.detachMedia?.(), this.engine?.destroy(), this.engine = null;
|
|
1866
2115
|
try {
|
|
1867
|
-
let t = await
|
|
2116
|
+
let t = await y({
|
|
1868
2117
|
...this.resolveOptions(),
|
|
1869
2118
|
waitForLive: this.opts.waitForLive ? this.buildWaitConfig(e) : void 0
|
|
1870
2119
|
});
|
|
@@ -1879,16 +2128,22 @@ var We = class {
|
|
|
1879
2128
|
return n.add(t), () => n.delete(t);
|
|
1880
2129
|
}
|
|
1881
2130
|
destroy() {
|
|
1882
|
-
this.destroyed || (this.destroyed = !0, this.loadGen += 1, this.abort.abort(), this.stopStats(), this.stopRefresh(), this.unmountControls(), this.closeArming(), this.closeLiveState(), this.detachMedia?.(), this.detachPip?.(), this.engine?.destroy(), this.engine = null, this.setState("idle"), this.clearListeners());
|
|
2131
|
+
this.destroyed || (this.destroyed = !0, this.loadGen += 1, this.abort.abort(), this.stopStats(), this.stopRefresh(), this.unmountControls(), this.closeArming(), this.closeLiveState(), this.detachMedia?.(), this.detachPip?.(), this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachSeekListener?.(), this.engine?.destroy(), this.engine = null, this.setState("idle"), this.clearListeners());
|
|
1883
2132
|
}
|
|
1884
2133
|
clearListeners() {
|
|
1885
2134
|
for (let e of Object.keys(this.listeners)) this.listeners[e]?.clear();
|
|
1886
2135
|
}
|
|
1887
2136
|
fail(e) {
|
|
1888
|
-
this._lastError = e, this.setState("error"), this.emit("error", e);
|
|
2137
|
+
this._lastError = e, this.setState("error"), this.analyticsSession?.noteFatal(), this.emit("error", e);
|
|
1889
2138
|
}
|
|
1890
2139
|
setState(e) {
|
|
1891
|
-
if (e
|
|
2140
|
+
if (e === this._state) return;
|
|
2141
|
+
let t = this._state;
|
|
2142
|
+
if (this._state = e, this.analyticsSession) {
|
|
2143
|
+
let n = this.opts.video;
|
|
2144
|
+
this.analyticsSession.noteStateChange(t, e, Math.round(n.currentTime * 1e3), this.engine?.getStats().levelHeight), e === "ended" && this.analyticsSession.noteEnded();
|
|
2145
|
+
}
|
|
2146
|
+
switch (this.emit("statechange", e), e) {
|
|
1892
2147
|
case "playing":
|
|
1893
2148
|
this.emit("playing");
|
|
1894
2149
|
break;
|
|
@@ -1914,12 +2169,12 @@ var We = class {
|
|
|
1914
2169
|
};
|
|
1915
2170
|
//#endregion
|
|
1916
2171
|
//#region src/embed/protocol.ts
|
|
1917
|
-
function
|
|
2172
|
+
function $(e) {
|
|
1918
2173
|
return !!e && typeof e == "object" && typeof e.type == "string" && e.type.startsWith("oddin:");
|
|
1919
2174
|
}
|
|
1920
2175
|
//#endregion
|
|
1921
2176
|
//#region src/embed/host.ts
|
|
1922
|
-
function
|
|
2177
|
+
function tt(e) {
|
|
1923
2178
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
1924
2179
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
1925
2180
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -1928,7 +2183,7 @@ function $(e) {
|
|
|
1928
2183
|
let r = document.createElement("iframe");
|
|
1929
2184
|
r.src = t.toString(), r.allow = "autoplay; encrypted-media; fullscreen", r.setAttribute("allowfullscreen", ""), r.referrerPolicy = "no-referrer", r.setAttribute("sandbox", e.sandbox ?? "allow-scripts allow-same-origin allow-presentation"), r.style.cssText = "border:0;width:100%;height:100%;display:block", e.container.appendChild(r);
|
|
1930
2185
|
let i = /* @__PURE__ */ new Set(), a = (t) => {
|
|
1931
|
-
if (t.source !== r.contentWindow || t.origin !== n ||
|
|
2186
|
+
if (t.source !== r.contentWindow || t.origin !== n || !$(t.data)) return;
|
|
1932
2187
|
let a = t.data;
|
|
1933
2188
|
a.type === "oddin:ready" && a.protocol !== 1 && console.warn(`havik-player: embed protocol v${a.protocol} != host v1. Pin the embed page version to the SDK version to avoid skew.`), e.onEvent?.(a), i.forEach((e) => e(a));
|
|
1934
2189
|
};
|
|
@@ -1978,8 +2233,8 @@ function $(e) {
|
|
|
1978
2233
|
}
|
|
1979
2234
|
//#endregion
|
|
1980
2235
|
//#region src/embed/page.ts
|
|
1981
|
-
var
|
|
1982
|
-
function
|
|
2236
|
+
var nt = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
2237
|
+
function rt() {
|
|
1983
2238
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
1984
2239
|
if (e) return {
|
|
1985
2240
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -2001,9 +2256,9 @@ function Ke() {
|
|
|
2001
2256
|
waitForLive: !0
|
|
2002
2257
|
};
|
|
2003
2258
|
}
|
|
2004
|
-
async function
|
|
2005
|
-
let e =
|
|
2006
|
-
|
|
2259
|
+
async function it() {
|
|
2260
|
+
let e = rt();
|
|
2261
|
+
ot();
|
|
2007
2262
|
let n = document.createElement("video");
|
|
2008
2263
|
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);
|
|
2009
2264
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
@@ -2058,12 +2313,12 @@ async function qe() {
|
|
|
2058
2313
|
code: e.code,
|
|
2059
2314
|
message: e.message
|
|
2060
2315
|
})), e.on("autoplayblocked", () => {
|
|
2061
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
2316
|
+
i({ type: "oddin:autoplayblocked" }), at(n, e);
|
|
2062
2317
|
});
|
|
2063
2318
|
}, s = async (r) => {
|
|
2064
2319
|
a?.destroy(), a = null;
|
|
2065
2320
|
try {
|
|
2066
|
-
let t = await
|
|
2321
|
+
let t = await Q({
|
|
2067
2322
|
video: n,
|
|
2068
2323
|
baseUrl: e.baseUrl,
|
|
2069
2324
|
matchUrn: r,
|
|
@@ -2124,32 +2379,32 @@ async function qe() {
|
|
|
2124
2379
|
a?.retry();
|
|
2125
2380
|
break;
|
|
2126
2381
|
case "oddin:load":
|
|
2127
|
-
typeof e.matchUrn == "string" &&
|
|
2382
|
+
typeof e.matchUrn == "string" && nt.test(e.matchUrn) && s(e.matchUrn);
|
|
2128
2383
|
break;
|
|
2129
2384
|
case "oddin:destroy":
|
|
2130
2385
|
c();
|
|
2131
2386
|
break;
|
|
2132
2387
|
}
|
|
2133
2388
|
}, u = (e) => {
|
|
2134
|
-
!r || e.origin !== r ||
|
|
2389
|
+
!r || e.origin !== r || $(e.data) && l(e.data);
|
|
2135
2390
|
};
|
|
2136
2391
|
r && window.addEventListener("message", u), window.addEventListener("pagehide", c, { once: !0 }), await s(e.matchUrn), i({
|
|
2137
2392
|
type: "oddin:ready",
|
|
2138
2393
|
protocol: 1
|
|
2139
2394
|
});
|
|
2140
2395
|
}
|
|
2141
|
-
function
|
|
2396
|
+
function at(e, t) {
|
|
2142
2397
|
if (document.getElementById("havik-tap")) return;
|
|
2143
2398
|
let n = document.createElement("button");
|
|
2144
2399
|
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", () => {
|
|
2145
2400
|
n.remove(), t.play();
|
|
2146
2401
|
}), document.body.appendChild(n);
|
|
2147
2402
|
}
|
|
2148
|
-
function
|
|
2403
|
+
function ot() {
|
|
2149
2404
|
let e = document.createElement("style");
|
|
2150
2405
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
2151
2406
|
}
|
|
2152
2407
|
//#endregion
|
|
2153
|
-
export { W as ODDIN_THEME, t as PlaybackError, K as applyTheme,
|
|
2408
|
+
export { W as ODDIN_THEME, t as PlaybackError, K as applyTheme, it as bootEmbed, fe as clearDeviceId, Q as createPlayer, w as deriveEventsBaseUrl, j as detectDrmSupport, x as fetchCatalog, ce as fetchTournament, ue as flattenMatches, D as getDeviceId, N as isLowLatencyManifest, $ as isOddinMessage, me as licenseRequestHeaders, tt as mountEmbed, _ as pollToLive, y as resolveStream, C as subscribeLiveState, de as watchStatus };
|
|
2154
2409
|
|
|
2155
2410
|
//# sourceMappingURL=index.js.map
|