@oddin-gg/havik-player 1.15.0 → 1.16.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 +4 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +41 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +431 -346
- package/dist/index.js.map +1 -1
- package/embed/index.html +1 -1
- package/examples/vanilla.html +1 -1
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import e from "hls.js";
|
|
1
|
+
import e, { CapLevelController as t } from "hls.js";
|
|
2
2
|
//#region src/core/errors.ts
|
|
3
|
-
var
|
|
3
|
+
var n = class extends Error {
|
|
4
4
|
code;
|
|
5
5
|
httpStatus;
|
|
6
6
|
retryAfterMs;
|
|
@@ -11,7 +11,7 @@ var t = class extends Error {
|
|
|
11
11
|
super(n), this.name = "PlaybackError", this.code = e, this.httpStatus = t, this.retryAfterMs = r?.retryAfterMs, this.requestId = r?.requestId, this.serverCode = r?.serverCode, this.liveStartsAtMs = r?.liveStartsAtMs, r?.cause !== void 0 && (this.cause = r.cause);
|
|
12
12
|
}
|
|
13
13
|
};
|
|
14
|
-
function
|
|
14
|
+
function r(e) {
|
|
15
15
|
switch (e) {
|
|
16
16
|
case 400: return "INVALID_URN";
|
|
17
17
|
case 401: return "UNAUTHORIZED";
|
|
@@ -24,102 +24,102 @@ function n(e) {
|
|
|
24
24
|
default: return "INTERNAL";
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
-
function
|
|
27
|
+
function i(e) {
|
|
28
28
|
return e === 401 ? "UNAUTHORIZED" : e === 403 ? "FORBIDDEN" : "DRM_CLIENT";
|
|
29
29
|
}
|
|
30
|
-
var
|
|
30
|
+
var a = /* @__PURE__ */ new Set([
|
|
31
31
|
"TOO_EARLY",
|
|
32
32
|
"UNAVAILABLE",
|
|
33
33
|
"RATE_LIMITED",
|
|
34
34
|
"NETWORK"
|
|
35
35
|
]);
|
|
36
|
-
function
|
|
37
|
-
return
|
|
36
|
+
function o(e) {
|
|
37
|
+
return a.has(e);
|
|
38
38
|
}
|
|
39
39
|
//#endregion
|
|
40
40
|
//#region src/core/types.ts
|
|
41
|
-
async function
|
|
41
|
+
async function s(e) {
|
|
42
42
|
let t = typeof e == "function" ? await e() : e;
|
|
43
43
|
if (!t || !t.apiKey) throw Error("havik-player: credential is missing an apiKey");
|
|
44
44
|
return t;
|
|
45
45
|
}
|
|
46
46
|
//#endregion
|
|
47
47
|
//#region src/core/http.ts
|
|
48
|
-
function
|
|
48
|
+
function c(e, t) {
|
|
49
49
|
let r = e.replace(/\/+$/, ""), i;
|
|
50
50
|
try {
|
|
51
|
-
i = new URL(r +
|
|
51
|
+
i = new URL(r + t);
|
|
52
52
|
} catch {
|
|
53
|
-
throw new
|
|
53
|
+
throw new n("INTERNAL", 0, `invalid baseUrl: ${JSON.stringify(e)}`);
|
|
54
54
|
}
|
|
55
|
-
if (i.protocol !== "https:" && i.protocol !== "http:") throw new
|
|
55
|
+
if (i.protocol !== "https:" && i.protocol !== "http:") throw new n("INTERNAL", 0, `baseUrl must be http(s), got: ${JSON.stringify(e)}`);
|
|
56
56
|
return i.toString();
|
|
57
57
|
}
|
|
58
|
-
function
|
|
58
|
+
function l(e) {
|
|
59
59
|
if (!e) return;
|
|
60
60
|
let t = Number(e);
|
|
61
61
|
if (Number.isFinite(t)) return Math.max(0, Math.round(t * 1e3));
|
|
62
62
|
let n = Date.parse(e);
|
|
63
63
|
if (!Number.isNaN(n)) return Math.max(0, n - Date.now());
|
|
64
64
|
}
|
|
65
|
-
async function
|
|
66
|
-
let r = await
|
|
67
|
-
if (
|
|
65
|
+
async function u(e, t) {
|
|
66
|
+
let r = await s(t.credential), i = t.headers ?? new Headers();
|
|
67
|
+
if (t.apiHeaders) for (let [e, n] of Object.entries(t.apiHeaders)) i.has(e) || i.set(e, n);
|
|
68
68
|
i.set("x-api-key", r.apiKey);
|
|
69
69
|
try {
|
|
70
70
|
return await fetch(e, {
|
|
71
|
-
method:
|
|
71
|
+
method: t.method ?? "GET",
|
|
72
72
|
headers: i,
|
|
73
|
-
body:
|
|
74
|
-
signal:
|
|
73
|
+
body: t.body,
|
|
74
|
+
signal: t.signal,
|
|
75
75
|
cache: "no-store",
|
|
76
76
|
credentials: "omit",
|
|
77
77
|
mode: "cors"
|
|
78
78
|
});
|
|
79
79
|
} catch (e) {
|
|
80
|
-
throw
|
|
80
|
+
throw t.signal?.aborted ? new n("ABORTED", 0, "request aborted", { cause: e }) : new n("NETWORK", 0, `network request failed: ${d(e)}`, { cause: e });
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
|
-
function
|
|
83
|
+
function d(e) {
|
|
84
84
|
return e instanceof Error ? e.message : String(e);
|
|
85
85
|
}
|
|
86
86
|
//#endregion
|
|
87
87
|
//#region src/core/waitForLive.ts
|
|
88
|
-
var
|
|
88
|
+
var f = 1e3, p = 3e4, m = 6e5, h = 3e5, g = 1e3, ee = {
|
|
89
89
|
TOO_EARLY: "tooEarly",
|
|
90
90
|
UNAVAILABLE: "unavailable",
|
|
91
91
|
RATE_LIMITED: "rateLimited",
|
|
92
92
|
NETWORK: "network"
|
|
93
93
|
};
|
|
94
|
-
function
|
|
95
|
-
let t = e === !0 || e === !1 ? {} : e, n = Math.max(
|
|
94
|
+
function te(e) {
|
|
95
|
+
let t = e === !0 || e === !1 ? {} : e, n = Math.max(g, t.floorMs ?? f), r = Math.max(n, t.ceilMs ?? p), i = Math.max(0, t.imminentMs ?? m), a = Math.max(r, t.sanityFloorMs ?? h);
|
|
96
96
|
return {
|
|
97
97
|
timeoutMs: t.timeoutMs,
|
|
98
98
|
floorMs: n,
|
|
99
99
|
ceilMs: r,
|
|
100
100
|
imminentMs: i,
|
|
101
101
|
sanityFloorMs: a,
|
|
102
|
-
kickoffMs:
|
|
102
|
+
kickoffMs: ne(t.kickoffAt),
|
|
103
103
|
jitter: t.jitter ?? !0,
|
|
104
104
|
onState: t.onState
|
|
105
105
|
};
|
|
106
106
|
}
|
|
107
|
-
function
|
|
107
|
+
function ne(e) {
|
|
108
108
|
if (e == null) return;
|
|
109
109
|
if (typeof e == "number") return Number.isFinite(e) ? e : void 0;
|
|
110
110
|
let t = Date.parse(e);
|
|
111
111
|
return Number.isFinite(t) ? t : void 0;
|
|
112
112
|
}
|
|
113
|
-
function
|
|
113
|
+
function re(e, t, n) {
|
|
114
114
|
return Math.min(n, Math.max(t, e));
|
|
115
115
|
}
|
|
116
|
-
function
|
|
116
|
+
function ie(e) {
|
|
117
117
|
return Math.round(e * (1 + .15 * Math.random()));
|
|
118
118
|
}
|
|
119
|
-
function
|
|
119
|
+
function ae(e, t, n, r) {
|
|
120
120
|
let i = r ?? n.kickoffMs, a = i == null ? void 0 : Math.max(0, i - t), o = Math.max(n.floorMs, e ?? 0);
|
|
121
121
|
if (a == null || a <= n.imminentMs) return {
|
|
122
|
-
delay:
|
|
122
|
+
delay: re(e ?? n.floorMs, o, n.ceilMs),
|
|
123
123
|
ttkMs: a
|
|
124
124
|
};
|
|
125
125
|
let s = Math.min(Math.floor(a / 10), n.sanityFloorMs, a);
|
|
@@ -128,62 +128,62 @@ function re(e, t, n, r) {
|
|
|
128
128
|
ttkMs: a
|
|
129
129
|
};
|
|
130
130
|
}
|
|
131
|
-
function
|
|
131
|
+
function oe(e, t) {
|
|
132
132
|
return new Promise((r, i) => {
|
|
133
|
-
if (
|
|
134
|
-
i(new
|
|
133
|
+
if (t?.aborted) {
|
|
134
|
+
i(new n("ABORTED", 0, "wait-for-live aborted"));
|
|
135
135
|
return;
|
|
136
136
|
}
|
|
137
137
|
let a = () => {
|
|
138
|
-
clearTimeout(o), i(new
|
|
138
|
+
clearTimeout(o), i(new n("ABORTED", 0, "wait-for-live aborted"));
|
|
139
139
|
}, o = setTimeout(() => {
|
|
140
|
-
|
|
140
|
+
t?.removeEventListener("abort", a), r();
|
|
141
141
|
}, e);
|
|
142
|
-
|
|
142
|
+
t?.addEventListener("abort", a, { once: !0 });
|
|
143
143
|
});
|
|
144
144
|
}
|
|
145
|
-
async function
|
|
146
|
-
let i =
|
|
145
|
+
async function _(e, t, r) {
|
|
146
|
+
let i = te(t), a = Date.now(), s = i.timeoutMs == null ? Infinity : a + i.timeoutMs, c = 0, l;
|
|
147
147
|
for (;;) {
|
|
148
|
-
if (r?.aborted) throw new
|
|
148
|
+
if (r?.aborted) throw new n("ABORTED", 0, "wait-for-live aborted");
|
|
149
149
|
try {
|
|
150
150
|
return await e();
|
|
151
151
|
} catch (e) {
|
|
152
|
-
if (!(e instanceof
|
|
152
|
+
if (!(e instanceof n) || !o(e.code)) throw e;
|
|
153
153
|
c += 1, e.liveStartsAtMs != null && Number.isFinite(e.liveStartsAtMs) && (l = e.liveStartsAtMs);
|
|
154
|
-
let
|
|
155
|
-
if (i.jitter && (f =
|
|
154
|
+
let t = Date.now(), u = ae(e.retryAfterMs, t, i, l), d = u.ttkMs, f = u.delay;
|
|
155
|
+
if (i.jitter && (f = ie(f)), t + f > s) throw new n("TIMEOUT", e.httpStatus, `timed out after ${i.timeoutMs}ms waiting for the stream to go live`, {
|
|
156
156
|
retryAfterMs: e.retryAfterMs,
|
|
157
157
|
cause: e
|
|
158
158
|
});
|
|
159
159
|
i.onState?.({
|
|
160
|
-
phase:
|
|
160
|
+
phase: ee[e.code] ?? "unavailable",
|
|
161
161
|
retryInMs: f,
|
|
162
162
|
attempt: c,
|
|
163
|
-
elapsedMs:
|
|
163
|
+
elapsedMs: t - a,
|
|
164
164
|
ttkMs: d
|
|
165
|
-
}), await
|
|
165
|
+
}), await oe(f, r);
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
}
|
|
169
169
|
//#endregion
|
|
170
170
|
//#region src/core/resolve.ts
|
|
171
|
-
async function
|
|
172
|
-
if (!e.matchUrn || typeof e.matchUrn != "string") throw new
|
|
173
|
-
let
|
|
171
|
+
async function v(e) {
|
|
172
|
+
if (!e.matchUrn || typeof e.matchUrn != "string") throw new n("INVALID_URN", 0, "resolveStream: a non-empty matchUrn is required");
|
|
173
|
+
let t = await u(c(e.baseUrl, `/v1/playback/${encodeURIComponent(e.matchUrn)}`), {
|
|
174
174
|
credential: e.credential,
|
|
175
175
|
signal: e.signal,
|
|
176
176
|
apiHeaders: e.apiHeaders
|
|
177
177
|
});
|
|
178
|
-
if (!
|
|
179
|
-
return
|
|
178
|
+
if (!t.ok) throw await se(t);
|
|
179
|
+
return le(await t.json(), e.matchUrn);
|
|
180
180
|
}
|
|
181
|
-
function
|
|
182
|
-
let t = () =>
|
|
183
|
-
return e.waitForLive ?
|
|
181
|
+
function y(e) {
|
|
182
|
+
let t = () => v(e);
|
|
183
|
+
return e.waitForLive ? _(t, e.waitForLive, e.signal) : t();
|
|
184
184
|
}
|
|
185
|
-
async function
|
|
186
|
-
let
|
|
185
|
+
async function se(e) {
|
|
186
|
+
let t = l(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;
|
|
187
187
|
try {
|
|
188
188
|
let t = await e.json();
|
|
189
189
|
if (t?.error?.message && (a = t.error.message), t?.error?.code && (o = t.error.code), typeof t?.liveStartsAt == "string") {
|
|
@@ -191,14 +191,14 @@ async function ae(e) {
|
|
|
191
191
|
Number.isFinite(e) && (s = e);
|
|
192
192
|
}
|
|
193
193
|
} catch {}
|
|
194
|
-
return new
|
|
195
|
-
retryAfterMs:
|
|
194
|
+
return new n(r(e.status), e.status, a, {
|
|
195
|
+
retryAfterMs: t,
|
|
196
196
|
requestId: i,
|
|
197
197
|
serverCode: o,
|
|
198
198
|
liveStartsAtMs: s
|
|
199
199
|
});
|
|
200
200
|
}
|
|
201
|
-
var
|
|
201
|
+
var ce = /* @__PURE__ */ new Set([
|
|
202
202
|
"matchUrn",
|
|
203
203
|
"protocol",
|
|
204
204
|
"drmEnabled",
|
|
@@ -209,62 +209,90 @@ var oe = /* @__PURE__ */ new Set([
|
|
|
209
209
|
"expiresAt",
|
|
210
210
|
"analytics"
|
|
211
211
|
]);
|
|
212
|
-
function
|
|
212
|
+
function b(e, t) {
|
|
213
213
|
let r;
|
|
214
214
|
try {
|
|
215
|
-
r = new URL(
|
|
215
|
+
r = new URL(t);
|
|
216
216
|
} catch {
|
|
217
|
-
throw new
|
|
217
|
+
throw new n("INTERNAL", 0, `playback ${e} is not a valid URL`);
|
|
218
218
|
}
|
|
219
|
-
if (r.protocol !== "https:" && r.protocol !== "http:") throw new
|
|
220
|
-
return
|
|
219
|
+
if (r.protocol !== "https:" && r.protocol !== "http:") throw new n("INTERNAL", 0, `playback ${e} has a disallowed scheme: ${r.protocol}`);
|
|
220
|
+
return t;
|
|
221
221
|
}
|
|
222
|
-
function
|
|
223
|
-
if (!e.manifestUrl) throw new
|
|
222
|
+
function le(e, t) {
|
|
223
|
+
if (!e.manifestUrl) throw new n("INTERNAL", 0, "playback response is missing manifestUrl");
|
|
224
224
|
let r = e.drmEnabled ?? !!e.drm, i = {
|
|
225
|
-
matchUrn: e.matchUrn ??
|
|
225
|
+
matchUrn: e.matchUrn ?? t,
|
|
226
226
|
protocol: "hls",
|
|
227
227
|
drmEnabled: r,
|
|
228
|
-
manifestUrl:
|
|
228
|
+
manifestUrl: b("manifestUrl", e.manifestUrl),
|
|
229
229
|
serverTime: e.serverTime ?? ""
|
|
230
230
|
};
|
|
231
231
|
if (e.liveStartsAt && (i.liveStartsAt = e.liveStartsAt), typeof e.analytics?.sid == "string" && e.analytics.sid && (i.analytics = { sid: e.analytics.sid }), r && e.drm) {
|
|
232
232
|
let t = {};
|
|
233
|
-
e.drm.widevine?.licenseUrl && (t.widevine = { licenseUrl:
|
|
234
|
-
licenseUrl:
|
|
235
|
-
certificateUrl:
|
|
233
|
+
e.drm.widevine?.licenseUrl && (t.widevine = { licenseUrl: b("widevine licenseUrl", e.drm.widevine.licenseUrl) }), e.drm.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && (t.fairplay = {
|
|
234
|
+
licenseUrl: b("fairplay licenseUrl", e.drm.fairplay.licenseUrl),
|
|
235
|
+
certificateUrl: b("fairplay certificateUrl", e.drm.fairplay.certificateUrl)
|
|
236
236
|
}), (t.widevine || t.fairplay) && (i.drm = t);
|
|
237
237
|
}
|
|
238
238
|
let a = {};
|
|
239
|
-
for (let [t, n] of Object.entries(e))
|
|
239
|
+
for (let [t, n] of Object.entries(e)) ce.has(t) || (a[t] = n);
|
|
240
240
|
return Object.keys(a).length > 0 && (i.extensions = a), i;
|
|
241
241
|
}
|
|
242
242
|
//#endregion
|
|
243
|
+
//#region src/core/fullscreen.ts
|
|
244
|
+
function x(e) {
|
|
245
|
+
return e.ownerDocument ?? document;
|
|
246
|
+
}
|
|
247
|
+
function S(e) {
|
|
248
|
+
return e.fullscreenElement ?? e.webkitFullscreenElement ?? null;
|
|
249
|
+
}
|
|
250
|
+
function C(e, t) {
|
|
251
|
+
let n = S(x(e));
|
|
252
|
+
return n != null && (n === e || t != null && n === t) || e.webkitDisplayingFullscreen === !0;
|
|
253
|
+
}
|
|
254
|
+
async function w(e, t) {
|
|
255
|
+
let n = t ?? e;
|
|
256
|
+
if (typeof n.requestFullscreen == "function") return await n.requestFullscreen(), !0;
|
|
257
|
+
if (typeof n.webkitRequestFullscreen == "function") return n.webkitRequestFullscreen(), !0;
|
|
258
|
+
let r = e;
|
|
259
|
+
return r.webkitSupportsFullscreen && typeof r.webkitEnterFullscreen == "function" ? (r.webkitEnterFullscreen(), !0) : !1;
|
|
260
|
+
}
|
|
261
|
+
async function T(e, t) {
|
|
262
|
+
let n = e;
|
|
263
|
+
if (n.webkitDisplayingFullscreen) {
|
|
264
|
+
n.webkitExitFullscreen?.();
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
let r = x(e), i = S(r);
|
|
268
|
+
i != null && (i === e || t != null && i === t) && (typeof r.exitFullscreen == "function" ? await r.exitFullscreen() : r.webkitExitFullscreen?.());
|
|
269
|
+
}
|
|
270
|
+
//#endregion
|
|
243
271
|
//#region src/core/catalog.ts
|
|
244
|
-
async function
|
|
245
|
-
let
|
|
246
|
-
e.status &&
|
|
247
|
-
let i =
|
|
272
|
+
async function ue(e) {
|
|
273
|
+
let t = new URLSearchParams();
|
|
274
|
+
e.status && t.set("status", Array.isArray(e.status) ? e.status.join(",") : e.status), e.sport && t.set("sport", e.sport);
|
|
275
|
+
let i = t.toString(), a = c(e.baseUrl, "/v1/catalog" + (i ? `?${i}` : "")), o = new Headers();
|
|
248
276
|
e.etag && o.set("If-None-Match", e.etag);
|
|
249
|
-
let
|
|
277
|
+
let s = await u(a, {
|
|
250
278
|
credential: e.credential,
|
|
251
279
|
signal: e.signal,
|
|
252
280
|
headers: o,
|
|
253
281
|
apiHeaders: e.apiHeaders
|
|
254
282
|
});
|
|
255
|
-
if (
|
|
283
|
+
if (s.status === 304) return {
|
|
256
284
|
tournaments: [],
|
|
257
285
|
etag: e.etag,
|
|
258
286
|
notModified: !0
|
|
259
287
|
};
|
|
260
|
-
if (!
|
|
288
|
+
if (!s.ok) throw new n(r(s.status), s.status, `catalog request failed (HTTP ${s.status})`);
|
|
261
289
|
return {
|
|
262
|
-
tournaments:
|
|
263
|
-
etag:
|
|
290
|
+
tournaments: de(await s.json()),
|
|
291
|
+
etag: s.headers.get("etag") ?? void 0,
|
|
264
292
|
notModified: !1
|
|
265
293
|
};
|
|
266
294
|
}
|
|
267
|
-
function
|
|
295
|
+
function de(e) {
|
|
268
296
|
return (e.tournaments ?? []).map((e) => {
|
|
269
297
|
let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
|
|
270
298
|
return {
|
|
@@ -284,10 +312,10 @@ function se(e) {
|
|
|
284
312
|
};
|
|
285
313
|
});
|
|
286
314
|
}
|
|
287
|
-
async function
|
|
288
|
-
let
|
|
315
|
+
async function fe(e) {
|
|
316
|
+
let t = c(e.baseUrl, `/v1/tournaments/${encodeURIComponent(e.urn)}`), i = new Headers();
|
|
289
317
|
e.etag && i.set("If-None-Match", e.etag);
|
|
290
|
-
let a = await
|
|
318
|
+
let a = await u(t, {
|
|
291
319
|
credential: e.credential,
|
|
292
320
|
signal: e.signal,
|
|
293
321
|
headers: i,
|
|
@@ -302,15 +330,15 @@ async function ce(e) {
|
|
|
302
330
|
notModified: !1,
|
|
303
331
|
notFound: !0
|
|
304
332
|
};
|
|
305
|
-
if (!a.ok) throw new
|
|
333
|
+
if (!a.ok) throw new n(r(a.status), a.status, `tournament request failed (HTTP ${a.status})`);
|
|
306
334
|
return {
|
|
307
|
-
tournament:
|
|
335
|
+
tournament: pe(await a.json()),
|
|
308
336
|
etag: a.headers.get("etag") ?? void 0,
|
|
309
337
|
notModified: !1,
|
|
310
338
|
notFound: !1
|
|
311
339
|
};
|
|
312
340
|
}
|
|
313
|
-
function
|
|
341
|
+
function pe(e) {
|
|
314
342
|
let t = e.urn ?? "", n = e.name ?? "", r = e.sport ?? "";
|
|
315
343
|
return {
|
|
316
344
|
urn: t,
|
|
@@ -328,55 +356,55 @@ function le(e) {
|
|
|
328
356
|
}))
|
|
329
357
|
};
|
|
330
358
|
}
|
|
331
|
-
function
|
|
359
|
+
function me(e) {
|
|
332
360
|
return e.tournaments.flatMap((e) => e.matches);
|
|
333
361
|
}
|
|
334
362
|
//#endregion
|
|
335
363
|
//#region src/core/poll.ts
|
|
336
|
-
function
|
|
337
|
-
let
|
|
338
|
-
|
|
364
|
+
function he(e) {
|
|
365
|
+
let t = Math.max(2e3, e.intervalMs ?? 1e4), i = new AbortController(), a, o, s, l = !1, d = () => {
|
|
366
|
+
l || (a = setTimeout(f, t));
|
|
339
367
|
}, f = async () => {
|
|
340
368
|
try {
|
|
341
|
-
let
|
|
369
|
+
let t = c(e.baseUrl, `/v1/matches/${encodeURIComponent(e.matchUrn)}`), a = new Headers();
|
|
342
370
|
o && a.set("If-None-Match", o);
|
|
343
|
-
let
|
|
371
|
+
let l = await u(t, {
|
|
344
372
|
credential: e.credential,
|
|
345
373
|
signal: i.signal,
|
|
346
374
|
headers: a,
|
|
347
375
|
apiHeaders: e.apiHeaders
|
|
348
376
|
});
|
|
349
|
-
if (
|
|
350
|
-
if (!
|
|
351
|
-
o =
|
|
352
|
-
let
|
|
353
|
-
i !==
|
|
354
|
-
matchUrn:
|
|
355
|
-
matchName:
|
|
377
|
+
if (l.status !== 304) {
|
|
378
|
+
if (!l.ok) throw new n(r(l.status), l.status, `match status request failed (HTTP ${l.status})`);
|
|
379
|
+
o = l.headers.get("etag") ?? o;
|
|
380
|
+
let t = await l.json(), i = t.status ?? "upcoming";
|
|
381
|
+
i !== s && (s = i, e.onChange({
|
|
382
|
+
matchUrn: t.matchUrn ?? e.matchUrn,
|
|
383
|
+
matchName: t.matchName,
|
|
356
384
|
status: i,
|
|
357
|
-
datePlannedStart:
|
|
385
|
+
datePlannedStart: t.datePlannedStart
|
|
358
386
|
}));
|
|
359
387
|
}
|
|
360
|
-
} catch (
|
|
361
|
-
i.signal.aborted || e.onError?.(
|
|
388
|
+
} catch (t) {
|
|
389
|
+
i.signal.aborted || e.onError?.(t instanceof n ? t : new n("NETWORK", 0, String(t)));
|
|
362
390
|
} finally {
|
|
363
391
|
d();
|
|
364
392
|
}
|
|
365
393
|
};
|
|
366
394
|
return f(), { stop() {
|
|
367
|
-
|
|
395
|
+
l = !0, i.abort(), a && clearTimeout(a);
|
|
368
396
|
} };
|
|
369
397
|
}
|
|
370
398
|
//#endregion
|
|
371
399
|
//#region src/core/events.ts
|
|
372
|
-
function
|
|
400
|
+
function E(e) {
|
|
373
401
|
let t = Math.max(250, e.minBackoffMs ?? 1e3), n = Math.max(t, e.maxBackoffMs ?? 15e3), r = new AbortController(), i = !1, a = (e) => new Promise((t) => {
|
|
374
402
|
if (r.signal.aborted) return t();
|
|
375
403
|
let n = setTimeout(t, e);
|
|
376
404
|
r.signal.addEventListener("abort", () => {
|
|
377
405
|
clearTimeout(n), t();
|
|
378
406
|
}, { once: !0 });
|
|
379
|
-
}),
|
|
407
|
+
}), o = (t) => {
|
|
380
408
|
e.onAlive?.();
|
|
381
409
|
let n = "message", r = [];
|
|
382
410
|
for (let e of t.split("\n")) {
|
|
@@ -385,19 +413,19 @@ function w(e) {
|
|
|
385
413
|
let i = t.indexOf(":"), a = i < 0 ? t : t.slice(0, i), o = i < 0 ? "" : t.slice(i + 1);
|
|
386
414
|
o.startsWith(" ") && (o = o.slice(1)), a === "event" ? n = o : a === "data" && r.push(o);
|
|
387
415
|
}
|
|
388
|
-
if (
|
|
416
|
+
if (n === "state" && r.length !== 0) try {
|
|
389
417
|
let t = JSON.parse(r.join("\n"));
|
|
390
418
|
t && typeof t.state == "string" && e.onState(t);
|
|
391
419
|
} catch {}
|
|
392
420
|
}, l = /\r\n\r\n|\n\n|\r\r/, u = async (e, t) => {
|
|
393
|
-
let n = e.getReader(), r = new TextDecoder(), a = "",
|
|
421
|
+
let n = e.getReader(), r = new TextDecoder(), a = "", s = !1;
|
|
394
422
|
try {
|
|
395
423
|
for (;;) {
|
|
396
|
-
let { value: e, done:
|
|
397
|
-
if (
|
|
398
|
-
!
|
|
424
|
+
let { value: e, done: c } = await n.read();
|
|
425
|
+
if (c) return;
|
|
426
|
+
!s && e && e.length > 0 && (s = !0, t()), a += r.decode(e, { stream: !0 });
|
|
399
427
|
let u;
|
|
400
|
-
for (; (u = l.exec(a)) !== null;)
|
|
428
|
+
for (; (u = l.exec(a)) !== null;) o(a.slice(0, u.index)), a = a.slice(u.index + u[0].length);
|
|
401
429
|
if (i) return;
|
|
402
430
|
}
|
|
403
431
|
} finally {
|
|
@@ -405,12 +433,12 @@ function w(e) {
|
|
|
405
433
|
}
|
|
406
434
|
};
|
|
407
435
|
return (async () => {
|
|
408
|
-
let
|
|
436
|
+
let o = t;
|
|
409
437
|
for (; !i;) {
|
|
410
438
|
try {
|
|
411
|
-
let n = await
|
|
439
|
+
let n = await s(e.credential);
|
|
412
440
|
if (i) return;
|
|
413
|
-
let a =
|
|
441
|
+
let a = c(e.eventsBaseUrl, `/v1/events/${encodeURIComponent(e.matchUrn)}`), l = await fetch(a, {
|
|
414
442
|
method: "GET",
|
|
415
443
|
headers: {
|
|
416
444
|
"x-api-key": n.apiKey,
|
|
@@ -423,20 +451,20 @@ function w(e) {
|
|
|
423
451
|
});
|
|
424
452
|
if (i) return;
|
|
425
453
|
!l.ok || !l.body ? e.onError?.(/* @__PURE__ */ Error(`live-state subscribe failed: HTTP ${l.status}`)) : await u(l.body, () => {
|
|
426
|
-
|
|
454
|
+
o = t;
|
|
427
455
|
});
|
|
428
456
|
} catch (t) {
|
|
429
457
|
if (i || r.signal.aborted) return;
|
|
430
458
|
e.onError?.(t);
|
|
431
459
|
}
|
|
432
460
|
if (i) return;
|
|
433
|
-
await a(
|
|
461
|
+
await a(o), o = Math.min(n, o * 2);
|
|
434
462
|
}
|
|
435
463
|
})(), { close() {
|
|
436
464
|
i || (i = !0, r.abort());
|
|
437
465
|
} };
|
|
438
466
|
}
|
|
439
|
-
function
|
|
467
|
+
function D(e) {
|
|
440
468
|
try {
|
|
441
469
|
let t = new URL(e);
|
|
442
470
|
return t.hostname = `events.${t.hostname}`, t.pathname = "", t.search = "", t.origin;
|
|
@@ -446,27 +474,27 @@ function T(e) {
|
|
|
446
474
|
}
|
|
447
475
|
//#endregion
|
|
448
476
|
//#region src/core/drm/deviceId.ts
|
|
449
|
-
var
|
|
450
|
-
function
|
|
451
|
-
if (
|
|
477
|
+
var O = "havik.player.deviceId", k;
|
|
478
|
+
function A() {
|
|
479
|
+
if (k) return k;
|
|
452
480
|
try {
|
|
453
|
-
let e = globalThis.localStorage?.getItem(
|
|
454
|
-
if (e) return
|
|
481
|
+
let e = globalThis.localStorage?.getItem(O);
|
|
482
|
+
if (e) return k = e, e;
|
|
455
483
|
} catch {}
|
|
456
|
-
let e =
|
|
457
|
-
|
|
484
|
+
let e = _e();
|
|
485
|
+
k = e;
|
|
458
486
|
try {
|
|
459
|
-
globalThis.localStorage?.setItem(
|
|
487
|
+
globalThis.localStorage?.setItem(O, e);
|
|
460
488
|
} catch {}
|
|
461
489
|
return e;
|
|
462
490
|
}
|
|
463
|
-
function
|
|
464
|
-
|
|
491
|
+
function ge() {
|
|
492
|
+
k = void 0;
|
|
465
493
|
try {
|
|
466
|
-
globalThis.localStorage?.removeItem(
|
|
494
|
+
globalThis.localStorage?.removeItem(O);
|
|
467
495
|
} catch {}
|
|
468
496
|
}
|
|
469
|
-
function
|
|
497
|
+
function _e() {
|
|
470
498
|
let e = globalThis.crypto;
|
|
471
499
|
if (e && typeof e.randomUUID == "function") return e.randomUUID();
|
|
472
500
|
let t = /* @__PURE__ */ new Uint8Array(16);
|
|
@@ -478,22 +506,22 @@ function pe() {
|
|
|
478
506
|
}
|
|
479
507
|
//#endregion
|
|
480
508
|
//#region src/core/drm/headers.ts
|
|
481
|
-
function
|
|
509
|
+
function ve(e, t, n = {}) {
|
|
482
510
|
let r = {
|
|
483
511
|
"x-api-key": t.apiKey,
|
|
484
512
|
"X-Match-Urn": e.matchUrn,
|
|
485
|
-
"X-Device-Id": n.deviceId ??
|
|
513
|
+
"X-Device-Id": n.deviceId ?? A(),
|
|
486
514
|
"Content-Type": "application/octet-stream"
|
|
487
515
|
};
|
|
488
516
|
return n.userId && (r["X-User-Id"] = n.userId), r;
|
|
489
517
|
}
|
|
490
518
|
//#endregion
|
|
491
519
|
//#region src/core/drm/support.ts
|
|
492
|
-
var
|
|
520
|
+
var ye = 5e3, j = "video/mp4; codecs=\"avc1.42E01E\"", M = "audio/mp4; codecs=\"mp4a.40.2\"", be = {
|
|
493
521
|
widevine: ["com.widevine.alpha"],
|
|
494
522
|
fairplay: ["com.apple.fps"]
|
|
495
523
|
};
|
|
496
|
-
function
|
|
524
|
+
function N(e) {
|
|
497
525
|
return e === "fairplay" ? [{
|
|
498
526
|
initDataTypes: [
|
|
499
527
|
"sinf",
|
|
@@ -501,30 +529,30 @@ function _e(e) {
|
|
|
501
529
|
"cenc"
|
|
502
530
|
],
|
|
503
531
|
videoCapabilities: [{
|
|
504
|
-
contentType:
|
|
532
|
+
contentType: j,
|
|
505
533
|
robustness: "",
|
|
506
534
|
encryptionScheme: "cbcs"
|
|
507
535
|
}],
|
|
508
536
|
audioCapabilities: [{
|
|
509
|
-
contentType:
|
|
537
|
+
contentType: M,
|
|
510
538
|
robustness: "",
|
|
511
539
|
encryptionScheme: "cbcs"
|
|
512
540
|
}]
|
|
513
541
|
}] : [{
|
|
514
542
|
initDataTypes: ["cenc"],
|
|
515
543
|
videoCapabilities: [{
|
|
516
|
-
contentType:
|
|
544
|
+
contentType: j,
|
|
517
545
|
robustness: "SW_SECURE_DECODE",
|
|
518
546
|
encryptionScheme: "cbcs"
|
|
519
547
|
}],
|
|
520
548
|
audioCapabilities: [{
|
|
521
|
-
contentType:
|
|
549
|
+
contentType: M,
|
|
522
550
|
robustness: "SW_SECURE_CRYPTO",
|
|
523
551
|
encryptionScheme: "cbcs"
|
|
524
552
|
}]
|
|
525
553
|
}];
|
|
526
554
|
}
|
|
527
|
-
function
|
|
555
|
+
function P(e, t) {
|
|
528
556
|
return new Promise((n, r) => {
|
|
529
557
|
let i = setTimeout(() => r(/* @__PURE__ */ Error("probe-timeout")), t);
|
|
530
558
|
e.then((e) => {
|
|
@@ -534,8 +562,8 @@ function j(e, t) {
|
|
|
534
562
|
});
|
|
535
563
|
});
|
|
536
564
|
}
|
|
537
|
-
async function
|
|
538
|
-
let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ??
|
|
565
|
+
async function xe(e = {}) {
|
|
566
|
+
let t = e.systems ?? ["widevine", "fairplay"], n = e.timeoutMs ?? ye, r = {};
|
|
539
567
|
if (typeof window < "u" && window.isSecureContext === !1) return {
|
|
540
568
|
verdict: "insecure-context",
|
|
541
569
|
detail: r
|
|
@@ -547,7 +575,7 @@ async function M(e = {}) {
|
|
|
547
575
|
};
|
|
548
576
|
let a = !1, o = !1, s = Date.now() + n, c = () => Math.max(1, s - Date.now());
|
|
549
577
|
for (let e of t) {
|
|
550
|
-
let t =
|
|
578
|
+
let t = be[e];
|
|
551
579
|
if (!t) {
|
|
552
580
|
r[e] = "unknown system";
|
|
553
581
|
continue;
|
|
@@ -558,7 +586,7 @@ async function M(e = {}) {
|
|
|
558
586
|
break;
|
|
559
587
|
}
|
|
560
588
|
try {
|
|
561
|
-
return await
|
|
589
|
+
return await P((await P(i(n, N(e)), c())).createMediaKeys(), c()), r[e] = `ok (${n})`, {
|
|
562
590
|
verdict: "supported",
|
|
563
591
|
system: e,
|
|
564
592
|
detail: r
|
|
@@ -582,9 +610,9 @@ async function M(e = {}) {
|
|
|
582
610
|
}
|
|
583
611
|
//#endregion
|
|
584
612
|
//#region src/core/manifest.ts
|
|
585
|
-
var
|
|
586
|
-
function
|
|
587
|
-
return
|
|
613
|
+
var Se = /^#EXT-X-(PART-INF|PART|PRELOAD-HINT)[:\s]/m;
|
|
614
|
+
function Ce(e) {
|
|
615
|
+
return Se.test(e);
|
|
588
616
|
}
|
|
589
617
|
//#endregion
|
|
590
618
|
//#region src/core/stats.ts
|
|
@@ -592,7 +620,7 @@ var F = { droppedFrames: 0 };
|
|
|
592
620
|
function I(e) {
|
|
593
621
|
return e.getVideoPlaybackQuality?.()?.droppedVideoFrames ?? 0;
|
|
594
622
|
}
|
|
595
|
-
function
|
|
623
|
+
function we(e, t) {
|
|
596
624
|
let n = [
|
|
597
625
|
["playing", () => t("playing")],
|
|
598
626
|
["waiting", () => t("buffering")],
|
|
@@ -609,7 +637,7 @@ function ve(e, t) {
|
|
|
609
637
|
}
|
|
610
638
|
//#endregion
|
|
611
639
|
//#region src/core/engine/native.ts
|
|
612
|
-
function
|
|
640
|
+
function Te(e) {
|
|
613
641
|
try {
|
|
614
642
|
let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
|
|
615
643
|
return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
|
|
@@ -639,12 +667,12 @@ var z = class {
|
|
|
639
667
|
this.deps = e;
|
|
640
668
|
}
|
|
641
669
|
async load() {
|
|
642
|
-
let { video: e, descriptor:
|
|
643
|
-
if (
|
|
644
|
-
if (!
|
|
670
|
+
let { video: e, descriptor: t, emit: r } = this.deps;
|
|
671
|
+
if (t.drmEnabled) {
|
|
672
|
+
if (!t.drm?.fairplay) {
|
|
645
673
|
r({
|
|
646
674
|
type: "error",
|
|
647
|
-
error: new
|
|
675
|
+
error: new n("DRM_CLIENT", 0, "native HLS engine cannot satisfy this DRM (Widevine requires the hls.js engine); use engine \"auto\"/\"hls\" on a Widevine-capable browser"),
|
|
648
676
|
fatal: !0
|
|
649
677
|
});
|
|
650
678
|
return;
|
|
@@ -653,25 +681,25 @@ var z = class {
|
|
|
653
681
|
}
|
|
654
682
|
this.onLoaded = () => r({ type: "ready" }), this.onError = () => r({
|
|
655
683
|
type: "error",
|
|
656
|
-
error: new
|
|
684
|
+
error: new n("INTERNAL", 0, "native HLS playback error"),
|
|
657
685
|
fatal: !0
|
|
658
|
-
}), e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src =
|
|
686
|
+
}), e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = Ee(t.manifestUrl, t.analytics?.sid), e.load();
|
|
659
687
|
}
|
|
660
688
|
armFairPlay() {
|
|
661
|
-
let { video: e, descriptor:
|
|
689
|
+
let { video: e, descriptor: t, credential: r, deviceId: a, userId: o, emit: s } = this.deps, c = t.drm?.fairplay;
|
|
662
690
|
if (!c) return;
|
|
663
691
|
this.fairplayLicenseUrl = c.licenseUrl;
|
|
664
|
-
let l = (e,
|
|
692
|
+
let l = (e, t, r) => s({
|
|
665
693
|
type: "error",
|
|
666
|
-
error: new
|
|
667
|
-
fatal:
|
|
694
|
+
error: new n(i(t), t, e),
|
|
695
|
+
fatal: r
|
|
668
696
|
});
|
|
669
|
-
this.onEncrypted = (
|
|
670
|
-
let
|
|
671
|
-
!
|
|
697
|
+
this.onEncrypted = (n) => {
|
|
698
|
+
let i = n;
|
|
699
|
+
!i.initData || this.fairplayArmed || (this.fairplayArmed = !0, this.fairplayKeyIV = Te(i.initData), (async () => {
|
|
672
700
|
try {
|
|
673
|
-
let
|
|
674
|
-
initDataTypes: [
|
|
701
|
+
let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
|
|
702
|
+
initDataTypes: [i.initDataType],
|
|
675
703
|
videoCapabilities: [{
|
|
676
704
|
contentType: "application/vnd.apple.mpegurl",
|
|
677
705
|
robustness: ""
|
|
@@ -679,37 +707,37 @@ var z = class {
|
|
|
679
707
|
distinctiveIdentifier: "not-allowed",
|
|
680
708
|
persistentState: "not-allowed",
|
|
681
709
|
sessionTypes: ["temporary"]
|
|
682
|
-
}])).createMediaKeys(), s = await fetch(c.certificateUrl, { headers: { "x-api-key":
|
|
710
|
+
}])).createMediaKeys(), s = await fetch(c.certificateUrl, { headers: { "x-api-key": r.apiKey } });
|
|
683
711
|
if (!s.ok) {
|
|
684
712
|
this.fairplayArmed = !1, l(`FairPlay certificate request failed: ${s.status}`, s.status, !0);
|
|
685
713
|
return;
|
|
686
714
|
}
|
|
687
|
-
await
|
|
688
|
-
let u =
|
|
715
|
+
await n.setServerCertificate(await s.arrayBuffer()), await e.setMediaKeys(n);
|
|
716
|
+
let u = n.createSession();
|
|
689
717
|
this.keySession = u, u.addEventListener("message", (e) => {
|
|
690
718
|
(async () => {
|
|
691
719
|
try {
|
|
692
|
-
let
|
|
720
|
+
let n = await fetch(this.fairplayLicenseUrl ?? c.licenseUrl, {
|
|
693
721
|
method: "POST",
|
|
694
722
|
body: e.message,
|
|
695
723
|
headers: {
|
|
696
|
-
"x-api-key":
|
|
697
|
-
"X-Match-Urn":
|
|
724
|
+
"x-api-key": r.apiKey,
|
|
725
|
+
"X-Match-Urn": t.matchUrn,
|
|
698
726
|
"X-Device-Id": a,
|
|
699
727
|
...o ? { "X-User-Id": o } : {},
|
|
700
728
|
...this.fairplayKeyIV ? { "X-Key-Iv": this.fairplayKeyIV } : {}
|
|
701
729
|
}
|
|
702
730
|
});
|
|
703
|
-
if (!
|
|
704
|
-
l(`FairPlay license request failed: ${
|
|
731
|
+
if (!n.ok) {
|
|
732
|
+
l(`FairPlay license request failed: ${n.status}`, n.status, !0);
|
|
705
733
|
return;
|
|
706
734
|
}
|
|
707
|
-
await u.update(new Uint8Array(await
|
|
735
|
+
await u.update(new Uint8Array(await n.arrayBuffer()));
|
|
708
736
|
} catch (e) {
|
|
709
737
|
l(`FairPlay license request failed: ${String(e)}`, 0, !0);
|
|
710
738
|
}
|
|
711
739
|
})();
|
|
712
|
-
}), await u.generateRequest(
|
|
740
|
+
}), await u.generateRequest(i.initDataType, i.initData);
|
|
713
741
|
} catch (e) {
|
|
714
742
|
this.fairplayArmed = !1, l(`FairPlay key session failed: ${String(e)}`, 0, !0);
|
|
715
743
|
}
|
|
@@ -783,29 +811,29 @@ var z = class {
|
|
|
783
811
|
} catch {}
|
|
784
812
|
}
|
|
785
813
|
};
|
|
786
|
-
function
|
|
814
|
+
function Ee(e, t) {
|
|
787
815
|
return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
|
|
788
816
|
}
|
|
789
817
|
//#endregion
|
|
790
818
|
//#region src/core/engine/hls.ts
|
|
791
|
-
function
|
|
819
|
+
function De() {
|
|
792
820
|
return e.isSupported();
|
|
793
821
|
}
|
|
794
|
-
var
|
|
795
|
-
function
|
|
822
|
+
var Oe = 3, ke = 5, Ae = 3, je = 3e4, Me = 12e3, Ne = 3e3, B = 6e3, Pe = 4e3, Fe = 2, Ie = 5, Le = 2e3, Re = 3e4, ze = 2, Be = 9, V = .5;
|
|
823
|
+
function Ve(e) {
|
|
796
824
|
if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
|
|
797
825
|
delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
|
|
798
826
|
return;
|
|
799
827
|
}
|
|
800
|
-
e.liveSyncDuration ??=
|
|
801
|
-
let t = Math.max(12, e.liveSyncDuration +
|
|
802
|
-
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t),
|
|
828
|
+
e.liveSyncDuration ??= ze;
|
|
829
|
+
let t = Math.max(12, e.liveSyncDuration + Be);
|
|
830
|
+
(e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), He(e, e.liveSyncDuration);
|
|
803
831
|
}
|
|
804
|
-
function
|
|
832
|
+
function He(e, t) {
|
|
805
833
|
let n = (e, t, n) => Math.min(n, Math.max(t, e));
|
|
806
834
|
e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
|
|
807
835
|
}
|
|
808
|
-
var
|
|
836
|
+
var H = class {
|
|
809
837
|
name = "hls";
|
|
810
838
|
hls = null;
|
|
811
839
|
deps;
|
|
@@ -834,27 +862,47 @@ var V = class {
|
|
|
834
862
|
chaseSuspended = !1;
|
|
835
863
|
savedLiveMaxLatency;
|
|
836
864
|
savedMaxSyncRate;
|
|
865
|
+
capObserver = null;
|
|
866
|
+
capTimer = null;
|
|
867
|
+
sizeCapLevel = null;
|
|
868
|
+
bitrateCapLevel = -1;
|
|
869
|
+
sizeCapManaged = !0;
|
|
870
|
+
dprMedia = null;
|
|
871
|
+
onDprChange = null;
|
|
837
872
|
constructor(e) {
|
|
838
873
|
this.deps = e, this.licenseUrl = e.descriptor.drm?.widevine?.licenseUrl;
|
|
839
874
|
}
|
|
840
875
|
async load() {
|
|
841
|
-
let { descriptor: e, snapToLiveOnRefocus:
|
|
876
|
+
let { descriptor: e, snapToLiveOnRefocus: t, video: r, emit: i } = this.deps, a = L(r) && R(), o = !!e.drm?.widevine?.licenseUrl && !a;
|
|
842
877
|
if (e.drmEnabled && !o) {
|
|
843
878
|
i({
|
|
844
879
|
type: "error",
|
|
845
|
-
error: new
|
|
880
|
+
error: new n("DRM_CLIENT", 0, e.drm?.fairplay?.licenseUrl && a ? "FairPlay cannot be played on the hls.js engine (WebKit binds keys via the media sinf box); use engine \"auto\" or \"native\"" : "DRM is required but none of the stream’s key systems is usable on this platform (WebKit takes FairPlay only; other browsers take Widevine only)"),
|
|
846
881
|
fatal: !0
|
|
847
882
|
});
|
|
848
883
|
return;
|
|
849
884
|
}
|
|
850
|
-
this.startHls(),
|
|
885
|
+
this.startHls(), t !== !1 && typeof document < "u" && (this.onVisibility = () => {
|
|
851
886
|
let e = this.hls;
|
|
852
887
|
if (document.visibilityState !== "visible" || !e) return;
|
|
853
888
|
let t = e.liveSyncPosition;
|
|
854
889
|
if (typeof t != "number") return;
|
|
855
890
|
let n = typeof e.targetLatency == "number" && e.targetLatency > 0 ? e.targetLatency : 3;
|
|
856
891
|
t - r.currentTime > Math.max(n * 3, 8) && (r.currentTime = t);
|
|
857
|
-
}, document.addEventListener("visibilitychange", this.onVisibility)), this.onSeeking = () => this.clampOverSeek(), r.addEventListener("seeking", this.onSeeking);
|
|
892
|
+
}, document.addEventListener("visibilitychange", this.onVisibility)), this.onSeeking = () => this.clampOverSeek(), r.addEventListener("seeking", this.onSeeking), this.sizeCapManaged && typeof ResizeObserver < "u" && (this.capObserver = new ResizeObserver(() => this.onMediaResize()), this.capObserver.observe(r), this.watchDprChanges());
|
|
893
|
+
}
|
|
894
|
+
watchDprChanges() {
|
|
895
|
+
if (typeof matchMedia != "function") return;
|
|
896
|
+
this.unwatchDprChanges();
|
|
897
|
+
let e = typeof self < "u" && self.devicePixelRatio || 1, t = matchMedia(`(resolution: ${e}dppx)`);
|
|
898
|
+
if (typeof t.addEventListener != "function") return;
|
|
899
|
+
let n = () => {
|
|
900
|
+
this.onMediaResize(), this.watchDprChanges();
|
|
901
|
+
};
|
|
902
|
+
t.addEventListener("change", n), this.dprMedia = t, this.onDprChange = n;
|
|
903
|
+
}
|
|
904
|
+
unwatchDprChanges() {
|
|
905
|
+
this.dprMedia && this.onDprChange && this.dprMedia.removeEventListener("change", this.onDprChange), this.dprMedia = null, this.onDprChange = null;
|
|
858
906
|
}
|
|
859
907
|
clampOverSeek() {
|
|
860
908
|
let e = this.hls;
|
|
@@ -862,7 +910,7 @@ var V = class {
|
|
|
862
910
|
let t = e.liveSyncPosition;
|
|
863
911
|
if (typeof t != "number" || !Number.isFinite(t)) return;
|
|
864
912
|
let { video: n } = this.deps;
|
|
865
|
-
n.currentTime <= t +
|
|
913
|
+
n.currentTime <= t + V || (n.currentTime = t);
|
|
866
914
|
}
|
|
867
915
|
startHls() {
|
|
868
916
|
let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps, u = n.drmEnabled && !!(n.drm?.widevine?.licenseUrl || n.drm?.fairplay?.licenseUrl), d = {
|
|
@@ -873,7 +921,7 @@ var V = class {
|
|
|
873
921
|
maxBufferHole: .5,
|
|
874
922
|
maxLiveSyncPlaybackRate: 1.5,
|
|
875
923
|
abrEwmaDefaultEstimate: 1e6,
|
|
876
|
-
capLevelToPlayerSize: !
|
|
924
|
+
capLevelToPlayerSize: !1,
|
|
877
925
|
...u ? {
|
|
878
926
|
emeEnabled: !0,
|
|
879
927
|
drmSystems: { ...this.licenseUrl ? { "com.widevine.alpha": { licenseUrl: this.licenseUrl } } : {} },
|
|
@@ -898,14 +946,14 @@ var V = class {
|
|
|
898
946
|
} } : {},
|
|
899
947
|
...c
|
|
900
948
|
};
|
|
901
|
-
|
|
949
|
+
Ve(d), this.sizeCapManaged = d.capLevelToPlayerSize !== !0;
|
|
902
950
|
let f = new e(d);
|
|
903
951
|
this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
|
|
904
|
-
this.mediaRecoveries = 0, this.networkRecoveries = 0, l({ type: "ready" });
|
|
952
|
+
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.applySizeCap(), l({ type: "ready" });
|
|
905
953
|
}), f.on(e.Events.FRAG_BUFFERED, (e, t) => {
|
|
906
954
|
t?.frag?.type === "main" && (this.mediaRecoveries > 0 || this.networkRecoveries > 0 || this.licenseRecoveries > 0 || this.starvationKicks > 0) && !this.recoveryResetTimer && (this.recoveryResetTimer = setTimeout(() => {
|
|
907
955
|
this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.recoveryResetTimer = null;
|
|
908
|
-
},
|
|
956
|
+
}, je));
|
|
909
957
|
}), f.on(e.Events.FRAG_LOADING, (e, t) => {
|
|
910
958
|
t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
|
|
911
959
|
}), f.on(e.Events.FRAG_LOADED, (e, t) => {
|
|
@@ -921,7 +969,7 @@ var V = class {
|
|
|
921
969
|
}));
|
|
922
970
|
}), f.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.endWatchdog = setInterval(() => {
|
|
923
971
|
this.checkEndStale(), this.checkStarvation();
|
|
924
|
-
},
|
|
972
|
+
}, Ne), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
|
|
925
973
|
this.renditionSwitches += 1, l({
|
|
926
974
|
type: "qualitychange",
|
|
927
975
|
index: t.level
|
|
@@ -951,15 +999,54 @@ var V = class {
|
|
|
951
999
|
}
|
|
952
1000
|
setMaxBitrate(e) {
|
|
953
1001
|
let t = this.hls;
|
|
954
|
-
if (
|
|
955
|
-
|
|
956
|
-
|
|
1002
|
+
if (t) {
|
|
1003
|
+
if (e == null) this.bitrateCapLevel = -1;
|
|
1004
|
+
else {
|
|
1005
|
+
let n = -1;
|
|
1006
|
+
t.levels.forEach((t, r) => {
|
|
1007
|
+
t.bitrate <= e && (n = r);
|
|
1008
|
+
}), this.bitrateCapLevel = n;
|
|
1009
|
+
}
|
|
1010
|
+
this.pushCap();
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
computeSizeCapTarget() {
|
|
1014
|
+
let e = this.hls;
|
|
1015
|
+
if (!e || e.levels.length === 0) return null;
|
|
1016
|
+
let { video: n } = this.deps, r = n.getBoundingClientRect(), i = r.width, a = r.height;
|
|
1017
|
+
if (!i && !a && (i = n.width || 0, a = n.height || 0), !(i > 0) || !(a > 0)) return null;
|
|
1018
|
+
let o = e.config ?? {}, s = 1;
|
|
1019
|
+
return !o.ignoreDevicePixelRatio && typeof self < "u" && self.devicePixelRatio > 0 && (s = self.devicePixelRatio), s = Math.min(s, o.maxDevicePixelRatio ?? Infinity), t.getMaxLevelByMediaSize(e.levels, i * s, a * s);
|
|
1020
|
+
}
|
|
1021
|
+
onMediaResize() {
|
|
1022
|
+
if (!this.sizeCapManaged) return;
|
|
1023
|
+
let e = this.computeSizeCapTarget();
|
|
1024
|
+
if (e == null) return;
|
|
1025
|
+
if (this.sizeCapLevel == null) {
|
|
1026
|
+
this.applySizeCap();
|
|
1027
|
+
return;
|
|
1028
|
+
}
|
|
1029
|
+
if (e === this.sizeCapLevel) {
|
|
1030
|
+
this.capTimer &&= (clearTimeout(this.capTimer), null);
|
|
957
1031
|
return;
|
|
958
1032
|
}
|
|
959
|
-
|
|
960
|
-
t.
|
|
961
|
-
|
|
962
|
-
|
|
1033
|
+
this.capTimer && clearTimeout(this.capTimer);
|
|
1034
|
+
let t = e > this.sizeCapLevel ? Le : Re;
|
|
1035
|
+
this.capTimer = setTimeout(() => {
|
|
1036
|
+
this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
|
|
1037
|
+
}, t);
|
|
1038
|
+
}
|
|
1039
|
+
applySizeCap() {
|
|
1040
|
+
if (!this.sizeCapManaged) return;
|
|
1041
|
+
this.capTimer &&= (clearTimeout(this.capTimer), null);
|
|
1042
|
+
let e = this.computeSizeCapTarget();
|
|
1043
|
+
e != null && (this.sizeCapLevel = e, this.pushCap());
|
|
1044
|
+
}
|
|
1045
|
+
pushCap() {
|
|
1046
|
+
let e = this.hls;
|
|
1047
|
+
if (!e) return;
|
|
1048
|
+
let t = this.sizeCapLevel ?? -1, n = this.bitrateCapLevel;
|
|
1049
|
+
e.autoLevelCapping = t < 0 ? n : n < 0 ? t : Math.min(t, n);
|
|
963
1050
|
}
|
|
964
1051
|
getAudioTracks() {
|
|
965
1052
|
return this.hls ? this.hls.audioTracks.map((e) => ({
|
|
@@ -1025,7 +1112,7 @@ var V = class {
|
|
|
1025
1112
|
return;
|
|
1026
1113
|
}
|
|
1027
1114
|
let e = Date.now() - this.lastAdvanceMs;
|
|
1028
|
-
!this.chaseSuspended && e > B && this.suspendChasing(), e >
|
|
1115
|
+
!this.chaseSuspended && e > B && this.suspendChasing(), e > Me && this.emitEnded("stalled");
|
|
1029
1116
|
}
|
|
1030
1117
|
checkStarvation() {
|
|
1031
1118
|
let e = this.hls, { video: t } = this.deps;
|
|
@@ -1034,12 +1121,12 @@ var V = class {
|
|
|
1034
1121
|
this.starvedTicks = 0;
|
|
1035
1122
|
return;
|
|
1036
1123
|
}
|
|
1037
|
-
let n = this.lastAdvanceMs !== 0 && Date.now() - this.lastAdvanceMs < B, r = this.lastFragLoadingMs !== 0 && Date.now() - this.lastFragLoadingMs >
|
|
1124
|
+
let n = this.lastAdvanceMs !== 0 && Date.now() - this.lastAdvanceMs < B, r = this.lastFragLoadingMs !== 0 && Date.now() - this.lastFragLoadingMs > Pe;
|
|
1038
1125
|
if (!(t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused && n && r)) {
|
|
1039
1126
|
this.starvedTicks = 0;
|
|
1040
1127
|
return;
|
|
1041
1128
|
}
|
|
1042
|
-
if (!(++this.starvedTicks <
|
|
1129
|
+
if (!(++this.starvedTicks < Fe) && (this.starvedTicks = 0, !(this.starvationKicks >= Ie))) {
|
|
1043
1130
|
this.starvationKicks += 1, console.warn("havik-player: video starved while the live playlist advances (wedged hls.js fragment pipeline) — restarting load at the live edge");
|
|
1044
1131
|
try {
|
|
1045
1132
|
e.stopLoad(), e.startLoad(-1);
|
|
@@ -1073,7 +1160,7 @@ var V = class {
|
|
|
1073
1160
|
} catch {}
|
|
1074
1161
|
}
|
|
1075
1162
|
destroy() {
|
|
1076
|
-
if (this.clearRecoveryReset(), this.endWatchdog &&= (clearInterval(this.endWatchdog), null), this.onVisibility && typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), this.onVisibility = null), this.onSeeking &&= (this.deps.video.removeEventListener("seeking", this.onSeeking), null), this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null), this.licenseRetryTimer &&= (clearTimeout(this.licenseRetryTimer), null), this.hls) {
|
|
1163
|
+
if (this.clearRecoveryReset(), this.capTimer &&= (clearTimeout(this.capTimer), null), this.capObserver &&= (this.capObserver.disconnect(), null), this.unwatchDprChanges(), this.endWatchdog &&= (clearInterval(this.endWatchdog), null), this.onVisibility && typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), this.onVisibility = null), this.onSeeking &&= (this.deps.video.removeEventListener("seeking", this.onSeeking), null), this.networkRetryTimer &&= (clearTimeout(this.networkRetryTimer), null), this.licenseRetryTimer &&= (clearTimeout(this.licenseRetryTimer), null), this.hls) {
|
|
1077
1164
|
try {
|
|
1078
1165
|
this.hls.destroy();
|
|
1079
1166
|
} catch (e) {
|
|
@@ -1086,9 +1173,9 @@ var V = class {
|
|
|
1086
1173
|
this.recoveryResetTimer &&= (clearTimeout(this.recoveryResetTimer), null);
|
|
1087
1174
|
}
|
|
1088
1175
|
scheduleLicenseRetry(t) {
|
|
1089
|
-
if (
|
|
1176
|
+
if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
|
|
1090
1177
|
let n = t.response?.code ?? 0;
|
|
1091
|
-
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >=
|
|
1178
|
+
if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= Ae) return !1;
|
|
1092
1179
|
this.licenseRecoveries += 1;
|
|
1093
1180
|
let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
|
|
1094
1181
|
return this.licenseRetryTimer = setTimeout(() => {
|
|
@@ -1116,7 +1203,7 @@ var V = class {
|
|
|
1116
1203
|
return;
|
|
1117
1204
|
}
|
|
1118
1205
|
if (t.type === e.ErrorTypes.NETWORK_ERROR) {
|
|
1119
|
-
if (this.networkRecoveries <
|
|
1206
|
+
if (this.networkRecoveries < ke) {
|
|
1120
1207
|
this.networkRecoveries += 1;
|
|
1121
1208
|
let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
|
|
1122
1209
|
this.networkRetryTimer = setTimeout(() => {
|
|
@@ -1132,7 +1219,7 @@ var V = class {
|
|
|
1132
1219
|
return;
|
|
1133
1220
|
}
|
|
1134
1221
|
if (t.type === e.ErrorTypes.MEDIA_ERROR) {
|
|
1135
|
-
if (this.mediaRecoveries <
|
|
1222
|
+
if (this.mediaRecoveries < Oe) {
|
|
1136
1223
|
this.mediaRecoveries += 1, n.recoverMediaError();
|
|
1137
1224
|
return;
|
|
1138
1225
|
}
|
|
@@ -1150,11 +1237,11 @@ var V = class {
|
|
|
1150
1237
|
});
|
|
1151
1238
|
}
|
|
1152
1239
|
}
|
|
1153
|
-
toError(e,
|
|
1154
|
-
let
|
|
1155
|
-
return new t
|
|
1240
|
+
toError(e, t = "PLAYBACK") {
|
|
1241
|
+
let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
|
|
1242
|
+
return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
|
|
1156
1243
|
}
|
|
1157
|
-
},
|
|
1244
|
+
}, Ue = 15e3, We = 100, U = 1, W = {
|
|
1158
1245
|
idle: "PLAYER_STATE_IDLE",
|
|
1159
1246
|
waiting: "PLAYER_STATE_WAITING",
|
|
1160
1247
|
loading: "PLAYER_STATE_LOADING",
|
|
@@ -1164,7 +1251,7 @@ var V = class {
|
|
|
1164
1251
|
ended: "PLAYER_STATE_ENDED",
|
|
1165
1252
|
error: "PLAYER_STATE_ERROR"
|
|
1166
1253
|
};
|
|
1167
|
-
function
|
|
1254
|
+
function Ge(e) {
|
|
1168
1255
|
try {
|
|
1169
1256
|
let t = new URL(e), [n, ...r] = t.hostname.split(".");
|
|
1170
1257
|
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);
|
|
@@ -1172,7 +1259,7 @@ function Re(e) {
|
|
|
1172
1259
|
return;
|
|
1173
1260
|
}
|
|
1174
1261
|
}
|
|
1175
|
-
var
|
|
1262
|
+
var Ke = class {
|
|
1176
1263
|
opts;
|
|
1177
1264
|
url;
|
|
1178
1265
|
now;
|
|
@@ -1207,7 +1294,7 @@ var ze = class {
|
|
|
1207
1294
|
constructor(e) {
|
|
1208
1295
|
this.opts = {
|
|
1209
1296
|
...e,
|
|
1210
|
-
heartbeatMs: e.heartbeatMs ??
|
|
1297
|
+
heartbeatMs: e.heartbeatMs ?? Ue
|
|
1211
1298
|
}, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`, this.now = e.now ?? (() => Date.now()), this.bornMs = this.now();
|
|
1212
1299
|
}
|
|
1213
1300
|
start() {
|
|
@@ -1219,18 +1306,18 @@ var ze = class {
|
|
|
1219
1306
|
noteStateChange(e, t, n, r) {
|
|
1220
1307
|
if (this.endedFlag || e === t) return;
|
|
1221
1308
|
let i = this.now();
|
|
1222
|
-
t === "playing" ? (this.playingSinceMs === null && (this.playingSinceMs = i), this.startupTimeMs === 0 && (this.startupTimeMs = Math.max(
|
|
1309
|
+
t === "playing" ? (this.playingSinceMs === null && (this.playingSinceMs = i), this.startupTimeMs === 0 && (this.startupTimeMs = Math.max(U, i - this.bornMs))) : this.playingSinceMs !== null && (this.playingTotalMs += i - this.playingSinceMs, this.playingSinceMs = null), t === "buffering" && e === "playing" ? (this.rebufferCount += 1, this.bufferingSinceMs = i) : e === "buffering" && this.bufferingSinceMs !== null && (this.rebufferTotalMs += i - this.bufferingSinceMs, this.bufferingSinceMs = null), t === "paused" && (this.pauseCount += 1);
|
|
1223
1310
|
let a = {
|
|
1224
|
-
fromState:
|
|
1225
|
-
toState:
|
|
1311
|
+
fromState: W[e] ?? "PLAYER_STATE_UNSPECIFIED",
|
|
1312
|
+
toState: W[t] ?? "PLAYER_STATE_UNSPECIFIED"
|
|
1226
1313
|
};
|
|
1227
1314
|
n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
|
|
1228
1315
|
}
|
|
1229
1316
|
noteReady() {
|
|
1230
|
-
this.manifestLoadMs === 0 && (this.manifestLoadMs = Math.max(
|
|
1317
|
+
this.manifestLoadMs === 0 && (this.manifestLoadMs = Math.max(U, this.now() - this.bornMs));
|
|
1231
1318
|
}
|
|
1232
1319
|
noteFirstBytes() {
|
|
1233
|
-
this.firstFragLoadMs === 0 && (this.firstFragLoadMs = Math.max(
|
|
1320
|
+
this.firstFragLoadMs === 0 && (this.firstFragLoadMs = Math.max(U, this.now() - this.bornMs));
|
|
1234
1321
|
}
|
|
1235
1322
|
noteSeek() {
|
|
1236
1323
|
this.endedFlag || (this.seekCount += 1);
|
|
@@ -1265,7 +1352,7 @@ var ze = class {
|
|
|
1265
1352
|
let c = e.renditionSwitches ?? 0;
|
|
1266
1353
|
c > this.lastSwitches && (i.renditionSwitchesDelta = c - this.lastSwitches), this.lastSwitches = c, n > this.lastHbPlayingMs && (i.playingMsDelta = Math.round(n - this.lastHbPlayingMs)), this.lastHbPlayingMs = n, r > this.lastHbHiddenMs && (i.hiddenMsDelta = Math.round(r - this.lastHbHiddenMs)), this.lastHbHiddenMs = r, typeof e.latencySeconds == "number" && (i.latencyMs = Math.round(e.latencySeconds * 1e3)), typeof e.targetLatencySeconds == "number" && (i.targetLatencyMs = Math.round(e.targetLatencySeconds * 1e3)), typeof e.bandwidthKbps == "number" && (i.bandwidthEstKbps = e.bandwidthKbps), typeof e.levelHeight == "number" && (i.renditionHeight = e.levelHeight), typeof e.renditionBitrateKbps == "number" && (i.renditionBitrateKbps = e.renditionBitrateKbps), e.atLiveEdge === !0 && (i.atLiveEdge = !0);
|
|
1267
1354
|
let l = this.bufferedMsFrom(e);
|
|
1268
|
-
l > 0 && (i.bufferedMs = l), i.playerState =
|
|
1355
|
+
l > 0 && (i.bufferedMs = l), i.playerState = W[e.state] ?? "PLAYER_STATE_UNSPECIFIED", this.enqueue({ heartbeat: i }), this.flush(), a > 0 && this.noteFirstBytes();
|
|
1269
1356
|
}
|
|
1270
1357
|
bufferedMsFrom(e) {
|
|
1271
1358
|
let t = e;
|
|
@@ -1299,7 +1386,7 @@ var ze = class {
|
|
|
1299
1386
|
};
|
|
1300
1387
|
}
|
|
1301
1388
|
enqueue(e) {
|
|
1302
|
-
for (this.pending.push(this.wrap(e)); this.pending.length >
|
|
1389
|
+
for (this.pending.push(this.wrap(e)); this.pending.length > We;) {
|
|
1303
1390
|
let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
|
|
1304
1391
|
this.pending.splice(e >= 0 ? e : 0, 1);
|
|
1305
1392
|
}
|
|
@@ -1321,7 +1408,7 @@ var ze = class {
|
|
|
1321
1408
|
keepalive: !0
|
|
1322
1409
|
}).catch(() => {});
|
|
1323
1410
|
}
|
|
1324
|
-
},
|
|
1411
|
+
}, qe = "1.16.0", G = {
|
|
1325
1412
|
accent: "#E1B600",
|
|
1326
1413
|
accentText: "#1B1C23",
|
|
1327
1414
|
background: "#0e0f13",
|
|
@@ -1332,7 +1419,7 @@ var ze = class {
|
|
|
1332
1419
|
border: "rgba(255, 255, 255, 0.1)",
|
|
1333
1420
|
radius: "8px",
|
|
1334
1421
|
fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
|
|
1335
|
-
},
|
|
1422
|
+
}, K = {
|
|
1336
1423
|
accent: "--havik-accent",
|
|
1337
1424
|
accentText: "--havik-accent-text",
|
|
1338
1425
|
background: "--havik-bg",
|
|
@@ -1344,25 +1431,25 @@ var ze = class {
|
|
|
1344
1431
|
radius: "--havik-radius",
|
|
1345
1432
|
fontFamily: "--havik-font"
|
|
1346
1433
|
};
|
|
1347
|
-
function
|
|
1434
|
+
function q(e, t) {
|
|
1348
1435
|
let n = {
|
|
1349
|
-
...
|
|
1436
|
+
...G,
|
|
1350
1437
|
...t
|
|
1351
1438
|
};
|
|
1352
|
-
for (let t of Object.keys(
|
|
1439
|
+
for (let t of Object.keys(K)) e.style.setProperty(K[t], n[t]);
|
|
1353
1440
|
n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
|
|
1354
1441
|
}
|
|
1355
1442
|
//#endregion
|
|
1356
1443
|
//#region src/ui/styles.ts
|
|
1357
|
-
var
|
|
1358
|
-
function
|
|
1359
|
-
if (e.getElementById(
|
|
1444
|
+
var J = "havik-player-styles", Je = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n.havik-spinner{width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n/* A status card carries its own logo — the corner watermark would duplicate it. */\n.havik-player.havik-has-status .havik-watermark{display:none}\n\n.havik-bar{position:absolute;left:0;right:0;bottom:0;padding:0 12px 8px;\n opacity:1;transition:opacity .25s;z-index:2}\n.havik-seek{position:relative;height:16px;display:flex;align-items:center;cursor:pointer;margin-bottom:2px}\n.havik-seek__track{position:relative;width:100%;height:4px;border-radius:3px;background:rgba(255,255,255,.25)}\n.havik-seek__buffered{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:rgba(255,255,255,.4)}\n.havik-seek__played{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-seek__thumb{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;\n background:var(--havik-accent,#E1B600);transform:translate(-50%,-50%) scale(0);transition:transform .1s}\n.havik-seek:hover .havik-seek__thumb{transform:translate(-50%,-50%) scale(1)}\n\n.havik-controls{display:flex;align-items:center;gap:6px;height:40px}\n.havik-spacer{flex:1}\n.havik-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;border-radius:var(--havik-radius,8px);\n padding:0;transition:background .12s,color .12s}\n.havik-btn:hover{background:rgba(255,255,255,.12)}\n.havik-btn:focus-visible{outline:2px solid var(--havik-accent,#E1B600);outline-offset:1px}\n.havik-btn svg{width:22px;height:22px}\n\n/* The volume level is filled in accent up to the thumb, like the seek bar's\n played span — a native range input paints no \"elapsed\" side, which left the\n level readable only from the dot's position. --havik-vol (0..1) is set by\n syncVolume(); the track width and thumb size live here as variables because\n the WebKit fill has to compute the thumb centre from both. */\n.havik-vol{display:flex;align-items:center}\n.havik-vol__slider{--havik-vol-w:70px;--havik-vol-thumb:12px;--havik-vol:1;\n --havik-vol-pos:calc(var(--havik-vol-thumb) / 2 + var(--havik-vol) * (var(--havik-vol-w) - var(--havik-vol-thumb)));\n width:0;opacity:0;transition:width .18s,opacity .18s;height:4px;cursor:pointer;\n appearance:none;-webkit-appearance:none;background:transparent;border-radius:3px;margin:0 4px}\n.havik-vol:hover .havik-vol__slider,.havik-vol:focus-within .havik-vol__slider{width:var(--havik-vol-w);opacity:1}\n/* WebKit/Blink have no progress pseudo-element: paint the fill as a hard-stop\n gradient that ends at the thumb centre. */\n.havik-vol__slider::-webkit-slider-runnable-track{height:4px;border-radius:3px;\n background:linear-gradient(to right,var(--havik-accent,#E1B600) var(--havik-vol-pos),\n rgba(255,255,255,.3) var(--havik-vol-pos))}\n/* Firefox fills natively, and tracks the thumb exactly. */\n.havik-vol__slider::-moz-range-track{height:4px;border-radius:3px;background:rgba(255,255,255,.3)}\n.havik-vol__slider::-moz-range-progress{height:4px;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-vol__slider::-webkit-slider-thumb{-webkit-appearance:none;width:var(--havik-vol-thumb);\n height:var(--havik-vol-thumb);border-radius:50%;background:var(--havik-accent,#E1B600);\n margin-top:calc((4px - var(--havik-vol-thumb)) / 2)}\n.havik-vol__slider::-moz-range-thumb{width:var(--havik-vol-thumb);height:var(--havik-vol-thumb);\n border:0;border-radius:50%;background:var(--havik-accent,#E1B600)}\n\n.havik-time{font-size:12px;color:var(--havik-text-muted,#9aa0ad);\n font-variant-numeric:tabular-nums;padding:0 6px;white-space:nowrap}\n.havik-live{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;\n letter-spacing:.4px;padding:0 8px;color:var(--havik-text,#fff)}\n.havik-live svg{width:9px;height:9px;color:var(--havik-text-muted,#9aa0ad)}\n.havik-live.is-live svg{color:var(--havik-accent,#E1B600)}\n.havik-live__go{margin-left:2px;border:0;cursor:pointer;background:transparent;color:var(--havik-text-muted,#9aa0ad);\n font:inherit;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:6px}\n.havik-live.is-live .havik-live__go{display:none}\n.havik-live__go:hover{color:var(--havik-accent,#E1B600)}\n\n.havik-menu{position:absolute;bottom:54px;right:12px;min-width:170px;max-height:230px;overflow:auto;\n background:var(--havik-surface,#1B1C23);border:1px solid var(--havik-border,rgba(255,255,255,.1));\n border-radius:var(--havik-radius,8px);box-shadow:0 10px 30px rgba(0,0,0,.5);padding:6px;z-index:3}\n.havik-menu[hidden]{display:none}\n.havik-menu__title{font-size:11px;text-transform:uppercase;letter-spacing:.6px;\n color:var(--havik-text-muted,#9aa0ad);padding:6px 8px 4px}\n.havik-menu__item{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;font:inherit;font-size:13px;\n text-align:left;padding:7px 8px;border-radius:6px}\n.havik-menu__item:hover{background:var(--havik-surface-muted,#2a2c36)}\n.havik-menu__item[aria-checked=\"true\"]{color:var(--havik-accent,#E1B600);font-weight:600}\n.havik-menu__item[aria-checked=\"true\"]::after{content:'✓'}\n";
|
|
1445
|
+
function Ye(e = document) {
|
|
1446
|
+
if (e.getElementById(J)) return;
|
|
1360
1447
|
let t = e.createElement("style");
|
|
1361
|
-
t.id =
|
|
1448
|
+
t.id = J, t.textContent = Je, e.head.appendChild(t);
|
|
1362
1449
|
}
|
|
1363
1450
|
//#endregion
|
|
1364
1451
|
//#region src/ui/icons.ts
|
|
1365
|
-
var
|
|
1452
|
+
var Xe = {
|
|
1366
1453
|
play: "<path d=\"M8 5v14l11-7z\"/>",
|
|
1367
1454
|
pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
|
|
1368
1455
|
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\"/>",
|
|
@@ -1375,21 +1462,21 @@ var Ue = {
|
|
|
1375
1462
|
liveDot: "<circle cx=\"12\" cy=\"12\" r=\"6\"/>",
|
|
1376
1463
|
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\"/>"
|
|
1377
1464
|
};
|
|
1378
|
-
function
|
|
1379
|
-
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${
|
|
1465
|
+
function Y(e) {
|
|
1466
|
+
return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${Xe[e]}</svg>`;
|
|
1380
1467
|
}
|
|
1381
1468
|
//#endregion
|
|
1382
1469
|
//#region src/ui/controls.ts
|
|
1383
|
-
var
|
|
1470
|
+
var Ze = 3e3, Qe = /* @__PURE__ */ new Set([
|
|
1384
1471
|
"GONE",
|
|
1385
1472
|
"NOT_FOUND",
|
|
1386
1473
|
"INVALID_URN",
|
|
1387
1474
|
"UNAUTHORIZED"
|
|
1388
1475
|
]);
|
|
1389
|
-
function
|
|
1390
|
-
return new
|
|
1476
|
+
function $e(e) {
|
|
1477
|
+
return new et(e);
|
|
1391
1478
|
}
|
|
1392
|
-
var
|
|
1479
|
+
var et = class {
|
|
1393
1480
|
root;
|
|
1394
1481
|
video;
|
|
1395
1482
|
player;
|
|
@@ -1429,7 +1516,7 @@ var qe = class {
|
|
|
1429
1516
|
scrubbing = !1;
|
|
1430
1517
|
offFns = [];
|
|
1431
1518
|
constructor(e) {
|
|
1432
|
-
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ??
|
|
1519
|
+
this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? Ze, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.errorMessage = e.errorMessage, Ye(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");
|
|
1433
1520
|
let t = (e, t, n) => {
|
|
1434
1521
|
let r = this.doc.createElement(e);
|
|
1435
1522
|
if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
|
|
@@ -1440,12 +1527,12 @@ var qe = class {
|
|
|
1440
1527
|
"aria-label": r,
|
|
1441
1528
|
title: r
|
|
1442
1529
|
});
|
|
1443
|
-
return i.innerHTML =
|
|
1530
|
+
return i.innerHTML = Y(n), i;
|
|
1444
1531
|
};
|
|
1445
1532
|
this.overlay = t("div", "havik-overlay"), this.center = t("button", "havik-center", {
|
|
1446
1533
|
type: "button",
|
|
1447
1534
|
"aria-label": "Play"
|
|
1448
|
-
}), this.center.innerHTML =
|
|
1535
|
+
}), this.center.innerHTML = Y("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", {
|
|
1449
1536
|
role: "slider",
|
|
1450
1537
|
"aria-label": "Seek",
|
|
1451
1538
|
"aria-valuemin": "0",
|
|
@@ -1463,7 +1550,7 @@ var qe = class {
|
|
|
1463
1550
|
"aria-label": "Volume"
|
|
1464
1551
|
});
|
|
1465
1552
|
let a = t("div", "havik-vol");
|
|
1466
|
-
a.append(this.muteBtn, this.volSlider), this.live = t("div", "havik-live"), this.live.innerHTML =
|
|
1553
|
+
a.append(this.muteBtn, this.volSlider), this.live = t("div", "havik-live"), this.live.innerHTML = Y("liveDot");
|
|
1467
1554
|
let o = this.doc.createElement("span");
|
|
1468
1555
|
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";
|
|
1469
1556
|
let s = t("div", "havik-spacer");
|
|
@@ -1485,7 +1572,7 @@ var qe = class {
|
|
|
1485
1572
|
this.setVolumeFill(t), this.player.setVolume(t), t > 0 && e.muted && this.player.setMuted(!1);
|
|
1486
1573
|
}), this.on(this.liveGo, "click", () => this.player.seekToLive()), this.on(this.pipBtn, "click", () => void this.togglePip()), this.on(this.fsBtn, "click", () => void this.toggleFullscreen()), this.on(this.ccBtn, "click", () => this.toggleMenu("cc")), this.on(this.audioBtn, "click", () => this.toggleMenu("audio")), this.on(this.qualityBtn, "click", () => this.toggleMenu("quality")), this.on(this.seek, "pointerdown", (e) => this.onSeekDown(e)), this.on(this.seek, "keydown", (e) => this.onSeekKey(e)), this.on(e, "play", () => this.syncPlayPause()), this.on(e, "pause", () => this.syncPlayPause()), this.on(e, "volumechange", () => this.syncVolume()), this.on(e, "timeupdate", () => this.syncProgress()), this.on(e, "progress", () => this.syncProgress()), this.on(e, "durationchange", () => this.syncProgress()), this.offFns.push(this.player.on("statechange", () => this.syncState())), this.offFns.push(this.player.on("ready", () => this.refreshTracks())), this.offFns.push(this.player.on("qualitychange", () => this.onTracksChanged())), this.offFns.push(this.player.on("audiotrackchange", () => this.onTracksChanged())), this.offFns.push(this.player.on("texttrackchange", () => this.onTracksChanged())), this.offFns.push(this.player.on("pipchange", (e) => this.syncPip(e))), this.offFns.push(this.player.on("stats", () => this.syncLive())), this.offFns.push(this.player.on("error", (e) => {
|
|
1487
1574
|
this.lastError = e, this.statusKind = null, this.syncState();
|
|
1488
|
-
})), this.on(this.root, "pointermove", () => this.poke()), this.on(this.root, "pointerleave", () => this.scheduleHide(0)), this.on(this.root, "focusin", () => this.poke()), this.on(this.root, "keydown", (e) => this.onKey(e)), this.on(this.doc, "pointerdown", (e) => this.onDocPointer(e), { capture: !0 }), this.on(this.doc, "fullscreenchange", () => this.syncFullscreen()), this.syncState();
|
|
1575
|
+
})), this.on(this.root, "pointermove", () => this.poke()), this.on(this.root, "pointerleave", () => this.scheduleHide(0)), this.on(this.root, "focusin", () => this.poke()), this.on(this.root, "keydown", (e) => this.onKey(e)), this.on(this.doc, "pointerdown", (e) => this.onDocPointer(e), { capture: !0 }), this.on(this.doc, "fullscreenchange", () => this.syncFullscreen()), this.on(this.doc, "webkitfullscreenchange", () => this.syncFullscreen()), this.on(e, "webkitbeginfullscreen", () => this.syncFullscreen()), this.on(e, "webkitendfullscreen", () => this.syncFullscreen()), this.syncState();
|
|
1489
1576
|
}
|
|
1490
1577
|
togglePlay() {
|
|
1491
1578
|
this.video.paused || this.video.ended ? this.player.play() : this.player.pause();
|
|
@@ -1513,12 +1600,12 @@ var qe = class {
|
|
|
1513
1600
|
}
|
|
1514
1601
|
if (e === "preplay") {
|
|
1515
1602
|
let e = this.doc.createElement("button");
|
|
1516
|
-
e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML =
|
|
1603
|
+
e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML = Y("play"), e.addEventListener("click", () => void this.player.play()), t.append(e);
|
|
1517
1604
|
} else {
|
|
1518
1605
|
let n = this.doc.createElement("div");
|
|
1519
|
-
if (n.className = "havik-status__msg", n.textContent = e === "ended" ? this.endedMessage : e === "waiting" ? "Starting soon…" : this.errorMessage ?? this.lastError?.message ?? "Playback unavailable", t.append(n), e === "error" && this.lastError && !
|
|
1606
|
+
if (n.className = "havik-status__msg", n.textContent = e === "ended" ? this.endedMessage : e === "waiting" ? "Starting soon…" : this.errorMessage ?? this.lastError?.message ?? "Playback unavailable", t.append(n), e === "error" && this.lastError && !Qe.has(this.lastError.code)) {
|
|
1520
1607
|
let e = this.doc.createElement("button");
|
|
1521
|
-
e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${
|
|
1608
|
+
e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${Y("retry")}<span>Retry</span>`, e.addEventListener("click", () => void this.player.retry()), t.append(e);
|
|
1522
1609
|
}
|
|
1523
1610
|
}
|
|
1524
1611
|
this.root.append(t), this.statusBox = t, this.show();
|
|
@@ -1557,7 +1644,7 @@ var qe = class {
|
|
|
1557
1644
|
let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
|
|
1558
1645
|
this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
|
|
1559
1646
|
}
|
|
1560
|
-
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${
|
|
1647
|
+
!this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${X(this.video.currentTime)} / ${X(this.video.duration)}`);
|
|
1561
1648
|
}
|
|
1562
1649
|
syncLive() {
|
|
1563
1650
|
let e = this.player.getStats(), t = e.isLive !== !1;
|
|
@@ -1607,17 +1694,17 @@ var qe = class {
|
|
|
1607
1694
|
renderQualityMenu() {
|
|
1608
1695
|
let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
|
|
1609
1696
|
n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
|
|
1610
|
-
for (let n of e) this.menu.append(this.menuItem(
|
|
1697
|
+
for (let n of e) this.menu.append(this.menuItem(tt(n), t === n.index, () => this.player.setQuality(n.index)));
|
|
1611
1698
|
}
|
|
1612
1699
|
renderAudioMenu() {
|
|
1613
1700
|
let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
|
|
1614
1701
|
t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
|
|
1615
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
1702
|
+
for (let t of e) this.menu.append(this.menuItem(nt(t), t.default, () => this.player.setAudioTrack(t.id)));
|
|
1616
1703
|
}
|
|
1617
1704
|
renderCcMenu() {
|
|
1618
1705
|
let e = this.player.getTextTracks(), t = this.doc.createElement("div");
|
|
1619
1706
|
t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
|
|
1620
|
-
for (let t of e) this.menu.append(this.menuItem(
|
|
1707
|
+
for (let t of e) this.menu.append(this.menuItem(rt(t), !1, () => this.player.setTextTrack(t.id)));
|
|
1621
1708
|
}
|
|
1622
1709
|
onTracksChanged() {
|
|
1623
1710
|
this.openMenu && this.renderMenu(this.openMenu);
|
|
@@ -1636,13 +1723,12 @@ var qe = class {
|
|
|
1636
1723
|
this.pipBtn.setAttribute("aria-pressed", e ? "true" : "false");
|
|
1637
1724
|
}
|
|
1638
1725
|
async toggleFullscreen() {
|
|
1639
|
-
let e = this.root, t = this.doc;
|
|
1640
1726
|
try {
|
|
1641
|
-
|
|
1727
|
+
C(this.video, this.root) ? await T(this.video, this.root) : await w(this.video, this.root);
|
|
1642
1728
|
} catch {}
|
|
1643
1729
|
}
|
|
1644
1730
|
syncFullscreen() {
|
|
1645
|
-
let e = this.
|
|
1731
|
+
let e = C(this.video, this.root);
|
|
1646
1732
|
this.setIcon(this.fsBtn, e ? "fullscreenExit" : "fullscreen"), this.fsBtn.setAttribute("aria-label", e ? "Exit fullscreen" : "Fullscreen");
|
|
1647
1733
|
}
|
|
1648
1734
|
poke() {
|
|
@@ -1701,7 +1787,7 @@ var qe = class {
|
|
|
1701
1787
|
}
|
|
1702
1788
|
}
|
|
1703
1789
|
setIcon(e, t) {
|
|
1704
|
-
e.innerHTML =
|
|
1790
|
+
e.innerHTML = Y(t);
|
|
1705
1791
|
}
|
|
1706
1792
|
destroy() {
|
|
1707
1793
|
this.hideTimer && clearTimeout(this.hideTimer);
|
|
@@ -1718,32 +1804,32 @@ var qe = class {
|
|
|
1718
1804
|
this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
|
|
1719
1805
|
}
|
|
1720
1806
|
};
|
|
1721
|
-
function
|
|
1807
|
+
function X(e) {
|
|
1722
1808
|
(!Number.isFinite(e) || e < 0) && (e = 0);
|
|
1723
1809
|
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");
|
|
1724
1810
|
return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
|
|
1725
1811
|
}
|
|
1726
|
-
function
|
|
1812
|
+
function tt(e) {
|
|
1727
1813
|
return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
|
|
1728
1814
|
}
|
|
1729
|
-
function
|
|
1815
|
+
function nt(e) {
|
|
1730
1816
|
return e.name || e.lang || `Track ${e.id}`;
|
|
1731
1817
|
}
|
|
1732
|
-
function
|
|
1818
|
+
function rt(e) {
|
|
1733
1819
|
return e.name || e.lang || `Track ${e.id}`;
|
|
1734
1820
|
}
|
|
1735
1821
|
//#endregion
|
|
1736
1822
|
//#region src/managed/index.ts
|
|
1737
|
-
var
|
|
1823
|
+
var it = 6e3, Z = 45e3, at = 2e3, ot = 3, st = 2e3, ct = 48e4;
|
|
1738
1824
|
async function Q(e) {
|
|
1739
|
-
if (!e.video || typeof e.video.play != "function") throw new
|
|
1740
|
-
if (!e.baseUrl) throw new
|
|
1741
|
-
if (!e.matchUrn) throw new
|
|
1742
|
-
if (!e.credential) throw new
|
|
1743
|
-
let
|
|
1744
|
-
return await
|
|
1745
|
-
}
|
|
1746
|
-
var
|
|
1825
|
+
if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
|
|
1826
|
+
if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: baseUrl is required");
|
|
1827
|
+
if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
|
|
1828
|
+
if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
|
|
1829
|
+
let t = new lt(e);
|
|
1830
|
+
return await t.start(), t;
|
|
1831
|
+
}
|
|
1832
|
+
var lt = class {
|
|
1747
1833
|
opts;
|
|
1748
1834
|
abort = new AbortController();
|
|
1749
1835
|
listeners = {};
|
|
@@ -1777,19 +1863,19 @@ var tt = class {
|
|
|
1777
1863
|
}
|
|
1778
1864
|
async start() {
|
|
1779
1865
|
this.opts.muted && (this.opts.video.muted = !0), this.opts.poster && (this.opts.video.poster = this.opts.poster), this.mountControls(), this.attachPipListeners(), this.setState("loading");
|
|
1780
|
-
let e = ++this.loadGen,
|
|
1866
|
+
let e = ++this.loadGen, t = this.resolveOptions();
|
|
1781
1867
|
try {
|
|
1782
|
-
let
|
|
1783
|
-
if (await this.onResolved(
|
|
1868
|
+
let n = await v(t);
|
|
1869
|
+
if (await this.onResolved(n, e), e === this.loadGen && this._state === "error" && this._lastError) {
|
|
1784
1870
|
let e = this._lastError;
|
|
1785
1871
|
throw this.destroy(), e;
|
|
1786
1872
|
}
|
|
1787
|
-
} catch (
|
|
1788
|
-
if (this.opts.waitForLive &&
|
|
1789
|
-
this.setState("waiting"), this.beginArming(e,
|
|
1873
|
+
} catch (t) {
|
|
1874
|
+
if (this.opts.waitForLive && t instanceof n && o(t.code)) {
|
|
1875
|
+
this.setState("waiting"), this.beginArming(e, t.liveStartsAtMs);
|
|
1790
1876
|
return;
|
|
1791
1877
|
}
|
|
1792
|
-
throw
|
|
1878
|
+
throw t;
|
|
1793
1879
|
}
|
|
1794
1880
|
}
|
|
1795
1881
|
resolveOptions() {
|
|
@@ -1802,67 +1888,67 @@ var tt = class {
|
|
|
1802
1888
|
};
|
|
1803
1889
|
}
|
|
1804
1890
|
beginArming(e, t) {
|
|
1805
|
-
let n = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ??
|
|
1891
|
+
let n = this.opts.liveStateEvents === !1 ? void 0 : this.opts.eventsBaseUrl ?? D(this.opts.baseUrl);
|
|
1806
1892
|
n ? this.armWithSse(e, n, t) : this.beginArmingByPolling(e);
|
|
1807
1893
|
}
|
|
1808
1894
|
beginArmingByPolling(e) {
|
|
1809
|
-
|
|
1895
|
+
y({
|
|
1810
1896
|
...this.resolveOptions(),
|
|
1811
1897
|
signal: this.abort.signal,
|
|
1812
1898
|
waitForLive: this.buildWaitConfig(e)
|
|
1813
1899
|
}).then((t) => {
|
|
1814
1900
|
if (!(this.destroyed || this.abort.signal.aborted || e !== this.loadGen)) return this.onResolved(t, e);
|
|
1815
|
-
}).catch((
|
|
1816
|
-
this.destroyed || this.abort.signal.aborted || e !== this.loadGen || this.fail(
|
|
1901
|
+
}).catch((t) => {
|
|
1902
|
+
this.destroyed || this.abort.signal.aborted || e !== this.loadGen || this.fail(t instanceof n ? t : new n("INTERNAL", 0, String(t)));
|
|
1817
1903
|
});
|
|
1818
1904
|
}
|
|
1819
|
-
armWithSse(e,
|
|
1820
|
-
let i = !1,
|
|
1905
|
+
armWithSse(e, t, r) {
|
|
1906
|
+
let i = !1, a = !1, s = new AbortController();
|
|
1821
1907
|
this.armFallbackCtrl = s, this.setState("waiting");
|
|
1822
1908
|
let c = this.opts.waitForLive, l = c && c !== !0 ? c.kickoffAt : void 0, u = typeof l == "number" ? l : typeof l == "string" ? Date.parse(l) : NaN, d = r ?? (Number.isFinite(u) ? u : void 0);
|
|
1823
1909
|
setTimeout(() => {
|
|
1824
1910
|
i || this.destroyed || e !== this.loadGen || this.emit("waiting", {
|
|
1825
1911
|
phase: "tooEarly",
|
|
1826
|
-
retryInMs:
|
|
1912
|
+
retryInMs: Z,
|
|
1827
1913
|
attempt: 1,
|
|
1828
1914
|
elapsedMs: 0,
|
|
1829
1915
|
...d !== void 0 && d > Date.now() ? { ttkMs: d - Date.now() } : {}
|
|
1830
1916
|
});
|
|
1831
1917
|
}, 0);
|
|
1832
|
-
let f = () => this.destroyed || this.abort.signal.aborted || e !== this.loadGen, p = async (
|
|
1918
|
+
let f = () => this.destroyed || this.abort.signal.aborted || e !== this.loadGen, p = async (t) => {
|
|
1833
1919
|
if (!(i || f())) {
|
|
1834
1920
|
i = !0, this.closeArming(), s.abort();
|
|
1835
1921
|
try {
|
|
1836
|
-
await this.onResolved(
|
|
1922
|
+
await this.onResolved(t, e);
|
|
1837
1923
|
} catch (e) {
|
|
1838
1924
|
if (f()) return;
|
|
1839
|
-
this.fail(e instanceof
|
|
1925
|
+
this.fail(e instanceof n ? e : new n("INTERNAL", 0, String(e)));
|
|
1840
1926
|
}
|
|
1841
1927
|
}
|
|
1842
1928
|
}, m = () => {
|
|
1843
|
-
i ||
|
|
1929
|
+
i || a || f() || (a = !0, y({
|
|
1844
1930
|
...this.resolveOptions(),
|
|
1845
1931
|
signal: s.signal,
|
|
1846
1932
|
waitForLive: this.buildWaitConfig(e)
|
|
1847
1933
|
}).then((e) => p(e)).catch((e) => {
|
|
1848
|
-
i || f() || s.signal.aborted || (i = !0, this.closeArming(), this.fail(e instanceof
|
|
1934
|
+
i || f() || s.signal.aborted || (i = !0, this.closeArming(), this.fail(e instanceof n ? e : new n("INTERNAL", 0, String(e))));
|
|
1849
1935
|
}));
|
|
1850
1936
|
}, h = () => {
|
|
1851
|
-
i || f() ||
|
|
1852
|
-
i || f() || e instanceof
|
|
1937
|
+
i || f() || v(this.resolveOptions()).then((e) => p(e)).catch((e) => {
|
|
1938
|
+
i || f() || e instanceof n && o(e.code) || (i = !0, this.closeArming(), s.abort(), this.fail(e instanceof n ? e : new n("INTERNAL", 0, String(e))));
|
|
1853
1939
|
});
|
|
1854
1940
|
}, g = (e) => {
|
|
1855
1941
|
this.armSseTimer && clearTimeout(this.armSseTimer), this.armSseTimer = setTimeout(() => {
|
|
1856
1942
|
!i && !f() && m();
|
|
1857
1943
|
}, e);
|
|
1858
1944
|
};
|
|
1859
|
-
g(
|
|
1860
|
-
eventsBaseUrl:
|
|
1945
|
+
g(it), this.armingSub = E({
|
|
1946
|
+
eventsBaseUrl: t,
|
|
1861
1947
|
matchUrn: this.opts.matchUrn,
|
|
1862
1948
|
credential: this.opts.credential,
|
|
1863
|
-
onAlive: () => g(
|
|
1949
|
+
onAlive: () => g(Z),
|
|
1864
1950
|
onState: (e) => {
|
|
1865
|
-
i || f() || (e.state === "live" || e.state === "gone") && setTimeout(h, Math.random() *
|
|
1951
|
+
i || f() || (e.state === "live" || e.state === "gone") && setTimeout(h, Math.random() * at);
|
|
1866
1952
|
},
|
|
1867
1953
|
onError: () => m()
|
|
1868
1954
|
});
|
|
@@ -1882,11 +1968,11 @@ var tt = class {
|
|
|
1882
1968
|
async onResolved(e, t) {
|
|
1883
1969
|
if (this.destroyed || t !== this.loadGen) return;
|
|
1884
1970
|
this._descriptor = e, this.endedHandled = !1;
|
|
1885
|
-
let n = await
|
|
1971
|
+
let n = await s(this.opts.credential);
|
|
1886
1972
|
if (this.destroyed || t !== this.loadGen) return;
|
|
1887
1973
|
this.setState("loading");
|
|
1888
|
-
let r = this.createEngine(e, n), i =
|
|
1889
|
-
this._state
|
|
1974
|
+
let r = this.createEngine(e, n), i = we(this.opts.video, (e) => {
|
|
1975
|
+
this._state !== "ended" && this._state !== "error" && this.setState(e);
|
|
1890
1976
|
});
|
|
1891
1977
|
if (await r.load(), this.destroyed || t !== this.loadGen) {
|
|
1892
1978
|
i(), r.destroy();
|
|
@@ -1902,14 +1988,14 @@ var tt = class {
|
|
|
1902
1988
|
if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachSeekListener?.(), this.opts.analytics === !1) return;
|
|
1903
1989
|
let r = e.analytics?.sid;
|
|
1904
1990
|
if (!r) return;
|
|
1905
|
-
let i = (typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0) ??
|
|
1991
|
+
let i = (typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0) ?? Ge(this.opts.baseUrl);
|
|
1906
1992
|
if (!i) return;
|
|
1907
|
-
let a = this.opts.video, o = new
|
|
1993
|
+
let a = this.opts.video, o = new Ke({
|
|
1908
1994
|
endpoint: i,
|
|
1909
1995
|
sid: r,
|
|
1910
1996
|
apiKey: n,
|
|
1911
1997
|
player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
|
|
1912
|
-
sdkVersion:
|
|
1998
|
+
sdkVersion: qe,
|
|
1913
1999
|
sample: () => {
|
|
1914
2000
|
let e = this.engine?.getStats() ?? F, t = a.buffered.length ? Math.max(0, a.buffered.end(a.buffered.length - 1) - a.currentTime) : 0;
|
|
1915
2001
|
return {
|
|
@@ -1924,14 +2010,14 @@ var tt = class {
|
|
|
1924
2010
|
let s = () => o.noteSeek();
|
|
1925
2011
|
a.addEventListener("seeking", s), this.detachSeekListener = () => a.removeEventListener("seeking", s), o.start();
|
|
1926
2012
|
}
|
|
1927
|
-
createEngine(e,
|
|
2013
|
+
createEngine(e, t) {
|
|
1928
2014
|
let r = { ...this.opts.hlsConfig };
|
|
1929
2015
|
this.opts.startLevel != null && (r.startLevel = this.opts.startLevel), this.opts.liveLatencyTarget != null && (r.liveSyncDuration = this.opts.liveLatencyTarget);
|
|
1930
2016
|
let i = {
|
|
1931
2017
|
video: this.opts.video,
|
|
1932
2018
|
descriptor: e,
|
|
1933
|
-
credential:
|
|
1934
|
-
deviceId:
|
|
2019
|
+
credential: t,
|
|
2020
|
+
deviceId: A(),
|
|
1935
2021
|
userId: this.opts.userId,
|
|
1936
2022
|
lowLatency: this.opts.lowLatency === void 0 || this.opts.lowLatency === "auto" || this.opts.lowLatency,
|
|
1937
2023
|
snapToLiveOnRefocus: this.opts.snapToLiveOnRefocus,
|
|
@@ -1940,11 +2026,11 @@ var tt = class {
|
|
|
1940
2026
|
emit: (e) => this.onEngineEvent(e)
|
|
1941
2027
|
}, a = this.opts.engine ?? "auto";
|
|
1942
2028
|
if (a === "native") return new z(i);
|
|
1943
|
-
if (a === "hls") return new
|
|
2029
|
+
if (a === "hls") return new H(i);
|
|
1944
2030
|
if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && L(this.opts.video) && R()) return new z(i);
|
|
1945
|
-
if (
|
|
2031
|
+
if (De()) return new H(i);
|
|
1946
2032
|
if (L(this.opts.video)) return new z(i);
|
|
1947
|
-
throw new
|
|
2033
|
+
throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
|
|
1948
2034
|
}
|
|
1949
2035
|
onEngineEvent(e) {
|
|
1950
2036
|
if (!this.destroyed) switch (e.type) {
|
|
@@ -1966,19 +2052,17 @@ var tt = class {
|
|
|
1966
2052
|
case "ended":
|
|
1967
2053
|
this.onStreamEnded();
|
|
1968
2054
|
break;
|
|
1969
|
-
case "error":
|
|
1970
|
-
this.analyticsSession?.noteError(e.error.code, e.error.message, e.fatal, e.error.httpStatus ?? 0, Math.round(this.opts.video.currentTime * 1e3)), e.fatal ? this.fail(e.error) : this.emit("warning", e.error);
|
|
1971
|
-
break;
|
|
2055
|
+
case "error": this.analyticsSession?.noteError(e.error.code, e.error.message, e.fatal, e.error.httpStatus ?? 0, Math.round(this.opts.video.currentTime * 1e3)), e.fatal ? this.fail(e.error) : this.emit("warning", e.error);
|
|
1972
2056
|
}
|
|
1973
2057
|
}
|
|
1974
2058
|
startLiveState(e) {
|
|
1975
2059
|
if (this.opts.liveStateEvents === !1) return;
|
|
1976
|
-
let
|
|
1977
|
-
if (!
|
|
2060
|
+
let t = this.opts.eventsBaseUrl ?? D(this.opts.baseUrl);
|
|
2061
|
+
if (!t) return;
|
|
1978
2062
|
this.closeLiveState();
|
|
1979
2063
|
let r = 0, i = !1;
|
|
1980
|
-
this.liveStateSub =
|
|
1981
|
-
eventsBaseUrl:
|
|
2064
|
+
this.liveStateSub = E({
|
|
2065
|
+
eventsBaseUrl: t,
|
|
1982
2066
|
matchUrn: this.opts.matchUrn,
|
|
1983
2067
|
credential: this.opts.credential,
|
|
1984
2068
|
onState: (t) => {
|
|
@@ -1988,7 +2072,7 @@ var tt = class {
|
|
|
1988
2072
|
r = 0, i = !1;
|
|
1989
2073
|
},
|
|
1990
2074
|
onError: () => {
|
|
1991
|
-
this.destroyed || e !== this.loadGen || i || (r += 1, r >=
|
|
2075
|
+
this.destroyed || e !== this.loadGen || i || (r += 1, r >= ot && (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.`))));
|
|
1992
2076
|
}
|
|
1993
2077
|
});
|
|
1994
2078
|
}
|
|
@@ -2010,7 +2094,7 @@ var tt = class {
|
|
|
2010
2094
|
}
|
|
2011
2095
|
t.controls = !1;
|
|
2012
2096
|
let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
|
|
2013
|
-
r && r.insertBefore(n, t), n.appendChild(t),
|
|
2097
|
+
r && r.insertBefore(n, t), n.appendChild(t), q(n, this.opts.theme), this.container = n, this.controlBar = $e({
|
|
2014
2098
|
root: n,
|
|
2015
2099
|
video: t,
|
|
2016
2100
|
player: this,
|
|
@@ -2033,7 +2117,7 @@ var tt = class {
|
|
|
2033
2117
|
}
|
|
2034
2118
|
startStats() {
|
|
2035
2119
|
this.stopStats();
|
|
2036
|
-
let e = Math.max(500, this.opts.statsIntervalMs ??
|
|
2120
|
+
let e = Math.max(500, this.opts.statsIntervalMs ?? st);
|
|
2037
2121
|
this.statsTimer = setInterval(() => {
|
|
2038
2122
|
if (!this.engine) return;
|
|
2039
2123
|
let e = this.engine.getStats();
|
|
@@ -2045,7 +2129,7 @@ var tt = class {
|
|
|
2045
2129
|
}
|
|
2046
2130
|
scheduleLicenseRefresh() {
|
|
2047
2131
|
this.stopRefresh();
|
|
2048
|
-
let e = this.opts.licenseRefreshMs ??
|
|
2132
|
+
let e = this.opts.licenseRefreshMs ?? ct;
|
|
2049
2133
|
!e || !this._descriptor?.drmEnabled || (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
|
|
2050
2134
|
}
|
|
2051
2135
|
stopRefresh() {
|
|
@@ -2054,7 +2138,7 @@ var tt = class {
|
|
|
2054
2138
|
async refreshLicense() {
|
|
2055
2139
|
let e = this.engine;
|
|
2056
2140
|
if (!(this.destroyed || !e)) try {
|
|
2057
|
-
let t = await
|
|
2141
|
+
let t = await v(this.resolveOptions());
|
|
2058
2142
|
if (this.destroyed || this.engine !== e) return;
|
|
2059
2143
|
let n = t.drm?.widevine?.licenseUrl, r = t.drm?.fairplay?.licenseUrl;
|
|
2060
2144
|
(n || r) && (e.setLicenseUrls({
|
|
@@ -2062,7 +2146,7 @@ var tt = class {
|
|
|
2062
2146
|
fairplay: r
|
|
2063
2147
|
}), this._descriptor = t);
|
|
2064
2148
|
} catch (e) {
|
|
2065
|
-
e instanceof
|
|
2149
|
+
e instanceof n && !o(e.code) && (this.stopRefresh(), this.destroyed || this.emit("warning", e));
|
|
2066
2150
|
}
|
|
2067
2151
|
}
|
|
2068
2152
|
async play() {
|
|
@@ -2120,6 +2204,12 @@ var tt = class {
|
|
|
2120
2204
|
let e = document;
|
|
2121
2205
|
e.pictureInPictureElement === this.opts.video && typeof e.exitPictureInPicture == "function" && await e.exitPictureInPicture();
|
|
2122
2206
|
}
|
|
2207
|
+
async enterFullscreen() {
|
|
2208
|
+
return !this.destroyed && w(this.opts.video, this.container ?? void 0);
|
|
2209
|
+
}
|
|
2210
|
+
async exitFullscreen() {
|
|
2211
|
+
await T(this.opts.video, this.container ?? void 0);
|
|
2212
|
+
}
|
|
2123
2213
|
retry() {
|
|
2124
2214
|
return this.reload();
|
|
2125
2215
|
}
|
|
@@ -2128,14 +2218,14 @@ var tt = class {
|
|
|
2128
2218
|
let e = ++this.loadGen;
|
|
2129
2219
|
this.stopStats(), this.stopRefresh(), this.closeArming(), this.closeLiveState(), this.detachMedia?.(), this.engine?.destroy(), this.engine = null;
|
|
2130
2220
|
try {
|
|
2131
|
-
let t = await
|
|
2221
|
+
let t = await y({
|
|
2132
2222
|
...this.resolveOptions(),
|
|
2133
2223
|
waitForLive: this.opts.waitForLive ? this.buildWaitConfig(e) : void 0
|
|
2134
2224
|
});
|
|
2135
2225
|
if (await this.onResolved(t, e), e === this.loadGen && this._state === "error" && this._lastError) throw this._lastError;
|
|
2136
|
-
} catch (
|
|
2226
|
+
} catch (t) {
|
|
2137
2227
|
if (this.destroyed || this.abort.signal.aborted || e !== this.loadGen) return;
|
|
2138
|
-
throw
|
|
2228
|
+
throw t !== this._lastError && this.fail(t instanceof n ? t : new n("INTERNAL", 0, String(t))), t;
|
|
2139
2229
|
}
|
|
2140
2230
|
}
|
|
2141
2231
|
on(e, t) {
|
|
@@ -2168,10 +2258,7 @@ var tt = class {
|
|
|
2168
2258
|
case "paused":
|
|
2169
2259
|
this.emit("paused");
|
|
2170
2260
|
break;
|
|
2171
|
-
case "ended":
|
|
2172
|
-
this.emit("ended");
|
|
2173
|
-
break;
|
|
2174
|
-
default: break;
|
|
2261
|
+
case "ended": this.emit("ended");
|
|
2175
2262
|
}
|
|
2176
2263
|
}
|
|
2177
2264
|
emit(e, t) {
|
|
@@ -2189,7 +2276,7 @@ function $(e) {
|
|
|
2189
2276
|
}
|
|
2190
2277
|
//#endregion
|
|
2191
2278
|
//#region src/embed/host.ts
|
|
2192
|
-
function
|
|
2279
|
+
function ut(e) {
|
|
2193
2280
|
if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
|
|
2194
2281
|
if (!e.src) throw Error("mountEmbed: opts.src is required");
|
|
2195
2282
|
if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
|
|
@@ -2248,8 +2335,8 @@ function nt(e) {
|
|
|
2248
2335
|
}
|
|
2249
2336
|
//#endregion
|
|
2250
2337
|
//#region src/embed/page.ts
|
|
2251
|
-
var
|
|
2252
|
-
function
|
|
2338
|
+
var dt = /^[A-Za-z0-9:_.-]{1,128}$/;
|
|
2339
|
+
function ft() {
|
|
2253
2340
|
let e = window.HAVIK_EMBED_CONFIG;
|
|
2254
2341
|
if (e) return {
|
|
2255
2342
|
baseUrl: e.baseUrl ?? "",
|
|
@@ -2271,11 +2358,11 @@ function it() {
|
|
|
2271
2358
|
waitForLive: !0
|
|
2272
2359
|
};
|
|
2273
2360
|
}
|
|
2274
|
-
async function
|
|
2275
|
-
let e =
|
|
2276
|
-
|
|
2277
|
-
let
|
|
2278
|
-
|
|
2361
|
+
async function pt() {
|
|
2362
|
+
let e = ft();
|
|
2363
|
+
ht();
|
|
2364
|
+
let t = document.createElement("video");
|
|
2365
|
+
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);
|
|
2279
2366
|
let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
|
|
2280
2367
|
r || console.warn("havik-player: embed has no parentOrigin — the postMessage bridge is disabled (no events posted, no commands accepted). mountEmbed sets parentOrigin automatically.");
|
|
2281
2368
|
let i = (e) => {
|
|
@@ -2328,13 +2415,13 @@ async function at() {
|
|
|
2328
2415
|
code: e.code,
|
|
2329
2416
|
message: e.message
|
|
2330
2417
|
})), e.on("autoplayblocked", () => {
|
|
2331
|
-
i({ type: "oddin:autoplayblocked" }),
|
|
2418
|
+
i({ type: "oddin:autoplayblocked" }), mt(t, e);
|
|
2332
2419
|
});
|
|
2333
2420
|
}, s = async (r) => {
|
|
2334
2421
|
a?.destroy(), a = null;
|
|
2335
2422
|
try {
|
|
2336
|
-
let
|
|
2337
|
-
video:
|
|
2423
|
+
let n = await Q({
|
|
2424
|
+
video: t,
|
|
2338
2425
|
baseUrl: e.baseUrl,
|
|
2339
2426
|
matchUrn: r,
|
|
2340
2427
|
credential: { apiKey: e.apiKey },
|
|
@@ -2342,14 +2429,14 @@ async function at() {
|
|
|
2342
2429
|
muted: e.muted,
|
|
2343
2430
|
waitForLive: e.waitForLive
|
|
2344
2431
|
});
|
|
2345
|
-
a =
|
|
2346
|
-
let i =
|
|
2347
|
-
i?.classList.contains("havik-player") && (i.style.cssText = "position:absolute;inset:0;width:100%;height:100%;aspect-ratio:auto"), o(
|
|
2432
|
+
a = n;
|
|
2433
|
+
let i = t.parentElement;
|
|
2434
|
+
i?.classList.contains("havik-player") && (i.style.cssText = "position:absolute;inset:0;width:100%;height:100%;aspect-ratio:auto"), o(n);
|
|
2348
2435
|
} catch (e) {
|
|
2349
|
-
let
|
|
2436
|
+
let t = e instanceof n ? e.code : "INTERNAL", r = e instanceof Error ? e.message : String(e);
|
|
2350
2437
|
i({
|
|
2351
2438
|
type: "oddin:error",
|
|
2352
|
-
code:
|
|
2439
|
+
code: t,
|
|
2353
2440
|
message: r
|
|
2354
2441
|
});
|
|
2355
2442
|
}
|
|
@@ -2394,11 +2481,9 @@ async function at() {
|
|
|
2394
2481
|
a?.retry();
|
|
2395
2482
|
break;
|
|
2396
2483
|
case "oddin:load":
|
|
2397
|
-
typeof e.matchUrn == "string" &&
|
|
2398
|
-
break;
|
|
2399
|
-
case "oddin:destroy":
|
|
2400
|
-
c();
|
|
2484
|
+
typeof e.matchUrn == "string" && dt.test(e.matchUrn) && s(e.matchUrn);
|
|
2401
2485
|
break;
|
|
2486
|
+
case "oddin:destroy": c();
|
|
2402
2487
|
}
|
|
2403
2488
|
}, u = (e) => {
|
|
2404
2489
|
!r || e.origin !== r || $(e.data) && l(e.data);
|
|
@@ -2408,18 +2493,18 @@ async function at() {
|
|
|
2408
2493
|
protocol: 1
|
|
2409
2494
|
});
|
|
2410
2495
|
}
|
|
2411
|
-
function
|
|
2496
|
+
function mt(e, t) {
|
|
2412
2497
|
if (document.getElementById("havik-tap")) return;
|
|
2413
2498
|
let n = document.createElement("button");
|
|
2414
2499
|
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", () => {
|
|
2415
2500
|
n.remove(), t.play();
|
|
2416
2501
|
}), document.body.appendChild(n);
|
|
2417
2502
|
}
|
|
2418
|
-
function
|
|
2503
|
+
function ht() {
|
|
2419
2504
|
let e = document.createElement("style");
|
|
2420
2505
|
e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
|
|
2421
2506
|
}
|
|
2422
2507
|
//#endregion
|
|
2423
|
-
export {
|
|
2508
|
+
export { G as ODDIN_THEME, n as PlaybackError, q as applyTheme, pt as bootEmbed, ge as clearDeviceId, Q as createPlayer, D as deriveEventsBaseUrl, xe as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, ue as fetchCatalog, fe as fetchTournament, me as flattenMatches, A as getDeviceId, Ce as isLowLatencyManifest, $ as isOddinMessage, ve as licenseRequestHeaders, ut as mountEmbed, _ as pollToLive, y as resolveStream, E as subscribeLiveState, C as videoFullscreenActive, he as watchStatus };
|
|
2424
2509
|
|
|
2425
2510
|
//# sourceMappingURL=index.js.map
|