@oddin-gg/havik-player 1.8.1 → 1.8.2
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 +2 -2
- 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.js +127 -122
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -171,7 +171,7 @@ async function y(e) {
|
|
|
171
171
|
signal: e.signal
|
|
172
172
|
});
|
|
173
173
|
if (!n.ok) throw await ie(n);
|
|
174
|
-
return
|
|
174
|
+
return S(await n.json(), e.matchUrn);
|
|
175
175
|
}
|
|
176
176
|
function b(e) {
|
|
177
177
|
let t = () => y(e);
|
|
@@ -193,7 +193,7 @@ async function ie(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 x = /* @__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 S(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 C(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 w(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: oe(await l.json()),
|
|
256
256
|
etag: l.headers.get("etag") ?? void 0,
|
|
257
257
|
notModified: !1
|
|
258
258
|
};
|
|
259
259
|
}
|
|
260
|
-
function
|
|
260
|
+
function oe(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 ae(e) {
|
|
|
277
277
|
};
|
|
278
278
|
});
|
|
279
279
|
}
|
|
280
|
-
async function
|
|
280
|
+
async function se(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 oe(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: ce(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 ce(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 se(e) {
|
|
|
320
320
|
}))
|
|
321
321
|
};
|
|
322
322
|
}
|
|
323
|
-
function
|
|
323
|
+
function le(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 ue(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 le(e) {
|
|
|
360
360
|
}
|
|
361
361
|
//#endregion
|
|
362
362
|
//#region src/core/events.ts
|
|
363
|
-
function
|
|
363
|
+
function w(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 T(e) {
|
|
|
427
427
|
i || (i = !0, r.abort());
|
|
428
428
|
} };
|
|
429
429
|
}
|
|
430
|
-
function
|
|
430
|
+
function T(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 E(e) {
|
|
|
437
437
|
}
|
|
438
438
|
//#endregion
|
|
439
439
|
//#region src/core/drm/deviceId.ts
|
|
440
|
-
var
|
|
441
|
-
function
|
|
442
|
-
if (
|
|
440
|
+
var E = "havik.player.deviceId", D;
|
|
441
|
+
function O() {
|
|
442
|
+
if (D) return D;
|
|
443
443
|
try {
|
|
444
|
-
let e = globalThis.localStorage?.getItem(
|
|
445
|
-
if (e) return
|
|
444
|
+
let e = globalThis.localStorage?.getItem(E);
|
|
445
|
+
if (e) return D = e, e;
|
|
446
446
|
} catch {}
|
|
447
|
-
let e =
|
|
448
|
-
|
|
447
|
+
let e = fe();
|
|
448
|
+
D = e;
|
|
449
449
|
try {
|
|
450
|
-
globalThis.localStorage?.setItem(
|
|
450
|
+
globalThis.localStorage?.setItem(E, e);
|
|
451
451
|
} catch {}
|
|
452
452
|
return e;
|
|
453
453
|
}
|
|
454
|
-
function
|
|
455
|
-
|
|
454
|
+
function de() {
|
|
455
|
+
D = void 0;
|
|
456
456
|
try {
|
|
457
|
-
globalThis.localStorage?.removeItem(
|
|
457
|
+
globalThis.localStorage?.removeItem(E);
|
|
458
458
|
} catch {}
|
|
459
459
|
}
|
|
460
|
-
function
|
|
460
|
+
function fe() {
|
|
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,22 +469,22 @@ function de() {
|
|
|
469
469
|
}
|
|
470
470
|
//#endregion
|
|
471
471
|
//#region src/core/drm/headers.ts
|
|
472
|
-
function
|
|
472
|
+
function pe(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 ?? O(),
|
|
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
482
|
//#region src/core/drm/support.ts
|
|
483
|
-
var
|
|
483
|
+
var me = 5e3, k = "video/mp4; codecs=\"avc1.42E01E\"", A = "audio/mp4; codecs=\"mp4a.40.2\"", j = {
|
|
484
484
|
widevine: ["com.widevine.alpha"],
|
|
485
485
|
fairplay: ["com.apple.fps"]
|
|
486
486
|
};
|
|
487
|
-
function
|
|
487
|
+
function M(e) {
|
|
488
488
|
return e === "fairplay" ? [{
|
|
489
489
|
initDataTypes: [
|
|
490
490
|
"sinf",
|
|
@@ -492,30 +492,30 @@ function N(e) {
|
|
|
492
492
|
"cenc"
|
|
493
493
|
],
|
|
494
494
|
videoCapabilities: [{
|
|
495
|
-
contentType:
|
|
495
|
+
contentType: k,
|
|
496
496
|
robustness: "",
|
|
497
497
|
encryptionScheme: "cbcs"
|
|
498
498
|
}],
|
|
499
499
|
audioCapabilities: [{
|
|
500
|
-
contentType:
|
|
500
|
+
contentType: A,
|
|
501
501
|
robustness: "",
|
|
502
502
|
encryptionScheme: "cbcs"
|
|
503
503
|
}]
|
|
504
504
|
}] : [{
|
|
505
505
|
initDataTypes: ["cenc"],
|
|
506
506
|
videoCapabilities: [{
|
|
507
|
-
contentType:
|
|
507
|
+
contentType: k,
|
|
508
508
|
robustness: "SW_SECURE_DECODE",
|
|
509
509
|
encryptionScheme: "cbcs"
|
|
510
510
|
}],
|
|
511
511
|
audioCapabilities: [{
|
|
512
|
-
contentType:
|
|
512
|
+
contentType: A,
|
|
513
513
|
robustness: "SW_SECURE_CRYPTO",
|
|
514
514
|
encryptionScheme: "cbcs"
|
|
515
515
|
}]
|
|
516
516
|
}];
|
|
517
517
|
}
|
|
518
|
-
function
|
|
518
|
+
function N(e, t) {
|
|
519
519
|
return new Promise((n, r) => {
|
|
520
520
|
let i = setTimeout(() => r(/* @__PURE__ */ Error("probe-timeout")), t);
|
|
521
521
|
e.then((e) => {
|
|
@@ -525,8 +525,8 @@ function P(e, t) {
|
|
|
525
525
|
});
|
|
526
526
|
});
|
|
527
527
|
}
|
|
528
|
-
async function
|
|
529
|
-
let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ??
|
|
528
|
+
async function P(e = {}) {
|
|
529
|
+
let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? me, r = {};
|
|
530
530
|
if (typeof window < "u" && window.isSecureContext === !1) return {
|
|
531
531
|
verdict: "insecure-context",
|
|
532
532
|
detail: r
|
|
@@ -538,7 +538,7 @@ async function F(e = {}) {
|
|
|
538
538
|
};
|
|
539
539
|
let a = !1, o = !1, s = Date.now() + n, c = () => Math.max(1, s - Date.now());
|
|
540
540
|
for (let e of t) {
|
|
541
|
-
let t =
|
|
541
|
+
let t = j[e];
|
|
542
542
|
if (!t) {
|
|
543
543
|
r[e] = "unknown system";
|
|
544
544
|
continue;
|
|
@@ -549,7 +549,7 @@ async function F(e = {}) {
|
|
|
549
549
|
break;
|
|
550
550
|
}
|
|
551
551
|
try {
|
|
552
|
-
return await
|
|
552
|
+
return await N((await N(i(n, M(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
|
|
553
553
|
verdict: "supported",
|
|
554
554
|
system: e,
|
|
555
555
|
detail: r
|
|
@@ -573,17 +573,17 @@ async function F(e = {}) {
|
|
|
573
573
|
}
|
|
574
574
|
//#endregion
|
|
575
575
|
//#region src/core/manifest.ts
|
|
576
|
-
var
|
|
577
|
-
function
|
|
578
|
-
return
|
|
576
|
+
var F = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
|
|
577
|
+
function I(e) {
|
|
578
|
+
return F.test(e);
|
|
579
579
|
}
|
|
580
580
|
//#endregion
|
|
581
581
|
//#region src/core/stats.ts
|
|
582
|
-
var
|
|
583
|
-
function
|
|
582
|
+
var L = { droppedFrames: 0 };
|
|
583
|
+
function R(e) {
|
|
584
584
|
return e.getVideoPlaybackQuality?.()?.droppedVideoFrames ?? 0;
|
|
585
585
|
}
|
|
586
|
-
function
|
|
586
|
+
function z(e, t) {
|
|
587
587
|
let n = [
|
|
588
588
|
["playing", () => t("playing")],
|
|
589
589
|
["waiting", () => t("buffering")],
|
|
@@ -600,7 +600,7 @@ function B(e, t) {
|
|
|
600
600
|
}
|
|
601
601
|
//#endregion
|
|
602
602
|
//#region src/core/engine/native.ts
|
|
603
|
-
function
|
|
603
|
+
function he(e) {
|
|
604
604
|
try {
|
|
605
605
|
let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
|
|
606
606
|
return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
|
|
@@ -608,9 +608,14 @@ function me(e) {
|
|
|
608
608
|
return;
|
|
609
609
|
}
|
|
610
610
|
}
|
|
611
|
-
function
|
|
611
|
+
function B(e) {
|
|
612
612
|
return !!(e ?? (typeof document < "u" ? document.createElement("video") : void 0))?.canPlayType("application/vnd.apple.mpegurl");
|
|
613
613
|
}
|
|
614
|
+
function V() {
|
|
615
|
+
if (typeof window > "u") return !1;
|
|
616
|
+
let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
|
|
617
|
+
return e || t;
|
|
618
|
+
}
|
|
614
619
|
var H = class {
|
|
615
620
|
name = "native";
|
|
616
621
|
deps;
|
|
@@ -654,7 +659,7 @@ var H = class {
|
|
|
654
659
|
});
|
|
655
660
|
this.onEncrypted = (t) => {
|
|
656
661
|
let o = t;
|
|
657
|
-
!o.initData || this.fairplayArmed || (this.fairplayArmed = !0, this.fairplayKeyIV =
|
|
662
|
+
!o.initData || this.fairplayArmed || (this.fairplayArmed = !0, this.fairplayKeyIV = he(o.initData), (async () => {
|
|
658
663
|
try {
|
|
659
664
|
let t = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
|
|
660
665
|
initDataTypes: [o.initDataType],
|
|
@@ -746,7 +751,7 @@ var H = class {
|
|
|
746
751
|
e.seekable.length > 0 && (e.currentTime = e.seekable.end(e.seekable.length - 1));
|
|
747
752
|
}
|
|
748
753
|
getStats() {
|
|
749
|
-
let e = this.deps.video, t = { droppedFrames:
|
|
754
|
+
let e = this.deps.video, t = { droppedFrames: R(e) };
|
|
750
755
|
return e.duration === Infinity && (t.isLive = !0, e.seekable.length > 0 && (t.atLiveEdge = e.currentTime >= e.seekable.end(e.seekable.length - 1) - 2)), t;
|
|
751
756
|
}
|
|
752
757
|
stop() {
|
|
@@ -768,20 +773,20 @@ var H = class {
|
|
|
768
773
|
};
|
|
769
774
|
//#endregion
|
|
770
775
|
//#region src/core/engine/hls.ts
|
|
771
|
-
function
|
|
776
|
+
function ge() {
|
|
772
777
|
return e.isSupported();
|
|
773
778
|
}
|
|
774
|
-
var
|
|
775
|
-
function
|
|
779
|
+
var _e = 3, ve = 5, ye = 3, be = 3e4, xe = 12e3, Se = 3e3, Ce = 6e3, we = 2, Te = 9, Ee = .5;
|
|
780
|
+
function De(e) {
|
|
776
781
|
if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
|
|
777
782
|
delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
|
|
778
783
|
return;
|
|
779
784
|
}
|
|
780
|
-
e.liveSyncDuration ??=
|
|
781
|
-
let t = Math.max(12, e.liveSyncDuration +
|
|
782
|
-
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t),
|
|
785
|
+
e.liveSyncDuration ??= we;
|
|
786
|
+
let t = Math.max(12, e.liveSyncDuration + Te);
|
|
787
|
+
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), Oe(e, e.liveSyncDuration);
|
|
783
788
|
}
|
|
784
|
-
function
|
|
789
|
+
function Oe(e, t) {
|
|
785
790
|
let n = (e, t, n) => Math.min(n, Math.max(t, e));
|
|
786
791
|
e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
|
|
787
792
|
}
|
|
@@ -811,7 +816,7 @@ var U = class {
|
|
|
811
816
|
this.deps = e, this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl;
|
|
812
817
|
}
|
|
813
818
|
async load() {
|
|
814
|
-
let { descriptor: e, snapToLiveOnRefocus: n, video: r, emit: i } = this.deps, a =
|
|
819
|
+
let { descriptor: e, snapToLiveOnRefocus: n, video: r, emit: i } = this.deps, a = B(r) && V(), o = !!e.drm?.widevine?.licenseUrl && !a;
|
|
815
820
|
if (e.drmEnabled && !o) {
|
|
816
821
|
i({
|
|
817
822
|
type: "error",
|
|
@@ -835,7 +840,7 @@ var U = class {
|
|
|
835
840
|
let t = e.liveSyncPosition;
|
|
836
841
|
if (typeof t != "number" || !Number.isFinite(t)) return;
|
|
837
842
|
let { video: n } = this.deps;
|
|
838
|
-
n.currentTime <= t +
|
|
843
|
+
n.currentTime <= t + Ee || (n.currentTime = t);
|
|
839
844
|
}
|
|
840
845
|
startHls() {
|
|
841
846
|
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 = {
|
|
@@ -862,14 +867,14 @@ var U = class {
|
|
|
862
867
|
} : {},
|
|
863
868
|
...c
|
|
864
869
|
};
|
|
865
|
-
|
|
870
|
+
De(d);
|
|
866
871
|
let f = new e(d);
|
|
867
872
|
this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
|
|
868
873
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, l({ type: "ready" });
|
|
869
874
|
}), f.on(e.Events.FRAG_BUFFERED, () => {
|
|
870
875
|
(this.mediaRecoveries > 0 || this.networkRecoveries > 0 || this.licenseRecoveries > 0) && !this.recoveryResetTimer && (this.recoveryResetTimer = setTimeout(() => {
|
|
871
876
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.recoveryResetTimer = null;
|
|
872
|
-
},
|
|
877
|
+
}, be));
|
|
873
878
|
}), f.on(e.Events.LEVEL_LOADED, (e, t) => {
|
|
874
879
|
if (this.detectedLowLatency) return;
|
|
875
880
|
let n = t.details;
|
|
@@ -877,7 +882,7 @@ var U = class {
|
|
|
877
882
|
type: "lowLatencyDetected",
|
|
878
883
|
value: !0
|
|
879
884
|
}));
|
|
880
|
-
}), f.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.endWatchdog = setInterval(() => this.checkEndStale(),
|
|
885
|
+
}), f.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.endWatchdog = setInterval(() => this.checkEndStale(), Se), f.on(e.Events.LEVEL_SWITCHED, (e, t) => l({
|
|
881
886
|
type: "qualitychange",
|
|
882
887
|
index: t.level
|
|
883
888
|
})), f.on(e.Events.AUDIO_TRACK_SWITCHED, (e, t) => l({
|
|
@@ -946,7 +951,7 @@ var U = class {
|
|
|
946
951
|
}
|
|
947
952
|
getStats() {
|
|
948
953
|
let e = this.hls, t = {
|
|
949
|
-
droppedFrames:
|
|
954
|
+
droppedFrames: R(this.deps.video),
|
|
950
955
|
lowLatency: this.detectedLowLatency
|
|
951
956
|
};
|
|
952
957
|
if (e) {
|
|
@@ -975,7 +980,7 @@ var U = class {
|
|
|
975
980
|
return;
|
|
976
981
|
}
|
|
977
982
|
let e = Date.now() - this.lastAdvanceMs;
|
|
978
|
-
!this.chaseSuspended && e >
|
|
983
|
+
!this.chaseSuspended && e > Ce && this.suspendChasing(), e > xe && this.emitEnded("stalled");
|
|
979
984
|
}
|
|
980
985
|
suspendChasing() {
|
|
981
986
|
let e = this.hls;
|
|
@@ -1017,7 +1022,7 @@ var U = class {
|
|
|
1017
1022
|
scheduleLicenseRetry(t) {
|
|
1018
1023
|
if (!(t.details === e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED || t.details === e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED)) return !1;
|
|
1019
1024
|
let n = t.response?.code ?? 0;
|
|
1020
|
-
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >=
|
|
1025
|
+
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= ye) return !1;
|
|
1021
1026
|
this.licenseRecoveries += 1;
|
|
1022
1027
|
let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
|
|
1023
1028
|
return this.licenseRetryTimer = setTimeout(() => {
|
|
@@ -1045,7 +1050,7 @@ var U = class {
|
|
|
1045
1050
|
return;
|
|
1046
1051
|
}
|
|
1047
1052
|
if (t.type === e.ErrorTypes.NETWORK_ERROR) {
|
|
1048
|
-
if (this.networkRecoveries <
|
|
1053
|
+
if (this.networkRecoveries < ve) {
|
|
1049
1054
|
this.networkRecoveries += 1;
|
|
1050
1055
|
let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
|
|
1051
1056
|
this.networkRetryTimer = setTimeout(() => {
|
|
@@ -1061,7 +1066,7 @@ var U = class {
|
|
|
1061
1066
|
return;
|
|
1062
1067
|
}
|
|
1063
1068
|
if (t.type === e.ErrorTypes.MEDIA_ERROR) {
|
|
1064
|
-
if (this.mediaRecoveries <
|
|
1069
|
+
if (this.mediaRecoveries < _e) {
|
|
1065
1070
|
this.mediaRecoveries += 1, n.recoverMediaError();
|
|
1066
1071
|
return;
|
|
1067
1072
|
}
|
|
@@ -1116,15 +1121,15 @@ function K(e, t) {
|
|
|
1116
1121
|
}
|
|
1117
1122
|
//#endregion
|
|
1118
1123
|
//#region src/ui/styles.ts
|
|
1119
|
-
var q = "havik-player-styles",
|
|
1120
|
-
function
|
|
1124
|
+
var q = "havik-player-styles", ke = "\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/* 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";
|
|
1125
|
+
function Ae(e = document) {
|
|
1121
1126
|
if (e.getElementById(q)) return;
|
|
1122
1127
|
let t = e.createElement("style");
|
|
1123
|
-
t.id = q, t.textContent =
|
|
1128
|
+
t.id = q, t.textContent = ke, e.head.appendChild(t);
|
|
1124
1129
|
}
|
|
1125
1130
|
//#endregion
|
|
1126
1131
|
//#region src/ui/icons.ts
|
|
1127
|
-
var
|
|
1132
|
+
var je = {
|
|
1128
1133
|
play: "<path d=\"M8 5v14l11-7z\"/>",
|
|
1129
1134
|
pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
|
|
1130
1135
|
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\"/>",
|
|
@@ -1138,20 +1143,20 @@ var Ae = {
|
|
|
1138
1143
|
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\"/>"
|
|
1139
1144
|
};
|
|
1140
1145
|
function J(e) {
|
|
1141
|
-
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${
|
|
1146
|
+
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${je[e]}</svg>`;
|
|
1142
1147
|
}
|
|
1143
1148
|
//#endregion
|
|
1144
1149
|
//#region src/ui/controls.ts
|
|
1145
|
-
var
|
|
1150
|
+
var Me = 3e3, Ne = /* @__PURE__ */ new Set([
|
|
1146
1151
|
"GONE",
|
|
1147
1152
|
"NOT_FOUND",
|
|
1148
1153
|
"INVALID_URN",
|
|
1149
1154
|
"UNAUTHORIZED"
|
|
1150
1155
|
]);
|
|
1151
|
-
function
|
|
1152
|
-
return new
|
|
1156
|
+
function Pe(e) {
|
|
1157
|
+
return new Fe(e);
|
|
1153
1158
|
}
|
|
1154
|
-
var
|
|
1159
|
+
var Fe = class {
|
|
1155
1160
|
root;
|
|
1156
1161
|
video;
|
|
1157
1162
|
player;
|
|
@@ -1191,7 +1196,7 @@ var Pe = class {
|
|
|
1191
1196
|
scrubbing = !1;
|
|
1192
1197
|
offFns = [];
|
|
1193
1198
|
constructor(e) {
|
|
1194
|
-
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ??
|
|
1199
|
+
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Me, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.errorMessage = e.errorMessage, Ae(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");
|
|
1195
1200
|
let t = (e, t, n) => {
|
|
1196
1201
|
let r = this.doc.createElement(e);
|
|
1197
1202
|
if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
|
|
@@ -1278,7 +1283,7 @@ var Pe = class {
|
|
|
1278
1283
|
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);
|
|
1279
1284
|
} else {
|
|
1280
1285
|
let n = this.doc.createElement("div");
|
|
1281
|
-
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 && !
|
|
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 && !Ne.has(this.lastError.code)) {
|
|
1282
1287
|
let e = this.doc.createElement("button");
|
|
1283
1288
|
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);
|
|
1284
1289
|
}
|
|
@@ -1369,17 +1374,17 @@ var Pe = class {
|
|
|
1369
1374
|
renderQualityMenu() {
|
|
1370
1375
|
let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
|
|
1371
1376
|
n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
|
|
1372
|
-
for (let n of e) this.menu.append(this.menuItem(
|
|
1377
|
+
for (let n of e) this.menu.append(this.menuItem(Ie(n), t === n.index, () => this.player.setQuality(n.index)));
|
|
1373
1378
|
}
|
|
1374
1379
|
renderAudioMenu() {
|
|
1375
1380
|
let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
|
|
1376
1381
|
t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
|
|
1377
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
1382
|
+
for (let t of e) this.menu.append(this.menuItem(Le(t), t.default, () => this.player.setAudioTrack(t.id)));
|
|
1378
1383
|
}
|
|
1379
1384
|
renderCcMenu() {
|
|
1380
1385
|
let e = this.player.getTextTracks(), t = this.doc.createElement("div");
|
|
1381
1386
|
t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
|
|
1382
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
1387
|
+
for (let t of e) this.menu.append(this.menuItem(Re(t), !1, () => this.player.setTextTrack(t.id)));
|
|
1383
1388
|
}
|
|
1384
1389
|
onTracksChanged() {
|
|
1385
1390
|
this.openMenu && this.renderMenu(this.openMenu);
|
|
@@ -1485,27 +1490,27 @@ function Y(e) {
|
|
|
1485
1490
|
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");
|
|
1486
1491
|
return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
|
|
1487
1492
|
}
|
|
1488
|
-
function
|
|
1493
|
+
function Ie(e) {
|
|
1489
1494
|
return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
|
|
1490
1495
|
}
|
|
1491
|
-
function
|
|
1496
|
+
function Le(e) {
|
|
1492
1497
|
return e.name || e.lang || `Track ${e.id}`;
|
|
1493
1498
|
}
|
|
1494
|
-
function
|
|
1499
|
+
function Re(e) {
|
|
1495
1500
|
return e.name || e.lang || `Track ${e.id}`;
|
|
1496
1501
|
}
|
|
1497
1502
|
//#endregion
|
|
1498
1503
|
//#region src/managed/index.ts
|
|
1499
|
-
var
|
|
1500
|
-
async function
|
|
1504
|
+
var ze = 6e3, X = 45e3, Be = 2e3, Ve = 3, He = 2e3, Ue = 480 * 1e3;
|
|
1505
|
+
async function Z(e) {
|
|
1501
1506
|
if (!e.video || typeof e.video.play != "function") throw new t("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
1502
1507
|
if (!e.baseUrl) throw new t("INTERNAL", 0, "createPlayer: baseUrl is required");
|
|
1503
1508
|
if (!e.matchUrn) throw new t("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
1504
1509
|
if (!e.credential) throw new t("INTERNAL", 0, "createPlayer: credential is required");
|
|
1505
|
-
let n = new
|
|
1510
|
+
let n = new We(e);
|
|
1506
1511
|
return await n.start(), n;
|
|
1507
1512
|
}
|
|
1508
|
-
var
|
|
1513
|
+
var We = class {
|
|
1509
1514
|
opts;
|
|
1510
1515
|
abort = new AbortController();
|
|
1511
1516
|
listeners = {};
|
|
@@ -1561,7 +1566,7 @@ var He = class {
|
|
|
1561
1566
|
};
|
|
1562
1567
|
}
|
|
1563
1568
|
beginArming(e, t) {
|
|
1564
|
-
let n = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ??
|
|
1569
|
+
let n = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? T(this.opts.baseUrl);
|
|
1565
1570
|
n ? this.armWithSse(e, n, t) : this.beginArmingByPolling(e);
|
|
1566
1571
|
}
|
|
1567
1572
|
beginArmingByPolling(e) {
|
|
@@ -1615,13 +1620,13 @@ var He = class {
|
|
|
1615
1620
|
!a && !f() && m();
|
|
1616
1621
|
}, e);
|
|
1617
1622
|
};
|
|
1618
|
-
g(
|
|
1623
|
+
g(ze), this.armingSub = w({
|
|
1619
1624
|
eventsBaseUrl: n,
|
|
1620
1625
|
matchUrn: this.opts.matchUrn,
|
|
1621
1626
|
credential: this.opts.credential,
|
|
1622
1627
|
onAlive: () => g(X),
|
|
1623
1628
|
onState: (e) => {
|
|
1624
|
-
a || f() || (e.state === "live" || e.state === "gone") && setTimeout(h, Math.random() *
|
|
1629
|
+
a || f() || (e.state === "live" || e.state === "gone") && setTimeout(h, Math.random() * Be);
|
|
1625
1630
|
},
|
|
1626
1631
|
onError: () => m()
|
|
1627
1632
|
});
|
|
@@ -1644,7 +1649,7 @@ var He = class {
|
|
|
1644
1649
|
let n = await a(this.opts.credential);
|
|
1645
1650
|
if (this.destroyed || t !== this.loadGen) return;
|
|
1646
1651
|
this.setState("loading");
|
|
1647
|
-
let r = this.createEngine(e, n), i =
|
|
1652
|
+
let r = this.createEngine(e, n), i = z(this.opts.video, (e) => {
|
|
1648
1653
|
this._state === "ended" || this._state === "error" || this.setState(e);
|
|
1649
1654
|
});
|
|
1650
1655
|
if (await r.load(), this.destroyed || t !== this.loadGen) {
|
|
@@ -1664,7 +1669,7 @@ var He = class {
|
|
|
1664
1669
|
video: this.opts.video,
|
|
1665
1670
|
descriptor: e,
|
|
1666
1671
|
credential: n,
|
|
1667
|
-
deviceId:
|
|
1672
|
+
deviceId: O(),
|
|
1668
1673
|
userId: this.opts.userId,
|
|
1669
1674
|
lowLatency: this.opts.lowLatency === void 0 || this.opts.lowLatency === "auto" || this.opts.lowLatency,
|
|
1670
1675
|
snapToLiveOnRefocus: this.opts.snapToLiveOnRefocus,
|
|
@@ -1674,9 +1679,9 @@ var He = class {
|
|
|
1674
1679
|
}, a = this.opts.engine ?? "auto";
|
|
1675
1680
|
if (a === "native") return new H(i);
|
|
1676
1681
|
if (a === "hls") return new U(i);
|
|
1677
|
-
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl &&
|
|
1678
|
-
if (
|
|
1679
|
-
if (
|
|
1682
|
+
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && B(this.opts.video) && V()) return new H(i);
|
|
1683
|
+
if (ge()) return new U(i);
|
|
1684
|
+
if (B(this.opts.video)) return new H(i);
|
|
1680
1685
|
throw new t("INTERNAL", 0, "no supported HLS playback engine in this browser");
|
|
1681
1686
|
}
|
|
1682
1687
|
onEngineEvent(e) {
|
|
@@ -1706,11 +1711,11 @@ var He = class {
|
|
|
1706
1711
|
}
|
|
1707
1712
|
startLiveState(e) {
|
|
1708
1713
|
if (this.opts.liveStateEvents === !1) return;
|
|
1709
|
-
let n = this.opts.eventsBaseUrl ??
|
|
1714
|
+
let n = this.opts.eventsBaseUrl ?? T(this.opts.baseUrl);
|
|
1710
1715
|
if (!n) return;
|
|
1711
1716
|
this.closeLiveState();
|
|
1712
1717
|
let r = 0, i = !1;
|
|
1713
|
-
this.liveStateSub =
|
|
1718
|
+
this.liveStateSub = w({
|
|
1714
1719
|
eventsBaseUrl: n,
|
|
1715
1720
|
matchUrn: this.opts.matchUrn,
|
|
1716
1721
|
credential: this.opts.credential,
|
|
@@ -1721,7 +1726,7 @@ var He = class {
|
|
|
1721
1726
|
r = 0, i = !1;
|
|
1722
1727
|
},
|
|
1723
1728
|
onError: () => {
|
|
1724
|
-
this.destroyed || e !== this.loadGen || i || (r += 1, r >=
|
|
1729
|
+
this.destroyed || e !== this.loadGen || i || (r += 1, r >= Ve && (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.`))));
|
|
1725
1730
|
}
|
|
1726
1731
|
});
|
|
1727
1732
|
}
|
|
@@ -1743,7 +1748,7 @@ var He = class {
|
|
|
1743
1748
|
}
|
|
1744
1749
|
t.controls = !1;
|
|
1745
1750
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
1746
|
-
r && r.insertBefore(n, t), n.appendChild(t), K(n, this.opts.theme), this.container = n, this.controlBar =
|
|
1751
|
+
r && r.insertBefore(n, t), n.appendChild(t), K(n, this.opts.theme), this.container = n, this.controlBar = Pe({
|
|
1747
1752
|
root: n,
|
|
1748
1753
|
video: t,
|
|
1749
1754
|
player: this,
|
|
@@ -1766,7 +1771,7 @@ var He = class {
|
|
|
1766
1771
|
}
|
|
1767
1772
|
startStats() {
|
|
1768
1773
|
this.stopStats();
|
|
1769
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
1774
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? He);
|
|
1770
1775
|
this.statsTimer = setInterval(() => {
|
|
1771
1776
|
this.engine && this.emit("stats", this.engine.getStats());
|
|
1772
1777
|
}, e);
|
|
@@ -1776,7 +1781,7 @@ var He = class {
|
|
|
1776
1781
|
}
|
|
1777
1782
|
scheduleLicenseRefresh() {
|
|
1778
1783
|
this.stopRefresh();
|
|
1779
|
-
let e = this.opts.licenseRefreshMs ??
|
|
1784
|
+
let e = this.opts.licenseRefreshMs ?? Ue;
|
|
1780
1785
|
!e || !this._descriptor?.drmEnabled || (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
1781
1786
|
}
|
|
1782
1787
|
stopRefresh() {
|
|
@@ -1813,7 +1818,7 @@ var He = class {
|
|
|
1813
1818
|
this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
|
|
1814
1819
|
}
|
|
1815
1820
|
getStats() {
|
|
1816
|
-
return this.engine?.getStats() ??
|
|
1821
|
+
return this.engine?.getStats() ?? L;
|
|
1817
1822
|
}
|
|
1818
1823
|
getQualityLevels() {
|
|
1819
1824
|
return this.engine?.getQualityLevels() ?? [];
|
|
@@ -1909,12 +1914,12 @@ var He = class {
|
|
|
1909
1914
|
};
|
|
1910
1915
|
//#endregion
|
|
1911
1916
|
//#region src/embed/protocol.ts
|
|
1912
|
-
function
|
|
1917
|
+
function Q(e) {
|
|
1913
1918
|
return !!e && typeof e == "object" && typeof e.type == "string" && e.type.startsWith("oddin:");
|
|
1914
1919
|
}
|
|
1915
1920
|
//#endregion
|
|
1916
1921
|
//#region src/embed/host.ts
|
|
1917
|
-
function
|
|
1922
|
+
function $(e) {
|
|
1918
1923
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
1919
1924
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
1920
1925
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -1923,7 +1928,7 @@ function Ue(e) {
|
|
|
1923
1928
|
let r = document.createElement("iframe");
|
|
1924
1929
|
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);
|
|
1925
1930
|
let i = /* @__PURE__ */ new Set(), a = (t) => {
|
|
1926
|
-
if (t.source !== r.contentWindow || t.origin !== n ||
|
|
1931
|
+
if (t.source !== r.contentWindow || t.origin !== n || !Q(t.data)) return;
|
|
1927
1932
|
let a = t.data;
|
|
1928
1933
|
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));
|
|
1929
1934
|
};
|
|
@@ -1973,8 +1978,8 @@ function Ue(e) {
|
|
|
1973
1978
|
}
|
|
1974
1979
|
//#endregion
|
|
1975
1980
|
//#region src/embed/page.ts
|
|
1976
|
-
var
|
|
1977
|
-
function
|
|
1981
|
+
var Ge = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
1982
|
+
function Ke() {
|
|
1978
1983
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
1979
1984
|
if (e) return {
|
|
1980
1985
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -1996,9 +2001,9 @@ function Ge() {
|
|
|
1996
2001
|
waitForLive: !0
|
|
1997
2002
|
};
|
|
1998
2003
|
}
|
|
1999
|
-
async function
|
|
2000
|
-
let e =
|
|
2001
|
-
|
|
2004
|
+
async function qe() {
|
|
2005
|
+
let e = Ke();
|
|
2006
|
+
Ye();
|
|
2002
2007
|
let n = document.createElement("video");
|
|
2003
2008
|
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);
|
|
2004
2009
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
@@ -2053,12 +2058,12 @@ async function Ke() {
|
|
|
2053
2058
|
code: e.code,
|
|
2054
2059
|
message: e.message
|
|
2055
2060
|
})), e.on("autoplayblocked", () => {
|
|
2056
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
2061
|
+
i({ type: "oddin:autoplayblocked" }), Je(n, e);
|
|
2057
2062
|
});
|
|
2058
2063
|
}, s = async (r) => {
|
|
2059
2064
|
a?.destroy(), a = null;
|
|
2060
2065
|
try {
|
|
2061
|
-
let t = await
|
|
2066
|
+
let t = await Z({
|
|
2062
2067
|
video: n,
|
|
2063
2068
|
baseUrl: e.baseUrl,
|
|
2064
2069
|
matchUrn: r,
|
|
@@ -2119,32 +2124,32 @@ async function Ke() {
|
|
|
2119
2124
|
a?.retry();
|
|
2120
2125
|
break;
|
|
2121
2126
|
case "oddin:load":
|
|
2122
|
-
typeof e.matchUrn == "string" &&
|
|
2127
|
+
typeof e.matchUrn == "string" && Ge.test(e.matchUrn) && s(e.matchUrn);
|
|
2123
2128
|
break;
|
|
2124
2129
|
case "oddin:destroy":
|
|
2125
2130
|
c();
|
|
2126
2131
|
break;
|
|
2127
2132
|
}
|
|
2128
2133
|
}, u = (e) => {
|
|
2129
|
-
!r || e.origin !== r ||
|
|
2134
|
+
!r || e.origin !== r || Q(e.data) && l(e.data);
|
|
2130
2135
|
};
|
|
2131
2136
|
r && window.addEventListener("message", u), window.addEventListener("pagehide", c, { once: !0 }), await s(e.matchUrn), i({
|
|
2132
2137
|
type: "oddin:ready",
|
|
2133
2138
|
protocol: 1
|
|
2134
2139
|
});
|
|
2135
2140
|
}
|
|
2136
|
-
function
|
|
2141
|
+
function Je(e, t) {
|
|
2137
2142
|
if (document.getElementById("havik-tap")) return;
|
|
2138
2143
|
let n = document.createElement("button");
|
|
2139
2144
|
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", () => {
|
|
2140
2145
|
n.remove(), t.play();
|
|
2141
2146
|
}), document.body.appendChild(n);
|
|
2142
2147
|
}
|
|
2143
|
-
function
|
|
2148
|
+
function Ye() {
|
|
2144
2149
|
let e = document.createElement("style");
|
|
2145
2150
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
2146
2151
|
}
|
|
2147
2152
|
//#endregion
|
|
2148
|
-
export { W as ODDIN_THEME, t as PlaybackError, K as applyTheme,
|
|
2153
|
+
export { W as ODDIN_THEME, t as PlaybackError, K as applyTheme, qe as bootEmbed, de as clearDeviceId, Z as createPlayer, T as deriveEventsBaseUrl, P as detectDrmSupport, C as fetchCatalog, se as fetchTournament, le as flattenMatches, O as getDeviceId, I as isLowLatencyManifest, Q as isOddinMessage, pe as licenseRequestHeaders, $ as mountEmbed, v as pollToLive, b as resolveStream, w as subscribeLiveState, ue as watchStatus };
|
|
2149
2154
|
|
|
2150
2155
|
//# sourceMappingURL=index.js.map
|