@oddin-gg/havik-player 1.0.4 → 1.0.6
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 +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +69 -59
- package/dist/index.js.map +1 -1
- package/docs/API.md +12 -0
- package/embed/index.html +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -510,17 +510,21 @@ function I(e, t) {
|
|
|
510
510
|
function L() {
|
|
511
511
|
return e.isSupported();
|
|
512
512
|
}
|
|
513
|
-
var R = 3, z = 5, B = 3, V = 3e4, H = 12e3, U = 3e3, de = 6e3, fe = 3, pe = 9;
|
|
514
|
-
function
|
|
513
|
+
var R = 3, z = 5, B = 3, V = 3e4, H = 12e3, U = 3e3, de = 6e3, fe = 3, pe = 9, me = .5;
|
|
514
|
+
function he(e) {
|
|
515
515
|
if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
|
|
516
516
|
delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
|
|
517
517
|
return;
|
|
518
518
|
}
|
|
519
519
|
e.liveSyncDuration ??= fe;
|
|
520
520
|
let t = Math.max(12, e.liveSyncDuration + pe);
|
|
521
|
-
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t);
|
|
521
|
+
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), ge(e, e.liveSyncDuration);
|
|
522
522
|
}
|
|
523
|
-
|
|
523
|
+
function ge(e, t) {
|
|
524
|
+
let n = (e, t, n) => Math.min(n, Math.max(t, e));
|
|
525
|
+
e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
|
|
526
|
+
}
|
|
527
|
+
var _e = class {
|
|
524
528
|
name = "hls";
|
|
525
529
|
hls = null;
|
|
526
530
|
deps;
|
|
@@ -533,6 +537,7 @@ var he = class {
|
|
|
533
537
|
networkRetryTimer = null;
|
|
534
538
|
licenseRetryTimer = null;
|
|
535
539
|
onVisibility = null;
|
|
540
|
+
onSeeking = null;
|
|
536
541
|
sawLive = !1;
|
|
537
542
|
lastEndSN = -1;
|
|
538
543
|
lastAdvanceMs = 0;
|
|
@@ -561,7 +566,15 @@ var he = class {
|
|
|
561
566
|
if (typeof t != "number") return;
|
|
562
567
|
let n = typeof e.targetLatency == "number" && e.targetLatency > 0 ? e.targetLatency : 3;
|
|
563
568
|
t - r.currentTime > Math.max(n * 3, 8) && (r.currentTime = t);
|
|
564
|
-
}, document.addEventListener("visibilitychange", this.onVisibility));
|
|
569
|
+
}, document.addEventListener("visibilitychange", this.onVisibility)), this.onSeeking = () => this.clampOverSeek(), r.addEventListener("seeking", this.onSeeking);
|
|
570
|
+
}
|
|
571
|
+
clampOverSeek() {
|
|
572
|
+
let e = this.hls;
|
|
573
|
+
if (!e || this.chaseSuspended || (e.levels[e.currentLevel] ?? e.levels[e.loadLevel])?.details?.live !== !0) return;
|
|
574
|
+
let t = e.liveSyncPosition;
|
|
575
|
+
if (typeof t != "number" || !Number.isFinite(t)) return;
|
|
576
|
+
let { video: n } = this.deps;
|
|
577
|
+
n.currentTime <= t + me || (n.currentTime = t);
|
|
565
578
|
}
|
|
566
579
|
startHls() {
|
|
567
580
|
let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, hlsConfig: s, emit: c } = this.deps, l = n.drmEnabled && !!n.drm?.widevine?.licenseUrl, u = {
|
|
@@ -587,7 +600,7 @@ var he = class {
|
|
|
587
600
|
} : {},
|
|
588
601
|
...s
|
|
589
602
|
};
|
|
590
|
-
|
|
603
|
+
he(u);
|
|
591
604
|
let d = new e(u);
|
|
592
605
|
this.hls = d, d.on(e.Events.MANIFEST_PARSED, () => {
|
|
593
606
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, c({ type: "ready" });
|
|
@@ -727,7 +740,7 @@ var he = class {
|
|
|
727
740
|
} catch {}
|
|
728
741
|
}
|
|
729
742
|
destroy() {
|
|
730
|
-
if (this.clearRecoveryReset(), this.endWatchdog &&= (clearInterval(this.endWatchdog), null), this.onVisibility && typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), this.onVisibility = null), this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null), this.licenseRetryTimer &&= (clearTimeout(this.licenseRetryTimer), null), this.hls) {
|
|
743
|
+
if (this.clearRecoveryReset(), this.endWatchdog &&= (clearInterval(this.endWatchdog), null), this.onVisibility && typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), this.onVisibility = null), this.onSeeking &&= (this.deps.video.removeEventListener("seeking", this.onSeeking), null), this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null), this.licenseRetryTimer &&= (clearTimeout(this.licenseRetryTimer), null), this.hls) {
|
|
731
744
|
try {
|
|
732
745
|
this.hls.destroy();
|
|
733
746
|
} catch (e) {
|
|
@@ -811,7 +824,7 @@ var he = class {
|
|
|
811
824
|
};
|
|
812
825
|
//#endregion
|
|
813
826
|
//#region src/core/engine/native.ts
|
|
814
|
-
function
|
|
827
|
+
function ve(e) {
|
|
815
828
|
return !!(e ?? (typeof document < "u" ? document.createElement("video") : void 0))?.canPlayType("application/vnd.apple.mpegurl");
|
|
816
829
|
}
|
|
817
830
|
var W = class {
|
|
@@ -942,15 +955,15 @@ function q(e, t) {
|
|
|
942
955
|
}
|
|
943
956
|
//#endregion
|
|
944
957
|
//#region src/ui/styles.ts
|
|
945
|
-
var J = "havik-player-styles",
|
|
946
|
-
function
|
|
958
|
+
var J = "havik-player-styles", ye = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n.havik-spinner{width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n\n.havik-bar{position:absolute;left:0;right:0;bottom:0;padding:0 12px 8px;\n opacity:1;transition:opacity .25s;z-index:2}\n.havik-seek{position:relative;height:16px;display:flex;align-items:center;cursor:pointer;margin-bottom:2px}\n.havik-seek__track{position:relative;width:100%;height:4px;border-radius:3px;background:rgba(255,255,255,.25)}\n.havik-seek__buffered{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:rgba(255,255,255,.4)}\n.havik-seek__played{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-seek__thumb{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;\n background:var(--havik-accent,#E1B600);transform:translate(-50%,-50%) scale(0);transition:transform .1s}\n.havik-seek:hover .havik-seek__thumb{transform:translate(-50%,-50%) scale(1)}\n\n.havik-controls{display:flex;align-items:center;gap:6px;height:40px}\n.havik-spacer{flex:1}\n.havik-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;border-radius:var(--havik-radius,8px);\n padding:0;transition:background .12s,color .12s}\n.havik-btn:hover{background:rgba(255,255,255,.12)}\n.havik-btn:focus-visible{outline:2px solid var(--havik-accent,#E1B600);outline-offset:1px}\n.havik-btn svg{width:22px;height:22px}\n\n.havik-vol{display:flex;align-items:center}\n.havik-vol__slider{width:0;opacity:0;transition:width .18s,opacity .18s;height:4px;cursor:pointer;\n appearance:none;-webkit-appearance:none;background:rgba(255,255,255,.3);border-radius:3px;margin:0 4px}\n.havik-vol:hover .havik-vol__slider,.havik-vol:focus-within .havik-vol__slider{width:70px;opacity:1}\n.havik-vol__slider::-webkit-slider-thumb{-webkit-appearance:none;width:12px;height:12px;border-radius:50%;background:var(--havik-accent,#E1B600)}\n.havik-vol__slider::-moz-range-thumb{width:12px;height:12px;border:0;border-radius:50%;background:var(--havik-accent,#E1B600)}\n\n.havik-time{font-size:12px;color:var(--havik-text-muted,#9aa0ad);\n font-variant-numeric:tabular-nums;padding:0 6px;white-space:nowrap}\n.havik-live{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;\n letter-spacing:.4px;padding:0 8px;color:var(--havik-text,#fff)}\n.havik-live svg{width:9px;height:9px;color:var(--havik-text-muted,#9aa0ad)}\n.havik-live.is-live svg{color:var(--havik-accent,#E1B600)}\n.havik-live__go{margin-left:2px;border:0;cursor:pointer;background:transparent;color:var(--havik-text-muted,#9aa0ad);\n font:inherit;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:6px}\n.havik-live.is-live .havik-live__go{display:none}\n.havik-live__go:hover{color:var(--havik-accent,#E1B600)}\n\n.havik-menu{position:absolute;bottom:54px;right:12px;min-width:170px;max-height:230px;overflow:auto;\n background:var(--havik-surface,#1B1C23);border:1px solid var(--havik-border,rgba(255,255,255,.1));\n border-radius:var(--havik-radius,8px);box-shadow:0 10px 30px rgba(0,0,0,.5);padding:6px;z-index:3}\n.havik-menu[hidden]{display:none}\n.havik-menu__title{font-size:11px;text-transform:uppercase;letter-spacing:.6px;\n color:var(--havik-text-muted,#9aa0ad);padding:6px 8px 4px}\n.havik-menu__item{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;font:inherit;font-size:13px;\n text-align:left;padding:7px 8px;border-radius:6px}\n.havik-menu__item:hover{background:var(--havik-surface-muted,#2a2c36)}\n.havik-menu__item[aria-checked=\"true\"]{color:var(--havik-accent,#E1B600);font-weight:600}\n.havik-menu__item[aria-checked=\"true\"]::after{content:'✓'}\n";
|
|
959
|
+
function be(e = document) {
|
|
947
960
|
if (e.getElementById(J)) return;
|
|
948
961
|
let t = e.createElement("style");
|
|
949
|
-
t.id = J, t.textContent =
|
|
962
|
+
t.id = J, t.textContent = ye, e.head.appendChild(t);
|
|
950
963
|
}
|
|
951
964
|
//#endregion
|
|
952
965
|
//#region src/ui/icons.ts
|
|
953
|
-
var
|
|
966
|
+
var xe = {
|
|
954
967
|
play: "<path d=\"M8 5v14l11-7z\"/>",
|
|
955
968
|
pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
|
|
956
969
|
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\"/>",
|
|
@@ -964,20 +977,20 @@ var ye = {
|
|
|
964
977
|
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\"/>"
|
|
965
978
|
};
|
|
966
979
|
function Y(e) {
|
|
967
|
-
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${
|
|
980
|
+
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${xe[e]}</svg>`;
|
|
968
981
|
}
|
|
969
982
|
//#endregion
|
|
970
983
|
//#region src/ui/controls.ts
|
|
971
|
-
var
|
|
984
|
+
var Se = 3e3, Ce = /* @__PURE__ */ new Set([
|
|
972
985
|
"GONE",
|
|
973
986
|
"NOT_FOUND",
|
|
974
987
|
"INVALID_URN",
|
|
975
988
|
"UNAUTHORIZED"
|
|
976
989
|
]);
|
|
977
|
-
function
|
|
978
|
-
return new
|
|
990
|
+
function we(e) {
|
|
991
|
+
return new Te(e);
|
|
979
992
|
}
|
|
980
|
-
var
|
|
993
|
+
var Te = class {
|
|
981
994
|
root;
|
|
982
995
|
video;
|
|
983
996
|
player;
|
|
@@ -1017,7 +1030,7 @@ var Ce = class {
|
|
|
1017
1030
|
scrubbing = !1;
|
|
1018
1031
|
offFns = [];
|
|
1019
1032
|
constructor(e) {
|
|
1020
|
-
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ??
|
|
1033
|
+
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Se, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.errorMessage = e.errorMessage, be(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");
|
|
1021
1034
|
let t = (e, t, n) => {
|
|
1022
1035
|
let r = this.doc.createElement(e);
|
|
1023
1036
|
if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
|
|
@@ -1104,7 +1117,7 @@ var Ce = class {
|
|
|
1104
1117
|
e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML = Y("play"), e.addEventListener("click", () => void this.player.play()), t.append(e);
|
|
1105
1118
|
} else {
|
|
1106
1119
|
let n = this.doc.createElement("div");
|
|
1107
|
-
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 && !
|
|
1120
|
+
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 && !Ce.has(this.lastError.code)) {
|
|
1108
1121
|
let e = this.doc.createElement("button");
|
|
1109
1122
|
e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${Y("retry")}<span>Retry</span>`, e.addEventListener("click", () => void this.player.retry()), t.append(e);
|
|
1110
1123
|
}
|
|
@@ -1116,17 +1129,14 @@ var Ce = class {
|
|
|
1116
1129
|
this.setIcon(this.muteBtn, t ? "volumeMute" : "volumeHigh"), this.muteBtn.setAttribute("aria-label", t ? "Unmute" : "Mute"), this.volSlider.value = String(t ? 0 : e.volume);
|
|
1117
1130
|
}
|
|
1118
1131
|
seekableRange() {
|
|
1119
|
-
let e = this.video;
|
|
1120
|
-
if (e.seekable && e.seekable.length > 0)
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
return Number.isFinite(e.duration) && e.duration > 0 ? {
|
|
1128
|
-
start: 0,
|
|
1129
|
-
end: e.duration
|
|
1132
|
+
let e = this.video, t, n;
|
|
1133
|
+
if (e.seekable && e.seekable.length > 0) t = e.seekable.start(0), n = e.seekable.end(e.seekable.length - 1);
|
|
1134
|
+
else if (Number.isFinite(e.duration) && e.duration > 0) t = 0, n = e.duration;
|
|
1135
|
+
else return null;
|
|
1136
|
+
let r = this.player.getStats();
|
|
1137
|
+
return r.isLive !== !1 && r.targetLatencySeconds && r.targetLatencySeconds > 0 && (n = Math.max(t, n - r.targetLatencySeconds)), n > t ? {
|
|
1138
|
+
start: t,
|
|
1139
|
+
end: n
|
|
1130
1140
|
} : null;
|
|
1131
1141
|
}
|
|
1132
1142
|
syncProgress() {
|
|
@@ -1193,17 +1203,17 @@ var Ce = class {
|
|
|
1193
1203
|
renderQualityMenu() {
|
|
1194
1204
|
let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
|
|
1195
1205
|
n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
|
|
1196
|
-
for (let n of e) this.menu.append(this.menuItem(
|
|
1206
|
+
for (let n of e) this.menu.append(this.menuItem(Ee(n), t === n.index, () => this.player.setQuality(n.index)));
|
|
1197
1207
|
}
|
|
1198
1208
|
renderAudioMenu() {
|
|
1199
1209
|
let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
|
|
1200
1210
|
t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
|
|
1201
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
1211
|
+
for (let t of e) this.menu.append(this.menuItem(De(t), t.default, () => this.player.setAudioTrack(t.id)));
|
|
1202
1212
|
}
|
|
1203
1213
|
renderCcMenu() {
|
|
1204
1214
|
let e = this.player.getTextTracks(), t = this.doc.createElement("div");
|
|
1205
1215
|
t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
|
|
1206
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
1216
|
+
for (let t of e) this.menu.append(this.menuItem(Oe(t), !1, () => this.player.setTextTrack(t.id)));
|
|
1207
1217
|
}
|
|
1208
1218
|
onTracksChanged() {
|
|
1209
1219
|
this.openMenu && this.renderMenu(this.openMenu);
|
|
@@ -1309,27 +1319,27 @@ function X(e) {
|
|
|
1309
1319
|
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");
|
|
1310
1320
|
return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
|
|
1311
1321
|
}
|
|
1312
|
-
function
|
|
1322
|
+
function Ee(e) {
|
|
1313
1323
|
return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
|
|
1314
1324
|
}
|
|
1315
|
-
function
|
|
1325
|
+
function De(e) {
|
|
1316
1326
|
return e.name || e.lang || `Track ${e.id}`;
|
|
1317
1327
|
}
|
|
1318
|
-
function
|
|
1328
|
+
function Oe(e) {
|
|
1319
1329
|
return e.name || e.lang || `Track ${e.id}`;
|
|
1320
1330
|
}
|
|
1321
1331
|
//#endregion
|
|
1322
1332
|
//#region src/managed/index.ts
|
|
1323
|
-
var
|
|
1333
|
+
var ke = 6e3, Z = 45e3, Ae = 2e3, je = 3, Me = 2e3, Ne = 480 * 1e3;
|
|
1324
1334
|
async function Q(e) {
|
|
1325
1335
|
if (!e.video || typeof e.video.play != "function") throw new t("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
1326
1336
|
if (!e.baseUrl) throw new t("INTERNAL", 0, "createPlayer: baseUrl is required");
|
|
1327
1337
|
if (!e.matchUrn) throw new t("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
1328
1338
|
if (!e.credential) throw new t("INTERNAL", 0, "createPlayer: credential is required");
|
|
1329
|
-
let n = new
|
|
1339
|
+
let n = new Pe(e);
|
|
1330
1340
|
return await n.start(), n;
|
|
1331
1341
|
}
|
|
1332
|
-
var
|
|
1342
|
+
var Pe = class {
|
|
1333
1343
|
opts;
|
|
1334
1344
|
abort = new AbortController();
|
|
1335
1345
|
listeners = {};
|
|
@@ -1408,13 +1418,13 @@ var Me = class {
|
|
|
1408
1418
|
!r && !s() && l();
|
|
1409
1419
|
}, e);
|
|
1410
1420
|
};
|
|
1411
|
-
d(
|
|
1421
|
+
d(ke), this.armingSub = w({
|
|
1412
1422
|
eventsBaseUrl: n,
|
|
1413
1423
|
matchUrn: this.opts.matchUrn,
|
|
1414
1424
|
credential: this.opts.credential,
|
|
1415
|
-
onAlive: () => d(
|
|
1425
|
+
onAlive: () => d(Z),
|
|
1416
1426
|
onState: (e) => {
|
|
1417
|
-
r || s() || (e.state === "live" || e.state === "gone") && setTimeout(u, Math.random() *
|
|
1427
|
+
r || s() || (e.state === "live" || e.state === "gone") && setTimeout(u, Math.random() * Ae);
|
|
1418
1428
|
},
|
|
1419
1429
|
onError: () => l()
|
|
1420
1430
|
});
|
|
@@ -1459,8 +1469,8 @@ var Me = class {
|
|
|
1459
1469
|
emit: (e) => this.onEngineEvent(e)
|
|
1460
1470
|
}, a = this.opts.engine ?? "auto";
|
|
1461
1471
|
if (a === "native") return new W(i);
|
|
1462
|
-
if (a === "hls" || L()) return new
|
|
1463
|
-
if (
|
|
1472
|
+
if (a === "hls" || L()) return new _e(i);
|
|
1473
|
+
if (ve(this.opts.video)) return new W(i);
|
|
1464
1474
|
throw new t("INTERNAL", 0, "no supported HLS playback engine in this browser");
|
|
1465
1475
|
}
|
|
1466
1476
|
onEngineEvent(e) {
|
|
@@ -1505,7 +1515,7 @@ var Me = class {
|
|
|
1505
1515
|
r = 0, i = !1;
|
|
1506
1516
|
},
|
|
1507
1517
|
onError: () => {
|
|
1508
|
-
this.destroyed || e !== this.loadGen || i || (r += 1, r >=
|
|
1518
|
+
this.destroyed || e !== this.loadGen || i || (r += 1, r >= je && (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.`))));
|
|
1509
1519
|
}
|
|
1510
1520
|
});
|
|
1511
1521
|
}
|
|
@@ -1527,7 +1537,7 @@ var Me = class {
|
|
|
1527
1537
|
}
|
|
1528
1538
|
t.controls = !1;
|
|
1529
1539
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
1530
|
-
r && r.insertBefore(n, t), n.appendChild(t), q(n, this.opts.theme), this.container = n, this.controlBar =
|
|
1540
|
+
r && r.insertBefore(n, t), n.appendChild(t), q(n, this.opts.theme), this.container = n, this.controlBar = we({
|
|
1531
1541
|
root: n,
|
|
1532
1542
|
video: t,
|
|
1533
1543
|
player: this,
|
|
@@ -1550,7 +1560,7 @@ var Me = class {
|
|
|
1550
1560
|
}
|
|
1551
1561
|
startStats() {
|
|
1552
1562
|
this.stopStats();
|
|
1553
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
1563
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? Me);
|
|
1554
1564
|
this.statsTimer = setInterval(() => {
|
|
1555
1565
|
this.engine && this.emit("stats", this.engine.getStats());
|
|
1556
1566
|
}, e);
|
|
@@ -1560,7 +1570,7 @@ var Me = class {
|
|
|
1560
1570
|
}
|
|
1561
1571
|
scheduleLicenseRefresh() {
|
|
1562
1572
|
this.stopRefresh();
|
|
1563
|
-
let e = this.opts.licenseRefreshMs ??
|
|
1573
|
+
let e = this.opts.licenseRefreshMs ?? Ne;
|
|
1564
1574
|
!e || !this._descriptor?.drmEnabled || (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
1565
1575
|
}
|
|
1566
1576
|
stopRefresh() {
|
|
@@ -1695,7 +1705,7 @@ function $(e) {
|
|
|
1695
1705
|
}
|
|
1696
1706
|
//#endregion
|
|
1697
1707
|
//#region src/embed/host.ts
|
|
1698
|
-
function
|
|
1708
|
+
function Fe(e) {
|
|
1699
1709
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
1700
1710
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
1701
1711
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -1754,8 +1764,8 @@ function Ne(e) {
|
|
|
1754
1764
|
}
|
|
1755
1765
|
//#endregion
|
|
1756
1766
|
//#region src/embed/page.ts
|
|
1757
|
-
var
|
|
1758
|
-
function
|
|
1767
|
+
var Ie = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
1768
|
+
function Le() {
|
|
1759
1769
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
1760
1770
|
if (e) return {
|
|
1761
1771
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -1777,9 +1787,9 @@ function Fe() {
|
|
|
1777
1787
|
waitForLive: !0
|
|
1778
1788
|
};
|
|
1779
1789
|
}
|
|
1780
|
-
async function
|
|
1781
|
-
let e =
|
|
1782
|
-
|
|
1790
|
+
async function Re() {
|
|
1791
|
+
let e = Le();
|
|
1792
|
+
Be();
|
|
1783
1793
|
let n = document.createElement("video");
|
|
1784
1794
|
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);
|
|
1785
1795
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
@@ -1834,7 +1844,7 @@ async function Ie() {
|
|
|
1834
1844
|
code: e.code,
|
|
1835
1845
|
message: e.message
|
|
1836
1846
|
})), e.on("autoplayblocked", () => {
|
|
1837
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
1847
|
+
i({ type: "oddin:autoplayblocked" }), ze(n, e);
|
|
1838
1848
|
});
|
|
1839
1849
|
}, s = async (r) => {
|
|
1840
1850
|
a?.destroy(), a = null;
|
|
@@ -1900,7 +1910,7 @@ async function Ie() {
|
|
|
1900
1910
|
a?.retry();
|
|
1901
1911
|
break;
|
|
1902
1912
|
case "oddin:load":
|
|
1903
|
-
typeof e.matchUrn == "string" &&
|
|
1913
|
+
typeof e.matchUrn == "string" && Ie.test(e.matchUrn) && s(e.matchUrn);
|
|
1904
1914
|
break;
|
|
1905
1915
|
case "oddin:destroy":
|
|
1906
1916
|
c();
|
|
@@ -1914,18 +1924,18 @@ async function Ie() {
|
|
|
1914
1924
|
protocol: 1
|
|
1915
1925
|
});
|
|
1916
1926
|
}
|
|
1917
|
-
function
|
|
1927
|
+
function ze(e, t) {
|
|
1918
1928
|
if (document.getElementById("havik-tap")) return;
|
|
1919
1929
|
let n = document.createElement("button");
|
|
1920
1930
|
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", () => {
|
|
1921
1931
|
n.remove(), t.play();
|
|
1922
1932
|
}), document.body.appendChild(n);
|
|
1923
1933
|
}
|
|
1924
|
-
function
|
|
1934
|
+
function Be() {
|
|
1925
1935
|
let e = document.createElement("style");
|
|
1926
1936
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
1927
1937
|
}
|
|
1928
1938
|
//#endregion
|
|
1929
|
-
export { G as ODDIN_THEME, t as PlaybackError, q as applyTheme,
|
|
1939
|
+
export { G as ODDIN_THEME, t as PlaybackError, q as applyTheme, Re as bootEmbed, k as clearDeviceId, Q as createPlayer, T as deriveEventsBaseUrl, oe as fetchCatalog, ce as fetchTournament, ue as flattenMatches, O as getDeviceId, N as isLowLatencyManifest, $ as isOddinMessage, j as licenseRequestHeaders, Fe as mountEmbed, y as pollToLive, x as resolveStream, w as subscribeLiveState, C as watchStatus };
|
|
1930
1940
|
|
|
1931
1941
|
//# sourceMappingURL=index.js.map
|