@oddin-gg/havik-player 1.0.5 → 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 +66 -60
- 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,21 +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
|
-
function
|
|
523
|
+
function ge(e, t) {
|
|
524
524
|
let n = (e, t, n) => Math.min(n, Math.max(t, e));
|
|
525
525
|
e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
|
|
526
526
|
}
|
|
527
|
-
var
|
|
527
|
+
var _e = class {
|
|
528
528
|
name = "hls";
|
|
529
529
|
hls = null;
|
|
530
530
|
deps;
|
|
@@ -537,6 +537,7 @@ var ge = class {
|
|
|
537
537
|
networkRetryTimer = null;
|
|
538
538
|
licenseRetryTimer = null;
|
|
539
539
|
onVisibility = null;
|
|
540
|
+
onSeeking = null;
|
|
540
541
|
sawLive = !1;
|
|
541
542
|
lastEndSN = -1;
|
|
542
543
|
lastAdvanceMs = 0;
|
|
@@ -565,7 +566,15 @@ var ge = class {
|
|
|
565
566
|
if (typeof t != "number") return;
|
|
566
567
|
let n = typeof e.targetLatency == "number" && e.targetLatency > 0 ? e.targetLatency : 3;
|
|
567
568
|
t - r.currentTime > Math.max(n * 3, 8) && (r.currentTime = t);
|
|
568
|
-
}, 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);
|
|
569
578
|
}
|
|
570
579
|
startHls() {
|
|
571
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 = {
|
|
@@ -591,7 +600,7 @@ var ge = class {
|
|
|
591
600
|
} : {},
|
|
592
601
|
...s
|
|
593
602
|
};
|
|
594
|
-
|
|
603
|
+
he(u);
|
|
595
604
|
let d = new e(u);
|
|
596
605
|
this.hls = d, d.on(e.Events.MANIFEST_PARSED, () => {
|
|
597
606
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, c({ type: "ready" });
|
|
@@ -731,7 +740,7 @@ var ge = class {
|
|
|
731
740
|
} catch {}
|
|
732
741
|
}
|
|
733
742
|
destroy() {
|
|
734
|
-
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) {
|
|
735
744
|
try {
|
|
736
745
|
this.hls.destroy();
|
|
737
746
|
} catch (e) {
|
|
@@ -815,7 +824,7 @@ var ge = class {
|
|
|
815
824
|
};
|
|
816
825
|
//#endregion
|
|
817
826
|
//#region src/core/engine/native.ts
|
|
818
|
-
function
|
|
827
|
+
function ve(e) {
|
|
819
828
|
return !!(e ?? (typeof document < "u" ? document.createElement("video") : void 0))?.canPlayType("application/vnd.apple.mpegurl");
|
|
820
829
|
}
|
|
821
830
|
var W = class {
|
|
@@ -946,15 +955,15 @@ function q(e, t) {
|
|
|
946
955
|
}
|
|
947
956
|
//#endregion
|
|
948
957
|
//#region src/ui/styles.ts
|
|
949
|
-
var J = "havik-player-styles",
|
|
950
|
-
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) {
|
|
951
960
|
if (e.getElementById(J)) return;
|
|
952
961
|
let t = e.createElement("style");
|
|
953
|
-
t.id = J, t.textContent =
|
|
962
|
+
t.id = J, t.textContent = ye, e.head.appendChild(t);
|
|
954
963
|
}
|
|
955
964
|
//#endregion
|
|
956
965
|
//#region src/ui/icons.ts
|
|
957
|
-
var
|
|
966
|
+
var xe = {
|
|
958
967
|
play: "<path d=\"M8 5v14l11-7z\"/>",
|
|
959
968
|
pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
|
|
960
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\"/>",
|
|
@@ -968,20 +977,20 @@ var be = {
|
|
|
968
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\"/>"
|
|
969
978
|
};
|
|
970
979
|
function Y(e) {
|
|
971
|
-
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>`;
|
|
972
981
|
}
|
|
973
982
|
//#endregion
|
|
974
983
|
//#region src/ui/controls.ts
|
|
975
|
-
var
|
|
984
|
+
var Se = 3e3, Ce = /* @__PURE__ */ new Set([
|
|
976
985
|
"GONE",
|
|
977
986
|
"NOT_FOUND",
|
|
978
987
|
"INVALID_URN",
|
|
979
988
|
"UNAUTHORIZED"
|
|
980
989
|
]);
|
|
981
|
-
function
|
|
982
|
-
return new
|
|
990
|
+
function we(e) {
|
|
991
|
+
return new Te(e);
|
|
983
992
|
}
|
|
984
|
-
var
|
|
993
|
+
var Te = class {
|
|
985
994
|
root;
|
|
986
995
|
video;
|
|
987
996
|
player;
|
|
@@ -1021,7 +1030,7 @@ var we = class {
|
|
|
1021
1030
|
scrubbing = !1;
|
|
1022
1031
|
offFns = [];
|
|
1023
1032
|
constructor(e) {
|
|
1024
|
-
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");
|
|
1025
1034
|
let t = (e, t, n) => {
|
|
1026
1035
|
let r = this.doc.createElement(e);
|
|
1027
1036
|
if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
|
|
@@ -1108,7 +1117,7 @@ var we = class {
|
|
|
1108
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);
|
|
1109
1118
|
} else {
|
|
1110
1119
|
let n = this.doc.createElement("div");
|
|
1111
|
-
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)) {
|
|
1112
1121
|
let e = this.doc.createElement("button");
|
|
1113
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);
|
|
1114
1123
|
}
|
|
@@ -1120,17 +1129,14 @@ var we = class {
|
|
|
1120
1129
|
this.setIcon(this.muteBtn, t ? "volumeMute" : "volumeHigh"), this.muteBtn.setAttribute("aria-label", t ? "Unmute" : "Mute"), this.volSlider.value = String(t ? 0 : e.volume);
|
|
1121
1130
|
}
|
|
1122
1131
|
seekableRange() {
|
|
1123
|
-
let e = this.video;
|
|
1124
|
-
if (e.seekable && e.seekable.length > 0)
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
return Number.isFinite(e.duration) && e.duration > 0 ? {
|
|
1132
|
-
start: 0,
|
|
1133
|
-
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
|
|
1134
1140
|
} : null;
|
|
1135
1141
|
}
|
|
1136
1142
|
syncProgress() {
|
|
@@ -1197,17 +1203,17 @@ var we = class {
|
|
|
1197
1203
|
renderQualityMenu() {
|
|
1198
1204
|
let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
|
|
1199
1205
|
n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
|
|
1200
|
-
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)));
|
|
1201
1207
|
}
|
|
1202
1208
|
renderAudioMenu() {
|
|
1203
1209
|
let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
|
|
1204
1210
|
t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
|
|
1205
|
-
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)));
|
|
1206
1212
|
}
|
|
1207
1213
|
renderCcMenu() {
|
|
1208
1214
|
let e = this.player.getTextTracks(), t = this.doc.createElement("div");
|
|
1209
1215
|
t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
|
|
1210
|
-
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)));
|
|
1211
1217
|
}
|
|
1212
1218
|
onTracksChanged() {
|
|
1213
1219
|
this.openMenu && this.renderMenu(this.openMenu);
|
|
@@ -1313,27 +1319,27 @@ function X(e) {
|
|
|
1313
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");
|
|
1314
1320
|
return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
|
|
1315
1321
|
}
|
|
1316
|
-
function
|
|
1322
|
+
function Ee(e) {
|
|
1317
1323
|
return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
|
|
1318
1324
|
}
|
|
1319
|
-
function
|
|
1325
|
+
function De(e) {
|
|
1320
1326
|
return e.name || e.lang || `Track ${e.id}`;
|
|
1321
1327
|
}
|
|
1322
|
-
function
|
|
1328
|
+
function Oe(e) {
|
|
1323
1329
|
return e.name || e.lang || `Track ${e.id}`;
|
|
1324
1330
|
}
|
|
1325
1331
|
//#endregion
|
|
1326
1332
|
//#region src/managed/index.ts
|
|
1327
|
-
var
|
|
1333
|
+
var ke = 6e3, Z = 45e3, Ae = 2e3, je = 3, Me = 2e3, Ne = 480 * 1e3;
|
|
1328
1334
|
async function Q(e) {
|
|
1329
1335
|
if (!e.video || typeof e.video.play != "function") throw new t("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
1330
1336
|
if (!e.baseUrl) throw new t("INTERNAL", 0, "createPlayer: baseUrl is required");
|
|
1331
1337
|
if (!e.matchUrn) throw new t("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
1332
1338
|
if (!e.credential) throw new t("INTERNAL", 0, "createPlayer: credential is required");
|
|
1333
|
-
let n = new
|
|
1339
|
+
let n = new Pe(e);
|
|
1334
1340
|
return await n.start(), n;
|
|
1335
1341
|
}
|
|
1336
|
-
var
|
|
1342
|
+
var Pe = class {
|
|
1337
1343
|
opts;
|
|
1338
1344
|
abort = new AbortController();
|
|
1339
1345
|
listeners = {};
|
|
@@ -1412,13 +1418,13 @@ var Ne = class {
|
|
|
1412
1418
|
!r && !s() && l();
|
|
1413
1419
|
}, e);
|
|
1414
1420
|
};
|
|
1415
|
-
d(
|
|
1421
|
+
d(ke), this.armingSub = w({
|
|
1416
1422
|
eventsBaseUrl: n,
|
|
1417
1423
|
matchUrn: this.opts.matchUrn,
|
|
1418
1424
|
credential: this.opts.credential,
|
|
1419
|
-
onAlive: () => d(
|
|
1425
|
+
onAlive: () => d(Z),
|
|
1420
1426
|
onState: (e) => {
|
|
1421
|
-
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);
|
|
1422
1428
|
},
|
|
1423
1429
|
onError: () => l()
|
|
1424
1430
|
});
|
|
@@ -1463,8 +1469,8 @@ var Ne = class {
|
|
|
1463
1469
|
emit: (e) => this.onEngineEvent(e)
|
|
1464
1470
|
}, a = this.opts.engine ?? "auto";
|
|
1465
1471
|
if (a === "native") return new W(i);
|
|
1466
|
-
if (a === "hls" || L()) return new
|
|
1467
|
-
if (
|
|
1472
|
+
if (a === "hls" || L()) return new _e(i);
|
|
1473
|
+
if (ve(this.opts.video)) return new W(i);
|
|
1468
1474
|
throw new t("INTERNAL", 0, "no supported HLS playback engine in this browser");
|
|
1469
1475
|
}
|
|
1470
1476
|
onEngineEvent(e) {
|
|
@@ -1509,7 +1515,7 @@ var Ne = class {
|
|
|
1509
1515
|
r = 0, i = !1;
|
|
1510
1516
|
},
|
|
1511
1517
|
onError: () => {
|
|
1512
|
-
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.`))));
|
|
1513
1519
|
}
|
|
1514
1520
|
});
|
|
1515
1521
|
}
|
|
@@ -1531,7 +1537,7 @@ var Ne = class {
|
|
|
1531
1537
|
}
|
|
1532
1538
|
t.controls = !1;
|
|
1533
1539
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
1534
|
-
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({
|
|
1535
1541
|
root: n,
|
|
1536
1542
|
video: t,
|
|
1537
1543
|
player: this,
|
|
@@ -1554,7 +1560,7 @@ var Ne = class {
|
|
|
1554
1560
|
}
|
|
1555
1561
|
startStats() {
|
|
1556
1562
|
this.stopStats();
|
|
1557
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
1563
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? Me);
|
|
1558
1564
|
this.statsTimer = setInterval(() => {
|
|
1559
1565
|
this.engine && this.emit("stats", this.engine.getStats());
|
|
1560
1566
|
}, e);
|
|
@@ -1564,7 +1570,7 @@ var Ne = class {
|
|
|
1564
1570
|
}
|
|
1565
1571
|
scheduleLicenseRefresh() {
|
|
1566
1572
|
this.stopRefresh();
|
|
1567
|
-
let e = this.opts.licenseRefreshMs ??
|
|
1573
|
+
let e = this.opts.licenseRefreshMs ?? Ne;
|
|
1568
1574
|
!e || !this._descriptor?.drmEnabled || (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
1569
1575
|
}
|
|
1570
1576
|
stopRefresh() {
|
|
@@ -1699,7 +1705,7 @@ function $(e) {
|
|
|
1699
1705
|
}
|
|
1700
1706
|
//#endregion
|
|
1701
1707
|
//#region src/embed/host.ts
|
|
1702
|
-
function
|
|
1708
|
+
function Fe(e) {
|
|
1703
1709
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
1704
1710
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
1705
1711
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -1758,8 +1764,8 @@ function Pe(e) {
|
|
|
1758
1764
|
}
|
|
1759
1765
|
//#endregion
|
|
1760
1766
|
//#region src/embed/page.ts
|
|
1761
|
-
var
|
|
1762
|
-
function
|
|
1767
|
+
var Ie = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
1768
|
+
function Le() {
|
|
1763
1769
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
1764
1770
|
if (e) return {
|
|
1765
1771
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -1781,9 +1787,9 @@ function Ie() {
|
|
|
1781
1787
|
waitForLive: !0
|
|
1782
1788
|
};
|
|
1783
1789
|
}
|
|
1784
|
-
async function
|
|
1785
|
-
let e =
|
|
1786
|
-
|
|
1790
|
+
async function Re() {
|
|
1791
|
+
let e = Le();
|
|
1792
|
+
Be();
|
|
1787
1793
|
let n = document.createElement("video");
|
|
1788
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);
|
|
1789
1795
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
@@ -1838,7 +1844,7 @@ async function Le() {
|
|
|
1838
1844
|
code: e.code,
|
|
1839
1845
|
message: e.message
|
|
1840
1846
|
})), e.on("autoplayblocked", () => {
|
|
1841
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
1847
|
+
i({ type: "oddin:autoplayblocked" }), ze(n, e);
|
|
1842
1848
|
});
|
|
1843
1849
|
}, s = async (r) => {
|
|
1844
1850
|
a?.destroy(), a = null;
|
|
@@ -1904,7 +1910,7 @@ async function Le() {
|
|
|
1904
1910
|
a?.retry();
|
|
1905
1911
|
break;
|
|
1906
1912
|
case "oddin:load":
|
|
1907
|
-
typeof e.matchUrn == "string" &&
|
|
1913
|
+
typeof e.matchUrn == "string" && Ie.test(e.matchUrn) && s(e.matchUrn);
|
|
1908
1914
|
break;
|
|
1909
1915
|
case "oddin:destroy":
|
|
1910
1916
|
c();
|
|
@@ -1918,18 +1924,18 @@ async function Le() {
|
|
|
1918
1924
|
protocol: 1
|
|
1919
1925
|
});
|
|
1920
1926
|
}
|
|
1921
|
-
function
|
|
1927
|
+
function ze(e, t) {
|
|
1922
1928
|
if (document.getElementById("havik-tap")) return;
|
|
1923
1929
|
let n = document.createElement("button");
|
|
1924
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", () => {
|
|
1925
1931
|
n.remove(), t.play();
|
|
1926
1932
|
}), document.body.appendChild(n);
|
|
1927
1933
|
}
|
|
1928
|
-
function
|
|
1934
|
+
function Be() {
|
|
1929
1935
|
let e = document.createElement("style");
|
|
1930
1936
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
1931
1937
|
}
|
|
1932
1938
|
//#endregion
|
|
1933
|
-
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 };
|
|
1934
1940
|
|
|
1935
1941
|
//# sourceMappingURL=index.js.map
|