@oddin-gg/havik-player 2.6.3 → 2.6.4
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 +123 -90
- 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
|
@@ -918,17 +918,17 @@ function Fe(e, t) {
|
|
|
918
918
|
function Ie() {
|
|
919
919
|
return e.isSupported();
|
|
920
920
|
}
|
|
921
|
-
var Le = 3, Re = 5, ze = 3, Be = 3e4, Ve = 12e3, He = 3e3, H = 6e3, Ue =
|
|
922
|
-
function
|
|
921
|
+
var Le = 3, Re = 5, ze = 3, Be = 3e4, Ve = 12e3, He = 3e3, H = 6e3, Ue = 5e3, We = 4e3, Ge = 2, Ke = 5, qe = 2, Je = 2, Ye = 2e3, Xe = 3e4, Ze = 2, Qe = 9, $e = .5, et = 64;
|
|
922
|
+
function tt(e) {
|
|
923
923
|
if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
|
|
924
924
|
delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
|
|
925
925
|
return;
|
|
926
926
|
}
|
|
927
|
-
e.liveSyncDuration ??=
|
|
928
|
-
let t = Math.max(12, e.liveSyncDuration +
|
|
929
|
-
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t),
|
|
927
|
+
e.liveSyncDuration ??= Ze;
|
|
928
|
+
let t = Math.max(12, e.liveSyncDuration + Qe);
|
|
929
|
+
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), nt(e, e.liveSyncDuration);
|
|
930
930
|
}
|
|
931
|
-
function
|
|
931
|
+
function nt(e, t) {
|
|
932
932
|
let n = (e, t, n) => Math.min(n, Math.max(t, e));
|
|
933
933
|
e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
|
|
934
934
|
}
|
|
@@ -960,6 +960,11 @@ var U = class {
|
|
|
960
960
|
licenseRetryTimer = null;
|
|
961
961
|
onVisibility = null;
|
|
962
962
|
onSeeking = null;
|
|
963
|
+
onPause = null;
|
|
964
|
+
onPlay = null;
|
|
965
|
+
pauseSuspendTimer = null;
|
|
966
|
+
loadSuspended = !1;
|
|
967
|
+
stopped = !1;
|
|
963
968
|
sawLive = !1;
|
|
964
969
|
lastEndSN = -1;
|
|
965
970
|
lastAdvanceMs = 0;
|
|
@@ -1002,10 +1007,34 @@ var U = class {
|
|
|
1002
1007
|
if (typeof t != "number") return;
|
|
1003
1008
|
let n = typeof e.targetLatency == "number" && e.targetLatency > 0 ? e.targetLatency : 3;
|
|
1004
1009
|
t - r.currentTime > Math.max(n * 3, 8) && (r.currentTime = t);
|
|
1005
|
-
}, document.addEventListener("visibilitychange", this.onVisibility)), this.onSeeking = () =>
|
|
1010
|
+
}, document.addEventListener("visibilitychange", this.onVisibility)), this.onSeeking = () => {
|
|
1011
|
+
this.clampOverSeek(), this.loadSuspended && (this.resumeLoading(), this.schedulePauseSuspend());
|
|
1012
|
+
}, r.addEventListener("seeking", this.onSeeking), this.onPause = () => this.schedulePauseSuspend(), this.onPlay = () => this.resumeLoading(), r.addEventListener("pause", this.onPause), r.addEventListener("play", this.onPlay), this.sizeCapManaged && typeof ResizeObserver < "u" && (this.capObserver = new ResizeObserver(() => this.onMediaResize()), this.capObserver.observe(r), this.watchDprChanges());
|
|
1013
|
+
}
|
|
1014
|
+
schedulePauseSuspend() {
|
|
1015
|
+
this.pauseSuspendTimer || this.loadSuspended || this.stopped || !this.loadStarted || (this.pauseSuspendTimer = setTimeout(() => {
|
|
1016
|
+
this.pauseSuspendTimer = null;
|
|
1017
|
+
let { video: e } = this.deps;
|
|
1018
|
+
if (e.paused && !e.ended && !this.stopped && this.hls) {
|
|
1019
|
+
try {
|
|
1020
|
+
this.hls.stopLoad();
|
|
1021
|
+
} catch {
|
|
1022
|
+
return;
|
|
1023
|
+
}
|
|
1024
|
+
this.loadSuspended = !0;
|
|
1025
|
+
}
|
|
1026
|
+
}, Ue));
|
|
1027
|
+
}
|
|
1028
|
+
resumeLoading() {
|
|
1029
|
+
if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
|
|
1030
|
+
this.lastAdvanceMs = Date.now(), this.lastFragLoadingMs = 0, this.starvedTicks = 0, this.kickPending = !1, this.kickTicks = 0;
|
|
1031
|
+
try {
|
|
1032
|
+
this.hls.startLoad(-1);
|
|
1033
|
+
} catch {}
|
|
1034
|
+
}
|
|
1006
1035
|
}
|
|
1007
1036
|
startLoad() {
|
|
1008
|
-
this.loadStarted || (this.loadStarted = !0, this.hls?.startLoad(-1));
|
|
1037
|
+
this.loadStarted || (this.loadStarted = !0, this.deps.video.paused && this.schedulePauseSuspend(), this.hls?.startLoad(-1));
|
|
1009
1038
|
}
|
|
1010
1039
|
watchDprChanges() {
|
|
1011
1040
|
if (typeof matchMedia != "function") return;
|
|
@@ -1026,7 +1055,7 @@ var U = class {
|
|
|
1026
1055
|
let t = e.liveSyncPosition;
|
|
1027
1056
|
if (typeof t != "number" || !Number.isFinite(t)) return;
|
|
1028
1057
|
let { video: n } = this.deps;
|
|
1029
|
-
n.currentTime <= t +
|
|
1058
|
+
n.currentTime <= t + $e || (n.currentTime = t);
|
|
1030
1059
|
}
|
|
1031
1060
|
startHls() {
|
|
1032
1061
|
let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps;
|
|
@@ -1066,12 +1095,12 @@ var U = class {
|
|
|
1066
1095
|
} } : {},
|
|
1067
1096
|
...c
|
|
1068
1097
|
};
|
|
1069
|
-
|
|
1098
|
+
tt(d), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.loadStarted = d.autoStartLoad !== !1;
|
|
1070
1099
|
let f = new e(d);
|
|
1071
1100
|
this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
|
|
1072
1101
|
this.mediaRecoveries = 0, this.networkRecoveries = 0;
|
|
1073
1102
|
let e = f.levels.map((e) => e.height).filter((e) => !!e);
|
|
1074
|
-
this.ladderHeights = e.length ? [...new Set(e)].sort((e, t) => e - t) : void 0, this.ladderTopBitrateKbps = f.levels.length ? Math.round(Math.max(...f.levels.map((e) => e.bitrate)) / 1e3) : 0, this.applySizeCap(), l({ type: "ready" });
|
|
1103
|
+
this.ladderHeights = e.length ? [...new Set(e)].sort((e, t) => e - t) : void 0, this.ladderTopBitrateKbps = f.levels.length ? Math.round(Math.max(...f.levels.map((e) => e.bitrate)) / 1e3) : 0, this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
|
|
1075
1104
|
}), f.on(e.Events.FRAG_BUFFERED, (e, t) => {
|
|
1076
1105
|
t?.frag?.type === "main" && (this.kickPending = !1, this.kickTicks = 0, (this.mediaRecoveries > 0 || this.networkRecoveries > 0 || this.licenseRecoveries > 0 || this.starvationKicks > 0 || this.starvationRebuilds > 0) && !this.recoveryResetTimer && (this.recoveryResetTimer = setTimeout(() => {
|
|
1077
1106
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
|
|
@@ -1082,7 +1111,7 @@ var U = class {
|
|
|
1082
1111
|
let n = t?.frag?.stats, r = n?.loaded;
|
|
1083
1112
|
typeof r == "number" && (this.bytesLoaded += r);
|
|
1084
1113
|
let i = n?.loading;
|
|
1085
|
-
i && i.end > 0 && i.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(i.end - i.start))), this.requestTimesMs.length >
|
|
1114
|
+
i && i.end > 0 && i.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(i.end - i.start))), this.requestTimesMs.length > et && this.requestTimesMs.shift());
|
|
1086
1115
|
let a = t?.frag?.url;
|
|
1087
1116
|
if (a) {
|
|
1088
1117
|
let e = L(a);
|
|
@@ -1162,7 +1191,7 @@ var U = class {
|
|
|
1162
1191
|
return;
|
|
1163
1192
|
}
|
|
1164
1193
|
this.capTimer && clearTimeout(this.capTimer);
|
|
1165
|
-
let t = e > this.sizeCapLevel ?
|
|
1194
|
+
let t = e > this.sizeCapLevel ? Ye : Xe;
|
|
1166
1195
|
this.capTimer = setTimeout(() => {
|
|
1167
1196
|
this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
|
|
1168
1197
|
}, t);
|
|
@@ -1250,27 +1279,31 @@ var U = class {
|
|
|
1250
1279
|
this.lastAdvanceMs = Date.now();
|
|
1251
1280
|
return;
|
|
1252
1281
|
}
|
|
1282
|
+
if (this.loadSuspended) {
|
|
1283
|
+
this.lastAdvanceMs = Date.now();
|
|
1284
|
+
return;
|
|
1285
|
+
}
|
|
1253
1286
|
let e = Date.now() - this.lastAdvanceMs;
|
|
1254
1287
|
!this.chaseSuspended && e > H && this.suspendChasing(), e > Ve && this.emitEnded("stalled");
|
|
1255
1288
|
}
|
|
1256
1289
|
checkStarvation() {
|
|
1257
1290
|
let e = this.hls, { video: t } = this.deps;
|
|
1258
1291
|
if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended) return;
|
|
1259
|
-
if (typeof document < "u" && document.hidden) {
|
|
1292
|
+
if (typeof document < "u" && document.hidden || this.loadSuspended) {
|
|
1260
1293
|
this.starvedTicks = 0;
|
|
1261
1294
|
return;
|
|
1262
1295
|
}
|
|
1263
|
-
let n = this.lastAdvanceMs !== 0 && Date.now() - this.lastAdvanceMs < H, r = this.lastFragLoadingMs !== 0 && Date.now() - this.lastFragLoadingMs >
|
|
1296
|
+
let n = this.lastAdvanceMs !== 0 && Date.now() - this.lastAdvanceMs < H, r = this.lastFragLoadingMs !== 0 && Date.now() - this.lastFragLoadingMs > We;
|
|
1264
1297
|
if (!(t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused && n && r)) {
|
|
1265
1298
|
this.starvedTicks = 0;
|
|
1266
1299
|
return;
|
|
1267
1300
|
}
|
|
1268
|
-
if (this.kickPending && (this.kickTicks += 1), !(++this.starvedTicks <
|
|
1269
|
-
if (this.starvedTicks = 0, this.kickPending && this.kickTicks >=
|
|
1301
|
+
if (this.kickPending && (this.kickTicks += 1), !(++this.starvedTicks < Ge)) {
|
|
1302
|
+
if (this.starvedTicks = 0, this.kickPending && this.kickTicks >= qe && (this.kickPending = !1, this.kickTicks = 0, this.starvationRebuilds < Je)) {
|
|
1270
1303
|
this.starvationRebuilds += 1, console.warn("havik-player: restarting the load did not resume video (the wedge is in hls.js state that only a rebuild clears) — rebuilding the player"), this.rebuildInstance("starvation rebuild");
|
|
1271
1304
|
return;
|
|
1272
1305
|
}
|
|
1273
|
-
if (!(this.starvationKicks >=
|
|
1306
|
+
if (!(this.starvationKicks >= Ke)) {
|
|
1274
1307
|
this.starvationKicks += 1, this.kickPending = !0, this.kickTicks = 0, console.warn("havik-player: video starved while the live playlist advances (wedged hls.js fragment pipeline) — restarting the load");
|
|
1275
1308
|
try {
|
|
1276
1309
|
e.stopLoad(), e.startLoad(-1);
|
|
@@ -1296,7 +1329,7 @@ var U = class {
|
|
|
1296
1329
|
}));
|
|
1297
1330
|
}
|
|
1298
1331
|
stop() {
|
|
1299
|
-
this.endWatchdog &&= (clearInterval(this.endWatchdog), null), this.kickPending = !1, this.kickTicks = 0;
|
|
1332
|
+
this.endWatchdog &&= (clearInterval(this.endWatchdog), null), this.kickPending = !1, this.kickTicks = 0, this.stopped = !0, this.loadSuspended = !1, this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null);
|
|
1300
1333
|
try {
|
|
1301
1334
|
this.hls?.stopLoad();
|
|
1302
1335
|
} catch {}
|
|
@@ -1305,7 +1338,7 @@ var U = class {
|
|
|
1305
1338
|
} catch {}
|
|
1306
1339
|
}
|
|
1307
1340
|
destroy() {
|
|
1308
|
-
if (this.clearRecoveryReset(), this.capTimer &&= (clearTimeout(this.capTimer), null), this.capObserver &&= (this.capObserver.disconnect(), null), this.unwatchDprChanges(), this.endWatchdog &&= (clearInterval(this.endWatchdog), null), this.onVisibility && typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), this.onVisibility = null), this.onSeeking &&= (this.deps.video.removeEventListener("seeking", this.onSeeking), null), this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null), this.licenseRetryTimer &&= (clearTimeout(this.licenseRetryTimer), null), this.hls) {
|
|
1341
|
+
if (this.clearRecoveryReset(), this.capTimer &&= (clearTimeout(this.capTimer), null), this.capObserver &&= (this.capObserver.disconnect(), null), this.unwatchDprChanges(), this.endWatchdog &&= (clearInterval(this.endWatchdog), null), this.onVisibility && typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), this.onVisibility = null), this.onSeeking &&= (this.deps.video.removeEventListener("seeking", this.onSeeking), null), this.onPause &&= (this.deps.video.removeEventListener("pause", this.onPause), null), this.onPlay &&= (this.deps.video.removeEventListener("play", this.onPlay), null), this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null), this.licenseRetryTimer &&= (clearTimeout(this.licenseRetryTimer), null), this.hls) {
|
|
1309
1342
|
try {
|
|
1310
1343
|
this.hls.destroy();
|
|
1311
1344
|
} catch (e) {
|
|
@@ -1393,11 +1426,11 @@ var U = class {
|
|
|
1393
1426
|
let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
|
|
1394
1427
|
return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
|
|
1395
1428
|
}
|
|
1396
|
-
},
|
|
1429
|
+
}, rt = 15e3, it = 100, W = 1, at = 1e3, G = 3e4, ot = 1e3, st = {
|
|
1397
1430
|
inline: "PRESENTATION_INLINE",
|
|
1398
1431
|
fullscreen: "PRESENTATION_FULLSCREEN",
|
|
1399
1432
|
pip: "PRESENTATION_PIP"
|
|
1400
|
-
},
|
|
1433
|
+
}, ct = {
|
|
1401
1434
|
widevine: "KEY_SYSTEM_WIDEVINE",
|
|
1402
1435
|
fairplay: "KEY_SYSTEM_FAIRPLAY",
|
|
1403
1436
|
none: "KEY_SYSTEM_NONE"
|
|
@@ -1405,7 +1438,7 @@ var U = class {
|
|
|
1405
1438
|
function K(e, t) {
|
|
1406
1439
|
return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
|
|
1407
1440
|
}
|
|
1408
|
-
var
|
|
1441
|
+
var lt = /* @__PURE__ */ new Set([
|
|
1409
1442
|
"INVALID_URN",
|
|
1410
1443
|
"NOT_FOUND",
|
|
1411
1444
|
"GONE",
|
|
@@ -1425,7 +1458,7 @@ var ct = /* @__PURE__ */ new Set([
|
|
|
1425
1458
|
ended: "PLAYER_STATE_ENDED",
|
|
1426
1459
|
error: "PLAYER_STATE_ERROR"
|
|
1427
1460
|
};
|
|
1428
|
-
function
|
|
1461
|
+
function ut(e) {
|
|
1429
1462
|
try {
|
|
1430
1463
|
let t = new URL(e), [n, ...r] = t.hostname.split(".");
|
|
1431
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);
|
|
@@ -1433,7 +1466,7 @@ function lt(e) {
|
|
|
1433
1466
|
return;
|
|
1434
1467
|
}
|
|
1435
1468
|
}
|
|
1436
|
-
var
|
|
1469
|
+
var dt = class {
|
|
1437
1470
|
opts;
|
|
1438
1471
|
url;
|
|
1439
1472
|
now;
|
|
@@ -1505,7 +1538,7 @@ var ut = class {
|
|
|
1505
1538
|
constructor(e) {
|
|
1506
1539
|
this.opts = {
|
|
1507
1540
|
...e,
|
|
1508
|
-
heartbeatMs: e.heartbeatMs ??
|
|
1541
|
+
heartbeatMs: e.heartbeatMs ?? rt
|
|
1509
1542
|
}, 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;
|
|
1510
1543
|
}
|
|
1511
1544
|
start() {
|
|
@@ -1515,7 +1548,7 @@ var ut = class {
|
|
|
1515
1548
|
sdkVersion: this.opts.sdkVersion,
|
|
1516
1549
|
...this.opts.environment
|
|
1517
1550
|
};
|
|
1518
|
-
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(),
|
|
1551
|
+
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), at), this.timer = setInterval(() => this.heartbeat(), this.opts.heartbeatMs), typeof window < "u" && window.addEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.addEventListener("visibilitychange", this.onVisibility), this.onVisibility());
|
|
1519
1552
|
}
|
|
1520
1553
|
noteStateChange(e, t, n, r) {
|
|
1521
1554
|
if (this.endedFlag || e === t) return;
|
|
@@ -1529,12 +1562,12 @@ var ut = class {
|
|
|
1529
1562
|
let a = {
|
|
1530
1563
|
fromState: q[e] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
1531
1564
|
toState: q[t] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
1532
|
-
presentation:
|
|
1565
|
+
presentation: st[this.presentation]
|
|
1533
1566
|
}, o = this.causeOf(e, t, i);
|
|
1534
1567
|
o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
|
|
1535
1568
|
}
|
|
1536
1569
|
seekInduced(e) {
|
|
1537
|
-
return this.lastSeekMs >= 0 && e - this.lastSeekMs <
|
|
1570
|
+
return this.lastSeekMs >= 0 && e - this.lastSeekMs < ot;
|
|
1538
1571
|
}
|
|
1539
1572
|
causeOf(e, t, n) {
|
|
1540
1573
|
if (t === "error") return "TRANSITION_CAUSE_ERROR";
|
|
@@ -1602,7 +1635,7 @@ var ut = class {
|
|
|
1602
1635
|
let r = n ?? "";
|
|
1603
1636
|
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";
|
|
1604
1637
|
if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
|
|
1605
|
-
if (
|
|
1638
|
+
if (lt.has(e)) return "ERROR_STAGE_RESOLVE";
|
|
1606
1639
|
let i = t ?? "";
|
|
1607
1640
|
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";
|
|
1608
1641
|
}
|
|
@@ -1654,7 +1687,7 @@ var ut = class {
|
|
|
1654
1687
|
maybeEmitMediaInfo(e) {
|
|
1655
1688
|
if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
|
|
1656
1689
|
let t = {};
|
|
1657
|
-
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem =
|
|
1690
|
+
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = ct[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);
|
|
1658
1691
|
let n = JSON.stringify(t);
|
|
1659
1692
|
n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
|
|
1660
1693
|
}
|
|
@@ -1694,7 +1727,7 @@ var ut = class {
|
|
|
1694
1727
|
};
|
|
1695
1728
|
}
|
|
1696
1729
|
enqueue(e) {
|
|
1697
|
-
for (this.pending.push(this.wrap(e)); this.pending.length >
|
|
1730
|
+
for (this.pending.push(this.wrap(e)); this.pending.length > it;) {
|
|
1698
1731
|
let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
|
|
1699
1732
|
this.pending.splice(e >= 0 ? e : 0, 1);
|
|
1700
1733
|
}
|
|
@@ -1717,7 +1750,7 @@ var ut = class {
|
|
|
1717
1750
|
};
|
|
1718
1751
|
//#endregion
|
|
1719
1752
|
//#region src/core/environment.ts
|
|
1720
|
-
function
|
|
1753
|
+
function ft() {
|
|
1721
1754
|
if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
|
|
1722
1755
|
let e;
|
|
1723
1756
|
try {
|
|
@@ -1742,14 +1775,14 @@ function dt() {
|
|
|
1742
1775
|
integration: "INTEGRATION_KIND_IFRAME"
|
|
1743
1776
|
};
|
|
1744
1777
|
}
|
|
1745
|
-
function
|
|
1778
|
+
function pt() {
|
|
1746
1779
|
if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
|
|
1747
1780
|
let e = navigator.userAgentData, t = e?.platform ?? "";
|
|
1748
1781
|
if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
|
|
1749
1782
|
let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
|
|
1750
1783
|
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";
|
|
1751
1784
|
}
|
|
1752
|
-
function
|
|
1785
|
+
function mt() {
|
|
1753
1786
|
let e = typeof navigator < "u" ? navigator.connection : void 0;
|
|
1754
1787
|
if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
|
|
1755
1788
|
let t = {
|
|
@@ -1768,17 +1801,17 @@ function pt() {
|
|
|
1768
1801
|
}
|
|
1769
1802
|
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;
|
|
1770
1803
|
}
|
|
1771
|
-
function
|
|
1772
|
-
let t =
|
|
1773
|
-
deviceClass:
|
|
1804
|
+
function ht(e) {
|
|
1805
|
+
let t = ft(), n = {
|
|
1806
|
+
deviceClass: pt(),
|
|
1774
1807
|
integration: t.integration,
|
|
1775
|
-
...
|
|
1808
|
+
...mt()
|
|
1776
1809
|
};
|
|
1777
1810
|
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);
|
|
1778
1811
|
let r = e.getBoundingClientRect?.();
|
|
1779
1812
|
return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
|
|
1780
1813
|
}
|
|
1781
|
-
async function
|
|
1814
|
+
async function gt() {
|
|
1782
1815
|
let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
|
|
1783
1816
|
if (!e?.getHighEntropyValues) return {};
|
|
1784
1817
|
try {
|
|
@@ -1790,7 +1823,7 @@ async function ht() {
|
|
|
1790
1823
|
}
|
|
1791
1824
|
//#endregion
|
|
1792
1825
|
//#region src/core/version.ts
|
|
1793
|
-
var
|
|
1826
|
+
var _t = "2.6.4", J = {
|
|
1794
1827
|
accent: "#E1B600",
|
|
1795
1828
|
accentText: "#1B1C23",
|
|
1796
1829
|
background: "#0e0f13",
|
|
@@ -1823,15 +1856,15 @@ function X(e, t) {
|
|
|
1823
1856
|
}
|
|
1824
1857
|
//#endregion
|
|
1825
1858
|
//#region src/ui/styles.ts
|
|
1826
|
-
var Z = "havik-player-styles",
|
|
1827
|
-
function
|
|
1859
|
+
var Z = "havik-player-styles", vt = "\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";
|
|
1860
|
+
function yt(e = document) {
|
|
1828
1861
|
if (e.getElementById(Z)) return;
|
|
1829
1862
|
let t = e.createElement("style");
|
|
1830
|
-
t.id = Z, t.textContent =
|
|
1863
|
+
t.id = Z, t.textContent = vt, e.head.appendChild(t);
|
|
1831
1864
|
}
|
|
1832
1865
|
//#endregion
|
|
1833
1866
|
//#region src/ui/icons.ts
|
|
1834
|
-
var
|
|
1867
|
+
var bt = {
|
|
1835
1868
|
play: "<path d=\"M8 5v14l11-7z\"/>",
|
|
1836
1869
|
pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
|
|
1837
1870
|
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\"/>",
|
|
@@ -1845,20 +1878,20 @@ var yt = {
|
|
|
1845
1878
|
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\"/>"
|
|
1846
1879
|
};
|
|
1847
1880
|
function Q(e) {
|
|
1848
|
-
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${
|
|
1881
|
+
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${bt[e]}</svg>`;
|
|
1849
1882
|
}
|
|
1850
1883
|
//#endregion
|
|
1851
1884
|
//#region src/ui/controls.ts
|
|
1852
|
-
var
|
|
1885
|
+
var xt = 3e3, St = /* @__PURE__ */ new Set([
|
|
1853
1886
|
"GONE",
|
|
1854
1887
|
"NOT_FOUND",
|
|
1855
1888
|
"INVALID_URN",
|
|
1856
1889
|
"UNAUTHORIZED"
|
|
1857
1890
|
]);
|
|
1858
|
-
function
|
|
1859
|
-
return new
|
|
1891
|
+
function Ct(e) {
|
|
1892
|
+
return new wt(e);
|
|
1860
1893
|
}
|
|
1861
|
-
var
|
|
1894
|
+
var wt = class {
|
|
1862
1895
|
root;
|
|
1863
1896
|
video;
|
|
1864
1897
|
player;
|
|
@@ -1900,7 +1933,7 @@ var Ct = class {
|
|
|
1900
1933
|
scrubbing = !1;
|
|
1901
1934
|
offFns = [];
|
|
1902
1935
|
constructor(e) {
|
|
1903
|
-
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ??
|
|
1936
|
+
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? xt, 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, yt(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");
|
|
1904
1937
|
let t = (e, t, n) => {
|
|
1905
1938
|
let r = this.doc.createElement(e);
|
|
1906
1939
|
if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
|
|
@@ -1991,7 +2024,7 @@ var Ct = class {
|
|
|
1991
2024
|
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);
|
|
1992
2025
|
} else {
|
|
1993
2026
|
let r = this.doc.createElement("div");
|
|
1994
|
-
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !
|
|
2027
|
+
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !St.has(this.lastError.code)) {
|
|
1995
2028
|
let e = this.doc.createElement("button");
|
|
1996
2029
|
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);
|
|
1997
2030
|
}
|
|
@@ -2032,7 +2065,7 @@ var Ct = class {
|
|
|
2032
2065
|
let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
|
|
2033
2066
|
this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
|
|
2034
2067
|
}
|
|
2035
|
-
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${
|
|
2068
|
+
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Tt(this.video.currentTime)} / ${Tt(this.video.duration)}`);
|
|
2036
2069
|
}
|
|
2037
2070
|
syncLive() {
|
|
2038
2071
|
let e = this.player.getStats(), t = e.isLive !== !1;
|
|
@@ -2082,17 +2115,17 @@ var Ct = class {
|
|
|
2082
2115
|
renderQualityMenu() {
|
|
2083
2116
|
let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
|
|
2084
2117
|
n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
|
|
2085
|
-
for (let n of e) this.menu.append(this.menuItem(
|
|
2118
|
+
for (let n of e) this.menu.append(this.menuItem(Et(n), t === n.index, () => this.player.setQuality(n.index)));
|
|
2086
2119
|
}
|
|
2087
2120
|
renderAudioMenu() {
|
|
2088
2121
|
let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
|
|
2089
2122
|
t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
|
|
2090
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
2123
|
+
for (let t of e) this.menu.append(this.menuItem(Dt(t), t.default, () => this.player.setAudioTrack(t.id)));
|
|
2091
2124
|
}
|
|
2092
2125
|
renderCcMenu() {
|
|
2093
2126
|
let e = this.player.getTextTracks(), t = this.doc.createElement("div");
|
|
2094
2127
|
t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
|
|
2095
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
2128
|
+
for (let t of e) this.menu.append(this.menuItem(Ot(t), !1, () => this.player.setTextTrack(t.id)));
|
|
2096
2129
|
}
|
|
2097
2130
|
onTracksChanged() {
|
|
2098
2131
|
this.openMenu && this.renderMenu(this.openMenu);
|
|
@@ -2192,32 +2225,32 @@ var Ct = class {
|
|
|
2192
2225
|
this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
|
|
2193
2226
|
}
|
|
2194
2227
|
};
|
|
2195
|
-
function
|
|
2228
|
+
function Tt(e) {
|
|
2196
2229
|
(!Number.isFinite(e) || e < 0) && (e = 0);
|
|
2197
2230
|
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");
|
|
2198
2231
|
return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
|
|
2199
2232
|
}
|
|
2200
|
-
function
|
|
2233
|
+
function Et(e) {
|
|
2201
2234
|
return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
|
|
2202
2235
|
}
|
|
2203
|
-
function
|
|
2236
|
+
function Dt(e) {
|
|
2204
2237
|
return e.name || e.lang || `Track ${e.id}`;
|
|
2205
2238
|
}
|
|
2206
|
-
function
|
|
2239
|
+
function Ot(e) {
|
|
2207
2240
|
return e.name || e.lang || `Track ${e.id}`;
|
|
2208
2241
|
}
|
|
2209
2242
|
//#endregion
|
|
2210
2243
|
//#region src/managed/index.ts
|
|
2211
|
-
var
|
|
2212
|
-
async function
|
|
2244
|
+
var kt = 6e3, At = 45e3, jt = 2e3, Mt = 3, Nt = 2e3, Pt = 48e4;
|
|
2245
|
+
async function Ft(e) {
|
|
2213
2246
|
if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
2214
2247
|
if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: baseUrl is required");
|
|
2215
2248
|
if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
2216
2249
|
if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
|
|
2217
|
-
let t = new
|
|
2250
|
+
let t = new It(e);
|
|
2218
2251
|
return await t.start(), t;
|
|
2219
2252
|
}
|
|
2220
|
-
var
|
|
2253
|
+
var It = class {
|
|
2221
2254
|
opts;
|
|
2222
2255
|
abort = new AbortController();
|
|
2223
2256
|
listeners = {};
|
|
@@ -2304,7 +2337,7 @@ var Ft = class {
|
|
|
2304
2337
|
setTimeout(() => {
|
|
2305
2338
|
a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
|
|
2306
2339
|
phase: i ? "unavailable" : "tooEarly",
|
|
2307
|
-
retryInMs:
|
|
2340
|
+
retryInMs: At,
|
|
2308
2341
|
attempt: 1,
|
|
2309
2342
|
elapsedMs: 0,
|
|
2310
2343
|
...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
|
|
@@ -2343,13 +2376,13 @@ var Ft = class {
|
|
|
2343
2376
|
!a && !p() && h();
|
|
2344
2377
|
}, e);
|
|
2345
2378
|
};
|
|
2346
|
-
_(
|
|
2379
|
+
_(kt), this.armingSub = E({
|
|
2347
2380
|
eventsBaseUrl: t,
|
|
2348
2381
|
matchUrn: this.opts.matchUrn,
|
|
2349
2382
|
credential: this.opts.credential,
|
|
2350
|
-
onAlive: () => _(
|
|
2383
|
+
onAlive: () => _(At),
|
|
2351
2384
|
onState: (e) => {
|
|
2352
|
-
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() *
|
|
2385
|
+
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * jt);
|
|
2353
2386
|
},
|
|
2354
2387
|
onError: () => h()
|
|
2355
2388
|
});
|
|
@@ -2391,14 +2424,14 @@ var Ft = class {
|
|
|
2391
2424
|
if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
|
|
2392
2425
|
let n = e.analytics?.sid;
|
|
2393
2426
|
if (!n) return;
|
|
2394
|
-
let r = (typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0) ??
|
|
2427
|
+
let r = (typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0) ?? ut(this.opts.baseUrl);
|
|
2395
2428
|
if (!r) return;
|
|
2396
|
-
let i = this.opts.video, a = new
|
|
2429
|
+
let i = this.opts.video, a = new dt({
|
|
2397
2430
|
endpoint: r,
|
|
2398
2431
|
sid: n,
|
|
2399
2432
|
player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
|
|
2400
|
-
sdkVersion:
|
|
2401
|
-
environment:
|
|
2433
|
+
sdkVersion: _t,
|
|
2434
|
+
environment: ht(i),
|
|
2402
2435
|
sample: () => {
|
|
2403
2436
|
let e = this.engine?.getStats() ?? I, t = i.buffered.length ? Math.max(0, i.buffered.end(i.buffered.length - 1) - i.currentTime) : 0;
|
|
2404
2437
|
return {
|
|
@@ -2414,7 +2447,7 @@ var Ft = class {
|
|
|
2414
2447
|
let o = () => a.noteSeek(), s = () => a.noteVolume(i.muted, i.volume);
|
|
2415
2448
|
i.addEventListener("seeking", o), i.addEventListener("volumechange", s), this.detachMediaListeners = () => {
|
|
2416
2449
|
i.removeEventListener("seeking", o), i.removeEventListener("volumechange", s);
|
|
2417
|
-
}, a.start(), a.seedVolume(i.muted, i.volume), a.notePresentation(this.currentPresentation()),
|
|
2450
|
+
}, a.start(), a.seedVolume(i.muted, i.volume), a.notePresentation(this.currentPresentation()), gt().then((e) => a.noteEnvironment(e)), this.opts.autoplay === !1 && a.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
|
|
2418
2451
|
}
|
|
2419
2452
|
currentPresentation() {
|
|
2420
2453
|
let e = this.opts.video;
|
|
@@ -2485,7 +2518,7 @@ var Ft = class {
|
|
|
2485
2518
|
r = 0, i = !1;
|
|
2486
2519
|
},
|
|
2487
2520
|
onError: () => {
|
|
2488
|
-
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >=
|
|
2521
|
+
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= Mt && (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.`))));
|
|
2489
2522
|
}
|
|
2490
2523
|
});
|
|
2491
2524
|
}
|
|
@@ -2507,7 +2540,7 @@ var Ft = class {
|
|
|
2507
2540
|
scheduleRejoin(e) {
|
|
2508
2541
|
this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
|
|
2509
2542
|
this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
|
|
2510
|
-
}, Math.random() *
|
|
2543
|
+
}, Math.random() * jt));
|
|
2511
2544
|
}
|
|
2512
2545
|
cancelRejoin() {
|
|
2513
2546
|
this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
|
|
@@ -2531,7 +2564,7 @@ var Ft = class {
|
|
|
2531
2564
|
}
|
|
2532
2565
|
t.controls = !1;
|
|
2533
2566
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
2534
|
-
r && r.insertBefore(n, t), n.appendChild(t), X(n, this.opts.theme), this.container = n, this.controlBar =
|
|
2567
|
+
r && r.insertBefore(n, t), n.appendChild(t), X(n, this.opts.theme), this.container = n, this.controlBar = Ct({
|
|
2535
2568
|
root: n,
|
|
2536
2569
|
video: t,
|
|
2537
2570
|
player: this,
|
|
@@ -2561,7 +2594,7 @@ var Ft = class {
|
|
|
2561
2594
|
}
|
|
2562
2595
|
startStats() {
|
|
2563
2596
|
this.stopStats();
|
|
2564
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
2597
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? Nt);
|
|
2565
2598
|
this.statsTimer = setInterval(() => {
|
|
2566
2599
|
if (!this.engine) return;
|
|
2567
2600
|
let e = this.engine.getStats();
|
|
@@ -2573,7 +2606,7 @@ var Ft = class {
|
|
|
2573
2606
|
}
|
|
2574
2607
|
scheduleLicenseRefresh() {
|
|
2575
2608
|
this.stopRefresh();
|
|
2576
|
-
let e = this.opts.licenseRefreshMs ??
|
|
2609
|
+
let e = this.opts.licenseRefreshMs ?? Pt;
|
|
2577
2610
|
e && this._descriptor?.drmEnabled && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
2578
2611
|
}
|
|
2579
2612
|
stopRefresh() {
|
|
@@ -2725,7 +2758,7 @@ function $(e) {
|
|
|
2725
2758
|
}
|
|
2726
2759
|
//#endregion
|
|
2727
2760
|
//#region src/embed/host.ts
|
|
2728
|
-
function
|
|
2761
|
+
function Lt(e) {
|
|
2729
2762
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
2730
2763
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
2731
2764
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -2784,8 +2817,8 @@ function It(e) {
|
|
|
2784
2817
|
}
|
|
2785
2818
|
//#endregion
|
|
2786
2819
|
//#region src/embed/page.ts
|
|
2787
|
-
var
|
|
2788
|
-
function
|
|
2820
|
+
var Rt = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
2821
|
+
function zt() {
|
|
2789
2822
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
2790
2823
|
if (e) return {
|
|
2791
2824
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -2807,9 +2840,9 @@ function Rt() {
|
|
|
2807
2840
|
waitForLive: !0
|
|
2808
2841
|
};
|
|
2809
2842
|
}
|
|
2810
|
-
async function
|
|
2811
|
-
let e =
|
|
2812
|
-
|
|
2843
|
+
async function Bt() {
|
|
2844
|
+
let e = zt();
|
|
2845
|
+
Ht();
|
|
2813
2846
|
let t = document.createElement("video");
|
|
2814
2847
|
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);
|
|
2815
2848
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
@@ -2864,12 +2897,12 @@ async function zt() {
|
|
|
2864
2897
|
code: e.code,
|
|
2865
2898
|
message: e.message
|
|
2866
2899
|
})), e.on("autoplayblocked", () => {
|
|
2867
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
2900
|
+
i({ type: "oddin:autoplayblocked" }), Vt(t, e);
|
|
2868
2901
|
});
|
|
2869
2902
|
}, s = async (r) => {
|
|
2870
2903
|
a?.destroy(), a = null;
|
|
2871
2904
|
try {
|
|
2872
|
-
let n = await
|
|
2905
|
+
let n = await Ft({
|
|
2873
2906
|
video: t,
|
|
2874
2907
|
baseUrl: e.baseUrl,
|
|
2875
2908
|
matchUrn: r,
|
|
@@ -2930,7 +2963,7 @@ async function zt() {
|
|
|
2930
2963
|
a?.retry();
|
|
2931
2964
|
break;
|
|
2932
2965
|
case "oddin:load":
|
|
2933
|
-
typeof e.matchUrn == "string" &&
|
|
2966
|
+
typeof e.matchUrn == "string" && Rt.test(e.matchUrn) && s(e.matchUrn);
|
|
2934
2967
|
break;
|
|
2935
2968
|
case "oddin:destroy": c();
|
|
2936
2969
|
}
|
|
@@ -2942,18 +2975,18 @@ async function zt() {
|
|
|
2942
2975
|
protocol: 1
|
|
2943
2976
|
});
|
|
2944
2977
|
}
|
|
2945
|
-
function
|
|
2978
|
+
function Vt(e, t) {
|
|
2946
2979
|
if (document.getElementById("havik-tap")) return;
|
|
2947
2980
|
let n = document.createElement("button");
|
|
2948
2981
|
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", () => {
|
|
2949
2982
|
n.remove(), t.play();
|
|
2950
2983
|
}), document.body.appendChild(n);
|
|
2951
2984
|
}
|
|
2952
|
-
function
|
|
2985
|
+
function Ht() {
|
|
2953
2986
|
let e = document.createElement("style");
|
|
2954
2987
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
2955
2988
|
}
|
|
2956
2989
|
//#endregion
|
|
2957
|
-
export { J as ODDIN_THEME, n as PlaybackError, X as applyTheme,
|
|
2990
|
+
export { J as ODDIN_THEME, n as PlaybackError, X as applyTheme, Bt as bootEmbed, _e as clearDeviceId, Ft 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, Lt as mountEmbed, oe as pollToLive, y as resolveStream, E as subscribeLiveState, C as videoFullscreenActive, he as watchStatus };
|
|
2958
2991
|
|
|
2959
2992
|
//# sourceMappingURL=index.js.map
|