@oddin-gg/havik-player 2.28.0 → 2.28.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 +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +196 -186
- package/dist/index.js.map +1 -1
- package/docs/API.md +9 -0
- package/embed/index.html +1 -1
- package/examples/vanilla.html +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1627,12 +1627,12 @@ function K(e, t) {
|
|
|
1627
1627
|
function Xt() {
|
|
1628
1628
|
return e.isSupported();
|
|
1629
1629
|
}
|
|
1630
|
-
var Zt = 3, Qt = 1e6, $t = 20, en = 1e4, tn = 3, nn =
|
|
1631
|
-
function
|
|
1630
|
+
var Zt = 3, Qt = 1e6, $t = 20, en = 1e4, tn = 3, nn = 2, rn = 5, an = 3, on = 1e4, sn = 3e4, cn = 12e3, ln = 3e3, un = .02, dn = 6e3, fn = .5, pn = 3, mn = .5, hn = 1.1, gn = .25, _n = 5e3, vn = 4e3, yn = 2, bn = 5, xn = 2, Sn = 2, Cn = 4, wn = 4, Tn = 2e3, En = 3e4, Dn = 1, On = 2, kn = .5, An = .6, jn = 2, Mn = 1.5, Nn = 1e4, Pn = 18e4, Fn = .5, In = 2;
|
|
1631
|
+
function Ln(e) {
|
|
1632
1632
|
let t = e.config ?? {};
|
|
1633
1633
|
return t.capLevelToPlayerSize === !0 || t.capLevelOnFPSDrop === !0;
|
|
1634
1634
|
}
|
|
1635
|
-
var q = 8,
|
|
1635
|
+
var q = 8, Rn = 12e4, zn = 6e4;
|
|
1636
1636
|
function J(e, t, n) {
|
|
1637
1637
|
if (n <= 0 || t < 0 || t >= e.length) return t;
|
|
1638
1638
|
let r = (t, n) => e[t].width === e[n].width && e[t].height === e[n].height, i = (t) => {
|
|
@@ -1645,11 +1645,11 @@ function J(e, t, n) {
|
|
|
1645
1645
|
function Y() {
|
|
1646
1646
|
return typeof self < "u" && self.devicePixelRatio > 0 ? self.devicePixelRatio : 1;
|
|
1647
1647
|
}
|
|
1648
|
-
var
|
|
1649
|
-
function
|
|
1648
|
+
var Bn = .2, Vn = 30, Hn = 2, Un = 2, Wn = 2, Gn = 9, Kn = .5, qn = 64, Jn = 1e4, Yn = 8, Xn = .6, Zn = .4, Qn = .4, $n = 2, er = 6e4, X = .5, tr = 3.5, nr = 300;
|
|
1649
|
+
function rr(e) {
|
|
1650
1650
|
return (e?.part ?? e?.frag)?.stats;
|
|
1651
1651
|
}
|
|
1652
|
-
function
|
|
1652
|
+
function ir() {
|
|
1653
1653
|
if (typeof navigator > "u") return 0;
|
|
1654
1654
|
try {
|
|
1655
1655
|
let e = navigator.connection?.rtt;
|
|
@@ -1658,20 +1658,20 @@ function rr() {
|
|
|
1658
1658
|
return 0;
|
|
1659
1659
|
}
|
|
1660
1660
|
}
|
|
1661
|
-
function
|
|
1661
|
+
function ar(e) {
|
|
1662
1662
|
if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
|
|
1663
1663
|
delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
|
|
1664
1664
|
return;
|
|
1665
1665
|
}
|
|
1666
|
-
e.liveSyncDuration ??=
|
|
1667
|
-
let t = Math.max(12, e.liveSyncDuration +
|
|
1668
|
-
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t),
|
|
1666
|
+
e.liveSyncDuration ??= Wn;
|
|
1667
|
+
let t = Math.max(12, e.liveSyncDuration + Gn);
|
|
1668
|
+
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), or(e, e.liveSyncDuration);
|
|
1669
1669
|
}
|
|
1670
|
-
function
|
|
1670
|
+
function or(e, t) {
|
|
1671
1671
|
let n = (e, t, n) => Math.min(n, Math.max(t, e));
|
|
1672
1672
|
e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
|
|
1673
1673
|
}
|
|
1674
|
-
var
|
|
1674
|
+
var sr = class {
|
|
1675
1675
|
name = "hls";
|
|
1676
1676
|
hls = null;
|
|
1677
1677
|
deps;
|
|
@@ -1696,6 +1696,7 @@ var or = class {
|
|
|
1696
1696
|
ladderHeights;
|
|
1697
1697
|
ladderTopBitrateKbps = 0;
|
|
1698
1698
|
mediaRecoveries = 0;
|
|
1699
|
+
holeKicks = 0;
|
|
1699
1700
|
networkRecoveries = 0;
|
|
1700
1701
|
licenseRecoveries = 0;
|
|
1701
1702
|
recoveryResetTimer = null;
|
|
@@ -1824,7 +1825,7 @@ var or = class {
|
|
|
1824
1825
|
}
|
|
1825
1826
|
this.loadSuspended = !0;
|
|
1826
1827
|
}
|
|
1827
|
-
},
|
|
1828
|
+
}, _n));
|
|
1828
1829
|
}
|
|
1829
1830
|
resumeLoading() {
|
|
1830
1831
|
if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
|
|
@@ -1856,7 +1857,7 @@ var or = class {
|
|
|
1856
1857
|
let t = e.liveSyncPosition;
|
|
1857
1858
|
if (typeof t != "number" || !Number.isFinite(t)) return;
|
|
1858
1859
|
let { video: n } = this.deps;
|
|
1859
|
-
n.currentTime <= t +
|
|
1860
|
+
n.currentTime <= t + Kn || (n.currentTime = t);
|
|
1860
1861
|
}
|
|
1861
1862
|
reanchorPartTimeline(e, t) {
|
|
1862
1863
|
let { frag: n, part: r } = t;
|
|
@@ -1868,7 +1869,7 @@ var or = class {
|
|
|
1868
1869
|
let o = n.sn, s = i.fragments.find((e) => e && e.sn === o) ?? (i.fragmentHint?.sn === o ? i.fragmentHint : void 0);
|
|
1869
1870
|
if (!s) return;
|
|
1870
1871
|
let c = a.startPTS - s.start;
|
|
1871
|
-
if (!(!Number.isFinite(c) || Math.abs(c) <
|
|
1872
|
+
if (!(!Number.isFinite(c) || Math.abs(c) < un)) {
|
|
1872
1873
|
for (let e of i.fragments) e && e.setStart(e.start + c);
|
|
1873
1874
|
i.fragmentHint?.setStart(i.fragmentHint.start + c), this.deps.debug === !0 && console.info(`havik-player: LL-HLS timeline re-anchored by ${c >= 0 ? "+" : ""}${c.toFixed(3)}s at sn ${n.sn} (level ${n.level})`);
|
|
1874
1875
|
}
|
|
@@ -1908,7 +1909,7 @@ var or = class {
|
|
|
1908
1909
|
return;
|
|
1909
1910
|
}
|
|
1910
1911
|
let l = this.hls, u, d = new Promise((e) => {
|
|
1911
|
-
u = setTimeout(() => e(void 0),
|
|
1912
|
+
u = setTimeout(() => e(void 0), on);
|
|
1912
1913
|
});
|
|
1913
1914
|
return Promise.race([c().catch(() => void 0), d]).finally(() => clearTimeout(u)).then((e) => {
|
|
1914
1915
|
if (!this.hls || this.hls !== l) throw Error("havik-player: engine torn down during refresh");
|
|
@@ -1932,22 +1933,22 @@ var or = class {
|
|
|
1932
1933
|
}), t = Gt(e, f.loader);
|
|
1933
1934
|
t && (this.prefetch = e, p = h, m = g, f.fLoader = t);
|
|
1934
1935
|
}
|
|
1935
|
-
|
|
1936
|
+
ar(f), this.catchUpRate = typeof f.maxLiveSyncPlaybackRate == "number" ? f.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (f.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = f.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = f.autoStartLoad !== !1;
|
|
1936
1937
|
let _ = new e(f);
|
|
1937
1938
|
if (this.hls = _, this.armHoldBack(_, f), _.on(e.Events.FRAG_PARSED, (e, t) => this.reanchorPartTimeline(_, t)), _.on(e.Events.MANIFEST_PARSED, () => {
|
|
1938
1939
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, u && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && this.dropLevelsWidevineCannotPlay(_), this.measureLadder(_), this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
|
|
1939
1940
|
}), _.on(e.Events.FRAG_BUFFERED, (e, t) => {
|
|
1940
|
-
t?.frag?.type === "main" && (this.kickKind !== "dead" && this.clearKick(), (this.mediaRecoveries > 0 || this.networkRecoveries > 0 || this.licenseRecoveries > 0 || this.starvationKicks > 0 || this.starvationRebuilds > 0) && !this.recoveryResetTimer && (this.recoveryResetTimer = setTimeout(() => {
|
|
1941
|
-
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
|
|
1942
|
-
},
|
|
1941
|
+
t?.frag?.type === "main" && (this.kickKind !== "dead" && this.clearKick(), (this.mediaRecoveries > 0 || this.networkRecoveries > 0 || this.licenseRecoveries > 0 || this.starvationKicks > 0 || this.starvationRebuilds > 0 || this.holeKicks > 0) && !this.recoveryResetTimer && (this.recoveryResetTimer = setTimeout(() => {
|
|
1942
|
+
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.holeKicks = 0, this.recoveryResetTimer = null;
|
|
1943
|
+
}, sn)));
|
|
1943
1944
|
}), _.on(e.Events.FRAG_LOADING, (e, t) => {
|
|
1944
1945
|
t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
|
|
1945
1946
|
}), _.on(e.Events.FRAG_LOADED, (e, t) => {
|
|
1946
1947
|
t?.frag?.type === "main" && (this.mainFragsSinceTick += 1, this.bwFragsLoaded += 1, this.maybeRememberBandwidth(!1));
|
|
1947
|
-
let n = t?.frag, r =
|
|
1948
|
+
let n = t?.frag, r = rr(t), i = r?.loaded;
|
|
1948
1949
|
typeof i == "number" && (this.bytesLoaded += i), !this.reportedFirstBytes && typeof i == "number" && i > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
|
|
1949
1950
|
let a = r?.loading;
|
|
1950
|
-
a && a.end > 0 && a.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(a.end - a.start))), this.requestTimesMs.length >
|
|
1951
|
+
a && a.end > 0 && a.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(a.end - a.start))), this.requestTimesMs.length > qn && this.requestTimesMs.shift()), this.sampleHoldBack(t), this.sampleHeadroom(t);
|
|
1951
1952
|
let o = n?.url;
|
|
1952
1953
|
if (o) {
|
|
1953
1954
|
let e = ft(o);
|
|
@@ -1988,7 +1989,7 @@ var or = class {
|
|
|
1988
1989
|
u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
|
|
1989
1990
|
}), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
|
|
1990
1991
|
this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.adaptHoldBack(), this.reviewSizeCapHeadroom(), this.releaseStallCap(), this.checkFrameDrops();
|
|
1991
|
-
},
|
|
1992
|
+
}, ln), _.on(e.Events.LEVEL_SWITCHED, (e, t) => {
|
|
1992
1993
|
this.renditionSwitches += 1;
|
|
1993
1994
|
let n = this.lastLevelIndex >= 0 ? _.levels[this.lastLevelIndex] : void 0, r = _.levels[t.level];
|
|
1994
1995
|
n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, this.armFrameDropGrace(), l({
|
|
@@ -2049,8 +2050,8 @@ var or = class {
|
|
|
2049
2050
|
let e = this.hls, t = this.sizeCapCover();
|
|
2050
2051
|
if (!e || !t) return null;
|
|
2051
2052
|
let { cover: n, deviceRatio: r } = t, i = this.deps.sizeCapHeadroom, a = i == null || Number.isNaN(i);
|
|
2052
|
-
if (a && r >=
|
|
2053
|
-
if (a) return this.headroomUngated || this.headroomGranted ? J(e.levels, n,
|
|
2053
|
+
if (a && r >= On) return n;
|
|
2054
|
+
if (a) return this.headroomUngated || this.headroomGranted ? J(e.levels, n, Dn) : n;
|
|
2054
2055
|
let o = i === Infinity ? e.levels.length : Math.max(0, Math.floor(i));
|
|
2055
2056
|
return J(e.levels, n, o);
|
|
2056
2057
|
}
|
|
@@ -2067,11 +2068,11 @@ var or = class {
|
|
|
2067
2068
|
return;
|
|
2068
2069
|
}
|
|
2069
2070
|
this.capTimer && clearTimeout(this.capTimer);
|
|
2070
|
-
let t = e > this.sizeCapLevel ?
|
|
2071
|
+
let t = e > this.sizeCapLevel ? Tn : En;
|
|
2071
2072
|
this.capTimer = setTimeout(() => {
|
|
2072
2073
|
this.capTimer = null;
|
|
2073
2074
|
let n = this.computeSizeCapTarget();
|
|
2074
|
-
n === e || t ===
|
|
2075
|
+
n === e || t === En && n != null && n < e ? this.applySizeCap() : this.onMediaResize();
|
|
2075
2076
|
}, t);
|
|
2076
2077
|
}
|
|
2077
2078
|
measureLadder(e) {
|
|
@@ -2098,7 +2099,7 @@ var or = class {
|
|
|
2098
2099
|
}
|
|
2099
2100
|
defaultHeadroomApplies() {
|
|
2100
2101
|
let e = this.deps.sizeCapHeadroom;
|
|
2101
|
-
return e != null && !Number.isNaN(e) || this.headroomUngated ? !1 : Y() <
|
|
2102
|
+
return e != null && !Number.isNaN(e) || this.headroomUngated ? !1 : Y() < On;
|
|
2102
2103
|
}
|
|
2103
2104
|
applySizeCapUnlessPending() {
|
|
2104
2105
|
this.capTimer || this.applySizeCap();
|
|
@@ -2107,7 +2108,7 @@ var or = class {
|
|
|
2107
2108
|
if (!this.sizeCapManaged || !this.defaultHeadroomApplies() || e.frag?.type !== "main" || typeof e.frag.level != "number" || typeof document < "u" && document.hidden) return;
|
|
2108
2109
|
let t = e.part ? e.part.duration : this.detectedLowLatency ? 0 : e.frag.duration;
|
|
2109
2110
|
if (typeof t != "number" || !(t > 0)) return;
|
|
2110
|
-
let n =
|
|
2111
|
+
let n = rr(e)?.loading;
|
|
2111
2112
|
if (!n || !(n.start > 0) || !(n.end >= n.start)) return;
|
|
2112
2113
|
let r = this.hls?.levels?.[e.frag.level]?.bitrate;
|
|
2113
2114
|
if (!(typeof r == "number" && r > 0)) return;
|
|
@@ -2120,7 +2121,7 @@ var or = class {
|
|
|
2120
2121
|
}
|
|
2121
2122
|
onPlaybackStall(e) {
|
|
2122
2123
|
let t = Date.now();
|
|
2123
|
-
this.deps.video.seeking || !this.playingSince || t - this.playingSince <
|
|
2124
|
+
this.deps.video.seeking || !this.playingSince || t - this.playingSince < Nn || (this.lastStallAt = t, this.stepStallCapDown(t, e), this.headroomGranted && (this.headroomGranted = !1, this.applySizeCapUnlessPending()));
|
|
2124
2125
|
}
|
|
2125
2126
|
stallCapLevel(e) {
|
|
2126
2127
|
if (this.stallCapBitrate == null) return -1;
|
|
@@ -2131,7 +2132,7 @@ var or = class {
|
|
|
2131
2132
|
}
|
|
2132
2133
|
stepStallCapDown(e, t) {
|
|
2133
2134
|
let n = this.hls;
|
|
2134
|
-
if (!n || !this.stallCapEnabled ||
|
|
2135
|
+
if (!n || !this.stallCapEnabled || Ln(n) || !n.autoLevelEnabled || typeof t == "number" && t >= Fn || this.isLiveEdgeWait(n, t ?? 0)) return;
|
|
2135
2136
|
this.stallCapBitrate != null && (this.stallCapSince = e);
|
|
2136
2137
|
let r = Math.max(n.levels[n.currentLevel]?.bitrate ?? 0, n.levels[n.loadLevel]?.bitrate ?? 0);
|
|
2137
2138
|
if (!(r > 0)) return;
|
|
@@ -2142,7 +2143,7 @@ var or = class {
|
|
|
2142
2143
|
let n = e.latestLevelDetails;
|
|
2143
2144
|
if (!n?.live) return !1;
|
|
2144
2145
|
let r = n.partTarget || n.targetduration;
|
|
2145
|
-
return !(r > 0) || !(n.edge > 0) ? !1 : n.edge - (this.deps.video.currentTime + t) <
|
|
2146
|
+
return !(r > 0) || !(n.edge > 0) ? !1 : n.edge - (this.deps.video.currentTime + t) < In * r;
|
|
2146
2147
|
}
|
|
2147
2148
|
releaseStallCap() {
|
|
2148
2149
|
let e = this.hls, t = Date.now(), n = this.stallCapTickAt;
|
|
@@ -2151,7 +2152,7 @@ var or = class {
|
|
|
2151
2152
|
n && (this.stallCapSince += t - Math.max(n, this.stallCapSince));
|
|
2152
2153
|
return;
|
|
2153
2154
|
}
|
|
2154
|
-
if (t - this.stallCapSince <
|
|
2155
|
+
if (t - this.stallCapSince < Pn) return;
|
|
2155
2156
|
let r = this.stallCapBitrate, i = e.levels.map((e) => e.bitrate).filter((e) => e > r).sort((e, t) => e - t)[0];
|
|
2156
2157
|
this.stallCapBitrate = i ?? null, this.stallCapSince = t, this.pushCap();
|
|
2157
2158
|
}
|
|
@@ -2164,26 +2165,26 @@ var or = class {
|
|
|
2164
2165
|
this.headroomGranted = !1, this.headroomSamples = [];
|
|
2165
2166
|
return;
|
|
2166
2167
|
}
|
|
2167
|
-
this.headroomSamples = this.headroomSamples.filter((t) => t.t >= e -
|
|
2168
|
+
this.headroomSamples = this.headroomSamples.filter((t) => t.t >= e - Jn);
|
|
2168
2169
|
let r = this.headroomEarned(n, e);
|
|
2169
|
-
r !== this.headroomGranted && (r || (this.headroomRegrantAt = e +
|
|
2170
|
+
r !== this.headroomGranted && (r || (this.headroomRegrantAt = e + zn), this.headroomGranted = r, this.applySizeCapUnlessPending());
|
|
2170
2171
|
}
|
|
2171
2172
|
headroomEarned(e, t) {
|
|
2172
|
-
if (t - this.lastStallAt <
|
|
2173
|
+
if (t - this.lastStallAt < Rn || !this.headroomGranted && t < this.headroomRegrantAt || !this.headroomGranted && this.headroomSamples.length < q) return !1;
|
|
2173
2174
|
let n = e.levels, r = this.sizeCapCoverLevel();
|
|
2174
2175
|
if (r == null) return this.headroomGranted;
|
|
2175
|
-
let i = J(n, r,
|
|
2176
|
+
let i = J(n, r, Dn);
|
|
2176
2177
|
if (i === r) return this.headroomGranted;
|
|
2177
|
-
let a = n[i]?.bitrate, o = e.bandwidthEstimate, s = this.headroomGranted ?
|
|
2178
|
+
let a = n[i]?.bitrate, o = e.bandwidthEstimate, s = this.headroomGranted ? Mn : jn;
|
|
2178
2179
|
if (!(a > 0) || !(o >= s * a)) return !1;
|
|
2179
2180
|
let c = (e) => K([...e].sort((e, t) => e - t), 90);
|
|
2180
2181
|
if (this.headroomGranted) {
|
|
2181
2182
|
let e = this.headroomSamples.filter((e) => e.bitrate >= a).map((e) => e.ratio);
|
|
2182
|
-
return e.length < q || c(e) <=
|
|
2183
|
+
return e.length < q || c(e) <= An;
|
|
2183
2184
|
}
|
|
2184
2185
|
let l = [];
|
|
2185
2186
|
for (let e of this.headroomSamples) e.bitrate < a && l.push(e.ratio * (a / e.bitrate));
|
|
2186
|
-
return l.length >= q && c(l) <=
|
|
2187
|
+
return l.length >= q && c(l) <= kn;
|
|
2187
2188
|
}
|
|
2188
2189
|
applySizeCap() {
|
|
2189
2190
|
if (!this.sizeCapManaged) return;
|
|
@@ -2258,7 +2259,7 @@ var or = class {
|
|
|
2258
2259
|
let t = e.currentLevel >= 0 ? e.levels[e.currentLevel] : void 0;
|
|
2259
2260
|
t && (n.levelHeight = t.height);
|
|
2260
2261
|
let r = e.autoLevelCapping, i = r >= 0 ? e.levels[r] : void 0;
|
|
2261
|
-
i && i.height > 0 && (n.maxLevelHeight = i.height, !
|
|
2262
|
+
i && i.height > 0 && (n.maxLevelHeight = i.height, !Ln(e) && r === this.pushedCapLevel && this.pushedCapReason && (n.capReason = this.pushedCapReason)), t?.videoCodec && (n.videoCodec = t.videoCodec), t?.audioCodec && (n.audioCodec = t.audioCodec), t && typeof t.bitrate == "number" && (n.renditionBitrateKbps = Math.round(t.bitrate / 1e3)), typeof t?.details?.live == "boolean" && (n.isLive = t.details.live, typeof e.liveSyncPosition == "number" && (n.atLiveEdge = this.deps.video.currentTime >= e.liveSyncPosition - 1.5));
|
|
2262
2263
|
}
|
|
2263
2264
|
return n;
|
|
2264
2265
|
}
|
|
@@ -2286,7 +2287,7 @@ var or = class {
|
|
|
2286
2287
|
return;
|
|
2287
2288
|
}
|
|
2288
2289
|
let e = Date.now() - this.lastAdvanceMs;
|
|
2289
|
-
!this.chaseSuspended && e >
|
|
2290
|
+
!this.chaseSuspended && e > dn && this.suspendChasing(), e > cn && this.emitEnded("stalled");
|
|
2290
2291
|
}
|
|
2291
2292
|
resetStarvationWindow() {
|
|
2292
2293
|
this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
|
|
@@ -2301,7 +2302,7 @@ var or = class {
|
|
|
2301
2302
|
this.resetStarvationWindow();
|
|
2302
2303
|
return;
|
|
2303
2304
|
}
|
|
2304
|
-
let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs <
|
|
2305
|
+
let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < dn, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > vn, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = R(t), c = o - s, l = c !== this.starvedFrames;
|
|
2305
2306
|
if (this.starvedFrames = c, !a || l) {
|
|
2306
2307
|
(t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
|
|
2307
2308
|
return;
|
|
@@ -2310,12 +2311,12 @@ var or = class {
|
|
|
2310
2311
|
this.resetStarvationWindow();
|
|
2311
2312
|
return;
|
|
2312
2313
|
}
|
|
2313
|
-
if (this.kickPending && (this.kickKind === "dead" || i) && (this.kickTicks += 1), this.starvedTicks = i ? this.starvedTicks + 1 : 0, this.deadTicks += 1, this.recentMainFrags.push(this.mainFragsSinceTick), this.mainFragsSinceTick = 0, this.recentMainFrags.length >
|
|
2314
|
+
if (this.kickPending && (this.kickKind === "dead" || i) && (this.kickTicks += 1), this.starvedTicks = i ? this.starvedTicks + 1 : 0, this.deadTicks += 1, this.recentMainFrags.push(this.mainFragsSinceTick), this.mainFragsSinceTick = 0, this.recentMainFrags.length > Cn && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= xn && (this.clearKick(), this.starvationRebuilds < Sn)) {
|
|
2314
2315
|
this.starvationRebuilds += 1, this.resetStarvationWindow(), this.clearRecoveryReset(), 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");
|
|
2315
2316
|
return;
|
|
2316
2317
|
}
|
|
2317
|
-
let u = i && this.starvedTicks >=
|
|
2318
|
-
if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >=
|
|
2318
|
+
let u = i && this.starvedTicks >= yn, d = !i && this.deadTicks >= Cn && this.recentMainFrags.reduce((e, t) => e + t, 0) >= wn;
|
|
2319
|
+
if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= bn))) {
|
|
2319
2320
|
this.starvationKicks += 1, this.kickPending = !0, this.kickTicks = 0, this.kickKind = d ? "dead" : "quiet", this.clearRecoveryReset(), console.warn(d ? "havik-player: video starved while hls.js keeps loading media it never plays (dead pipeline at the live edge) — restarting the load" : "havik-player: video starved while the live playlist advances (wedged hls.js fragment pipeline) — restarting the load");
|
|
2320
2321
|
try {
|
|
2321
2322
|
e.stopLoad(), e.startLoad(-1);
|
|
@@ -2330,7 +2331,7 @@ var or = class {
|
|
|
2330
2331
|
let t = e.latency, n = e.targetLatency;
|
|
2331
2332
|
if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
|
|
2332
2333
|
let r = t - n;
|
|
2333
|
-
!this.catchUpEngaged && r >
|
|
2334
|
+
!this.catchUpEngaged && r > fn ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= fn && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
|
|
2334
2335
|
let i = this.catchUpEngaged ? this.catchUpRate : 1;
|
|
2335
2336
|
e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
|
|
2336
2337
|
}
|
|
@@ -2343,7 +2344,7 @@ var or = class {
|
|
|
2343
2344
|
}), n < 0 ? 0 : n;
|
|
2344
2345
|
}
|
|
2345
2346
|
armFrameDropGrace() {
|
|
2346
|
-
this.fpsGraceTicks > 0 || (this.fpsGraceTicks =
|
|
2347
|
+
this.fpsGraceTicks > 0 || (this.fpsGraceTicks = Un, this.fpsBadTicks = 0);
|
|
2347
2348
|
}
|
|
2348
2349
|
resetFrameDropWindow() {
|
|
2349
2350
|
this.fpsLastFrames = -1, this.fpsLastDropped = -1, this.fpsBadTicks = 0;
|
|
@@ -2355,7 +2356,7 @@ var or = class {
|
|
|
2355
2356
|
return;
|
|
2356
2357
|
}
|
|
2357
2358
|
let { totalFrames: n, dropped: r } = R(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
|
|
2358
|
-
if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a <
|
|
2359
|
+
if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < Vn || o < 0) {
|
|
2359
2360
|
this.fpsBadTicks = 0;
|
|
2360
2361
|
return;
|
|
2361
2362
|
}
|
|
@@ -2363,11 +2364,11 @@ var or = class {
|
|
|
2363
2364
|
--this.fpsGraceTicks, this.fpsBadTicks = 0;
|
|
2364
2365
|
return;
|
|
2365
2366
|
}
|
|
2366
|
-
if (o <=
|
|
2367
|
+
if (o <= Bn * a) {
|
|
2367
2368
|
this.fpsBadTicks = 0;
|
|
2368
2369
|
return;
|
|
2369
2370
|
}
|
|
2370
|
-
if (this.fpsBadTicks += 1, this.fpsBadTicks <
|
|
2371
|
+
if (this.fpsBadTicks += 1, this.fpsBadTicks < Hn) return;
|
|
2371
2372
|
this.fpsBadTicks = 0;
|
|
2372
2373
|
let s = e.levels, c = s[e.currentLevel];
|
|
2373
2374
|
if (!c) return;
|
|
@@ -2384,22 +2385,22 @@ var or = class {
|
|
|
2384
2385
|
return;
|
|
2385
2386
|
}
|
|
2386
2387
|
let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
|
|
2387
|
-
if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(
|
|
2388
|
+
if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(hn, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
|
|
2388
2389
|
this.resetChaseWindow();
|
|
2389
2390
|
return;
|
|
2390
2391
|
}
|
|
2391
|
-
if (this.chaseLatency < 0 || this.chaseLatency - n >=
|
|
2392
|
+
if (this.chaseLatency < 0 || this.chaseLatency - n >= mn) {
|
|
2392
2393
|
this.chaseLatency = n, this.chaseTicks = 0;
|
|
2393
2394
|
return;
|
|
2394
2395
|
}
|
|
2395
|
-
if (this.chaseTicks += 1, this.chaseTicks <
|
|
2396
|
+
if (this.chaseTicks += 1, this.chaseTicks < pn) return;
|
|
2396
2397
|
this.resetChaseWindow();
|
|
2397
2398
|
let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
|
|
2398
2399
|
if (!(a > 1)) return;
|
|
2399
2400
|
let o = e.targetLatency;
|
|
2400
2401
|
if (typeof o != "number" || !(o > 0)) return;
|
|
2401
2402
|
let s = Math.min(n, a - 1);
|
|
2402
|
-
s < o +
|
|
2403
|
+
s < o + gn || (console.warn(`havik-player: catch-up at ${r}x not gaining on the live edge (latency ${n.toFixed(1)}s); holding at ${s.toFixed(1)}s`), this.liveRetargets += 1, e.targetLatency = s, this.deps.emit({
|
|
2403
2404
|
type: "livetargetchange",
|
|
2404
2405
|
change: {
|
|
2405
2406
|
targetSeconds: s,
|
|
@@ -2416,13 +2417,13 @@ var or = class {
|
|
|
2416
2417
|
if (!this.holdBackEnabled || this.holdBackPriorChecked || !e || (this.holdBackPriorChecked = !0, this.holdBackApplied > 0 || this.holdBackStepCount > 0)) return;
|
|
2417
2418
|
let t = e.targetLatency;
|
|
2418
2419
|
if (this.holdBackBase < 0 && typeof t == "number" && t > 0 && (this.holdBackBase = t), this.holdBackBase < 0) return;
|
|
2419
|
-
let n =
|
|
2420
|
-
if (!(n >=
|
|
2420
|
+
let n = ir();
|
|
2421
|
+
if (!(n >= nr)) return;
|
|
2421
2422
|
let r = typeof t == "number" && t > 0 ? t : this.holdBackBase, i = Math.min(this.holdBackCeiling(e), this.holdBackBase + X);
|
|
2422
2423
|
i > r && (this.holdBackStepCount = 1, this.moveHoldBack(e, r, i, "connection-rtt", `connection rtt ${n} ms`));
|
|
2423
2424
|
}
|
|
2424
2425
|
holdBackCeiling(e) {
|
|
2425
|
-
let t = this.deps.adaptiveHoldBackCeiling, n = typeof t == "number" && Number.isFinite(t) ? t :
|
|
2426
|
+
let t = this.deps.adaptiveHoldBackCeiling, n = typeof t == "number" && Number.isFinite(t) ? t : tr, r = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
|
|
2426
2427
|
return r > 1 ? Math.min(n, r - 1) : n;
|
|
2427
2428
|
}
|
|
2428
2429
|
sampleHoldBack(e) {
|
|
@@ -2431,7 +2432,7 @@ var or = class {
|
|
|
2431
2432
|
if (t !== "main" && t !== "audio") return;
|
|
2432
2433
|
let n = e.part ? e.part.duration : this.detectedLowLatency ? 0 : e.frag?.duration;
|
|
2433
2434
|
if (typeof n != "number" || !(n > 0)) return;
|
|
2434
|
-
let r =
|
|
2435
|
+
let r = rr(e)?.loading;
|
|
2435
2436
|
if (!r || !(r.start > 0) || !(r.end > 0)) return;
|
|
2436
2437
|
let i = r.first > r.start ? r.first : r.end, a = Math.max(0, i - r.start) / (n * 1e3);
|
|
2437
2438
|
this.holdBackSamples.push({
|
|
@@ -2446,20 +2447,20 @@ var or = class {
|
|
|
2446
2447
|
this.holdBackSlowTicks = 0, this.holdBackFastSince = 0, this.holdBackSamples = [];
|
|
2447
2448
|
return;
|
|
2448
2449
|
}
|
|
2449
|
-
let t = Date.now(), n = t -
|
|
2450
|
+
let t = Date.now(), n = t - Jn, r = this.holdBackSamples, i = 0;
|
|
2450
2451
|
for (; i < r.length && r[i].t < n;) i += 1;
|
|
2451
2452
|
i > 0 && r.splice(0, i);
|
|
2452
2453
|
let a = e.targetLatency;
|
|
2453
2454
|
if (typeof a != "number" || !(a > 0)) return;
|
|
2454
2455
|
this.holdBackBase < 0 && (this.holdBackBase = a);
|
|
2455
2456
|
let o = this.holdBackBase, s = this.holdBackCeiling(e);
|
|
2456
|
-
if (r.length <
|
|
2457
|
+
if (r.length < Yn) {
|
|
2457
2458
|
this.holdBackSlowTicks = 0;
|
|
2458
2459
|
return;
|
|
2459
2460
|
}
|
|
2460
2461
|
let c = r.map((e) => e.ratio).sort((e, t) => e - t), l = K(c, 95), u = K(c, 50), d = Math.round(l * 1e3);
|
|
2461
|
-
if (l >=
|
|
2462
|
-
if (this.holdBackFastSince = 0, this.holdBackSlowTicks += 1, this.holdBackSlowTicks <
|
|
2462
|
+
if (l >= Xn && u >= Zn) {
|
|
2463
|
+
if (this.holdBackFastSince = 0, this.holdBackSlowTicks += 1, this.holdBackSlowTicks < $n) return;
|
|
2463
2464
|
this.holdBackSlowTicks = 0;
|
|
2464
2465
|
let t = Math.ceil((s - o) / X), n = Math.ceil((a - o) / X - 1e-9);
|
|
2465
2466
|
if (n > this.holdBackStepCount && (this.holdBackStepCount = n), this.holdBackStepCount >= t) return;
|
|
@@ -2469,7 +2470,7 @@ var or = class {
|
|
|
2469
2470
|
this.moveHoldBack(e, a, r, "slow-fetches", `part fetches slow (first byte p50 ${Math.round(u * 1e3)} / p95 ${d} ms per 1 s of media)`);
|
|
2470
2471
|
return;
|
|
2471
2472
|
}
|
|
2472
|
-
if (this.holdBackSlowTicks = 0, l >=
|
|
2473
|
+
if (this.holdBackSlowTicks = 0, l >= Qn) {
|
|
2473
2474
|
this.holdBackFastSince = 0;
|
|
2474
2475
|
return;
|
|
2475
2476
|
}
|
|
@@ -2477,7 +2478,7 @@ var or = class {
|
|
|
2477
2478
|
this.holdBackFastSince = t;
|
|
2478
2479
|
return;
|
|
2479
2480
|
}
|
|
2480
|
-
if (t - this.holdBackFastSince <
|
|
2481
|
+
if (t - this.holdBackFastSince < er || (this.holdBackFastSince = t, this.holdBackStepCount === 0 || a !== this.holdBackApplied)) return;
|
|
2481
2482
|
--this.holdBackStepCount;
|
|
2482
2483
|
let f = Math.max(o, o + this.holdBackStepCount * X);
|
|
2483
2484
|
f >= a || this.moveHoldBack(e, a, f, "fast-fetches", `part fetches fast again (p95 first byte ${d} ms per 1 s of media)`);
|
|
@@ -2545,7 +2546,7 @@ var or = class {
|
|
|
2545
2546
|
scheduleLicenseRetry(t) {
|
|
2546
2547
|
if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
|
|
2547
2548
|
let n = t.response?.code ?? 0;
|
|
2548
|
-
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >=
|
|
2549
|
+
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= an) return !1;
|
|
2549
2550
|
this.licenseRecoveries += 1;
|
|
2550
2551
|
let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
|
|
2551
2552
|
return this.licenseRetryTimer = setTimeout(() => {
|
|
@@ -2581,7 +2582,7 @@ var or = class {
|
|
|
2581
2582
|
this.offlineHold = !0, this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null);
|
|
2582
2583
|
return;
|
|
2583
2584
|
}
|
|
2584
|
-
if (this.networkRecoveries <
|
|
2585
|
+
if (this.networkRecoveries < rn) {
|
|
2585
2586
|
this.networkRecoveries += 1;
|
|
2586
2587
|
let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
|
|
2587
2588
|
this.networkRetryTimer = setTimeout(() => {
|
|
@@ -2598,6 +2599,15 @@ var or = class {
|
|
|
2598
2599
|
return;
|
|
2599
2600
|
}
|
|
2600
2601
|
if (t.type === e.ErrorTypes.MEDIA_ERROR) {
|
|
2602
|
+
if (t.details != null && (t.details === e.ErrorDetails.BUFFER_SEEK_OVER_HOLE || t.details === e.ErrorDetails.BUFFER_STALLED_ERROR) && this.sawLive && this.holeKicks < nn && this.mediaRecoveries < tn) {
|
|
2603
|
+
this.holeKicks += 1, this.mediaRecoveries += 1, console.warn("havik-player: playback stuck at a buffer hole hls.js could not nudge across — re-syncing to the live edge");
|
|
2604
|
+
try {
|
|
2605
|
+
n.stopLoad(), n.startLoad(-1);
|
|
2606
|
+
return;
|
|
2607
|
+
} catch (e) {
|
|
2608
|
+
console.warn("havik-player: live re-sync after a buffer hole failed", e);
|
|
2609
|
+
}
|
|
2610
|
+
}
|
|
2601
2611
|
if (this.mediaRecoveries < tn) {
|
|
2602
2612
|
this.mediaRecoveries += 1, n.recoverMediaError();
|
|
2603
2613
|
return;
|
|
@@ -2625,15 +2635,15 @@ var or = class {
|
|
|
2625
2635
|
...l ? { serverCode: l } : {}
|
|
2626
2636
|
});
|
|
2627
2637
|
}
|
|
2628
|
-
},
|
|
2638
|
+
}, cr = 15e3, lr = 6e5, ur = 3e5, dr = 100, Z = 1, fr = 1e3, pr = 3e4, mr = 1e3, hr = {
|
|
2629
2639
|
inline: "PRESENTATION_INLINE",
|
|
2630
2640
|
fullscreen: "PRESENTATION_FULLSCREEN",
|
|
2631
2641
|
pip: "PRESENTATION_PIP"
|
|
2632
|
-
},
|
|
2642
|
+
}, gr = {
|
|
2633
2643
|
widevine: "KEY_SYSTEM_WIDEVINE",
|
|
2634
2644
|
fairplay: "KEY_SYSTEM_FAIRPLAY",
|
|
2635
2645
|
none: "KEY_SYSTEM_NONE"
|
|
2636
|
-
},
|
|
2646
|
+
}, _r = /* @__PURE__ */ new Set([
|
|
2637
2647
|
"INVALID_URN",
|
|
2638
2648
|
"NOT_FOUND",
|
|
2639
2649
|
"GEO_DENIED",
|
|
@@ -2644,7 +2654,7 @@ var or = class {
|
|
|
2644
2654
|
"FORBIDDEN",
|
|
2645
2655
|
"RATE_LIMITED",
|
|
2646
2656
|
"TIMEOUT"
|
|
2647
|
-
]),
|
|
2657
|
+
]), vr = {
|
|
2648
2658
|
idle: "PLAYER_STATE_IDLE",
|
|
2649
2659
|
waiting: "PLAYER_STATE_WAITING",
|
|
2650
2660
|
loading: "PLAYER_STATE_LOADING",
|
|
@@ -2654,7 +2664,7 @@ var or = class {
|
|
|
2654
2664
|
ended: "PLAYER_STATE_ENDED",
|
|
2655
2665
|
error: "PLAYER_STATE_ERROR"
|
|
2656
2666
|
};
|
|
2657
|
-
function
|
|
2667
|
+
function yr(e) {
|
|
2658
2668
|
try {
|
|
2659
2669
|
let t = new URL(e), [n, ...r] = t.hostname.split(".");
|
|
2660
2670
|
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);
|
|
@@ -2662,8 +2672,8 @@ function vr(e) {
|
|
|
2662
2672
|
return;
|
|
2663
2673
|
}
|
|
2664
2674
|
}
|
|
2665
|
-
var
|
|
2666
|
-
function
|
|
2675
|
+
var br = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), xr = /* @__PURE__ */ new Set(), Sr = /* @__PURE__ */ new Set(), Cr = /* @__PURE__ */ new Set(), wr = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
|
|
2676
|
+
function Tr(e) {
|
|
2667
2677
|
if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
|
|
2668
2678
|
let t;
|
|
2669
2679
|
try {
|
|
@@ -2672,19 +2682,19 @@ function wr(e) {
|
|
|
2672
2682
|
} catch {
|
|
2673
2683
|
return;
|
|
2674
2684
|
}
|
|
2675
|
-
if (
|
|
2676
|
-
|
|
2677
|
-
for (let e of
|
|
2685
|
+
if (xr.has(t) && !Sr.has(t)) {
|
|
2686
|
+
Sr.add(t), _(wr(new URL(t).origin));
|
|
2687
|
+
for (let e of Cr) e.noteCspBlocked();
|
|
2678
2688
|
}
|
|
2679
2689
|
}
|
|
2680
|
-
function
|
|
2690
|
+
function Er(e, t) {
|
|
2681
2691
|
return _(t, e), { disabledReason: t };
|
|
2682
2692
|
}
|
|
2683
|
-
function
|
|
2684
|
-
if (n) return t && !
|
|
2693
|
+
function Dr(e, t, n) {
|
|
2694
|
+
if (n) return t && !br(t, n) && _(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
|
|
2685
2695
|
if (t) return { endpoint: t };
|
|
2686
|
-
if (t !== void 0) return
|
|
2687
|
-
let r =
|
|
2696
|
+
if (t !== void 0) return Er("empty-endpoint", "analytics is disabled: no QoE beacons will be sent. analytics.endpoint was supplied but empty. Pass a real beacons origin, analytics: { endpoint: 'https://beacons[-dev].<domain>' }, or omit the option to derive it from baseUrl (or analytics: false to opt out).");
|
|
2697
|
+
let r = yr(e);
|
|
2688
2698
|
if (r) return { endpoint: r };
|
|
2689
2699
|
let i;
|
|
2690
2700
|
try {
|
|
@@ -2692,9 +2702,9 @@ function Er(e, t, n) {
|
|
|
2692
2702
|
} catch {
|
|
2693
2703
|
i = e;
|
|
2694
2704
|
}
|
|
2695
|
-
return
|
|
2705
|
+
return Er(i, `analytics is disabled: no QoE beacons will be sent. The beacons endpoint cannot be derived from the baseUrl host "${i}" — the convention is feed[-dev].<domain> → beacons[-dev].<domain>. Pass an explicit endpoint, analytics: { endpoint: 'https://beacons[-dev].<domain>' }, to createPlayer (or analytics: false to opt out deliberately).`);
|
|
2696
2706
|
}
|
|
2697
|
-
var
|
|
2707
|
+
var Or = class {
|
|
2698
2708
|
opts;
|
|
2699
2709
|
url;
|
|
2700
2710
|
cspKey;
|
|
@@ -2776,8 +2786,8 @@ var Dr = class {
|
|
|
2776
2786
|
constructor(e) {
|
|
2777
2787
|
this.opts = {
|
|
2778
2788
|
...e,
|
|
2779
|
-
heartbeatMs: e.heartbeatMs ??
|
|
2780
|
-
idleMs: e.idleMs ??
|
|
2789
|
+
heartbeatMs: e.heartbeatMs ?? cr,
|
|
2790
|
+
idleMs: e.idleMs ?? lr
|
|
2781
2791
|
}, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
|
|
2782
2792
|
try {
|
|
2783
2793
|
let e = new URL(this.url);
|
|
@@ -2794,11 +2804,11 @@ var Dr = class {
|
|
|
2794
2804
|
sdkVersion: this.opts.sdkVersion,
|
|
2795
2805
|
...this.opts.environment
|
|
2796
2806
|
};
|
|
2797
|
-
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(),
|
|
2807
|
+
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), fr), this.lastTickMs = this.now(), this.timer = setInterval(() => this.heartbeat(), this.opts.heartbeatMs), typeof window < "u" && window.addEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.addEventListener("visibilitychange", this.onVisibility), document.addEventListener("freeze", this.onFreeze), document.addEventListener("resume", this.onResume), this.cspKey && xr.add(this.cspKey), document.addEventListener("securitypolicyviolation", Tr), Cr.add(this), this.noteCspBlocked(), this.onVisibility());
|
|
2798
2808
|
}
|
|
2799
2809
|
checkSuspension(e) {
|
|
2800
2810
|
if (this.endedFlag || !this.opts.idleMs) return !1;
|
|
2801
|
-
let t = Math.max(this.opts.idleMs,
|
|
2811
|
+
let t = Math.max(this.opts.idleMs, ur);
|
|
2802
2812
|
return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
|
|
2803
2813
|
}
|
|
2804
2814
|
syncIdle(e) {
|
|
@@ -2819,14 +2829,14 @@ var Dr = class {
|
|
|
2819
2829
|
} else e === "buffering" && (this.isBuffering = !1, this.stallIsSeekInduced = !1);
|
|
2820
2830
|
this.syncBuffering(), t === "paused" && (this.pauseCount += 1), this.syncIdle(t);
|
|
2821
2831
|
let a = {
|
|
2822
|
-
fromState:
|
|
2823
|
-
toState:
|
|
2824
|
-
presentation:
|
|
2832
|
+
fromState: vr[e] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2833
|
+
toState: vr[t] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2834
|
+
presentation: hr[this.presentation]
|
|
2825
2835
|
}, o = this.causeOf(e, t, i);
|
|
2826
2836
|
o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
|
|
2827
2837
|
}
|
|
2828
2838
|
seekInduced(e) {
|
|
2829
|
-
return this.lastSeekMs >= 0 && e - this.lastSeekMs <
|
|
2839
|
+
return this.lastSeekMs >= 0 && e - this.lastSeekMs < mr;
|
|
2830
2840
|
}
|
|
2831
2841
|
causeOf(e, t, n) {
|
|
2832
2842
|
if (t === "error") return "TRANSITION_CAUSE_ERROR";
|
|
@@ -2900,7 +2910,7 @@ var Dr = class {
|
|
|
2900
2910
|
let r = n ?? "";
|
|
2901
2911
|
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";
|
|
2902
2912
|
if (e === "DRM_CLIENT" || e === "DRM_DEVICE_REVOKED") return "ERROR_STAGE_DRM";
|
|
2903
|
-
if (
|
|
2913
|
+
if (_r.has(e)) return "ERROR_STAGE_RESOLVE";
|
|
2904
2914
|
let i = t ?? "";
|
|
2905
2915
|
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";
|
|
2906
2916
|
}
|
|
@@ -2932,7 +2942,7 @@ var Dr = class {
|
|
|
2932
2942
|
let l = t.droppedFrames ?? 0;
|
|
2933
2943
|
l > this.lastDropped && (o.droppedFramesDelta = l - this.lastDropped), this.lastDropped = l;
|
|
2934
2944
|
let u = t.renditionSwitches ?? 0;
|
|
2935
|
-
u > this.lastSwitches && (o.renditionSwitchesDelta = u - this.lastSwitches), this.lastSwitches = u, n > this.lastHbPlayingMs && (o.playingMsDelta = Math.round(n - this.lastHbPlayingMs)), this.lastHbPlayingMs = n, r > this.lastHbHiddenMs && (o.hiddenMsDelta = Math.round(r - this.lastHbHiddenMs)), this.lastHbHiddenMs = r, i > this.lastHbRebufferMs && (o.rebufferMsDelta = Math.round(i - this.lastHbRebufferMs)), this.lastHbRebufferMs = i, this.rebufferCount > this.lastHbRebufferCount && (o.rebufferCountDelta = this.rebufferCount - this.lastHbRebufferCount), this.lastHbRebufferCount = this.rebufferCount, a > this.lastHbActiveMs && (o.activeMsDelta = Math.round(a - this.lastHbActiveMs)), this.lastHbActiveMs = a, typeof t.latencySeconds == "number" && (o.latencyMs = Math.round(t.latencySeconds * 1e3)), typeof t.targetLatencySeconds == "number" && (o.targetLatencyMs = Math.round(t.targetLatencySeconds * 1e3)), typeof t.bandwidthKbps == "number" && (o.bandwidthEstKbps = t.bandwidthKbps), typeof t.levelHeight == "number" && (o.renditionHeight = t.levelHeight), typeof t.renditionBitrateKbps == "number" && (o.renditionBitrateKbps = t.renditionBitrateKbps), t.atLiveEdge === !0 && (o.atLiveEdge = !0), typeof t.bufferedMs == "number" && t.bufferedMs > 0 && (o.bufferedMs = Math.round(t.bufferedMs)), o.playerState =
|
|
2945
|
+
u > this.lastSwitches && (o.renditionSwitchesDelta = u - this.lastSwitches), this.lastSwitches = u, n > this.lastHbPlayingMs && (o.playingMsDelta = Math.round(n - this.lastHbPlayingMs)), this.lastHbPlayingMs = n, r > this.lastHbHiddenMs && (o.hiddenMsDelta = Math.round(r - this.lastHbHiddenMs)), this.lastHbHiddenMs = r, i > this.lastHbRebufferMs && (o.rebufferMsDelta = Math.round(i - this.lastHbRebufferMs)), this.lastHbRebufferMs = i, this.rebufferCount > this.lastHbRebufferCount && (o.rebufferCountDelta = this.rebufferCount - this.lastHbRebufferCount), this.lastHbRebufferCount = this.rebufferCount, a > this.lastHbActiveMs && (o.activeMsDelta = Math.round(a - this.lastHbActiveMs)), this.lastHbActiveMs = a, typeof t.latencySeconds == "number" && (o.latencyMs = Math.round(t.latencySeconds * 1e3)), typeof t.targetLatencySeconds == "number" && (o.targetLatencyMs = Math.round(t.targetLatencySeconds * 1e3)), typeof t.bandwidthKbps == "number" && (o.bandwidthEstKbps = t.bandwidthKbps), typeof t.levelHeight == "number" && (o.renditionHeight = t.levelHeight), typeof t.renditionBitrateKbps == "number" && (o.renditionBitrateKbps = t.renditionBitrateKbps), t.atLiveEdge === !0 && (o.atLiveEdge = !0), typeof t.bufferedMs == "number" && t.bufferedMs > 0 && (o.bufferedMs = Math.round(t.bufferedMs)), o.playerState = vr[t.state] ?? "PLAYER_STATE_UNSPECIFIED";
|
|
2936
2946
|
let d = this.mutedTotalMs;
|
|
2937
2947
|
this.mutedSinceMs !== null && (d += e - this.mutedSinceMs), d > this.lastHbMutedMs && (o.mutedMsDelta = Math.round(d - this.lastHbMutedMs)), this.lastHbMutedMs = d;
|
|
2938
2948
|
let f = t.upshifts ?? 0;
|
|
@@ -2954,13 +2964,13 @@ var Dr = class {
|
|
|
2954
2964
|
maybeEmitMediaInfo(e) {
|
|
2955
2965
|
if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
|
|
2956
2966
|
let t = {};
|
|
2957
|
-
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem =
|
|
2967
|
+
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = gr[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);
|
|
2958
2968
|
let n = JSON.stringify(t);
|
|
2959
2969
|
n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
|
|
2960
2970
|
}
|
|
2961
2971
|
end(e, t) {
|
|
2962
2972
|
if (this.endedFlag) return;
|
|
2963
|
-
this.endedFlag = !0,
|
|
2973
|
+
this.endedFlag = !0, Cr.delete(this);
|
|
2964
2974
|
let n = t ?? this.now();
|
|
2965
2975
|
this.playingSinceMs !== null && (this.playingTotalMs += n - this.playingSinceMs, this.playingSinceMs = null), this.hiddenSinceMs !== null && (this.hiddenTotalMs += n - this.hiddenSinceMs, this.hiddenSinceMs = null), this.bufferingSinceMs !== null && (this.rebufferTotalMs += n - this.bufferingSinceMs, this.bufferingSinceMs = null), this.mutedSinceMs !== null && (this.mutedTotalMs += n - this.mutedSinceMs, this.mutedSinceMs = null), this.waitingSinceMs !== null && (this.waitingTotalMs += n - this.waitingSinceMs, this.waitingSinceMs = null), this.isPlaying = !1, this.syncActive(n), this.closePresentation(n), this.firstFlushTimer &&= (clearTimeout(this.firstFlushTimer), null), this.timer &&= (clearInterval(this.timer), null), this.idleTimer &&= (clearTimeout(this.idleTimer), null), typeof window < "u" && window.removeEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), document.removeEventListener("freeze", this.onFreeze), document.removeEventListener("resume", this.onResume));
|
|
2966
2976
|
let r = this.safeSample();
|
|
@@ -2974,7 +2984,7 @@ var Dr = class {
|
|
|
2974
2984
|
let c = r?.positionMs ?? 0;
|
|
2975
2985
|
c > 0 && (i.exitPositionMs = Math.round(c)), this.activeTotalMs > 0 && (i.activeWatchTimeMs = Math.round(this.activeTotalMs)), this.mutedTotalMs > 0 && (i.mutedTimeMs = Math.round(this.mutedTotalMs));
|
|
2976
2986
|
let l = e !== "END_REASON_ENDED";
|
|
2977
|
-
l && this.lastStallMs > 0 && n - this.lastStallMs <=
|
|
2987
|
+
l && this.lastStallMs > 0 && n - this.lastStallMs <= pr && (i.abandonAfterStallMs = Math.max(Z, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= pr && (i.abandonAfterErrorMs = Math.max(Z, Math.round(n - this.lastErrorMs))), this.fullscreenTotalMs > 0 && (i.fullscreenTimeMs = Math.round(this.fullscreenTotalMs)), this.pipTotalMs > 0 && (i.pipTimeMs = Math.round(this.pipTotalMs)), this.volumeChanges > 0 && (i.volumeChanges = this.volumeChanges), this.muteChanges > 0 && (i.muteChanges = this.muteChanges);
|
|
2978
2988
|
let u = r?.decodedFrames ?? this.lastDecoded;
|
|
2979
2989
|
u > 0 && (i.decodedFramesTotal = u), e === "END_REASON_STOPPED" && this.startupTimeMs === 0 && this.lastErrorStage === null && (e = "END_REASON_ABORTED", i.reason = e), this.startupTimeMs === 0 && e !== "END_REASON_ABORTED" && (i.failedStage = this.lastErrorStage ?? (this.manifestLoadMs === 0 ? "ERROR_STAGE_MANIFEST" : this.firstFragLoadMs === 0 ? "ERROR_STAGE_FIRST_SEGMENT" : "ERROR_STAGE_OTHER")), this.pending.push(this.wrap({ sessionEnd: i })), this.flush(e === "END_REASON_PAGEHIDE");
|
|
2980
2990
|
}
|
|
@@ -2994,13 +3004,13 @@ var Dr = class {
|
|
|
2994
3004
|
};
|
|
2995
3005
|
}
|
|
2996
3006
|
noteCspBlocked() {
|
|
2997
|
-
this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(
|
|
3007
|
+
this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(wr(new URL(this.url).origin)));
|
|
2998
3008
|
}
|
|
2999
3009
|
cspBlocked() {
|
|
3000
|
-
return !!this.cspKey &&
|
|
3010
|
+
return !!this.cspKey && Sr.has(this.cspKey);
|
|
3001
3011
|
}
|
|
3002
3012
|
enqueue(e) {
|
|
3003
|
-
if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length >
|
|
3013
|
+
if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > dr;) {
|
|
3004
3014
|
let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
|
|
3005
3015
|
this.pending.splice(e >= 0 ? e : 0, 1);
|
|
3006
3016
|
}
|
|
@@ -3027,7 +3037,7 @@ var Dr = class {
|
|
|
3027
3037
|
};
|
|
3028
3038
|
//#endregion
|
|
3029
3039
|
//#region src/core/environment.ts
|
|
3030
|
-
function
|
|
3040
|
+
function kr() {
|
|
3031
3041
|
if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
|
|
3032
3042
|
let e;
|
|
3033
3043
|
try {
|
|
@@ -3052,14 +3062,14 @@ function Or() {
|
|
|
3052
3062
|
integration: "INTEGRATION_KIND_IFRAME"
|
|
3053
3063
|
};
|
|
3054
3064
|
}
|
|
3055
|
-
function
|
|
3065
|
+
function Ar() {
|
|
3056
3066
|
if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
|
|
3057
3067
|
let e = navigator.userAgentData, t = e?.platform ?? "";
|
|
3058
3068
|
if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
|
|
3059
3069
|
let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
|
|
3060
3070
|
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";
|
|
3061
3071
|
}
|
|
3062
|
-
function
|
|
3072
|
+
function jr() {
|
|
3063
3073
|
let e = typeof navigator < "u" ? navigator.connection : void 0;
|
|
3064
3074
|
if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
|
|
3065
3075
|
let t = {
|
|
@@ -3078,17 +3088,17 @@ function Ar() {
|
|
|
3078
3088
|
}
|
|
3079
3089
|
return typeof e.downlink == "number" && e.downlink > 0 && (i.downlinkKbps = Math.round(e.downlink * 1e3)), typeof e.rtt == "number" && e.rtt > 0 && (i.rttMs = Math.round(e.rtt)), e.saveData && (i.saveData = !0), i;
|
|
3080
3090
|
}
|
|
3081
|
-
function
|
|
3082
|
-
let t =
|
|
3083
|
-
deviceClass:
|
|
3091
|
+
function Mr(e) {
|
|
3092
|
+
let t = kr(), n = {
|
|
3093
|
+
deviceClass: Ar(),
|
|
3084
3094
|
integration: t.integration,
|
|
3085
|
-
...
|
|
3095
|
+
...jr()
|
|
3086
3096
|
};
|
|
3087
3097
|
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);
|
|
3088
3098
|
let r = e.getBoundingClientRect?.();
|
|
3089
3099
|
return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
|
|
3090
3100
|
}
|
|
3091
|
-
async function
|
|
3101
|
+
async function Nr() {
|
|
3092
3102
|
let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
|
|
3093
3103
|
if (!e?.getHighEntropyValues) return {};
|
|
3094
3104
|
try {
|
|
@@ -3100,7 +3110,7 @@ async function Mr() {
|
|
|
3100
3110
|
}
|
|
3101
3111
|
//#endregion
|
|
3102
3112
|
//#region src/core/version.ts
|
|
3103
|
-
var
|
|
3113
|
+
var Pr = "2.28.1", Fr = {
|
|
3104
3114
|
accent: "#E1B600",
|
|
3105
3115
|
accentText: "#1B1C23",
|
|
3106
3116
|
background: "#0e0f13",
|
|
@@ -3111,7 +3121,7 @@ var Nr = "2.28.0", Pr = {
|
|
|
3111
3121
|
border: "rgba(255, 255, 255, 0.1)",
|
|
3112
3122
|
radius: "8px",
|
|
3113
3123
|
fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
|
|
3114
|
-
},
|
|
3124
|
+
}, Ir = {
|
|
3115
3125
|
accent: "--havik-accent",
|
|
3116
3126
|
accentText: "--havik-accent-text",
|
|
3117
3127
|
background: "--havik-bg",
|
|
@@ -3123,26 +3133,26 @@ var Nr = "2.28.0", Pr = {
|
|
|
3123
3133
|
radius: "--havik-radius",
|
|
3124
3134
|
fontFamily: "--havik-font"
|
|
3125
3135
|
};
|
|
3126
|
-
function
|
|
3136
|
+
function Lr(e, t) {
|
|
3127
3137
|
let n = {
|
|
3128
|
-
...
|
|
3138
|
+
...Fr,
|
|
3129
3139
|
...t
|
|
3130
3140
|
};
|
|
3131
|
-
for (let t of Object.keys(
|
|
3141
|
+
for (let t of Object.keys(Ir)) e.style.setProperty(Ir[t], n[t]);
|
|
3132
3142
|
n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
|
|
3133
3143
|
}
|
|
3134
3144
|
//#endregion
|
|
3135
3145
|
//#region src/ui/styles.ts
|
|
3136
|
-
var
|
|
3137
|
-
function
|
|
3138
|
-
let n = e.querySelector(`style#${
|
|
3139
|
-
if (n && (!t ||
|
|
3146
|
+
var Rr = "havik-player-styles", zr = "\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 touch-action:manipulation}\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/* Absolutely centred, NOT a flex sibling of .havik-center: the hidden center\n button (.havik-gone) still occupies its 74px in the row, which pushed an\n in-flow spinner 37px right of centre. */\n.havik-spinner{position:absolute;inset:0;margin:auto;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", Br = /* @__PURE__ */ new WeakMap();
|
|
3147
|
+
function Vr(e = document, t) {
|
|
3148
|
+
let n = e.querySelector(`style#${Rr}`);
|
|
3149
|
+
if (n && (!t || Br.get(n) === t)) return;
|
|
3140
3150
|
let r = e.createElement("style");
|
|
3141
|
-
r.id =
|
|
3151
|
+
r.id = Rr, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = zr, Br.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
|
|
3142
3152
|
}
|
|
3143
3153
|
//#endregion
|
|
3144
3154
|
//#region src/ui/icons.ts
|
|
3145
|
-
var
|
|
3155
|
+
var Hr = {
|
|
3146
3156
|
play: "<path d=\"M8 5v14l11-7z\"/>",
|
|
3147
3157
|
pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
|
|
3148
3158
|
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\"/>",
|
|
@@ -3156,11 +3166,11 @@ var Vr = {
|
|
|
3156
3166
|
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\"/>"
|
|
3157
3167
|
};
|
|
3158
3168
|
function Q(e) {
|
|
3159
|
-
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${
|
|
3169
|
+
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Hr[e]}</svg>`;
|
|
3160
3170
|
}
|
|
3161
3171
|
//#endregion
|
|
3162
3172
|
//#region src/ui/controls.ts
|
|
3163
|
-
var
|
|
3173
|
+
var Ur = 3e3, Wr = 250, Gr = /* @__PURE__ */ new Set([
|
|
3164
3174
|
"GONE",
|
|
3165
3175
|
"NOT_FOUND",
|
|
3166
3176
|
"GEO_DENIED",
|
|
@@ -3168,19 +3178,19 @@ var Hr = 3e3, Ur = 250, Wr = /* @__PURE__ */ new Set([
|
|
|
3168
3178
|
"UNAUTHORIZED",
|
|
3169
3179
|
"DRM_DEVICE_REVOKED"
|
|
3170
3180
|
]);
|
|
3171
|
-
function
|
|
3181
|
+
function Kr(e) {
|
|
3172
3182
|
let t = "This match isn't available in your country";
|
|
3173
3183
|
return e ? `${t} (${e})` : t;
|
|
3174
3184
|
}
|
|
3175
|
-
var
|
|
3176
|
-
function
|
|
3185
|
+
var qr = "This device can't play protected video";
|
|
3186
|
+
function Jr(e) {
|
|
3177
3187
|
return `This browser can't play protected video. Allow protected content in its site settings, or use ${e ? "Chrome, Edge or Safari" : "Chrome or Edge"} (Firefox asks when you retry)`;
|
|
3178
3188
|
}
|
|
3179
|
-
var
|
|
3180
|
-
function
|
|
3181
|
-
return new
|
|
3189
|
+
var Yr = "Protected video can't be shown on this display. Use the built-in screen, or an HDCP-capable monitor and cable";
|
|
3190
|
+
function Xr(e) {
|
|
3191
|
+
return new Zr(e);
|
|
3182
3192
|
}
|
|
3183
|
-
var
|
|
3193
|
+
var Zr = class {
|
|
3184
3194
|
root;
|
|
3185
3195
|
video;
|
|
3186
3196
|
player;
|
|
@@ -3229,7 +3239,7 @@ var Xr = class {
|
|
|
3229
3239
|
scrubbing = !1;
|
|
3230
3240
|
offFns = [];
|
|
3231
3241
|
constructor(e) {
|
|
3232
|
-
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ??
|
|
3242
|
+
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Ur, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.streamEnded = e.streamEnded ?? (() => !1), this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, this.offlineMessage = e.offlineMessage ?? "No internet connection — waiting to reconnect", Vr(this.doc, e.cspNonce), 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");
|
|
3233
3243
|
let t = (e, t, n) => {
|
|
3234
3244
|
let r = this.doc.createElement(e);
|
|
3235
3245
|
if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
|
|
@@ -3315,7 +3325,7 @@ var Xr = class {
|
|
|
3315
3325
|
let t = this.surfaceWasHidden;
|
|
3316
3326
|
this.tapTimer = setTimeout(() => {
|
|
3317
3327
|
this.tapTimer = void 0, this.toggleBar(t);
|
|
3318
|
-
},
|
|
3328
|
+
}, Wr);
|
|
3319
3329
|
}
|
|
3320
3330
|
toggleBar(e) {
|
|
3321
3331
|
e ? this.poke() : this.hideIfIdle();
|
|
@@ -3347,11 +3357,11 @@ var Xr = class {
|
|
|
3347
3357
|
if (e === "waiting") return this.hasPlayed ? "Reconnecting — please stand by" : "Starting soon…";
|
|
3348
3358
|
if (e === "error") {
|
|
3349
3359
|
if (this.errorMessage !== void 0) return this.errorMessage;
|
|
3350
|
-
if (this.lastError?.code === "GEO_DENIED") return
|
|
3351
|
-
if (this.lastError?.code === "DRM_DEVICE_REVOKED") return
|
|
3360
|
+
if (this.lastError?.code === "GEO_DENIED") return Kr(this.lastError.country);
|
|
3361
|
+
if (this.lastError?.code === "DRM_DEVICE_REVOKED") return qr;
|
|
3352
3362
|
if (this.lastError?.code === "DRM_CLIENT") {
|
|
3353
|
-
if (this.lastError.detail === "keySystemNoAccess") return
|
|
3354
|
-
if (this.lastError.detail === "keySystemStatusOutputRestricted") return
|
|
3363
|
+
if (this.lastError.detail === "keySystemNoAccess") return Jr(!!this.player.descriptor?.drm?.fairplay?.licenseUrl);
|
|
3364
|
+
if (this.lastError.detail === "keySystemStatusOutputRestricted") return Yr;
|
|
3355
3365
|
}
|
|
3356
3366
|
return this.lastError?.message ?? "Playback unavailable";
|
|
3357
3367
|
}
|
|
@@ -3370,7 +3380,7 @@ var Xr = class {
|
|
|
3370
3380
|
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);
|
|
3371
3381
|
} else {
|
|
3372
3382
|
let r = this.doc.createElement("div");
|
|
3373
|
-
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !
|
|
3383
|
+
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !Gr.has(this.lastError.code)) {
|
|
3374
3384
|
let e = this.doc.createElement("button");
|
|
3375
3385
|
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);
|
|
3376
3386
|
}
|
|
@@ -3411,7 +3421,7 @@ var Xr = class {
|
|
|
3411
3421
|
let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
|
|
3412
3422
|
this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
|
|
3413
3423
|
}
|
|
3414
|
-
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${
|
|
3424
|
+
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Qr(this.video.currentTime)} / ${Qr(this.video.duration)}`);
|
|
3415
3425
|
}
|
|
3416
3426
|
syncLive() {
|
|
3417
3427
|
let e = this.player.getStats(), t = e.isLive !== !1, n = this.isGone(), r = this.player.state === "ended" || n, i = !t && !this.streamEnded() && !n;
|
|
@@ -3461,17 +3471,17 @@ var Xr = class {
|
|
|
3461
3471
|
renderQualityMenu() {
|
|
3462
3472
|
let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
|
|
3463
3473
|
n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
|
|
3464
|
-
for (let n of e) this.menu.append(this.menuItem(
|
|
3474
|
+
for (let n of e) this.menu.append(this.menuItem($r(n), t === n.index, () => this.player.setQuality(n.index)));
|
|
3465
3475
|
}
|
|
3466
3476
|
renderAudioMenu() {
|
|
3467
3477
|
let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
|
|
3468
3478
|
t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
|
|
3469
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
3479
|
+
for (let t of e) this.menu.append(this.menuItem(ei(t), t.default, () => this.player.setAudioTrack(t.id)));
|
|
3470
3480
|
}
|
|
3471
3481
|
renderCcMenu() {
|
|
3472
3482
|
let e = this.player.getTextTracks(), t = this.doc.createElement("div");
|
|
3473
3483
|
t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
|
|
3474
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
3484
|
+
for (let t of e) this.menu.append(this.menuItem(ti(t), !1, () => this.player.setTextTrack(t.id)));
|
|
3475
3485
|
}
|
|
3476
3486
|
onTracksChanged() {
|
|
3477
3487
|
this.openMenu && this.renderMenu(this.openMenu);
|
|
@@ -3576,23 +3586,23 @@ var Xr = class {
|
|
|
3576
3586
|
this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
|
|
3577
3587
|
}
|
|
3578
3588
|
};
|
|
3579
|
-
function
|
|
3589
|
+
function Qr(e) {
|
|
3580
3590
|
(!Number.isFinite(e) || e < 0) && (e = 0);
|
|
3581
3591
|
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");
|
|
3582
3592
|
return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
|
|
3583
3593
|
}
|
|
3584
|
-
function
|
|
3594
|
+
function $r(e) {
|
|
3585
3595
|
return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
|
|
3586
3596
|
}
|
|
3587
|
-
function
|
|
3597
|
+
function ei(e) {
|
|
3588
3598
|
return e.name || e.lang || `Track ${e.id}`;
|
|
3589
3599
|
}
|
|
3590
|
-
function
|
|
3600
|
+
function ti(e) {
|
|
3591
3601
|
return e.name || e.lang || `Track ${e.id}`;
|
|
3592
3602
|
}
|
|
3593
3603
|
//#endregion
|
|
3594
3604
|
//#region src/managed/index.ts
|
|
3595
|
-
var
|
|
3605
|
+
var ni = 6e3, ri = 45e3, ii = 2e3, ai = 3, oi = 6e4, si = 2, ci = 6e5, li = 5e3, ui = 2e3, di = 48e4, fi = "keySystemLicenseRequestFailed", pi = /* @__PURE__ */ new Set([
|
|
3596
3606
|
"GONE",
|
|
3597
3607
|
"NOT_FOUND",
|
|
3598
3608
|
"INVALID_URN",
|
|
@@ -3600,27 +3610,27 @@ var ti = 6e3, ni = 45e3, ri = 2e3, ii = 3, ai = 6e4, oi = 2, si = 6e5, ci = 5e3,
|
|
|
3600
3610
|
"GEO_DENIED",
|
|
3601
3611
|
"DRM_DEVICE_REVOKED"
|
|
3602
3612
|
]);
|
|
3603
|
-
function pi(e) {
|
|
3604
|
-
return !fi.has(e);
|
|
3605
|
-
}
|
|
3606
3613
|
function mi(e) {
|
|
3614
|
+
return !pi.has(e);
|
|
3615
|
+
}
|
|
3616
|
+
function hi(e) {
|
|
3607
3617
|
if (e.env !== void 0 && e.baseUrl !== void 0) throw new n("INTERNAL", 0, `createPlayer: pass env OR baseUrl, not both (got env=${JSON.stringify(e.env)} and baseUrl=${JSON.stringify(e.baseUrl)})`);
|
|
3608
3618
|
if (e.env !== void 0) return lt(e.env);
|
|
3609
3619
|
if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
|
|
3610
3620
|
return e.baseUrl;
|
|
3611
3621
|
}
|
|
3612
|
-
async function
|
|
3622
|
+
async function gi(e) {
|
|
3613
3623
|
if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
3614
|
-
let t =
|
|
3624
|
+
let t = hi(e);
|
|
3615
3625
|
if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
3616
3626
|
if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
|
|
3617
|
-
let r = new
|
|
3627
|
+
let r = new _i({
|
|
3618
3628
|
...e,
|
|
3619
3629
|
baseUrl: t
|
|
3620
3630
|
});
|
|
3621
3631
|
return await r.start(), r;
|
|
3622
3632
|
}
|
|
3623
|
-
var
|
|
3633
|
+
var _i = class {
|
|
3624
3634
|
opts;
|
|
3625
3635
|
abort = new AbortController();
|
|
3626
3636
|
listeners = {};
|
|
@@ -3724,7 +3734,7 @@ var gi = class {
|
|
|
3724
3734
|
setTimeout(() => {
|
|
3725
3735
|
a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
|
|
3726
3736
|
phase: i ? "unavailable" : "tooEarly",
|
|
3727
|
-
retryInMs:
|
|
3737
|
+
retryInMs: ri,
|
|
3728
3738
|
attempt: 1,
|
|
3729
3739
|
elapsedMs: 0,
|
|
3730
3740
|
...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
|
|
@@ -3763,13 +3773,13 @@ var gi = class {
|
|
|
3763
3773
|
!a && !p() && h();
|
|
3764
3774
|
}, e);
|
|
3765
3775
|
};
|
|
3766
|
-
_(
|
|
3776
|
+
_(ni), this.armingSub = D({
|
|
3767
3777
|
eventsBaseUrl: t,
|
|
3768
3778
|
matchUrn: this.opts.matchUrn,
|
|
3769
3779
|
credential: this.opts.credential,
|
|
3770
|
-
onAlive: () => _(
|
|
3780
|
+
onAlive: () => _(ri),
|
|
3771
3781
|
onState: (e) => {
|
|
3772
|
-
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() *
|
|
3782
|
+
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * ii);
|
|
3773
3783
|
},
|
|
3774
3784
|
onError: () => h()
|
|
3775
3785
|
});
|
|
@@ -3814,19 +3824,19 @@ var gi = class {
|
|
|
3814
3824
|
if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
|
|
3815
3825
|
let i = e.analytics?.sid;
|
|
3816
3826
|
if (!i) return;
|
|
3817
|
-
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } =
|
|
3827
|
+
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = Dr(this.opts.baseUrl, a, e.analytics?.endpoint);
|
|
3818
3828
|
if (!o) {
|
|
3819
3829
|
s && setTimeout(() => {
|
|
3820
3830
|
this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
|
|
3821
3831
|
}, 0);
|
|
3822
3832
|
return;
|
|
3823
3833
|
}
|
|
3824
|
-
let c = this.opts.video, l = new
|
|
3834
|
+
let c = this.opts.video, l = new Or({
|
|
3825
3835
|
endpoint: o,
|
|
3826
3836
|
sid: i,
|
|
3827
3837
|
player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
|
|
3828
|
-
sdkVersion:
|
|
3829
|
-
environment:
|
|
3838
|
+
sdkVersion: Pr,
|
|
3839
|
+
environment: Mr(c),
|
|
3830
3840
|
idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
|
|
3831
3841
|
onIdle: () => this.onAnalyticsIdle(t),
|
|
3832
3842
|
onBlocked: (e) => setTimeout(() => {
|
|
@@ -3847,7 +3857,7 @@ var gi = class {
|
|
|
3847
3857
|
let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
|
|
3848
3858
|
c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
|
|
3849
3859
|
c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
|
|
3850
|
-
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()),
|
|
3860
|
+
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), Nr().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
|
|
3851
3861
|
}
|
|
3852
3862
|
currentPresentation() {
|
|
3853
3863
|
let e = this.opts.video;
|
|
@@ -3881,9 +3891,9 @@ var gi = class {
|
|
|
3881
3891
|
freshLicenseUrl: () => this.refreshLicense()
|
|
3882
3892
|
}, o = this.opts.engine ?? "auto";
|
|
3883
3893
|
if (o === "native") return new H(a);
|
|
3884
|
-
if (o === "hls") return new
|
|
3894
|
+
if (o === "hls") return new sr(a);
|
|
3885
3895
|
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && B(this.opts.video) && V() || !e.drmEnabled && Pt() && B(this.opts.video)) return new H(a);
|
|
3886
|
-
if (Xt()) return new
|
|
3896
|
+
if (Xt()) return new sr(a);
|
|
3887
3897
|
if (B(this.opts.video)) return new H(a);
|
|
3888
3898
|
throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
|
|
3889
3899
|
}
|
|
@@ -3955,7 +3965,7 @@ var gi = class {
|
|
|
3955
3965
|
a = !0, this.emit("warning", new n(r(o.status), o.status, `live-state events answered HTTP ${o.status} for ${this.opts.matchUrn}: the match is ` + (o.terminal ? "gone, so the subscription stopped" : "not in the catalog (ended and dropped, or not listed yet), so it retries every 5 min") + " — end-of-stream detection falls back to the HLS staleness watchdog."));
|
|
3956
3966
|
return;
|
|
3957
3967
|
}
|
|
3958
|
-
i += 1, i >=
|
|
3968
|
+
i += 1, i >= ai && (a = !0, this.emit("warning", new n("NETWORK", 0, `live-state events unreachable at ${t} after ${i} 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.`)));
|
|
3959
3969
|
}
|
|
3960
3970
|
}
|
|
3961
3971
|
});
|
|
@@ -3966,9 +3976,9 @@ var gi = class {
|
|
|
3966
3976
|
reloadStaleEnd() {
|
|
3967
3977
|
if (this.destroyed || this.endedHandled || this._state === "error" || this._state === "ended") return !1;
|
|
3968
3978
|
let e = Date.now();
|
|
3969
|
-
if (this.liveStateLast !== "live" || e - this.liveStateAliveAt >
|
|
3979
|
+
if (this.liveStateLast !== "live" || e - this.liveStateAliveAt > oi || (e - this.staleEndWindowAt > ci && (this.staleEndReloads = 0, this.staleEndWindowAt = e), this.staleEndReloads >= si)) return !1;
|
|
3970
3980
|
this.staleEndReloads += 1;
|
|
3971
|
-
let t = new n("UNAVAILABLE", 0, `live playlist stopped advancing for 12 s while the match is live (live-state push heard ${Math.round((e - this.liveStateAliveAt) / 1e3)} s ago): reloading instead of ending (${this.staleEndReloads} of ${
|
|
3981
|
+
let t = new n("UNAVAILABLE", 0, `live playlist stopped advancing for 12 s while the match is live (live-state push heard ${Math.round((e - this.liveStateAliveAt) / 1e3)} s ago): reloading instead of ending (${this.staleEndReloads} of ${si} this window)`);
|
|
3972
3982
|
this.analyticsSession?.noteError(t.code, t.message, !1, 0, Math.round(this.opts.video.currentTime * 1e3), "staleEndReload");
|
|
3973
3983
|
let r = this.loadGen;
|
|
3974
3984
|
return this.emit("warning", t), Promise.resolve().then(() => {
|
|
@@ -3984,7 +3994,7 @@ var gi = class {
|
|
|
3984
3994
|
}
|
|
3985
3995
|
if (this.emit("online"), this._state !== "error" || !this._lastError) return;
|
|
3986
3996
|
let t = this._lastError.code;
|
|
3987
|
-
|
|
3997
|
+
mi(t) && (t === "NETWORK" || this.failedWhileOffline) && this.retry().catch(() => void 0);
|
|
3988
3998
|
}));
|
|
3989
3999
|
}
|
|
3990
4000
|
watchReturn() {
|
|
@@ -3994,7 +4004,7 @@ var gi = class {
|
|
|
3994
4004
|
return;
|
|
3995
4005
|
}
|
|
3996
4006
|
let e = this.hiddenAtMs;
|
|
3997
|
-
this.hiddenAtMs = null, e != null && Date.now() - e >=
|
|
4007
|
+
this.hiddenAtMs = null, e != null && Date.now() - e >= li && this.resyncLiveState();
|
|
3998
4008
|
}, this.onReturnPageShow = (e) => {
|
|
3999
4009
|
e.persisted && this.resyncLiveState();
|
|
4000
4010
|
}, document.addEventListener("visibilitychange", this.onReturnVisible), typeof window < "u" && window.addEventListener("pageshow", this.onReturnPageShow));
|
|
@@ -4026,7 +4036,7 @@ var gi = class {
|
|
|
4026
4036
|
scheduleRejoin(e) {
|
|
4027
4037
|
this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
|
|
4028
4038
|
this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
|
|
4029
|
-
}, Math.random() *
|
|
4039
|
+
}, Math.random() * ii));
|
|
4030
4040
|
}
|
|
4031
4041
|
cancelRejoin() {
|
|
4032
4042
|
this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
|
|
@@ -4050,7 +4060,7 @@ var gi = class {
|
|
|
4050
4060
|
}
|
|
4051
4061
|
t.controls = !1;
|
|
4052
4062
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
4053
|
-
r && r.insertBefore(n, t), n.appendChild(t),
|
|
4063
|
+
r && r.insertBefore(n, t), n.appendChild(t), Lr(n, this.opts.theme), this.container = n, this.controlBar = Xr({
|
|
4054
4064
|
root: n,
|
|
4055
4065
|
video: t,
|
|
4056
4066
|
player: this,
|
|
@@ -4089,7 +4099,7 @@ var gi = class {
|
|
|
4089
4099
|
}
|
|
4090
4100
|
startStats() {
|
|
4091
4101
|
this.stopStats();
|
|
4092
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
4102
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? ui);
|
|
4093
4103
|
this.statsTimer = setInterval(() => {
|
|
4094
4104
|
if (!this.engine) return;
|
|
4095
4105
|
let e = this.engine.getStats();
|
|
@@ -4100,14 +4110,14 @@ var gi = class {
|
|
|
4100
4110
|
this.statsTimer && clearInterval(this.statsTimer), this.statsTimer = void 0;
|
|
4101
4111
|
}
|
|
4102
4112
|
isStaleLicenseDenial(e) {
|
|
4103
|
-
return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !==
|
|
4113
|
+
return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== fi || e.error.httpStatus !== 403 || e.error.code !== "FORBIDDEN" || e.error.serverCode === "license_refused" ? !1 : W(this._descriptor?.drm?.widevine?.licenseUrl);
|
|
4104
4114
|
}
|
|
4105
4115
|
scheduleLicenseRefresh() {
|
|
4106
4116
|
if (this.stopRefresh(), !this._descriptor?.drmEnabled) return;
|
|
4107
4117
|
typeof document < "u" && this.engine?.name === "hls" && (this.onRefocus = () => {
|
|
4108
4118
|
document.visibilityState !== "visible" || this.destroyed || W(this._descriptor?.drm?.widevine?.licenseUrl) && this.refreshLicense();
|
|
4109
4119
|
}, document.addEventListener("visibilitychange", this.onRefocus));
|
|
4110
|
-
let e = this.opts.licenseRefreshMs ??
|
|
4120
|
+
let e = this.opts.licenseRefreshMs ?? di;
|
|
4111
4121
|
e && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
4112
4122
|
}
|
|
4113
4123
|
stopRefresh() {
|
|
@@ -4277,7 +4287,7 @@ function $(e) {
|
|
|
4277
4287
|
}
|
|
4278
4288
|
//#endregion
|
|
4279
4289
|
//#region src/embed/host.ts
|
|
4280
|
-
function
|
|
4290
|
+
function vi(e) {
|
|
4281
4291
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
4282
4292
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
4283
4293
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -4336,15 +4346,15 @@ function _i(e) {
|
|
|
4336
4346
|
}
|
|
4337
4347
|
//#endregion
|
|
4338
4348
|
//#region src/embed/page.ts
|
|
4339
|
-
var
|
|
4340
|
-
function
|
|
4349
|
+
var yi = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
4350
|
+
function bi(e) {
|
|
4341
4351
|
if (typeof e == "boolean") return e;
|
|
4342
4352
|
if (typeof e == "object" && e) {
|
|
4343
4353
|
let t = e.endpoint;
|
|
4344
4354
|
return typeof t == "string" ? { endpoint: t } : {};
|
|
4345
4355
|
}
|
|
4346
4356
|
}
|
|
4347
|
-
function
|
|
4357
|
+
function xi() {
|
|
4348
4358
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
4349
4359
|
if (e) return {
|
|
4350
4360
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -4354,7 +4364,7 @@ function bi() {
|
|
|
4354
4364
|
autoplay: e.autoplay ?? !0,
|
|
4355
4365
|
muted: e.muted ?? !0,
|
|
4356
4366
|
waitForLive: e.waitForLive ?? !0,
|
|
4357
|
-
analytics:
|
|
4367
|
+
analytics: bi(e.analytics)
|
|
4358
4368
|
};
|
|
4359
4369
|
let t = new URLSearchParams(location.search);
|
|
4360
4370
|
return {
|
|
@@ -4367,9 +4377,9 @@ function bi() {
|
|
|
4367
4377
|
waitForLive: !0
|
|
4368
4378
|
};
|
|
4369
4379
|
}
|
|
4370
|
-
async function
|
|
4371
|
-
let e =
|
|
4372
|
-
|
|
4380
|
+
async function Si() {
|
|
4381
|
+
let e = xi();
|
|
4382
|
+
wi();
|
|
4373
4383
|
let t = document.createElement("video");
|
|
4374
4384
|
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);
|
|
4375
4385
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
@@ -4425,12 +4435,12 @@ async function xi() {
|
|
|
4425
4435
|
message: e.message,
|
|
4426
4436
|
...e.country === void 0 ? {} : { country: e.country }
|
|
4427
4437
|
})), e.on("autoplayblocked", () => {
|
|
4428
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
4438
|
+
i({ type: "oddin:autoplayblocked" }), Ci(t, e);
|
|
4429
4439
|
});
|
|
4430
4440
|
}, s = async (r) => {
|
|
4431
4441
|
a?.destroy(), a = null;
|
|
4432
4442
|
try {
|
|
4433
|
-
let n = await
|
|
4443
|
+
let n = await gi({
|
|
4434
4444
|
video: t,
|
|
4435
4445
|
baseUrl: e.baseUrl,
|
|
4436
4446
|
matchUrn: r,
|
|
@@ -4493,7 +4503,7 @@ async function xi() {
|
|
|
4493
4503
|
a?.retry();
|
|
4494
4504
|
break;
|
|
4495
4505
|
case "oddin:load":
|
|
4496
|
-
typeof e.matchUrn == "string" &&
|
|
4506
|
+
typeof e.matchUrn == "string" && yi.test(e.matchUrn) && s(e.matchUrn);
|
|
4497
4507
|
break;
|
|
4498
4508
|
case "oddin:destroy": c();
|
|
4499
4509
|
}
|
|
@@ -4505,18 +4515,18 @@ async function xi() {
|
|
|
4505
4515
|
protocol: 1
|
|
4506
4516
|
});
|
|
4507
4517
|
}
|
|
4508
|
-
function
|
|
4518
|
+
function Ci(e, t) {
|
|
4509
4519
|
if (document.getElementById("havik-tap")) return;
|
|
4510
4520
|
let n = document.createElement("button");
|
|
4511
4521
|
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", () => {
|
|
4512
4522
|
n.remove(), t.play();
|
|
4513
4523
|
}), document.body.appendChild(n);
|
|
4514
4524
|
}
|
|
4515
|
-
function
|
|
4525
|
+
function wi() {
|
|
4516
4526
|
let e = document.createElement("style");
|
|
4517
4527
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
4518
4528
|
}
|
|
4519
4529
|
//#endregion
|
|
4520
|
-
export { E as LiveStateHttpError,
|
|
4530
|
+
export { E as LiveStateHttpError, Fr as ODDIN_THEME, n as PlaybackError, Lr as applyTheme, lt as baseUrlForEnv, Si as bootEmbed, ke as clearDeviceId, He as clearRememberedBandwidth, gi as createPlayer, O as deriveEventsBaseUrl, at as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, ve as fetchCatalog, be as fetchTournament, Se as flattenMatches, C as fullscreenSupported, Oe as getDeviceId, st as isLowLatencyManifest, $ as isOddinMessage, je as licenseRequestHeaders, vi as mountEmbed, fe as pollToLive, y as resolveStream, D as subscribeLiveState, S as videoFullscreenActive, we as watchStatus };
|
|
4521
4531
|
|
|
4522
4532
|
//# sourceMappingURL=index.js.map
|