@oddin-gg/havik-player 2.6.4 → 2.7.0
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/README.md +9 -2
- 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.d.cts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +144 -113
- package/dist/index.js.map +1 -1
- package/embed/index.html +1 -1
- package/examples/vanilla.html +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1426,11 +1426,11 @@ var U = class {
|
|
|
1426
1426
|
let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
|
|
1427
1427
|
return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
|
|
1428
1428
|
}
|
|
1429
|
-
}, rt = 15e3, it = 100, W = 1,
|
|
1429
|
+
}, rt = 15e3, it = 6e5, at = 3e5, ot = 100, W = 1, st = 1e3, G = 3e4, ct = 1e3, lt = {
|
|
1430
1430
|
inline: "PRESENTATION_INLINE",
|
|
1431
1431
|
fullscreen: "PRESENTATION_FULLSCREEN",
|
|
1432
1432
|
pip: "PRESENTATION_PIP"
|
|
1433
|
-
},
|
|
1433
|
+
}, ut = {
|
|
1434
1434
|
widevine: "KEY_SYSTEM_WIDEVINE",
|
|
1435
1435
|
fairplay: "KEY_SYSTEM_FAIRPLAY",
|
|
1436
1436
|
none: "KEY_SYSTEM_NONE"
|
|
@@ -1438,7 +1438,7 @@ var U = class {
|
|
|
1438
1438
|
function K(e, t) {
|
|
1439
1439
|
return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
|
|
1440
1440
|
}
|
|
1441
|
-
var
|
|
1441
|
+
var dt = /* @__PURE__ */ new Set([
|
|
1442
1442
|
"INVALID_URN",
|
|
1443
1443
|
"NOT_FOUND",
|
|
1444
1444
|
"GONE",
|
|
@@ -1458,7 +1458,7 @@ var lt = /* @__PURE__ */ new Set([
|
|
|
1458
1458
|
ended: "PLAYER_STATE_ENDED",
|
|
1459
1459
|
error: "PLAYER_STATE_ERROR"
|
|
1460
1460
|
};
|
|
1461
|
-
function
|
|
1461
|
+
function ft(e) {
|
|
1462
1462
|
try {
|
|
1463
1463
|
let t = new URL(e), [n, ...r] = t.hostname.split(".");
|
|
1464
1464
|
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);
|
|
@@ -1466,7 +1466,7 @@ function ut(e) {
|
|
|
1466
1466
|
return;
|
|
1467
1467
|
}
|
|
1468
1468
|
}
|
|
1469
|
-
var
|
|
1469
|
+
var pt = class {
|
|
1470
1470
|
opts;
|
|
1471
1471
|
url;
|
|
1472
1472
|
now;
|
|
@@ -1526,19 +1526,26 @@ var dt = class {
|
|
|
1526
1526
|
lastRequestErrors = 0;
|
|
1527
1527
|
pendingStart = null;
|
|
1528
1528
|
firstFlushTimer = null;
|
|
1529
|
+
idleTimer = null;
|
|
1530
|
+
lastTickMs = 0;
|
|
1529
1531
|
bornMs;
|
|
1530
1532
|
startupAnchorMs;
|
|
1531
1533
|
startupTimeMs = 0;
|
|
1532
1534
|
manifestLoadMs = 0;
|
|
1533
1535
|
firstFragLoadMs = 0;
|
|
1534
1536
|
onPagehide = () => this.end("END_REASON_PAGEHIDE");
|
|
1537
|
+
onFreeze = () => {
|
|
1538
|
+
this.endedFlag || this.flush(!0);
|
|
1539
|
+
};
|
|
1540
|
+
onResume = () => this.checkSuspension(this.now());
|
|
1535
1541
|
onVisibility = () => {
|
|
1536
1542
|
typeof document > "u" || (document.visibilityState === "hidden" ? (this.hiddenSinceMs === null && (this.hiddenSinceMs = this.now()), this.isHidden = !0) : (this.hiddenSinceMs !== null && (this.hiddenTotalMs += this.now() - this.hiddenSinceMs, this.hiddenSinceMs = null), this.isHidden = !1), this.syncActive(), this.syncBuffering());
|
|
1537
1543
|
};
|
|
1538
1544
|
constructor(e) {
|
|
1539
1545
|
this.opts = {
|
|
1540
1546
|
...e,
|
|
1541
|
-
heartbeatMs: e.heartbeatMs ?? rt
|
|
1547
|
+
heartbeatMs: e.heartbeatMs ?? rt,
|
|
1548
|
+
idleMs: e.idleMs ?? it
|
|
1542
1549
|
}, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`, this.now = e.now ?? (() => Date.now()), this.bornMs = this.now(), this.presentationSinceMs = this.bornMs, this.startupAnchorMs = this.bornMs;
|
|
1543
1550
|
}
|
|
1544
1551
|
start() {
|
|
@@ -1548,7 +1555,20 @@ var dt = class {
|
|
|
1548
1555
|
sdkVersion: this.opts.sdkVersion,
|
|
1549
1556
|
...this.opts.environment
|
|
1550
1557
|
};
|
|
1551
|
-
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(),
|
|
1558
|
+
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), st), 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.onVisibility());
|
|
1559
|
+
}
|
|
1560
|
+
checkSuspension(e) {
|
|
1561
|
+
if (this.endedFlag || !this.opts.idleMs) return !1;
|
|
1562
|
+
let t = Math.max(this.opts.idleMs, at);
|
|
1563
|
+
return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
|
|
1564
|
+
}
|
|
1565
|
+
syncIdle(e) {
|
|
1566
|
+
e === "paused" && this.opts.idleMs ? this.idleTimer === null && (this.idleTimer = setTimeout(() => {
|
|
1567
|
+
this.idleTimer = null, this.endIdle();
|
|
1568
|
+
}, this.opts.idleMs)) : this.idleTimer !== null && (clearTimeout(this.idleTimer), this.idleTimer = null);
|
|
1569
|
+
}
|
|
1570
|
+
endIdle(e) {
|
|
1571
|
+
this.endedFlag || (this.end("END_REASON_IDLE", e), this.opts.onIdle?.());
|
|
1552
1572
|
}
|
|
1553
1573
|
noteStateChange(e, t, n, r) {
|
|
1554
1574
|
if (this.endedFlag || e === t) return;
|
|
@@ -1558,32 +1578,32 @@ var dt = class {
|
|
|
1558
1578
|
let e = !this.isHidden && !this.stallIsSeekInduced;
|
|
1559
1579
|
e && (this.rebufferCount += 1), this.isBuffering = !0, this.lastStallMs = i, e && this.timeToFirstStallMs === 0 && (this.timeToFirstStallMs = Math.max(W, Math.round(this.playingTotalMs)));
|
|
1560
1580
|
} else e === "buffering" && (this.isBuffering = !1, this.stallIsSeekInduced = !1);
|
|
1561
|
-
this.syncBuffering(), t === "paused" && (this.pauseCount += 1);
|
|
1581
|
+
this.syncBuffering(), t === "paused" && (this.pauseCount += 1), this.syncIdle(t);
|
|
1562
1582
|
let a = {
|
|
1563
1583
|
fromState: q[e] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
1564
1584
|
toState: q[t] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
1565
|
-
presentation:
|
|
1585
|
+
presentation: lt[this.presentation]
|
|
1566
1586
|
}, o = this.causeOf(e, t, i);
|
|
1567
1587
|
o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
|
|
1568
1588
|
}
|
|
1569
1589
|
seekInduced(e) {
|
|
1570
|
-
return this.lastSeekMs >= 0 && e - this.lastSeekMs <
|
|
1590
|
+
return this.lastSeekMs >= 0 && e - this.lastSeekMs < ct;
|
|
1571
1591
|
}
|
|
1572
1592
|
causeOf(e, t, n) {
|
|
1573
1593
|
if (t === "error") return "TRANSITION_CAUSE_ERROR";
|
|
1574
1594
|
if (t === "buffering") return this.seekInduced(n) ? "TRANSITION_CAUSE_SEEK" : "TRANSITION_CAUSE_NETWORK_STALL";
|
|
1575
1595
|
if (t === "paused" || t === "playing" && e === "paused") return "TRANSITION_CAUSE_USER";
|
|
1576
1596
|
}
|
|
1577
|
-
syncActive() {
|
|
1578
|
-
let
|
|
1579
|
-
|
|
1597
|
+
syncActive(e = this.now()) {
|
|
1598
|
+
let t = this.isPlaying && !this.isHidden && !this.isMuted;
|
|
1599
|
+
t && this.activeSinceMs === null ? this.activeSinceMs = e : !t && this.activeSinceMs !== null && (this.activeTotalMs += e - this.activeSinceMs, this.activeSinceMs = null);
|
|
1580
1600
|
}
|
|
1581
1601
|
syncBuffering() {
|
|
1582
1602
|
let e = this.isBuffering && !this.isHidden && !this.stallIsSeekInduced;
|
|
1583
1603
|
e && this.bufferingSinceMs === null ? this.bufferingSinceMs = this.now() : !e && this.bufferingSinceMs !== null && (this.rebufferTotalMs += this.now() - this.bufferingSinceMs, this.bufferingSinceMs = null);
|
|
1584
1604
|
}
|
|
1585
|
-
closePresentation() {
|
|
1586
|
-
let
|
|
1605
|
+
closePresentation(e = this.now()) {
|
|
1606
|
+
let t = e - this.presentationSinceMs;
|
|
1587
1607
|
this.presentation === "fullscreen" ? this.fullscreenTotalMs += t : this.presentation === "pip" && (this.pipTotalMs += t), this.presentationSinceMs = e;
|
|
1588
1608
|
}
|
|
1589
1609
|
noteAutoplay(e) {
|
|
@@ -1635,7 +1655,7 @@ var dt = class {
|
|
|
1635
1655
|
let r = n ?? "";
|
|
1636
1656
|
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";
|
|
1637
1657
|
if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
|
|
1638
|
-
if (
|
|
1658
|
+
if (dt.has(e)) return "ERROR_STAGE_RESOLVE";
|
|
1639
1659
|
let i = t ?? "";
|
|
1640
1660
|
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";
|
|
1641
1661
|
}
|
|
@@ -1650,66 +1670,68 @@ var dt = class {
|
|
|
1650
1670
|
}
|
|
1651
1671
|
heartbeat() {
|
|
1652
1672
|
if (this.endedFlag) return;
|
|
1653
|
-
let e = this.
|
|
1654
|
-
|
|
1673
|
+
let e = this.now();
|
|
1674
|
+
if (this.checkSuspension(e)) return;
|
|
1675
|
+
let t = this.opts.sample(), n = this.playingTotalMs;
|
|
1676
|
+
this.playingSinceMs !== null && (n += e - this.playingSinceMs);
|
|
1655
1677
|
let r = this.hiddenTotalMs;
|
|
1656
|
-
this.hiddenSinceMs !== null && (r +=
|
|
1678
|
+
this.hiddenSinceMs !== null && (r += e - this.hiddenSinceMs);
|
|
1657
1679
|
let i = this.rebufferTotalMs;
|
|
1658
|
-
this.bufferingSinceMs !== null && (i +=
|
|
1680
|
+
this.bufferingSinceMs !== null && (i += e - this.bufferingSinceMs);
|
|
1659
1681
|
let a = this.activeTotalMs;
|
|
1660
|
-
this.activeSinceMs !== null && (a +=
|
|
1661
|
-
let o = {}, s =
|
|
1682
|
+
this.activeSinceMs !== null && (a += e - this.activeSinceMs);
|
|
1683
|
+
let o = {}, s = t.bytesLoaded ?? 0;
|
|
1662
1684
|
s > this.lastBytes && (o.bytesDownloadedDelta = s - this.lastBytes), this.lastBytes = s;
|
|
1663
|
-
let c =
|
|
1685
|
+
let c = t.playlistBytesLoaded ?? 0;
|
|
1664
1686
|
c > this.lastPlaylistBytes && (o.playlistBytesDelta = c - this.lastPlaylistBytes), this.lastPlaylistBytes = c;
|
|
1665
|
-
let l =
|
|
1687
|
+
let l = t.droppedFrames ?? 0;
|
|
1666
1688
|
l > this.lastDropped && (o.droppedFramesDelta = l - this.lastDropped), this.lastDropped = l;
|
|
1667
|
-
let u =
|
|
1668
|
-
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
|
|
1689
|
+
let u = t.renditionSwitches ?? 0;
|
|
1690
|
+
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 = q[t.state] ?? "PLAYER_STATE_UNSPECIFIED";
|
|
1669
1691
|
let d = this.mutedTotalMs;
|
|
1670
|
-
this.mutedSinceMs !== null && (d +=
|
|
1671
|
-
let f =
|
|
1692
|
+
this.mutedSinceMs !== null && (d += e - this.mutedSinceMs), d > this.lastHbMutedMs && (o.mutedMsDelta = Math.round(d - this.lastHbMutedMs)), this.lastHbMutedMs = d;
|
|
1693
|
+
let f = t.upshifts ?? 0;
|
|
1672
1694
|
f > this.lastUpshifts && (o.upshiftsDelta = f - this.lastUpshifts), this.lastUpshifts = f;
|
|
1673
|
-
let p =
|
|
1695
|
+
let p = t.downshifts ?? 0;
|
|
1674
1696
|
p > this.lastDownshifts && (o.downshiftsDelta = p - this.lastDownshifts), this.lastDownshifts = p;
|
|
1675
|
-
let m =
|
|
1697
|
+
let m = t.decodedFrames ?? 0;
|
|
1676
1698
|
m > this.lastDecoded && (o.decodedFramesDelta = m - this.lastDecoded), this.lastDecoded = m;
|
|
1677
|
-
let h =
|
|
1699
|
+
let h = t.requestErrors ?? 0;
|
|
1678
1700
|
h > this.lastRequestErrors && (o.requestErrorsDelta = h - this.lastRequestErrors), this.lastRequestErrors = h;
|
|
1679
|
-
let g =
|
|
1701
|
+
let g = t.requestCount ?? 0, _ = g - this.lastRequestCount;
|
|
1680
1702
|
if (this.lastRequestCount = g, _ > 0) {
|
|
1681
1703
|
o.requestCountDelta = _;
|
|
1682
|
-
let
|
|
1704
|
+
let e = t.requestTimesMs ?? [], n = e.slice(Math.max(0, e.length - _)).sort((e, t) => e - t);
|
|
1683
1705
|
n.length > 0 && (o.requestTimeP50Ms = K(n, 50), o.requestTimeP95Ms = K(n, 95));
|
|
1684
1706
|
}
|
|
1685
|
-
typeof
|
|
1707
|
+
typeof t.latencySeconds == "number" && typeof t.targetLatencySeconds == "number" && (o.driftMs = Math.round((t.latencySeconds - t.targetLatencySeconds) * 1e3)), typeof t.playbackRate == "number" && t.playbackRate > 0 && (o.playbackRate = t.playbackRate), t.qualityPinned === !0 && (o.qualityPinned = !0), t.cdnHost && (o.cdnHost = t.cdnHost), this.maybeEmitMediaInfo(t), this.enqueue({ heartbeat: o }), this.flush(), s > 0 && this.noteFirstBytes();
|
|
1686
1708
|
}
|
|
1687
1709
|
maybeEmitMediaInfo(e) {
|
|
1688
1710
|
if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
|
|
1689
1711
|
let t = {};
|
|
1690
|
-
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem =
|
|
1712
|
+
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = ut[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);
|
|
1691
1713
|
let n = JSON.stringify(t);
|
|
1692
1714
|
n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
|
|
1693
1715
|
}
|
|
1694
|
-
end(e) {
|
|
1716
|
+
end(e, t) {
|
|
1695
1717
|
if (this.endedFlag) return;
|
|
1696
1718
|
this.endedFlag = !0;
|
|
1697
|
-
let
|
|
1698
|
-
this.playingSinceMs !== null && (this.playingTotalMs +=
|
|
1699
|
-
let
|
|
1700
|
-
|
|
1701
|
-
let
|
|
1702
|
-
|
|
1703
|
-
let
|
|
1704
|
-
|
|
1705
|
-
let
|
|
1706
|
-
|
|
1707
|
-
let
|
|
1708
|
-
|
|
1709
|
-
let
|
|
1710
|
-
|
|
1711
|
-
let
|
|
1712
|
-
|
|
1719
|
+
let n = t ?? this.now();
|
|
1720
|
+
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));
|
|
1721
|
+
let r = this.safeSample();
|
|
1722
|
+
r && this.maybeEmitMediaInfo(r);
|
|
1723
|
+
let i = { reason: e }, a = r?.bytesLoaded ?? this.lastBytes;
|
|
1724
|
+
a > 0 && (i.bytesDownloadedTotal = a), this.playingTotalMs > 0 && (i.watchTimeMs = Math.round(this.playingTotalMs)), this.rebufferCount > 0 && (i.rebufferCount = this.rebufferCount), this.rebufferTotalMs > 0 && (i.rebufferTimeMs = Math.round(this.rebufferTotalMs)), this.startupTimeMs > 0 && (i.startupTimeMs = Math.round(this.startupTimeMs)), this.manifestLoadMs > 0 && (i.manifestLoadMs = Math.round(this.manifestLoadMs)), this.firstFragLoadMs > 0 && (i.firstFragLoadMs = Math.round(this.firstFragLoadMs));
|
|
1725
|
+
let o = r?.licenseTimeMs ?? 0;
|
|
1726
|
+
o > 0 && (i.licenseTimeMs = Math.round(o));
|
|
1727
|
+
let s = r?.droppedFrames ?? this.lastDropped;
|
|
1728
|
+
s > 0 && (i.droppedFramesTotal = s), this.errorCount > 0 && (i.errorCount = this.errorCount), this.hiddenTotalMs > 0 && (i.hiddenTimeMs = Math.round(this.hiddenTotalMs)), this.seekCount > 0 && (i.seekCount = this.seekCount), this.pauseCount > 0 && (i.pauseCount = this.pauseCount), this.firstAudioMs > 0 && (i.firstAudioMs = Math.round(this.firstAudioMs)), this.waitingTotalMs > 0 && (i.waitingForLiveMs = Math.round(this.waitingTotalMs)), this.timeToFirstStallMs > 0 && (i.timeToFirstStallMs = Math.round(this.timeToFirstStallMs));
|
|
1729
|
+
let c = r?.positionMs ?? 0;
|
|
1730
|
+
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));
|
|
1731
|
+
let l = e !== "END_REASON_ENDED";
|
|
1732
|
+
l && this.lastStallMs > 0 && n - this.lastStallMs <= G && (i.abandonAfterStallMs = Math.max(W, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= G && (i.abandonAfterErrorMs = Math.max(W, 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);
|
|
1733
|
+
let u = r?.decodedFrames ?? this.lastDecoded;
|
|
1734
|
+
u > 0 && (i.decodedFramesTotal = u), this.startupTimeMs === 0 && (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");
|
|
1713
1735
|
}
|
|
1714
1736
|
safeSample() {
|
|
1715
1737
|
try {
|
|
@@ -1727,7 +1749,7 @@ var dt = class {
|
|
|
1727
1749
|
};
|
|
1728
1750
|
}
|
|
1729
1751
|
enqueue(e) {
|
|
1730
|
-
for (this.pending.push(this.wrap(e)); this.pending.length >
|
|
1752
|
+
for (this.pending.push(this.wrap(e)); this.pending.length > ot;) {
|
|
1731
1753
|
let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
|
|
1732
1754
|
this.pending.splice(e >= 0 ? e : 0, 1);
|
|
1733
1755
|
}
|
|
@@ -1750,7 +1772,7 @@ var dt = class {
|
|
|
1750
1772
|
};
|
|
1751
1773
|
//#endregion
|
|
1752
1774
|
//#region src/core/environment.ts
|
|
1753
|
-
function
|
|
1775
|
+
function mt() {
|
|
1754
1776
|
if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
|
|
1755
1777
|
let e;
|
|
1756
1778
|
try {
|
|
@@ -1775,14 +1797,14 @@ function ft() {
|
|
|
1775
1797
|
integration: "INTEGRATION_KIND_IFRAME"
|
|
1776
1798
|
};
|
|
1777
1799
|
}
|
|
1778
|
-
function
|
|
1800
|
+
function ht() {
|
|
1779
1801
|
if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
|
|
1780
1802
|
let e = navigator.userAgentData, t = e?.platform ?? "";
|
|
1781
1803
|
if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
|
|
1782
1804
|
let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
|
|
1783
1805
|
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";
|
|
1784
1806
|
}
|
|
1785
|
-
function
|
|
1807
|
+
function gt() {
|
|
1786
1808
|
let e = typeof navigator < "u" ? navigator.connection : void 0;
|
|
1787
1809
|
if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
|
|
1788
1810
|
let t = {
|
|
@@ -1801,17 +1823,17 @@ function mt() {
|
|
|
1801
1823
|
}
|
|
1802
1824
|
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;
|
|
1803
1825
|
}
|
|
1804
|
-
function
|
|
1805
|
-
let t =
|
|
1806
|
-
deviceClass:
|
|
1826
|
+
function _t(e) {
|
|
1827
|
+
let t = mt(), n = {
|
|
1828
|
+
deviceClass: ht(),
|
|
1807
1829
|
integration: t.integration,
|
|
1808
|
-
...
|
|
1830
|
+
...gt()
|
|
1809
1831
|
};
|
|
1810
1832
|
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);
|
|
1811
1833
|
let r = e.getBoundingClientRect?.();
|
|
1812
1834
|
return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
|
|
1813
1835
|
}
|
|
1814
|
-
async function
|
|
1836
|
+
async function vt() {
|
|
1815
1837
|
let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
|
|
1816
1838
|
if (!e?.getHighEntropyValues) return {};
|
|
1817
1839
|
try {
|
|
@@ -1823,7 +1845,7 @@ async function gt() {
|
|
|
1823
1845
|
}
|
|
1824
1846
|
//#endregion
|
|
1825
1847
|
//#region src/core/version.ts
|
|
1826
|
-
var
|
|
1848
|
+
var yt = "2.7.0", J = {
|
|
1827
1849
|
accent: "#E1B600",
|
|
1828
1850
|
accentText: "#1B1C23",
|
|
1829
1851
|
background: "#0e0f13",
|
|
@@ -1856,15 +1878,15 @@ function X(e, t) {
|
|
|
1856
1878
|
}
|
|
1857
1879
|
//#endregion
|
|
1858
1880
|
//#region src/ui/styles.ts
|
|
1859
|
-
var Z = "havik-player-styles",
|
|
1860
|
-
function
|
|
1881
|
+
var Z = "havik-player-styles", bt = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n.havik-spinner{width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n/* A status card carries its own logo — the corner watermark would duplicate it. */\n.havik-player.havik-has-status .havik-watermark{display:none}\n\n.havik-bar{position:absolute;left:0;right:0;bottom:0;padding:0 12px 8px;\n opacity:1;transition:opacity .25s;z-index:2}\n.havik-seek{position:relative;height:16px;display:flex;align-items:center;cursor:pointer;margin-bottom:2px}\n.havik-seek__track{position:relative;width:100%;height:4px;border-radius:3px;background:rgba(255,255,255,.25)}\n.havik-seek__buffered{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:rgba(255,255,255,.4)}\n.havik-seek__played{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-seek__thumb{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;\n background:var(--havik-accent,#E1B600);transform:translate(-50%,-50%) scale(0);transition:transform .1s}\n.havik-seek:hover .havik-seek__thumb{transform:translate(-50%,-50%) scale(1)}\n\n.havik-controls{display:flex;align-items:center;gap:6px;height:40px}\n.havik-spacer{flex:1}\n.havik-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;border-radius:var(--havik-radius,8px);\n padding:0;transition:background .12s,color .12s}\n.havik-btn:hover{background:rgba(255,255,255,.12)}\n.havik-btn:focus-visible{outline:2px solid var(--havik-accent,#E1B600);outline-offset:1px}\n.havik-btn svg{width:22px;height:22px}\n\n/* The volume level is filled in accent up to the thumb, like the seek bar's\n played span — a native range input paints no \"elapsed\" side, which left the\n level readable only from the dot's position. --havik-vol (0..1) is set by\n syncVolume(); the track width and thumb size live here as variables because\n the WebKit fill has to compute the thumb centre from both. */\n.havik-vol{display:flex;align-items:center}\n.havik-vol__slider{--havik-vol-w:70px;--havik-vol-thumb:12px;--havik-vol:1;\n --havik-vol-pos:calc(var(--havik-vol-thumb) / 2 + var(--havik-vol) * (var(--havik-vol-w) - var(--havik-vol-thumb)));\n width:0;opacity:0;transition:width .18s,opacity .18s;height:4px;cursor:pointer;\n appearance:none;-webkit-appearance:none;background:transparent;border-radius:3px;margin:0 4px}\n.havik-vol:hover .havik-vol__slider,.havik-vol:focus-within .havik-vol__slider{width:var(--havik-vol-w);opacity:1}\n/* WebKit/Blink have no progress pseudo-element: paint the fill as a hard-stop\n gradient that ends at the thumb centre. */\n.havik-vol__slider::-webkit-slider-runnable-track{height:4px;border-radius:3px;\n background:linear-gradient(to right,var(--havik-accent,#E1B600) var(--havik-vol-pos),\n rgba(255,255,255,.3) var(--havik-vol-pos))}\n/* Firefox fills natively, and tracks the thumb exactly. */\n.havik-vol__slider::-moz-range-track{height:4px;border-radius:3px;background:rgba(255,255,255,.3)}\n.havik-vol__slider::-moz-range-progress{height:4px;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-vol__slider::-webkit-slider-thumb{-webkit-appearance:none;width:var(--havik-vol-thumb);\n height:var(--havik-vol-thumb);border-radius:50%;background:var(--havik-accent,#E1B600);\n margin-top:calc((4px - var(--havik-vol-thumb)) / 2)}\n.havik-vol__slider::-moz-range-thumb{width:var(--havik-vol-thumb);height:var(--havik-vol-thumb);\n border:0;border-radius:50%;background:var(--havik-accent,#E1B600)}\n\n.havik-time{font-size:12px;color:var(--havik-text-muted,#9aa0ad);\n font-variant-numeric:tabular-nums;padding:0 6px;white-space:nowrap}\n.havik-live{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;\n letter-spacing:.4px;padding:0 8px;color:var(--havik-text,#fff)}\n.havik-live svg{width:9px;height:9px;color:var(--havik-text-muted,#9aa0ad)}\n.havik-live.is-live svg{color:var(--havik-accent,#E1B600)}\n.havik-live__go{margin-left:2px;border:0;cursor:pointer;background:transparent;color:var(--havik-text-muted,#9aa0ad);\n font:inherit;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:6px}\n.havik-live.is-live .havik-live__go{display:none}\n.havik-live__go:hover{color:var(--havik-accent,#E1B600)}\n\n.havik-menu{position:absolute;bottom:54px;right:12px;min-width:170px;max-height:230px;overflow:auto;\n background:var(--havik-surface,#1B1C23);border:1px solid var(--havik-border,rgba(255,255,255,.1));\n border-radius:var(--havik-radius,8px);box-shadow:0 10px 30px rgba(0,0,0,.5);padding:6px;z-index:3}\n.havik-menu[hidden]{display:none}\n.havik-menu__title{font-size:11px;text-transform:uppercase;letter-spacing:.6px;\n color:var(--havik-text-muted,#9aa0ad);padding:6px 8px 4px}\n.havik-menu__item{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;font:inherit;font-size:13px;\n text-align:left;padding:7px 8px;border-radius:6px}\n.havik-menu__item:hover{background:var(--havik-surface-muted,#2a2c36)}\n.havik-menu__item[aria-checked=\"true\"]{color:var(--havik-accent,#E1B600);font-weight:600}\n.havik-menu__item[aria-checked=\"true\"]::after{content:'✓'}\n";
|
|
1882
|
+
function xt(e = document) {
|
|
1861
1883
|
if (e.getElementById(Z)) return;
|
|
1862
1884
|
let t = e.createElement("style");
|
|
1863
|
-
t.id = Z, t.textContent =
|
|
1885
|
+
t.id = Z, t.textContent = bt, e.head.appendChild(t);
|
|
1864
1886
|
}
|
|
1865
1887
|
//#endregion
|
|
1866
1888
|
//#region src/ui/icons.ts
|
|
1867
|
-
var
|
|
1889
|
+
var St = {
|
|
1868
1890
|
play: "<path d=\"M8 5v14l11-7z\"/>",
|
|
1869
1891
|
pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
|
|
1870
1892
|
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\"/>",
|
|
@@ -1878,20 +1900,20 @@ var bt = {
|
|
|
1878
1900
|
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\"/>"
|
|
1879
1901
|
};
|
|
1880
1902
|
function Q(e) {
|
|
1881
|
-
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${
|
|
1903
|
+
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${St[e]}</svg>`;
|
|
1882
1904
|
}
|
|
1883
1905
|
//#endregion
|
|
1884
1906
|
//#region src/ui/controls.ts
|
|
1885
|
-
var
|
|
1907
|
+
var Ct = 3e3, wt = /* @__PURE__ */ new Set([
|
|
1886
1908
|
"GONE",
|
|
1887
1909
|
"NOT_FOUND",
|
|
1888
1910
|
"INVALID_URN",
|
|
1889
1911
|
"UNAUTHORIZED"
|
|
1890
1912
|
]);
|
|
1891
|
-
function
|
|
1892
|
-
return new
|
|
1913
|
+
function Tt(e) {
|
|
1914
|
+
return new Et(e);
|
|
1893
1915
|
}
|
|
1894
|
-
var
|
|
1916
|
+
var Et = class {
|
|
1895
1917
|
root;
|
|
1896
1918
|
video;
|
|
1897
1919
|
player;
|
|
@@ -1933,7 +1955,7 @@ var wt = class {
|
|
|
1933
1955
|
scrubbing = !1;
|
|
1934
1956
|
offFns = [];
|
|
1935
1957
|
constructor(e) {
|
|
1936
|
-
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ??
|
|
1958
|
+
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Ct, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, xt(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");
|
|
1937
1959
|
let t = (e, t, n) => {
|
|
1938
1960
|
let r = this.doc.createElement(e);
|
|
1939
1961
|
if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
|
|
@@ -2024,7 +2046,7 @@ var wt = class {
|
|
|
2024
2046
|
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);
|
|
2025
2047
|
} else {
|
|
2026
2048
|
let r = this.doc.createElement("div");
|
|
2027
|
-
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !
|
|
2049
|
+
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !wt.has(this.lastError.code)) {
|
|
2028
2050
|
let e = this.doc.createElement("button");
|
|
2029
2051
|
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);
|
|
2030
2052
|
}
|
|
@@ -2065,7 +2087,7 @@ var wt = class {
|
|
|
2065
2087
|
let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
|
|
2066
2088
|
this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
|
|
2067
2089
|
}
|
|
2068
|
-
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${
|
|
2090
|
+
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Dt(this.video.currentTime)} / ${Dt(this.video.duration)}`);
|
|
2069
2091
|
}
|
|
2070
2092
|
syncLive() {
|
|
2071
2093
|
let e = this.player.getStats(), t = e.isLive !== !1;
|
|
@@ -2115,17 +2137,17 @@ var wt = class {
|
|
|
2115
2137
|
renderQualityMenu() {
|
|
2116
2138
|
let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
|
|
2117
2139
|
n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
|
|
2118
|
-
for (let n of e) this.menu.append(this.menuItem(
|
|
2140
|
+
for (let n of e) this.menu.append(this.menuItem(Ot(n), t === n.index, () => this.player.setQuality(n.index)));
|
|
2119
2141
|
}
|
|
2120
2142
|
renderAudioMenu() {
|
|
2121
2143
|
let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
|
|
2122
2144
|
t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
|
|
2123
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
2145
|
+
for (let t of e) this.menu.append(this.menuItem(kt(t), t.default, () => this.player.setAudioTrack(t.id)));
|
|
2124
2146
|
}
|
|
2125
2147
|
renderCcMenu() {
|
|
2126
2148
|
let e = this.player.getTextTracks(), t = this.doc.createElement("div");
|
|
2127
2149
|
t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
|
|
2128
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
2150
|
+
for (let t of e) this.menu.append(this.menuItem(At(t), !1, () => this.player.setTextTrack(t.id)));
|
|
2129
2151
|
}
|
|
2130
2152
|
onTracksChanged() {
|
|
2131
2153
|
this.openMenu && this.renderMenu(this.openMenu);
|
|
@@ -2225,32 +2247,32 @@ var wt = class {
|
|
|
2225
2247
|
this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
|
|
2226
2248
|
}
|
|
2227
2249
|
};
|
|
2228
|
-
function
|
|
2250
|
+
function Dt(e) {
|
|
2229
2251
|
(!Number.isFinite(e) || e < 0) && (e = 0);
|
|
2230
2252
|
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");
|
|
2231
2253
|
return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
|
|
2232
2254
|
}
|
|
2233
|
-
function
|
|
2255
|
+
function Ot(e) {
|
|
2234
2256
|
return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
|
|
2235
2257
|
}
|
|
2236
|
-
function
|
|
2258
|
+
function kt(e) {
|
|
2237
2259
|
return e.name || e.lang || `Track ${e.id}`;
|
|
2238
2260
|
}
|
|
2239
|
-
function
|
|
2261
|
+
function At(e) {
|
|
2240
2262
|
return e.name || e.lang || `Track ${e.id}`;
|
|
2241
2263
|
}
|
|
2242
2264
|
//#endregion
|
|
2243
2265
|
//#region src/managed/index.ts
|
|
2244
|
-
var
|
|
2245
|
-
async function
|
|
2266
|
+
var jt = 6e3, Mt = 45e3, Nt = 2e3, Pt = 3, Ft = 2e3, It = 48e4;
|
|
2267
|
+
async function Lt(e) {
|
|
2246
2268
|
if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
2247
2269
|
if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: baseUrl is required");
|
|
2248
2270
|
if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
2249
2271
|
if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
|
|
2250
|
-
let t = new
|
|
2272
|
+
let t = new Rt(e);
|
|
2251
2273
|
return await t.start(), t;
|
|
2252
2274
|
}
|
|
2253
|
-
var
|
|
2275
|
+
var Rt = class {
|
|
2254
2276
|
opts;
|
|
2255
2277
|
abort = new AbortController();
|
|
2256
2278
|
listeners = {};
|
|
@@ -2276,6 +2298,7 @@ var It = class {
|
|
|
2276
2298
|
analyticsSession = null;
|
|
2277
2299
|
detachMediaListeners;
|
|
2278
2300
|
playRequested = !1;
|
|
2301
|
+
idleClosed = !1;
|
|
2279
2302
|
pendingStartLoad = !1;
|
|
2280
2303
|
constructor(e) {
|
|
2281
2304
|
this.opts = e;
|
|
@@ -2337,7 +2360,7 @@ var It = class {
|
|
|
2337
2360
|
setTimeout(() => {
|
|
2338
2361
|
a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
|
|
2339
2362
|
phase: i ? "unavailable" : "tooEarly",
|
|
2340
|
-
retryInMs:
|
|
2363
|
+
retryInMs: Mt,
|
|
2341
2364
|
attempt: 1,
|
|
2342
2365
|
elapsedMs: 0,
|
|
2343
2366
|
...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
|
|
@@ -2376,13 +2399,13 @@ var It = class {
|
|
|
2376
2399
|
!a && !p() && h();
|
|
2377
2400
|
}, e);
|
|
2378
2401
|
};
|
|
2379
|
-
_(
|
|
2402
|
+
_(jt), this.armingSub = E({
|
|
2380
2403
|
eventsBaseUrl: t,
|
|
2381
2404
|
matchUrn: this.opts.matchUrn,
|
|
2382
2405
|
credential: this.opts.credential,
|
|
2383
|
-
onAlive: () => _(
|
|
2406
|
+
onAlive: () => _(Mt),
|
|
2384
2407
|
onState: (e) => {
|
|
2385
|
-
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() *
|
|
2408
|
+
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Nt);
|
|
2386
2409
|
},
|
|
2387
2410
|
onError: () => h()
|
|
2388
2411
|
});
|
|
@@ -2420,18 +2443,23 @@ var It = class {
|
|
|
2420
2443
|
this.destroyed || t !== this.loadGen || this.engine !== i || (this.analyticsSession?.noteReady(), this.emit("ready"));
|
|
2421
2444
|
}, 0));
|
|
2422
2445
|
}
|
|
2446
|
+
onAnalyticsIdle(e) {
|
|
2447
|
+
this.destroyed || this.engine !== e || (this.idleClosed = !0, this.pendingStartLoad = !1, e.stop());
|
|
2448
|
+
}
|
|
2423
2449
|
startAnalytics(e, t) {
|
|
2424
2450
|
if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
|
|
2425
2451
|
let n = e.analytics?.sid;
|
|
2426
2452
|
if (!n) return;
|
|
2427
|
-
let r = (typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0) ??
|
|
2453
|
+
let r = (typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0) ?? ft(this.opts.baseUrl);
|
|
2428
2454
|
if (!r) return;
|
|
2429
|
-
let i = this.opts.video, a = new
|
|
2455
|
+
let i = this.opts.video, a = new pt({
|
|
2430
2456
|
endpoint: r,
|
|
2431
2457
|
sid: n,
|
|
2432
2458
|
player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
|
|
2433
|
-
sdkVersion:
|
|
2434
|
-
environment:
|
|
2459
|
+
sdkVersion: yt,
|
|
2460
|
+
environment: _t(i),
|
|
2461
|
+
idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
|
|
2462
|
+
onIdle: () => this.onAnalyticsIdle(t),
|
|
2435
2463
|
sample: () => {
|
|
2436
2464
|
let e = this.engine?.getStats() ?? I, t = i.buffered.length ? Math.max(0, i.buffered.end(i.buffered.length - 1) - i.currentTime) : 0;
|
|
2437
2465
|
return {
|
|
@@ -2447,7 +2475,7 @@ var It = class {
|
|
|
2447
2475
|
let o = () => a.noteSeek(), s = () => a.noteVolume(i.muted, i.volume);
|
|
2448
2476
|
i.addEventListener("seeking", o), i.addEventListener("volumechange", s), this.detachMediaListeners = () => {
|
|
2449
2477
|
i.removeEventListener("seeking", o), i.removeEventListener("volumechange", s);
|
|
2450
|
-
}, a.start(), a.seedVolume(i.muted, i.volume), a.notePresentation(this.currentPresentation()),
|
|
2478
|
+
}, a.start(), a.seedVolume(i.muted, i.volume), a.notePresentation(this.currentPresentation()), vt().then((e) => a.noteEnvironment(e)), this.opts.autoplay === !1 && a.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
|
|
2451
2479
|
}
|
|
2452
2480
|
currentPresentation() {
|
|
2453
2481
|
let e = this.opts.video;
|
|
@@ -2518,7 +2546,7 @@ var It = class {
|
|
|
2518
2546
|
r = 0, i = !1;
|
|
2519
2547
|
},
|
|
2520
2548
|
onError: () => {
|
|
2521
|
-
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >=
|
|
2549
|
+
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= Pt && (i = !0, this.emit("warning", new n("NETWORK", 0, `live-state events unreachable at ${t} after ${r} attempts — end-of-stream detection degraded to the HLS staleness watchdog. Check the events host, the api-key's allowed origins, and CSP connect-src.`))));
|
|
2522
2550
|
}
|
|
2523
2551
|
});
|
|
2524
2552
|
}
|
|
@@ -2540,7 +2568,7 @@ var It = class {
|
|
|
2540
2568
|
scheduleRejoin(e) {
|
|
2541
2569
|
this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
|
|
2542
2570
|
this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
|
|
2543
|
-
}, Math.random() *
|
|
2571
|
+
}, Math.random() * Nt));
|
|
2544
2572
|
}
|
|
2545
2573
|
cancelRejoin() {
|
|
2546
2574
|
this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
|
|
@@ -2550,7 +2578,7 @@ var It = class {
|
|
|
2550
2578
|
this.teardownPlayback(), this.setState("waiting"), this.beginArming(e, void 0, !0);
|
|
2551
2579
|
}
|
|
2552
2580
|
teardownPlayback() {
|
|
2553
|
-
this.stopStats(), this.stopRefresh(), this.cancelRejoin(), this.closeArming(), this.closeLiveState(), this.detachMedia?.(), this.engine?.destroy(), this.engine = null, this.pendingStartLoad = !1;
|
|
2581
|
+
this.stopStats(), this.stopRefresh(), this.cancelRejoin(), this.closeArming(), this.closeLiveState(), this.detachMedia?.(), this.engine?.destroy(), this.engine = null, this.pendingStartLoad = !1, this.idleClosed = !1;
|
|
2554
2582
|
}
|
|
2555
2583
|
mountControls() {
|
|
2556
2584
|
let e = this.opts.controls ?? "custom", t = this.opts.video;
|
|
@@ -2564,7 +2592,7 @@ var It = class {
|
|
|
2564
2592
|
}
|
|
2565
2593
|
t.controls = !1;
|
|
2566
2594
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
2567
|
-
r && r.insertBefore(n, t), n.appendChild(t), X(n, this.opts.theme), this.container = n, this.controlBar =
|
|
2595
|
+
r && r.insertBefore(n, t), n.appendChild(t), X(n, this.opts.theme), this.container = n, this.controlBar = Tt({
|
|
2568
2596
|
root: n,
|
|
2569
2597
|
video: t,
|
|
2570
2598
|
player: this,
|
|
@@ -2594,7 +2622,7 @@ var It = class {
|
|
|
2594
2622
|
}
|
|
2595
2623
|
startStats() {
|
|
2596
2624
|
this.stopStats();
|
|
2597
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
2625
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? Ft);
|
|
2598
2626
|
this.statsTimer = setInterval(() => {
|
|
2599
2627
|
if (!this.engine) return;
|
|
2600
2628
|
let e = this.engine.getStats();
|
|
@@ -2606,7 +2634,7 @@ var It = class {
|
|
|
2606
2634
|
}
|
|
2607
2635
|
scheduleLicenseRefresh() {
|
|
2608
2636
|
this.stopRefresh();
|
|
2609
|
-
let e = this.opts.licenseRefreshMs ??
|
|
2637
|
+
let e = this.opts.licenseRefreshMs ?? It;
|
|
2610
2638
|
e && this._descriptor?.drmEnabled && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
2611
2639
|
}
|
|
2612
2640
|
stopRefresh() {
|
|
@@ -2629,7 +2657,10 @@ var It = class {
|
|
|
2629
2657
|
async play() {
|
|
2630
2658
|
if (this.destroyed) return;
|
|
2631
2659
|
let e = !this.playRequested;
|
|
2632
|
-
this.playRequested = !0
|
|
2660
|
+
if (this.playRequested = !0, this.idleClosed && this._state !== "ended" && this._state !== "error") {
|
|
2661
|
+
this.idleClosed = !1, await this.reload();
|
|
2662
|
+
return;
|
|
2663
|
+
}
|
|
2633
2664
|
let t = this.pendingStartLoad && this._state !== "ended" && this._state !== "error";
|
|
2634
2665
|
this.opts.autoplay === !1 && this.analyticsSession?.notePlayIntent(), t && (this.pendingStartLoad = !1, this.setState("loading"), this.engine?.startLoad());
|
|
2635
2666
|
try {
|
|
@@ -2758,7 +2789,7 @@ function $(e) {
|
|
|
2758
2789
|
}
|
|
2759
2790
|
//#endregion
|
|
2760
2791
|
//#region src/embed/host.ts
|
|
2761
|
-
function
|
|
2792
|
+
function zt(e) {
|
|
2762
2793
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
2763
2794
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
2764
2795
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -2817,8 +2848,8 @@ function Lt(e) {
|
|
|
2817
2848
|
}
|
|
2818
2849
|
//#endregion
|
|
2819
2850
|
//#region src/embed/page.ts
|
|
2820
|
-
var
|
|
2821
|
-
function
|
|
2851
|
+
var Bt = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
2852
|
+
function Vt() {
|
|
2822
2853
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
2823
2854
|
if (e) return {
|
|
2824
2855
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -2840,9 +2871,9 @@ function zt() {
|
|
|
2840
2871
|
waitForLive: !0
|
|
2841
2872
|
};
|
|
2842
2873
|
}
|
|
2843
|
-
async function
|
|
2844
|
-
let e =
|
|
2845
|
-
|
|
2874
|
+
async function Ht() {
|
|
2875
|
+
let e = Vt();
|
|
2876
|
+
Wt();
|
|
2846
2877
|
let t = document.createElement("video");
|
|
2847
2878
|
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);
|
|
2848
2879
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
@@ -2897,12 +2928,12 @@ async function Bt() {
|
|
|
2897
2928
|
code: e.code,
|
|
2898
2929
|
message: e.message
|
|
2899
2930
|
})), e.on("autoplayblocked", () => {
|
|
2900
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
2931
|
+
i({ type: "oddin:autoplayblocked" }), Ut(t, e);
|
|
2901
2932
|
});
|
|
2902
2933
|
}, s = async (r) => {
|
|
2903
2934
|
a?.destroy(), a = null;
|
|
2904
2935
|
try {
|
|
2905
|
-
let n = await
|
|
2936
|
+
let n = await Lt({
|
|
2906
2937
|
video: t,
|
|
2907
2938
|
baseUrl: e.baseUrl,
|
|
2908
2939
|
matchUrn: r,
|
|
@@ -2963,7 +2994,7 @@ async function Bt() {
|
|
|
2963
2994
|
a?.retry();
|
|
2964
2995
|
break;
|
|
2965
2996
|
case "oddin:load":
|
|
2966
|
-
typeof e.matchUrn == "string" &&
|
|
2997
|
+
typeof e.matchUrn == "string" && Bt.test(e.matchUrn) && s(e.matchUrn);
|
|
2967
2998
|
break;
|
|
2968
2999
|
case "oddin:destroy": c();
|
|
2969
3000
|
}
|
|
@@ -2975,18 +3006,18 @@ async function Bt() {
|
|
|
2975
3006
|
protocol: 1
|
|
2976
3007
|
});
|
|
2977
3008
|
}
|
|
2978
|
-
function
|
|
3009
|
+
function Ut(e, t) {
|
|
2979
3010
|
if (document.getElementById("havik-tap")) return;
|
|
2980
3011
|
let n = document.createElement("button");
|
|
2981
3012
|
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", () => {
|
|
2982
3013
|
n.remove(), t.play();
|
|
2983
3014
|
}), document.body.appendChild(n);
|
|
2984
3015
|
}
|
|
2985
|
-
function
|
|
3016
|
+
function Wt() {
|
|
2986
3017
|
let e = document.createElement("style");
|
|
2987
3018
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
2988
3019
|
}
|
|
2989
3020
|
//#endregion
|
|
2990
|
-
export { J as ODDIN_THEME, n as PlaybackError, X as applyTheme,
|
|
3021
|
+
export { J as ODDIN_THEME, n as PlaybackError, X as applyTheme, Ht as bootEmbed, _e as clearDeviceId, Lt as createPlayer, D as deriveEventsBaseUrl, Oe as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, ue as fetchCatalog, fe as fetchTournament, me as flattenMatches, A as getDeviceId, Ae as isLowLatencyManifest, $ as isOddinMessage, ye as licenseRequestHeaders, zt as mountEmbed, oe as pollToLive, y as resolveStream, E as subscribeLiveState, C as videoFullscreenActive, he as watchStatus };
|
|
2991
3022
|
|
|
2992
3023
|
//# sourceMappingURL=index.js.map
|