@kkcompany/player 2.25.0-canary.23 → 2.25.0-canary.25

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.
@@ -0,0 +1,1560 @@
1
+ import { r as getVersion } from "./util-B2YBSBjR.mjs";
2
+ import { b as isIOS, i as isLiveDuration, k as on, x as isSafari } from "./mediaBindings-CoY60lQw.mjs";
3
+ import { t as fixDashManifest_default } from "./fixDashManifest-CJ63KKaA.mjs";
4
+
5
+ //#region src/playerCore/errors.js
6
+ const handleError = async ({ nativeEvent: event }, { media, displayError, delay = 5e3 }) => {
7
+ console.warn(event);
8
+ if (event.defaultPrevented) return;
9
+ const { code, name, data, message } = event.error || {};
10
+ if ([
11
+ code,
12
+ name,
13
+ data,
14
+ message
15
+ ].every((it) => typeof it === "undefined")) {
16
+ setTimeout(() => {
17
+ if (!(media.readyState >= 1)) displayError({
18
+ code: `VIDEO:${media.error?.code || 0}`,
19
+ message: media.error?.message
20
+ });
21
+ }, delay);
22
+ console.warn("error from video element, let base player handle it", event);
23
+ } else displayError({
24
+ code,
25
+ name,
26
+ data,
27
+ message
28
+ });
29
+ };
30
+ const reloadOnLiveStall = (media, { reload, stallDuration = 6e3 }) => {
31
+ const getBufferedEnd = () => Math.max(0, ...Array.from({ length: media.buffered?.length || 0 }, (_, i) => media.buffered.end(i)));
32
+ let checkTimer;
33
+ const state = { lastBufferedEnd: 0 };
34
+ const removeListener = on(media, "loadeddata", () => {
35
+ if (!isLiveDuration(media.duration)) return;
36
+ const checkStall = () => {
37
+ const currentBufferedEnd = getBufferedEnd();
38
+ if (!media.paused && state.lastBufferedEnd === currentBufferedEnd && (media.buffered.length < 1 || state.lastPlayed === media.currentTime)) {
39
+ console.warn("Live stream stall, reload to recover");
40
+ state.lastBufferedEnd = 0;
41
+ reload();
42
+ }
43
+ state.lastBufferedEnd = currentBufferedEnd;
44
+ state.lastPlayed = media.currentTime;
45
+ clearTimeout(checkTimer);
46
+ checkTimer = setTimeout(checkStall, stallDuration);
47
+ };
48
+ clearTimeout(checkTimer);
49
+ checkTimer = setTimeout(checkStall, stallDuration);
50
+ });
51
+ return () => {
52
+ removeListener();
53
+ clearTimeout(checkTimer);
54
+ };
55
+ };
56
+
57
+ //#endregion
58
+ //#region src/util/printVersion.js
59
+ const printVersion = () => {
60
+ console.log([`%KKCompany Web Player SDK\n-----------\nVersion: ${getVersion()}`, `We are hiring, and looking for geeks like you! please join us at https://www.kkcompany.com/zh-tw/career/`].join("\n"), "color: #0E78F4");
61
+ };
62
+ var printVersion_default = printVersion;
63
+
64
+ //#endregion
65
+ //#region src/playerCore/native.js
66
+ const loadNative = ({ videoElement }) => ({
67
+ load: ({ native: url }) => {
68
+ videoElement.src = url;
69
+ videoElement.style.height = "100%";
70
+ videoElement.style.width = "100%";
71
+ },
72
+ play: () => videoElement.play(),
73
+ pause: () => videoElement.pause(),
74
+ seek: (time) => {
75
+ videoElement.currentTime = time;
76
+ },
77
+ getVideoElement: () => videoElement,
78
+ getVideoQuality: () => ({}),
79
+ destroy: () => {}
80
+ });
81
+
82
+ //#endregion
83
+ //#region src/util/getUrlObject.js
84
+ const getUrlObject = (fn) => {
85
+ const createObjectURL = window.URL.createObjectURL.bind();
86
+ window.URL.createObjectURL = (blob) => {
87
+ if (blob.addSourceBuffer) fn(blob);
88
+ return createObjectURL(blob);
89
+ };
90
+ };
91
+ var getUrlObject_default = getUrlObject;
92
+
93
+ //#endregion
94
+ //#region src/plugins/shaka/HttpFetchPlugin.js
95
+ /*! @license
96
+ * Shaka Player
97
+ * Copyright 2016 Google LLC
98
+ * SPDX-License-Identifier: Apache-2.0
99
+ */
100
+ let shaka$1;
101
+ const shakaLog$1 = { v1: () => {} };
102
+ const asMap = (object) => {
103
+ const map = /* @__PURE__ */ new Map();
104
+ for (const key of Object.keys(object)) map.set(key, object[key]);
105
+ return map;
106
+ };
107
+ const makeResponse = (headers, data, status, uri, responseURL, requestType) => {
108
+ if (status >= 200 && status <= 299 && status != 202) return {
109
+ uri: responseURL || uri,
110
+ originalUri: uri,
111
+ data,
112
+ status,
113
+ headers,
114
+ fromCache: !!headers["x-shaka-from-cache"]
115
+ };
116
+ let responseText = null;
117
+ try {
118
+ responseText = shaka$1.util.StringUtils.fromBytesAutoDetect(data);
119
+ } catch (exception) {}
120
+ const severity = status == 401 || status == 403 ? shaka$1.util.Error.Severity.CRITICAL : shaka$1.util.Error.Severity.RECOVERABLE;
121
+ throw new shaka$1.util.Error(severity, shaka$1.util.Error.Category.NETWORK, shaka$1.util.Error.Code.BAD_HTTP_STATUS, uri, status, responseText, headers, requestType);
122
+ };
123
+ const goog$2 = { asserts: { assert: () => {} } };
124
+ /**
125
+ * @summary A networking plugin to handle http and https URIs via the Fetch API.
126
+ * @export
127
+ */
128
+ var HttpFetchPlugin = class HttpFetchPlugin {
129
+ /**
130
+ * @param {string} uri
131
+ * @param {shaka.extern.Request} request
132
+ * @param {shaka.net.NetworkingEngine.RequestType} requestType
133
+ * @param {shaka.extern.ProgressUpdated} progressUpdated Called when a
134
+ * progress event happened.
135
+ * @param {shaka.extern.HeadersReceived} headersReceived Called when the
136
+ * headers for the download are received, but before the body is.
137
+ * @return {!shaka.extern.IAbortableOperation.<shaka.extern.Response>}
138
+ * @export
139
+ */
140
+ static parse(uri, request, requestType, progressUpdated, headersReceived) {
141
+ const headers = new HttpFetchPlugin.Headers_();
142
+ asMap(request.headers).forEach((value, key) => {
143
+ headers.append(key, value);
144
+ });
145
+ const controller = new HttpFetchPlugin.AbortController_();
146
+ /** @type {!RequestInit} */
147
+ const init = {
148
+ body: request.body || void 0,
149
+ headers,
150
+ method: request.method,
151
+ signal: controller.signal,
152
+ credentials: request.allowCrossSiteCredentials ? "include" : void 0
153
+ };
154
+ /** @type {shaka.net.HttpFetchPlugin.AbortStatus} */
155
+ const abortStatus = {
156
+ canceled: false,
157
+ timedOut: false
158
+ };
159
+ const pendingRequest = HttpFetchPlugin.request_(uri, requestType, init, abortStatus, progressUpdated, headersReceived, request.streamDataCallback);
160
+ /** @type {!shaka.util.AbortableOperation} */
161
+ const op = new shaka$1.util.AbortableOperation(pendingRequest, () => {
162
+ abortStatus.canceled = true;
163
+ controller.abort();
164
+ return Promise.resolve();
165
+ });
166
+ const timeoutMs = request.retryParameters.timeout;
167
+ if (timeoutMs) {
168
+ const timer = new shaka$1.util.Timer(() => {
169
+ abortStatus.timedOut = true;
170
+ controller.abort();
171
+ });
172
+ timer.tickAfter(timeoutMs / 1e3);
173
+ op.finally(() => {
174
+ timer.stop();
175
+ });
176
+ }
177
+ return op;
178
+ }
179
+ /**
180
+ * @param {string} uri
181
+ * @param {shaka.net.NetworkingEngine.RequestType} requestType
182
+ * @param {!RequestInit} init
183
+ * @param {shaka.net.HttpFetchPlugin.AbortStatus} abortStatus
184
+ * @param {shaka.extern.ProgressUpdated} progressUpdated
185
+ * @param {shaka.extern.HeadersReceived} headersReceived
186
+ * @param {?function(BufferSource):!Promise} streamDataCallback
187
+ * @return {!Promise<!shaka.extern.Response>}
188
+ * @private
189
+ */
190
+ static async request_(uri, requestType, init, abortStatus, progressUpdated, headersReceived, streamDataCallback) {
191
+ const fetch = HttpFetchPlugin.fetch_;
192
+ const ReadableStream = HttpFetchPlugin.ReadableStream_;
193
+ let response;
194
+ let arrayBuffer;
195
+ let loaded = 0;
196
+ let lastLoaded = 0;
197
+ let lastTime = Date.now();
198
+ try {
199
+ response = await fetch(uri, init);
200
+ headersReceived(HttpFetchPlugin.headersToGenericObject_(response.headers));
201
+ const reader = response.clone().body.getReader();
202
+ const contentLengthRaw = response.headers.get("Content-Length");
203
+ const contentLength = contentLengthRaw ? parseInt(contentLengthRaw, 10) : 0;
204
+ const start = (controller) => {
205
+ const push = async () => {
206
+ let readObj;
207
+ try {
208
+ readObj = await reader.read();
209
+ } catch (e) {
210
+ shakaLog$1.v1("error reading from stream", e.message);
211
+ return;
212
+ }
213
+ if (!readObj.done) {
214
+ loaded += readObj.value.byteLength;
215
+ if (response.status === 200 && streamDataCallback) await streamDataCallback(readObj.value);
216
+ }
217
+ const currentTime = Date.now();
218
+ if (currentTime - lastTime > 100 || readObj.done) {
219
+ progressUpdated(currentTime - lastTime, loaded - lastLoaded, contentLength - loaded);
220
+ lastLoaded = loaded;
221
+ lastTime = currentTime;
222
+ }
223
+ if (readObj.done) {
224
+ goog$2.asserts.assert(!readObj.value, "readObj should be unset when \"done\" is true.");
225
+ controller.close();
226
+ } else {
227
+ controller.enqueue(readObj.value);
228
+ push();
229
+ }
230
+ };
231
+ push();
232
+ };
233
+ new ReadableStream({ start });
234
+ arrayBuffer = await response.arrayBuffer();
235
+ } catch (error) {
236
+ if (abortStatus.canceled) throw new shaka$1.util.Error(shaka$1.util.Error.Severity.RECOVERABLE, shaka$1.util.Error.Category.NETWORK, shaka$1.util.Error.Code.OPERATION_ABORTED, uri, requestType);
237
+ else if (abortStatus.timedOut) throw new shaka$1.util.Error(shaka$1.util.Error.Severity.RECOVERABLE, shaka$1.util.Error.Category.NETWORK, shaka$1.util.Error.Code.TIMEOUT, uri, requestType);
238
+ else throw new shaka$1.util.Error(shaka$1.util.Error.Severity.RECOVERABLE, shaka$1.util.Error.Category.NETWORK, shaka$1.util.Error.Code.HTTP_ERROR, uri, error, requestType);
239
+ }
240
+ return makeResponse(HttpFetchPlugin.headersToGenericObject_(response.headers), arrayBuffer, response.status, uri, response.url, requestType);
241
+ }
242
+ /**
243
+ * @param {!Headers} headers
244
+ * @return {!Object.<string, string>}
245
+ * @private
246
+ */
247
+ static headersToGenericObject_(headers) {
248
+ const headersObj = {};
249
+ headers.forEach((value, key) => {
250
+ headersObj[key.trim()] = value;
251
+ });
252
+ return headersObj;
253
+ }
254
+ };
255
+ HttpFetchPlugin.register = (shakaNamespace) => {
256
+ shaka$1 = shakaNamespace;
257
+ /**
258
+ * Overridden in unit tests, but compiled out in production.
259
+ *
260
+ * @const {function(string, !RequestInit)}
261
+ * @private
262
+ */
263
+ HttpFetchPlugin.fetch_ = window.fetch;
264
+ /**
265
+ * Overridden in unit tests, but compiled out in production.
266
+ *
267
+ * @const {function(new: AbortController)}
268
+ * @private
269
+ */
270
+ HttpFetchPlugin.AbortController_ = window.AbortController;
271
+ /**
272
+ * Overridden in unit tests, but compiled out in production.
273
+ *
274
+ * @const {function(new: ReadableStream, !Object)}
275
+ * @private
276
+ */
277
+ HttpFetchPlugin.ReadableStream_ = window.ReadableStream;
278
+ /**
279
+ * Overridden in unit tests, but compiled out in production.
280
+ *
281
+ * @const {function(new: Headers)}
282
+ * @private
283
+ */
284
+ HttpFetchPlugin.Headers_ = window.Headers;
285
+ shaka$1.net.NetworkingEngine.registerScheme("http", HttpFetchPlugin.parse);
286
+ shaka$1.net.NetworkingEngine.registerScheme("https", HttpFetchPlugin.parse);
287
+ shaka$1.net.NetworkingEngine.registerScheme("blob", HttpFetchPlugin.parse);
288
+ };
289
+ var HttpFetchPlugin_default = HttpFetchPlugin;
290
+
291
+ //#endregion
292
+ //#region src/plugins/shaka/setupKKFariplay.js
293
+ const defaultInitDataTransform = (initData, initDataType, drmInfo) => {
294
+ if (initDataType === "skd") {
295
+ const { defaultGetContentId, initDataTransform } = shaka.util.FairPlayUtils;
296
+ const cert = drmInfo.serverCertificate;
297
+ return initDataTransform(initData, defaultGetContentId(initData), cert);
298
+ }
299
+ return initData;
300
+ };
301
+ const wrapFairplayLicenseRequest = (request) => {
302
+ const base64Payload = encodeURIComponent(btoa(String.fromCharCode(...new Uint8Array(request.body))));
303
+ const contentId = encodeURIComponent(new TextDecoder("utf-8").decode(request.initData).slice(6));
304
+ request.headers["Content-Type"] = "application/x-www-form-urlencoded";
305
+ request.body = `spc=${base64Payload}&asset_id=${contentId}`;
306
+ };
307
+ const requestHandler = (type, request, player, extensionOptions) => {
308
+ const { LICENSE, SERVER_CERTIFICATE } = shaka.net.NetworkingEngine.RequestType;
309
+ if (type === SERVER_CERTIFICATE) Object.assign(request.headers, extensionOptions.drm[player.drmInfo().keySystem]?.headers);
310
+ if (type === LICENSE) wrapFairplayLicenseRequest(request);
311
+ return request;
312
+ };
313
+ const stripResponseCkc = (type, response) => {
314
+ if (type !== shaka.net.NetworkingEngine.RequestType.LICENSE) return response;
315
+ const keyMessage = new TextDecoder("utf-8").decode(response.data).trim();
316
+ if (keyMessage.slice(0, 5) === "<ckc>" && keyMessage.slice(-6) === "</ckc>") response.data = Uint8Array.from(atob(keyMessage.slice(5, -6)), (c) => c.charCodeAt(0));
317
+ return response;
318
+ };
319
+ const setupKKFariplay = (player, extensionOptions) => {
320
+ if (!window.WebKitMediaKeys) return;
321
+ shaka.polyfill.PatchedMediaKeysApple.install();
322
+ player.configure({ drm: { initDataTransform: defaultInitDataTransform } });
323
+ extensionOptions.requestHandlers.push(requestHandler);
324
+ extensionOptions.responseHandlers.push(stripResponseCkc);
325
+ };
326
+ var setupKKFariplay_default = setupKKFariplay;
327
+
328
+ //#endregion
329
+ //#region src/plugins/shaka/VttTextParser.js
330
+ /*! @license
331
+ * Shaka Player
332
+ * Copyright 2016 Google LLC
333
+ * SPDX-License-Identifier: Apache-2.0
334
+ */
335
+ const goog$1 = { asserts: { assert: (condition, message) => {
336
+ if (!condition) console.warn("GOOG Assert!", message);
337
+ } } };
338
+ const addDefaultTextColor = (styles) => {
339
+ const textColor = shaka.text.Cue.defaultTextColor;
340
+ for (const [key, value] of Object.entries(textColor)) {
341
+ const cue = new shaka.text.Cue(0, 0, "");
342
+ cue.color = value;
343
+ styles.set(`.${key}`, cue);
344
+ }
345
+ const bgColor = shaka.text.Cue.defaultTextBackgroundColor;
346
+ for (const [key, value] of Object.entries(bgColor)) {
347
+ const cue = new shaka.text.Cue(0, 0, "");
348
+ cue.backgroundColor = value;
349
+ styles.set(`.${key}`, cue);
350
+ }
351
+ };
352
+ const parseTime = (text) => {
353
+ const results = Array.from(text.matchAll(/(?:(\d{1,}):)?(\d{2}):(\d{2})((\.(\d{1,3})))?/g))?.[0];
354
+ if (results == null) return null;
355
+ const hours = Number(results[1]) || 0;
356
+ const minutes = Number(results[2]);
357
+ const seconds = Number(results[3]);
358
+ const milliseconds = Number(results[6]) || 0;
359
+ if (minutes > 59 || seconds > 59) return null;
360
+ return milliseconds / 1e3 + seconds + minutes * 60 + hours * 3600;
361
+ };
362
+ const parseRegion = (block) => {
363
+ if (block[0].trim() !== "REGION") return [];
364
+ const region = new shaka.text.CueRegion();
365
+ block.slice(1).forEach((word) => {
366
+ let results = null;
367
+ if (results = /^id:(.*)$/.exec(word)) region.id = results[1];
368
+ else if (results = /^width:(\d{1,2}|100)%$/.exec(word)) region.width = Number(results[1]);
369
+ else if (results = /^lines:(\d+)$/.exec(word)) {
370
+ region.height = Number(results[1]);
371
+ region.heightUnits = shaka.text.CueRegion.units.LINES;
372
+ } else if (results = /^regionanchor:(\d{1,2}|100)%,(\d{1,2}|100)%$/.exec(word)) {
373
+ region.regionAnchorX = Number(results[1]);
374
+ region.regionAnchorY = Number(results[2]);
375
+ } else if (results = /^viewportanchor:(\d{1,2}|100)%,(\d{1,2}|100)%$/.exec(word)) {
376
+ region.viewportAnchorX = Number(results[1]);
377
+ region.viewportAnchorY = Number(results[2]);
378
+ } else if (results = /^scroll:up$/.exec(word)) region.scroll = shaka.text.CueRegion.scrollMode.UP;
379
+ else shaka.log.warning("VTT parser encountered an invalid VTTRegion setting: ", word, " The setting will be ignored.");
380
+ });
381
+ return [region];
382
+ };
383
+ /**
384
+ * @implements {shaka.extern.TextParser}
385
+ * @export
386
+ */
387
+ var VttTextParser = class VttTextParser {
388
+ /** Constructs a VTT parser. */
389
+ constructor() {
390
+ /** @private {boolean} */
391
+ this.sequenceMode_ = false;
392
+ /** @private {string} */
393
+ this.manifestType_ = shaka.media.ManifestParser.UNKNOWN;
394
+ }
395
+ /**
396
+ * @override
397
+ * @export
398
+ */
399
+ parseInit() {
400
+ goog$1.asserts.assert(false, "VTT does not have init segments");
401
+ }
402
+ /**
403
+ * @override
404
+ * @export
405
+ */
406
+ setSequenceMode(sequenceMode) {
407
+ this.sequenceMode_ = sequenceMode;
408
+ }
409
+ /**
410
+ * @override
411
+ * @export
412
+ */
413
+ setManifestType(manifestType) {
414
+ this.manifestType_ = manifestType;
415
+ }
416
+ /**
417
+ * @override
418
+ * @export
419
+ */
420
+ parseMedia(data, time) {
421
+ let str = shaka.util.StringUtils.fromUTF8(data);
422
+ str = str.replace(/\r\n|\r(?=[^\n]|$)/gm, "\n");
423
+ const blocks = str.split(/\n{2,}/m);
424
+ if (!/^WEBVTT($|[ \t\n])/m.test(blocks[0])) throw new shaka.util.Error(shaka.util.Error.Severity.CRITICAL, shaka.util.Error.Category.TEXT, shaka.util.Error.Code.INVALID_TEXT_HEADER);
425
+ let offset = time.vttOffset;
426
+ if (this.manifestType_ == shaka.media.ManifestParser.HLS) {
427
+ if (blocks[0].includes("X-TIMESTAMP-MAP")) offset = this.computeHlsOffset_(blocks[0], time);
428
+ else if (time.periodStart && time.vttOffset == time.periodStart) offset = 0;
429
+ }
430
+ const regions = [];
431
+ /** @type {!Map<string, !shaka.text.Cue>} */
432
+ const styles = /* @__PURE__ */ new Map();
433
+ addDefaultTextColor(styles);
434
+ const ret = [];
435
+ for (const block of blocks.slice(1)) {
436
+ const lines = block.split("\n");
437
+ VttTextParser.parseStyle_(lines, styles);
438
+ regions.push(...parseRegion(lines));
439
+ const cue = VttTextParser.parseCue_(lines, offset, regions, styles);
440
+ if (cue) ret.push(cue);
441
+ }
442
+ return ret;
443
+ }
444
+ /**
445
+ * @param {string} headerBlock Contains X-TIMESTAMP-MAP.
446
+ * @param {shaka.extern.TextParser.TimeContext} time
447
+ * @return {number}
448
+ * @private
449
+ */
450
+ computeHlsOffset_(headerBlock, time) {
451
+ const cueTimeMatch = headerBlock.match(/LOCAL:((?:(\d{1,}):)?(\d{2}):(\d{2})\.(\d{3}))/m);
452
+ const mpegTimeMatch = headerBlock.match(/MPEGTS:(\d+)/m);
453
+ if (!cueTimeMatch || !mpegTimeMatch) throw new shaka.util.Error(shaka.util.Error.Severity.CRITICAL, shaka.util.Error.Category.TEXT, shaka.util.Error.Code.INVALID_TEXT_HEADER);
454
+ const cueTime = parseTime(cueTimeMatch[1]);
455
+ if (cueTime == null) throw new shaka.util.Error(shaka.util.Error.Severity.CRITICAL, shaka.util.Error.Category.TEXT, shaka.util.Error.Code.INVALID_TEXT_HEADER);
456
+ let mpegTime = Number(mpegTimeMatch[1]);
457
+ const mpegTimescale = VttTextParser.MPEG_TIMESCALE_;
458
+ const rolloverSeconds = VttTextParser.TS_ROLLOVER_ / mpegTimescale;
459
+ let segmentStart = time.segmentStart - time.periodStart;
460
+ while (segmentStart >= rolloverSeconds) {
461
+ segmentStart -= rolloverSeconds;
462
+ mpegTime += VttTextParser.TS_ROLLOVER_;
463
+ }
464
+ return time.periodStart + mpegTime / mpegTimescale - cueTime;
465
+ }
466
+ /**
467
+ * Parses a style block into a Cue object.
468
+ *
469
+ * @param {!Array<string>} text
470
+ * @param {!Map<string, !shaka.text.Cue>} styles
471
+ * @private
472
+ */
473
+ static parseStyle_(text, styles) {
474
+ if (text.length == 1 && !text[0]) return;
475
+ if (/^NOTE($|[ \t])/.test(text[0])) return;
476
+ if (text[0] != "STYLE") return;
477
+ /** @type {!Array<!Array<string>>} */
478
+ const styleBlocks = [];
479
+ let lastBlockIndex = -1;
480
+ for (let i = 1; i < text.length; i++) {
481
+ if (text[i].includes("::cue")) {
482
+ styleBlocks.push([]);
483
+ lastBlockIndex = styleBlocks.length - 1;
484
+ }
485
+ if (lastBlockIndex == -1) continue;
486
+ styleBlocks[lastBlockIndex].push(text[i]);
487
+ if (text[i].includes("}")) lastBlockIndex = -1;
488
+ }
489
+ for (const styleBlock of styleBlocks) {
490
+ let styleSelector = "global";
491
+ const selector = styleBlock[0].match(/\((.*)\)/);
492
+ if (selector) styleSelector = selector.pop();
493
+ let propertyLines = styleBlock.slice(1, -1);
494
+ if (styleBlock[0].includes("}")) {
495
+ const payload = /\{(.*?)\}/.exec(styleBlock[0]);
496
+ if (payload) propertyLines = payload[1].split(";");
497
+ }
498
+ let cue = styles.get(styleSelector);
499
+ if (!cue) cue = new shaka.text.Cue(0, 0, "");
500
+ let validStyle = false;
501
+ for (let i = 0; i < propertyLines.length; i++) {
502
+ const lineParts = /^\s*([^:]+):\s*(.*)/.exec(propertyLines[i]);
503
+ if (lineParts) {
504
+ const name = lineParts[1].trim();
505
+ const value = lineParts[2].trim().replace(";", "");
506
+ switch (name) {
507
+ case "background-color":
508
+ case "background":
509
+ validStyle = true;
510
+ cue.backgroundColor = value;
511
+ break;
512
+ case "color":
513
+ validStyle = true;
514
+ cue.color = value;
515
+ break;
516
+ case "font-family":
517
+ validStyle = true;
518
+ cue.fontFamily = value;
519
+ break;
520
+ case "font-size":
521
+ validStyle = true;
522
+ cue.fontSize = value;
523
+ break;
524
+ case "font-weight":
525
+ if (parseInt(value, 10) >= 700 || value == "bold") {
526
+ validStyle = true;
527
+ cue.fontWeight = shaka.text.Cue.fontWeight.BOLD;
528
+ }
529
+ break;
530
+ case "font-style":
531
+ switch (value) {
532
+ case "normal":
533
+ validStyle = true;
534
+ cue.fontStyle = shaka.text.Cue.fontStyle.NORMAL;
535
+ break;
536
+ case "italic":
537
+ validStyle = true;
538
+ cue.fontStyle = shaka.text.Cue.fontStyle.ITALIC;
539
+ break;
540
+ case "oblique":
541
+ validStyle = true;
542
+ cue.fontStyle = shaka.text.Cue.fontStyle.OBLIQUE;
543
+ break;
544
+ }
545
+ break;
546
+ case "opacity":
547
+ validStyle = true;
548
+ cue.opacity = parseFloat(value);
549
+ break;
550
+ case "text-combine-upright":
551
+ validStyle = true;
552
+ cue.textCombineUpright = value;
553
+ break;
554
+ case "text-shadow":
555
+ validStyle = true;
556
+ cue.textShadow = value;
557
+ break;
558
+ case "white-space":
559
+ validStyle = true;
560
+ cue.wrapLine = value != "noWrap";
561
+ break;
562
+ default:
563
+ shaka.log.warning("VTT parser encountered an unsupported style: ", lineParts);
564
+ break;
565
+ }
566
+ }
567
+ }
568
+ if (validStyle) styles.set(styleSelector, cue);
569
+ }
570
+ }
571
+ /**
572
+ * Parses a text block into a Cue object.
573
+ *
574
+ * @param {!Array<string>} text
575
+ * @param {number} timeOffset
576
+ * @param {!Array<!shaka.text.CueRegion>} regions
577
+ * @param {!Map<string, !shaka.text.Cue>} styles
578
+ * @return {shaka.text.Cue}
579
+ * @private
580
+ */
581
+ static parseCue_(text, timeOffset, regions, styles) {
582
+ if (text.length == 1 && !text[0]) return null;
583
+ if (/^NOTE($|[ \t])/.test(text[0])) return null;
584
+ if (text[0] == "STYLE" || text[0] == "REGION") return null;
585
+ const skipIndex = text.findIndex((line) => /^#/.test(line.trim()));
586
+ if (skipIndex > 0) text = text.slice(skipIndex);
587
+ if (text.length < 2) return;
588
+ let id = null;
589
+ if (!text[0].includes("-->")) {
590
+ id = text[0];
591
+ text.splice(0, 1);
592
+ }
593
+ let [start, end] = text[0].split("-->").map((part) => parseTime(part.trim()));
594
+ if (start == null || end == null) {
595
+ shaka.log.alwaysWarn("Failed to parse VTT time code. Cue skipped:", id, text);
596
+ return null;
597
+ }
598
+ start += timeOffset;
599
+ end += timeOffset;
600
+ const payload = text.slice(1).join("\n").trim();
601
+ let cue = null;
602
+ if (styles.has("global")) {
603
+ cue = styles.get("global").clone();
604
+ cue.startTime = start;
605
+ cue.endTime = end;
606
+ cue.payload = payload;
607
+ } else cue = new shaka.text.Cue(start, end, payload);
608
+ text[0].split(/\s+/g).slice(3).forEach((word) => {
609
+ if (!word.trim()) return;
610
+ if (!VttTextParser.parseCueSetting(cue, word, regions)) shaka.log.warning("VTT parser encountered an invalid VTT setting: ", word, " The setting will be ignored.");
611
+ });
612
+ shaka.text.Cue.parseCuePayload(cue, styles);
613
+ if (id != null) cue.id = id;
614
+ return cue;
615
+ }
616
+ /**
617
+ * Parses a WebVTT setting from the given word.
618
+ *
619
+ * @param {!shaka.text.Cue} cue
620
+ * @param {string} word
621
+ * @param {!Array<!shaka.text.CueRegion>} regions
622
+ * @return {boolean} True on success.
623
+ */
624
+ static parseCueSetting(cue, word, regions) {
625
+ let results = null;
626
+ if (results = /^align:(start|middle|center|end|left|right)$/.exec(word)) VttTextParser.setTextAlign_(cue, results[1]);
627
+ else if (results = /^vertical:(lr|rl)$/.exec(word)) VttTextParser.setVerticalWritingMode_(cue, results[1]);
628
+ else if (results = /^size:([\d.]+)%$/.exec(word)) cue.size = Number(results[1]);
629
+ else if (results = /^position:([\d.]+)%(?:,(line-left|line-right|middle|center|start|end|auto))?$/.exec(word)) {
630
+ cue.position = Number(results[1]);
631
+ if (results[2]) VttTextParser.setPositionAlign_(cue, results[2]);
632
+ } else if (results = /^region:(.*)$/.exec(word)) {
633
+ const region = VttTextParser.getRegionById_(regions, results[1]);
634
+ if (region) cue.region = region;
635
+ } else return VttTextParser.parsedLineValueAndInterpretation_(cue, word);
636
+ return true;
637
+ }
638
+ /**
639
+ *
640
+ * @param {!Array<!shaka.text.CueRegion>} regions
641
+ * @param {string} id
642
+ * @return {?shaka.text.CueRegion}
643
+ * @private
644
+ */
645
+ static getRegionById_(regions, id) {
646
+ const regionsWithId = regions.filter((region) => region.id == id);
647
+ if (!regionsWithId.length) {
648
+ shaka.log.warning("VTT parser could not find a region with id: ", id, " The region will be ignored.");
649
+ return null;
650
+ }
651
+ goog$1.asserts.assert(regionsWithId.length == 1, "VTTRegion ids should be unique!");
652
+ return regionsWithId[0];
653
+ }
654
+ /**
655
+ * @param {!shaka.text.Cue} cue
656
+ * @param {string} align
657
+ * @private
658
+ */
659
+ static setTextAlign_(cue, align) {
660
+ const Cue = shaka.text.Cue;
661
+ if (align == "middle") cue.textAlign = Cue.textAlign.CENTER;
662
+ else {
663
+ goog$1.asserts.assert(align.toUpperCase() in Cue.textAlign, `${align.toUpperCase()} Should be in Cue.textAlign values!`);
664
+ cue.textAlign = Cue.textAlign[align.toUpperCase()];
665
+ }
666
+ }
667
+ /**
668
+ * @param {!shaka.text.Cue} cue
669
+ * @param {string} align
670
+ * @private
671
+ */
672
+ static setPositionAlign_(cue, align) {
673
+ const Cue = shaka.text.Cue;
674
+ if (align == "line-left" || align == "start") cue.positionAlign = Cue.positionAlign.LEFT;
675
+ else if (align == "line-right" || align == "end") cue.positionAlign = Cue.positionAlign.RIGHT;
676
+ else if (align == "center" || align == "middle") cue.positionAlign = Cue.positionAlign.CENTER;
677
+ else cue.positionAlign = Cue.positionAlign.AUTO;
678
+ }
679
+ /**
680
+ * @param {!shaka.text.Cue} cue
681
+ * @param {string} value
682
+ * @private
683
+ */
684
+ static setVerticalWritingMode_(cue, value) {
685
+ const Cue = shaka.text.Cue;
686
+ if (value == "lr") cue.writingMode = Cue.writingMode.VERTICAL_LEFT_TO_RIGHT;
687
+ else cue.writingMode = Cue.writingMode.VERTICAL_RIGHT_TO_LEFT;
688
+ }
689
+ /**
690
+ * @param {!shaka.text.Cue} cue
691
+ * @param {string} word
692
+ * @return {boolean}
693
+ * @private
694
+ */
695
+ static parsedLineValueAndInterpretation_(cue, word) {
696
+ const Cue = shaka.text.Cue;
697
+ let results = null;
698
+ if (results = /^line:([\d.]+)%(?:,(start|end|center))?$/.exec(word)) {
699
+ cue.lineInterpretation = Cue.lineInterpretation.PERCENTAGE;
700
+ cue.line = Number(results[1]);
701
+ if (results[2]) {
702
+ goog$1.asserts.assert(results[2].toUpperCase() in Cue.lineAlign, `${results[2].toUpperCase()} Should be in Cue.lineAlign values!`);
703
+ cue.lineAlign = Cue.lineAlign[results[2].toUpperCase()];
704
+ }
705
+ } else if (results = /^line:(-?\d+)(?:,(start|end|center))?$/.exec(word)) {
706
+ cue.lineInterpretation = Cue.lineInterpretation.LINE_NUMBER;
707
+ cue.line = Number(results[1]);
708
+ if (results[2]) {
709
+ goog$1.asserts.assert(results[2].toUpperCase() in Cue.lineAlign, `${results[2].toUpperCase()} Should be in Cue.lineAlign values!`);
710
+ cue.lineAlign = Cue.lineAlign[results[2].toUpperCase()];
711
+ }
712
+ } else return false;
713
+ return true;
714
+ }
715
+ };
716
+ /**
717
+ * @const {number}
718
+ * @private
719
+ */
720
+ VttTextParser.MPEG_TIMESCALE_ = 9e4;
721
+ /**
722
+ * At this value, timestamps roll over in TS content.
723
+ * @const {number}
724
+ * @private
725
+ */
726
+ VttTextParser.TS_ROLLOVER_ = 8589934592;
727
+ VttTextParser.register = (shakaNameSpace) => {
728
+ shakaNameSpace.text.TextEngine.registerParser("text/vtt", () => new VttTextParser());
729
+ shakaNameSpace.text.TextEngine.registerParser("text/vtt; codecs=\"vtt\"", () => new VttTextParser());
730
+ shakaNameSpace.text.TextEngine.registerParser("text/vtt; codecs=\"wvtt\"", () => new VttTextParser());
731
+ };
732
+ var VttTextParser_default = VttTextParser;
733
+
734
+ //#endregion
735
+ //#region src/plugins/shaka/UITextDisplayer.js
736
+ /*! @license
737
+ * Shaka Player
738
+ * Copyright 2016 Google LLC
739
+ * SPDX-License-Identifier: Apache-2.0
740
+ */
741
+ const shakaLog = {
742
+ debug: (...messages) => console.warn(...messages),
743
+ error: (...messages) => console.warn(...messages),
744
+ info: (...messages) => console.warn(...messages),
745
+ warning: (...messages) => console.warn(...messages),
746
+ alwaysWarn: (...messages) => console.warn(...messages)
747
+ };
748
+ const goog = { asserts: { assert: (result, message) => {
749
+ result || console.warn(message);
750
+ } } };
751
+ /**
752
+ * Returns info about provided lengthValue
753
+ * @example 100px => { value: 100, unit: 'px' }
754
+ * @param {?string} lengthValue
755
+ *
756
+ * @return {?{ value: number, unit: string }}
757
+ * @private
758
+ */
759
+ const getLengthValueInfo_ = (lengthValue) => {
760
+ const matches = /(\d*\.?\d+)([a-z]+|%+)/.exec(lengthValue);
761
+ if (!matches) return null;
762
+ return {
763
+ value: Number(matches[1]),
764
+ unit: matches[2]
765
+ };
766
+ };
767
+ /**
768
+ * Returns computed absolute length value in pixels based on cell
769
+ * and a video container size
770
+ * @param {number} value
771
+ * @param {!shaka.text.Cue} cue
772
+ * @param {HTMLElement} videoContainer
773
+ * @return {string}
774
+ *
775
+ * @private
776
+ */
777
+ const getAbsoluteLengthInPixels_ = (value, cue, videoContainer) => {
778
+ return `${videoContainer.clientHeight * value / cue.cellResolution.rows}px`;
779
+ };
780
+ /**
781
+ * Inherits a property from the parent Cue elements. If the value is falsy,
782
+ * it is assumed to be inherited from the parent. This returns null if the
783
+ * value isn't found.
784
+ *
785
+ * @param {!Array<!shaka.text.Cue>} parents
786
+ * @param {function(!shaka.text.Cue):?T} cb
787
+ * @return {?T}
788
+ * @template T
789
+ * @private
790
+ */
791
+ const inheritProperty_ = (parents, cb) => {
792
+ for (let i = parents.length - 1; i >= 0; i--) {
793
+ const val = cb(parents[i]);
794
+ if (val || val === 0) return val;
795
+ }
796
+ return null;
797
+ };
798
+ /**
799
+ * Converts length value to an absolute value in pixels.
800
+ * If lengthValue is already an absolute value it will not
801
+ * be modified. Relative lengthValue will be converted to an
802
+ * absolute value in pixels based on Computed Cell Size
803
+ *
804
+ * @param {string} lengthValue
805
+ * @param {!shaka.text.Cue} cue
806
+ * @param {HTMLElement} videoContainer
807
+ * @return {string}
808
+ * @private
809
+ */
810
+ const convertLengthValue_ = (lengthValue, cue, videoContainer) => {
811
+ const lengthValueInfo = getLengthValueInfo_(lengthValue);
812
+ if (!lengthValueInfo) return lengthValue;
813
+ const { unit, value } = lengthValueInfo;
814
+ switch (unit) {
815
+ case "%": return getAbsoluteLengthInPixels_(value / 100, cue, videoContainer);
816
+ case "c": return getAbsoluteLengthInPixels_(value, cue, videoContainer);
817
+ default: return lengthValue;
818
+ }
819
+ };
820
+ const removeDuplicates = (cues) => {
821
+ const uniqueCues = [];
822
+ for (const cue of cues) if (!uniqueCues.some((existingCue) => shaka.text.Cue.equal(cue, existingCue))) uniqueCues.push(cue);
823
+ return uniqueCues;
824
+ };
825
+ /**
826
+ * The text displayer plugin for the Shaka Player UI. Can also be used directly
827
+ * by providing an appropriate container element.
828
+ *
829
+ * @implements {shaka.extern.TextDisplayer}
830
+ * @final
831
+ * @export
832
+ */
833
+ var UITextDisplayer = class {
834
+ /**
835
+ * Constructor.
836
+ * @param {HTMLMediaElement} video
837
+ * @param {HTMLElement} videoContainer
838
+ */
839
+ constructor(video, videoContainer) {
840
+ window.shaka.log = shakaLog;
841
+ goog.asserts.assert(videoContainer, "videoContainer should be valid.");
842
+ if (!document.fullscreenEnabled) shaka.log.alwaysWarn("Using UITextDisplayer in a browser without Fullscreen API support causes subtitles to not be rendered in fullscreen");
843
+ /** @private {boolean} */
844
+ this.isTextVisible_ = false;
845
+ /** @private {!Array<!shaka.text.Cue>} */
846
+ this.cues_ = [];
847
+ /** @private {HTMLMediaElement} */
848
+ this.video_ = video;
849
+ /** @private {HTMLElement} */
850
+ this.videoContainer_ = videoContainer;
851
+ /** @private {?number} */
852
+ this.aspectRatio_ = null;
853
+ /** @private {?shaka.extern.TextDisplayerConfiguration} */
854
+ this.config_ = null;
855
+ /** @type {HTMLElement} */
856
+ this.textContainer_ = document.createElement("div");
857
+ this.textContainer_.classList.add("shaka-text-container");
858
+ this.textContainer_.style.textAlign = "center";
859
+ this.textContainer_.style.display = "flex";
860
+ this.textContainer_.style.flexDirection = "column";
861
+ this.textContainer_.style.alignItems = "center";
862
+ this.textContainer_.style.justifyContent = "flex-end";
863
+ this.videoContainer_.appendChild(this.textContainer_);
864
+ /** @private {shaka.util.Timer} */
865
+ this.captionsTimer_ = new shaka.util.Timer(() => {
866
+ if (!this.video_.paused) this.updateCaptions_();
867
+ });
868
+ this.configureCaptionsTimer_();
869
+ /**
870
+ * Maps cues to cue elements. Specifically points out the wrapper element of
871
+ * the cue (e.g. the HTML element to put nested cues inside).
872
+ * @private {Map<!shaka.text.Cue, !{
873
+ * cueElement: !HTMLElement,
874
+ * regionElement: HTMLElement,
875
+ * wrapper: !HTMLElement
876
+ * }>}
877
+ */
878
+ this.currentCuesMap_ = /* @__PURE__ */ new Map();
879
+ /** @private {shaka.util.EventManager} */
880
+ this.eventManager_ = new shaka.util.EventManager();
881
+ this.eventManager_.listen(document, "fullscreenchange", () => {
882
+ this.updateCaptions_(true);
883
+ });
884
+ this.eventManager_.listen(this.video_, "seeking", () => {
885
+ this.updateCaptions_(true);
886
+ });
887
+ this.eventManager_.listen(this.video_, "ratechange", () => {
888
+ this.configureCaptionsTimer_();
889
+ });
890
+ this.eventManager_.listen(this.video_, "resize", () => {
891
+ const element = this.video_;
892
+ const width = element.videoWidth;
893
+ const height = element.videoHeight;
894
+ if (width && height) this.aspectRatio_ = width / height;
895
+ else this.aspectRatio_ = null;
896
+ });
897
+ /** @private {ResizeObserver} */
898
+ this.resizeObserver_ = null;
899
+ if ("ResizeObserver" in window) {
900
+ this.resizeObserver_ = new ResizeObserver(() => {
901
+ this.updateCaptions_(true);
902
+ });
903
+ this.resizeObserver_.observe(this.textContainer_);
904
+ }
905
+ /** @private {Map<string, !HTMLElement>} */
906
+ this.regionElements_ = /* @__PURE__ */ new Map();
907
+ }
908
+ /**
909
+ * @override
910
+ * @export
911
+ */
912
+ configure(config) {
913
+ this.config_ = config;
914
+ this.configureCaptionsTimer_();
915
+ }
916
+ /**
917
+ * @override
918
+ * @export
919
+ */
920
+ append(cues) {
921
+ const cuesList = [...this.cues_];
922
+ for (const cue of removeDuplicates(cues)) if (!cuesList.some((cueInList) => shaka.text.Cue.equal(cueInList, cue))) this.cues_.push(cue);
923
+ this.updateCaptions_();
924
+ }
925
+ /**
926
+ * @override
927
+ * @export
928
+ */
929
+ destroy() {
930
+ if (!this.textContainer_) return Promise.resolve();
931
+ this.videoContainer_.removeChild(this.textContainer_);
932
+ this.textContainer_ = null;
933
+ this.isTextVisible_ = false;
934
+ this.cues_ = [];
935
+ if (this.captionsTimer_) {
936
+ this.captionsTimer_.stop();
937
+ this.captionsTimer_ = null;
938
+ }
939
+ this.currentCuesMap_.clear();
940
+ if (this.eventManager_) {
941
+ this.eventManager_.release();
942
+ this.eventManager_ = null;
943
+ }
944
+ if (this.resizeObserver_) {
945
+ this.resizeObserver_.disconnect();
946
+ this.resizeObserver_ = null;
947
+ }
948
+ return Promise.resolve();
949
+ }
950
+ /**
951
+ * @override
952
+ * @export
953
+ */
954
+ remove(start, end) {
955
+ if (!this.textContainer_) return false;
956
+ const oldNumCues = this.cues_.length;
957
+ this.cues_ = this.cues_.filter((cue) => cue.startTime < start || cue.endTime >= end);
958
+ const forceUpdate = oldNumCues > this.cues_.length;
959
+ this.updateCaptions_(forceUpdate);
960
+ return true;
961
+ }
962
+ /**
963
+ * @override
964
+ * @export
965
+ */
966
+ isTextVisible() {
967
+ return this.isTextVisible_;
968
+ }
969
+ /**
970
+ * @override
971
+ * @export
972
+ */
973
+ setTextVisibility(on$1) {
974
+ this.isTextVisible_ = on$1;
975
+ this.updateCaptions_(true);
976
+ }
977
+ /**
978
+ * @override
979
+ * @export
980
+ */
981
+ setTextLanguage(language) {
982
+ if (language && language != "und") this.textContainer_.setAttribute("lang", language);
983
+ else this.textContainer_.setAttribute("lang", "");
984
+ }
985
+ /**
986
+ * @override
987
+ * @export
988
+ */
989
+ enableTextDisplayer() {}
990
+ /**
991
+ * @private
992
+ */
993
+ configureCaptionsTimer_() {
994
+ if (this.captionsTimer_) {
995
+ const updateTime = (this.config_ ? this.config_.captionsUpdatePeriod : .25) / Math.max(1, Math.abs(this.video_.playbackRate));
996
+ this.captionsTimer_.tickEvery(updateTime);
997
+ }
998
+ }
999
+ /**
1000
+ * @private
1001
+ */
1002
+ isElementUnderTextContainer_(elemToCheck) {
1003
+ while (elemToCheck != null) {
1004
+ if (elemToCheck == this.textContainer_) return true;
1005
+ elemToCheck = elemToCheck.parentElement;
1006
+ }
1007
+ return false;
1008
+ }
1009
+ /**
1010
+ * @param {!Array<!shaka.text.Cue>} cues
1011
+ * @param {!HTMLElement} container
1012
+ * @param {number} currentTime
1013
+ * @param {!Array<!shaka.text.Cue>} parents
1014
+ * @private
1015
+ */
1016
+ updateCuesRecursive_(cues, container, currentTime, parents) {
1017
+ let updateDOM = false;
1018
+ /**
1019
+ * The elements to remove from the DOM.
1020
+ * Some of these elements may be added back again, if their corresponding
1021
+ * cue is in toPlant.
1022
+ * These elements are only removed if updateDOM is true.
1023
+ * @type {!Array<!HTMLElement>}
1024
+ */
1025
+ const toUproot = [];
1026
+ /**
1027
+ * The cues whose corresponding elements should be in the DOM.
1028
+ * Some of these might be new, some might have been displayed beforehand.
1029
+ * These will only be added if updateDOM is true.
1030
+ * @type {!Array<!shaka.text.Cue>}
1031
+ */
1032
+ const toPlant = [];
1033
+ for (const cue of cues) {
1034
+ parents.push(cue);
1035
+ let cueRegistry = this.currentCuesMap_.get(cue);
1036
+ const shouldBeDisplayed = cue.startTime <= currentTime && cue.endTime > currentTime;
1037
+ let wrapper = cueRegistry ? cueRegistry.wrapper : null;
1038
+ if (cueRegistry) {
1039
+ toUproot.push(cueRegistry.cueElement);
1040
+ if (cueRegistry.regionElement) toUproot.push(cueRegistry.regionElement);
1041
+ if (!shouldBeDisplayed) {
1042
+ updateDOM = true;
1043
+ this.currentCuesMap_.delete(cue);
1044
+ cueRegistry = null;
1045
+ }
1046
+ }
1047
+ if (shouldBeDisplayed) {
1048
+ toPlant.push(cue);
1049
+ if (!cueRegistry) {
1050
+ this.createCue_(cue, parents);
1051
+ cueRegistry = this.currentCuesMap_.get(cue);
1052
+ wrapper = cueRegistry.wrapper;
1053
+ updateDOM = true;
1054
+ } else if (!this.isElementUnderTextContainer_(wrapper)) updateDOM = true;
1055
+ }
1056
+ if (cue.nestedCues.length > 0 && wrapper) this.updateCuesRecursive_(cue.nestedCues, wrapper, currentTime, parents);
1057
+ const topCue = parents.pop();
1058
+ goog.asserts.assert(topCue == cue, "Parent cues should be kept in order");
1059
+ }
1060
+ if (updateDOM) {
1061
+ for (const element of toUproot) if (element.parentElement) element.parentElement.removeChild(element);
1062
+ toPlant.sort((a, b) => {
1063
+ if (a.startTime != b.startTime) return a.startTime - b.startTime;
1064
+ return a.endTime - b.endTime;
1065
+ });
1066
+ for (const cue of toPlant) {
1067
+ const cueRegistry = this.currentCuesMap_.get(cue);
1068
+ goog.asserts.assert(cueRegistry, "cueRegistry should exist.");
1069
+ if (cueRegistry.regionElement) {
1070
+ if (cueRegistry.regionElement.contains(container)) cueRegistry.regionElement.removeChild(container);
1071
+ container.appendChild(cueRegistry.regionElement);
1072
+ cueRegistry.regionElement.appendChild(cueRegistry.cueElement);
1073
+ } else container.appendChild(cueRegistry.cueElement);
1074
+ }
1075
+ }
1076
+ }
1077
+ /**
1078
+ * Display the current captions.
1079
+ * @param {boolean=} forceUpdate
1080
+ * @private
1081
+ */
1082
+ updateCaptions_(forceUpdate = false) {
1083
+ if (!this.textContainer_) return;
1084
+ const { currentTime } = this.video_;
1085
+ if (!this.isTextVisible_ || forceUpdate) {
1086
+ for (const regionElement of this.regionElements_.values()) regionElement.replaceChildren();
1087
+ this.textContainer_.replaceChildren();
1088
+ this.currentCuesMap_.clear();
1089
+ this.regionElements_.clear();
1090
+ }
1091
+ if (this.isTextVisible_) {
1092
+ const previousCuesMap = /* @__PURE__ */ new Map();
1093
+ if (goog.DEBUG) for (const cue of this.currentCuesMap_.keys()) previousCuesMap.set(cue, this.currentCuesMap_.get(cue));
1094
+ this.updateCuesRecursive_(this.cues_, this.textContainer_, currentTime, []);
1095
+ if (goog.DEBUG) {
1096
+ for (const cue of previousCuesMap.keys()) if (!this.currentCuesMap_.has(cue)) {
1097
+ const { cueElement } = previousCuesMap.get(cue);
1098
+ goog.asserts.assert(!cueElement.parentNode, "Cue was not properly removed!");
1099
+ }
1100
+ }
1101
+ }
1102
+ }
1103
+ /**
1104
+ * Compute a unique internal id:
1105
+ * Regions can reuse the id but have different dimensions, we need to
1106
+ * consider those differences
1107
+ * @param {shaka.text.CueRegion} region
1108
+ * @private
1109
+ */
1110
+ generateRegionId_(region) {
1111
+ const percentageUnit = shaka.text.CueRegion.units.PERCENTAGE;
1112
+ const heightUnit = region.heightUnits == percentageUnit ? "%" : "px";
1113
+ const viewportAnchorUnit = region.viewportAnchorUnits == percentageUnit ? "%" : "px";
1114
+ return `${region.id}_${region.width}x${region.height}${heightUnit}-${region.viewportAnchorX}x${region.viewportAnchorY}${viewportAnchorUnit}`;
1115
+ }
1116
+ /**
1117
+ * Get or create a region element corresponding to the cue region. These are
1118
+ * cached by ID.
1119
+ *
1120
+ * @param {!shaka.text.Cue} cue
1121
+ * @return {!HTMLElement}
1122
+ * @private
1123
+ */
1124
+ getRegionElement_(cue) {
1125
+ const { region } = cue;
1126
+ const lineWidthMultiple = this.aspectRatio_ === 4 / 3 ? 2.5 : 1.9;
1127
+ const lineHeightMultiple = 5.33;
1128
+ const regionId = this.generateRegionId_(region);
1129
+ if (this.regionElements_.has(regionId)) return this.regionElements_.get(regionId);
1130
+ const regionElement = document.createElement("span");
1131
+ const linesUnit = shaka.text.CueRegion.units.LINES;
1132
+ const percentageUnit = shaka.text.CueRegion.units.PERCENTAGE;
1133
+ const pixelUnit = shaka.text.CueRegion.units.PX;
1134
+ let heightUnit = region.heightUnits == percentageUnit ? "%" : "px";
1135
+ let widthUnit = region.widthUnits == percentageUnit ? "%" : "px";
1136
+ const viewportAnchorUnit = region.viewportAnchorUnits == percentageUnit ? "%" : "px";
1137
+ regionElement.id = `shaka-text-region---${regionId}`;
1138
+ regionElement.classList.add("shaka-text-region");
1139
+ regionElement.style.position = "absolute";
1140
+ let regionHeight = region.height;
1141
+ let regionWidth = region.width;
1142
+ if (region.heightUnits === linesUnit) {
1143
+ regionHeight = region.height * lineHeightMultiple;
1144
+ heightUnit = "%";
1145
+ }
1146
+ if (region.widthUnits === linesUnit) {
1147
+ regionWidth = region.width * lineWidthMultiple;
1148
+ widthUnit = "%";
1149
+ }
1150
+ regionElement.style.height = regionHeight + heightUnit;
1151
+ regionElement.style.width = regionWidth + widthUnit;
1152
+ if (region.viewportAnchorUnits === linesUnit) {
1153
+ let top = region.viewportAnchorY / 75 * 100;
1154
+ const windowWidth = this.aspectRatio_ === 4 / 3 ? 160 : 210;
1155
+ let left = region.viewportAnchorX / windowWidth * 100;
1156
+ top -= region.regionAnchorY * regionHeight / 100;
1157
+ left -= region.regionAnchorX * regionWidth / 100;
1158
+ regionElement.style.top = `${top}%`;
1159
+ regionElement.style.left = `${left}%`;
1160
+ } else {
1161
+ regionElement.style.top = region.viewportAnchorY - region.regionAnchorY * regionHeight / 100 + viewportAnchorUnit;
1162
+ regionElement.style.left = region.viewportAnchorX - region.regionAnchorX * regionWidth / 100 + viewportAnchorUnit;
1163
+ }
1164
+ if (region.heightUnits !== pixelUnit && region.widthUnits !== pixelUnit && region.viewportAnchorUnits !== pixelUnit) {
1165
+ const top = parseInt(regionElement.style.top.slice(0, -1), 10) || 0;
1166
+ const left = parseInt(regionElement.style.left.slice(0, -1), 10) || 0;
1167
+ const height = parseInt(regionElement.style.height.slice(0, -1), 10) || 0;
1168
+ const width = parseInt(regionElement.style.width.slice(0, -1), 10) || 0;
1169
+ const realTop = Math.max(0, Math.min(100 - height, top));
1170
+ const realLeft = Math.max(0, Math.min(100 - width, left));
1171
+ regionElement.style.top = `${realTop}%`;
1172
+ regionElement.style.left = `${realLeft}%`;
1173
+ }
1174
+ regionElement.style.display = "flex";
1175
+ regionElement.style.flexDirection = "column";
1176
+ regionElement.style.alignItems = "center";
1177
+ if (cue.displayAlign == shaka.text.Cue.displayAlign.BEFORE) regionElement.style.justifyContent = "flex-start";
1178
+ else if (cue.displayAlign == shaka.text.Cue.displayAlign.CENTER) regionElement.style.justifyContent = "center";
1179
+ else regionElement.style.justifyContent = "flex-end";
1180
+ this.regionElements_.set(regionId, regionElement);
1181
+ return regionElement;
1182
+ }
1183
+ /**
1184
+ * Creates the object for a cue.
1185
+ *
1186
+ * @param {!shaka.text.Cue} cue
1187
+ * @param {!Array<!shaka.text.Cue>} parents
1188
+ * @private
1189
+ */
1190
+ createCue_(cue, parents) {
1191
+ const isNested = parents.length > 1;
1192
+ let type = isNested ? "span" : "div";
1193
+ if (cue.lineBreak) type = "br";
1194
+ if (cue.rubyTag) type = cue.rubyTag;
1195
+ const needWrapper = !isNested && cue.nestedCues.length > 0;
1196
+ const cueElement = document.createElement(type);
1197
+ if (type != "br") {
1198
+ this.setCaptionStyles_(cueElement, cue, parents, needWrapper);
1199
+ if (!cue.line) cueElement.classList.add(`shaka-cue-${cue.writingMode}`);
1200
+ }
1201
+ let regionElement = null;
1202
+ if (cue.region && cue.region.id) regionElement = this.getRegionElement_(cue);
1203
+ let wrapper = cueElement;
1204
+ if (needWrapper) {
1205
+ wrapper = document.createElement("span");
1206
+ wrapper.classList.add("shaka-text-wrapper");
1207
+ wrapper.style.backgroundColor = cue.backgroundColor;
1208
+ wrapper.style.lineHeight = "normal";
1209
+ cueElement.appendChild(wrapper);
1210
+ }
1211
+ this.currentCuesMap_.set(cue, {
1212
+ cueElement,
1213
+ wrapper,
1214
+ regionElement
1215
+ });
1216
+ }
1217
+ /**
1218
+ * Compute cue position alignment
1219
+ * See https://www.w3.org/TR/webvtt1/#webvtt-cue-position-alignment
1220
+ *
1221
+ * @param {!shaka.text.Cue} cue
1222
+ * @private
1223
+ */
1224
+ computeCuePositionAlignment_(cue) {
1225
+ const { Cue } = shaka.text;
1226
+ const { direction, positionAlign, textAlign } = cue;
1227
+ if (positionAlign !== Cue.positionAlign.AUTO) return positionAlign;
1228
+ if (textAlign === Cue.textAlign.LEFT || textAlign === Cue.textAlign.START && direction === Cue.direction.HORIZONTAL_LEFT_TO_RIGHT || textAlign === Cue.textAlign.END && direction === Cue.direction.HORIZONTAL_RIGHT_TO_LEFT) return Cue.positionAlign.LEFT;
1229
+ if (textAlign === Cue.textAlign.RIGHT || textAlign === Cue.textAlign.START && direction === Cue.direction.HORIZONTAL_RIGHT_TO_LEFT || textAlign === Cue.textAlign.END && direction === Cue.direction.HORIZONTAL_LEFT_TO_RIGHT) return Cue.positionAlign.RIGHT;
1230
+ return Cue.positionAlign.CENTER;
1231
+ }
1232
+ /**
1233
+ * @param {!HTMLElement} cueElement
1234
+ * @param {!shaka.text.Cue} cue
1235
+ * @param {!Array<!shaka.text.Cue>} parents
1236
+ * @param {boolean} hasWrapper
1237
+ * @private
1238
+ */
1239
+ setCaptionStyles_(cueElement, cue, parents, hasWrapper) {
1240
+ const { Cue } = shaka.text;
1241
+ const inherit = (cb) => inheritProperty_(parents, cb);
1242
+ const { style } = cueElement;
1243
+ const isLeaf = cue.nestedCues.length == 0;
1244
+ const isNested = parents.length > 1;
1245
+ style.whiteSpace = "pre-wrap";
1246
+ const text = cue.payload.replace(/\s+$/g, (match) => {
1247
+ return "\xA0".repeat(match.length);
1248
+ });
1249
+ style.webkitTextStrokeColor = cue.textStrokeColor;
1250
+ style.webkitTextStrokeWidth = cue.textStrokeWidth;
1251
+ style.color = cue.color;
1252
+ style.direction = cue.direction;
1253
+ style.opacity = cue.opacity;
1254
+ style.paddingLeft = convertLengthValue_(cue.linePadding, cue, this.videoContainer_);
1255
+ style.paddingRight = convertLengthValue_(cue.linePadding, cue, this.videoContainer_);
1256
+ style.textCombineUpright = cue.textCombineUpright;
1257
+ style.textShadow = cue.textShadow;
1258
+ if (cue.backgroundImage) {
1259
+ style.backgroundImage = `url('${cue.backgroundImage}')`;
1260
+ style.backgroundRepeat = "no-repeat";
1261
+ style.backgroundSize = "contain";
1262
+ style.backgroundPosition = "center";
1263
+ if (cue.backgroundColor) style.backgroundColor = cue.backgroundColor;
1264
+ style.width = "100%";
1265
+ style.height = "100%";
1266
+ } else {
1267
+ let elem;
1268
+ if (cue.nestedCues.length) elem = cueElement;
1269
+ else {
1270
+ elem = document.createElement("span");
1271
+ cueElement.appendChild(elem);
1272
+ }
1273
+ if (cue.border) elem.style.border = cue.border;
1274
+ if (!hasWrapper) {
1275
+ const bgColor = inherit((c) => c.backgroundColor);
1276
+ if (bgColor) elem.style.backgroundColor = bgColor;
1277
+ else if (text) elem.style.backgroundColor = "rgba(0, 0, 0, 0)";
1278
+ }
1279
+ if (text) elem.textContent = text;
1280
+ }
1281
+ if (/ruby|rt/i.test(cueElement.tagName)) {} else if (isNested && !parents[parents.length - 1].isContainer) style.display = "inline";
1282
+ else {
1283
+ style.display = "flex";
1284
+ style.flexDirection = "column";
1285
+ style.alignItems = "center";
1286
+ if (cue.textAlign == Cue.textAlign.LEFT || cue.textAlign == Cue.textAlign.START) {
1287
+ style.width = "100%";
1288
+ style.alignItems = "start";
1289
+ } else if (cue.textAlign == Cue.textAlign.RIGHT || cue.textAlign == Cue.textAlign.END) {
1290
+ style.width = "100%";
1291
+ style.alignItems = "end";
1292
+ }
1293
+ if (/vertical/.test(cue.writingMode)) style.justifyContent = "flex-start";
1294
+ else if (cue.displayAlign == Cue.displayAlign.BEFORE) style.justifyContent = "flex-start";
1295
+ else if (cue.displayAlign == Cue.displayAlign.CENTER) style.justifyContent = "center";
1296
+ else style.justifyContent = "flex-end";
1297
+ }
1298
+ if (!isLeaf) style.margin = "0";
1299
+ style.fontFamily = cue.fontFamily;
1300
+ style.fontWeight = cue.fontWeight.toString();
1301
+ style.fontStyle = cue.fontStyle;
1302
+ style.letterSpacing = cue.letterSpacing;
1303
+ style.fontSize = convertLengthValue_(cue.fontSize, cue, this.videoContainer_);
1304
+ let line = !isNested && /vertical/.test(cue.writingMode) && cue.line == null ? 0 : cue.line;
1305
+ if (line != null) {
1306
+ let { lineInterpretation } = cue;
1307
+ if (lineInterpretation == Cue.lineInterpretation.LINE_NUMBER) {
1308
+ lineInterpretation = Cue.lineInterpretation.PERCENTAGE;
1309
+ let maxLines = 16;
1310
+ if (this.aspectRatio_ && this.aspectRatio_ < 1) maxLines = 32;
1311
+ if (line < 0) line = 100 + line / maxLines * 100;
1312
+ else line = line / maxLines * 100;
1313
+ }
1314
+ if (lineInterpretation == Cue.lineInterpretation.PERCENTAGE) {
1315
+ style.position = "absolute";
1316
+ if (cue.writingMode == Cue.writingMode.HORIZONTAL_TOP_TO_BOTTOM) {
1317
+ style.width = "100%";
1318
+ if (cue.lineAlign == Cue.lineAlign.START) style.top = `${line}%`;
1319
+ else if (cue.lineAlign == Cue.lineAlign.END) style.bottom = `${100 - line}%`;
1320
+ } else if (cue.writingMode == Cue.writingMode.VERTICAL_LEFT_TO_RIGHT) {
1321
+ style.height = "100%";
1322
+ if (cue.lineAlign == Cue.lineAlign.START) style.left = `${3 + line}%`;
1323
+ else if (cue.lineAlign == Cue.lineAlign.END) style.right = `${97 - line}%`;
1324
+ } else {
1325
+ style.height = "100%";
1326
+ if (cue.lineAlign == Cue.lineAlign.START) style.right = `${3 + line}%`;
1327
+ else if (cue.lineAlign == Cue.lineAlign.END) style.left = `${97 - line}%`;
1328
+ }
1329
+ }
1330
+ }
1331
+ style.lineHeight = cue.lineHeight;
1332
+ if (!isNested && /vertical/.test(cue.writingMode) && cue.position == null) cue.position = 1;
1333
+ const computedPositionAlign = this.computeCuePositionAlignment_(cue);
1334
+ const computedCuePosition = !isNested && /vertical/.test(cue.writingMode) && cue.position == null ? 1 : cue.position;
1335
+ if (/ruby|rt/i.test(cueElement.tagName)) {} else if (computedPositionAlign == Cue.positionAlign.LEFT) {
1336
+ style.cssFloat = "left";
1337
+ if (computedCuePosition !== null) {
1338
+ style.position = "absolute";
1339
+ if (cue.writingMode == Cue.writingMode.HORIZONTAL_TOP_TO_BOTTOM) {
1340
+ style.left = `${computedCuePosition}%`;
1341
+ style.width = "auto";
1342
+ } else style.top = `${computedCuePosition}%`;
1343
+ }
1344
+ } else if (computedPositionAlign == Cue.positionAlign.RIGHT) {
1345
+ style.cssFloat = "right";
1346
+ if (computedCuePosition !== null) {
1347
+ style.position = "absolute";
1348
+ if (cue.writingMode == Cue.writingMode.HORIZONTAL_TOP_TO_BOTTOM) {
1349
+ style.right = `${100 - computedCuePosition}%`;
1350
+ style.width = "auto";
1351
+ } else style.bottom = `${computedCuePosition}%`;
1352
+ }
1353
+ } else if (computedCuePosition !== null && computedCuePosition != 50) {
1354
+ style.position = "absolute";
1355
+ if (cue.writingMode == Cue.writingMode.HORIZONTAL_TOP_TO_BOTTOM) {
1356
+ style.left = `${computedCuePosition}%`;
1357
+ style.width = "auto";
1358
+ } else style.top = `${computedCuePosition}%`;
1359
+ }
1360
+ style.textAlign = cue.textAlign;
1361
+ style.textDecoration = cue.textDecoration.join(" ");
1362
+ style.writingMode = cue.writingMode;
1363
+ if (!("writingMode" in document.documentElement.style) || style.writingMode != cue.writingMode) style.webkitWritingMode = cue.writingMode;
1364
+ if (cue.size) {
1365
+ if (cue.writingMode != Cue.writingMode.HORIZONTAL_TOP_TO_BOTTOM) style.height = `${cue.size}%`;
1366
+ }
1367
+ }
1368
+ };
1369
+ var UITextDisplayer_default = UITextDisplayer;
1370
+
1371
+ //#endregion
1372
+ //#region src/playerCore/shaka.js
1373
+ const getQualityItem = (track) => ({
1374
+ id: track.originalVideoId,
1375
+ bitrate: track.videoBandwidth,
1376
+ width: track.width,
1377
+ height: track.height,
1378
+ codec: track.videoCodec,
1379
+ frameRate: track.frameRate
1380
+ });
1381
+ const rewriteDashManifest = (type, response) => {
1382
+ const { MANIFEST } = window.shaka.net.NetworkingEngine.RequestType;
1383
+ if (type !== MANIFEST) return response;
1384
+ const data = new TextDecoder().decode(response.data);
1385
+ if (/<MPD/i.test(data)) response.data = new TextEncoder().encode(fixDashManifest_default(data));
1386
+ return response;
1387
+ };
1388
+ const sleep = (ms) => new Promise((r) => {
1389
+ setTimeout(r, ms);
1390
+ });
1391
+ const MAX_ERROR_RETRY = 3;
1392
+ const RETRY_DELAY = 5e3;
1393
+ const isSegmentNotFound = (detail) => detail?.code === window.shaka.util.Error.Code.BAD_HTTP_STATUS && detail.severity === window.shaka.util.Error.Severity.RECOVERABLE && detail?.data[1] === 404;
1394
+ const syncStartOver = (media, player) => {
1395
+ media.addEventListener("timeupdate", () => {
1396
+ const { start, end } = player.seekRange();
1397
+ const defaultLiveOffset = end - Date.now() / 1e3;
1398
+ const seekDurationDiff = end - start - Date.now() / 1e3;
1399
+ if (media.defaultLiveOffset && Math.abs(defaultLiveOffset - media.defaultLiveOffset) + Math.abs(seekDurationDiff - media.seekDurationDiff) > 7) {
1400
+ media.defaultLiveOffset = defaultLiveOffset;
1401
+ media.seekDurationDiff = seekDurationDiff;
1402
+ }
1403
+ });
1404
+ };
1405
+ const proxyTextTrackEvents = (media, { player }) => {
1406
+ const handleTextTrackChange = () => media.dispatchEvent(new CustomEvent("textTrackChange", { detail: { getTextTracks: () => player.isTextTrackVisible() ? player.getTextTracks() : [] } }));
1407
+ player.addEventListener("texttrackvisibility", handleTextTrackChange);
1408
+ player.addEventListener("textchange", handleTextTrackChange);
1409
+ };
1410
+ const loadShaka = async (videoElement, config = {}, options = {}) => {
1411
+ window.shakaMediaKeysPolyfill = true;
1412
+ const shakaModule = await import("shaka-player");
1413
+ const shaka$2 = shakaModule.default || shakaModule;
1414
+ window.shaka = shaka$2;
1415
+ shaka$2.polyfill.installAll();
1416
+ const player = new shaka$2.Player();
1417
+ getUrlObject_default((mediaSource) => {
1418
+ if (player) player.mediaSource = mediaSource;
1419
+ });
1420
+ player.attach(videoElement);
1421
+ player.configure({
1422
+ ...config,
1423
+ manifest: {
1424
+ dash: { ignoreSuggestedPresentationDelay: true },
1425
+ retryParameters: { maxAttempts: 6 },
1426
+ ...config.manifest
1427
+ },
1428
+ streaming: {
1429
+ autoLowLatencyMode: true,
1430
+ safeSeekOffset: 0,
1431
+ rebufferingGoal: 0,
1432
+ ...isSafari() && { preferNativeHls: true },
1433
+ ...config.streaming
1434
+ },
1435
+ ...options.container && document.fullscreenEnabled && { textDisplayFactory: () => new UITextDisplayer_default(videoElement, options.container) }
1436
+ });
1437
+ syncStartOver(videoElement, player);
1438
+ player.addEventListener("error", (event) => {
1439
+ console.log(event);
1440
+ const { detail = {} } = event;
1441
+ const error = /* @__PURE__ */ new Error(`Player: ${detail.code}/${detail.name}`);
1442
+ if (!detail || /The video element has thrown a media error|Video element triggered an Error/.test(detail.message) || detail.data?.some?.((message) => /Unsupported source type/i.test(message))) return;
1443
+ if (detail.code == 3016) return;
1444
+ if (isSegmentNotFound(detail)) {
1445
+ setTimeout(() => {
1446
+ if (player.errorRetry < MAX_ERROR_RETRY) {
1447
+ player.errorRetry += 1;
1448
+ player.reload();
1449
+ }
1450
+ }, RETRY_DELAY);
1451
+ return;
1452
+ }
1453
+ videoElement.dispatchEvent(Object.assign(new CustomEvent("error"), {
1454
+ error: detail,
1455
+ message: `Player Error: ${detail.code}/${detail.message?.split(" ", 3)[2]}`
1456
+ }));
1457
+ if (detail.code === 1001 || detail.severity === 2) {
1458
+ console.info("Stream unavailable, unload source");
1459
+ player.unload();
1460
+ }
1461
+ window.Sentry?.captureException(error);
1462
+ });
1463
+ player.addEventListener("loaded", () => {
1464
+ videoElement.dispatchEvent(new CustomEvent("canplay", {}));
1465
+ });
1466
+ player.addEventListener("adaptation", (event) => {
1467
+ const { videoBandwidth, width, height } = event.newTrack;
1468
+ if (event.oldTrack.height !== height) videoElement.dispatchEvent(new CustomEvent("downloadQualityChange", { detail: {
1469
+ bitrate: parseInt(videoBandwidth / 1e3, 10),
1470
+ height,
1471
+ width
1472
+ } }));
1473
+ });
1474
+ player.addEventListener("variantchanged", (event) => {
1475
+ const { language } = event.newTrack;
1476
+ if (event.oldTrack.language !== language) videoElement.dispatchEvent(new CustomEvent("audioTrackChange", { detail: { lang: language } }));
1477
+ });
1478
+ proxyTextTrackEvents(videoElement, { player });
1479
+ const extensionOptions = {
1480
+ requestHandlers: [],
1481
+ responseHandlers: [rewriteDashManifest]
1482
+ };
1483
+ if (isSafari()) setupKKFariplay_default(player, extensionOptions);
1484
+ const getAvailableVideoQualities = () => player.getVariantTracks().reduce((trackList, currentTrack) => {
1485
+ if (!trackList.find((track) => track.height === currentTrack.height)) trackList.push(getQualityItem(currentTrack));
1486
+ return trackList;
1487
+ }, []);
1488
+ const getVideoQuality = () => {
1489
+ const activeTrack = player.getVariantTracks().find((track) => track.active);
1490
+ if (!activeTrack) return {};
1491
+ return getQualityItem(activeTrack);
1492
+ };
1493
+ VttTextParser_default.register(shaka$2);
1494
+ HttpFetchPlugin_default.register(shaka$2);
1495
+ const networkEngine = player.getNetworkingEngine();
1496
+ networkEngine.registerRequestFilter((type, request) => extensionOptions.requestHandlers.reduce((merged, handler) => handler(type, merged, player, extensionOptions), request));
1497
+ networkEngine.registerResponseFilter((type, response) => extensionOptions.responseHandlers.reduce((merged, handler) => handler(type, merged, player, extensionOptions), response));
1498
+ const load = player.load.bind(player);
1499
+ const extensions = {
1500
+ shaka: shaka$2,
1501
+ errorRetry: 0,
1502
+ lastLoad: {},
1503
+ get mediaSource() {
1504
+ return player.mediaSource;
1505
+ },
1506
+ configureExtensions: ({ drm } = {}) => {
1507
+ extensionOptions.drm = drm;
1508
+ },
1509
+ load: async (assetUri, startTime, mimeType) => {
1510
+ await sleep(0);
1511
+ player.lastLoad = {
1512
+ assetUri,
1513
+ startTime,
1514
+ mimeType
1515
+ };
1516
+ return load(assetUri, startTime, mimeType);
1517
+ },
1518
+ reload: async () => {
1519
+ await player.unload();
1520
+ const { assetUri, startTime, mimeType } = player.lastLoad;
1521
+ return player.load(assetUri, startTime, mimeType);
1522
+ },
1523
+ getPlaybackSpeed: () => videoElement.playbackRate,
1524
+ getVideoElement: () => videoElement,
1525
+ getVideoQuality,
1526
+ getAvailableVideoQualities,
1527
+ isAlive: () => player.getLoadMode() !== shaka$2.Player.LoadMode.DESTROYED,
1528
+ on: player.addEventListener.bind(player)
1529
+ };
1530
+ Object.assign(player, extensions);
1531
+ return player;
1532
+ };
1533
+
1534
+ //#endregion
1535
+ //#region src/playerCore/loadPlayer.js
1536
+ const loadPlayer = async (videoElement, { container, source, shaka: shaka$2, bitmovin }) => {
1537
+ if (isIOS()) on(document, "visibilitychange", () => setTimeout(() => videoElement.pause(), 50));
1538
+ printVersion_default();
1539
+ let player;
1540
+ if (source?.native) player = await loadNative({ videoElement });
1541
+ else if (shaka$2 || !bitmovin) {
1542
+ player = await loadShaka(videoElement, shaka$2, { container });
1543
+ videoElement.dispatchEvent(new CustomEvent("playerStarted"));
1544
+ } else if (bitmovin?.load) {
1545
+ player = await bitmovin.load({
1546
+ container,
1547
+ videoElement,
1548
+ config: bitmovin
1549
+ });
1550
+ videoElement.dispatchEvent(new CustomEvent("playerStarted"));
1551
+ }
1552
+ reloadOnLiveStall(videoElement, { reload: () => player.reload() });
1553
+ player.preferredSettings = {};
1554
+ player.modules = {};
1555
+ return player;
1556
+ };
1557
+ var loadPlayer_default = loadPlayer;
1558
+
1559
+ //#endregion
1560
+ export { handleError as n, loadPlayer_default as t };