@oddin-gg/havik-player 2.2.2 → 2.3.1
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 +214 -189
- 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
|
@@ -241,35 +241,35 @@ function ce(e, t) {
|
|
|
241
241
|
}
|
|
242
242
|
//#endregion
|
|
243
243
|
//#region src/core/fullscreen.ts
|
|
244
|
-
function
|
|
244
|
+
function le(e) {
|
|
245
245
|
return e.ownerDocument ?? document;
|
|
246
246
|
}
|
|
247
|
-
function
|
|
247
|
+
function ue(e) {
|
|
248
248
|
return e.fullscreenElement ?? e.webkitFullscreenElement ?? null;
|
|
249
249
|
}
|
|
250
|
-
function
|
|
251
|
-
let n = le(
|
|
250
|
+
function S(e, t) {
|
|
251
|
+
let n = ue(le(e));
|
|
252
252
|
return n != null && (n === e || t != null && n === t) || e.webkitDisplayingFullscreen === !0;
|
|
253
253
|
}
|
|
254
|
-
async function
|
|
254
|
+
async function C(e, t) {
|
|
255
255
|
let n = t ?? e;
|
|
256
256
|
if (typeof n.requestFullscreen == "function") return await n.requestFullscreen(), !0;
|
|
257
257
|
if (typeof n.webkitRequestFullscreen == "function") return n.webkitRequestFullscreen(), !0;
|
|
258
258
|
let r = e;
|
|
259
259
|
return r.webkitSupportsFullscreen && typeof r.webkitEnterFullscreen == "function" ? (r.webkitEnterFullscreen(), !0) : !1;
|
|
260
260
|
}
|
|
261
|
-
async function
|
|
261
|
+
async function w(e, t) {
|
|
262
262
|
let n = e;
|
|
263
263
|
if (n.webkitDisplayingFullscreen) {
|
|
264
264
|
n.webkitExitFullscreen?.();
|
|
265
265
|
return;
|
|
266
266
|
}
|
|
267
|
-
let r =
|
|
267
|
+
let r = le(e), i = ue(r);
|
|
268
268
|
i != null && (i === e || t != null && i === t) && (typeof r.exitFullscreen == "function" ? await r.exitFullscreen() : r.webkitExitFullscreen?.());
|
|
269
269
|
}
|
|
270
270
|
//#endregion
|
|
271
271
|
//#region src/core/catalog.ts
|
|
272
|
-
async function
|
|
272
|
+
async function de(e) {
|
|
273
273
|
let t = new URLSearchParams();
|
|
274
274
|
e.status && t.set("status", Array.isArray(e.status) ? e.status.join(",") : e.status), e.sport && t.set("sport", e.sport);
|
|
275
275
|
let i = t.toString(), a = c(e.baseUrl, "/v1/catalog" + (i ? `?${i}` : "")), o = new Headers();
|
|
@@ -287,12 +287,12 @@ async function ue(e) {
|
|
|
287
287
|
};
|
|
288
288
|
if (!s.ok) throw new n(r(s.status), s.status, `catalog request failed (HTTP ${s.status})`);
|
|
289
289
|
return {
|
|
290
|
-
tournaments:
|
|
290
|
+
tournaments: fe(await s.json()),
|
|
291
291
|
etag: s.headers.get("etag") ?? void 0,
|
|
292
292
|
notModified: !1
|
|
293
293
|
};
|
|
294
294
|
}
|
|
295
|
-
function
|
|
295
|
+
function fe(e) {
|
|
296
296
|
return (e.tournaments ?? []).map((e) => {
|
|
297
297
|
let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
|
|
298
298
|
return {
|
|
@@ -312,7 +312,7 @@ function de(e) {
|
|
|
312
312
|
};
|
|
313
313
|
});
|
|
314
314
|
}
|
|
315
|
-
async function
|
|
315
|
+
async function pe(e) {
|
|
316
316
|
let t = c(e.baseUrl, `/v1/tournaments/${encodeURIComponent(e.urn)}`), i = new Headers();
|
|
317
317
|
e.etag && i.set("If-None-Match", e.etag);
|
|
318
318
|
let a = await u(t, {
|
|
@@ -332,13 +332,13 @@ async function fe(e) {
|
|
|
332
332
|
};
|
|
333
333
|
if (!a.ok) throw new n(r(a.status), a.status, `tournament request failed (HTTP ${a.status})`);
|
|
334
334
|
return {
|
|
335
|
-
tournament:
|
|
335
|
+
tournament: me(await a.json()),
|
|
336
336
|
etag: a.headers.get("etag") ?? void 0,
|
|
337
337
|
notModified: !1,
|
|
338
338
|
notFound: !1
|
|
339
339
|
};
|
|
340
340
|
}
|
|
341
|
-
function
|
|
341
|
+
function me(e) {
|
|
342
342
|
let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
|
|
343
343
|
return {
|
|
344
344
|
urn: t,
|
|
@@ -356,12 +356,12 @@ function pe(e) {
|
|
|
356
356
|
}))
|
|
357
357
|
};
|
|
358
358
|
}
|
|
359
|
-
function
|
|
359
|
+
function he(e) {
|
|
360
360
|
return e.tournaments.flatMap((e) => e.matches);
|
|
361
361
|
}
|
|
362
362
|
//#endregion
|
|
363
363
|
//#region src/core/poll.ts
|
|
364
|
-
function
|
|
364
|
+
function ge(e) {
|
|
365
365
|
let t = Math.max(2e3, e.intervalMs ?? 1e4), i = new AbortController(), a, o, s, l = !1, d = () => {
|
|
366
366
|
l || (a = setTimeout(f, t));
|
|
367
367
|
}, f = async () => {
|
|
@@ -397,7 +397,7 @@ function he(e) {
|
|
|
397
397
|
}
|
|
398
398
|
//#endregion
|
|
399
399
|
//#region src/core/events.ts
|
|
400
|
-
function
|
|
400
|
+
function T(e) {
|
|
401
401
|
let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = new AbortController(), i = !1, a = (e) => new Promise((t) => {
|
|
402
402
|
if (r.signal.aborted) return t();
|
|
403
403
|
let n = setTimeout(t, e);
|
|
@@ -464,7 +464,7 @@ function E(e) {
|
|
|
464
464
|
i || (i = !0, r.abort());
|
|
465
465
|
} };
|
|
466
466
|
}
|
|
467
|
-
function
|
|
467
|
+
function E(e) {
|
|
468
468
|
try {
|
|
469
469
|
let t = new URL(e);
|
|
470
470
|
return t.hostname = `events.${t.hostname}`, t.pathname = "", t.search = "", t.origin;
|
|
@@ -474,27 +474,27 @@ function D(e) {
|
|
|
474
474
|
}
|
|
475
475
|
//#endregion
|
|
476
476
|
//#region src/core/drm/deviceId.ts
|
|
477
|
-
var
|
|
478
|
-
function
|
|
479
|
-
if (
|
|
477
|
+
var D = "havik.player.deviceId", O;
|
|
478
|
+
function k() {
|
|
479
|
+
if (O) return O;
|
|
480
480
|
try {
|
|
481
|
-
let e = globalThis.localStorage?.getItem(
|
|
482
|
-
if (e) return
|
|
481
|
+
let e = globalThis.localStorage?.getItem(D);
|
|
482
|
+
if (e) return O = e, e;
|
|
483
483
|
} catch {}
|
|
484
|
-
let e =
|
|
485
|
-
|
|
484
|
+
let e = ve();
|
|
485
|
+
O = e;
|
|
486
486
|
try {
|
|
487
|
-
globalThis.localStorage?.setItem(
|
|
487
|
+
globalThis.localStorage?.setItem(D, e);
|
|
488
488
|
} catch {}
|
|
489
489
|
return e;
|
|
490
490
|
}
|
|
491
|
-
function
|
|
492
|
-
|
|
491
|
+
function _e() {
|
|
492
|
+
O = void 0;
|
|
493
493
|
try {
|
|
494
|
-
globalThis.localStorage?.removeItem(
|
|
494
|
+
globalThis.localStorage?.removeItem(D);
|
|
495
495
|
} catch {}
|
|
496
496
|
}
|
|
497
|
-
function
|
|
497
|
+
function ve() {
|
|
498
498
|
let e = globalThis.crypto;
|
|
499
499
|
if (e && typeof e.randomUUID == "function") return e.randomUUID();
|
|
500
500
|
let t = /* @__PURE__ */ new Uint8Array(16);
|
|
@@ -506,21 +506,21 @@ function _e() {
|
|
|
506
506
|
}
|
|
507
507
|
//#endregion
|
|
508
508
|
//#region src/core/drm/headers.ts
|
|
509
|
-
function
|
|
509
|
+
function ye(e, t, n = {}) {
|
|
510
510
|
let r = {
|
|
511
511
|
"x-api-key": t.apiKey,
|
|
512
512
|
"X-Match-Urn": e.matchUrn,
|
|
513
|
-
"X-Device-Id": n.deviceId ??
|
|
513
|
+
"X-Device-Id": n.deviceId ?? k(),
|
|
514
514
|
"Content-Type": "application/octet-stream"
|
|
515
515
|
};
|
|
516
516
|
return n.userId && (r["X-User-Id"] = n.userId), r;
|
|
517
517
|
}
|
|
518
518
|
//#endregion
|
|
519
519
|
//#region src/core/drm/cdm.ts
|
|
520
|
-
var
|
|
521
|
-
function
|
|
522
|
-
let n =
|
|
523
|
-
n || (n = /* @__PURE__ */ new Map(),
|
|
520
|
+
var A = /* @__PURE__ */ new WeakMap();
|
|
521
|
+
function be(e, t) {
|
|
522
|
+
let n = A.get(e);
|
|
523
|
+
n || (n = /* @__PURE__ */ new Map(), A.set(e, n));
|
|
524
524
|
let r = n.get(t.keySystem);
|
|
525
525
|
if (r) return r;
|
|
526
526
|
let i = t.createMediaKeys().catch((e) => {
|
|
@@ -528,22 +528,22 @@ function ye(e, t) {
|
|
|
528
528
|
});
|
|
529
529
|
return n.set(t.keySystem, i), i;
|
|
530
530
|
}
|
|
531
|
-
function
|
|
531
|
+
function j() {
|
|
532
532
|
return typeof navigator < "u" && typeof navigator.requestMediaKeySystemAccess == "function";
|
|
533
533
|
}
|
|
534
|
-
var
|
|
535
|
-
function
|
|
534
|
+
var M = ["SW_SECURE_DECODE", "SW_SECURE_CRYPTO"];
|
|
535
|
+
function xe(e) {
|
|
536
536
|
return e.startsWith("com.widevine");
|
|
537
537
|
}
|
|
538
|
-
function
|
|
539
|
-
if (!
|
|
538
|
+
function N(e, t) {
|
|
539
|
+
if (!xe(e)) return t;
|
|
540
540
|
let n = (e, t) => {
|
|
541
541
|
let n = e.videoCapabilities;
|
|
542
542
|
return !n?.length || !n.some((e) => e.robustness) ? !1 : n.every((e) => {
|
|
543
|
-
let n =
|
|
544
|
-
return n === -1 ||
|
|
543
|
+
let n = M.indexOf(e.robustness);
|
|
544
|
+
return n === -1 || M.indexOf(t) > n;
|
|
545
545
|
});
|
|
546
|
-
}, r =
|
|
546
|
+
}, r = M.flatMap((e) => t.filter((t) => n(t, e)).map((t) => ({
|
|
547
547
|
...t,
|
|
548
548
|
videoCapabilities: t.videoCapabilities?.map((t) => ({
|
|
549
549
|
...t,
|
|
@@ -552,20 +552,20 @@ function P(e, t) {
|
|
|
552
552
|
})));
|
|
553
553
|
return [...t, ...r];
|
|
554
554
|
}
|
|
555
|
-
function
|
|
556
|
-
return (t, n) =>
|
|
555
|
+
function Se(e) {
|
|
556
|
+
return (t, n) => j() ? navigator.requestMediaKeySystemAccess(t, N(t, n)).then((t) => ({
|
|
557
557
|
keySystem: t.keySystem,
|
|
558
558
|
getConfiguration: () => t.getConfiguration(),
|
|
559
|
-
createMediaKeys: () =>
|
|
559
|
+
createMediaKeys: () => be(e, t)
|
|
560
560
|
})) : Promise.reject(/* @__PURE__ */ Error("navigator.requestMediaKeySystemAccess is unavailable — EME needs a secure context (https, or localhost)"));
|
|
561
561
|
}
|
|
562
562
|
//#endregion
|
|
563
563
|
//#region src/core/drm/support.ts
|
|
564
|
-
var
|
|
564
|
+
var Ce = 5e3, we = "video/mp4; codecs=\"avc1.42E01E\"", P = "audio/mp4; codecs=\"mp4a.40.2\"", Te = {
|
|
565
565
|
widevine: ["com.widevine.alpha"],
|
|
566
566
|
fairplay: ["com.apple.fps"]
|
|
567
567
|
};
|
|
568
|
-
function
|
|
568
|
+
function Ee(e) {
|
|
569
569
|
return e === "fairplay" ? [{
|
|
570
570
|
initDataTypes: [
|
|
571
571
|
"sinf",
|
|
@@ -573,30 +573,30 @@ function Te(e) {
|
|
|
573
573
|
"cenc"
|
|
574
574
|
],
|
|
575
575
|
videoCapabilities: [{
|
|
576
|
-
contentType:
|
|
576
|
+
contentType: we,
|
|
577
577
|
robustness: "",
|
|
578
578
|
encryptionScheme: "cbcs"
|
|
579
579
|
}],
|
|
580
580
|
audioCapabilities: [{
|
|
581
|
-
contentType:
|
|
581
|
+
contentType: P,
|
|
582
582
|
robustness: "",
|
|
583
583
|
encryptionScheme: "cbcs"
|
|
584
584
|
}]
|
|
585
|
-
}] :
|
|
585
|
+
}] : N("com.widevine.alpha", [{
|
|
586
586
|
initDataTypes: ["cenc"],
|
|
587
587
|
videoCapabilities: [{
|
|
588
|
-
contentType:
|
|
588
|
+
contentType: we,
|
|
589
589
|
robustness: "SW_SECURE_DECODE",
|
|
590
590
|
encryptionScheme: "cbcs"
|
|
591
591
|
}],
|
|
592
592
|
audioCapabilities: [{
|
|
593
|
-
contentType:
|
|
593
|
+
contentType: P,
|
|
594
594
|
robustness: "SW_SECURE_CRYPTO",
|
|
595
595
|
encryptionScheme: "cbcs"
|
|
596
596
|
}]
|
|
597
597
|
}]);
|
|
598
598
|
}
|
|
599
|
-
function
|
|
599
|
+
function F(e, t) {
|
|
600
600
|
return new Promise((n, r) => {
|
|
601
601
|
let i = setTimeout(() => r(/* @__PURE__ */ Error("probe-timeout")), t);
|
|
602
602
|
e.then((e) => {
|
|
@@ -606,8 +606,8 @@ function I(e, t) {
|
|
|
606
606
|
});
|
|
607
607
|
});
|
|
608
608
|
}
|
|
609
|
-
async function
|
|
610
|
-
let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ??
|
|
609
|
+
async function De(e = {}) {
|
|
610
|
+
let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? Ce, r = {};
|
|
611
611
|
if (typeof window < "u" && window.isSecureContext === !1) return {
|
|
612
612
|
verdict: "insecure-context",
|
|
613
613
|
detail: r
|
|
@@ -619,7 +619,7 @@ async function Ee(e = {}) {
|
|
|
619
619
|
};
|
|
620
620
|
let a = !1, o = !1, s = Date.now() + n, c = () => Math.max(1, s - Date.now());
|
|
621
621
|
for (let e of t) {
|
|
622
|
-
let t =
|
|
622
|
+
let t = Te[e];
|
|
623
623
|
if (!t) {
|
|
624
624
|
r[e] = "unknown system";
|
|
625
625
|
continue;
|
|
@@ -630,7 +630,7 @@ async function Ee(e = {}) {
|
|
|
630
630
|
break;
|
|
631
631
|
}
|
|
632
632
|
try {
|
|
633
|
-
return await
|
|
633
|
+
return await F((await F(i(n, Ee(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
|
|
634
634
|
verdict: "supported",
|
|
635
635
|
system: e,
|
|
636
636
|
detail: r
|
|
@@ -654,13 +654,30 @@ async function Ee(e = {}) {
|
|
|
654
654
|
}
|
|
655
655
|
//#endregion
|
|
656
656
|
//#region src/core/manifest.ts
|
|
657
|
-
var
|
|
658
|
-
function
|
|
659
|
-
return
|
|
657
|
+
var Oe = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
|
|
658
|
+
function ke(e) {
|
|
659
|
+
return Oe.test(e);
|
|
660
660
|
}
|
|
661
661
|
//#endregion
|
|
662
662
|
//#region src/core/stats.ts
|
|
663
|
-
var
|
|
663
|
+
var I = { droppedFrames: 0 };
|
|
664
|
+
function L(e) {
|
|
665
|
+
try {
|
|
666
|
+
return new URL(e).host;
|
|
667
|
+
} catch {
|
|
668
|
+
return "";
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
var Ae = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
|
|
672
|
+
function je(e) {
|
|
673
|
+
if (typeof performance > "u" || typeof performance.getEntriesByType != "function") return "";
|
|
674
|
+
let t = "", n = -1, r = performance.getEntriesByType("resource");
|
|
675
|
+
for (let i of r) if (!(i.startTime < e) && !(i.initiatorType !== "video" && i.initiatorType !== "audio" && !Ae.test(i.name)) && i.startTime >= n) {
|
|
676
|
+
let e = L(i.name);
|
|
677
|
+
e && (t = e, n = i.startTime);
|
|
678
|
+
}
|
|
679
|
+
return t;
|
|
680
|
+
}
|
|
664
681
|
function R(e) {
|
|
665
682
|
let t = e.getVideoPlaybackQuality?.();
|
|
666
683
|
return {
|
|
@@ -668,7 +685,7 @@ function R(e) {
|
|
|
668
685
|
decoded: t?.totalVideoFrames ?? 0
|
|
669
686
|
};
|
|
670
687
|
}
|
|
671
|
-
function
|
|
688
|
+
function Me(e, t) {
|
|
672
689
|
let n = [
|
|
673
690
|
["playing", () => t("playing")],
|
|
674
691
|
["waiting", () => t("buffering")],
|
|
@@ -685,7 +702,7 @@ function ke(e, t) {
|
|
|
685
702
|
}
|
|
686
703
|
//#endregion
|
|
687
704
|
//#region src/core/engine/native.ts
|
|
688
|
-
function
|
|
705
|
+
function Ne(e) {
|
|
689
706
|
try {
|
|
690
707
|
let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
|
|
691
708
|
return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
|
|
@@ -714,8 +731,10 @@ var V = class {
|
|
|
714
731
|
loadStarted;
|
|
715
732
|
preloadTouched = !1;
|
|
716
733
|
savedPreload = null;
|
|
734
|
+
cdnHost = "";
|
|
735
|
+
builtAt;
|
|
717
736
|
constructor(e) {
|
|
718
|
-
this.deps = e, this.loadStarted = e.deferLoad !== !0;
|
|
737
|
+
this.deps = e, this.loadStarted = e.deferLoad !== !0, this.builtAt = typeof performance < "u" ? performance.now() : 0;
|
|
719
738
|
}
|
|
720
739
|
async load() {
|
|
721
740
|
let { video: e, descriptor: t, emit: r } = this.deps;
|
|
@@ -735,7 +754,7 @@ var V = class {
|
|
|
735
754
|
type: "error",
|
|
736
755
|
error: new n("INTERNAL", 0, "native HLS playback error"),
|
|
737
756
|
fatal: !0
|
|
738
|
-
}), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src =
|
|
757
|
+
}), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = Pe(t.manifestUrl, t.analytics?.sid), e.load();
|
|
739
758
|
}
|
|
740
759
|
startLoad() {
|
|
741
760
|
this.loadStarted || (this.loadStarted = !0, this.restorePreload());
|
|
@@ -757,7 +776,7 @@ var V = class {
|
|
|
757
776
|
});
|
|
758
777
|
this.onEncrypted = (n) => {
|
|
759
778
|
let i = n;
|
|
760
|
-
!i.initData || this.fairplayArmed || (this.fairplayArmed = !0, this.fairplayKeyIV =
|
|
779
|
+
!i.initData || this.fairplayArmed || (this.fairplayArmed = !0, this.fairplayKeyIV = Ne(i.initData), (async () => {
|
|
761
780
|
try {
|
|
762
781
|
let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
|
|
763
782
|
initDataTypes: [i.initDataType],
|
|
@@ -856,7 +875,7 @@ var V = class {
|
|
|
856
875
|
droppedFrames: t.dropped,
|
|
857
876
|
decodedFrames: t.decoded
|
|
858
877
|
};
|
|
859
|
-
return this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity && (n.isLive = !0, e.seekable.length > 0 && (n.atLiveEdge = e.currentTime >= e.seekable.end(e.seekable.length - 1) - 2)), n;
|
|
878
|
+
return this.cdnHost ||= je(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity && (n.isLive = !0, e.seekable.length > 0 && (n.atLiveEdge = e.currentTime >= e.seekable.end(e.seekable.length - 1) - 2)), n;
|
|
860
879
|
}
|
|
861
880
|
stop() {
|
|
862
881
|
try {
|
|
@@ -875,32 +894,25 @@ var V = class {
|
|
|
875
894
|
} catch {}
|
|
876
895
|
}
|
|
877
896
|
};
|
|
878
|
-
function
|
|
897
|
+
function Pe(e, t) {
|
|
879
898
|
return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
|
|
880
899
|
}
|
|
881
900
|
//#endregion
|
|
882
901
|
//#region src/core/engine/hls.ts
|
|
883
|
-
function
|
|
902
|
+
function Fe() {
|
|
884
903
|
return e.isSupported();
|
|
885
904
|
}
|
|
886
|
-
var
|
|
887
|
-
function
|
|
888
|
-
try {
|
|
889
|
-
return new URL(e).host;
|
|
890
|
-
} catch {
|
|
891
|
-
return "";
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
function Ze(e) {
|
|
905
|
+
var Ie = 3, Le = 5, Re = 3, ze = 3e4, Be = 12e3, Ve = 3e3, H = 6e3, He = 4e3, Ue = 2, We = 5, Ge = 2, Ke = 2, qe = 2e3, Je = 3e4, Ye = 2, Xe = 9, Ze = .5, Qe = 64;
|
|
906
|
+
function $e(e) {
|
|
895
907
|
if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
|
|
896
908
|
delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
|
|
897
909
|
return;
|
|
898
910
|
}
|
|
899
|
-
e.liveSyncDuration ??=
|
|
900
|
-
let t = Math.max(12, e.liveSyncDuration +
|
|
901
|
-
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t),
|
|
911
|
+
e.liveSyncDuration ??= Ye;
|
|
912
|
+
let t = Math.max(12, e.liveSyncDuration + Xe);
|
|
913
|
+
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), et(e, e.liveSyncDuration);
|
|
902
914
|
}
|
|
903
|
-
function
|
|
915
|
+
function et(e, t) {
|
|
904
916
|
let n = (e, t, n) => Math.min(n, Math.max(t, e));
|
|
905
917
|
e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
|
|
906
918
|
}
|
|
@@ -998,7 +1010,7 @@ var U = class {
|
|
|
998
1010
|
let t = e.liveSyncPosition;
|
|
999
1011
|
if (typeof t != "number" || !Number.isFinite(t)) return;
|
|
1000
1012
|
let { video: n } = this.deps;
|
|
1001
|
-
n.currentTime <= t +
|
|
1013
|
+
n.currentTime <= t + Ze || (n.currentTime = t);
|
|
1002
1014
|
}
|
|
1003
1015
|
startHls() {
|
|
1004
1016
|
let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps;
|
|
@@ -1022,7 +1034,7 @@ var U = class {
|
|
|
1022
1034
|
videoEncryptionScheme: "cbcs",
|
|
1023
1035
|
audioEncryptionScheme: "cbcs"
|
|
1024
1036
|
},
|
|
1025
|
-
...
|
|
1037
|
+
...j() ? { requestMediaKeySystemAccessFunc: Se(t) } : {},
|
|
1026
1038
|
licenseXhrSetup: (e, t) => {
|
|
1027
1039
|
e.open("POST", this.licenseUrl ?? t, !0), e.setRequestHeader("x-api-key", r.apiKey), e.setRequestHeader("X-Match-Urn", n.matchUrn), e.setRequestHeader("X-Device-Id", i), a && e.setRequestHeader("X-User-Id", a), this.licenseRequested = !0;
|
|
1028
1040
|
let o = performance.now();
|
|
@@ -1038,7 +1050,7 @@ var U = class {
|
|
|
1038
1050
|
} } : {},
|
|
1039
1051
|
...c
|
|
1040
1052
|
};
|
|
1041
|
-
|
|
1053
|
+
$e(d), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.loadStarted = d.autoStartLoad !== !1;
|
|
1042
1054
|
let f = new e(d);
|
|
1043
1055
|
this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
|
|
1044
1056
|
this.mediaRecoveries = 0, this.networkRecoveries = 0;
|
|
@@ -1047,17 +1059,17 @@ var U = class {
|
|
|
1047
1059
|
}), f.on(e.Events.FRAG_BUFFERED, (e, t) => {
|
|
1048
1060
|
t?.frag?.type === "main" && (this.kickPending = !1, this.kickTicks = 0, (this.mediaRecoveries > 0 || this.networkRecoveries > 0 || this.licenseRecoveries > 0 || this.starvationKicks > 0 || this.starvationRebuilds > 0) && !this.recoveryResetTimer && (this.recoveryResetTimer = setTimeout(() => {
|
|
1049
1061
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
|
|
1050
|
-
},
|
|
1062
|
+
}, ze)));
|
|
1051
1063
|
}), f.on(e.Events.FRAG_LOADING, (e, t) => {
|
|
1052
1064
|
t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
|
|
1053
1065
|
}), f.on(e.Events.FRAG_LOADED, (e, t) => {
|
|
1054
1066
|
let n = t?.frag?.stats, r = n?.loaded;
|
|
1055
1067
|
typeof r == "number" && (this.bytesLoaded += r);
|
|
1056
1068
|
let i = n?.loading;
|
|
1057
|
-
i && i.end > 0 && i.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(i.end - i.start))), this.requestTimesMs.length >
|
|
1069
|
+
i && i.end > 0 && i.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(i.end - i.start))), this.requestTimesMs.length > Qe && this.requestTimesMs.shift());
|
|
1058
1070
|
let a = t?.frag?.url;
|
|
1059
1071
|
if (a) {
|
|
1060
|
-
let e =
|
|
1072
|
+
let e = L(a);
|
|
1061
1073
|
e && (this.cdnHost = e);
|
|
1062
1074
|
}
|
|
1063
1075
|
}), f.on(e.Events.LEVEL_LOADED, (e, t) => {
|
|
@@ -1070,7 +1082,7 @@ var U = class {
|
|
|
1070
1082
|
}));
|
|
1071
1083
|
}), f.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
|
|
1072
1084
|
this.checkEndStale(), this.checkStarvation();
|
|
1073
|
-
},
|
|
1085
|
+
}, Ve), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
|
|
1074
1086
|
this.renditionSwitches += 1;
|
|
1075
1087
|
let n = this.lastLevelIndex >= 0 ? f.levels[this.lastLevelIndex] : void 0, r = f.levels[t.level];
|
|
1076
1088
|
n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, l({
|
|
@@ -1134,7 +1146,7 @@ var U = class {
|
|
|
1134
1146
|
return;
|
|
1135
1147
|
}
|
|
1136
1148
|
this.capTimer && clearTimeout(this.capTimer);
|
|
1137
|
-
let t = e > this.sizeCapLevel ?
|
|
1149
|
+
let t = e > this.sizeCapLevel ? qe : Je;
|
|
1138
1150
|
this.capTimer = setTimeout(() => {
|
|
1139
1151
|
this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
|
|
1140
1152
|
}, t);
|
|
@@ -1223,7 +1235,7 @@ var U = class {
|
|
|
1223
1235
|
return;
|
|
1224
1236
|
}
|
|
1225
1237
|
let e = Date.now() - this.lastAdvanceMs;
|
|
1226
|
-
!this.chaseSuspended && e > H && this.suspendChasing(), e >
|
|
1238
|
+
!this.chaseSuspended && e > H && this.suspendChasing(), e > Be && this.emitEnded("stalled");
|
|
1227
1239
|
}
|
|
1228
1240
|
checkStarvation() {
|
|
1229
1241
|
let e = this.hls, { video: t } = this.deps;
|
|
@@ -1232,17 +1244,17 @@ var U = class {
|
|
|
1232
1244
|
this.starvedTicks = 0;
|
|
1233
1245
|
return;
|
|
1234
1246
|
}
|
|
1235
|
-
let n = this.lastAdvanceMs !== 0 && Date.now() - this.lastAdvanceMs < H, r = this.lastFragLoadingMs !== 0 && Date.now() - this.lastFragLoadingMs >
|
|
1247
|
+
let n = this.lastAdvanceMs !== 0 && Date.now() - this.lastAdvanceMs < H, r = this.lastFragLoadingMs !== 0 && Date.now() - this.lastFragLoadingMs > He;
|
|
1236
1248
|
if (!(t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused && n && r)) {
|
|
1237
1249
|
this.starvedTicks = 0;
|
|
1238
1250
|
return;
|
|
1239
1251
|
}
|
|
1240
|
-
if (this.kickPending && (this.kickTicks += 1), !(++this.starvedTicks <
|
|
1241
|
-
if (this.starvedTicks = 0, this.kickPending && this.kickTicks >=
|
|
1252
|
+
if (this.kickPending && (this.kickTicks += 1), !(++this.starvedTicks < Ue)) {
|
|
1253
|
+
if (this.starvedTicks = 0, this.kickPending && this.kickTicks >= Ge && (this.kickPending = !1, this.kickTicks = 0, this.starvationRebuilds < Ke)) {
|
|
1242
1254
|
this.starvationRebuilds += 1, console.warn("havik-player: restarting the load did not resume video (the wedge is in hls.js state that only a rebuild clears) — rebuilding the player"), this.rebuildInstance("starvation rebuild");
|
|
1243
1255
|
return;
|
|
1244
1256
|
}
|
|
1245
|
-
if (!(this.starvationKicks >=
|
|
1257
|
+
if (!(this.starvationKicks >= We)) {
|
|
1246
1258
|
this.starvationKicks += 1, this.kickPending = !0, this.kickTicks = 0, console.warn("havik-player: video starved while the live playlist advances (wedged hls.js fragment pipeline) — restarting the load");
|
|
1247
1259
|
try {
|
|
1248
1260
|
e.stopLoad(), e.startLoad(-1);
|
|
@@ -1292,7 +1304,7 @@ var U = class {
|
|
|
1292
1304
|
scheduleLicenseRetry(t) {
|
|
1293
1305
|
if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
|
|
1294
1306
|
let n = t.response?.code ?? 0;
|
|
1295
|
-
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >=
|
|
1307
|
+
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= Re) return !1;
|
|
1296
1308
|
this.licenseRecoveries += 1;
|
|
1297
1309
|
let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
|
|
1298
1310
|
return this.licenseRetryTimer = setTimeout(() => {
|
|
@@ -1324,7 +1336,7 @@ var U = class {
|
|
|
1324
1336
|
return;
|
|
1325
1337
|
}
|
|
1326
1338
|
if (t.type === e.ErrorTypes.NETWORK_ERROR) {
|
|
1327
|
-
if (this.networkRecoveries <
|
|
1339
|
+
if (this.networkRecoveries < Le) {
|
|
1328
1340
|
this.networkRecoveries += 1;
|
|
1329
1341
|
let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
|
|
1330
1342
|
this.networkRetryTimer = setTimeout(() => {
|
|
@@ -1341,7 +1353,7 @@ var U = class {
|
|
|
1341
1353
|
return;
|
|
1342
1354
|
}
|
|
1343
1355
|
if (t.type === e.ErrorTypes.MEDIA_ERROR) {
|
|
1344
|
-
if (this.mediaRecoveries <
|
|
1356
|
+
if (this.mediaRecoveries < Ie) {
|
|
1345
1357
|
this.mediaRecoveries += 1, n.recoverMediaError();
|
|
1346
1358
|
return;
|
|
1347
1359
|
}
|
|
@@ -1365,11 +1377,11 @@ var U = class {
|
|
|
1365
1377
|
let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
|
|
1366
1378
|
return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
|
|
1367
1379
|
}
|
|
1368
|
-
},
|
|
1380
|
+
}, tt = 15e3, nt = 100, W = 1, rt = 1e3, G = 3e4, it = 1e3, at = {
|
|
1369
1381
|
inline: "PRESENTATION_INLINE",
|
|
1370
1382
|
fullscreen: "PRESENTATION_FULLSCREEN",
|
|
1371
1383
|
pip: "PRESENTATION_PIP"
|
|
1372
|
-
},
|
|
1384
|
+
}, ot = {
|
|
1373
1385
|
widevine: "KEY_SYSTEM_WIDEVINE",
|
|
1374
1386
|
fairplay: "KEY_SYSTEM_FAIRPLAY",
|
|
1375
1387
|
none: "KEY_SYSTEM_NONE"
|
|
@@ -1377,7 +1389,7 @@ var U = class {
|
|
|
1377
1389
|
function K(e, t) {
|
|
1378
1390
|
return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
|
|
1379
1391
|
}
|
|
1380
|
-
var
|
|
1392
|
+
var st = /* @__PURE__ */ new Set([
|
|
1381
1393
|
"INVALID_URN",
|
|
1382
1394
|
"NOT_FOUND",
|
|
1383
1395
|
"GONE",
|
|
@@ -1397,7 +1409,7 @@ var it = /* @__PURE__ */ new Set([
|
|
|
1397
1409
|
ended: "PLAYER_STATE_ENDED",
|
|
1398
1410
|
error: "PLAYER_STATE_ERROR"
|
|
1399
1411
|
};
|
|
1400
|
-
function
|
|
1412
|
+
function ct(e) {
|
|
1401
1413
|
try {
|
|
1402
1414
|
let t = new URL(e), [n, ...r] = t.hostname.split(".");
|
|
1403
1415
|
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);
|
|
@@ -1405,7 +1417,7 @@ function at(e) {
|
|
|
1405
1417
|
return;
|
|
1406
1418
|
}
|
|
1407
1419
|
}
|
|
1408
|
-
var
|
|
1420
|
+
var lt = class {
|
|
1409
1421
|
opts;
|
|
1410
1422
|
url;
|
|
1411
1423
|
now;
|
|
@@ -1450,7 +1462,8 @@ var ot = class {
|
|
|
1450
1462
|
timeToFirstStallMs = 0;
|
|
1451
1463
|
lastStallMs = 0;
|
|
1452
1464
|
lastErrorMs = 0;
|
|
1453
|
-
lastSeekMs =
|
|
1465
|
+
lastSeekMs = -1;
|
|
1466
|
+
stallIsSeekInduced = !1;
|
|
1454
1467
|
lastErrorStage = null;
|
|
1455
1468
|
sawFirstBytes = !1;
|
|
1456
1469
|
mediaInfoSignature = "";
|
|
@@ -1462,6 +1475,7 @@ var ot = class {
|
|
|
1462
1475
|
pendingStart = null;
|
|
1463
1476
|
firstFlushTimer = null;
|
|
1464
1477
|
bornMs;
|
|
1478
|
+
startupAnchorMs;
|
|
1465
1479
|
startupTimeMs = 0;
|
|
1466
1480
|
manifestLoadMs = 0;
|
|
1467
1481
|
firstFragLoadMs = 0;
|
|
@@ -1472,8 +1486,8 @@ var ot = class {
|
|
|
1472
1486
|
constructor(e) {
|
|
1473
1487
|
this.opts = {
|
|
1474
1488
|
...e,
|
|
1475
|
-
heartbeatMs: e.heartbeatMs ??
|
|
1476
|
-
}, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`, this.now = e.now ?? (() => Date.now()), this.bornMs = this.now(), this.presentationSinceMs = this.bornMs;
|
|
1489
|
+
heartbeatMs: e.heartbeatMs ?? tt
|
|
1490
|
+
}, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`, this.now = e.now ?? (() => Date.now()), this.bornMs = this.now(), this.presentationSinceMs = this.bornMs, this.startupAnchorMs = this.bornMs;
|
|
1477
1491
|
}
|
|
1478
1492
|
start() {
|
|
1479
1493
|
if (this.endedFlag) return;
|
|
@@ -1482,22 +1496,30 @@ var ot = class {
|
|
|
1482
1496
|
sdkVersion: this.opts.sdkVersion,
|
|
1483
1497
|
...this.opts.environment
|
|
1484
1498
|
};
|
|
1485
|
-
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(),
|
|
1499
|
+
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), rt), 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());
|
|
1486
1500
|
}
|
|
1487
1501
|
noteStateChange(e, t, n, r) {
|
|
1488
1502
|
if (this.endedFlag || e === t) return;
|
|
1489
1503
|
let i = this.now();
|
|
1490
|
-
t === "playing" ? (this.playingSinceMs === null && (this.playingSinceMs = i), this.startupTimeMs === 0 && (this.startupTimeMs = Math.max(W, i - this.
|
|
1504
|
+
if (t === "playing" ? (this.playingSinceMs === null && (this.playingSinceMs = i), this.startupTimeMs === 0 && (this.startupTimeMs = Math.max(W, i - this.startupAnchorMs)), this.firstAudioMs === 0 && !this.isMuted && (this.firstAudioMs = Math.max(W, i - this.startupAnchorMs)), this.isMuted && this.mutedSinceMs === null && (this.mutedSinceMs = i)) : this.playingSinceMs !== null && (this.playingTotalMs += i - this.playingSinceMs, this.playingSinceMs = null, this.mutedSinceMs !== null && (this.mutedTotalMs += i - this.mutedSinceMs, this.mutedSinceMs = null)), this.isPlaying = t === "playing", this.syncActive(), t === "waiting" ? this.waitingSinceMs = i : this.waitingSinceMs !== null && (this.waitingTotalMs += i - this.waitingSinceMs, this.waitingSinceMs = null), t === "buffering" && e === "playing") {
|
|
1505
|
+
this.stallIsSeekInduced = this.seekInduced(i);
|
|
1506
|
+
let e = !this.isHidden && !this.stallIsSeekInduced;
|
|
1507
|
+
e && (this.rebufferCount += 1), this.isBuffering = !0, this.lastStallMs = i, e && this.timeToFirstStallMs === 0 && (this.timeToFirstStallMs = Math.max(W, Math.round(this.playingTotalMs)));
|
|
1508
|
+
} else e === "buffering" && (this.isBuffering = !1, this.stallIsSeekInduced = !1);
|
|
1509
|
+
this.syncBuffering(), t === "paused" && (this.pauseCount += 1);
|
|
1491
1510
|
let a = {
|
|
1492
1511
|
fromState: q[e] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
1493
1512
|
toState: q[t] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
1494
|
-
presentation:
|
|
1513
|
+
presentation: at[this.presentation]
|
|
1495
1514
|
}, o = this.causeOf(e, t, i);
|
|
1496
1515
|
o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
|
|
1497
1516
|
}
|
|
1517
|
+
seekInduced(e) {
|
|
1518
|
+
return this.lastSeekMs >= 0 && e - this.lastSeekMs < it;
|
|
1519
|
+
}
|
|
1498
1520
|
causeOf(e, t, n) {
|
|
1499
1521
|
if (t === "error") return "TRANSITION_CAUSE_ERROR";
|
|
1500
|
-
if (t === "buffering") return
|
|
1522
|
+
if (t === "buffering") return this.seekInduced(n) ? "TRANSITION_CAUSE_SEEK" : "TRANSITION_CAUSE_NETWORK_STALL";
|
|
1501
1523
|
if (t === "paused" || t === "playing" && e === "paused") return "TRANSITION_CAUSE_USER";
|
|
1502
1524
|
}
|
|
1503
1525
|
syncActive() {
|
|
@@ -1505,7 +1527,7 @@ var ot = class {
|
|
|
1505
1527
|
e && this.activeSinceMs === null ? this.activeSinceMs = this.now() : !e && this.activeSinceMs !== null && (this.activeTotalMs += this.now() - this.activeSinceMs, this.activeSinceMs = null);
|
|
1506
1528
|
}
|
|
1507
1529
|
syncBuffering() {
|
|
1508
|
-
let e = this.isBuffering && !this.isHidden;
|
|
1530
|
+
let e = this.isBuffering && !this.isHidden && !this.stallIsSeekInduced;
|
|
1509
1531
|
e && this.bufferingSinceMs === null ? this.bufferingSinceMs = this.now() : !e && this.bufferingSinceMs !== null && (this.rebufferTotalMs += this.now() - this.bufferingSinceMs, this.bufferingSinceMs = null);
|
|
1510
1532
|
}
|
|
1511
1533
|
closePresentation() {
|
|
@@ -1530,16 +1552,19 @@ var ot = class {
|
|
|
1530
1552
|
}
|
|
1531
1553
|
this.muteChanges += 1;
|
|
1532
1554
|
let r = this.now();
|
|
1533
|
-
n ? this.isPlaying && this.mutedSinceMs === null && (this.mutedSinceMs = r) : (this.mutedSinceMs !== null && (this.mutedTotalMs += r - this.mutedSinceMs, this.mutedSinceMs = null), this.firstAudioMs === 0 && this.isPlaying && (this.firstAudioMs = Math.max(W, r - this.
|
|
1555
|
+
n ? this.isPlaying && this.mutedSinceMs === null && (this.mutedSinceMs = r) : (this.mutedSinceMs !== null && (this.mutedTotalMs += r - this.mutedSinceMs, this.mutedSinceMs = null), this.firstAudioMs === 0 && this.isPlaying && (this.firstAudioMs = Math.max(W, r - this.startupAnchorMs))), this.isMuted = n, this.syncActive();
|
|
1534
1556
|
}
|
|
1535
1557
|
notePresentation(e) {
|
|
1536
1558
|
this.endedFlag || e === this.presentation || (this.closePresentation(), this.presentation = e);
|
|
1537
1559
|
}
|
|
1560
|
+
notePlayIntent() {
|
|
1561
|
+
this.endedFlag || this.startupTimeMs > 0 || (this.startupAnchorMs = this.now(), this.manifestLoadMs > 0 && (this.manifestLoadMs = W), this.firstFragLoadMs > 0 && (this.firstFragLoadMs = W));
|
|
1562
|
+
}
|
|
1538
1563
|
noteReady() {
|
|
1539
|
-
this.manifestLoadMs === 0 && (this.manifestLoadMs = Math.max(W, this.now() - this.
|
|
1564
|
+
this.manifestLoadMs === 0 && (this.manifestLoadMs = Math.max(W, this.now() - this.startupAnchorMs));
|
|
1540
1565
|
}
|
|
1541
1566
|
noteFirstBytes() {
|
|
1542
|
-
this.sawFirstBytes = !0, this.firstFragLoadMs === 0 && (this.firstFragLoadMs = Math.max(W, this.now() - this.
|
|
1567
|
+
this.sawFirstBytes = !0, this.firstFragLoadMs === 0 && (this.firstFragLoadMs = Math.max(W, this.now() - this.startupAnchorMs));
|
|
1543
1568
|
}
|
|
1544
1569
|
noteSeek() {
|
|
1545
1570
|
this.endedFlag || (this.seekCount += 1, this.lastSeekMs = this.now());
|
|
@@ -1558,7 +1583,7 @@ var ot = class {
|
|
|
1558
1583
|
let r = n ?? "";
|
|
1559
1584
|
if (r !== "") return /^fragLoad/i.test(r) ? this.sawFirstBytes ? "ERROR_STAGE_SEGMENT" : "ERROR_STAGE_FIRST_SEGMENT" : /^(manifest|level|audioTrack|subtitleTrack)/i.test(r) ? "ERROR_STAGE_MANIFEST" : /key|licen[cs]e/i.test(r) ? "ERROR_STAGE_DRM" : /parsing|append|buffer|remux|decrypt|media/i.test(r) ? "ERROR_STAGE_DECODE" : "ERROR_STAGE_OTHER";
|
|
1560
1585
|
if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
|
|
1561
|
-
if (
|
|
1586
|
+
if (st.has(e)) return "ERROR_STAGE_RESOLVE";
|
|
1562
1587
|
let i = t ?? "";
|
|
1563
1588
|
return /frag|segment/i.test(i) ? this.sawFirstBytes ? "ERROR_STAGE_SEGMENT" : "ERROR_STAGE_FIRST_SEGMENT" : /manifest|level|playlist/i.test(i) ? "ERROR_STAGE_MANIFEST" : /key|licen[cs]e/i.test(i) ? "ERROR_STAGE_DRM" : /buffer|decode|media|append/i.test(i) ? "ERROR_STAGE_DECODE" : "ERROR_STAGE_OTHER";
|
|
1564
1589
|
}
|
|
@@ -1606,7 +1631,7 @@ var ot = class {
|
|
|
1606
1631
|
maybeEmitMediaInfo(e) {
|
|
1607
1632
|
if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
|
|
1608
1633
|
let t = {};
|
|
1609
|
-
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem =
|
|
1634
|
+
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = ot[e.keySystem]), e.drmSecurityLevel && (t.drmSecurityLevel = e.drmSecurityLevel), e.ladderHeights?.length && (t.ladderHeights = e.ladderHeights), e.ladderTopBitrateKbps && (t.ladderTopBitrateKbps = e.ladderTopBitrateKbps), e.lowLatency && (t.lowLatency = !0);
|
|
1610
1635
|
let n = JSON.stringify(t);
|
|
1611
1636
|
n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
|
|
1612
1637
|
}
|
|
@@ -1646,7 +1671,7 @@ var ot = class {
|
|
|
1646
1671
|
};
|
|
1647
1672
|
}
|
|
1648
1673
|
enqueue(e) {
|
|
1649
|
-
for (this.pending.push(this.wrap(e)); this.pending.length >
|
|
1674
|
+
for (this.pending.push(this.wrap(e)); this.pending.length > nt;) {
|
|
1650
1675
|
let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
|
|
1651
1676
|
this.pending.splice(e >= 0 ? e : 0, 1);
|
|
1652
1677
|
}
|
|
@@ -1671,7 +1696,7 @@ var ot = class {
|
|
|
1671
1696
|
};
|
|
1672
1697
|
//#endregion
|
|
1673
1698
|
//#region src/core/environment.ts
|
|
1674
|
-
function
|
|
1699
|
+
function ut() {
|
|
1675
1700
|
if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
|
|
1676
1701
|
let e;
|
|
1677
1702
|
try {
|
|
@@ -1696,14 +1721,14 @@ function st() {
|
|
|
1696
1721
|
integration: "INTEGRATION_KIND_IFRAME"
|
|
1697
1722
|
};
|
|
1698
1723
|
}
|
|
1699
|
-
function
|
|
1724
|
+
function dt() {
|
|
1700
1725
|
if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
|
|
1701
1726
|
let e = navigator.userAgentData, t = e?.platform ?? "";
|
|
1702
1727
|
if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
|
|
1703
1728
|
let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
|
|
1704
1729
|
return e?.mobile ?? (typeof navigator.maxTouchPoints == "number" && navigator.maxTouchPoints > 1 && n > 0 && n < 900) ? n >= 600 ? "DEVICE_CLASS_TABLET" : "DEVICE_CLASS_PHONE" : e || n >= 900 || /mac|win|linux|chrome os/i.test(t) ? "DEVICE_CLASS_DESKTOP" : "DEVICE_CLASS_OTHER";
|
|
1705
1730
|
}
|
|
1706
|
-
function
|
|
1731
|
+
function ft() {
|
|
1707
1732
|
let e = typeof navigator < "u" ? navigator.connection : void 0;
|
|
1708
1733
|
if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
|
|
1709
1734
|
let t = { connectionType: e.type ? {
|
|
@@ -1713,17 +1738,17 @@ function lt() {
|
|
|
1713
1738
|
}[e.type] ?? "CONNECTION_TYPE_OTHER" : "CONNECTION_TYPE_UNKNOWN" };
|
|
1714
1739
|
return typeof e.downlink == "number" && e.downlink > 0 && (t.downlinkKbps = Math.round(e.downlink * 1e3)), e.saveData && (t.saveData = !0), t;
|
|
1715
1740
|
}
|
|
1716
|
-
function
|
|
1717
|
-
let t =
|
|
1718
|
-
deviceClass:
|
|
1741
|
+
function pt(e) {
|
|
1742
|
+
let t = ut(), n = {
|
|
1743
|
+
deviceClass: dt(),
|
|
1719
1744
|
integration: t.integration,
|
|
1720
|
-
...
|
|
1745
|
+
...ft()
|
|
1721
1746
|
};
|
|
1722
1747
|
t.host && (n.host = t.host), typeof screen < "u" && screen.width > 0 && (n.screenWidth = screen.width, n.screenHeight = screen.height), typeof window < "u" && window.devicePixelRatio > 0 && (n.devicePixelRatio = Math.round(window.devicePixelRatio * 100) / 100);
|
|
1723
1748
|
let r = e.getBoundingClientRect?.();
|
|
1724
1749
|
return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
|
|
1725
1750
|
}
|
|
1726
|
-
async function
|
|
1751
|
+
async function mt() {
|
|
1727
1752
|
let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
|
|
1728
1753
|
if (!e?.getHighEntropyValues) return {};
|
|
1729
1754
|
try {
|
|
@@ -1735,7 +1760,7 @@ async function dt() {
|
|
|
1735
1760
|
}
|
|
1736
1761
|
//#endregion
|
|
1737
1762
|
//#region src/core/version.ts
|
|
1738
|
-
var
|
|
1763
|
+
var ht = "2.3.1", J = {
|
|
1739
1764
|
accent: "#E1B600",
|
|
1740
1765
|
accentText: "#1B1C23",
|
|
1741
1766
|
background: "#0e0f13",
|
|
@@ -1768,15 +1793,15 @@ function X(e, t) {
|
|
|
1768
1793
|
}
|
|
1769
1794
|
//#endregion
|
|
1770
1795
|
//#region src/ui/styles.ts
|
|
1771
|
-
var Z = "havik-player-styles",
|
|
1772
|
-
function
|
|
1796
|
+
var Z = "havik-player-styles", gt = "\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";
|
|
1797
|
+
function _t(e = document) {
|
|
1773
1798
|
if (e.getElementById(Z)) return;
|
|
1774
1799
|
let t = e.createElement("style");
|
|
1775
|
-
t.id = Z, t.textContent =
|
|
1800
|
+
t.id = Z, t.textContent = gt, e.head.appendChild(t);
|
|
1776
1801
|
}
|
|
1777
1802
|
//#endregion
|
|
1778
1803
|
//#region src/ui/icons.ts
|
|
1779
|
-
var
|
|
1804
|
+
var vt = {
|
|
1780
1805
|
play: "<path d=\"M8 5v14l11-7z\"/>",
|
|
1781
1806
|
pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
|
|
1782
1807
|
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\"/>",
|
|
@@ -1790,20 +1815,20 @@ var ht = {
|
|
|
1790
1815
|
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\"/>"
|
|
1791
1816
|
};
|
|
1792
1817
|
function Q(e) {
|
|
1793
|
-
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${
|
|
1818
|
+
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${vt[e]}</svg>`;
|
|
1794
1819
|
}
|
|
1795
1820
|
//#endregion
|
|
1796
1821
|
//#region src/ui/controls.ts
|
|
1797
|
-
var
|
|
1822
|
+
var yt = 3e3, bt = /* @__PURE__ */ new Set([
|
|
1798
1823
|
"GONE",
|
|
1799
1824
|
"NOT_FOUND",
|
|
1800
1825
|
"INVALID_URN",
|
|
1801
1826
|
"UNAUTHORIZED"
|
|
1802
1827
|
]);
|
|
1803
|
-
function
|
|
1804
|
-
return new
|
|
1828
|
+
function xt(e) {
|
|
1829
|
+
return new St(e);
|
|
1805
1830
|
}
|
|
1806
|
-
var
|
|
1831
|
+
var St = class {
|
|
1807
1832
|
root;
|
|
1808
1833
|
video;
|
|
1809
1834
|
player;
|
|
@@ -1845,7 +1870,7 @@ var yt = class {
|
|
|
1845
1870
|
scrubbing = !1;
|
|
1846
1871
|
offFns = [];
|
|
1847
1872
|
constructor(e) {
|
|
1848
|
-
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ??
|
|
1873
|
+
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? yt, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, _t(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");
|
|
1849
1874
|
let t = (e, t, n) => {
|
|
1850
1875
|
let r = this.doc.createElement(e);
|
|
1851
1876
|
if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
|
|
@@ -1936,7 +1961,7 @@ var yt = class {
|
|
|
1936
1961
|
e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML = Q("play"), e.addEventListener("click", () => void this.player.play()), n.append(e);
|
|
1937
1962
|
} else {
|
|
1938
1963
|
let r = this.doc.createElement("div");
|
|
1939
|
-
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !
|
|
1964
|
+
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !bt.has(this.lastError.code)) {
|
|
1940
1965
|
let e = this.doc.createElement("button");
|
|
1941
1966
|
e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${Q("retry")}<span>Retry</span>`, e.addEventListener("click", () => void this.player.retry()), n.append(e);
|
|
1942
1967
|
}
|
|
@@ -1977,7 +2002,7 @@ var yt = class {
|
|
|
1977
2002
|
let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
|
|
1978
2003
|
this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
|
|
1979
2004
|
}
|
|
1980
|
-
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${
|
|
2005
|
+
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Ct(this.video.currentTime)} / ${Ct(this.video.duration)}`);
|
|
1981
2006
|
}
|
|
1982
2007
|
syncLive() {
|
|
1983
2008
|
let e = this.player.getStats(), t = e.isLive !== !1;
|
|
@@ -2027,17 +2052,17 @@ var yt = class {
|
|
|
2027
2052
|
renderQualityMenu() {
|
|
2028
2053
|
let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
|
|
2029
2054
|
n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
|
|
2030
|
-
for (let n of e) this.menu.append(this.menuItem(
|
|
2055
|
+
for (let n of e) this.menu.append(this.menuItem(wt(n), t === n.index, () => this.player.setQuality(n.index)));
|
|
2031
2056
|
}
|
|
2032
2057
|
renderAudioMenu() {
|
|
2033
2058
|
let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
|
|
2034
2059
|
t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
|
|
2035
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
2060
|
+
for (let t of e) this.menu.append(this.menuItem(Tt(t), t.default, () => this.player.setAudioTrack(t.id)));
|
|
2036
2061
|
}
|
|
2037
2062
|
renderCcMenu() {
|
|
2038
2063
|
let e = this.player.getTextTracks(), t = this.doc.createElement("div");
|
|
2039
2064
|
t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
|
|
2040
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
2065
|
+
for (let t of e) this.menu.append(this.menuItem(Et(t), !1, () => this.player.setTextTrack(t.id)));
|
|
2041
2066
|
}
|
|
2042
2067
|
onTracksChanged() {
|
|
2043
2068
|
this.openMenu && this.renderMenu(this.openMenu);
|
|
@@ -2057,11 +2082,11 @@ var yt = class {
|
|
|
2057
2082
|
}
|
|
2058
2083
|
async toggleFullscreen() {
|
|
2059
2084
|
try {
|
|
2060
|
-
|
|
2085
|
+
S(this.video, this.root) ? await w(this.video, this.root) : await C(this.video, this.root);
|
|
2061
2086
|
} catch {}
|
|
2062
2087
|
}
|
|
2063
2088
|
syncFullscreen() {
|
|
2064
|
-
let e =
|
|
2089
|
+
let e = S(this.video, this.root);
|
|
2065
2090
|
this.setIcon(this.fsBtn, e ? "fullscreenExit" : "fullscreen"), this.fsBtn.setAttribute("aria-label", e ? "Exit fullscreen" : "Fullscreen");
|
|
2066
2091
|
}
|
|
2067
2092
|
poke() {
|
|
@@ -2137,32 +2162,32 @@ var yt = class {
|
|
|
2137
2162
|
this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
|
|
2138
2163
|
}
|
|
2139
2164
|
};
|
|
2140
|
-
function
|
|
2165
|
+
function Ct(e) {
|
|
2141
2166
|
(!Number.isFinite(e) || e < 0) && (e = 0);
|
|
2142
2167
|
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");
|
|
2143
2168
|
return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
|
|
2144
2169
|
}
|
|
2145
|
-
function
|
|
2170
|
+
function wt(e) {
|
|
2146
2171
|
return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
|
|
2147
2172
|
}
|
|
2148
|
-
function
|
|
2173
|
+
function Tt(e) {
|
|
2149
2174
|
return e.name || e.lang || `Track ${e.id}`;
|
|
2150
2175
|
}
|
|
2151
|
-
function
|
|
2176
|
+
function Et(e) {
|
|
2152
2177
|
return e.name || e.lang || `Track ${e.id}`;
|
|
2153
2178
|
}
|
|
2154
2179
|
//#endregion
|
|
2155
2180
|
//#region src/managed/index.ts
|
|
2156
|
-
var
|
|
2157
|
-
async function
|
|
2181
|
+
var Dt = 6e3, Ot = 45e3, kt = 2e3, At = 3, jt = 2e3, Mt = 48e4;
|
|
2182
|
+
async function Nt(e) {
|
|
2158
2183
|
if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
2159
2184
|
if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: baseUrl is required");
|
|
2160
2185
|
if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
2161
2186
|
if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
|
|
2162
|
-
let t = new
|
|
2187
|
+
let t = new Pt(e);
|
|
2163
2188
|
return await t.start(), t;
|
|
2164
2189
|
}
|
|
2165
|
-
var
|
|
2190
|
+
var Pt = class {
|
|
2166
2191
|
opts;
|
|
2167
2192
|
abort = new AbortController();
|
|
2168
2193
|
listeners = {};
|
|
@@ -2228,7 +2253,7 @@ var jt = class {
|
|
|
2228
2253
|
};
|
|
2229
2254
|
}
|
|
2230
2255
|
beginArming(e, t, n = !1) {
|
|
2231
|
-
let r = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ??
|
|
2256
|
+
let r = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? E(this.opts.baseUrl);
|
|
2232
2257
|
r ? this.armWithSse(e, r, t, n) : this.beginArmingByPolling(e);
|
|
2233
2258
|
}
|
|
2234
2259
|
beginArmingByPolling(e) {
|
|
@@ -2249,7 +2274,7 @@ var jt = class {
|
|
|
2249
2274
|
setTimeout(() => {
|
|
2250
2275
|
a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
|
|
2251
2276
|
phase: i ? "unavailable" : "tooEarly",
|
|
2252
|
-
retryInMs:
|
|
2277
|
+
retryInMs: Ot,
|
|
2253
2278
|
attempt: 1,
|
|
2254
2279
|
elapsedMs: 0,
|
|
2255
2280
|
...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
|
|
@@ -2288,13 +2313,13 @@ var jt = class {
|
|
|
2288
2313
|
!a && !p() && h();
|
|
2289
2314
|
}, e);
|
|
2290
2315
|
};
|
|
2291
|
-
_(
|
|
2316
|
+
_(Dt), this.armingSub = T({
|
|
2292
2317
|
eventsBaseUrl: t,
|
|
2293
2318
|
matchUrn: this.opts.matchUrn,
|
|
2294
2319
|
credential: this.opts.credential,
|
|
2295
|
-
onAlive: () => _(
|
|
2320
|
+
onAlive: () => _(Ot),
|
|
2296
2321
|
onState: (e) => {
|
|
2297
|
-
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() *
|
|
2322
|
+
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * kt);
|
|
2298
2323
|
},
|
|
2299
2324
|
onError: () => h()
|
|
2300
2325
|
});
|
|
@@ -2317,7 +2342,7 @@ var jt = class {
|
|
|
2317
2342
|
let n = await s(this.opts.credential);
|
|
2318
2343
|
if (this.destroyed || t !== this.loadGen) return;
|
|
2319
2344
|
this.setState("loading");
|
|
2320
|
-
let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a =
|
|
2345
|
+
let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = Me(this.opts.video, (e) => {
|
|
2321
2346
|
this._state !== "ended" && this._state !== "error" && this.setState(e);
|
|
2322
2347
|
});
|
|
2323
2348
|
if (await i.load(), this.destroyed || t !== this.loadGen) {
|
|
@@ -2336,17 +2361,17 @@ var jt = class {
|
|
|
2336
2361
|
if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
|
|
2337
2362
|
let r = e.analytics?.sid;
|
|
2338
2363
|
if (!r) return;
|
|
2339
|
-
let i = (typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0) ??
|
|
2364
|
+
let i = (typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0) ?? ct(this.opts.baseUrl);
|
|
2340
2365
|
if (!i) return;
|
|
2341
|
-
let a = this.opts.video, o = new
|
|
2366
|
+
let a = this.opts.video, o = new lt({
|
|
2342
2367
|
endpoint: i,
|
|
2343
2368
|
sid: r,
|
|
2344
2369
|
apiKey: n,
|
|
2345
2370
|
player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
|
|
2346
|
-
sdkVersion:
|
|
2347
|
-
environment:
|
|
2371
|
+
sdkVersion: ht,
|
|
2372
|
+
environment: pt(a),
|
|
2348
2373
|
sample: () => {
|
|
2349
|
-
let e = this.engine?.getStats() ??
|
|
2374
|
+
let e = this.engine?.getStats() ?? I, t = a.buffered.length ? Math.max(0, a.buffered.end(a.buffered.length - 1) - a.currentTime) : 0;
|
|
2350
2375
|
return {
|
|
2351
2376
|
...e,
|
|
2352
2377
|
bufferedMs: Math.round(t * 1e3),
|
|
@@ -2360,7 +2385,7 @@ var jt = class {
|
|
|
2360
2385
|
let s = () => o.noteSeek(), c = () => o.noteVolume(a.muted, a.volume);
|
|
2361
2386
|
a.addEventListener("seeking", s), a.addEventListener("volumechange", c), this.detachMediaListeners = () => {
|
|
2362
2387
|
a.removeEventListener("seeking", s), a.removeEventListener("volumechange", c);
|
|
2363
|
-
}, o.start(), o.seedVolume(a.muted, a.volume), o.notePresentation(this.currentPresentation()),
|
|
2388
|
+
}, o.start(), o.seedVolume(a.muted, a.volume), o.notePresentation(this.currentPresentation()), mt().then((e) => o.noteEnvironment(e)), this.opts.autoplay === !1 && o.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
|
|
2364
2389
|
}
|
|
2365
2390
|
currentPresentation() {
|
|
2366
2391
|
let e = this.opts.video;
|
|
@@ -2375,7 +2400,7 @@ var jt = class {
|
|
|
2375
2400
|
video: this.opts.video,
|
|
2376
2401
|
descriptor: e,
|
|
2377
2402
|
credential: t,
|
|
2378
|
-
deviceId:
|
|
2403
|
+
deviceId: k(),
|
|
2379
2404
|
userId: this.opts.userId,
|
|
2380
2405
|
lowLatency: this.opts.lowLatency === void 0 || this.opts.lowLatency === "auto" || this.opts.lowLatency,
|
|
2381
2406
|
snapToLiveOnRefocus: this.opts.snapToLiveOnRefocus,
|
|
@@ -2387,7 +2412,7 @@ var jt = class {
|
|
|
2387
2412
|
if (o === "native") return new V(a);
|
|
2388
2413
|
if (o === "hls") return new U(a);
|
|
2389
2414
|
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && z(this.opts.video) && B()) return new V(a);
|
|
2390
|
-
if (
|
|
2415
|
+
if (Fe()) return new U(a);
|
|
2391
2416
|
if (z(this.opts.video)) return new V(a);
|
|
2392
2417
|
throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
|
|
2393
2418
|
}
|
|
@@ -2416,11 +2441,11 @@ var jt = class {
|
|
|
2416
2441
|
}
|
|
2417
2442
|
startLiveState(e) {
|
|
2418
2443
|
if (this.opts.liveStateEvents === !1) return;
|
|
2419
|
-
let t = this.opts.eventsBaseUrl ??
|
|
2444
|
+
let t = this.opts.eventsBaseUrl ?? E(this.opts.baseUrl);
|
|
2420
2445
|
if (!t) return;
|
|
2421
2446
|
this.closeLiveState();
|
|
2422
2447
|
let r = 0, i = !1;
|
|
2423
|
-
this.liveStateSub =
|
|
2448
|
+
this.liveStateSub = T({
|
|
2424
2449
|
eventsBaseUrl: t,
|
|
2425
2450
|
matchUrn: this.opts.matchUrn,
|
|
2426
2451
|
credential: this.opts.credential,
|
|
@@ -2431,7 +2456,7 @@ var jt = class {
|
|
|
2431
2456
|
r = 0, i = !1;
|
|
2432
2457
|
},
|
|
2433
2458
|
onError: () => {
|
|
2434
|
-
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >=
|
|
2459
|
+
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= At && (i = !0, this.emit("warning", new n("NETWORK", 0, `live-state events unreachable at ${t} after ${r} attempts — end-of-stream detection degraded to the HLS staleness watchdog. Check the events host, the api-key's allowed origins, and CSP connect-src.`))));
|
|
2435
2460
|
}
|
|
2436
2461
|
});
|
|
2437
2462
|
}
|
|
@@ -2453,7 +2478,7 @@ var jt = class {
|
|
|
2453
2478
|
scheduleRejoin(e) {
|
|
2454
2479
|
!this.rejoinEnabled() || this.rejoinTimer || (this.rejoinTimer = setTimeout(() => {
|
|
2455
2480
|
this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
|
|
2456
|
-
}, Math.random() *
|
|
2481
|
+
}, Math.random() * kt));
|
|
2457
2482
|
}
|
|
2458
2483
|
cancelRejoin() {
|
|
2459
2484
|
this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
|
|
@@ -2477,7 +2502,7 @@ var jt = class {
|
|
|
2477
2502
|
}
|
|
2478
2503
|
t.controls = !1;
|
|
2479
2504
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
2480
|
-
r && r.insertBefore(n, t), n.appendChild(t), X(n, this.opts.theme), this.container = n, this.controlBar =
|
|
2505
|
+
r && r.insertBefore(n, t), n.appendChild(t), X(n, this.opts.theme), this.container = n, this.controlBar = xt({
|
|
2481
2506
|
root: n,
|
|
2482
2507
|
video: t,
|
|
2483
2508
|
player: this,
|
|
@@ -2507,7 +2532,7 @@ var jt = class {
|
|
|
2507
2532
|
}
|
|
2508
2533
|
startStats() {
|
|
2509
2534
|
this.stopStats();
|
|
2510
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
2535
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? jt);
|
|
2511
2536
|
this.statsTimer = setInterval(() => {
|
|
2512
2537
|
if (!this.engine) return;
|
|
2513
2538
|
let e = this.engine.getStats();
|
|
@@ -2519,7 +2544,7 @@ var jt = class {
|
|
|
2519
2544
|
}
|
|
2520
2545
|
scheduleLicenseRefresh() {
|
|
2521
2546
|
this.stopRefresh();
|
|
2522
|
-
let e = this.opts.licenseRefreshMs ??
|
|
2547
|
+
let e = this.opts.licenseRefreshMs ?? Mt;
|
|
2523
2548
|
!e || !this._descriptor?.drmEnabled || (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
2524
2549
|
}
|
|
2525
2550
|
stopRefresh() {
|
|
@@ -2544,7 +2569,7 @@ var jt = class {
|
|
|
2544
2569
|
let e = !this.playRequested;
|
|
2545
2570
|
this.playRequested = !0;
|
|
2546
2571
|
let t = this.pendingStartLoad && this._state !== "ended" && this._state !== "error";
|
|
2547
|
-
t && (this.pendingStartLoad = !1, this.setState("loading"), this.engine?.startLoad());
|
|
2572
|
+
this.opts.autoplay === !1 && this.analyticsSession?.notePlayIntent(), t && (this.pendingStartLoad = !1, this.setState("loading"), this.engine?.startLoad());
|
|
2548
2573
|
try {
|
|
2549
2574
|
await this.opts.video.play(), e && this.analyticsSession?.noteAutoplay(this.opts.video.muted ? "AUTOPLAY_RESULT_ALLOWED_MUTED" : "AUTOPLAY_RESULT_ALLOWED");
|
|
2550
2575
|
} catch (n) {
|
|
@@ -2561,7 +2586,7 @@ var jt = class {
|
|
|
2561
2586
|
this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
|
|
2562
2587
|
}
|
|
2563
2588
|
getStats() {
|
|
2564
|
-
return this.engine?.getStats() ??
|
|
2589
|
+
return this.engine?.getStats() ?? I;
|
|
2565
2590
|
}
|
|
2566
2591
|
getQualityLevels() {
|
|
2567
2592
|
return this.engine?.getQualityLevels() ?? [];
|
|
@@ -2600,10 +2625,10 @@ var jt = class {
|
|
|
2600
2625
|
e.pictureInPictureElement === this.opts.video && typeof e.exitPictureInPicture == "function" && await e.exitPictureInPicture();
|
|
2601
2626
|
}
|
|
2602
2627
|
async enterFullscreen() {
|
|
2603
|
-
return !this.destroyed &&
|
|
2628
|
+
return !this.destroyed && C(this.opts.video, this.container ?? void 0);
|
|
2604
2629
|
}
|
|
2605
2630
|
async exitFullscreen() {
|
|
2606
|
-
await
|
|
2631
|
+
await w(this.opts.video, this.container ?? void 0);
|
|
2607
2632
|
}
|
|
2608
2633
|
retry() {
|
|
2609
2634
|
return this.reload();
|
|
@@ -2671,7 +2696,7 @@ function $(e) {
|
|
|
2671
2696
|
}
|
|
2672
2697
|
//#endregion
|
|
2673
2698
|
//#region src/embed/host.ts
|
|
2674
|
-
function
|
|
2699
|
+
function Ft(e) {
|
|
2675
2700
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
2676
2701
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
2677
2702
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -2730,8 +2755,8 @@ function Mt(e) {
|
|
|
2730
2755
|
}
|
|
2731
2756
|
//#endregion
|
|
2732
2757
|
//#region src/embed/page.ts
|
|
2733
|
-
var
|
|
2734
|
-
function
|
|
2758
|
+
var It = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
2759
|
+
function Lt() {
|
|
2735
2760
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
2736
2761
|
if (e) return {
|
|
2737
2762
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -2753,9 +2778,9 @@ function Pt() {
|
|
|
2753
2778
|
waitForLive: !0
|
|
2754
2779
|
};
|
|
2755
2780
|
}
|
|
2756
|
-
async function
|
|
2757
|
-
let e =
|
|
2758
|
-
|
|
2781
|
+
async function Rt() {
|
|
2782
|
+
let e = Lt();
|
|
2783
|
+
Bt();
|
|
2759
2784
|
let t = document.createElement("video");
|
|
2760
2785
|
t.setAttribute("playsinline", ""), t.muted = e.muted ?? !0, t.style.cssText = "width:100%;height:100%;object-fit:contain;background:#000;aspect-ratio:auto", document.body.appendChild(t);
|
|
2761
2786
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
@@ -2810,12 +2835,12 @@ async function Ft() {
|
|
|
2810
2835
|
code: e.code,
|
|
2811
2836
|
message: e.message
|
|
2812
2837
|
})), e.on("autoplayblocked", () => {
|
|
2813
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
2838
|
+
i({ type: "oddin:autoplayblocked" }), zt(t, e);
|
|
2814
2839
|
});
|
|
2815
2840
|
}, s = async (r) => {
|
|
2816
2841
|
a?.destroy(), a = null;
|
|
2817
2842
|
try {
|
|
2818
|
-
let n = await
|
|
2843
|
+
let n = await Nt({
|
|
2819
2844
|
video: t,
|
|
2820
2845
|
baseUrl: e.baseUrl,
|
|
2821
2846
|
matchUrn: r,
|
|
@@ -2876,7 +2901,7 @@ async function Ft() {
|
|
|
2876
2901
|
a?.retry();
|
|
2877
2902
|
break;
|
|
2878
2903
|
case "oddin:load":
|
|
2879
|
-
typeof e.matchUrn == "string" &&
|
|
2904
|
+
typeof e.matchUrn == "string" && It.test(e.matchUrn) && s(e.matchUrn);
|
|
2880
2905
|
break;
|
|
2881
2906
|
case "oddin:destroy": c();
|
|
2882
2907
|
}
|
|
@@ -2888,18 +2913,18 @@ async function Ft() {
|
|
|
2888
2913
|
protocol: 1
|
|
2889
2914
|
});
|
|
2890
2915
|
}
|
|
2891
|
-
function
|
|
2916
|
+
function zt(e, t) {
|
|
2892
2917
|
if (document.getElementById("havik-tap")) return;
|
|
2893
2918
|
let n = document.createElement("button");
|
|
2894
2919
|
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", () => {
|
|
2895
2920
|
n.remove(), t.play();
|
|
2896
2921
|
}), document.body.appendChild(n);
|
|
2897
2922
|
}
|
|
2898
|
-
function
|
|
2923
|
+
function Bt() {
|
|
2899
2924
|
let e = document.createElement("style");
|
|
2900
2925
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
2901
2926
|
}
|
|
2902
2927
|
//#endregion
|
|
2903
|
-
export { J as ODDIN_THEME, n as PlaybackError, X as applyTheme,
|
|
2928
|
+
export { J as ODDIN_THEME, n as PlaybackError, X as applyTheme, Rt as bootEmbed, _e as clearDeviceId, Nt as createPlayer, E as deriveEventsBaseUrl, De as detectDrmSupport, C as enterVideoFullscreen, w as exitVideoFullscreen, de as fetchCatalog, pe as fetchTournament, he as flattenMatches, k as getDeviceId, ke as isLowLatencyManifest, $ as isOddinMessage, ye as licenseRequestHeaders, Ft as mountEmbed, v as pollToLive, b as resolveStream, T as subscribeLiveState, S as videoFullscreenActive, ge as watchStatus };
|
|
2904
2929
|
|
|
2905
2930
|
//# sourceMappingURL=index.js.map
|