@oddin-gg/havik-player 2.16.5 → 2.16.7
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 +263 -223
- package/dist/index.js.map +1 -1
- package/docs/API.md +14 -12
- package/embed/index.html +1 -1
- package/examples/vanilla.html +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -818,32 +818,32 @@ function Ke(e) {
|
|
|
818
818
|
}
|
|
819
819
|
//#endregion
|
|
820
820
|
//#region src/core/stats.ts
|
|
821
|
-
var
|
|
822
|
-
function
|
|
821
|
+
var qe = { droppedFrames: 0 };
|
|
822
|
+
function z(e) {
|
|
823
823
|
try {
|
|
824
824
|
return new URL(e).host;
|
|
825
825
|
} catch {
|
|
826
826
|
return "";
|
|
827
827
|
}
|
|
828
828
|
}
|
|
829
|
-
var
|
|
830
|
-
function
|
|
829
|
+
var Je = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
|
|
830
|
+
function Ye(e) {
|
|
831
831
|
if (typeof performance > "u" || typeof performance.getEntriesByType != "function") return "";
|
|
832
832
|
let t = "", n = -1, r = performance.getEntriesByType("resource");
|
|
833
|
-
for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" ||
|
|
834
|
-
let e =
|
|
833
|
+
for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || Je.test(i.name)) && i.startTime >= n) {
|
|
834
|
+
let e = z(i.name);
|
|
835
835
|
e && (t = e, n = i.startTime);
|
|
836
836
|
}
|
|
837
837
|
return t;
|
|
838
838
|
}
|
|
839
|
-
function
|
|
839
|
+
function B(e) {
|
|
840
840
|
let t = e.getVideoPlaybackQuality?.();
|
|
841
841
|
return {
|
|
842
842
|
dropped: t?.droppedVideoFrames ?? 0,
|
|
843
843
|
totalFrames: t?.totalVideoFrames ?? 0
|
|
844
844
|
};
|
|
845
845
|
}
|
|
846
|
-
var
|
|
846
|
+
var V = class {
|
|
847
847
|
video;
|
|
848
848
|
baseFrames = 0;
|
|
849
849
|
baseDropped = 0;
|
|
@@ -853,7 +853,7 @@ var H = class {
|
|
|
853
853
|
this.video = e;
|
|
854
854
|
}
|
|
855
855
|
read() {
|
|
856
|
-
let e =
|
|
856
|
+
let e = B(this.video);
|
|
857
857
|
return e.totalFrames < this.lastFrames && (this.baseFrames += this.lastFrames), e.dropped < this.lastDropped && (this.baseDropped += this.lastDropped), this.lastFrames = e.totalFrames, this.lastDropped = e.dropped, {
|
|
858
858
|
dropped: this.baseDropped + e.dropped,
|
|
859
859
|
totalFrames: this.baseFrames + e.totalFrames
|
|
@@ -866,7 +866,7 @@ var H = class {
|
|
|
866
866
|
};
|
|
867
867
|
}
|
|
868
868
|
};
|
|
869
|
-
function
|
|
869
|
+
function Xe(e, t) {
|
|
870
870
|
let n = [
|
|
871
871
|
["playing", () => t("playing")],
|
|
872
872
|
["waiting", () => t("buffering")],
|
|
@@ -883,8 +883,8 @@ function Ye(e, t) {
|
|
|
883
883
|
}
|
|
884
884
|
//#endregion
|
|
885
885
|
//#region src/core/engine/native.ts
|
|
886
|
-
var
|
|
887
|
-
function
|
|
886
|
+
var Ze = 2e3, Qe = 3, H = 500, $e = 6e3, et = .25;
|
|
887
|
+
function tt(e) {
|
|
888
888
|
try {
|
|
889
889
|
let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
|
|
890
890
|
return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
|
|
@@ -892,20 +892,20 @@ function et(e) {
|
|
|
892
892
|
return;
|
|
893
893
|
}
|
|
894
894
|
}
|
|
895
|
-
function
|
|
895
|
+
function U(e) {
|
|
896
896
|
return !!(e ?? (typeof document < "u" ? document.createElement("video") : void 0))?.canPlayType("application/vnd.apple.mpegurl");
|
|
897
897
|
}
|
|
898
|
-
function
|
|
898
|
+
function W() {
|
|
899
899
|
if (typeof window > "u") return !1;
|
|
900
900
|
let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
|
|
901
901
|
return e || t;
|
|
902
902
|
}
|
|
903
|
-
function
|
|
904
|
-
if (typeof navigator > "u" || !
|
|
903
|
+
function nt() {
|
|
904
|
+
if (typeof navigator > "u" || !W()) return !1;
|
|
905
905
|
let e = navigator.userAgent ?? "";
|
|
906
906
|
return /iPhone|iPad|iPod/.test(e) ? !0 : /Macintosh/.test(e) && typeof navigator.maxTouchPoints == "number" && navigator.maxTouchPoints > 1;
|
|
907
907
|
}
|
|
908
|
-
var
|
|
908
|
+
var G = class {
|
|
909
909
|
name = "native";
|
|
910
910
|
deps;
|
|
911
911
|
onLoaded;
|
|
@@ -927,7 +927,7 @@ var K = class {
|
|
|
927
927
|
frameCounter;
|
|
928
928
|
detachFrames = null;
|
|
929
929
|
constructor(e) {
|
|
930
|
-
this.deps = e, this.frameCounter = new
|
|
930
|
+
this.deps = e, this.frameCounter = new V(e.video), this.loadStarted = e.deferLoad !== !0, this.builtAt = typeof performance < "u" ? performance.now() : 0;
|
|
931
931
|
}
|
|
932
932
|
async load() {
|
|
933
933
|
this.detachFrames ??= this.frameCounter.attach();
|
|
@@ -948,7 +948,7 @@ var K = class {
|
|
|
948
948
|
type: "error",
|
|
949
949
|
error: new n("INTERNAL", 0, "native HLS playback error"),
|
|
950
950
|
fatal: !0
|
|
951
|
-
}), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src =
|
|
951
|
+
}), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = rt(t.manifestUrl, t.analytics?.sid), e.load();
|
|
952
952
|
}
|
|
953
953
|
startLoad() {
|
|
954
954
|
this.loadStarted || (this.loadStarted = !0, this.restorePreload());
|
|
@@ -970,7 +970,7 @@ var K = class {
|
|
|
970
970
|
});
|
|
971
971
|
this.onEncrypted = (n) => {
|
|
972
972
|
let i = n;
|
|
973
|
-
i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV =
|
|
973
|
+
i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = tt(i.initData), (async () => {
|
|
974
974
|
try {
|
|
975
975
|
let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
|
|
976
976
|
initDataTypes: [i.initDataType],
|
|
@@ -1069,7 +1069,7 @@ var K = class {
|
|
|
1069
1069
|
droppedFrames: t.dropped,
|
|
1070
1070
|
decodedFrames: t.totalFrames
|
|
1071
1071
|
};
|
|
1072
|
-
if (this.cdnHost ||=
|
|
1072
|
+
if (this.cdnHost ||= Ye(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity) {
|
|
1073
1073
|
if (n.isLive = !0, e.seekable.length > 0) {
|
|
1074
1074
|
let t = e.seekable.end(e.seekable.length - 1);
|
|
1075
1075
|
n.atLiveEdge = e.currentTime >= t - 2;
|
|
@@ -1092,7 +1092,7 @@ var K = class {
|
|
|
1092
1092
|
return;
|
|
1093
1093
|
}
|
|
1094
1094
|
let t = this.hiddenSince;
|
|
1095
|
-
this.hiddenSince = null, t != null && e - t >=
|
|
1095
|
+
this.hiddenSince = null, t != null && e - t >= Ze && this.armRefocus();
|
|
1096
1096
|
}, this.onPageShow = (e) => {
|
|
1097
1097
|
e.persisted && this.armRefocus();
|
|
1098
1098
|
}, document.addEventListener("visibilitychange", this.onVisibility), typeof window < "u" && window.addEventListener("pageshow", this.onPageShow));
|
|
@@ -1101,15 +1101,15 @@ var K = class {
|
|
|
1101
1101
|
if (this.cancelRefocus(), Number.isFinite(this.deps.video.duration)) return;
|
|
1102
1102
|
let e = this.liveEnd(), t = () => typeof performance < "u" ? performance.now() : Date.now(), n = t(), r = 0, i = () => {
|
|
1103
1103
|
if (this.refocusTimer = null, Number.isFinite(this.deps.video.duration)) return;
|
|
1104
|
-
r +=
|
|
1105
|
-
let a = this.liveEnd(), o = a != null && (e == null || a >= e +
|
|
1104
|
+
r += H;
|
|
1105
|
+
let a = this.liveEnd(), o = a != null && (e == null || a >= e + et), s = Math.max(r, t() - n) >= $e;
|
|
1106
1106
|
if (o || s && a != null) {
|
|
1107
1107
|
this.snapToLive();
|
|
1108
1108
|
return;
|
|
1109
1109
|
}
|
|
1110
|
-
this.refocusTimer = setTimeout(i,
|
|
1110
|
+
this.refocusTimer = setTimeout(i, H);
|
|
1111
1111
|
};
|
|
1112
|
-
this.refocusTimer = setTimeout(i,
|
|
1112
|
+
this.refocusTimer = setTimeout(i, H);
|
|
1113
1113
|
}
|
|
1114
1114
|
cancelRefocus() {
|
|
1115
1115
|
this.refocusTimer != null && clearTimeout(this.refocusTimer), this.refocusTimer = null;
|
|
@@ -1123,7 +1123,7 @@ var K = class {
|
|
|
1123
1123
|
snapToLive() {
|
|
1124
1124
|
let e = this.deps.video, t = this.liveEnd();
|
|
1125
1125
|
if (t == null) return;
|
|
1126
|
-
let n = e.seekable.start(e.seekable.length - 1), r = Math.min(e.currentTime, t), i = Math.max(n, t -
|
|
1126
|
+
let n = e.seekable.start(e.seekable.length - 1), r = Math.min(e.currentTime, t), i = Math.max(n, t - Qe, r);
|
|
1127
1127
|
try {
|
|
1128
1128
|
e.currentTime = i;
|
|
1129
1129
|
} catch {}
|
|
@@ -1141,13 +1141,25 @@ var K = class {
|
|
|
1141
1141
|
} catch {}
|
|
1142
1142
|
}
|
|
1143
1143
|
};
|
|
1144
|
-
function
|
|
1144
|
+
function rt(e, t) {
|
|
1145
1145
|
return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
|
|
1146
1146
|
}
|
|
1147
1147
|
//#endregion
|
|
1148
|
+
//#region src/core/drm/signedUrl.ts
|
|
1149
|
+
function K(e, t = Date.now()) {
|
|
1150
|
+
if (!e) return !1;
|
|
1151
|
+
let n;
|
|
1152
|
+
try {
|
|
1153
|
+
n = new URL(e).searchParams.get("exp");
|
|
1154
|
+
} catch {
|
|
1155
|
+
return !1;
|
|
1156
|
+
}
|
|
1157
|
+
return !n || !/^\d+$/.test(n) ? !1 : Number(n) * 1e3 <= t;
|
|
1158
|
+
}
|
|
1159
|
+
//#endregion
|
|
1148
1160
|
//#region src/core/engine/prefetch.ts
|
|
1149
|
-
var
|
|
1150
|
-
function
|
|
1161
|
+
var it = 15e3, at = 5e3, ot = 6;
|
|
1162
|
+
function st(e) {
|
|
1151
1163
|
try {
|
|
1152
1164
|
let t = new URL(e);
|
|
1153
1165
|
return t.searchParams.delete("CMCD"), t.toString();
|
|
@@ -1155,7 +1167,7 @@ function ot(e) {
|
|
|
1155
1167
|
return e;
|
|
1156
1168
|
}
|
|
1157
1169
|
}
|
|
1158
|
-
var
|
|
1170
|
+
var ct = class {
|
|
1159
1171
|
cmcd;
|
|
1160
1172
|
entries = /* @__PURE__ */ new Map();
|
|
1161
1173
|
keyed = /* @__PURE__ */ new Set();
|
|
@@ -1178,10 +1190,10 @@ var st = class {
|
|
|
1178
1190
|
}
|
|
1179
1191
|
prefetch(e, t, n) {
|
|
1180
1192
|
if (!this.isActive(t)) return;
|
|
1181
|
-
let r =
|
|
1193
|
+
let r = st(e);
|
|
1182
1194
|
if (this.entries.has(r)) return;
|
|
1183
1195
|
let i = this.perTrack.get(t) ?? 0;
|
|
1184
|
-
if (i >=
|
|
1196
|
+
if (i >= ot) return;
|
|
1185
1197
|
this.perTrack.set(t, i + 1);
|
|
1186
1198
|
let a = new AbortController(), o = {
|
|
1187
1199
|
started: performance.now(),
|
|
@@ -1195,10 +1207,10 @@ var st = class {
|
|
|
1195
1207
|
signal: a.signal
|
|
1196
1208
|
}).then(async (e) => (o.first = performance.now(), e.ok ? e.arrayBuffer() : null)).catch(() => null), this.entries.set(r, o), this.stats.started += 1, setTimeout(() => {
|
|
1197
1209
|
this.entries.get(r) === o && (this.entries.delete(r), a.abort(), this.stats.expired += 1);
|
|
1198
|
-
},
|
|
1210
|
+
}, it);
|
|
1199
1211
|
}
|
|
1200
1212
|
take(e) {
|
|
1201
|
-
let t =
|
|
1213
|
+
let t = st(e), n = this.entries.get(t);
|
|
1202
1214
|
return n && this.entries.delete(t), n;
|
|
1203
1215
|
}
|
|
1204
1216
|
destroy() {
|
|
@@ -1218,13 +1230,13 @@ var st = class {
|
|
|
1218
1230
|
}
|
|
1219
1231
|
}
|
|
1220
1232
|
};
|
|
1221
|
-
function
|
|
1233
|
+
function lt(t) {
|
|
1222
1234
|
let n = e.DefaultConfig?.loader;
|
|
1223
1235
|
if (typeof n != "function") return;
|
|
1224
1236
|
class r extends n {
|
|
1225
1237
|
served = !1;
|
|
1226
1238
|
cancelled = !1;
|
|
1227
|
-
stats =
|
|
1239
|
+
stats = ut();
|
|
1228
1240
|
load(e, n, r) {
|
|
1229
1241
|
let i = e.rangeEnd ? void 0 : t.take(e.url);
|
|
1230
1242
|
if (!i) {
|
|
@@ -1232,7 +1244,7 @@ function ct(t) {
|
|
|
1232
1244
|
return;
|
|
1233
1245
|
}
|
|
1234
1246
|
this.served = !0;
|
|
1235
|
-
let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs ||
|
|
1247
|
+
let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || at, s = setTimeout(() => {
|
|
1236
1248
|
!this.cancelled && this.served && (i.abort.abort(), t.stats.failed += 1, this.served = !1, super.load(e, n, r));
|
|
1237
1249
|
}, o);
|
|
1238
1250
|
i.bytes.then((o) => {
|
|
@@ -1259,7 +1271,7 @@ function ct(t) {
|
|
|
1259
1271
|
}
|
|
1260
1272
|
return r;
|
|
1261
1273
|
}
|
|
1262
|
-
function
|
|
1274
|
+
function ut() {
|
|
1263
1275
|
return {
|
|
1264
1276
|
aborted: !1,
|
|
1265
1277
|
loaded: 0,
|
|
@@ -1283,10 +1295,10 @@ function lt() {
|
|
|
1283
1295
|
}
|
|
1284
1296
|
};
|
|
1285
1297
|
}
|
|
1286
|
-
function
|
|
1298
|
+
function dt(e) {
|
|
1287
1299
|
return e === "audio" ? "audio" : "main";
|
|
1288
1300
|
}
|
|
1289
|
-
function
|
|
1301
|
+
function ft(e, t) {
|
|
1290
1302
|
let n = [];
|
|
1291
1303
|
t.initSegment?.url && !t.initSegment.data && n.push({
|
|
1292
1304
|
url: t.initSegment.url,
|
|
@@ -1305,24 +1317,24 @@ function dt(e, t) {
|
|
|
1305
1317
|
}
|
|
1306
1318
|
//#endregion
|
|
1307
1319
|
//#region src/core/engine/hls.ts
|
|
1308
|
-
function
|
|
1320
|
+
function pt() {
|
|
1309
1321
|
return e.isSupported();
|
|
1310
1322
|
}
|
|
1311
|
-
var
|
|
1312
|
-
function
|
|
1323
|
+
var mt = 3, ht = 5, gt = 3, _t = 1e4, vt = 3e4, yt = 12e3, bt = 3e3, xt = .02, St = 6e3, Ct = .5, wt = 3, Tt = .5, Et = 1.1, Dt = .25, Ot = 5e3, kt = 4e3, At = 2, jt = 5, Mt = 2, Nt = 2, Pt = 4, Ft = 4, It = 2e3, Lt = 3e4, Rt = .2, zt = 30, Bt = 2, Vt = 2, Ht = 9, Ut = .5, Wt = 64;
|
|
1324
|
+
function Gt(e) {
|
|
1313
1325
|
if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
|
|
1314
1326
|
delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
|
|
1315
1327
|
return;
|
|
1316
1328
|
}
|
|
1317
|
-
e.liveSyncDuration ??=
|
|
1318
|
-
let t = Math.max(12, e.liveSyncDuration +
|
|
1319
|
-
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t),
|
|
1329
|
+
e.liveSyncDuration ??= Vt;
|
|
1330
|
+
let t = Math.max(12, e.liveSyncDuration + Ht);
|
|
1331
|
+
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), Kt(e, e.liveSyncDuration);
|
|
1320
1332
|
}
|
|
1321
|
-
function
|
|
1333
|
+
function Kt(e, t) {
|
|
1322
1334
|
let n = (e, t, n) => Math.min(n, Math.max(t, e));
|
|
1323
1335
|
e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
|
|
1324
1336
|
}
|
|
1325
|
-
var
|
|
1337
|
+
var qt = class {
|
|
1326
1338
|
name = "hls";
|
|
1327
1339
|
hls = null;
|
|
1328
1340
|
deps;
|
|
@@ -1402,11 +1414,11 @@ var Wt = class {
|
|
|
1402
1414
|
frameCounter;
|
|
1403
1415
|
detachFrames = null;
|
|
1404
1416
|
constructor(e) {
|
|
1405
|
-
this.deps = e, this.frameCounter = new
|
|
1417
|
+
this.deps = e, this.frameCounter = new V(e.video), this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
|
|
1406
1418
|
}
|
|
1407
1419
|
async load() {
|
|
1408
1420
|
this.detachFrames ??= this.frameCounter.attach();
|
|
1409
|
-
let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a =
|
|
1421
|
+
let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = U(r) && W(), o = !!e.drm?.widevine?.licenseUrl && !a;
|
|
1410
1422
|
if (e.drmEnabled && !o) {
|
|
1411
1423
|
i({
|
|
1412
1424
|
type: "error",
|
|
@@ -1438,7 +1450,7 @@ var Wt = class {
|
|
|
1438
1450
|
}
|
|
1439
1451
|
this.loadSuspended = !0;
|
|
1440
1452
|
}
|
|
1441
|
-
},
|
|
1453
|
+
}, Ot));
|
|
1442
1454
|
}
|
|
1443
1455
|
resumeLoading() {
|
|
1444
1456
|
if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
|
|
@@ -1470,7 +1482,22 @@ var Wt = class {
|
|
|
1470
1482
|
let t = e.liveSyncPosition;
|
|
1471
1483
|
if (typeof t != "number" || !Number.isFinite(t)) return;
|
|
1472
1484
|
let { video: n } = this.deps;
|
|
1473
|
-
n.currentTime <= t +
|
|
1485
|
+
n.currentTime <= t + Ut || (n.currentTime = t);
|
|
1486
|
+
}
|
|
1487
|
+
reanchorPartTimeline(e, t) {
|
|
1488
|
+
let { frag: n, part: r } = t;
|
|
1489
|
+
if (!r || r.index !== 0 || n.type !== "main" || typeof n.sn != "number") return;
|
|
1490
|
+
let i = e.levels[n.level]?.details;
|
|
1491
|
+
if (!i?.live) return;
|
|
1492
|
+
let a = r.elementaryStreams.video ?? r.elementaryStreams.audiovideo ?? r.elementaryStreams.audio;
|
|
1493
|
+
if (!a) return;
|
|
1494
|
+
let o = n.sn, s = i.fragments.find((e) => e && e.sn === o) ?? (i.fragmentHint?.sn === o ? i.fragmentHint : void 0);
|
|
1495
|
+
if (!s) return;
|
|
1496
|
+
let c = a.startPTS - s.start;
|
|
1497
|
+
if (!(!Number.isFinite(c) || Math.abs(c) < xt)) {
|
|
1498
|
+
for (let e of i.fragments) e && e.setStart(e.start + c);
|
|
1499
|
+
i.fragmentHint?.setStart(i.fragmentHint.start + c), this.deps.debug === !0 && console.info(`havik-player: LL-HLS timeline re-anchored by ${c >= 0 ? "+" : ""}${c.toFixed(3)}s at sn ${n.sn} (level ${n.level})`);
|
|
1500
|
+
}
|
|
1474
1501
|
}
|
|
1475
1502
|
startHls() {
|
|
1476
1503
|
let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps;
|
|
@@ -1496,10 +1523,21 @@ var Wt = class {
|
|
|
1496
1523
|
},
|
|
1497
1524
|
...j() ? { requestMediaKeySystemAccessFunc: P(t) } : {},
|
|
1498
1525
|
licenseXhrSetup: (e, t) => {
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1526
|
+
let o = performance.now(), s = () => {
|
|
1527
|
+
e.open("POST", this.licenseUrl ?? t, !0), e.setRequestHeader("x-api-key", r.apiKey), e.setRequestHeader("X-Match-Urn", n.matchUrn), e.setRequestHeader("X-Device-Id", i), a && e.setRequestHeader("X-User-Id", a), this.licenseRequested = !0, e.addEventListener("loadend", () => {
|
|
1528
|
+
this.licenseTimeMs === 0 && (this.licenseTimeMs = Math.max(1, Math.round(performance.now() - o)));
|
|
1529
|
+
});
|
|
1530
|
+
}, { freshLicenseUrl: c } = this.deps;
|
|
1531
|
+
if (!c || !K(this.licenseUrl)) {
|
|
1532
|
+
s();
|
|
1533
|
+
return;
|
|
1534
|
+
}
|
|
1535
|
+
let l = this.hls, u, d = new Promise((e) => {
|
|
1536
|
+
u = setTimeout(() => e(void 0), _t);
|
|
1537
|
+
});
|
|
1538
|
+
return Promise.race([c().catch(() => void 0), d]).finally(() => clearTimeout(u)).then((e) => {
|
|
1539
|
+
if (!this.hls || this.hls !== l) throw Error("havik-player: engine torn down during refresh");
|
|
1540
|
+
e && (this.licenseUrl = e), s();
|
|
1503
1541
|
});
|
|
1504
1542
|
}
|
|
1505
1543
|
} : {},
|
|
@@ -1511,20 +1549,20 @@ var Wt = class {
|
|
|
1511
1549
|
...c
|
|
1512
1550
|
};
|
|
1513
1551
|
if (this.prefetch?.destroy(), this.prefetch = null, u && this.deps.mediaDuringKey !== !1 && !d.fLoader) {
|
|
1514
|
-
let e = new
|
|
1552
|
+
let e = new ct({
|
|
1515
1553
|
sessionId: n.analytics?.sid,
|
|
1516
1554
|
contentId: n.matchUrn
|
|
1517
|
-
}), t =
|
|
1555
|
+
}), t = lt(e);
|
|
1518
1556
|
t && (this.prefetch = e, d.fLoader = t);
|
|
1519
1557
|
}
|
|
1520
|
-
|
|
1558
|
+
Gt(d), this.catchUpRate = typeof d.maxLiveSyncPlaybackRate == "number" ? d.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (d.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = d.autoStartLoad !== !1;
|
|
1521
1559
|
let f = new e(d);
|
|
1522
|
-
if (this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
|
|
1560
|
+
if (this.hls = f, f.on(e.Events.FRAG_PARSED, (e, t) => this.reanchorPartTimeline(f, t)), f.on(e.Events.MANIFEST_PARSED, () => {
|
|
1523
1561
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, u && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && this.dropLevelsWidevineCannotPlay(f), this.measureLadder(f), this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
|
|
1524
1562
|
}), f.on(e.Events.FRAG_BUFFERED, (e, t) => {
|
|
1525
1563
|
t?.frag?.type === "main" && (this.kickKind !== "dead" && this.clearKick(), (this.mediaRecoveries > 0 || this.networkRecoveries > 0 || this.licenseRecoveries > 0 || this.starvationKicks > 0 || this.starvationRebuilds > 0) && !this.recoveryResetTimer && (this.recoveryResetTimer = setTimeout(() => {
|
|
1526
1564
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
|
|
1527
|
-
},
|
|
1565
|
+
}, vt)));
|
|
1528
1566
|
}), f.on(e.Events.FRAG_LOADING, (e, t) => {
|
|
1529
1567
|
t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
|
|
1530
1568
|
}), f.on(e.Events.FRAG_LOADED, (e, t) => {
|
|
@@ -1532,10 +1570,10 @@ var Wt = class {
|
|
|
1532
1570
|
let n = t?.frag?.stats, r = n?.loaded;
|
|
1533
1571
|
typeof r == "number" && (this.bytesLoaded += r), !this.reportedFirstBytes && typeof r == "number" && r > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
|
|
1534
1572
|
let i = n?.loading;
|
|
1535
|
-
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 >
|
|
1573
|
+
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 > Wt && this.requestTimesMs.shift());
|
|
1536
1574
|
let a = t?.frag?.url;
|
|
1537
1575
|
if (a) {
|
|
1538
|
-
let e =
|
|
1576
|
+
let e = z(a);
|
|
1539
1577
|
e && (this.cdnHost = e);
|
|
1540
1578
|
}
|
|
1541
1579
|
}), f.on(e.Events.LEVEL_LOADED, (e, t) => {
|
|
@@ -1549,15 +1587,15 @@ var Wt = class {
|
|
|
1549
1587
|
}), f.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.prefetch) {
|
|
1550
1588
|
let t = this.prefetch;
|
|
1551
1589
|
f.on(e.Events.KEY_LOADING, (e, n) => {
|
|
1552
|
-
let r = n?.frag, i =
|
|
1553
|
-
if (r && t.isActive(i)) for (let e of
|
|
1554
|
-
}), f.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(
|
|
1590
|
+
let r = n?.frag, i = dt(r?.type);
|
|
1591
|
+
if (r && t.isActive(i)) for (let e of ft(f, r)) t.prefetch(e.url, i, e.kind);
|
|
1592
|
+
}), f.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(dt(n?.frag?.type)));
|
|
1555
1593
|
}
|
|
1556
1594
|
f.on(e.Events.KEY_LOADED, () => {
|
|
1557
1595
|
u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
|
|
1558
1596
|
}), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
|
|
1559
1597
|
this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.checkFrameDrops();
|
|
1560
|
-
},
|
|
1598
|
+
}, bt), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
|
|
1561
1599
|
this.renditionSwitches += 1;
|
|
1562
1600
|
let n = this.lastLevelIndex >= 0 ? f.levels[this.lastLevelIndex] : void 0, r = f.levels[t.level];
|
|
1563
1601
|
n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, l({
|
|
@@ -1621,7 +1659,7 @@ var Wt = class {
|
|
|
1621
1659
|
return;
|
|
1622
1660
|
}
|
|
1623
1661
|
this.capTimer && clearTimeout(this.capTimer);
|
|
1624
|
-
let t = e > this.sizeCapLevel ?
|
|
1662
|
+
let t = e > this.sizeCapLevel ? It : Lt;
|
|
1625
1663
|
this.capTimer = setTimeout(() => {
|
|
1626
1664
|
this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
|
|
1627
1665
|
}, t);
|
|
@@ -1742,7 +1780,7 @@ var Wt = class {
|
|
|
1742
1780
|
return;
|
|
1743
1781
|
}
|
|
1744
1782
|
let e = Date.now() - this.lastAdvanceMs;
|
|
1745
|
-
!this.chaseSuspended && e >
|
|
1783
|
+
!this.chaseSuspended && e > St && this.suspendChasing(), e > yt && this.emitEnded("stalled");
|
|
1746
1784
|
}
|
|
1747
1785
|
resetStarvationWindow() {
|
|
1748
1786
|
this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
|
|
@@ -1757,7 +1795,7 @@ var Wt = class {
|
|
|
1757
1795
|
this.resetStarvationWindow();
|
|
1758
1796
|
return;
|
|
1759
1797
|
}
|
|
1760
|
-
let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs <
|
|
1798
|
+
let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < St, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > kt, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = B(t), c = o - s, l = c !== this.starvedFrames;
|
|
1761
1799
|
if (this.starvedFrames = c, !a || l) {
|
|
1762
1800
|
(t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
|
|
1763
1801
|
return;
|
|
@@ -1766,12 +1804,12 @@ var Wt = class {
|
|
|
1766
1804
|
this.resetStarvationWindow();
|
|
1767
1805
|
return;
|
|
1768
1806
|
}
|
|
1769
|
-
if (this.kickPending && (this.kickKind === "dead" || i) && (this.kickTicks += 1), this.starvedTicks = i ? this.starvedTicks + 1 : 0, this.deadTicks += 1, this.recentMainFrags.push(this.mainFragsSinceTick), this.mainFragsSinceTick = 0, this.recentMainFrags.length >
|
|
1807
|
+
if (this.kickPending && (this.kickKind === "dead" || i) && (this.kickTicks += 1), this.starvedTicks = i ? this.starvedTicks + 1 : 0, this.deadTicks += 1, this.recentMainFrags.push(this.mainFragsSinceTick), this.mainFragsSinceTick = 0, this.recentMainFrags.length > Pt && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= Mt && (this.clearKick(), this.starvationRebuilds < Nt)) {
|
|
1770
1808
|
this.starvationRebuilds += 1, this.resetStarvationWindow(), this.clearRecoveryReset(), console.warn("havik-player: restarting the load did not resume video (the wedge is in hls.js state that only a rebuild clears) — rebuilding the player"), this.rebuildInstance("starvation rebuild");
|
|
1771
1809
|
return;
|
|
1772
1810
|
}
|
|
1773
|
-
let u = i && this.starvedTicks >=
|
|
1774
|
-
if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >=
|
|
1811
|
+
let u = i && this.starvedTicks >= At, d = !i && this.deadTicks >= Pt && this.recentMainFrags.reduce((e, t) => e + t, 0) >= Ft;
|
|
1812
|
+
if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= jt))) {
|
|
1775
1813
|
this.starvationKicks += 1, this.kickPending = !0, this.kickTicks = 0, this.kickKind = d ? "dead" : "quiet", this.clearRecoveryReset(), console.warn(d ? "havik-player: video starved while hls.js keeps loading media it never plays (dead pipeline at the live edge) — restarting the load" : "havik-player: video starved while the live playlist advances (wedged hls.js fragment pipeline) — restarting the load");
|
|
1776
1814
|
try {
|
|
1777
1815
|
e.stopLoad(), e.startLoad(-1);
|
|
@@ -1786,7 +1824,7 @@ var Wt = class {
|
|
|
1786
1824
|
let t = e.latency, n = e.targetLatency;
|
|
1787
1825
|
if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
|
|
1788
1826
|
let r = t - n;
|
|
1789
|
-
!this.catchUpEngaged && r >
|
|
1827
|
+
!this.catchUpEngaged && r > Ct ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= Ct && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
|
|
1790
1828
|
let i = this.catchUpEngaged ? this.catchUpRate : 1;
|
|
1791
1829
|
e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
|
|
1792
1830
|
}
|
|
@@ -1807,16 +1845,16 @@ var Wt = class {
|
|
|
1807
1845
|
this.resetFrameDropWindow();
|
|
1808
1846
|
return;
|
|
1809
1847
|
}
|
|
1810
|
-
let { totalFrames: n, dropped: r } =
|
|
1811
|
-
if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a <
|
|
1848
|
+
let { totalFrames: n, dropped: r } = B(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
|
|
1849
|
+
if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < zt || o < 0) {
|
|
1812
1850
|
this.fpsBadTicks = 0;
|
|
1813
1851
|
return;
|
|
1814
1852
|
}
|
|
1815
|
-
if (o <=
|
|
1853
|
+
if (o <= Rt * a) {
|
|
1816
1854
|
this.fpsBadTicks = 0;
|
|
1817
1855
|
return;
|
|
1818
1856
|
}
|
|
1819
|
-
if (this.fpsBadTicks += 1, this.fpsBadTicks <
|
|
1857
|
+
if (this.fpsBadTicks += 1, this.fpsBadTicks < Bt) return;
|
|
1820
1858
|
this.fpsBadTicks = 0;
|
|
1821
1859
|
let s = e.levels, c = s[e.currentLevel];
|
|
1822
1860
|
if (!c) return;
|
|
@@ -1833,20 +1871,20 @@ var Wt = class {
|
|
|
1833
1871
|
return;
|
|
1834
1872
|
}
|
|
1835
1873
|
let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
|
|
1836
|
-
if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(
|
|
1874
|
+
if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(Et, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
|
|
1837
1875
|
this.resetChaseWindow();
|
|
1838
1876
|
return;
|
|
1839
1877
|
}
|
|
1840
|
-
if (this.chaseLatency < 0 || this.chaseLatency - n >=
|
|
1878
|
+
if (this.chaseLatency < 0 || this.chaseLatency - n >= Tt) {
|
|
1841
1879
|
this.chaseLatency = n, this.chaseTicks = 0;
|
|
1842
1880
|
return;
|
|
1843
1881
|
}
|
|
1844
|
-
if (this.chaseTicks += 1, this.chaseTicks <
|
|
1882
|
+
if (this.chaseTicks += 1, this.chaseTicks < wt) return;
|
|
1845
1883
|
this.resetChaseWindow();
|
|
1846
1884
|
let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
|
|
1847
1885
|
if (!(a > 1)) return;
|
|
1848
1886
|
let o = typeof e.targetLatency == "number" ? e.targetLatency : 0, s = Math.min(n, a - 1);
|
|
1849
|
-
s < o +
|
|
1887
|
+
s < o + Dt || (console.warn(`havik-player: catch-up at ${r}x not gaining on the live edge (latency ${n.toFixed(1)}s); holding at ${s.toFixed(1)}s`), this.liveRetargets += 1, e.targetLatency = s);
|
|
1850
1888
|
}
|
|
1851
1889
|
suspendChasing() {
|
|
1852
1890
|
let e = this.hls;
|
|
@@ -1891,7 +1929,7 @@ var Wt = class {
|
|
|
1891
1929
|
scheduleLicenseRetry(t) {
|
|
1892
1930
|
if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
|
|
1893
1931
|
let n = t.response?.code ?? 0;
|
|
1894
|
-
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >=
|
|
1932
|
+
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= gt) return !1;
|
|
1895
1933
|
this.licenseRecoveries += 1;
|
|
1896
1934
|
let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
|
|
1897
1935
|
return this.licenseRetryTimer = setTimeout(() => {
|
|
@@ -1923,7 +1961,7 @@ var Wt = class {
|
|
|
1923
1961
|
return;
|
|
1924
1962
|
}
|
|
1925
1963
|
if (t.type === e.ErrorTypes.NETWORK_ERROR) {
|
|
1926
|
-
if (this.networkRecoveries <
|
|
1964
|
+
if (this.networkRecoveries < ht) {
|
|
1927
1965
|
this.networkRecoveries += 1;
|
|
1928
1966
|
let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
|
|
1929
1967
|
this.networkRetryTimer = setTimeout(() => {
|
|
@@ -1940,7 +1978,7 @@ var Wt = class {
|
|
|
1940
1978
|
return;
|
|
1941
1979
|
}
|
|
1942
1980
|
if (t.type === e.ErrorTypes.MEDIA_ERROR) {
|
|
1943
|
-
if (this.mediaRecoveries <
|
|
1981
|
+
if (this.mediaRecoveries < mt) {
|
|
1944
1982
|
this.mediaRecoveries += 1, n.recoverMediaError();
|
|
1945
1983
|
return;
|
|
1946
1984
|
}
|
|
@@ -1964,34 +2002,19 @@ var Wt = class {
|
|
|
1964
2002
|
let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
|
|
1965
2003
|
return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
|
|
1966
2004
|
}
|
|
1967
|
-
}
|
|
1968
|
-
//#endregion
|
|
1969
|
-
//#region src/core/drm/signedUrl.ts
|
|
1970
|
-
function Gt(e, t = Date.now()) {
|
|
1971
|
-
if (!e) return !1;
|
|
1972
|
-
let n;
|
|
1973
|
-
try {
|
|
1974
|
-
n = new URL(e).searchParams.get("exp");
|
|
1975
|
-
} catch {
|
|
1976
|
-
return !1;
|
|
1977
|
-
}
|
|
1978
|
-
return !n || !/^\d+$/.test(n) ? !1 : Number(n) * 1e3 <= t;
|
|
1979
|
-
}
|
|
1980
|
-
//#endregion
|
|
1981
|
-
//#region src/core/analytics.ts
|
|
1982
|
-
var Kt = 15e3, qt = 6e5, Jt = 3e5, Yt = 100, q = 1, Xt = 1e3, Zt = 3e4, Qt = 1e3, $t = {
|
|
2005
|
+
}, Jt = 15e3, Yt = 6e5, Xt = 3e5, Zt = 100, q = 1, Qt = 1e3, $t = 3e4, en = 1e3, tn = {
|
|
1983
2006
|
inline: "PRESENTATION_INLINE",
|
|
1984
2007
|
fullscreen: "PRESENTATION_FULLSCREEN",
|
|
1985
2008
|
pip: "PRESENTATION_PIP"
|
|
1986
|
-
},
|
|
2009
|
+
}, nn = {
|
|
1987
2010
|
widevine: "KEY_SYSTEM_WIDEVINE",
|
|
1988
2011
|
fairplay: "KEY_SYSTEM_FAIRPLAY",
|
|
1989
2012
|
none: "KEY_SYSTEM_NONE"
|
|
1990
2013
|
};
|
|
1991
|
-
function
|
|
2014
|
+
function rn(e, t) {
|
|
1992
2015
|
return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
|
|
1993
2016
|
}
|
|
1994
|
-
var
|
|
2017
|
+
var an = /* @__PURE__ */ new Set([
|
|
1995
2018
|
"INVALID_URN",
|
|
1996
2019
|
"NOT_FOUND",
|
|
1997
2020
|
"GONE",
|
|
@@ -2011,7 +2034,7 @@ var nn = /* @__PURE__ */ new Set([
|
|
|
2011
2034
|
ended: "PLAYER_STATE_ENDED",
|
|
2012
2035
|
error: "PLAYER_STATE_ERROR"
|
|
2013
2036
|
};
|
|
2014
|
-
function
|
|
2037
|
+
function on(e) {
|
|
2015
2038
|
try {
|
|
2016
2039
|
let t = new URL(e), [n, ...r] = t.hostname.split(".");
|
|
2017
2040
|
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);
|
|
@@ -2019,8 +2042,8 @@ function rn(e) {
|
|
|
2019
2042
|
return;
|
|
2020
2043
|
}
|
|
2021
2044
|
}
|
|
2022
|
-
var
|
|
2023
|
-
function
|
|
2045
|
+
var sn = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), cn = /* @__PURE__ */ new Set(), Y = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), ln = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
|
|
2046
|
+
function un(e) {
|
|
2024
2047
|
if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
|
|
2025
2048
|
let t;
|
|
2026
2049
|
try {
|
|
@@ -2029,19 +2052,19 @@ function cn(e) {
|
|
|
2029
2052
|
} catch {
|
|
2030
2053
|
return;
|
|
2031
2054
|
}
|
|
2032
|
-
if (
|
|
2033
|
-
Y.add(t), g(
|
|
2055
|
+
if (cn.has(t) && !Y.has(t)) {
|
|
2056
|
+
Y.add(t), g(ln(new URL(t).origin));
|
|
2034
2057
|
for (let e of X) e.noteCspBlocked();
|
|
2035
2058
|
}
|
|
2036
2059
|
}
|
|
2037
|
-
function
|
|
2060
|
+
function dn(e, t) {
|
|
2038
2061
|
return g(t, e), { disabledReason: t };
|
|
2039
2062
|
}
|
|
2040
|
-
function
|
|
2041
|
-
if (n) return t && !
|
|
2063
|
+
function fn(e, t, n) {
|
|
2064
|
+
if (n) return t && !sn(t, n) && g(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
|
|
2042
2065
|
if (t) return { endpoint: t };
|
|
2043
|
-
if (t !== void 0) return
|
|
2044
|
-
let r =
|
|
2066
|
+
if (t !== void 0) return dn("empty-endpoint", "analytics is disabled: no QoE beacons will be sent. analytics.endpoint was supplied but empty. Pass a real beacons origin, analytics: { endpoint: 'https://beacons[-dev].<domain>' }, or omit the option to derive it from baseUrl (or analytics: false to opt out).");
|
|
2067
|
+
let r = on(e);
|
|
2045
2068
|
if (r) return { endpoint: r };
|
|
2046
2069
|
let i;
|
|
2047
2070
|
try {
|
|
@@ -2049,9 +2072,9 @@ function un(e, t, n) {
|
|
|
2049
2072
|
} catch {
|
|
2050
2073
|
i = e;
|
|
2051
2074
|
}
|
|
2052
|
-
return
|
|
2075
|
+
return dn(i, `analytics is disabled: no QoE beacons will be sent. The beacons endpoint cannot be derived from the baseUrl host "${i}" — the convention is feed[-dev].<domain> → beacons[-dev].<domain>. Pass an explicit endpoint, analytics: { endpoint: 'https://beacons[-dev].<domain>' }, to createPlayer (or analytics: false to opt out deliberately).`);
|
|
2053
2076
|
}
|
|
2054
|
-
var
|
|
2077
|
+
var pn = class {
|
|
2055
2078
|
opts;
|
|
2056
2079
|
url;
|
|
2057
2080
|
cspKey;
|
|
@@ -2133,8 +2156,8 @@ var dn = class {
|
|
|
2133
2156
|
constructor(e) {
|
|
2134
2157
|
this.opts = {
|
|
2135
2158
|
...e,
|
|
2136
|
-
heartbeatMs: e.heartbeatMs ??
|
|
2137
|
-
idleMs: e.idleMs ??
|
|
2159
|
+
heartbeatMs: e.heartbeatMs ?? Jt,
|
|
2160
|
+
idleMs: e.idleMs ?? Yt
|
|
2138
2161
|
}, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
|
|
2139
2162
|
try {
|
|
2140
2163
|
let e = new URL(this.url);
|
|
@@ -2151,11 +2174,11 @@ var dn = class {
|
|
|
2151
2174
|
sdkVersion: this.opts.sdkVersion,
|
|
2152
2175
|
...this.opts.environment
|
|
2153
2176
|
};
|
|
2154
|
-
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(),
|
|
2177
|
+
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Qt), this.lastTickMs = this.now(), this.timer = setInterval(() => this.heartbeat(), this.opts.heartbeatMs), typeof window < "u" && window.addEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.addEventListener("visibilitychange", this.onVisibility), document.addEventListener("freeze", this.onFreeze), document.addEventListener("resume", this.onResume), this.cspKey && cn.add(this.cspKey), document.addEventListener("securitypolicyviolation", un), X.add(this), this.noteCspBlocked(), this.onVisibility());
|
|
2155
2178
|
}
|
|
2156
2179
|
checkSuspension(e) {
|
|
2157
2180
|
if (this.endedFlag || !this.opts.idleMs) return !1;
|
|
2158
|
-
let t = Math.max(this.opts.idleMs,
|
|
2181
|
+
let t = Math.max(this.opts.idleMs, Xt);
|
|
2159
2182
|
return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
|
|
2160
2183
|
}
|
|
2161
2184
|
syncIdle(e) {
|
|
@@ -2178,12 +2201,12 @@ var dn = class {
|
|
|
2178
2201
|
let a = {
|
|
2179
2202
|
fromState: J[e] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2180
2203
|
toState: J[t] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
2181
|
-
presentation:
|
|
2204
|
+
presentation: tn[this.presentation]
|
|
2182
2205
|
}, o = this.causeOf(e, t, i);
|
|
2183
2206
|
o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
|
|
2184
2207
|
}
|
|
2185
2208
|
seekInduced(e) {
|
|
2186
|
-
return this.lastSeekMs >= 0 && e - this.lastSeekMs <
|
|
2209
|
+
return this.lastSeekMs >= 0 && e - this.lastSeekMs < en;
|
|
2187
2210
|
}
|
|
2188
2211
|
causeOf(e, t, n) {
|
|
2189
2212
|
if (t === "error") return "TRANSITION_CAUSE_ERROR";
|
|
@@ -2257,7 +2280,7 @@ var dn = class {
|
|
|
2257
2280
|
let r = n ?? "";
|
|
2258
2281
|
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";
|
|
2259
2282
|
if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
|
|
2260
|
-
if (
|
|
2283
|
+
if (an.has(e)) return "ERROR_STAGE_RESOLVE";
|
|
2261
2284
|
let i = t ?? "";
|
|
2262
2285
|
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";
|
|
2263
2286
|
}
|
|
@@ -2304,14 +2327,14 @@ var dn = class {
|
|
|
2304
2327
|
if (this.lastRequestCount = g, _ > 0) {
|
|
2305
2328
|
o.requestCountDelta = _;
|
|
2306
2329
|
let e = t.requestTimesMs ?? [], n = e.slice(Math.max(0, e.length - _)).sort((e, t) => e - t);
|
|
2307
|
-
n.length > 0 && (o.requestTimeP50Ms =
|
|
2330
|
+
n.length > 0 && (o.requestTimeP50Ms = rn(n, 50), o.requestTimeP95Ms = rn(n, 95));
|
|
2308
2331
|
}
|
|
2309
2332
|
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();
|
|
2310
2333
|
}
|
|
2311
2334
|
maybeEmitMediaInfo(e) {
|
|
2312
2335
|
if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
|
|
2313
2336
|
let t = {};
|
|
2314
|
-
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem =
|
|
2337
|
+
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = nn[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);
|
|
2315
2338
|
let n = JSON.stringify(t);
|
|
2316
2339
|
n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
|
|
2317
2340
|
}
|
|
@@ -2331,7 +2354,7 @@ var dn = class {
|
|
|
2331
2354
|
let c = r?.positionMs ?? 0;
|
|
2332
2355
|
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));
|
|
2333
2356
|
let l = e !== "END_REASON_ENDED";
|
|
2334
|
-
l && this.lastStallMs > 0 && n - this.lastStallMs <=
|
|
2357
|
+
l && this.lastStallMs > 0 && n - this.lastStallMs <= $t && (i.abandonAfterStallMs = Math.max(q, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= $t && (i.abandonAfterErrorMs = Math.max(q, 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);
|
|
2335
2358
|
let u = r?.decodedFrames ?? this.lastDecoded;
|
|
2336
2359
|
u > 0 && (i.decodedFramesTotal = u), e === "END_REASON_STOPPED" && this.startupTimeMs === 0 && this.lastErrorStage === null && (e = "END_REASON_ABORTED", i.reason = e), this.startupTimeMs === 0 && e !== "END_REASON_ABORTED" && (i.failedStage = this.lastErrorStage ?? (this.manifestLoadMs === 0 ? "ERROR_STAGE_MANIFEST" : this.firstFragLoadMs === 0 ? "ERROR_STAGE_FIRST_SEGMENT" : "ERROR_STAGE_OTHER")), this.pending.push(this.wrap({ sessionEnd: i })), this.flush(e === "END_REASON_PAGEHIDE");
|
|
2337
2360
|
}
|
|
@@ -2351,13 +2374,13 @@ var dn = class {
|
|
|
2351
2374
|
};
|
|
2352
2375
|
}
|
|
2353
2376
|
noteCspBlocked() {
|
|
2354
|
-
this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(
|
|
2377
|
+
this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(ln(new URL(this.url).origin)));
|
|
2355
2378
|
}
|
|
2356
2379
|
cspBlocked() {
|
|
2357
2380
|
return !!this.cspKey && Y.has(this.cspKey);
|
|
2358
2381
|
}
|
|
2359
2382
|
enqueue(e) {
|
|
2360
|
-
if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length >
|
|
2383
|
+
if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > Zt;) {
|
|
2361
2384
|
let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
|
|
2362
2385
|
this.pending.splice(e >= 0 ? e : 0, 1);
|
|
2363
2386
|
}
|
|
@@ -2384,7 +2407,7 @@ var dn = class {
|
|
|
2384
2407
|
};
|
|
2385
2408
|
//#endregion
|
|
2386
2409
|
//#region src/core/environment.ts
|
|
2387
|
-
function
|
|
2410
|
+
function mn() {
|
|
2388
2411
|
if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
|
|
2389
2412
|
let e;
|
|
2390
2413
|
try {
|
|
@@ -2409,14 +2432,14 @@ function fn() {
|
|
|
2409
2432
|
integration: "INTEGRATION_KIND_IFRAME"
|
|
2410
2433
|
};
|
|
2411
2434
|
}
|
|
2412
|
-
function
|
|
2435
|
+
function hn() {
|
|
2413
2436
|
if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
|
|
2414
2437
|
let e = navigator.userAgentData, t = e?.platform ?? "";
|
|
2415
2438
|
if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
|
|
2416
2439
|
let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
|
|
2417
2440
|
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";
|
|
2418
2441
|
}
|
|
2419
|
-
function
|
|
2442
|
+
function gn() {
|
|
2420
2443
|
let e = typeof navigator < "u" ? navigator.connection : void 0;
|
|
2421
2444
|
if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
|
|
2422
2445
|
let t = {
|
|
@@ -2435,17 +2458,17 @@ function mn() {
|
|
|
2435
2458
|
}
|
|
2436
2459
|
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;
|
|
2437
2460
|
}
|
|
2438
|
-
function
|
|
2439
|
-
let t =
|
|
2440
|
-
deviceClass:
|
|
2461
|
+
function _n(e) {
|
|
2462
|
+
let t = mn(), n = {
|
|
2463
|
+
deviceClass: hn(),
|
|
2441
2464
|
integration: t.integration,
|
|
2442
|
-
...
|
|
2465
|
+
...gn()
|
|
2443
2466
|
};
|
|
2444
2467
|
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);
|
|
2445
2468
|
let r = e.getBoundingClientRect?.();
|
|
2446
2469
|
return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
|
|
2447
2470
|
}
|
|
2448
|
-
async function
|
|
2471
|
+
async function vn() {
|
|
2449
2472
|
let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
|
|
2450
2473
|
if (!e?.getHighEntropyValues) return {};
|
|
2451
2474
|
try {
|
|
@@ -2457,7 +2480,7 @@ async function gn() {
|
|
|
2457
2480
|
}
|
|
2458
2481
|
//#endregion
|
|
2459
2482
|
//#region src/core/version.ts
|
|
2460
|
-
var
|
|
2483
|
+
var yn = "2.16.7", bn = {
|
|
2461
2484
|
accent: "#E1B600",
|
|
2462
2485
|
accentText: "#1B1C23",
|
|
2463
2486
|
background: "#0e0f13",
|
|
@@ -2468,7 +2491,7 @@ var _n = "2.16.5", vn = {
|
|
|
2468
2491
|
border: "rgba(255, 255, 255, 0.1)",
|
|
2469
2492
|
radius: "8px",
|
|
2470
2493
|
fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
|
|
2471
|
-
},
|
|
2494
|
+
}, xn = {
|
|
2472
2495
|
accent: "--havik-accent",
|
|
2473
2496
|
accentText: "--havik-accent-text",
|
|
2474
2497
|
background: "--havik-bg",
|
|
@@ -2480,26 +2503,26 @@ var _n = "2.16.5", vn = {
|
|
|
2480
2503
|
radius: "--havik-radius",
|
|
2481
2504
|
fontFamily: "--havik-font"
|
|
2482
2505
|
};
|
|
2483
|
-
function
|
|
2506
|
+
function Sn(e, t) {
|
|
2484
2507
|
let n = {
|
|
2485
|
-
...
|
|
2508
|
+
...bn,
|
|
2486
2509
|
...t
|
|
2487
2510
|
};
|
|
2488
|
-
for (let t of Object.keys(
|
|
2511
|
+
for (let t of Object.keys(xn)) e.style.setProperty(xn[t], n[t]);
|
|
2489
2512
|
n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
|
|
2490
2513
|
}
|
|
2491
2514
|
//#endregion
|
|
2492
2515
|
//#region src/ui/styles.ts
|
|
2493
|
-
var
|
|
2494
|
-
function
|
|
2495
|
-
let n = e.querySelector(`style#${
|
|
2496
|
-
if (n && (!t ||
|
|
2516
|
+
var Cn = "havik-player-styles", wn = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer;\n touch-action:manipulation}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n/* Absolutely centred, NOT a flex sibling of .havik-center: the hidden center\n button (.havik-gone) still occupies its 74px in the row, which pushed an\n in-flow spinner 37px right of centre. */\n.havik-spinner{position:absolute;inset:0;margin:auto;width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n/* A status card carries its own logo — the corner watermark would duplicate it. */\n.havik-player.havik-has-status .havik-watermark{display:none}\n\n.havik-bar{position:absolute;left:0;right:0;bottom:0;padding:0 12px 8px;\n opacity:1;transition:opacity .25s;z-index:2}\n.havik-seek{position:relative;height:16px;display:flex;align-items:center;cursor:pointer;margin-bottom:2px}\n.havik-seek__track{position:relative;width:100%;height:4px;border-radius:3px;background:rgba(255,255,255,.25)}\n.havik-seek__buffered{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:rgba(255,255,255,.4)}\n.havik-seek__played{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-seek__thumb{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;\n background:var(--havik-accent,#E1B600);transform:translate(-50%,-50%) scale(0);transition:transform .1s}\n.havik-seek:hover .havik-seek__thumb{transform:translate(-50%,-50%) scale(1)}\n\n.havik-controls{display:flex;align-items:center;gap:6px;height:40px}\n.havik-spacer{flex:1}\n.havik-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;border-radius:var(--havik-radius,8px);\n padding:0;transition:background .12s,color .12s}\n.havik-btn:hover{background:rgba(255,255,255,.12)}\n.havik-btn:focus-visible{outline:2px solid var(--havik-accent,#E1B600);outline-offset:1px}\n.havik-btn svg{width:22px;height:22px}\n\n/* The volume level is filled in accent up to the thumb, like the seek bar's\n played span — a native range input paints no \"elapsed\" side, which left the\n level readable only from the dot's position. --havik-vol (0..1) is set by\n syncVolume(); the track width and thumb size live here as variables because\n the WebKit fill has to compute the thumb centre from both. */\n.havik-vol{display:flex;align-items:center}\n.havik-vol__slider{--havik-vol-w:70px;--havik-vol-thumb:12px;--havik-vol:1;\n --havik-vol-pos:calc(var(--havik-vol-thumb) / 2 + var(--havik-vol) * (var(--havik-vol-w) - var(--havik-vol-thumb)));\n width:0;opacity:0;transition:width .18s,opacity .18s;height:4px;cursor:pointer;\n appearance:none;-webkit-appearance:none;background:transparent;border-radius:3px;margin:0 4px}\n.havik-vol:hover .havik-vol__slider,.havik-vol:focus-within .havik-vol__slider{width:var(--havik-vol-w);opacity:1}\n/* WebKit/Blink have no progress pseudo-element: paint the fill as a hard-stop\n gradient that ends at the thumb centre. */\n.havik-vol__slider::-webkit-slider-runnable-track{height:4px;border-radius:3px;\n background:linear-gradient(to right,var(--havik-accent,#E1B600) var(--havik-vol-pos),\n rgba(255,255,255,.3) var(--havik-vol-pos))}\n/* Firefox fills natively, and tracks the thumb exactly. */\n.havik-vol__slider::-moz-range-track{height:4px;border-radius:3px;background:rgba(255,255,255,.3)}\n.havik-vol__slider::-moz-range-progress{height:4px;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-vol__slider::-webkit-slider-thumb{-webkit-appearance:none;width:var(--havik-vol-thumb);\n height:var(--havik-vol-thumb);border-radius:50%;background:var(--havik-accent,#E1B600);\n margin-top:calc((4px - var(--havik-vol-thumb)) / 2)}\n.havik-vol__slider::-moz-range-thumb{width:var(--havik-vol-thumb);height:var(--havik-vol-thumb);\n border:0;border-radius:50%;background:var(--havik-accent,#E1B600)}\n\n.havik-time{font-size:12px;color:var(--havik-text-muted,#9aa0ad);\n font-variant-numeric:tabular-nums;padding:0 6px;white-space:nowrap}\n.havik-live{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;\n letter-spacing:.4px;padding:0 8px;color:var(--havik-text,#fff)}\n.havik-live svg{width:9px;height:9px;color:var(--havik-text-muted,#9aa0ad)}\n.havik-live.is-live svg{color:var(--havik-accent,#E1B600)}\n.havik-live__go{margin-left:2px;border:0;cursor:pointer;background:transparent;color:var(--havik-text-muted,#9aa0ad);\n font:inherit;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:6px}\n.havik-live.is-live .havik-live__go{display:none}\n.havik-live__go:hover{color:var(--havik-accent,#E1B600)}\n\n.havik-menu{position:absolute;bottom:54px;right:12px;min-width:170px;max-height:230px;overflow:auto;\n background:var(--havik-surface,#1B1C23);border:1px solid var(--havik-border,rgba(255,255,255,.1));\n border-radius:var(--havik-radius,8px);box-shadow:0 10px 30px rgba(0,0,0,.5);padding:6px;z-index:3}\n.havik-menu[hidden]{display:none}\n.havik-menu__title{font-size:11px;text-transform:uppercase;letter-spacing:.6px;\n color:var(--havik-text-muted,#9aa0ad);padding:6px 8px 4px}\n.havik-menu__item{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;font:inherit;font-size:13px;\n text-align:left;padding:7px 8px;border-radius:6px}\n.havik-menu__item:hover{background:var(--havik-surface-muted,#2a2c36)}\n.havik-menu__item[aria-checked=\"true\"]{color:var(--havik-accent,#E1B600);font-weight:600}\n.havik-menu__item[aria-checked=\"true\"]::after{content:'✓'}\n", Z = /* @__PURE__ */ new WeakMap();
|
|
2517
|
+
function Tn(e = document, t) {
|
|
2518
|
+
let n = e.querySelector(`style#${Cn}`);
|
|
2519
|
+
if (n && (!t || Z.get(n) === t)) return;
|
|
2497
2520
|
let r = e.createElement("style");
|
|
2498
|
-
r.id =
|
|
2521
|
+
r.id = Cn, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = wn, Z.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
|
|
2499
2522
|
}
|
|
2500
2523
|
//#endregion
|
|
2501
2524
|
//#region src/ui/icons.ts
|
|
2502
|
-
var
|
|
2525
|
+
var En = {
|
|
2503
2526
|
play: "<path d=\"M8 5v14l11-7z\"/>",
|
|
2504
2527
|
pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
|
|
2505
2528
|
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\"/>",
|
|
@@ -2513,20 +2536,20 @@ var wn = {
|
|
|
2513
2536
|
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\"/>"
|
|
2514
2537
|
};
|
|
2515
2538
|
function Q(e) {
|
|
2516
|
-
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${
|
|
2539
|
+
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${En[e]}</svg>`;
|
|
2517
2540
|
}
|
|
2518
2541
|
//#endregion
|
|
2519
2542
|
//#region src/ui/controls.ts
|
|
2520
|
-
var
|
|
2543
|
+
var Dn = 3e3, On = 250, kn = /* @__PURE__ */ new Set([
|
|
2521
2544
|
"GONE",
|
|
2522
2545
|
"NOT_FOUND",
|
|
2523
2546
|
"INVALID_URN",
|
|
2524
2547
|
"UNAUTHORIZED"
|
|
2525
2548
|
]);
|
|
2526
|
-
function
|
|
2527
|
-
return new
|
|
2549
|
+
function An(e) {
|
|
2550
|
+
return new jn(e);
|
|
2528
2551
|
}
|
|
2529
|
-
var
|
|
2552
|
+
var jn = class {
|
|
2530
2553
|
root;
|
|
2531
2554
|
video;
|
|
2532
2555
|
player;
|
|
@@ -2572,7 +2595,7 @@ var kn = class {
|
|
|
2572
2595
|
scrubbing = !1;
|
|
2573
2596
|
offFns = [];
|
|
2574
2597
|
constructor(e) {
|
|
2575
|
-
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ??
|
|
2598
|
+
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Dn, 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, Tn(this.doc, e.cspNonce), this.root.classList.add("havik-player"), this.root.hasAttribute("tabindex") || (this.root.tabIndex = 0), this.root.setAttribute("role", "region"), this.root.setAttribute("aria-label", "Video player");
|
|
2576
2599
|
let t = (e, t, n) => {
|
|
2577
2600
|
let r = this.doc.createElement(e);
|
|
2578
2601
|
if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
|
|
@@ -2658,7 +2681,7 @@ var kn = class {
|
|
|
2658
2681
|
let t = this.surfaceWasHidden;
|
|
2659
2682
|
this.tapTimer = setTimeout(() => {
|
|
2660
2683
|
this.tapTimer = void 0, this.toggleBar(t);
|
|
2661
|
-
},
|
|
2684
|
+
}, On);
|
|
2662
2685
|
}
|
|
2663
2686
|
toggleBar(e) {
|
|
2664
2687
|
e ? this.poke() : this.hideIfIdle();
|
|
@@ -2693,7 +2716,7 @@ var kn = class {
|
|
|
2693
2716
|
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);
|
|
2694
2717
|
} else {
|
|
2695
2718
|
let r = this.doc.createElement("div");
|
|
2696
|
-
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !
|
|
2719
|
+
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !kn.has(this.lastError.code)) {
|
|
2697
2720
|
let e = this.doc.createElement("button");
|
|
2698
2721
|
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);
|
|
2699
2722
|
}
|
|
@@ -2734,7 +2757,7 @@ var kn = class {
|
|
|
2734
2757
|
let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
|
|
2735
2758
|
this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
|
|
2736
2759
|
}
|
|
2737
|
-
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${
|
|
2760
|
+
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Mn(this.video.currentTime)} / ${Mn(this.video.duration)}`);
|
|
2738
2761
|
}
|
|
2739
2762
|
syncLive() {
|
|
2740
2763
|
let e = this.player.getStats(), t = e.isLive !== !1;
|
|
@@ -2784,17 +2807,17 @@ var kn = class {
|
|
|
2784
2807
|
renderQualityMenu() {
|
|
2785
2808
|
let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
|
|
2786
2809
|
n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
|
|
2787
|
-
for (let n of e) this.menu.append(this.menuItem(
|
|
2810
|
+
for (let n of e) this.menu.append(this.menuItem(Nn(n), t === n.index, () => this.player.setQuality(n.index)));
|
|
2788
2811
|
}
|
|
2789
2812
|
renderAudioMenu() {
|
|
2790
2813
|
let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
|
|
2791
2814
|
t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
|
|
2792
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
2815
|
+
for (let t of e) this.menu.append(this.menuItem(Pn(t), t.default, () => this.player.setAudioTrack(t.id)));
|
|
2793
2816
|
}
|
|
2794
2817
|
renderCcMenu() {
|
|
2795
2818
|
let e = this.player.getTextTracks(), t = this.doc.createElement("div");
|
|
2796
2819
|
t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
|
|
2797
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
2820
|
+
for (let t of e) this.menu.append(this.menuItem(Fn(t), !1, () => this.player.setTextTrack(t.id)));
|
|
2798
2821
|
}
|
|
2799
2822
|
onTracksChanged() {
|
|
2800
2823
|
this.openMenu && this.renderMenu(this.openMenu);
|
|
@@ -2895,41 +2918,41 @@ var kn = class {
|
|
|
2895
2918
|
this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
|
|
2896
2919
|
}
|
|
2897
2920
|
};
|
|
2898
|
-
function
|
|
2921
|
+
function Mn(e) {
|
|
2899
2922
|
(!Number.isFinite(e) || e < 0) && (e = 0);
|
|
2900
2923
|
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");
|
|
2901
2924
|
return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
|
|
2902
2925
|
}
|
|
2903
|
-
function
|
|
2926
|
+
function Nn(e) {
|
|
2904
2927
|
return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
|
|
2905
2928
|
}
|
|
2906
|
-
function
|
|
2929
|
+
function Pn(e) {
|
|
2907
2930
|
return e.name || e.lang || `Track ${e.id}`;
|
|
2908
2931
|
}
|
|
2909
|
-
function
|
|
2932
|
+
function Fn(e) {
|
|
2910
2933
|
return e.name || e.lang || `Track ${e.id}`;
|
|
2911
2934
|
}
|
|
2912
2935
|
//#endregion
|
|
2913
2936
|
//#region src/managed/index.ts
|
|
2914
|
-
var
|
|
2915
|
-
function
|
|
2937
|
+
var In = 6e3, Ln = 45e3, Rn = 2e3, zn = 3, Bn = 2e3, Vn = 48e4, Hn = "keySystemLicenseRequestFailed";
|
|
2938
|
+
function Un(e) {
|
|
2916
2939
|
if (e.env !== void 0 && e.baseUrl !== void 0) throw new n("INTERNAL", 0, `createPlayer: pass env OR baseUrl, not both (got env=${JSON.stringify(e.env)} and baseUrl=${JSON.stringify(e.baseUrl)})`);
|
|
2917
2940
|
if (e.env !== void 0) return Ke(e.env);
|
|
2918
2941
|
if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
|
|
2919
2942
|
return e.baseUrl;
|
|
2920
2943
|
}
|
|
2921
|
-
async function
|
|
2944
|
+
async function Wn(e) {
|
|
2922
2945
|
if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
2923
|
-
let t =
|
|
2946
|
+
let t = Un(e);
|
|
2924
2947
|
if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
2925
2948
|
if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
|
|
2926
|
-
let r = new
|
|
2949
|
+
let r = new Gn({
|
|
2927
2950
|
...e,
|
|
2928
2951
|
baseUrl: t
|
|
2929
2952
|
});
|
|
2930
2953
|
return await r.start(), r;
|
|
2931
2954
|
}
|
|
2932
|
-
var
|
|
2955
|
+
var Gn = class {
|
|
2933
2956
|
opts;
|
|
2934
2957
|
abort = new AbortController();
|
|
2935
2958
|
listeners = {};
|
|
@@ -2940,6 +2963,8 @@ var Un = class {
|
|
|
2940
2963
|
detachPip;
|
|
2941
2964
|
statsTimer;
|
|
2942
2965
|
refreshTimer;
|
|
2966
|
+
refreshInFlight;
|
|
2967
|
+
onRefocus;
|
|
2943
2968
|
staleLicenseReloaded = !1;
|
|
2944
2969
|
_state = "idle";
|
|
2945
2970
|
_descriptor = null;
|
|
@@ -3018,7 +3043,7 @@ var Un = class {
|
|
|
3018
3043
|
setTimeout(() => {
|
|
3019
3044
|
a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
|
|
3020
3045
|
phase: i ? "unavailable" : "tooEarly",
|
|
3021
|
-
retryInMs:
|
|
3046
|
+
retryInMs: Ln,
|
|
3022
3047
|
attempt: 1,
|
|
3023
3048
|
elapsedMs: 0,
|
|
3024
3049
|
...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
|
|
@@ -3057,13 +3082,13 @@ var Un = class {
|
|
|
3057
3082
|
!a && !p() && h();
|
|
3058
3083
|
}, e);
|
|
3059
3084
|
};
|
|
3060
|
-
_(
|
|
3085
|
+
_(In), this.armingSub = T({
|
|
3061
3086
|
eventsBaseUrl: t,
|
|
3062
3087
|
matchUrn: this.opts.matchUrn,
|
|
3063
3088
|
credential: this.opts.credential,
|
|
3064
|
-
onAlive: () => _(
|
|
3089
|
+
onAlive: () => _(Ln),
|
|
3065
3090
|
onState: (e) => {
|
|
3066
|
-
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() *
|
|
3091
|
+
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * Rn);
|
|
3067
3092
|
},
|
|
3068
3093
|
onError: () => h()
|
|
3069
3094
|
});
|
|
@@ -3086,7 +3111,7 @@ var Un = class {
|
|
|
3086
3111
|
let n = await s(this.opts.credential);
|
|
3087
3112
|
if (this.destroyed || t !== this.loadGen) return;
|
|
3088
3113
|
this.setState("loading");
|
|
3089
|
-
let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a =
|
|
3114
|
+
let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = Xe(this.opts.video, (e) => {
|
|
3090
3115
|
this._state !== "ended" && this._state !== "error" && this.setState(e);
|
|
3091
3116
|
});
|
|
3092
3117
|
if (await i.load(), this.destroyed || t !== this.loadGen) {
|
|
@@ -3108,26 +3133,26 @@ var Un = class {
|
|
|
3108
3133
|
if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
|
|
3109
3134
|
let i = e.analytics?.sid;
|
|
3110
3135
|
if (!i) return;
|
|
3111
|
-
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } =
|
|
3136
|
+
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = fn(this.opts.baseUrl, a, e.analytics?.endpoint);
|
|
3112
3137
|
if (!o) {
|
|
3113
3138
|
s && setTimeout(() => {
|
|
3114
3139
|
this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
|
|
3115
3140
|
}, 0);
|
|
3116
3141
|
return;
|
|
3117
3142
|
}
|
|
3118
|
-
let c = this.opts.video, l = new
|
|
3143
|
+
let c = this.opts.video, l = new pn({
|
|
3119
3144
|
endpoint: o,
|
|
3120
3145
|
sid: i,
|
|
3121
3146
|
player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
|
|
3122
|
-
sdkVersion:
|
|
3123
|
-
environment:
|
|
3147
|
+
sdkVersion: yn,
|
|
3148
|
+
environment: _n(c),
|
|
3124
3149
|
idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
|
|
3125
3150
|
onIdle: () => this.onAnalyticsIdle(t),
|
|
3126
3151
|
onBlocked: (e) => setTimeout(() => {
|
|
3127
3152
|
this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, e));
|
|
3128
3153
|
}, 0),
|
|
3129
3154
|
sample: () => {
|
|
3130
|
-
let e = this.engine?.getStats() ??
|
|
3155
|
+
let e = this.engine?.getStats() ?? qe, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
|
|
3131
3156
|
return {
|
|
3132
3157
|
...e,
|
|
3133
3158
|
bufferedMs: Math.round(t * 1e3),
|
|
@@ -3141,7 +3166,7 @@ var Un = class {
|
|
|
3141
3166
|
let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
|
|
3142
3167
|
c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
|
|
3143
3168
|
c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
|
|
3144
|
-
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()),
|
|
3169
|
+
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), vn().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
|
|
3145
3170
|
}
|
|
3146
3171
|
currentPresentation() {
|
|
3147
3172
|
let e = this.opts.video;
|
|
@@ -3164,13 +3189,14 @@ var Un = class {
|
|
|
3164
3189
|
debug: this.opts.debug,
|
|
3165
3190
|
deferLoad: r,
|
|
3166
3191
|
hlsConfig: i,
|
|
3167
|
-
emit: (e) => this.onEngineEvent(e)
|
|
3192
|
+
emit: (e) => this.onEngineEvent(e),
|
|
3193
|
+
freshLicenseUrl: () => this.refreshLicense()
|
|
3168
3194
|
}, o = this.opts.engine ?? "auto";
|
|
3169
|
-
if (o === "native") return new
|
|
3170
|
-
if (o === "hls") return new
|
|
3171
|
-
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl &&
|
|
3172
|
-
if (
|
|
3173
|
-
if (
|
|
3195
|
+
if (o === "native") return new G(a);
|
|
3196
|
+
if (o === "hls") return new qt(a);
|
|
3197
|
+
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && U(this.opts.video) && W() || !e.drmEnabled && nt() && U(this.opts.video)) return new G(a);
|
|
3198
|
+
if (pt()) return new qt(a);
|
|
3199
|
+
if (U(this.opts.video)) return new G(a);
|
|
3174
3200
|
throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
|
|
3175
3201
|
}
|
|
3176
3202
|
onEngineEvent(e) {
|
|
@@ -3232,7 +3258,7 @@ var Un = class {
|
|
|
3232
3258
|
r = 0, i = !1;
|
|
3233
3259
|
},
|
|
3234
3260
|
onError: () => {
|
|
3235
|
-
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >=
|
|
3261
|
+
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= zn && (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.`))));
|
|
3236
3262
|
}
|
|
3237
3263
|
});
|
|
3238
3264
|
}
|
|
@@ -3254,7 +3280,7 @@ var Un = class {
|
|
|
3254
3280
|
scheduleRejoin(e) {
|
|
3255
3281
|
this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
|
|
3256
3282
|
this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
|
|
3257
|
-
}, Math.random() *
|
|
3283
|
+
}, Math.random() * Rn));
|
|
3258
3284
|
}
|
|
3259
3285
|
cancelRejoin() {
|
|
3260
3286
|
this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
|
|
@@ -3278,7 +3304,7 @@ var Un = class {
|
|
|
3278
3304
|
}
|
|
3279
3305
|
t.controls = !1;
|
|
3280
3306
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
3281
|
-
r && r.insertBefore(n, t), n.appendChild(t),
|
|
3307
|
+
r && r.insertBefore(n, t), n.appendChild(t), Sn(n, this.opts.theme), this.container = n, this.controlBar = An({
|
|
3282
3308
|
root: n,
|
|
3283
3309
|
video: t,
|
|
3284
3310
|
player: this,
|
|
@@ -3309,7 +3335,7 @@ var Un = class {
|
|
|
3309
3335
|
}
|
|
3310
3336
|
startStats() {
|
|
3311
3337
|
this.stopStats();
|
|
3312
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
3338
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? Bn);
|
|
3313
3339
|
this.statsTimer = setInterval(() => {
|
|
3314
3340
|
if (!this.engine) return;
|
|
3315
3341
|
let e = this.engine.getStats();
|
|
@@ -3320,29 +3346,43 @@ var Un = class {
|
|
|
3320
3346
|
this.statsTimer && clearInterval(this.statsTimer), this.statsTimer = void 0;
|
|
3321
3347
|
}
|
|
3322
3348
|
isStaleLicenseDenial(e) {
|
|
3323
|
-
return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !==
|
|
3349
|
+
return this.staleLicenseReloaded || this.opts.hlsConfig?.licenseXhrSetup || this._state === "ended" || this._state === "error" || e.detail !== Hn || e.error.httpStatus !== 403 ? !1 : K(this._descriptor?.drm?.widevine?.licenseUrl);
|
|
3324
3350
|
}
|
|
3325
3351
|
scheduleLicenseRefresh() {
|
|
3326
|
-
this.stopRefresh();
|
|
3327
|
-
|
|
3328
|
-
|
|
3352
|
+
if (this.stopRefresh(), !this._descriptor?.drmEnabled) return;
|
|
3353
|
+
typeof document < "u" && this.engine?.name === "hls" && (this.onRefocus = () => {
|
|
3354
|
+
document.visibilityState !== "visible" || this.destroyed || K(this._descriptor?.drm?.widevine?.licenseUrl) && this.refreshLicense();
|
|
3355
|
+
}, document.addEventListener("visibilitychange", this.onRefocus));
|
|
3356
|
+
let e = this.opts.licenseRefreshMs ?? Vn;
|
|
3357
|
+
e && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
3329
3358
|
}
|
|
3330
3359
|
stopRefresh() {
|
|
3331
|
-
this.refreshTimer && clearInterval(this.refreshTimer), this.refreshTimer = void 0;
|
|
3360
|
+
this.refreshTimer && clearInterval(this.refreshTimer), this.refreshTimer = void 0, this.onRefocus && typeof document < "u" && (document.removeEventListener("visibilitychange", this.onRefocus), this.onRefocus = void 0);
|
|
3332
3361
|
}
|
|
3333
|
-
|
|
3362
|
+
refreshLicense() {
|
|
3334
3363
|
let e = this.engine;
|
|
3335
|
-
if (
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3364
|
+
if (this.destroyed || !e) return Promise.resolve(void 0);
|
|
3365
|
+
if (this.refreshInFlight?.engine === e) return this.refreshInFlight.promise;
|
|
3366
|
+
let t = (async () => {
|
|
3367
|
+
try {
|
|
3368
|
+
let t = await v(this.resolveOptions());
|
|
3369
|
+
if (this.destroyed || this.engine !== e) return;
|
|
3370
|
+
let n = t.drm?.widevine?.licenseUrl, r = t.drm?.fairplay?.licenseUrl;
|
|
3371
|
+
return (n || r) && (e.setLicenseUrls({
|
|
3372
|
+
widevine: n,
|
|
3373
|
+
fairplay: r
|
|
3374
|
+
}), this._descriptor = t), n;
|
|
3375
|
+
} catch (e) {
|
|
3376
|
+
e instanceof n && !o(e.code) && (this.stopRefresh(), this.destroyed || this.emit("warning", e));
|
|
3377
|
+
return;
|
|
3378
|
+
} finally {
|
|
3379
|
+
this.refreshInFlight?.promise === t && (this.refreshInFlight = void 0);
|
|
3380
|
+
}
|
|
3381
|
+
})();
|
|
3382
|
+
return this.refreshInFlight = {
|
|
3383
|
+
engine: e,
|
|
3384
|
+
promise: t
|
|
3385
|
+
}, t;
|
|
3346
3386
|
}
|
|
3347
3387
|
async play() {
|
|
3348
3388
|
if (this.destroyed) return;
|
|
@@ -3369,7 +3409,7 @@ var Un = class {
|
|
|
3369
3409
|
this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
|
|
3370
3410
|
}
|
|
3371
3411
|
getStats() {
|
|
3372
|
-
return this.engine?.getStats() ??
|
|
3412
|
+
return this.engine?.getStats() ?? qe;
|
|
3373
3413
|
}
|
|
3374
3414
|
getQualityLevels() {
|
|
3375
3415
|
return this.engine?.getQualityLevels() ?? [];
|
|
@@ -3479,7 +3519,7 @@ function $(e) {
|
|
|
3479
3519
|
}
|
|
3480
3520
|
//#endregion
|
|
3481
3521
|
//#region src/embed/host.ts
|
|
3482
|
-
function
|
|
3522
|
+
function Kn(e) {
|
|
3483
3523
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
3484
3524
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
3485
3525
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -3538,15 +3578,15 @@ function Wn(e) {
|
|
|
3538
3578
|
}
|
|
3539
3579
|
//#endregion
|
|
3540
3580
|
//#region src/embed/page.ts
|
|
3541
|
-
var
|
|
3542
|
-
function
|
|
3581
|
+
var qn = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
3582
|
+
function Jn(e) {
|
|
3543
3583
|
if (typeof e == "boolean") return e;
|
|
3544
3584
|
if (typeof e == "object" && e) {
|
|
3545
3585
|
let t = e.endpoint;
|
|
3546
3586
|
return typeof t == "string" ? { endpoint: t } : {};
|
|
3547
3587
|
}
|
|
3548
3588
|
}
|
|
3549
|
-
function
|
|
3589
|
+
function Yn() {
|
|
3550
3590
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
3551
3591
|
if (e) return {
|
|
3552
3592
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -3556,7 +3596,7 @@ function qn() {
|
|
|
3556
3596
|
autoplay: e.autoplay ?? !0,
|
|
3557
3597
|
muted: e.muted ?? !0,
|
|
3558
3598
|
waitForLive: e.waitForLive ?? !0,
|
|
3559
|
-
analytics:
|
|
3599
|
+
analytics: Jn(e.analytics)
|
|
3560
3600
|
};
|
|
3561
3601
|
let t = new URLSearchParams(location.search);
|
|
3562
3602
|
return {
|
|
@@ -3569,9 +3609,9 @@ function qn() {
|
|
|
3569
3609
|
waitForLive: !0
|
|
3570
3610
|
};
|
|
3571
3611
|
}
|
|
3572
|
-
async function
|
|
3573
|
-
let e =
|
|
3574
|
-
|
|
3612
|
+
async function Xn() {
|
|
3613
|
+
let e = Yn();
|
|
3614
|
+
Qn();
|
|
3575
3615
|
let t = document.createElement("video");
|
|
3576
3616
|
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);
|
|
3577
3617
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
@@ -3626,12 +3666,12 @@ async function Jn() {
|
|
|
3626
3666
|
code: e.code,
|
|
3627
3667
|
message: e.message
|
|
3628
3668
|
})), e.on("autoplayblocked", () => {
|
|
3629
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
3669
|
+
i({ type: "oddin:autoplayblocked" }), Zn(t, e);
|
|
3630
3670
|
});
|
|
3631
3671
|
}, s = async (r) => {
|
|
3632
3672
|
a?.destroy(), a = null;
|
|
3633
3673
|
try {
|
|
3634
|
-
let n = await
|
|
3674
|
+
let n = await Wn({
|
|
3635
3675
|
video: t,
|
|
3636
3676
|
baseUrl: e.baseUrl,
|
|
3637
3677
|
matchUrn: r,
|
|
@@ -3693,7 +3733,7 @@ async function Jn() {
|
|
|
3693
3733
|
a?.retry();
|
|
3694
3734
|
break;
|
|
3695
3735
|
case "oddin:load":
|
|
3696
|
-
typeof e.matchUrn == "string" &&
|
|
3736
|
+
typeof e.matchUrn == "string" && qn.test(e.matchUrn) && s(e.matchUrn);
|
|
3697
3737
|
break;
|
|
3698
3738
|
case "oddin:destroy": c();
|
|
3699
3739
|
}
|
|
@@ -3705,18 +3745,18 @@ async function Jn() {
|
|
|
3705
3745
|
protocol: 1
|
|
3706
3746
|
});
|
|
3707
3747
|
}
|
|
3708
|
-
function
|
|
3748
|
+
function Zn(e, t) {
|
|
3709
3749
|
if (document.getElementById("havik-tap")) return;
|
|
3710
3750
|
let n = document.createElement("button");
|
|
3711
3751
|
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", () => {
|
|
3712
3752
|
n.remove(), t.play();
|
|
3713
3753
|
}), document.body.appendChild(n);
|
|
3714
3754
|
}
|
|
3715
|
-
function
|
|
3755
|
+
function Qn() {
|
|
3716
3756
|
let e = document.createElement("style");
|
|
3717
3757
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
3718
3758
|
}
|
|
3719
3759
|
//#endregion
|
|
3720
|
-
export {
|
|
3760
|
+
export { bn as ODDIN_THEME, n as PlaybackError, Sn as applyTheme, Ke as baseUrlForEnv, Xn as bootEmbed, Te as clearDeviceId, Wn as createPlayer, E as deriveEventsBaseUrl, He as detectDrmSupport, C as enterVideoFullscreen, w as exitVideoFullscreen, _e as fetchCatalog, ye as fetchTournament, xe as flattenMatches, k as getDeviceId, We as isLowLatencyManifest, $ as isOddinMessage, De as licenseRequestHeaders, Kn as mountEmbed, de as pollToLive, y as resolveStream, T as subscribeLiveState, S as videoFullscreenActive, Ce as watchStatus };
|
|
3721
3761
|
|
|
3722
3762
|
//# sourceMappingURL=index.js.map
|