@oddin-gg/havik-player 2.9.3 → 2.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/havik-player.global.js +18 -18
- package/dist/havik-player.global.js.map +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +60 -4
- package/dist/index.d.ts +60 -4
- package/dist/index.js +557 -294
- package/dist/index.js.map +1 -1
- package/docs/API.md +55 -23
- package/embed/index.html +1 -1
- package/examples/vanilla.html +1 -1
- package/package.json +4 -1
package/dist/index.js
CHANGED
|
@@ -44,11 +44,34 @@ async function s(e) {
|
|
|
44
44
|
return t;
|
|
45
45
|
}
|
|
46
46
|
function c(e) {
|
|
47
|
-
return e === "live" || e === "ended" || e === "upcoming" ? e : "upcoming";
|
|
47
|
+
return e === "live" || e === "ended" || e === "upcoming" || e === "pending" ? e : "upcoming";
|
|
48
|
+
}
|
|
49
|
+
function l(e) {
|
|
50
|
+
if (!Array.isArray(e)) return;
|
|
51
|
+
let t = [];
|
|
52
|
+
for (let n of e) {
|
|
53
|
+
if (!n || typeof n != "object") continue;
|
|
54
|
+
let e = typeof n.urn == "string" ? n.urn : "", r = typeof n.name == "string" ? n.name : "";
|
|
55
|
+
if (!e && !r) continue;
|
|
56
|
+
let i = {
|
|
57
|
+
urn: e,
|
|
58
|
+
name: r,
|
|
59
|
+
isHome: n.isHome === !0
|
|
60
|
+
};
|
|
61
|
+
typeof n.logoUrl == "string" && u(n.logoUrl) && (i.logoUrl = n.logoUrl), t.push(i);
|
|
62
|
+
}
|
|
63
|
+
return t.length > 0 ? t : void 0;
|
|
64
|
+
}
|
|
65
|
+
function u(e) {
|
|
66
|
+
try {
|
|
67
|
+
return new URL(e).protocol === "https:";
|
|
68
|
+
} catch {
|
|
69
|
+
return !1;
|
|
70
|
+
}
|
|
48
71
|
}
|
|
49
72
|
//#endregion
|
|
50
73
|
//#region src/core/http.ts
|
|
51
|
-
function
|
|
74
|
+
function d(e, t) {
|
|
52
75
|
let r = e.replace(/\/+$/, ""), i;
|
|
53
76
|
try {
|
|
54
77
|
i = new URL(r + t);
|
|
@@ -58,14 +81,14 @@ function l(e, t) {
|
|
|
58
81
|
if (i.protocol !== "https:" && i.protocol !== "http:") throw new n("INTERNAL", 0, `baseUrl must be http(s), got: ${JSON.stringify(e)}`);
|
|
59
82
|
return i.toString();
|
|
60
83
|
}
|
|
61
|
-
function
|
|
84
|
+
function f(e) {
|
|
62
85
|
if (!e) return;
|
|
63
86
|
let t = Number(e);
|
|
64
87
|
if (Number.isFinite(t)) return Math.max(0, Math.round(t * 1e3));
|
|
65
88
|
let n = Date.parse(e);
|
|
66
89
|
if (!Number.isNaN(n)) return Math.max(0, n - Date.now());
|
|
67
90
|
}
|
|
68
|
-
async function
|
|
91
|
+
async function p(e, t) {
|
|
69
92
|
let r = await s(t.credential), i = t.headers ?? new Headers();
|
|
70
93
|
if (t.apiHeaders) for (let [e, n] of Object.entries(t.apiHeaders)) i.has(e) || i.set(e, n);
|
|
71
94
|
i.set("x-api-key", r.apiKey);
|
|
@@ -80,49 +103,49 @@ async function d(e, t) {
|
|
|
80
103
|
mode: "cors"
|
|
81
104
|
});
|
|
82
105
|
} catch (e) {
|
|
83
|
-
throw t.signal?.aborted ? new n("ABORTED", 0, "request aborted", { cause: e }) : new n("NETWORK", 0, `network request failed: ${
|
|
106
|
+
throw t.signal?.aborted ? new n("ABORTED", 0, "request aborted", { cause: e }) : new n("NETWORK", 0, `network request failed: ${m(e)}`, { cause: e });
|
|
84
107
|
}
|
|
85
108
|
}
|
|
86
|
-
function
|
|
109
|
+
function m(e) {
|
|
87
110
|
return e instanceof Error ? e.message : String(e);
|
|
88
111
|
}
|
|
89
112
|
//#endregion
|
|
90
113
|
//#region src/core/waitForLive.ts
|
|
91
|
-
var
|
|
114
|
+
var h = 1e3, g = 3e4, _ = 6e5, ee = 3e5, te = 1e3, ne = {
|
|
92
115
|
TOO_EARLY: "tooEarly",
|
|
93
116
|
UNAVAILABLE: "unavailable",
|
|
94
117
|
RATE_LIMITED: "rateLimited",
|
|
95
118
|
NETWORK: "network"
|
|
96
119
|
};
|
|
97
|
-
function
|
|
98
|
-
let t = e === !0 || e === !1 ? {} : e, n = Math.max(
|
|
120
|
+
function re(e) {
|
|
121
|
+
let t = e === !0 || e === !1 ? {} : e, n = Math.max(te, t.floorMs ?? h), r = Math.max(n, t.ceilMs ?? g), i = Math.max(0, t.imminentMs ?? _), a = Math.max(r, t.sanityFloorMs ?? ee);
|
|
99
122
|
return {
|
|
100
123
|
timeoutMs: t.timeoutMs,
|
|
101
124
|
floorMs: n,
|
|
102
125
|
ceilMs: r,
|
|
103
126
|
imminentMs: i,
|
|
104
127
|
sanityFloorMs: a,
|
|
105
|
-
kickoffMs:
|
|
128
|
+
kickoffMs: ie(t.kickoffAt),
|
|
106
129
|
jitter: t.jitter ?? !0,
|
|
107
130
|
onState: t.onState
|
|
108
131
|
};
|
|
109
132
|
}
|
|
110
|
-
function
|
|
133
|
+
function ie(e) {
|
|
111
134
|
if (e == null) return;
|
|
112
135
|
if (typeof e == "number") return Number.isFinite(e) ? e : void 0;
|
|
113
136
|
let t = Date.parse(e);
|
|
114
137
|
return Number.isFinite(t) ? t : void 0;
|
|
115
138
|
}
|
|
116
|
-
function
|
|
139
|
+
function ae(e, t, n) {
|
|
117
140
|
return Math.min(n, Math.max(t, e));
|
|
118
141
|
}
|
|
119
|
-
function
|
|
142
|
+
function oe(e) {
|
|
120
143
|
return Math.round(e * (1 + .15 * Math.random()));
|
|
121
144
|
}
|
|
122
|
-
function
|
|
145
|
+
function se(e, t, n, r) {
|
|
123
146
|
let i = r ?? n.kickoffMs, a = i == null ? void 0 : Math.max(0, i - t), o = Math.max(n.floorMs, e ?? 0);
|
|
124
147
|
if (a == null || a <= n.imminentMs) return {
|
|
125
|
-
delay:
|
|
148
|
+
delay: ae(e ?? n.floorMs, o, n.ceilMs),
|
|
126
149
|
ttkMs: a
|
|
127
150
|
};
|
|
128
151
|
let s = Math.min(Math.floor(a / 10), n.sanityFloorMs, a);
|
|
@@ -131,7 +154,7 @@ function ae(e, t, n, r) {
|
|
|
131
154
|
ttkMs: a
|
|
132
155
|
};
|
|
133
156
|
}
|
|
134
|
-
function
|
|
157
|
+
function ce(e, t) {
|
|
135
158
|
return new Promise((r, i) => {
|
|
136
159
|
if (t?.aborted) {
|
|
137
160
|
i(new n("ABORTED", 0, "wait-for-live aborted"));
|
|
@@ -146,7 +169,7 @@ function oe(e, t) {
|
|
|
146
169
|
});
|
|
147
170
|
}
|
|
148
171
|
async function v(e, t, r) {
|
|
149
|
-
let i =
|
|
172
|
+
let i = re(t), a = Date.now(), s = i.timeoutMs == null ? Infinity : a + i.timeoutMs, c = 0, l;
|
|
150
173
|
for (;;) {
|
|
151
174
|
if (r?.aborted) throw new n("ABORTED", 0, "wait-for-live aborted");
|
|
152
175
|
try {
|
|
@@ -154,18 +177,18 @@ async function v(e, t, r) {
|
|
|
154
177
|
} catch (e) {
|
|
155
178
|
if (!(e instanceof n) || !o(e.code)) throw e;
|
|
156
179
|
c += 1, e.liveStartsAtMs != null && Number.isFinite(e.liveStartsAtMs) && (l = e.liveStartsAtMs);
|
|
157
|
-
let t = Date.now(), u =
|
|
158
|
-
if (i.jitter && (f =
|
|
180
|
+
let t = Date.now(), u = se(e.retryAfterMs, t, i, l), d = u.ttkMs, f = u.delay;
|
|
181
|
+
if (i.jitter && (f = oe(f)), t + f > s) throw new n("TIMEOUT", e.httpStatus, `timed out after ${i.timeoutMs}ms waiting for the stream to go live`, {
|
|
159
182
|
retryAfterMs: e.retryAfterMs,
|
|
160
183
|
cause: e
|
|
161
184
|
});
|
|
162
185
|
i.onState?.({
|
|
163
|
-
phase:
|
|
186
|
+
phase: ne[e.code] ?? "unavailable",
|
|
164
187
|
retryInMs: f,
|
|
165
188
|
attempt: c,
|
|
166
189
|
elapsedMs: t - a,
|
|
167
190
|
ttkMs: d
|
|
168
|
-
}), await
|
|
191
|
+
}), await ce(f, r);
|
|
169
192
|
}
|
|
170
193
|
}
|
|
171
194
|
}
|
|
@@ -173,20 +196,20 @@ async function v(e, t, r) {
|
|
|
173
196
|
//#region src/core/resolve.ts
|
|
174
197
|
async function y(e) {
|
|
175
198
|
if (!e.matchUrn || typeof e.matchUrn != "string") throw new n("INVALID_URN", 0, "resolveStream: a non-empty matchUrn is required");
|
|
176
|
-
let t = await d(
|
|
199
|
+
let t = await p(d(e.baseUrl, `/v1/playback/${encodeURIComponent(e.matchUrn)}`), {
|
|
177
200
|
credential: e.credential,
|
|
178
201
|
signal: e.signal,
|
|
179
202
|
apiHeaders: e.apiHeaders
|
|
180
203
|
});
|
|
181
|
-
if (!t.ok) throw await
|
|
182
|
-
return
|
|
204
|
+
if (!t.ok) throw await le(t);
|
|
205
|
+
return de(await t.json(), e.matchUrn);
|
|
183
206
|
}
|
|
184
207
|
function b(e) {
|
|
185
208
|
let t = () => y(e);
|
|
186
209
|
return e.waitForLive ? v(t, e.waitForLive, e.signal) : t();
|
|
187
210
|
}
|
|
188
|
-
async function
|
|
189
|
-
let t =
|
|
211
|
+
async function le(e) {
|
|
212
|
+
let t = f(e.headers.get("retry-after")), i = e.headers.get("x-request-id") ?? e.headers.get("x-amzn-requestid") ?? void 0, a = e.statusText || `HTTP ${e.status}`, o, s;
|
|
190
213
|
try {
|
|
191
214
|
let t = await e.json();
|
|
192
215
|
if (t?.error?.message && (a = t.error.message), t?.error?.code && (o = t.error.code), typeof t?.liveStartsAt == "string") {
|
|
@@ -201,7 +224,7 @@ async function se(e) {
|
|
|
201
224
|
liveStartsAtMs: s
|
|
202
225
|
});
|
|
203
226
|
}
|
|
204
|
-
var
|
|
227
|
+
var ue = /* @__PURE__ */ new Set([
|
|
205
228
|
"matchUrn",
|
|
206
229
|
"protocol",
|
|
207
230
|
"drmEnabled",
|
|
@@ -222,7 +245,7 @@ function x(e, t) {
|
|
|
222
245
|
if (r.protocol !== "https:" && r.protocol !== "http:") throw new n("INTERNAL", 0, `playback ${e} has a disallowed scheme: ${r.protocol}`);
|
|
223
246
|
return t;
|
|
224
247
|
}
|
|
225
|
-
function
|
|
248
|
+
function de(e, t) {
|
|
226
249
|
if (!e.manifestUrl) throw new n("INTERNAL", 0, "playback response is missing manifestUrl");
|
|
227
250
|
let r = e.drmEnabled ?? !!e.drm, i = {
|
|
228
251
|
matchUrn: e.matchUrn ?? t,
|
|
@@ -239,19 +262,19 @@ function le(e, t) {
|
|
|
239
262
|
}), (t.widevine || t.fairplay) && (i.drm = t);
|
|
240
263
|
}
|
|
241
264
|
let a = {};
|
|
242
|
-
for (let [t, n] of Object.entries(e))
|
|
265
|
+
for (let [t, n] of Object.entries(e)) ue.has(t) || (a[t] = n);
|
|
243
266
|
return Object.keys(a).length > 0 && (i.extensions = a), i;
|
|
244
267
|
}
|
|
245
268
|
//#endregion
|
|
246
269
|
//#region src/core/fullscreen.ts
|
|
247
|
-
function
|
|
270
|
+
function fe(e) {
|
|
248
271
|
return e.ownerDocument ?? document;
|
|
249
272
|
}
|
|
250
|
-
function
|
|
273
|
+
function S(e) {
|
|
251
274
|
return e.fullscreenElement ?? e.webkitFullscreenElement ?? null;
|
|
252
275
|
}
|
|
253
276
|
function C(e, t) {
|
|
254
|
-
let n =
|
|
277
|
+
let n = S(fe(e));
|
|
255
278
|
return n != null && (n === e || t != null && n === t) || e.webkitDisplayingFullscreen === !0;
|
|
256
279
|
}
|
|
257
280
|
async function w(e, t) {
|
|
@@ -267,17 +290,17 @@ async function T(e, t) {
|
|
|
267
290
|
n.webkitExitFullscreen?.();
|
|
268
291
|
return;
|
|
269
292
|
}
|
|
270
|
-
let r =
|
|
293
|
+
let r = fe(e), i = S(r);
|
|
271
294
|
i != null && (i === e || t != null && i === t) && (typeof r.exitFullscreen == "function" ? await r.exitFullscreen() : r.webkitExitFullscreen?.());
|
|
272
295
|
}
|
|
273
296
|
//#endregion
|
|
274
297
|
//#region src/core/catalog.ts
|
|
275
|
-
async function
|
|
298
|
+
async function pe(e) {
|
|
276
299
|
let t = new URLSearchParams();
|
|
277
300
|
e.status && t.set("status", Array.isArray(e.status) ? e.status.join(",") : e.status), e.sport && t.set("sport", e.sport);
|
|
278
|
-
let i = t.toString(), a =
|
|
301
|
+
let i = t.toString(), a = d(e.baseUrl, "/v1/catalog" + (i ? `?${i}` : "")), o = new Headers();
|
|
279
302
|
e.etag && o.set("If-None-Match", e.etag);
|
|
280
|
-
let s = await
|
|
303
|
+
let s = await p(a, {
|
|
281
304
|
credential: e.credential,
|
|
282
305
|
signal: e.signal,
|
|
283
306
|
headers: o,
|
|
@@ -290,12 +313,12 @@ async function de(e) {
|
|
|
290
313
|
};
|
|
291
314
|
if (!s.ok) throw new n(r(s.status), s.status, `catalog request failed (HTTP ${s.status})`);
|
|
292
315
|
return {
|
|
293
|
-
tournaments:
|
|
316
|
+
tournaments: me(await s.json()),
|
|
294
317
|
etag: s.headers.get("etag") ?? void 0,
|
|
295
318
|
notModified: !1
|
|
296
319
|
};
|
|
297
320
|
}
|
|
298
|
-
function
|
|
321
|
+
function me(e) {
|
|
299
322
|
return (e.tournaments ?? []).map((e) => {
|
|
300
323
|
let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
|
|
301
324
|
return {
|
|
@@ -311,15 +334,16 @@ function fe(e) {
|
|
|
311
334
|
datePlannedStart: e.datePlannedStart,
|
|
312
335
|
tournamentUrn: t,
|
|
313
336
|
tournamentName: n,
|
|
314
|
-
sport: r
|
|
337
|
+
sport: r,
|
|
338
|
+
teams: l(e.teams)
|
|
315
339
|
}))
|
|
316
340
|
};
|
|
317
341
|
});
|
|
318
342
|
}
|
|
319
|
-
async function
|
|
320
|
-
let t =
|
|
343
|
+
async function he(e) {
|
|
344
|
+
let t = d(e.baseUrl, `/v1/tournaments/${encodeURIComponent(e.urn)}`), i = new Headers();
|
|
321
345
|
e.etag && i.set("If-None-Match", e.etag);
|
|
322
|
-
let a = await
|
|
346
|
+
let a = await p(t, {
|
|
323
347
|
credential: e.credential,
|
|
324
348
|
signal: e.signal,
|
|
325
349
|
headers: i,
|
|
@@ -336,13 +360,13 @@ async function pe(e) {
|
|
|
336
360
|
};
|
|
337
361
|
if (!a.ok) throw new n(r(a.status), a.status, `tournament request failed (HTTP ${a.status})`);
|
|
338
362
|
return {
|
|
339
|
-
tournament:
|
|
363
|
+
tournament: ge(await a.json()),
|
|
340
364
|
etag: a.headers.get("etag") ?? void 0,
|
|
341
365
|
notModified: !1,
|
|
342
366
|
notFound: !1
|
|
343
367
|
};
|
|
344
368
|
}
|
|
345
|
-
function
|
|
369
|
+
function ge(e) {
|
|
346
370
|
let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
|
|
347
371
|
return {
|
|
348
372
|
urn: t,
|
|
@@ -357,23 +381,24 @@ function me(e) {
|
|
|
357
381
|
datePlannedStart: e.datePlannedStart,
|
|
358
382
|
tournamentUrn: t,
|
|
359
383
|
tournamentName: n,
|
|
360
|
-
sport: r
|
|
384
|
+
sport: r,
|
|
385
|
+
teams: l(e.teams)
|
|
361
386
|
}))
|
|
362
387
|
};
|
|
363
388
|
}
|
|
364
|
-
function
|
|
389
|
+
function _e(e) {
|
|
365
390
|
return e.tournaments.flatMap((e) => e.matches);
|
|
366
391
|
}
|
|
367
392
|
//#endregion
|
|
368
393
|
//#region src/core/poll.ts
|
|
369
|
-
function
|
|
394
|
+
function ve(e) {
|
|
370
395
|
let t = Math.max(2e3, e.intervalMs ?? 1e4), i = new AbortController(), a, o, s, u = !1, f = () => {
|
|
371
|
-
u || (a = setTimeout(
|
|
372
|
-
},
|
|
396
|
+
u || (a = setTimeout(m, t));
|
|
397
|
+
}, m = async () => {
|
|
373
398
|
try {
|
|
374
|
-
let t =
|
|
399
|
+
let t = d(e.baseUrl, `/v1/matches/${encodeURIComponent(e.matchUrn)}`), a = new Headers();
|
|
375
400
|
o && a.set("If-None-Match", o);
|
|
376
|
-
let u = await
|
|
401
|
+
let u = await p(t, {
|
|
377
402
|
credential: e.credential,
|
|
378
403
|
signal: i.signal,
|
|
379
404
|
headers: a,
|
|
@@ -382,13 +407,18 @@ function ge(e) {
|
|
|
382
407
|
if (u.status !== 304) {
|
|
383
408
|
if (!u.ok) throw new n(r(u.status), u.status, `match status request failed (HTTP ${u.status})`);
|
|
384
409
|
o = u.headers.get("etag") ?? o;
|
|
385
|
-
let t = await u.json(), i = c(t.status), a = typeof t.status == "string" ? t.status : i
|
|
386
|
-
|
|
410
|
+
let t = await u.json(), i = c(t.status), a = typeof t.status == "string" ? t.status : i, d = l(t.teams), f = JSON.stringify([
|
|
411
|
+
a,
|
|
412
|
+
t.datePlannedStart ?? null,
|
|
413
|
+
d ?? null
|
|
414
|
+
]);
|
|
415
|
+
f !== s && (s = f, e.onChange({
|
|
387
416
|
matchUrn: t.matchUrn ?? e.matchUrn,
|
|
388
417
|
matchName: t.matchName,
|
|
389
418
|
status: i,
|
|
390
419
|
statusRaw: t.status,
|
|
391
|
-
datePlannedStart: t.datePlannedStart
|
|
420
|
+
datePlannedStart: t.datePlannedStart,
|
|
421
|
+
teams: d
|
|
392
422
|
}));
|
|
393
423
|
}
|
|
394
424
|
} catch (t) {
|
|
@@ -397,21 +427,21 @@ function ge(e) {
|
|
|
397
427
|
f();
|
|
398
428
|
}
|
|
399
429
|
};
|
|
400
|
-
return
|
|
430
|
+
return m(), { stop() {
|
|
401
431
|
u = !0, i.abort(), a && clearTimeout(a);
|
|
402
432
|
} };
|
|
403
433
|
}
|
|
404
434
|
//#endregion
|
|
405
435
|
//#region src/core/events.ts
|
|
406
|
-
var
|
|
436
|
+
var ye = 45e3;
|
|
407
437
|
function E(e) {
|
|
408
|
-
let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = e.idleTimeoutMs ??
|
|
438
|
+
let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = e.idleTimeoutMs ?? ye, i = Number.isFinite(r) && r > 0 ? r : 0, a = new AbortController(), o = !1, c = (e) => new Promise((t) => {
|
|
409
439
|
if (a.signal.aborted) return t();
|
|
410
440
|
let n = setTimeout(t, e);
|
|
411
441
|
a.signal.addEventListener("abort", () => {
|
|
412
442
|
clearTimeout(n), t();
|
|
413
443
|
}, { once: !0 });
|
|
414
|
-
}),
|
|
444
|
+
}), l = (t) => {
|
|
415
445
|
e.onAlive?.();
|
|
416
446
|
let n = "message", r = [];
|
|
417
447
|
for (let e of t.split("\n")) {
|
|
@@ -424,9 +454,9 @@ function E(e) {
|
|
|
424
454
|
let t = JSON.parse(r.join("\n"));
|
|
425
455
|
t && typeof t.state == "string" && e.onState(t);
|
|
426
456
|
} catch {}
|
|
427
|
-
},
|
|
428
|
-
let r = e.getReader(), a = new TextDecoder(), s = "", c = !1,
|
|
429
|
-
i && (clearTimeout(
|
|
457
|
+
}, u = /\r\n\r\n|\n\n|\r\r/, f = async (e, t, n) => {
|
|
458
|
+
let r = e.getReader(), a = new TextDecoder(), s = "", c = !1, d, f = () => {
|
|
459
|
+
i && (clearTimeout(d), d = setTimeout(() => {
|
|
430
460
|
n(), r.cancel().catch(() => {});
|
|
431
461
|
}, i));
|
|
432
462
|
};
|
|
@@ -436,27 +466,27 @@ function E(e) {
|
|
|
436
466
|
if (n) return;
|
|
437
467
|
e && e.length > 0 && (f(), c || (c = !0, t())), s += a.decode(e, { stream: !0 });
|
|
438
468
|
let i;
|
|
439
|
-
for (; (i =
|
|
469
|
+
for (; (i = u.exec(s)) !== null;) l(s.slice(0, i.index)), s = s.slice(i.index + i[0].length);
|
|
440
470
|
if (o) return;
|
|
441
471
|
}
|
|
442
472
|
} finally {
|
|
443
|
-
clearTimeout(
|
|
473
|
+
clearTimeout(d), await r.cancel().catch(() => {});
|
|
444
474
|
}
|
|
445
475
|
};
|
|
446
476
|
return (async () => {
|
|
447
477
|
let r = t;
|
|
448
478
|
for (; !o;) {
|
|
449
|
-
let
|
|
450
|
-
a.signal.addEventListener("abort",
|
|
479
|
+
let l = new AbortController(), u = () => l.abort();
|
|
480
|
+
a.signal.addEventListener("abort", u, { once: !0 });
|
|
451
481
|
let p = null, m, h = () => {
|
|
452
|
-
p = `no data for ${i}ms`,
|
|
482
|
+
p = `no data for ${i}ms`, l.abort();
|
|
453
483
|
};
|
|
454
484
|
try {
|
|
455
485
|
let n = await s(e.credential);
|
|
456
486
|
if (o) return;
|
|
457
|
-
let a =
|
|
487
|
+
let a = d(e.eventsBaseUrl, `/v1/events/${encodeURIComponent(e.matchUrn)}`);
|
|
458
488
|
i && (m = setTimeout(() => {
|
|
459
|
-
p = `no response headers within ${i}ms`,
|
|
489
|
+
p = `no response headers within ${i}ms`, l.abort();
|
|
460
490
|
}, i));
|
|
461
491
|
let c = await fetch(a, {
|
|
462
492
|
method: "GET",
|
|
@@ -464,7 +494,7 @@ function E(e) {
|
|
|
464
494
|
"x-api-key": n.apiKey,
|
|
465
495
|
accept: "text/event-stream"
|
|
466
496
|
},
|
|
467
|
-
signal:
|
|
497
|
+
signal: l.signal,
|
|
468
498
|
cache: "no-store",
|
|
469
499
|
credentials: "omit",
|
|
470
500
|
mode: "cors"
|
|
@@ -477,7 +507,7 @@ function E(e) {
|
|
|
477
507
|
if (o || a.signal.aborted) return;
|
|
478
508
|
p || e.onError?.(t);
|
|
479
509
|
} finally {
|
|
480
|
-
clearTimeout(m), a.signal.removeEventListener("abort",
|
|
510
|
+
clearTimeout(m), a.signal.removeEventListener("abort", u), l.abort();
|
|
481
511
|
}
|
|
482
512
|
if (o) return;
|
|
483
513
|
p && e.onError?.(/* @__PURE__ */ Error(`live-state subscribe idle: ${p} — reconnecting`)), await c(r), r = Math.min(n, r * 2);
|
|
@@ -503,20 +533,20 @@ function A() {
|
|
|
503
533
|
let e = globalThis.localStorage?.getItem(O);
|
|
504
534
|
if (e) return k = e, e;
|
|
505
535
|
} catch {}
|
|
506
|
-
let e =
|
|
536
|
+
let e = xe();
|
|
507
537
|
k = e;
|
|
508
538
|
try {
|
|
509
539
|
globalThis.localStorage?.setItem(O, e);
|
|
510
540
|
} catch {}
|
|
511
541
|
return e;
|
|
512
542
|
}
|
|
513
|
-
function
|
|
543
|
+
function be() {
|
|
514
544
|
k = void 0;
|
|
515
545
|
try {
|
|
516
546
|
globalThis.localStorage?.removeItem(O);
|
|
517
547
|
} catch {}
|
|
518
548
|
}
|
|
519
|
-
function
|
|
549
|
+
function xe() {
|
|
520
550
|
let e = globalThis.crypto;
|
|
521
551
|
if (e && typeof e.randomUUID == "function") return e.randomUUID();
|
|
522
552
|
let t = /* @__PURE__ */ new Uint8Array(16);
|
|
@@ -528,7 +558,7 @@ function ye() {
|
|
|
528
558
|
}
|
|
529
559
|
//#endregion
|
|
530
560
|
//#region src/core/drm/headers.ts
|
|
531
|
-
function
|
|
561
|
+
function Se(e, t, n = {}) {
|
|
532
562
|
let r = {
|
|
533
563
|
"x-api-key": t.apiKey,
|
|
534
564
|
"X-Match-Urn": e.matchUrn,
|
|
@@ -540,7 +570,7 @@ function be(e, t, n = {}) {
|
|
|
540
570
|
//#endregion
|
|
541
571
|
//#region src/core/drm/cdm.ts
|
|
542
572
|
var j = /* @__PURE__ */ new WeakMap();
|
|
543
|
-
function
|
|
573
|
+
function Ce(e, t) {
|
|
544
574
|
let n = j.get(e);
|
|
545
575
|
n || (n = /* @__PURE__ */ new Map(), j.set(e, n));
|
|
546
576
|
let r = n.get(t.keySystem);
|
|
@@ -554,11 +584,11 @@ function M() {
|
|
|
554
584
|
return typeof navigator < "u" && typeof navigator.requestMediaKeySystemAccess == "function";
|
|
555
585
|
}
|
|
556
586
|
var N = ["SW_SECURE_DECODE", "SW_SECURE_CRYPTO"];
|
|
557
|
-
function
|
|
587
|
+
function we(e) {
|
|
558
588
|
return e.startsWith("com.widevine");
|
|
559
589
|
}
|
|
560
|
-
function
|
|
561
|
-
if (!
|
|
590
|
+
function P(e, t) {
|
|
591
|
+
if (!we(e)) return t;
|
|
562
592
|
let n = (e, t) => {
|
|
563
593
|
let n = e.videoCapabilities;
|
|
564
594
|
return !n?.length || !n.some((e) => e.robustness) ? !1 : n.every((e) => {
|
|
@@ -574,20 +604,41 @@ function Ce(e, t) {
|
|
|
574
604
|
})));
|
|
575
605
|
return [...t, ...r];
|
|
576
606
|
}
|
|
577
|
-
function
|
|
578
|
-
return (t, n) => M() ? navigator.requestMediaKeySystemAccess(t,
|
|
607
|
+
function Te(e) {
|
|
608
|
+
return (t, n) => M() ? navigator.requestMediaKeySystemAccess(t, P(t, n)).then((t) => ({
|
|
579
609
|
keySystem: t.keySystem,
|
|
580
610
|
getConfiguration: () => t.getConfiguration(),
|
|
581
|
-
createMediaKeys: () =>
|
|
611
|
+
createMediaKeys: () => Ce(e, t)
|
|
582
612
|
})) : Promise.reject(/* @__PURE__ */ Error("navigator.requestMediaKeySystemAccess is unavailable — EME needs a secure context (https, or localhost)"));
|
|
583
613
|
}
|
|
614
|
+
var F = {
|
|
615
|
+
video: "SW_SECURE_DECODE",
|
|
616
|
+
audio: "SW_SECURE_CRYPTO",
|
|
617
|
+
scheme: "cbcs"
|
|
618
|
+
};
|
|
619
|
+
function Ee(e) {
|
|
620
|
+
if (!M()) return;
|
|
621
|
+
let t = (e, t) => ({
|
|
622
|
+
contentType: e,
|
|
623
|
+
robustness: t,
|
|
624
|
+
encryptionScheme: F.scheme
|
|
625
|
+
});
|
|
626
|
+
Te(e)("com.widevine.alpha", [{
|
|
627
|
+
initDataTypes: ["cenc"],
|
|
628
|
+
distinctiveIdentifier: "optional",
|
|
629
|
+
persistentState: "optional",
|
|
630
|
+
sessionTypes: ["temporary"],
|
|
631
|
+
audioCapabilities: [t("audio/mp4; codecs=\"mp4a.40.2\"", F.audio)],
|
|
632
|
+
videoCapabilities: [t("video/mp4; codecs=\"avc1.42e01e\"", F.video)]
|
|
633
|
+
}]).then((e) => e.createMediaKeys()).catch(() => {});
|
|
634
|
+
}
|
|
584
635
|
//#endregion
|
|
585
636
|
//#region src/core/drm/support.ts
|
|
586
|
-
var
|
|
637
|
+
var De = 5e3, Oe = "video/mp4; codecs=\"avc1.42E01E\"", ke = "audio/mp4; codecs=\"mp4a.40.2\"", Ae = {
|
|
587
638
|
widevine: ["com.widevine.alpha"],
|
|
588
639
|
fairplay: ["com.apple.fps"]
|
|
589
640
|
};
|
|
590
|
-
function
|
|
641
|
+
function je(e) {
|
|
591
642
|
return e === "fairplay" ? [{
|
|
592
643
|
initDataTypes: [
|
|
593
644
|
"sinf",
|
|
@@ -595,30 +646,30 @@ function ke(e) {
|
|
|
595
646
|
"cenc"
|
|
596
647
|
],
|
|
597
648
|
videoCapabilities: [{
|
|
598
|
-
contentType:
|
|
649
|
+
contentType: Oe,
|
|
599
650
|
robustness: "",
|
|
600
651
|
encryptionScheme: "cbcs"
|
|
601
652
|
}],
|
|
602
653
|
audioCapabilities: [{
|
|
603
|
-
contentType:
|
|
654
|
+
contentType: ke,
|
|
604
655
|
robustness: "",
|
|
605
656
|
encryptionScheme: "cbcs"
|
|
606
657
|
}]
|
|
607
|
-
}] :
|
|
658
|
+
}] : P("com.widevine.alpha", [{
|
|
608
659
|
initDataTypes: ["cenc"],
|
|
609
660
|
videoCapabilities: [{
|
|
610
|
-
contentType:
|
|
611
|
-
robustness:
|
|
612
|
-
encryptionScheme:
|
|
661
|
+
contentType: Oe,
|
|
662
|
+
robustness: F.video,
|
|
663
|
+
encryptionScheme: F.scheme
|
|
613
664
|
}],
|
|
614
665
|
audioCapabilities: [{
|
|
615
|
-
contentType:
|
|
616
|
-
robustness:
|
|
617
|
-
encryptionScheme:
|
|
666
|
+
contentType: ke,
|
|
667
|
+
robustness: F.audio,
|
|
668
|
+
encryptionScheme: F.scheme
|
|
618
669
|
}]
|
|
619
670
|
}]);
|
|
620
671
|
}
|
|
621
|
-
function
|
|
672
|
+
function Me(e, t) {
|
|
622
673
|
return new Promise((n, r) => {
|
|
623
674
|
let i = setTimeout(() => r(/* @__PURE__ */ Error("probe-timeout")), t);
|
|
624
675
|
e.then((e) => {
|
|
@@ -628,8 +679,8 @@ function P(e, t) {
|
|
|
628
679
|
});
|
|
629
680
|
});
|
|
630
681
|
}
|
|
631
|
-
async function
|
|
632
|
-
let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ??
|
|
682
|
+
async function Ne(e = {}) {
|
|
683
|
+
let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? De, r = {};
|
|
633
684
|
if (typeof window < "u" && window.isSecureContext === !1) return {
|
|
634
685
|
verdict: "insecure-context",
|
|
635
686
|
detail: r
|
|
@@ -641,7 +692,7 @@ async function Ae(e = {}) {
|
|
|
641
692
|
};
|
|
642
693
|
let a = !1, o = !1, s = Date.now() + n, c = () => Math.max(1, s - Date.now());
|
|
643
694
|
for (let e of t) {
|
|
644
|
-
let t =
|
|
695
|
+
let t = Ae[e];
|
|
645
696
|
if (!t) {
|
|
646
697
|
r[e] = "unknown system";
|
|
647
698
|
continue;
|
|
@@ -652,7 +703,7 @@ async function Ae(e = {}) {
|
|
|
652
703
|
break;
|
|
653
704
|
}
|
|
654
705
|
try {
|
|
655
|
-
return await
|
|
706
|
+
return await Me((await Me(i(n, je(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
|
|
656
707
|
verdict: "supported",
|
|
657
708
|
system: e,
|
|
658
709
|
detail: r
|
|
@@ -676,49 +727,49 @@ async function Ae(e = {}) {
|
|
|
676
727
|
}
|
|
677
728
|
//#endregion
|
|
678
729
|
//#region src/core/manifest.ts
|
|
679
|
-
var
|
|
680
|
-
function
|
|
681
|
-
return
|
|
730
|
+
var Pe = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
|
|
731
|
+
function Fe(e) {
|
|
732
|
+
return Pe.test(e);
|
|
682
733
|
}
|
|
683
734
|
//#endregion
|
|
684
735
|
//#region src/core/env.ts
|
|
685
|
-
var
|
|
736
|
+
var I = {
|
|
686
737
|
integration: "https://feed-dev.oddin-video.gg",
|
|
687
738
|
production: "https://feed.oddin-video.gg"
|
|
688
739
|
};
|
|
689
|
-
function
|
|
690
|
-
let t = Object.prototype.hasOwnProperty.call(
|
|
740
|
+
function L(e) {
|
|
741
|
+
let t = Object.prototype.hasOwnProperty.call(I, e) ? I[e] : void 0;
|
|
691
742
|
if (!t) throw new n("INTERNAL", 0, `unknown env ${JSON.stringify(e)} — expected 'integration' or 'production'`);
|
|
692
743
|
return t;
|
|
693
744
|
}
|
|
694
745
|
//#endregion
|
|
695
746
|
//#region src/core/stats.ts
|
|
696
|
-
var
|
|
697
|
-
function
|
|
747
|
+
var R = { droppedFrames: 0 };
|
|
748
|
+
function z(e) {
|
|
698
749
|
try {
|
|
699
750
|
return new URL(e).host;
|
|
700
751
|
} catch {
|
|
701
752
|
return "";
|
|
702
753
|
}
|
|
703
754
|
}
|
|
704
|
-
var
|
|
705
|
-
function
|
|
755
|
+
var Ie = /\.(m3u8|ts|m4s|mp4|cmfv|cmfa)(\?|$)/i;
|
|
756
|
+
function Le(e) {
|
|
706
757
|
if (typeof performance > "u" || typeof performance.getEntriesByType != "function") return "";
|
|
707
758
|
let t = "", n = -1, r = performance.getEntriesByType("resource");
|
|
708
|
-
for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" ||
|
|
709
|
-
let e =
|
|
759
|
+
for (let i of r) if (!(i.startTime < e) && (i.initiatorType === "video" || i.initiatorType === "audio" || Ie.test(i.name)) && i.startTime >= n) {
|
|
760
|
+
let e = z(i.name);
|
|
710
761
|
e && (t = e, n = i.startTime);
|
|
711
762
|
}
|
|
712
763
|
return t;
|
|
713
764
|
}
|
|
714
|
-
function
|
|
765
|
+
function B(e) {
|
|
715
766
|
let t = e.getVideoPlaybackQuality?.();
|
|
716
767
|
return {
|
|
717
768
|
dropped: t?.droppedVideoFrames ?? 0,
|
|
718
769
|
totalFrames: t?.totalVideoFrames ?? 0
|
|
719
770
|
};
|
|
720
771
|
}
|
|
721
|
-
function
|
|
772
|
+
function Re(e, t) {
|
|
722
773
|
let n = [
|
|
723
774
|
["playing", () => t("playing")],
|
|
724
775
|
["waiting", () => t("buffering")],
|
|
@@ -735,7 +786,7 @@ function Fe(e, t) {
|
|
|
735
786
|
}
|
|
736
787
|
//#endregion
|
|
737
788
|
//#region src/core/engine/native.ts
|
|
738
|
-
function
|
|
789
|
+
function ze(e) {
|
|
739
790
|
try {
|
|
740
791
|
let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
|
|
741
792
|
return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
|
|
@@ -743,15 +794,15 @@ function Ie(e) {
|
|
|
743
794
|
return;
|
|
744
795
|
}
|
|
745
796
|
}
|
|
746
|
-
function
|
|
797
|
+
function V(e) {
|
|
747
798
|
return !!(e ?? (typeof document < "u" ? document.createElement("video") : void 0))?.canPlayType("application/vnd.apple.mpegurl");
|
|
748
799
|
}
|
|
749
|
-
function
|
|
800
|
+
function H() {
|
|
750
801
|
if (typeof window > "u") return !1;
|
|
751
802
|
let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
|
|
752
803
|
return e || t;
|
|
753
804
|
}
|
|
754
|
-
var
|
|
805
|
+
var U = class {
|
|
755
806
|
name = "native";
|
|
756
807
|
deps;
|
|
757
808
|
onLoaded;
|
|
@@ -787,7 +838,7 @@ var H = class {
|
|
|
787
838
|
type: "error",
|
|
788
839
|
error: new n("INTERNAL", 0, "native HLS playback error"),
|
|
789
840
|
fatal: !0
|
|
790
|
-
}), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src =
|
|
841
|
+
}), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = Be(t.manifestUrl, t.analytics?.sid), e.load();
|
|
791
842
|
}
|
|
792
843
|
startLoad() {
|
|
793
844
|
this.loadStarted || (this.loadStarted = !0, this.restorePreload());
|
|
@@ -809,7 +860,7 @@ var H = class {
|
|
|
809
860
|
});
|
|
810
861
|
this.onEncrypted = (n) => {
|
|
811
862
|
let i = n;
|
|
812
|
-
i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV =
|
|
863
|
+
i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = ze(i.initData), (async () => {
|
|
813
864
|
try {
|
|
814
865
|
let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
|
|
815
866
|
initDataTypes: [i.initDataType],
|
|
@@ -904,11 +955,11 @@ var H = class {
|
|
|
904
955
|
e.seekable.length > 0 && (e.currentTime = e.seekable.end(e.seekable.length - 1));
|
|
905
956
|
}
|
|
906
957
|
getStats() {
|
|
907
|
-
let e = this.deps.video, t =
|
|
958
|
+
let e = this.deps.video, t = B(e), n = {
|
|
908
959
|
droppedFrames: t.dropped,
|
|
909
960
|
decodedFrames: t.totalFrames
|
|
910
961
|
};
|
|
911
|
-
return this.cdnHost ||=
|
|
962
|
+
return this.cdnHost ||= Le(this.builtAt), this.cdnHost && (n.cdnHost = this.cdnHost), this.deps.descriptor.drmEnabled && (n.keySystem = "fairplay"), e.duration === Infinity ? (n.isLive = !0, e.seekable.length > 0 && (n.atLiveEdge = e.currentTime >= e.seekable.end(e.seekable.length - 1) - 2)) : Number.isFinite(e.duration) && e.duration > 0 && (n.isLive = !1), n;
|
|
912
963
|
}
|
|
913
964
|
stop() {
|
|
914
965
|
try {
|
|
@@ -927,35 +978,198 @@ var H = class {
|
|
|
927
978
|
} catch {}
|
|
928
979
|
}
|
|
929
980
|
};
|
|
930
|
-
function
|
|
981
|
+
function Be(e, t) {
|
|
931
982
|
return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
|
|
932
983
|
}
|
|
933
984
|
//#endregion
|
|
985
|
+
//#region src/core/engine/prefetch.ts
|
|
986
|
+
var Ve = 15e3, He = 5e3, Ue = 6;
|
|
987
|
+
function W(e) {
|
|
988
|
+
try {
|
|
989
|
+
let t = new URL(e);
|
|
990
|
+
return t.searchParams.delete("CMCD"), t.toString();
|
|
991
|
+
} catch {
|
|
992
|
+
return e;
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
var We = class {
|
|
996
|
+
cmcd;
|
|
997
|
+
entries = /* @__PURE__ */ new Map();
|
|
998
|
+
keyed = /* @__PURE__ */ new Set();
|
|
999
|
+
perTrack = /* @__PURE__ */ new Map();
|
|
1000
|
+
stats = {
|
|
1001
|
+
started: 0,
|
|
1002
|
+
served: 0,
|
|
1003
|
+
missed: 0,
|
|
1004
|
+
failed: 0,
|
|
1005
|
+
expired: 0
|
|
1006
|
+
};
|
|
1007
|
+
constructor(e = {}) {
|
|
1008
|
+
this.cmcd = e;
|
|
1009
|
+
}
|
|
1010
|
+
keyUsable(e) {
|
|
1011
|
+
this.keyed.add(e);
|
|
1012
|
+
}
|
|
1013
|
+
isActive(e) {
|
|
1014
|
+
return !this.keyed.has(e);
|
|
1015
|
+
}
|
|
1016
|
+
prefetch(e, t, n) {
|
|
1017
|
+
if (!this.isActive(t)) return;
|
|
1018
|
+
let r = W(e);
|
|
1019
|
+
if (this.entries.has(r)) return;
|
|
1020
|
+
let i = this.perTrack.get(t) ?? 0;
|
|
1021
|
+
if (i >= Ue) return;
|
|
1022
|
+
this.perTrack.set(t, i + 1);
|
|
1023
|
+
let a = new AbortController(), o = {
|
|
1024
|
+
started: performance.now(),
|
|
1025
|
+
first: 0,
|
|
1026
|
+
bytes: Promise.resolve(null),
|
|
1027
|
+
abort: a
|
|
1028
|
+
};
|
|
1029
|
+
o.bytes = fetch(this.withCmcd(e, t, n), {
|
|
1030
|
+
credentials: "omit",
|
|
1031
|
+
mode: "cors",
|
|
1032
|
+
signal: a.signal
|
|
1033
|
+
}).then(async (e) => (o.first = performance.now(), e.ok ? e.arrayBuffer() : null)).catch(() => null), this.entries.set(r, o), this.stats.started += 1, setTimeout(() => {
|
|
1034
|
+
this.entries.get(r) === o && (this.entries.delete(r), a.abort(), this.stats.expired += 1);
|
|
1035
|
+
}, Ve);
|
|
1036
|
+
}
|
|
1037
|
+
take(e) {
|
|
1038
|
+
let t = W(e), n = this.entries.get(t);
|
|
1039
|
+
return n && this.entries.delete(t), n;
|
|
1040
|
+
}
|
|
1041
|
+
destroy() {
|
|
1042
|
+
for (let e of this.entries.values()) e.abort.abort();
|
|
1043
|
+
this.entries.clear();
|
|
1044
|
+
}
|
|
1045
|
+
withCmcd(e, t, n) {
|
|
1046
|
+
let { sessionId: r, contentId: i } = this.cmcd;
|
|
1047
|
+
if (!r && !i) return e;
|
|
1048
|
+
let a = [];
|
|
1049
|
+
i && a.push(`cid="${i}"`), a.push(`ot=${n === "init" ? "i" : t === "audio" ? "a" : "v"}`), a.push("sf=h"), r && a.push(`sid="${r}"`), a.push("st=ll");
|
|
1050
|
+
try {
|
|
1051
|
+
let t = new URL(e);
|
|
1052
|
+
return t.searchParams.set("CMCD", a.join(",")), t.toString();
|
|
1053
|
+
} catch {
|
|
1054
|
+
return e;
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
};
|
|
1058
|
+
function Ge(t) {
|
|
1059
|
+
let n = e.DefaultConfig?.loader;
|
|
1060
|
+
if (typeof n != "function") return;
|
|
1061
|
+
class r extends n {
|
|
1062
|
+
served = !1;
|
|
1063
|
+
cancelled = !1;
|
|
1064
|
+
stats = Ke();
|
|
1065
|
+
load(e, n, r) {
|
|
1066
|
+
let i = e.rangeEnd ? void 0 : t.take(e.url);
|
|
1067
|
+
if (!i) {
|
|
1068
|
+
super.load(e, n, r);
|
|
1069
|
+
return;
|
|
1070
|
+
}
|
|
1071
|
+
this.served = !0;
|
|
1072
|
+
let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || He, s = setTimeout(() => {
|
|
1073
|
+
!this.cancelled && this.served && (i.abort.abort(), t.stats.failed += 1, this.served = !1, super.load(e, n, r));
|
|
1074
|
+
}, o);
|
|
1075
|
+
i.bytes.then((o) => {
|
|
1076
|
+
if (clearTimeout(s), this.cancelled || !this.served) return;
|
|
1077
|
+
if (!o) {
|
|
1078
|
+
t.stats.failed += 1, this.served = !1, super.load(e, n, r);
|
|
1079
|
+
return;
|
|
1080
|
+
}
|
|
1081
|
+
t.stats.served += 1;
|
|
1082
|
+
let c = this.stats;
|
|
1083
|
+
c.loading.start = a, c.loading.first = Math.max(a, i.first || a), c.loading.end = performance.now(), c.loaded = c.total = o.byteLength, r.onSuccess({
|
|
1084
|
+
url: e.url,
|
|
1085
|
+
data: o
|
|
1086
|
+
}, c, e, null);
|
|
1087
|
+
});
|
|
1088
|
+
}
|
|
1089
|
+
abort() {
|
|
1090
|
+
if (this.served) {
|
|
1091
|
+
this.cancelled = !0, this.stats.aborted = !0;
|
|
1092
|
+
return;
|
|
1093
|
+
}
|
|
1094
|
+
super.abort();
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
return r;
|
|
1098
|
+
}
|
|
1099
|
+
function Ke() {
|
|
1100
|
+
return {
|
|
1101
|
+
aborted: !1,
|
|
1102
|
+
loaded: 0,
|
|
1103
|
+
retry: 0,
|
|
1104
|
+
total: 0,
|
|
1105
|
+
chunkCount: 0,
|
|
1106
|
+
bwEstimate: 0,
|
|
1107
|
+
loading: {
|
|
1108
|
+
start: 0,
|
|
1109
|
+
first: 0,
|
|
1110
|
+
end: 0
|
|
1111
|
+
},
|
|
1112
|
+
parsing: {
|
|
1113
|
+
start: 0,
|
|
1114
|
+
end: 0
|
|
1115
|
+
},
|
|
1116
|
+
buffering: {
|
|
1117
|
+
start: 0,
|
|
1118
|
+
first: 0,
|
|
1119
|
+
end: 0
|
|
1120
|
+
}
|
|
1121
|
+
};
|
|
1122
|
+
}
|
|
1123
|
+
function G(e) {
|
|
1124
|
+
return e === "audio" ? "audio" : "main";
|
|
1125
|
+
}
|
|
1126
|
+
function qe(e, t) {
|
|
1127
|
+
let n = [];
|
|
1128
|
+
t.initSegment?.url && !t.initSegment.data && n.push({
|
|
1129
|
+
url: t.initSegment.url,
|
|
1130
|
+
kind: "init"
|
|
1131
|
+
});
|
|
1132
|
+
let r = ((t.type === "audio" ? e.audioTracks?.[e.audioTrack]?.details : typeof t.level == "number" ? e.levels?.[t.level]?.details : void 0)?.partList ?? []).filter((e) => e.fragment.sn === t.sn);
|
|
1133
|
+
if (r.length) for (let e of r) e.url && n.push({
|
|
1134
|
+
url: e.url,
|
|
1135
|
+
kind: "media"
|
|
1136
|
+
});
|
|
1137
|
+
else t.url && n.push({
|
|
1138
|
+
url: t.url,
|
|
1139
|
+
kind: "media"
|
|
1140
|
+
});
|
|
1141
|
+
return n;
|
|
1142
|
+
}
|
|
1143
|
+
//#endregion
|
|
934
1144
|
//#region src/core/engine/hls.ts
|
|
935
|
-
function
|
|
1145
|
+
function Je() {
|
|
936
1146
|
return e.isSupported();
|
|
937
1147
|
}
|
|
938
|
-
var
|
|
939
|
-
function
|
|
1148
|
+
var Ye = 3, Xe = 5, Ze = 3, Qe = 3e4, $e = 12e3, et = 3e3, K = 6e3, tt = 5e3, nt = 4e3, rt = 2, it = 5, at = 2, ot = 2, q = 4, st = 4, ct = 2e3, lt = 3e4, ut = 2, dt = 9, ft = .5, pt = 64;
|
|
1149
|
+
function mt(e) {
|
|
940
1150
|
if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
|
|
941
1151
|
delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
|
|
942
1152
|
return;
|
|
943
1153
|
}
|
|
944
|
-
e.liveSyncDuration ??=
|
|
945
|
-
let t = Math.max(12, e.liveSyncDuration +
|
|
946
|
-
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t),
|
|
1154
|
+
e.liveSyncDuration ??= ut;
|
|
1155
|
+
let t = Math.max(12, e.liveSyncDuration + dt);
|
|
1156
|
+
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), ht(e, e.liveSyncDuration);
|
|
947
1157
|
}
|
|
948
|
-
function
|
|
1158
|
+
function ht(e, t) {
|
|
949
1159
|
let n = (e, t, n) => Math.min(n, Math.max(t, e));
|
|
950
1160
|
e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
|
|
951
1161
|
}
|
|
952
|
-
var
|
|
1162
|
+
var J = class {
|
|
953
1163
|
name = "hls";
|
|
954
1164
|
hls = null;
|
|
955
1165
|
deps;
|
|
956
1166
|
licenseUrl;
|
|
957
1167
|
detectedLowLatency = !1;
|
|
958
1168
|
bytesLoaded = 0;
|
|
1169
|
+
prefetch = null;
|
|
1170
|
+
reportedFirstPlaylist = !1;
|
|
1171
|
+
reportedFirstBytes = !1;
|
|
1172
|
+
reportedDrmReady = !1;
|
|
959
1173
|
playlistBytesLoaded = 0;
|
|
960
1174
|
renditionSwitches = 0;
|
|
961
1175
|
licenseTimeMs = 0;
|
|
@@ -993,6 +1207,11 @@ var W = class {
|
|
|
993
1207
|
kickPending = !1;
|
|
994
1208
|
kickTicks = 0;
|
|
995
1209
|
starvationRebuilds = 0;
|
|
1210
|
+
kickKind = null;
|
|
1211
|
+
starvedFrames = 0;
|
|
1212
|
+
deadTicks = 0;
|
|
1213
|
+
mainFragsSinceTick = 0;
|
|
1214
|
+
recentMainFrags = [];
|
|
996
1215
|
chaseSuspended = !1;
|
|
997
1216
|
savedLiveMaxLatency;
|
|
998
1217
|
savedMaxSyncRate;
|
|
@@ -1008,7 +1227,7 @@ var W = class {
|
|
|
1008
1227
|
this.deps = e, this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl, this.loadStarted = e.deferLoad !== !0;
|
|
1009
1228
|
}
|
|
1010
1229
|
async load() {
|
|
1011
|
-
let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a =
|
|
1230
|
+
let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = V(r) && H(), o = !!e.drm?.widevine?.licenseUrl && !a;
|
|
1012
1231
|
if (e.drmEnabled && !o) {
|
|
1013
1232
|
i({
|
|
1014
1233
|
type: "error",
|
|
@@ -1017,7 +1236,7 @@ var W = class {
|
|
|
1017
1236
|
});
|
|
1018
1237
|
return;
|
|
1019
1238
|
}
|
|
1020
|
-
this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
|
|
1239
|
+
e.drmEnabled && o && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && Ee(r), this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
|
|
1021
1240
|
let e = this.hls;
|
|
1022
1241
|
if (document.visibilityState !== "visible" || !e) return;
|
|
1023
1242
|
let t = e.liveSyncPosition;
|
|
@@ -1040,11 +1259,11 @@ var W = class {
|
|
|
1040
1259
|
}
|
|
1041
1260
|
this.loadSuspended = !0;
|
|
1042
1261
|
}
|
|
1043
|
-
},
|
|
1262
|
+
}, tt));
|
|
1044
1263
|
}
|
|
1045
1264
|
resumeLoading() {
|
|
1046
1265
|
if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
|
|
1047
|
-
this.lastAdvanceMs = Date.now(), this.lastFragLoadingMs = 0, this.
|
|
1266
|
+
this.lastAdvanceMs = Date.now(), this.lastFragLoadingMs = 0, this.resetStarvationWindow(), this.clearKick();
|
|
1048
1267
|
try {
|
|
1049
1268
|
this.hls.startLoad(-1);
|
|
1050
1269
|
} catch {}
|
|
@@ -1072,11 +1291,11 @@ var W = class {
|
|
|
1072
1291
|
let t = e.liveSyncPosition;
|
|
1073
1292
|
if (typeof t != "number" || !Number.isFinite(t)) return;
|
|
1074
1293
|
let { video: n } = this.deps;
|
|
1075
|
-
n.currentTime <= t +
|
|
1294
|
+
n.currentTime <= t + ft || (n.currentTime = t);
|
|
1076
1295
|
}
|
|
1077
1296
|
startHls() {
|
|
1078
1297
|
let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps;
|
|
1079
|
-
this.
|
|
1298
|
+
this.clearKick(), this.resetStarvationWindow(), this.lastFragLoadingMs = 0, this.lastEndSN = -1, this.lastAdvanceMs = 0;
|
|
1080
1299
|
let u = n.drmEnabled && !!(n.drm?.widevine?.licenseUrl || n.drm?.fairplay?.licenseUrl), d = {
|
|
1081
1300
|
debug: s === !0,
|
|
1082
1301
|
enableWorker: !o,
|
|
@@ -1091,17 +1310,17 @@ var W = class {
|
|
|
1091
1310
|
emeEnabled: !0,
|
|
1092
1311
|
drmSystems: { ...this.licenseUrl ? { "com.widevine.alpha": { licenseUrl: this.licenseUrl } } : {} },
|
|
1093
1312
|
drmSystemOptions: {
|
|
1094
|
-
videoRobustness:
|
|
1095
|
-
audioRobustness:
|
|
1096
|
-
videoEncryptionScheme:
|
|
1097
|
-
audioEncryptionScheme:
|
|
1313
|
+
videoRobustness: F.video,
|
|
1314
|
+
audioRobustness: F.audio,
|
|
1315
|
+
videoEncryptionScheme: F.scheme,
|
|
1316
|
+
audioEncryptionScheme: F.scheme
|
|
1098
1317
|
},
|
|
1099
|
-
...M() ? { requestMediaKeySystemAccessFunc:
|
|
1318
|
+
...M() ? { requestMediaKeySystemAccessFunc: Te(t) } : {},
|
|
1100
1319
|
licenseXhrSetup: (e, t) => {
|
|
1101
1320
|
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;
|
|
1102
1321
|
let o = performance.now();
|
|
1103
1322
|
e.addEventListener("loadend", () => {
|
|
1104
|
-
this.licenseTimeMs = Math.max(1, Math.round(performance.now() - o));
|
|
1323
|
+
this.licenseTimeMs === 0 && (this.licenseTimeMs = Math.max(1, Math.round(performance.now() - o)));
|
|
1105
1324
|
});
|
|
1106
1325
|
}
|
|
1107
1326
|
} : {},
|
|
@@ -1112,39 +1331,56 @@ var W = class {
|
|
|
1112
1331
|
} } : {},
|
|
1113
1332
|
...c
|
|
1114
1333
|
};
|
|
1115
|
-
|
|
1334
|
+
if (this.prefetch?.destroy(), this.prefetch = null, u && this.deps.mediaDuringKey !== !1 && !d.fLoader) {
|
|
1335
|
+
let e = new We({
|
|
1336
|
+
sessionId: n.analytics?.sid,
|
|
1337
|
+
contentId: n.matchUrn
|
|
1338
|
+
}), t = Ge(e);
|
|
1339
|
+
t && (this.prefetch = e, d.fLoader = t);
|
|
1340
|
+
}
|
|
1341
|
+
mt(d), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.loadStarted = d.autoStartLoad !== !1;
|
|
1116
1342
|
let f = new e(d);
|
|
1117
|
-
this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
|
|
1343
|
+
if (this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
|
|
1118
1344
|
this.mediaRecoveries = 0, this.networkRecoveries = 0;
|
|
1119
1345
|
let e = f.levels.map((e) => e.height).filter((e) => !!e);
|
|
1120
1346
|
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" });
|
|
1121
1347
|
}), f.on(e.Events.FRAG_BUFFERED, (e, t) => {
|
|
1122
|
-
t?.frag?.type === "main" && (this.
|
|
1348
|
+
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(() => {
|
|
1123
1349
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
|
|
1124
|
-
},
|
|
1350
|
+
}, Qe)));
|
|
1125
1351
|
}), f.on(e.Events.FRAG_LOADING, (e, t) => {
|
|
1126
1352
|
t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
|
|
1127
1353
|
}), f.on(e.Events.FRAG_LOADED, (e, t) => {
|
|
1354
|
+
t?.frag?.type === "main" && (this.mainFragsSinceTick += 1);
|
|
1128
1355
|
let n = t?.frag?.stats, r = n?.loaded;
|
|
1129
|
-
typeof r == "number" && (this.bytesLoaded += r);
|
|
1356
|
+
typeof r == "number" && (this.bytesLoaded += r), !this.reportedFirstBytes && typeof r == "number" && r > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
|
|
1130
1357
|
let i = n?.loading;
|
|
1131
|
-
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 >
|
|
1358
|
+
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 > pt && this.requestTimesMs.shift());
|
|
1132
1359
|
let a = t?.frag?.url;
|
|
1133
1360
|
if (a) {
|
|
1134
|
-
let e =
|
|
1361
|
+
let e = z(a);
|
|
1135
1362
|
e && (this.cdnHost = e);
|
|
1136
1363
|
}
|
|
1137
1364
|
}), f.on(e.Events.LEVEL_LOADED, (e, t) => {
|
|
1138
1365
|
let n = t?.stats?.loaded;
|
|
1139
|
-
if (typeof n == "number" && (this.playlistBytesLoaded += n), this.detectedLowLatency) return;
|
|
1366
|
+
if (typeof n == "number" && (this.playlistBytesLoaded += n), this.reportedFirstPlaylist || (this.reportedFirstPlaylist = !0, l({ type: "firstPlaylist" })), this.detectedLowLatency) return;
|
|
1140
1367
|
let r = t.details;
|
|
1141
1368
|
(r?.partList?.length || (r?.partTarget ?? 0) > 0) && (this.detectedLowLatency = !0, l({
|
|
1142
1369
|
type: "lowLatencyDetected",
|
|
1143
1370
|
value: !0
|
|
1144
1371
|
}));
|
|
1145
|
-
}), f.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.
|
|
1372
|
+
}), f.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.prefetch) {
|
|
1373
|
+
let t = this.prefetch;
|
|
1374
|
+
f.on(e.Events.KEY_LOADING, (e, n) => {
|
|
1375
|
+
let r = n?.frag, i = G(r?.type);
|
|
1376
|
+
if (r && t.isActive(i)) for (let e of qe(f, r)) t.prefetch(e.url, i, e.kind);
|
|
1377
|
+
}), f.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(G(n?.frag?.type)));
|
|
1378
|
+
}
|
|
1379
|
+
f.on(e.Events.KEY_LOADED, () => {
|
|
1380
|
+
u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
|
|
1381
|
+
}), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
|
|
1146
1382
|
this.checkEndStale(), this.checkStarvation();
|
|
1147
|
-
},
|
|
1383
|
+
}, et), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
|
|
1148
1384
|
this.renditionSwitches += 1;
|
|
1149
1385
|
let n = this.lastLevelIndex >= 0 ? f.levels[this.lastLevelIndex] : void 0, r = f.levels[t.level];
|
|
1150
1386
|
n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, l({
|
|
@@ -1208,7 +1444,7 @@ var W = class {
|
|
|
1208
1444
|
return;
|
|
1209
1445
|
}
|
|
1210
1446
|
this.capTimer && clearTimeout(this.capTimer);
|
|
1211
|
-
let t = e > this.sizeCapLevel ?
|
|
1447
|
+
let t = e > this.sizeCapLevel ? ct : lt;
|
|
1212
1448
|
this.capTimer = setTimeout(() => {
|
|
1213
1449
|
this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
|
|
1214
1450
|
}, t);
|
|
@@ -1255,7 +1491,7 @@ var W = class {
|
|
|
1255
1491
|
e.widevine && (this.licenseUrl = e.widevine);
|
|
1256
1492
|
}
|
|
1257
1493
|
getStats() {
|
|
1258
|
-
let e = this.hls, t =
|
|
1494
|
+
let e = this.hls, t = B(this.deps.video), n = {
|
|
1259
1495
|
droppedFrames: t.dropped,
|
|
1260
1496
|
decodedFrames: t.totalFrames,
|
|
1261
1497
|
lowLatency: this.detectedLowLatency,
|
|
@@ -1301,32 +1537,41 @@ var W = class {
|
|
|
1301
1537
|
return;
|
|
1302
1538
|
}
|
|
1303
1539
|
let e = Date.now() - this.lastAdvanceMs;
|
|
1304
|
-
!this.chaseSuspended && e >
|
|
1540
|
+
!this.chaseSuspended && e > K && this.suspendChasing(), e > $e && this.emitEnded("stalled");
|
|
1541
|
+
}
|
|
1542
|
+
resetStarvationWindow() {
|
|
1543
|
+
this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
|
|
1544
|
+
}
|
|
1545
|
+
clearKick() {
|
|
1546
|
+
this.kickPending = !1, this.kickTicks = 0, this.kickKind = null;
|
|
1305
1547
|
}
|
|
1306
1548
|
checkStarvation() {
|
|
1307
1549
|
let e = this.hls, { video: t } = this.deps;
|
|
1308
1550
|
if (!e || this.endedEmitted || !this.sawLive || this.chaseSuspended) return;
|
|
1309
1551
|
if (typeof document < "u" && document.hidden || this.loadSuspended) {
|
|
1310
|
-
this.
|
|
1552
|
+
this.resetStarvationWindow();
|
|
1311
1553
|
return;
|
|
1312
1554
|
}
|
|
1313
|
-
let n = this.lastAdvanceMs !== 0 &&
|
|
1314
|
-
if (
|
|
1315
|
-
this.
|
|
1555
|
+
let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < K, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > nt, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = B(t), c = o - s, l = c !== this.starvedFrames;
|
|
1556
|
+
if (this.starvedFrames = c, !a || l) {
|
|
1557
|
+
(t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
|
|
1316
1558
|
return;
|
|
1317
1559
|
}
|
|
1318
|
-
if (
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1560
|
+
if (!r) {
|
|
1561
|
+
this.resetStarvationWindow();
|
|
1562
|
+
return;
|
|
1563
|
+
}
|
|
1564
|
+
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 > q && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= at && (this.clearKick(), this.starvationRebuilds < ot)) {
|
|
1565
|
+
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");
|
|
1566
|
+
return;
|
|
1567
|
+
}
|
|
1568
|
+
let u = i && this.starvedTicks >= rt, d = !i && this.deadTicks >= q && this.recentMainFrags.reduce((e, t) => e + t, 0) >= st;
|
|
1569
|
+
if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= it))) {
|
|
1570
|
+
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");
|
|
1571
|
+
try {
|
|
1572
|
+
e.stopLoad(), e.startLoad(-1);
|
|
1573
|
+
} catch (e) {
|
|
1574
|
+
console.warn("havik-player: starvation kick failed", e);
|
|
1330
1575
|
}
|
|
1331
1576
|
}
|
|
1332
1577
|
}
|
|
@@ -1346,7 +1591,7 @@ var W = class {
|
|
|
1346
1591
|
}));
|
|
1347
1592
|
}
|
|
1348
1593
|
stop() {
|
|
1349
|
-
this.endWatchdog &&= (clearInterval(this.endWatchdog), null), this.
|
|
1594
|
+
this.endWatchdog &&= (clearInterval(this.endWatchdog), null), this.clearKick(), this.stopped = !0, this.loadSuspended = !1, this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null);
|
|
1350
1595
|
try {
|
|
1351
1596
|
this.hls?.stopLoad();
|
|
1352
1597
|
} catch {}
|
|
@@ -1355,7 +1600,7 @@ var W = class {
|
|
|
1355
1600
|
} catch {}
|
|
1356
1601
|
}
|
|
1357
1602
|
destroy() {
|
|
1358
|
-
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) {
|
|
1603
|
+
if (this.prefetch?.destroy(), this.prefetch = null, 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) {
|
|
1359
1604
|
try {
|
|
1360
1605
|
this.hls.destroy();
|
|
1361
1606
|
} catch (e) {
|
|
@@ -1370,7 +1615,7 @@ var W = class {
|
|
|
1370
1615
|
scheduleLicenseRetry(t) {
|
|
1371
1616
|
if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
|
|
1372
1617
|
let n = t.response?.code ?? 0;
|
|
1373
|
-
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >=
|
|
1618
|
+
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= Ze) return !1;
|
|
1374
1619
|
this.licenseRecoveries += 1;
|
|
1375
1620
|
let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
|
|
1376
1621
|
return this.licenseRetryTimer = setTimeout(() => {
|
|
@@ -1402,7 +1647,7 @@ var W = class {
|
|
|
1402
1647
|
return;
|
|
1403
1648
|
}
|
|
1404
1649
|
if (t.type === e.ErrorTypes.NETWORK_ERROR) {
|
|
1405
|
-
if (this.networkRecoveries <
|
|
1650
|
+
if (this.networkRecoveries < Xe) {
|
|
1406
1651
|
this.networkRecoveries += 1;
|
|
1407
1652
|
let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
|
|
1408
1653
|
this.networkRetryTimer = setTimeout(() => {
|
|
@@ -1419,7 +1664,7 @@ var W = class {
|
|
|
1419
1664
|
return;
|
|
1420
1665
|
}
|
|
1421
1666
|
if (t.type === e.ErrorTypes.MEDIA_ERROR) {
|
|
1422
|
-
if (this.mediaRecoveries <
|
|
1667
|
+
if (this.mediaRecoveries < Ye) {
|
|
1423
1668
|
this.mediaRecoveries += 1, n.recoverMediaError();
|
|
1424
1669
|
return;
|
|
1425
1670
|
}
|
|
@@ -1443,19 +1688,19 @@ var W = class {
|
|
|
1443
1688
|
let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
|
|
1444
1689
|
return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
|
|
1445
1690
|
}
|
|
1446
|
-
},
|
|
1691
|
+
}, gt = 15e3, _t = 6e5, vt = 3e5, yt = 100, Y = 1, bt = 1e3, xt = 3e4, St = 1e3, Ct = {
|
|
1447
1692
|
inline: "PRESENTATION_INLINE",
|
|
1448
1693
|
fullscreen: "PRESENTATION_FULLSCREEN",
|
|
1449
1694
|
pip: "PRESENTATION_PIP"
|
|
1450
|
-
},
|
|
1695
|
+
}, wt = {
|
|
1451
1696
|
widevine: "KEY_SYSTEM_WIDEVINE",
|
|
1452
1697
|
fairplay: "KEY_SYSTEM_FAIRPLAY",
|
|
1453
1698
|
none: "KEY_SYSTEM_NONE"
|
|
1454
1699
|
};
|
|
1455
|
-
function
|
|
1700
|
+
function Tt(e, t) {
|
|
1456
1701
|
return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
|
|
1457
1702
|
}
|
|
1458
|
-
var
|
|
1703
|
+
var Et = /* @__PURE__ */ new Set([
|
|
1459
1704
|
"INVALID_URN",
|
|
1460
1705
|
"NOT_FOUND",
|
|
1461
1706
|
"GONE",
|
|
@@ -1465,7 +1710,7 @@ var pt = /* @__PURE__ */ new Set([
|
|
|
1465
1710
|
"FORBIDDEN",
|
|
1466
1711
|
"RATE_LIMITED",
|
|
1467
1712
|
"TIMEOUT"
|
|
1468
|
-
]),
|
|
1713
|
+
]), X = {
|
|
1469
1714
|
idle: "PLAYER_STATE_IDLE",
|
|
1470
1715
|
waiting: "PLAYER_STATE_WAITING",
|
|
1471
1716
|
loading: "PLAYER_STATE_LOADING",
|
|
@@ -1475,7 +1720,7 @@ var pt = /* @__PURE__ */ new Set([
|
|
|
1475
1720
|
ended: "PLAYER_STATE_ENDED",
|
|
1476
1721
|
error: "PLAYER_STATE_ERROR"
|
|
1477
1722
|
};
|
|
1478
|
-
function
|
|
1723
|
+
function Dt(e) {
|
|
1479
1724
|
try {
|
|
1480
1725
|
let t = new URL(e), [n, ...r] = t.hostname.split(".");
|
|
1481
1726
|
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);
|
|
@@ -1483,14 +1728,14 @@ function mt(e) {
|
|
|
1483
1728
|
return;
|
|
1484
1729
|
}
|
|
1485
1730
|
}
|
|
1486
|
-
var
|
|
1487
|
-
function
|
|
1488
|
-
return
|
|
1731
|
+
var Ot = /* @__PURE__ */ new Set();
|
|
1732
|
+
function kt(e, t) {
|
|
1733
|
+
return Ot.has(e) || (Ot.add(e), console.warn(`havik-player: ${t}`)), { disabledReason: t };
|
|
1489
1734
|
}
|
|
1490
|
-
function
|
|
1735
|
+
function At(e, t) {
|
|
1491
1736
|
if (t) return { endpoint: t };
|
|
1492
|
-
if (t !== void 0) return
|
|
1493
|
-
let n =
|
|
1737
|
+
if (t !== void 0) return kt("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).");
|
|
1738
|
+
let n = Dt(e);
|
|
1494
1739
|
if (n) return { endpoint: n };
|
|
1495
1740
|
let r;
|
|
1496
1741
|
try {
|
|
@@ -1498,9 +1743,9 @@ function ht(e, t) {
|
|
|
1498
1743
|
} catch {
|
|
1499
1744
|
r = e;
|
|
1500
1745
|
}
|
|
1501
|
-
return
|
|
1746
|
+
return kt(r, `analytics is disabled: no QoE beacons will be sent. The beacons endpoint cannot be derived from the baseUrl host "${r}" — 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).`);
|
|
1502
1747
|
}
|
|
1503
|
-
var
|
|
1748
|
+
var jt = class {
|
|
1504
1749
|
opts;
|
|
1505
1750
|
url;
|
|
1506
1751
|
now;
|
|
@@ -1567,6 +1812,8 @@ var gt = class {
|
|
|
1567
1812
|
startupTimeMs = 0;
|
|
1568
1813
|
manifestLoadMs = 0;
|
|
1569
1814
|
firstFragLoadMs = 0;
|
|
1815
|
+
firstPlaylistMs = 0;
|
|
1816
|
+
drmSetupMs = 0;
|
|
1570
1817
|
onPagehide = () => this.end("END_REASON_PAGEHIDE");
|
|
1571
1818
|
onFreeze = () => {
|
|
1572
1819
|
this.endedFlag || this.flush(!0);
|
|
@@ -1578,8 +1825,8 @@ var gt = class {
|
|
|
1578
1825
|
constructor(e) {
|
|
1579
1826
|
this.opts = {
|
|
1580
1827
|
...e,
|
|
1581
|
-
heartbeatMs: e.heartbeatMs ??
|
|
1582
|
-
idleMs: e.idleMs ??
|
|
1828
|
+
heartbeatMs: e.heartbeatMs ?? gt,
|
|
1829
|
+
idleMs: e.idleMs ?? _t
|
|
1583
1830
|
}, 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;
|
|
1584
1831
|
}
|
|
1585
1832
|
start() {
|
|
@@ -1589,11 +1836,11 @@ var gt = class {
|
|
|
1589
1836
|
sdkVersion: this.opts.sdkVersion,
|
|
1590
1837
|
...this.opts.environment
|
|
1591
1838
|
};
|
|
1592
|
-
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(),
|
|
1839
|
+
this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), bt), this.lastTickMs = this.now(), this.timer = setInterval(() => this.heartbeat(), this.opts.heartbeatMs), typeof window < "u" && window.addEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.addEventListener("visibilitychange", this.onVisibility), document.addEventListener("freeze", this.onFreeze), document.addEventListener("resume", this.onResume), this.onVisibility());
|
|
1593
1840
|
}
|
|
1594
1841
|
checkSuspension(e) {
|
|
1595
1842
|
if (this.endedFlag || !this.opts.idleMs) return !1;
|
|
1596
|
-
let t = Math.max(this.opts.idleMs,
|
|
1843
|
+
let t = Math.max(this.opts.idleMs, vt);
|
|
1597
1844
|
return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
|
|
1598
1845
|
}
|
|
1599
1846
|
syncIdle(e) {
|
|
@@ -1607,21 +1854,21 @@ var gt = class {
|
|
|
1607
1854
|
noteStateChange(e, t, n, r) {
|
|
1608
1855
|
if (this.endedFlag || e === t) return;
|
|
1609
1856
|
let i = this.now();
|
|
1610
|
-
if (t === "playing" ? (this.playingSinceMs === null && (this.playingSinceMs = i), this.startupTimeMs === 0 && (this.startupTimeMs = Math.max(
|
|
1857
|
+
if (t === "playing" ? (this.playingSinceMs === null && (this.playingSinceMs = i), this.startupTimeMs === 0 && (this.startupTimeMs = Math.max(Y, i - this.startupAnchorMs)), this.firstAudioMs === 0 && !this.isMuted && (this.firstAudioMs = Math.max(Y, i - this.startupAnchorMs)), this.isMuted && this.mutedSinceMs === null && (this.mutedSinceMs = i)) : this.playingSinceMs !== null && (this.playingTotalMs += i - this.playingSinceMs, this.playingSinceMs = null, this.mutedSinceMs !== null && (this.mutedTotalMs += i - this.mutedSinceMs, this.mutedSinceMs = null)), this.isPlaying = t === "playing", this.syncActive(), t === "waiting" ? this.waitingSinceMs = i : this.waitingSinceMs !== null && (this.waitingTotalMs += i - this.waitingSinceMs, this.waitingSinceMs = null), t === "buffering" && e === "playing") {
|
|
1611
1858
|
this.stallIsSeekInduced = this.seekInduced(i);
|
|
1612
1859
|
let e = !this.isHidden && !this.stallIsSeekInduced;
|
|
1613
|
-
e && (this.rebufferCount += 1), this.isBuffering = !0, this.lastStallMs = i, e && this.timeToFirstStallMs === 0 && (this.timeToFirstStallMs = Math.max(
|
|
1860
|
+
e && (this.rebufferCount += 1), this.isBuffering = !0, this.lastStallMs = i, e && this.timeToFirstStallMs === 0 && (this.timeToFirstStallMs = Math.max(Y, Math.round(this.playingTotalMs)));
|
|
1614
1861
|
} else e === "buffering" && (this.isBuffering = !1, this.stallIsSeekInduced = !1);
|
|
1615
1862
|
this.syncBuffering(), t === "paused" && (this.pauseCount += 1), this.syncIdle(t);
|
|
1616
1863
|
let a = {
|
|
1617
|
-
fromState:
|
|
1618
|
-
toState:
|
|
1619
|
-
presentation:
|
|
1864
|
+
fromState: X[e] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
1865
|
+
toState: X[t] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
1866
|
+
presentation: Ct[this.presentation]
|
|
1620
1867
|
}, o = this.causeOf(e, t, i);
|
|
1621
1868
|
o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
|
|
1622
1869
|
}
|
|
1623
1870
|
seekInduced(e) {
|
|
1624
|
-
return this.lastSeekMs >= 0 && e - this.lastSeekMs <
|
|
1871
|
+
return this.lastSeekMs >= 0 && e - this.lastSeekMs < St;
|
|
1625
1872
|
}
|
|
1626
1873
|
causeOf(e, t, n) {
|
|
1627
1874
|
if (t === "error") return "TRANSITION_CAUSE_ERROR";
|
|
@@ -1658,19 +1905,25 @@ var gt = class {
|
|
|
1658
1905
|
}
|
|
1659
1906
|
this.muteChanges += 1;
|
|
1660
1907
|
let r = this.now();
|
|
1661
|
-
n ? this.isPlaying && this.mutedSinceMs === null && (this.mutedSinceMs = r) : (this.mutedSinceMs !== null && (this.mutedTotalMs += r - this.mutedSinceMs, this.mutedSinceMs = null), this.firstAudioMs === 0 && this.isPlaying && (this.firstAudioMs = Math.max(
|
|
1908
|
+
n ? this.isPlaying && this.mutedSinceMs === null && (this.mutedSinceMs = r) : (this.mutedSinceMs !== null && (this.mutedTotalMs += r - this.mutedSinceMs, this.mutedSinceMs = null), this.firstAudioMs === 0 && this.isPlaying && (this.firstAudioMs = Math.max(Y, r - this.startupAnchorMs))), this.isMuted = n, this.syncActive();
|
|
1662
1909
|
}
|
|
1663
1910
|
notePresentation(e) {
|
|
1664
1911
|
this.endedFlag || e === this.presentation || (this.closePresentation(), this.presentation = e);
|
|
1665
1912
|
}
|
|
1666
1913
|
notePlayIntent() {
|
|
1667
|
-
this.endedFlag || this.startupTimeMs > 0 || (this.startupAnchorMs = this.now(), this.manifestLoadMs > 0 && (this.manifestLoadMs =
|
|
1914
|
+
this.endedFlag || this.startupTimeMs > 0 || (this.startupAnchorMs = this.now(), this.manifestLoadMs > 0 && (this.manifestLoadMs = Y), this.firstPlaylistMs > 0 && (this.firstPlaylistMs = Y), this.firstFragLoadMs > 0 && (this.firstFragLoadMs = Y), this.drmSetupMs > 0 && (this.drmSetupMs = Y));
|
|
1668
1915
|
}
|
|
1669
1916
|
noteReady() {
|
|
1670
|
-
this.manifestLoadMs === 0 && (this.manifestLoadMs = Math.max(
|
|
1917
|
+
this.manifestLoadMs === 0 && (this.manifestLoadMs = Math.max(Y, this.now() - this.startupAnchorMs));
|
|
1918
|
+
}
|
|
1919
|
+
noteFirstPlaylist() {
|
|
1920
|
+
this.firstPlaylistMs === 0 && (this.firstPlaylistMs = Math.max(Y, this.now() - this.startupAnchorMs));
|
|
1921
|
+
}
|
|
1922
|
+
noteDrmReady() {
|
|
1923
|
+
this.drmSetupMs === 0 && (this.drmSetupMs = Math.max(Y, this.now() - this.startupAnchorMs));
|
|
1671
1924
|
}
|
|
1672
1925
|
noteFirstBytes() {
|
|
1673
|
-
this.sawFirstBytes = !0, this.firstFragLoadMs === 0 && (this.firstFragLoadMs = Math.max(
|
|
1926
|
+
this.sawFirstBytes = !0, this.firstFragLoadMs === 0 && (this.firstFragLoadMs = Math.max(Y, this.now() - this.startupAnchorMs));
|
|
1674
1927
|
}
|
|
1675
1928
|
noteSeek() {
|
|
1676
1929
|
this.endedFlag || (this.seekCount += 1, this.lastSeekMs = this.now());
|
|
@@ -1689,7 +1942,7 @@ var gt = class {
|
|
|
1689
1942
|
let r = n ?? "";
|
|
1690
1943
|
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";
|
|
1691
1944
|
if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
|
|
1692
|
-
if (
|
|
1945
|
+
if (Et.has(e)) return "ERROR_STAGE_RESOLVE";
|
|
1693
1946
|
let i = t ?? "";
|
|
1694
1947
|
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";
|
|
1695
1948
|
}
|
|
@@ -1721,7 +1974,7 @@ var gt = class {
|
|
|
1721
1974
|
let l = t.droppedFrames ?? 0;
|
|
1722
1975
|
l > this.lastDropped && (o.droppedFramesDelta = l - this.lastDropped), this.lastDropped = l;
|
|
1723
1976
|
let u = t.renditionSwitches ?? 0;
|
|
1724
|
-
u > this.lastSwitches && (o.renditionSwitchesDelta = u - this.lastSwitches), this.lastSwitches = u, n > this.lastHbPlayingMs && (o.playingMsDelta = Math.round(n - this.lastHbPlayingMs)), this.lastHbPlayingMs = n, r > this.lastHbHiddenMs && (o.hiddenMsDelta = Math.round(r - this.lastHbHiddenMs)), this.lastHbHiddenMs = r, i > this.lastHbRebufferMs && (o.rebufferMsDelta = Math.round(i - this.lastHbRebufferMs)), this.lastHbRebufferMs = i, this.rebufferCount > this.lastHbRebufferCount && (o.rebufferCountDelta = this.rebufferCount - this.lastHbRebufferCount), this.lastHbRebufferCount = this.rebufferCount, a > this.lastHbActiveMs && (o.activeMsDelta = Math.round(a - this.lastHbActiveMs)), this.lastHbActiveMs = a, typeof t.latencySeconds == "number" && (o.latencyMs = Math.round(t.latencySeconds * 1e3)), typeof t.targetLatencySeconds == "number" && (o.targetLatencyMs = Math.round(t.targetLatencySeconds * 1e3)), typeof t.bandwidthKbps == "number" && (o.bandwidthEstKbps = t.bandwidthKbps), typeof t.levelHeight == "number" && (o.renditionHeight = t.levelHeight), typeof t.renditionBitrateKbps == "number" && (o.renditionBitrateKbps = t.renditionBitrateKbps), t.atLiveEdge === !0 && (o.atLiveEdge = !0), typeof t.bufferedMs == "number" && t.bufferedMs > 0 && (o.bufferedMs = Math.round(t.bufferedMs)), o.playerState =
|
|
1977
|
+
u > this.lastSwitches && (o.renditionSwitchesDelta = u - this.lastSwitches), this.lastSwitches = u, n > this.lastHbPlayingMs && (o.playingMsDelta = Math.round(n - this.lastHbPlayingMs)), this.lastHbPlayingMs = n, r > this.lastHbHiddenMs && (o.hiddenMsDelta = Math.round(r - this.lastHbHiddenMs)), this.lastHbHiddenMs = r, i > this.lastHbRebufferMs && (o.rebufferMsDelta = Math.round(i - this.lastHbRebufferMs)), this.lastHbRebufferMs = i, this.rebufferCount > this.lastHbRebufferCount && (o.rebufferCountDelta = this.rebufferCount - this.lastHbRebufferCount), this.lastHbRebufferCount = this.rebufferCount, a > this.lastHbActiveMs && (o.activeMsDelta = Math.round(a - this.lastHbActiveMs)), this.lastHbActiveMs = a, typeof t.latencySeconds == "number" && (o.latencyMs = Math.round(t.latencySeconds * 1e3)), typeof t.targetLatencySeconds == "number" && (o.targetLatencyMs = Math.round(t.targetLatencySeconds * 1e3)), typeof t.bandwidthKbps == "number" && (o.bandwidthEstKbps = t.bandwidthKbps), typeof t.levelHeight == "number" && (o.renditionHeight = t.levelHeight), typeof t.renditionBitrateKbps == "number" && (o.renditionBitrateKbps = t.renditionBitrateKbps), t.atLiveEdge === !0 && (o.atLiveEdge = !0), typeof t.bufferedMs == "number" && t.bufferedMs > 0 && (o.bufferedMs = Math.round(t.bufferedMs)), o.playerState = X[t.state] ?? "PLAYER_STATE_UNSPECIFIED";
|
|
1725
1978
|
let d = this.mutedTotalMs;
|
|
1726
1979
|
this.mutedSinceMs !== null && (d += e - this.mutedSinceMs), d > this.lastHbMutedMs && (o.mutedMsDelta = Math.round(d - this.lastHbMutedMs)), this.lastHbMutedMs = d;
|
|
1727
1980
|
let f = t.upshifts ?? 0;
|
|
@@ -1736,14 +1989,14 @@ var gt = class {
|
|
|
1736
1989
|
if (this.lastRequestCount = g, _ > 0) {
|
|
1737
1990
|
o.requestCountDelta = _;
|
|
1738
1991
|
let e = t.requestTimesMs ?? [], n = e.slice(Math.max(0, e.length - _)).sort((e, t) => e - t);
|
|
1739
|
-
n.length > 0 && (o.requestTimeP50Ms =
|
|
1992
|
+
n.length > 0 && (o.requestTimeP50Ms = Tt(n, 50), o.requestTimeP95Ms = Tt(n, 95));
|
|
1740
1993
|
}
|
|
1741
1994
|
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();
|
|
1742
1995
|
}
|
|
1743
1996
|
maybeEmitMediaInfo(e) {
|
|
1744
1997
|
if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
|
|
1745
1998
|
let t = {};
|
|
1746
|
-
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem =
|
|
1999
|
+
e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = wt[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);
|
|
1747
2000
|
let n = JSON.stringify(t);
|
|
1748
2001
|
n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
|
|
1749
2002
|
}
|
|
@@ -1755,7 +2008,7 @@ var gt = class {
|
|
|
1755
2008
|
let r = this.safeSample();
|
|
1756
2009
|
r && this.maybeEmitMediaInfo(r);
|
|
1757
2010
|
let i = { reason: e }, a = r?.bytesLoaded ?? this.lastBytes;
|
|
1758
|
-
a > 0 && (i.bytesDownloadedTotal = a), this.playingTotalMs > 0 && (i.watchTimeMs = Math.round(this.playingTotalMs)), this.rebufferCount > 0 && (i.rebufferCount = this.rebufferCount), this.rebufferTotalMs > 0 && (i.rebufferTimeMs = Math.round(this.rebufferTotalMs)), this.startupTimeMs > 0 && (i.startupTimeMs = Math.round(this.startupTimeMs)), this.manifestLoadMs > 0 && (i.manifestLoadMs = Math.round(this.manifestLoadMs)), this.firstFragLoadMs > 0 && (i.firstFragLoadMs = Math.round(this.firstFragLoadMs));
|
|
2011
|
+
a > 0 && (i.bytesDownloadedTotal = a), this.playingTotalMs > 0 && (i.watchTimeMs = Math.round(this.playingTotalMs)), this.rebufferCount > 0 && (i.rebufferCount = this.rebufferCount), this.rebufferTotalMs > 0 && (i.rebufferTimeMs = Math.round(this.rebufferTotalMs)), this.startupTimeMs > 0 && (i.startupTimeMs = Math.round(this.startupTimeMs)), this.manifestLoadMs > 0 && (i.manifestLoadMs = Math.round(this.manifestLoadMs)), this.firstPlaylistMs > 0 && (i.firstPlaylistMs = Math.round(this.firstPlaylistMs)), this.firstFragLoadMs > 0 && (i.firstFragLoadMs = Math.round(this.firstFragLoadMs)), this.drmSetupMs > 0 && (i.drmSetupMs = Math.round(this.drmSetupMs));
|
|
1759
2012
|
let o = r?.licenseTimeMs ?? 0;
|
|
1760
2013
|
o > 0 && (i.licenseTimeMs = Math.round(o));
|
|
1761
2014
|
let s = r?.droppedFrames ?? this.lastDropped;
|
|
@@ -1763,9 +2016,9 @@ var gt = class {
|
|
|
1763
2016
|
let c = r?.positionMs ?? 0;
|
|
1764
2017
|
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));
|
|
1765
2018
|
let l = e !== "END_REASON_ENDED";
|
|
1766
|
-
l && this.lastStallMs > 0 && n - this.lastStallMs <=
|
|
2019
|
+
l && this.lastStallMs > 0 && n - this.lastStallMs <= xt && (i.abandonAfterStallMs = Math.max(Y, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= xt && (i.abandonAfterErrorMs = Math.max(Y, 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);
|
|
1767
2020
|
let u = r?.decodedFrames ?? this.lastDecoded;
|
|
1768
|
-
u > 0 && (i.decodedFramesTotal = u), this.startupTimeMs === 0 && (i.failedStage = this.lastErrorStage ?? (this.manifestLoadMs === 0 ? "ERROR_STAGE_MANIFEST" : this.firstFragLoadMs === 0 ? "ERROR_STAGE_FIRST_SEGMENT" : "ERROR_STAGE_OTHER")), this.pending.push(this.wrap({ sessionEnd: i })), this.flush(e === "END_REASON_PAGEHIDE");
|
|
2021
|
+
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");
|
|
1769
2022
|
}
|
|
1770
2023
|
safeSample() {
|
|
1771
2024
|
try {
|
|
@@ -1783,7 +2036,7 @@ var gt = class {
|
|
|
1783
2036
|
};
|
|
1784
2037
|
}
|
|
1785
2038
|
enqueue(e) {
|
|
1786
|
-
for (this.pending.push(this.wrap(e)); this.pending.length >
|
|
2039
|
+
for (this.pending.push(this.wrap(e)); this.pending.length > yt;) {
|
|
1787
2040
|
let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
|
|
1788
2041
|
this.pending.splice(e >= 0 ? e : 0, 1);
|
|
1789
2042
|
}
|
|
@@ -1806,7 +2059,7 @@ var gt = class {
|
|
|
1806
2059
|
};
|
|
1807
2060
|
//#endregion
|
|
1808
2061
|
//#region src/core/environment.ts
|
|
1809
|
-
function
|
|
2062
|
+
function Mt() {
|
|
1810
2063
|
if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
|
|
1811
2064
|
let e;
|
|
1812
2065
|
try {
|
|
@@ -1831,14 +2084,14 @@ function _t() {
|
|
|
1831
2084
|
integration: "INTEGRATION_KIND_IFRAME"
|
|
1832
2085
|
};
|
|
1833
2086
|
}
|
|
1834
|
-
function
|
|
2087
|
+
function Nt() {
|
|
1835
2088
|
if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
|
|
1836
2089
|
let e = navigator.userAgentData, t = e?.platform ?? "";
|
|
1837
2090
|
if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
|
|
1838
2091
|
let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
|
|
1839
2092
|
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";
|
|
1840
2093
|
}
|
|
1841
|
-
function
|
|
2094
|
+
function Pt() {
|
|
1842
2095
|
let e = typeof navigator < "u" ? navigator.connection : void 0;
|
|
1843
2096
|
if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
|
|
1844
2097
|
let t = {
|
|
@@ -1857,17 +2110,17 @@ function yt() {
|
|
|
1857
2110
|
}
|
|
1858
2111
|
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;
|
|
1859
2112
|
}
|
|
1860
|
-
function
|
|
1861
|
-
let t =
|
|
1862
|
-
deviceClass:
|
|
2113
|
+
function Ft(e) {
|
|
2114
|
+
let t = Mt(), n = {
|
|
2115
|
+
deviceClass: Nt(),
|
|
1863
2116
|
integration: t.integration,
|
|
1864
|
-
...
|
|
2117
|
+
...Pt()
|
|
1865
2118
|
};
|
|
1866
2119
|
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);
|
|
1867
2120
|
let r = e.getBoundingClientRect?.();
|
|
1868
2121
|
return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
|
|
1869
2122
|
}
|
|
1870
|
-
async function
|
|
2123
|
+
async function It() {
|
|
1871
2124
|
let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
|
|
1872
2125
|
if (!e?.getHighEntropyValues) return {};
|
|
1873
2126
|
try {
|
|
@@ -1879,7 +2132,7 @@ async function xt() {
|
|
|
1879
2132
|
}
|
|
1880
2133
|
//#endregion
|
|
1881
2134
|
//#region src/core/version.ts
|
|
1882
|
-
var
|
|
2135
|
+
var Lt = "2.11.0", Rt = {
|
|
1883
2136
|
accent: "#E1B600",
|
|
1884
2137
|
accentText: "#1B1C23",
|
|
1885
2138
|
background: "#0e0f13",
|
|
@@ -1890,7 +2143,7 @@ var St = "2.9.3", Ct = {
|
|
|
1890
2143
|
border: "rgba(255, 255, 255, 0.1)",
|
|
1891
2144
|
radius: "8px",
|
|
1892
2145
|
fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
|
|
1893
|
-
},
|
|
2146
|
+
}, zt = {
|
|
1894
2147
|
accent: "--havik-accent",
|
|
1895
2148
|
accentText: "--havik-accent-text",
|
|
1896
2149
|
background: "--havik-bg",
|
|
@@ -1902,25 +2155,25 @@ var St = "2.9.3", Ct = {
|
|
|
1902
2155
|
radius: "--havik-radius",
|
|
1903
2156
|
fontFamily: "--havik-font"
|
|
1904
2157
|
};
|
|
1905
|
-
function
|
|
2158
|
+
function Z(e, t) {
|
|
1906
2159
|
let n = {
|
|
1907
|
-
...
|
|
2160
|
+
...Rt,
|
|
1908
2161
|
...t
|
|
1909
2162
|
};
|
|
1910
|
-
for (let t of Object.keys(
|
|
2163
|
+
for (let t of Object.keys(zt)) e.style.setProperty(zt[t], n[t]);
|
|
1911
2164
|
n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
|
|
1912
2165
|
}
|
|
1913
2166
|
//#endregion
|
|
1914
2167
|
//#region src/ui/styles.ts
|
|
1915
|
-
var
|
|
1916
|
-
function
|
|
1917
|
-
if (e.getElementById(
|
|
2168
|
+
var Bt = "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/* 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";
|
|
2169
|
+
function Ht(e = document) {
|
|
2170
|
+
if (e.getElementById(Bt)) return;
|
|
1918
2171
|
let t = e.createElement("style");
|
|
1919
|
-
t.id =
|
|
2172
|
+
t.id = Bt, t.textContent = Vt, e.head.appendChild(t);
|
|
1920
2173
|
}
|
|
1921
2174
|
//#endregion
|
|
1922
2175
|
//#region src/ui/icons.ts
|
|
1923
|
-
var
|
|
2176
|
+
var Ut = {
|
|
1924
2177
|
play: "<path d=\"M8 5v14l11-7z\"/>",
|
|
1925
2178
|
pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
|
|
1926
2179
|
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\"/>",
|
|
@@ -1933,21 +2186,21 @@ var kt = {
|
|
|
1933
2186
|
liveDot: "<circle cx=\"12\" cy=\"12\" r=\"6\"/>",
|
|
1934
2187
|
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\"/>"
|
|
1935
2188
|
};
|
|
1936
|
-
function
|
|
1937
|
-
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${
|
|
2189
|
+
function Q(e) {
|
|
2190
|
+
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Ut[e]}</svg>`;
|
|
1938
2191
|
}
|
|
1939
2192
|
//#endregion
|
|
1940
2193
|
//#region src/ui/controls.ts
|
|
1941
|
-
var
|
|
2194
|
+
var Wt = 3e3, Gt = /* @__PURE__ */ new Set([
|
|
1942
2195
|
"GONE",
|
|
1943
2196
|
"NOT_FOUND",
|
|
1944
2197
|
"INVALID_URN",
|
|
1945
2198
|
"UNAUTHORIZED"
|
|
1946
2199
|
]);
|
|
1947
|
-
function
|
|
1948
|
-
return new
|
|
2200
|
+
function Kt(e) {
|
|
2201
|
+
return new qt(e);
|
|
1949
2202
|
}
|
|
1950
|
-
var
|
|
2203
|
+
var qt = class {
|
|
1951
2204
|
root;
|
|
1952
2205
|
video;
|
|
1953
2206
|
player;
|
|
@@ -1989,7 +2242,7 @@ var Nt = class {
|
|
|
1989
2242
|
scrubbing = !1;
|
|
1990
2243
|
offFns = [];
|
|
1991
2244
|
constructor(e) {
|
|
1992
|
-
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ??
|
|
2245
|
+
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Wt, 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, Ht(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");
|
|
1993
2246
|
let t = (e, t, n) => {
|
|
1994
2247
|
let r = this.doc.createElement(e);
|
|
1995
2248
|
if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
|
|
@@ -2000,12 +2253,12 @@ var Nt = class {
|
|
|
2000
2253
|
"aria-label": r,
|
|
2001
2254
|
title: r
|
|
2002
2255
|
});
|
|
2003
|
-
return i.innerHTML =
|
|
2256
|
+
return i.innerHTML = Q(n), i;
|
|
2004
2257
|
};
|
|
2005
2258
|
this.overlay = t("div", "havik-overlay"), this.center = t("button", "havik-center", {
|
|
2006
2259
|
type: "button",
|
|
2007
2260
|
"aria-label": "Play"
|
|
2008
|
-
}), this.center.innerHTML =
|
|
2261
|
+
}), this.center.innerHTML = Q("play"), this.spinner = t("div", "havik-spinner"), this.spinner.style.display = "none", this.overlay.append(this.center, this.spinner), this.gradient = t("div", "havik-gradient"), this.bar = t("div", "havik-bar"), this.seek = t("div", "havik-seek", {
|
|
2009
2262
|
role: "slider",
|
|
2010
2263
|
"aria-label": "Seek",
|
|
2011
2264
|
"aria-valuemin": "0",
|
|
@@ -2023,7 +2276,7 @@ var Nt = class {
|
|
|
2023
2276
|
"aria-label": "Volume"
|
|
2024
2277
|
});
|
|
2025
2278
|
let a = t("div", "havik-vol");
|
|
2026
|
-
a.append(this.muteBtn, this.volSlider), this.live = t("div", "havik-live"), this.live.innerHTML =
|
|
2279
|
+
a.append(this.muteBtn, this.volSlider), this.live = t("div", "havik-live"), this.live.innerHTML = Q("liveDot");
|
|
2027
2280
|
let o = this.doc.createElement("span");
|
|
2028
2281
|
o.textContent = "LIVE", this.liveGo = t("button", "havik-live__go", { type: "button" }), this.liveGo.textContent = "Go live", this.live.append(o, this.liveGo), this.time = t("div", "havik-time"), this.time.textContent = "0:00", this.time.style.display = "none";
|
|
2029
2282
|
let s = t("div", "havik-spacer");
|
|
@@ -2077,12 +2330,12 @@ var Nt = class {
|
|
|
2077
2330
|
}
|
|
2078
2331
|
if (e === "preplay") {
|
|
2079
2332
|
let e = this.doc.createElement("button");
|
|
2080
|
-
e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML =
|
|
2333
|
+
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);
|
|
2081
2334
|
} else {
|
|
2082
2335
|
let r = this.doc.createElement("div");
|
|
2083
|
-
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !
|
|
2336
|
+
if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !Gt.has(this.lastError.code)) {
|
|
2084
2337
|
let e = this.doc.createElement("button");
|
|
2085
|
-
e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${
|
|
2338
|
+
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);
|
|
2086
2339
|
}
|
|
2087
2340
|
}
|
|
2088
2341
|
this.root.append(n), this.statusBox = n, this.show();
|
|
@@ -2121,11 +2374,11 @@ var Nt = class {
|
|
|
2121
2374
|
let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
|
|
2122
2375
|
this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
|
|
2123
2376
|
}
|
|
2124
|
-
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${
|
|
2377
|
+
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Jt(this.video.currentTime)} / ${Jt(this.video.duration)}`);
|
|
2125
2378
|
}
|
|
2126
2379
|
syncLive() {
|
|
2127
2380
|
let e = this.player.getStats(), t = e.isLive !== !1;
|
|
2128
|
-
this.live.style.display = t ? "" : "none", this.time.style.display = t ? "none" : "", this.live.classList.toggle("is-live", e.atLiveEdge !== !1 && t);
|
|
2381
|
+
this.live.style.display = t ? "" : "none", this.time.style.display = t ? "none" : "", this.seek.style.display = t ? "none" : "", this.live.classList.toggle("is-live", e.atLiveEdge !== !1 && t);
|
|
2129
2382
|
}
|
|
2130
2383
|
onSeekDown(e) {
|
|
2131
2384
|
let t = this.seekableRange();
|
|
@@ -2171,17 +2424,17 @@ var Nt = class {
|
|
|
2171
2424
|
renderQualityMenu() {
|
|
2172
2425
|
let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
|
|
2173
2426
|
n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
|
|
2174
|
-
for (let n of e) this.menu.append(this.menuItem(
|
|
2427
|
+
for (let n of e) this.menu.append(this.menuItem(Yt(n), t === n.index, () => this.player.setQuality(n.index)));
|
|
2175
2428
|
}
|
|
2176
2429
|
renderAudioMenu() {
|
|
2177
2430
|
let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
|
|
2178
2431
|
t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
|
|
2179
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
2432
|
+
for (let t of e) this.menu.append(this.menuItem(Xt(t), t.default, () => this.player.setAudioTrack(t.id)));
|
|
2180
2433
|
}
|
|
2181
2434
|
renderCcMenu() {
|
|
2182
2435
|
let e = this.player.getTextTracks(), t = this.doc.createElement("div");
|
|
2183
2436
|
t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
|
|
2184
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
2437
|
+
for (let t of e) this.menu.append(this.menuItem(Zt(t), !1, () => this.player.setTextTrack(t.id)));
|
|
2185
2438
|
}
|
|
2186
2439
|
onTracksChanged() {
|
|
2187
2440
|
this.openMenu && this.renderMenu(this.openMenu);
|
|
@@ -2264,7 +2517,7 @@ var Nt = class {
|
|
|
2264
2517
|
}
|
|
2265
2518
|
}
|
|
2266
2519
|
setIcon(e, t) {
|
|
2267
|
-
e.innerHTML =
|
|
2520
|
+
e.innerHTML = Q(t);
|
|
2268
2521
|
}
|
|
2269
2522
|
destroy() {
|
|
2270
2523
|
this.hideTimer && clearTimeout(this.hideTimer);
|
|
@@ -2281,41 +2534,41 @@ var Nt = class {
|
|
|
2281
2534
|
this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
|
|
2282
2535
|
}
|
|
2283
2536
|
};
|
|
2284
|
-
function
|
|
2537
|
+
function Jt(e) {
|
|
2285
2538
|
(!Number.isFinite(e) || e < 0) && (e = 0);
|
|
2286
2539
|
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");
|
|
2287
2540
|
return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
|
|
2288
2541
|
}
|
|
2289
|
-
function
|
|
2542
|
+
function Yt(e) {
|
|
2290
2543
|
return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
|
|
2291
2544
|
}
|
|
2292
|
-
function
|
|
2545
|
+
function Xt(e) {
|
|
2293
2546
|
return e.name || e.lang || `Track ${e.id}`;
|
|
2294
2547
|
}
|
|
2295
|
-
function
|
|
2548
|
+
function Zt(e) {
|
|
2296
2549
|
return e.name || e.lang || `Track ${e.id}`;
|
|
2297
2550
|
}
|
|
2298
2551
|
//#endregion
|
|
2299
2552
|
//#region src/managed/index.ts
|
|
2300
|
-
var
|
|
2301
|
-
function
|
|
2553
|
+
var Qt = 6e3, $t = 45e3, en = 2e3, tn = 3, nn = 2e3, rn = 48e4;
|
|
2554
|
+
function an(e) {
|
|
2302
2555
|
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)})`);
|
|
2303
|
-
if (e.env !== void 0) return
|
|
2556
|
+
if (e.env !== void 0) return L(e.env);
|
|
2304
2557
|
if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
|
|
2305
2558
|
return e.baseUrl;
|
|
2306
2559
|
}
|
|
2307
|
-
async function
|
|
2560
|
+
async function on(e) {
|
|
2308
2561
|
if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
2309
|
-
let t =
|
|
2562
|
+
let t = an(e);
|
|
2310
2563
|
if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
2311
2564
|
if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
|
|
2312
|
-
let r = new
|
|
2565
|
+
let r = new sn({
|
|
2313
2566
|
...e,
|
|
2314
2567
|
baseUrl: t
|
|
2315
2568
|
});
|
|
2316
2569
|
return await r.start(), r;
|
|
2317
2570
|
}
|
|
2318
|
-
var
|
|
2571
|
+
var sn = class {
|
|
2319
2572
|
opts;
|
|
2320
2573
|
abort = new AbortController();
|
|
2321
2574
|
listeners = {};
|
|
@@ -2403,7 +2656,7 @@ var Gt = class {
|
|
|
2403
2656
|
setTimeout(() => {
|
|
2404
2657
|
a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
|
|
2405
2658
|
phase: i ? "unavailable" : "tooEarly",
|
|
2406
|
-
retryInMs:
|
|
2659
|
+
retryInMs: $t,
|
|
2407
2660
|
attempt: 1,
|
|
2408
2661
|
elapsedMs: 0,
|
|
2409
2662
|
...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
|
|
@@ -2442,13 +2695,13 @@ var Gt = class {
|
|
|
2442
2695
|
!a && !p() && h();
|
|
2443
2696
|
}, e);
|
|
2444
2697
|
};
|
|
2445
|
-
_(
|
|
2698
|
+
_(Qt), this.armingSub = E({
|
|
2446
2699
|
eventsBaseUrl: t,
|
|
2447
2700
|
matchUrn: this.opts.matchUrn,
|
|
2448
2701
|
credential: this.opts.credential,
|
|
2449
|
-
onAlive: () => _(
|
|
2702
|
+
onAlive: () => _($t),
|
|
2450
2703
|
onState: (e) => {
|
|
2451
|
-
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() *
|
|
2704
|
+
a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * en);
|
|
2452
2705
|
},
|
|
2453
2706
|
onError: () => h()
|
|
2454
2707
|
});
|
|
@@ -2471,7 +2724,7 @@ var Gt = class {
|
|
|
2471
2724
|
let n = await s(this.opts.credential);
|
|
2472
2725
|
if (this.destroyed || t !== this.loadGen) return;
|
|
2473
2726
|
this.setState("loading");
|
|
2474
|
-
let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a =
|
|
2727
|
+
let r = this.opts.autoplay === !1 && !this.playRequested, i = this.createEngine(e, n, r), a = Re(this.opts.video, (e) => {
|
|
2475
2728
|
this._state !== "ended" && this._state !== "error" && this.setState(e);
|
|
2476
2729
|
});
|
|
2477
2730
|
if (await i.load(), this.destroyed || t !== this.loadGen) {
|
|
@@ -2493,23 +2746,23 @@ var Gt = class {
|
|
|
2493
2746
|
if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
|
|
2494
2747
|
let i = e.analytics?.sid;
|
|
2495
2748
|
if (!i) return;
|
|
2496
|
-
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } =
|
|
2749
|
+
let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = At(this.opts.baseUrl, a);
|
|
2497
2750
|
if (!o) {
|
|
2498
2751
|
s && setTimeout(() => {
|
|
2499
2752
|
this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
|
|
2500
2753
|
}, 0);
|
|
2501
2754
|
return;
|
|
2502
2755
|
}
|
|
2503
|
-
let c = this.opts.video, l = new
|
|
2756
|
+
let c = this.opts.video, l = new jt({
|
|
2504
2757
|
endpoint: o,
|
|
2505
2758
|
sid: i,
|
|
2506
2759
|
player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
|
|
2507
|
-
sdkVersion:
|
|
2508
|
-
environment:
|
|
2760
|
+
sdkVersion: Lt,
|
|
2761
|
+
environment: Ft(c),
|
|
2509
2762
|
idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
|
|
2510
2763
|
onIdle: () => this.onAnalyticsIdle(t),
|
|
2511
2764
|
sample: () => {
|
|
2512
|
-
let e = this.engine?.getStats() ??
|
|
2765
|
+
let e = this.engine?.getStats() ?? R, t = c.buffered.length ? Math.max(0, c.buffered.end(c.buffered.length - 1) - c.currentTime) : 0;
|
|
2513
2766
|
return {
|
|
2514
2767
|
...e,
|
|
2515
2768
|
bufferedMs: Math.round(t * 1e3),
|
|
@@ -2523,7 +2776,7 @@ var Gt = class {
|
|
|
2523
2776
|
let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
|
|
2524
2777
|
c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
|
|
2525
2778
|
c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
|
|
2526
|
-
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()),
|
|
2779
|
+
}, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), It().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
|
|
2527
2780
|
}
|
|
2528
2781
|
currentPresentation() {
|
|
2529
2782
|
let e = this.opts.video;
|
|
@@ -2542,20 +2795,30 @@ var Gt = class {
|
|
|
2542
2795
|
userId: this.opts.userId,
|
|
2543
2796
|
lowLatency: this.opts.lowLatency === void 0 || this.opts.lowLatency === "auto" || this.opts.lowLatency,
|
|
2544
2797
|
snapToLiveOnRefocus: this.opts.snapToLiveOnRefocus,
|
|
2798
|
+
mediaDuringKey: this.opts.mediaDuringKey,
|
|
2545
2799
|
debug: this.opts.debug,
|
|
2546
2800
|
deferLoad: r,
|
|
2547
2801
|
hlsConfig: i,
|
|
2548
2802
|
emit: (e) => this.onEngineEvent(e)
|
|
2549
2803
|
}, o = this.opts.engine ?? "auto";
|
|
2550
|
-
if (o === "native") return new
|
|
2551
|
-
if (o === "hls") return new
|
|
2552
|
-
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl &&
|
|
2553
|
-
if (
|
|
2554
|
-
if (
|
|
2804
|
+
if (o === "native") return new U(a);
|
|
2805
|
+
if (o === "hls") return new J(a);
|
|
2806
|
+
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && V(this.opts.video) && H()) return new U(a);
|
|
2807
|
+
if (Je()) return new J(a);
|
|
2808
|
+
if (V(this.opts.video)) return new U(a);
|
|
2555
2809
|
throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
|
|
2556
2810
|
}
|
|
2557
2811
|
onEngineEvent(e) {
|
|
2558
2812
|
if (!this.destroyed) switch (e.type) {
|
|
2813
|
+
case "firstPlaylist":
|
|
2814
|
+
this.analyticsSession?.noteFirstPlaylist();
|
|
2815
|
+
break;
|
|
2816
|
+
case "firstBytes":
|
|
2817
|
+
this.analyticsSession?.noteFirstBytes();
|
|
2818
|
+
break;
|
|
2819
|
+
case "drmReady":
|
|
2820
|
+
this.analyticsSession?.noteDrmReady();
|
|
2821
|
+
break;
|
|
2559
2822
|
case "ready":
|
|
2560
2823
|
this.analyticsSession?.noteReady(), this.emit("ready"), (this.opts.autoplay !== !1 || this.playRequested) && this.play();
|
|
2561
2824
|
break;
|
|
@@ -2594,7 +2857,7 @@ var Gt = class {
|
|
|
2594
2857
|
r = 0, i = !1;
|
|
2595
2858
|
},
|
|
2596
2859
|
onError: () => {
|
|
2597
|
-
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >=
|
|
2860
|
+
this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= tn && (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.`))));
|
|
2598
2861
|
}
|
|
2599
2862
|
});
|
|
2600
2863
|
}
|
|
@@ -2616,7 +2879,7 @@ var Gt = class {
|
|
|
2616
2879
|
scheduleRejoin(e) {
|
|
2617
2880
|
this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
|
|
2618
2881
|
this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
|
|
2619
|
-
}, Math.random() *
|
|
2882
|
+
}, Math.random() * en));
|
|
2620
2883
|
}
|
|
2621
2884
|
cancelRejoin() {
|
|
2622
2885
|
this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
|
|
@@ -2640,7 +2903,7 @@ var Gt = class {
|
|
|
2640
2903
|
}
|
|
2641
2904
|
t.controls = !1;
|
|
2642
2905
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
2643
|
-
r && r.insertBefore(n, t), n.appendChild(t),
|
|
2906
|
+
r && r.insertBefore(n, t), n.appendChild(t), Z(n, this.opts.theme), this.container = n, this.controlBar = Kt({
|
|
2644
2907
|
root: n,
|
|
2645
2908
|
video: t,
|
|
2646
2909
|
player: this,
|
|
@@ -2670,7 +2933,7 @@ var Gt = class {
|
|
|
2670
2933
|
}
|
|
2671
2934
|
startStats() {
|
|
2672
2935
|
this.stopStats();
|
|
2673
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
2936
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? nn);
|
|
2674
2937
|
this.statsTimer = setInterval(() => {
|
|
2675
2938
|
if (!this.engine) return;
|
|
2676
2939
|
let e = this.engine.getStats();
|
|
@@ -2682,7 +2945,7 @@ var Gt = class {
|
|
|
2682
2945
|
}
|
|
2683
2946
|
scheduleLicenseRefresh() {
|
|
2684
2947
|
this.stopRefresh();
|
|
2685
|
-
let e = this.opts.licenseRefreshMs ??
|
|
2948
|
+
let e = this.opts.licenseRefreshMs ?? rn;
|
|
2686
2949
|
e && this._descriptor?.drmEnabled && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
2687
2950
|
}
|
|
2688
2951
|
stopRefresh() {
|
|
@@ -2727,7 +2990,7 @@ var Gt = class {
|
|
|
2727
2990
|
this.destroyed || (this.opts.video.volume = Math.min(1, Math.max(0, e)));
|
|
2728
2991
|
}
|
|
2729
2992
|
getStats() {
|
|
2730
|
-
return this.engine?.getStats() ??
|
|
2993
|
+
return this.engine?.getStats() ?? R;
|
|
2731
2994
|
}
|
|
2732
2995
|
getQualityLevels() {
|
|
2733
2996
|
return this.engine?.getQualityLevels() ?? [];
|
|
@@ -2837,7 +3100,7 @@ function $(e) {
|
|
|
2837
3100
|
}
|
|
2838
3101
|
//#endregion
|
|
2839
3102
|
//#region src/embed/host.ts
|
|
2840
|
-
function
|
|
3103
|
+
function cn(e) {
|
|
2841
3104
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
2842
3105
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
2843
3106
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -2896,15 +3159,15 @@ function Kt(e) {
|
|
|
2896
3159
|
}
|
|
2897
3160
|
//#endregion
|
|
2898
3161
|
//#region src/embed/page.ts
|
|
2899
|
-
var
|
|
2900
|
-
function
|
|
3162
|
+
var ln = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
3163
|
+
function un(e) {
|
|
2901
3164
|
if (typeof e == "boolean") return e;
|
|
2902
3165
|
if (typeof e == "object" && e) {
|
|
2903
3166
|
let t = e.endpoint;
|
|
2904
3167
|
return typeof t == "string" ? { endpoint: t } : {};
|
|
2905
3168
|
}
|
|
2906
3169
|
}
|
|
2907
|
-
function
|
|
3170
|
+
function dn() {
|
|
2908
3171
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
2909
3172
|
if (e) return {
|
|
2910
3173
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -2914,7 +3177,7 @@ function Yt() {
|
|
|
2914
3177
|
autoplay: e.autoplay ?? !0,
|
|
2915
3178
|
muted: e.muted ?? !0,
|
|
2916
3179
|
waitForLive: e.waitForLive ?? !0,
|
|
2917
|
-
analytics:
|
|
3180
|
+
analytics: un(e.analytics)
|
|
2918
3181
|
};
|
|
2919
3182
|
let t = new URLSearchParams(location.search);
|
|
2920
3183
|
return {
|
|
@@ -2927,9 +3190,9 @@ function Yt() {
|
|
|
2927
3190
|
waitForLive: !0
|
|
2928
3191
|
};
|
|
2929
3192
|
}
|
|
2930
|
-
async function
|
|
2931
|
-
let e =
|
|
2932
|
-
|
|
3193
|
+
async function fn() {
|
|
3194
|
+
let e = dn();
|
|
3195
|
+
mn();
|
|
2933
3196
|
let t = document.createElement("video");
|
|
2934
3197
|
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);
|
|
2935
3198
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
@@ -2984,12 +3247,12 @@ async function Xt() {
|
|
|
2984
3247
|
code: e.code,
|
|
2985
3248
|
message: e.message
|
|
2986
3249
|
})), e.on("autoplayblocked", () => {
|
|
2987
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
3250
|
+
i({ type: "oddin:autoplayblocked" }), pn(t, e);
|
|
2988
3251
|
});
|
|
2989
3252
|
}, s = async (r) => {
|
|
2990
3253
|
a?.destroy(), a = null;
|
|
2991
3254
|
try {
|
|
2992
|
-
let n = await
|
|
3255
|
+
let n = await on({
|
|
2993
3256
|
video: t,
|
|
2994
3257
|
baseUrl: e.baseUrl,
|
|
2995
3258
|
matchUrn: r,
|
|
@@ -3051,7 +3314,7 @@ async function Xt() {
|
|
|
3051
3314
|
a?.retry();
|
|
3052
3315
|
break;
|
|
3053
3316
|
case "oddin:load":
|
|
3054
|
-
typeof e.matchUrn == "string" &&
|
|
3317
|
+
typeof e.matchUrn == "string" && ln.test(e.matchUrn) && s(e.matchUrn);
|
|
3055
3318
|
break;
|
|
3056
3319
|
case "oddin:destroy": c();
|
|
3057
3320
|
}
|
|
@@ -3063,18 +3326,18 @@ async function Xt() {
|
|
|
3063
3326
|
protocol: 1
|
|
3064
3327
|
});
|
|
3065
3328
|
}
|
|
3066
|
-
function
|
|
3329
|
+
function pn(e, t) {
|
|
3067
3330
|
if (document.getElementById("havik-tap")) return;
|
|
3068
3331
|
let n = document.createElement("button");
|
|
3069
3332
|
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", () => {
|
|
3070
3333
|
n.remove(), t.play();
|
|
3071
3334
|
}), document.body.appendChild(n);
|
|
3072
3335
|
}
|
|
3073
|
-
function
|
|
3336
|
+
function mn() {
|
|
3074
3337
|
let e = document.createElement("style");
|
|
3075
3338
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
3076
3339
|
}
|
|
3077
3340
|
//#endregion
|
|
3078
|
-
export {
|
|
3341
|
+
export { Rt as ODDIN_THEME, n as PlaybackError, Z as applyTheme, L as baseUrlForEnv, fn as bootEmbed, be as clearDeviceId, on as createPlayer, D as deriveEventsBaseUrl, Ne as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, pe as fetchCatalog, he as fetchTournament, _e as flattenMatches, A as getDeviceId, Fe as isLowLatencyManifest, $ as isOddinMessage, Se as licenseRequestHeaders, cn as mountEmbed, v as pollToLive, b as resolveStream, E as subscribeLiveState, C as videoFullscreenActive, ve as watchStatus };
|
|
3079
3342
|
|
|
3080
3343
|
//# sourceMappingURL=index.js.map
|