@vplayer/core 0.1.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/index.js ADDED
@@ -0,0 +1,1446 @@
1
+ import { Store as e } from "@tanstack/store";
2
+ //#region src/event-bus.ts
3
+ var t = class {
4
+ listeners = /* @__PURE__ */ new Map();
5
+ on(e, t) {
6
+ return this.listeners.has(e) || this.listeners.set(e, /* @__PURE__ */ new Set()), this.listeners.get(e).add(t), () => this.off(e, t);
7
+ }
8
+ once(e, t) {
9
+ let n = (...r) => {
10
+ t(...r), this.off(e, n);
11
+ };
12
+ return this.on(e, n);
13
+ }
14
+ off(e, t) {
15
+ if (!t) {
16
+ this.listeners.delete(e);
17
+ return;
18
+ }
19
+ let n = this.listeners.get(e);
20
+ n && (n.delete(t), n.size === 0 && this.listeners.delete(e));
21
+ }
22
+ emit(e, ...t) {
23
+ this.listeners.get(e)?.forEach((n) => {
24
+ try {
25
+ n(...t);
26
+ } catch (t) {
27
+ console.error(`[vplayer] EventBus error in "${e}":`, t);
28
+ }
29
+ });
30
+ }
31
+ clear() {
32
+ this.listeners.clear();
33
+ }
34
+ listenerCount(e) {
35
+ if (e) return this.listeners.get(e)?.size ?? 0;
36
+ let t = 0;
37
+ return this.listeners.forEach((e) => t += e.size), t;
38
+ }
39
+ }, n = class {
40
+ bindings = /* @__PURE__ */ new Map();
41
+ enabled = !0;
42
+ register(e) {
43
+ let { key: t } = e;
44
+ return this.bindings.has(t) || this.bindings.set(t, []), this.bindings.get(t).push(e), () => this.unregister(e);
45
+ }
46
+ unregister(e) {
47
+ let { key: t } = e, n = this.bindings.get(t);
48
+ if (!n) return;
49
+ let r = n.indexOf(e);
50
+ r !== -1 && (n.splice(r, 1), n.length === 0 && this.bindings.delete(t));
51
+ }
52
+ unregisterAll(e) {
53
+ this.bindings.delete(e);
54
+ }
55
+ clear() {
56
+ this.bindings.clear();
57
+ }
58
+ setEnabled(e) {
59
+ this.enabled = e;
60
+ }
61
+ handleKeyDown(e) {
62
+ if (!this.enabled) return !1;
63
+ let t = this.bindings.get(e.code);
64
+ if (!t || t.length === 0) return !1;
65
+ let n = e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement || e.target?.isContentEditable, r = !1;
66
+ for (let i of t) n && !i.allowWhenEditing || (i.handler(e), r = !0);
67
+ return r;
68
+ }
69
+ getBindings() {
70
+ let e = [];
71
+ return this.bindings.forEach((t) => e.push(...t)), e;
72
+ }
73
+ }, r = {
74
+ play: "Play",
75
+ pause: "Pause",
76
+ replay: "Replay",
77
+ mute: "Mute",
78
+ unmute: "Unmute",
79
+ settings: "Settings",
80
+ pip: "Picture in Picture",
81
+ pipExit: "Exit Picture in Picture",
82
+ fullscreen: "Fullscreen",
83
+ fullscreenExit: "Exit fullscreen",
84
+ speed: "Speed",
85
+ quality: "Quality",
86
+ subtitles: "Subtitles",
87
+ off: "Off",
88
+ endedTitle: "You've reached the end",
89
+ skipForward: "Skip forward {seconds}s",
90
+ skipBack: "Skip back {seconds}s",
91
+ seek: "Seek",
92
+ volume: "Volume",
93
+ loading: "Loading…",
94
+ error: "Video load failed",
95
+ reconnect: "Reconnecting… ({attempt}/{max})",
96
+ replayBtn: "Replay",
97
+ playBtn: "Play",
98
+ pauseBtn: "Pause"
99
+ }, i = {
100
+ en: r,
101
+ "zh-cn": {
102
+ play: "播放",
103
+ pause: "暂停",
104
+ replay: "重播",
105
+ mute: "静音",
106
+ unmute: "取消静音",
107
+ settings: "设置",
108
+ pip: "画中画",
109
+ pipExit: "退出画中画",
110
+ fullscreen: "全屏",
111
+ fullscreenExit: "退出全屏",
112
+ speed: "速度",
113
+ quality: "画质",
114
+ subtitles: "字幕",
115
+ off: "关闭",
116
+ endedTitle: "已播放完毕",
117
+ skipForward: "快进 {seconds} 秒",
118
+ skipBack: "快退 {seconds} 秒",
119
+ seek: "进度",
120
+ volume: "音量",
121
+ loading: "加载中…",
122
+ error: "视频加载失败",
123
+ reconnect: "重新连接… ({attempt}/{max})",
124
+ replayBtn: "重新播放",
125
+ playBtn: "播放",
126
+ pauseBtn: "暂停"
127
+ }
128
+ }, a = class {
129
+ languages = { ...i };
130
+ currentLang = "en";
131
+ currentDict = r;
132
+ constructor(e) {
133
+ e && this.setLanguage(e);
134
+ }
135
+ getLanguage() {
136
+ return this.currentLang;
137
+ }
138
+ setLanguage(e) {
139
+ this.currentLang = e.toLowerCase(), this.currentDict = this.languages[this.currentLang] ?? this.languages.en ?? r;
140
+ }
141
+ addTranslations(e, t) {
142
+ let n = e.toLowerCase();
143
+ this.languages[n] = {
144
+ ...this.languages[n],
145
+ ...t
146
+ }, n === this.currentLang && (this.currentDict = this.languages[n]);
147
+ }
148
+ t(e, t, n) {
149
+ let r = this.currentDict[e] ?? t ?? e;
150
+ if (n) for (let [e, t] of Object.entries(n)) r = r.replace(`{${e}}`, String(t));
151
+ return r;
152
+ }
153
+ getCurrentDict() {
154
+ return { ...this.currentDict };
155
+ }
156
+ getAvailableLanguages() {
157
+ return Object.keys(this.languages);
158
+ }
159
+ };
160
+ //#endregion
161
+ //#region src/media-capabilities.ts
162
+ function o() {
163
+ return typeof window < "u" && "MediaSource" in window;
164
+ }
165
+ function s(e) {
166
+ return e ? e.canPlayType("application/vnd.apple.mpegurl") !== "" || e.canPlayType("application/x-mpegURL") !== "" : !1;
167
+ }
168
+ function c(e) {
169
+ let t = e;
170
+ return !!t && (typeof t.requestFullscreen == "function" || typeof t.webkitRequestFullscreen == "function");
171
+ }
172
+ function l(e) {
173
+ return !e || typeof document > "u" ? !1 : "pictureInPictureEnabled" in document && !!document.pictureInPictureEnabled && "requestPictureInPicture" in e;
174
+ }
175
+ function u(e) {
176
+ return !!e && "textTracks" in e;
177
+ }
178
+ function d(e, t) {
179
+ return {
180
+ mse: o(),
181
+ nativeHls: s(e),
182
+ fullscreen: c(t),
183
+ pictureInPicture: l(e),
184
+ textTracks: u(e)
185
+ };
186
+ }
187
+ function f(e) {
188
+ return Number.isFinite(e) && e > 0;
189
+ }
190
+ //#endregion
191
+ //#region src/media-engine/base-engine.ts
192
+ var p = class {
193
+ element;
194
+ destroyed = !1;
195
+ listeners = /* @__PURE__ */ new Map();
196
+ domListeners = [];
197
+ constructor(e) {
198
+ this.element = e, this.attachDOMListeners();
199
+ }
200
+ async play() {
201
+ try {
202
+ await this.element.play();
203
+ } catch (e) {
204
+ let t = e instanceof DOMException || e instanceof Error ? e : Error(String(e));
205
+ this.emit("playblocked", {
206
+ name: t.name,
207
+ message: t.message || "Playback was blocked by the browser"
208
+ }), t.name !== "AbortError" && this.emit("error", { message: t.message || "Playback failed" });
209
+ }
210
+ }
211
+ pause() {
212
+ this.element.pause();
213
+ }
214
+ seek(e) {
215
+ let t = Number.isFinite(this.element.duration) ? this.element.duration : Infinity, n = Math.max(0, Math.min(e, t));
216
+ this.element.currentTime = n;
217
+ }
218
+ setVolume(e) {
219
+ this.element.volume = Math.max(0, Math.min(1, e));
220
+ }
221
+ setMuted(e) {
222
+ this.element.muted = e;
223
+ }
224
+ setPlaybackRate(e) {
225
+ !Number.isFinite(e) || e <= 0 || (this.element.playbackRate = e);
226
+ }
227
+ setLooping(e) {
228
+ this.element.loop = e;
229
+ }
230
+ load() {
231
+ this.element.load();
232
+ }
233
+ async requestPictureInPicture() {
234
+ if ("requestPictureInPicture" in this.element) try {
235
+ await this.element.requestPictureInPicture();
236
+ } catch {}
237
+ }
238
+ async exitPictureInPicture() {
239
+ if (!(typeof document > "u" || !("exitPictureInPicture" in document))) try {
240
+ await document.exitPictureInPicture();
241
+ } catch {}
242
+ }
243
+ async screenshot() {
244
+ if (this.element.videoWidth === 0 || this.element.videoHeight === 0) return null;
245
+ let e = document.createElement("canvas");
246
+ e.width = this.element.videoWidth, e.height = this.element.videoHeight;
247
+ let t = e.getContext("2d");
248
+ return t ? (t.drawImage(this.element, 0, 0), new Promise((t) => {
249
+ e.toBlob((e) => t(e), "image/png");
250
+ })) : null;
251
+ }
252
+ get currentTime() {
253
+ return this.element.currentTime;
254
+ }
255
+ get duration() {
256
+ return this.element.duration;
257
+ }
258
+ get volume() {
259
+ return this.element.volume;
260
+ }
261
+ get muted() {
262
+ return this.element.muted;
263
+ }
264
+ get playbackRate() {
265
+ return this.element.playbackRate;
266
+ }
267
+ get paused() {
268
+ return this.element.paused;
269
+ }
270
+ get ended() {
271
+ return this.element.ended;
272
+ }
273
+ get looping() {
274
+ return this.element.loop;
275
+ }
276
+ get buffered() {
277
+ return this.element.buffered;
278
+ }
279
+ get videoWidth() {
280
+ return this.element.videoWidth;
281
+ }
282
+ get videoHeight() {
283
+ return this.element.videoHeight;
284
+ }
285
+ get error() {
286
+ let e = this.element.error;
287
+ return e ? {
288
+ message: e.message ?? "Video playback error",
289
+ code: e.code
290
+ } : null;
291
+ }
292
+ on(e, t) {
293
+ return this.listeners.has(e) || this.listeners.set(e, /* @__PURE__ */ new Set()), this.listeners.get(e).add(t), () => {
294
+ this.listeners.get(e)?.delete(t);
295
+ };
296
+ }
297
+ emit(e, ...t) {
298
+ this.destroyed || this.listeners.get(e)?.forEach((n) => {
299
+ try {
300
+ n(...t);
301
+ } catch (t) {
302
+ console.error(`[vplayer] BaseMediaEngine error in "${e}":`, t);
303
+ }
304
+ });
305
+ }
306
+ attachDOMListeners() {
307
+ let e = this.element;
308
+ for (let [t, n] of [
309
+ ["play", "play"],
310
+ ["pause", "pause"],
311
+ ["ended", "ended"],
312
+ ["timeupdate", "timeupdate"],
313
+ ["loadedmetadata", "loadedmetadata"],
314
+ ["loadeddata", "loadeddata"],
315
+ ["durationchange", "durationchange"],
316
+ ["progress", "progress"],
317
+ ["seeking", "seeking"],
318
+ ["seeked", "seeked"],
319
+ ["waiting", "waiting"],
320
+ ["stalled", "stalled"],
321
+ ["playing", "playing"],
322
+ ["canplay", "canplay"],
323
+ ["canplaythrough", "canplaythrough"],
324
+ ["volumechange", "volumechange"],
325
+ ["ratechange", "ratechange"],
326
+ ["error", "error"]
327
+ ]) {
328
+ let r = () => this.emit(n);
329
+ e.addEventListener(t, r), this.domListeners.push({
330
+ event: t,
331
+ handler: r
332
+ });
333
+ }
334
+ }
335
+ detachDOMListeners() {
336
+ for (let { event: e, handler: t } of this.domListeners) this.element.removeEventListener(e, t);
337
+ this.domListeners = [];
338
+ }
339
+ destroy() {
340
+ this.destroyed || (this.destroyed = !0, this.detachDOMListeners(), this.listeners.clear());
341
+ }
342
+ }, m = class extends p {}, h = class extends p {
343
+ hls = null;
344
+ hlsSrc;
345
+ hlsConfig;
346
+ constructor(e, t) {
347
+ super(e), this.hlsSrc = t?.src, this.hlsConfig = t?.hlsConfig, this.hlsSrc && this.initHls();
348
+ }
349
+ initHls() {
350
+ this.initHlsAsync().catch((e) => {
351
+ console.error("[vplayer] HlsMediaEngine: failed to initialise hls.js", e), this.emit("error", { message: e instanceof Error ? e.message : "Failed to initialise hls.js" });
352
+ });
353
+ }
354
+ async initHlsAsync() {
355
+ if (this.destroyed || !this.hlsSrc) return;
356
+ let e = await import("hls.js"), t = e.default ?? e;
357
+ this.destroyed || (t.isSupported() ? (this.hls = new t(this.hlsConfig ?? {}), this.hls.on(t.Events.MANIFEST_PARSED, () => {
358
+ let e = this.hls.levels.length;
359
+ this.emit("manifestparsed", { levels: e });
360
+ }), this.hls.on(t.Events.LEVEL_SWITCHED, (e, t) => {
361
+ this.emit("levelswitched", { level: t.level });
362
+ }), this.hls.on(t.Events.ERROR, (e, n) => {
363
+ if (n.fatal) switch (n.type) {
364
+ case t.ErrorTypes.NETWORK_ERROR:
365
+ this.hls?.startLoad();
366
+ break;
367
+ case t.ErrorTypes.MEDIA_ERROR:
368
+ this.hls?.recoverMediaError();
369
+ break;
370
+ default:
371
+ this.emit("error", { message: `HLS fatal error: ${n.type} — ${n.details}` });
372
+ break;
373
+ }
374
+ }), this.hls.attachMedia(this.element), this.hls.loadSource(this.hlsSrc)) : this.element.canPlayType("application/vnd.apple.mpegurl") === "" ? this.emit("error", { message: "HLS is not supported in this browser" }) : this.element.src = this.hlsSrc);
375
+ }
376
+ load() {
377
+ this.hls && this.hlsSrc ? this.hls.loadSource(this.hlsSrc) : this.hlsSrc ? this.initHls() : super.load();
378
+ }
379
+ destroy() {
380
+ this.destroyed || (super.destroy(), this.hls &&= (this.hls.destroy(), null));
381
+ }
382
+ }, g = class extends p {
383
+ dashPlayer = null;
384
+ dashSrc;
385
+ dashConfig;
386
+ constructor(e, t) {
387
+ super(e), this.dashSrc = t?.src, this.dashConfig = t?.dashConfig, this.dashSrc && this.initDash();
388
+ }
389
+ initDash() {
390
+ this.initDashAsync().catch((e) => {
391
+ console.error("[vplayer] DashMediaEngine: failed to initialise dash.js", e), this.emit("error", { message: e instanceof Error ? e.message : "Failed to initialise dash.js" });
392
+ });
393
+ }
394
+ async initDashAsync() {
395
+ if (this.destroyed || !this.dashSrc) return;
396
+ let { MediaPlayer: e, MediaPlayer: { events: t } } = await import("dashjs");
397
+ this.destroyed || (this.dashPlayer = e().create(), this.dashConfig && this.dashPlayer.updateSettings(this.dashConfig), this.dashPlayer.on(t.PLAYBACK_PLAYING, () => this.emit("play")), this.dashPlayer.on(t.PLAYBACK_PAUSED, () => this.emit("pause")), this.dashPlayer.on(t.PLAYBACK_ENDED, () => this.emit("ended")), this.dashPlayer.on(t.PLAYBACK_TIME_UPDATED, () => this.emit("timeupdate")), this.dashPlayer.on(t.PLAYBACK_WAITING, () => this.emit("waiting")), this.dashPlayer.on(t.PLAYBACK_LOADED_DATA, () => this.emit("canplay")), this.dashPlayer.on(t.PLAYBACK_METADATA_LOADED, () => this.emit("loadedmetadata")), this.dashPlayer.on(t.ERROR, () => {
398
+ this.emit("error", { message: "DASH playback error" });
399
+ }), this.dashPlayer.attachView(this.element), this.dashPlayer.attachSource(this.dashSrc));
400
+ }
401
+ load() {
402
+ this.dashPlayer && this.dashSrc ? this.dashPlayer.attachSource(this.dashSrc) : this.dashSrc ? this.initDash() : super.load();
403
+ }
404
+ destroy() {
405
+ this.destroyed || (super.destroy(), this.dashPlayer &&= (this.dashPlayer.destroy(), null));
406
+ }
407
+ };
408
+ //#endregion
409
+ //#region src/source-resolver.ts
410
+ function _(e) {
411
+ try {
412
+ return new URL(e, typeof window < "u" ? window.location.href : "http://localhost").pathname.toLowerCase();
413
+ } catch {
414
+ return e.toLowerCase().split("?")[0].split("#")[0];
415
+ }
416
+ }
417
+ function v(e) {
418
+ let t = e.type?.toLowerCase() ?? "", n = _(e.src);
419
+ return t.includes("mpegurl") || t.includes("hls") || n.endsWith(".m3u8") ? "hls" : t.includes("dash") || n.endsWith(".mpd") ? "dash" : /\.(mp4|m4v|webm|ogv|ogg|mov)$/i.test(n) || t.startsWith("video/") ? "native" : "unknown";
420
+ }
421
+ function y(e) {
422
+ return {
423
+ src: e.src,
424
+ type: e.type
425
+ };
426
+ }
427
+ function b(e, t) {
428
+ if (t.engine) return typeof t.engine == "function" ? t.engine(e) : t.engine;
429
+ let n = y(t), r = v(n);
430
+ return r === "hls" && !s(e) ? new h(e, {
431
+ src: n.src,
432
+ hlsConfig: t.hlsConfig
433
+ }) : r === "dash" ? new g(e, {
434
+ src: n.src,
435
+ dashConfig: t.dashConfig
436
+ }) : (e.src = n.src, new m(e));
437
+ }
438
+ //#endregion
439
+ //#region src/state/slices.ts
440
+ function x() {
441
+ return new e(S());
442
+ }
443
+ function S() {
444
+ return {
445
+ status: "idle",
446
+ source: null,
447
+ isPlaying: !1,
448
+ isPaused: !0,
449
+ isBuffering: !1,
450
+ isEnded: !1,
451
+ currentTime: 0,
452
+ duration: 0,
453
+ bufferedPercent: 0,
454
+ playbackRate: 1,
455
+ isLive: !1,
456
+ volume: 1,
457
+ isMuted: !1,
458
+ isLooping: !1,
459
+ flip: "normal",
460
+ aspectRatio: "default",
461
+ activeSubtitle: null,
462
+ subtitleTracks: [],
463
+ activeQuality: "Auto",
464
+ qualities: [],
465
+ controlsVisible: !0,
466
+ capabilities: {
467
+ mse: !1,
468
+ nativeHls: !1,
469
+ fullscreen: !1,
470
+ pictureInPicture: !1,
471
+ textTracks: !1
472
+ },
473
+ isFullscreen: !1,
474
+ infoPanelVisible: !1,
475
+ notification: null,
476
+ controls: [],
477
+ settings: [],
478
+ layers: [],
479
+ contextMenuItems: [],
480
+ contextMenuEnabled: !0,
481
+ thumbnailCues: [],
482
+ error: null
483
+ };
484
+ }
485
+ var C = (e) => ({
486
+ status: e.status,
487
+ source: e.source,
488
+ isPlaying: e.isPlaying,
489
+ isPaused: e.isPaused,
490
+ isBuffering: e.isBuffering,
491
+ isEnded: e.isEnded,
492
+ currentTime: e.currentTime,
493
+ duration: e.duration,
494
+ bufferedPercent: e.bufferedPercent,
495
+ playbackRate: e.playbackRate,
496
+ isLive: e.isLive
497
+ }), w = (e) => ({
498
+ volume: e.volume,
499
+ isMuted: e.isMuted
500
+ }), T = (e) => ({
501
+ isLooping: e.isLooping,
502
+ flip: e.flip,
503
+ aspectRatio: e.aspectRatio,
504
+ activeSubtitle: e.activeSubtitle,
505
+ subtitleTracks: e.subtitleTracks,
506
+ activeQuality: e.activeQuality,
507
+ qualities: e.qualities
508
+ }), E = (e) => ({
509
+ controlsVisible: e.controlsVisible,
510
+ capabilities: e.capabilities,
511
+ isFullscreen: e.isFullscreen,
512
+ infoPanelVisible: e.infoPanelVisible,
513
+ notification: e.notification
514
+ }), D = (e) => ({
515
+ controls: e.controls,
516
+ settings: e.settings,
517
+ layers: e.layers,
518
+ contextMenuItems: e.contextMenuItems,
519
+ contextMenuEnabled: e.contextMenuEnabled
520
+ }), O = (e) => ({ thumbnailCues: e.thumbnailCues }), k = (e) => e.error, A = "vplayer", j = class {
521
+ fallback = /* @__PURE__ */ new Map();
522
+ prefix;
523
+ constructor(e = {}) {
524
+ this.prefix = e.prefix ?? A;
525
+ }
526
+ fullKey(e) {
527
+ return `${this.prefix}:${e}`;
528
+ }
529
+ get(e) {
530
+ let t = this.fullKey(e);
531
+ try {
532
+ let e = window.localStorage.getItem(t);
533
+ return e === null ? void 0 : JSON.parse(e);
534
+ } catch {
535
+ let e = this.fallback.get(t);
536
+ return e === void 0 ? void 0 : JSON.parse(e);
537
+ }
538
+ }
539
+ set(e, t) {
540
+ let n = this.fullKey(e);
541
+ try {
542
+ window.localStorage.setItem(n, JSON.stringify(t));
543
+ } catch {
544
+ this.fallback.set(n, JSON.stringify(t));
545
+ }
546
+ }
547
+ remove(e) {
548
+ let t = this.fullKey(e);
549
+ try {
550
+ window.localStorage.removeItem(t);
551
+ } catch {}
552
+ this.fallback.delete(t);
553
+ }
554
+ clear() {
555
+ try {
556
+ let e = [];
557
+ for (let t = 0; t < window.localStorage.length; t++) {
558
+ let n = window.localStorage.key(t);
559
+ n?.startsWith(this.prefix + ":") && e.push(n);
560
+ }
561
+ e.forEach((e) => window.localStorage.removeItem(e));
562
+ } catch {}
563
+ this.fallback.clear();
564
+ }
565
+ }, M = {
566
+ VOLUME: "volume",
567
+ MUTED: "muted",
568
+ PLAYBACK_RATE: "playbackRate",
569
+ SUBTITLE_LANG: "subtitleLang",
570
+ QUALITY: "quality",
571
+ PLAYBACK_PROGRESS: "playbackProgress",
572
+ LOOP: "loop",
573
+ FLIP: "flip",
574
+ ASPECT_RATIO: "aspectRatio"
575
+ };
576
+ //#endregion
577
+ //#region src/subtitle-parser.ts
578
+ function N(e) {
579
+ let t = e.replace(",", ".").split(":");
580
+ return t.length === 3 ? Number(t[0]) * 3600 + Number(t[1]) * 60 + Number(t[2]) : t.length === 2 ? Number(t[0]) * 60 + Number(t[1]) : Number(t[0]);
581
+ }
582
+ function P(e) {
583
+ return e.trim().replace(/\r\n/g, "\n").split(/\n\n+/).map((e) => {
584
+ let t = e.split("\n");
585
+ if (t.length < 3) return null;
586
+ let n = Number.parseInt(t[0], 10);
587
+ if (Number.isNaN(n)) return null;
588
+ let r = t[1].match(/(\d{2}:\d{2}:\d{2}[.,]\d{3})\s*-->\s*(\d{2}:\d{2}:\d{2}[.,]\d{3})/);
589
+ if (!r) return null;
590
+ let i = t.slice(2).join("\n");
591
+ return {
592
+ index: n,
593
+ start: N(r[1]),
594
+ end: N(r[2]),
595
+ text: i
596
+ };
597
+ }).filter((e) => e !== null);
598
+ }
599
+ function F(e) {
600
+ let t = e.replace(/\r\n/g, "\n"), n = t.indexOf("\n\n");
601
+ n > 0 && (t = t.slice(n + 2));
602
+ let r = t.trim().split(/\n\n+/), i = 0;
603
+ return r.map((e) => {
604
+ let t = e.split("\n");
605
+ if (t[0]?.startsWith("NOTE") || t[0]?.startsWith("STYLE")) return null;
606
+ let n = t.findIndex((e) => e.includes("-->"));
607
+ if (n === -1) return null;
608
+ let r = t[n].match(/(\d{2}:\d{2}:\d{2}[.,]\d{3})\s*-->\s*(\d{2}:\d{2}:\d{2}[.,]\d{3})/);
609
+ if (!r) return null;
610
+ let a = t.slice(n + 1).filter((e) => e.trim().length > 0);
611
+ return a.length === 0 ? null : (i++, {
612
+ index: i,
613
+ start: N(r[1]),
614
+ end: N(r[2]),
615
+ text: a.join("\n")
616
+ });
617
+ }).filter((e) => e !== null);
618
+ }
619
+ async function I(e) {
620
+ let t = await (await fetch(e.src)).text();
621
+ return e.src.endsWith(".srt") ? P(t) : F(t);
622
+ }
623
+ function L(e, t) {
624
+ let n = 0, r = e.length - 1;
625
+ for (; n <= r;) {
626
+ let i = n + r >> 1, a = e[i];
627
+ if (t < a.start) r = i - 1;
628
+ else if (t > a.end) n = i + 1;
629
+ else return a;
630
+ }
631
+ return null;
632
+ }
633
+ function R(e) {
634
+ let t = e.match(/#xywh=(\d+),(\d+),(\d+),(\d+)/);
635
+ return t ? {
636
+ src: e.replace(/#xywh=.*$/, ""),
637
+ x: Number(t[1]),
638
+ y: Number(t[2]),
639
+ w: Number(t[3]),
640
+ h: Number(t[4])
641
+ } : null;
642
+ }
643
+ function z(e) {
644
+ let t = e.replace(/\r\n/g, "\n"), n = t.indexOf("\n\n");
645
+ return n > 0 && (t = t.slice(n + 2)), t.trim().split(/\n\n+/).map((e) => {
646
+ let t = e.split("\n"), n = t.findIndex((e) => e.includes("-->"));
647
+ if (n === -1) return null;
648
+ let r = t[n].match(/(\d{2}:\d{2}:\d{2}[.,]\d{3})\s*-->\s*(\d{2}:\d{2}:\d{2}[.,]\d{3})/);
649
+ if (!r) return null;
650
+ let i = t.slice(n + 1).find((e) => e.trim().length > 0);
651
+ if (!i) return null;
652
+ let a = i.trim(), o = R(a), s = N(r[1]), c = N(r[2]);
653
+ return o ? {
654
+ start: s,
655
+ end: c,
656
+ src: o.src,
657
+ x: o.x,
658
+ y: o.y,
659
+ w: o.w,
660
+ h: o.h
661
+ } : {
662
+ start: s,
663
+ end: c,
664
+ src: a,
665
+ x: 0,
666
+ y: 0,
667
+ w: 160,
668
+ h: 90
669
+ };
670
+ }).filter((e) => e !== null);
671
+ }
672
+ function B(e, t) {
673
+ try {
674
+ return new URL(e, t).toString();
675
+ } catch {
676
+ return e;
677
+ }
678
+ }
679
+ async function V(e, t) {
680
+ let n = await fetch(e, { signal: t });
681
+ if (!n.ok) throw Error(`Failed to fetch thumbnail VTT: ${n.status}`);
682
+ return z(await n.text()).map((t) => (t.src = B(t.src, n.url || e), t));
683
+ }
684
+ function H(e, t) {
685
+ if (e.length === 0) return null;
686
+ let n = 0, r = e.length - 1;
687
+ for (; n <= r;) {
688
+ let i = n + r >> 1, a = e[i];
689
+ if (t < a.start) r = i - 1;
690
+ else if (t >= a.end) n = i + 1;
691
+ else return a;
692
+ }
693
+ return null;
694
+ }
695
+ //#endregion
696
+ //#region src/player.ts
697
+ var U = [
698
+ "default",
699
+ "16:9",
700
+ "4:3",
701
+ "21:9",
702
+ "cover",
703
+ "fill"
704
+ ], W = {
705
+ "16:9": "16 / 9",
706
+ "4:3": "4 / 3",
707
+ "21:9": "21 / 9"
708
+ }, G = {
709
+ default: "default",
710
+ "16:9": "16-9",
711
+ "4:3": "4-3",
712
+ "21:9": "21-9",
713
+ cover: "cover",
714
+ fill: "fill"
715
+ };
716
+ function K(e) {
717
+ e.classList.remove("vplayer--media-default", "vplayer--media-16-9", "vplayer--media-4-3", "vplayer--media-21-9", "vplayer--media-cover", "vplayer--media-fill");
718
+ }
719
+ function q(e) {
720
+ return typeof e == "string" && e in G ? e : "default";
721
+ }
722
+ function J(e) {
723
+ return e === "cover" ? "cover" : e === "fill" ? "fill" : "contain";
724
+ }
725
+ function Y(e) {
726
+ let r = x(), i = { ...e }, o = new t(), s = new j(), c = new a(i.lang);
727
+ i.translations && c.addTranslations(i.lang ?? "en", i.translations);
728
+ let l = new n(), u = i.reconnectMax ?? 3, p = i.reconnectSleep ?? 1500, m = null, h = null, g = null, _ = null, v = null, S = 0, C = null;
729
+ function w() {
730
+ l.register({
731
+ key: "Space",
732
+ description: "Toggle play/pause",
733
+ handler: (e) => {
734
+ e.preventDefault(), E.togglePlay();
735
+ }
736
+ }), l.register({
737
+ key: "KeyK",
738
+ description: "Toggle play/pause",
739
+ handler: (e) => {
740
+ e.preventDefault(), E.togglePlay();
741
+ }
742
+ }), l.register({
743
+ key: "KeyL",
744
+ description: "Toggle loop",
745
+ handler: (e) => {
746
+ e.preventDefault(), E.toggleLoop();
747
+ }
748
+ }), l.register({
749
+ key: "KeyI",
750
+ description: "Toggle info panel",
751
+ handler: (e) => {
752
+ e.preventDefault(), E.toggleInfoPanel();
753
+ }
754
+ }), l.register({
755
+ key: "KeyF",
756
+ description: "Toggle fullscreen",
757
+ handler: (e) => {
758
+ e.preventDefault(), E.toggleFullscreen();
759
+ }
760
+ }), l.register({
761
+ key: "KeyA",
762
+ description: "Cycle aspect ratio",
763
+ handler: (e) => {
764
+ e.preventDefault(), E.cycleAspectRatio();
765
+ }
766
+ }), l.register({
767
+ key: "KeyM",
768
+ description: "Toggle mute",
769
+ handler: (e) => {
770
+ e.preventDefault(), E.toggleMute();
771
+ }
772
+ }), l.register({
773
+ key: "ArrowLeft",
774
+ description: "Seek backward 5s",
775
+ handler: (e) => {
776
+ e.preventDefault(), E.skip(-5);
777
+ }
778
+ }), l.register({
779
+ key: "ArrowRight",
780
+ description: "Seek forward 5s",
781
+ handler: (e) => {
782
+ e.preventDefault(), E.skip(5);
783
+ }
784
+ }), l.register({
785
+ key: "ArrowUp",
786
+ description: "Volume up 10%",
787
+ handler: (e) => {
788
+ e.preventDefault();
789
+ let t = Math.min(1, r.state.volume + .1);
790
+ E.setVolume(t);
791
+ }
792
+ }), l.register({
793
+ key: "ArrowDown",
794
+ description: "Volume down 10%",
795
+ handler: (e) => {
796
+ e.preventDefault();
797
+ let t = Math.max(0, r.state.volume - .1);
798
+ E.setVolume(t);
799
+ }
800
+ });
801
+ }
802
+ i.defaultHotkeys !== !1 && w();
803
+ function T() {
804
+ if (typeof document > "u") return;
805
+ let e = document;
806
+ r.setState((t) => ({
807
+ ...t,
808
+ isFullscreen: !!(document.fullscreenElement || e.webkitFullscreenElement),
809
+ capabilities: d(h?.element ?? void 0, m)
810
+ }));
811
+ }
812
+ let E = {
813
+ play: () => {
814
+ h?.play();
815
+ },
816
+ pause: () => h?.pause(),
817
+ togglePlay: () => {
818
+ let e = h;
819
+ e && (e.paused || e.ended ? e.play() : e.pause());
820
+ },
821
+ seek: (e) => h?.seek(e),
822
+ skip: (e) => {
823
+ let t = h;
824
+ if (!t) return;
825
+ let n = f(t.duration) ? t.duration : Infinity, r = Math.max(0, Math.min(t.currentTime + e, n));
826
+ t.seek(r);
827
+ },
828
+ setVolume: (e) => {
829
+ let t = h;
830
+ if (!t) return;
831
+ let n = Math.max(0, Math.min(1, e));
832
+ t.setVolume(n), n > 0 && t.setMuted(!1), r.setState((e) => ({
833
+ ...e,
834
+ volume: n,
835
+ isMuted: t.muted
836
+ }));
837
+ },
838
+ toggleMute: () => {
839
+ let e = h;
840
+ e && (e.setMuted(!e.muted), r.setState((t) => ({
841
+ ...t,
842
+ isMuted: e.muted
843
+ })));
844
+ },
845
+ setPlaybackRate: (e) => {
846
+ let t = h;
847
+ t && (t.setPlaybackRate(e), r.setState((e) => ({
848
+ ...e,
849
+ playbackRate: t.playbackRate
850
+ })));
851
+ },
852
+ toggleFullscreen: () => {
853
+ if (!m || typeof document > "u") return;
854
+ let e = m, t = document, n = !!(document.fullscreenElement || t.webkitFullscreenElement), r = () => {
855
+ m?.focus({ preventScroll: !0 }), T();
856
+ }, i = n ? typeof document.exitFullscreen == "function" ? document.exitFullscreen() : t.webkitExitFullscreen?.() : typeof m.requestFullscreen == "function" ? m.requestFullscreen() : e.webkitRequestFullscreen?.();
857
+ Promise.resolve(i).then(r, r);
858
+ },
859
+ togglePiP: () => {
860
+ let e = h;
861
+ !e || typeof document > "u" || (document.pictureInPictureElement ? e.exitPictureInPicture() : e.requestPictureInPicture());
862
+ },
863
+ setActiveSubtitle: (e) => {
864
+ r.setState((t) => ({
865
+ ...t,
866
+ activeSubtitle: e
867
+ }));
868
+ },
869
+ setActiveQuality: (e) => {
870
+ r.setState((t) => ({
871
+ ...t,
872
+ activeQuality: e
873
+ }));
874
+ },
875
+ takeScreenshot: async () => {
876
+ let e = h;
877
+ if (!e) return;
878
+ let t = await e.screenshot();
879
+ if (!t) return;
880
+ let n = URL.createObjectURL(t), r = document.createElement("a");
881
+ r.href = n, r.download = `vplayer-screenshot-${Date.now()}.png`, r.click(), URL.revokeObjectURL(n);
882
+ },
883
+ setFlip: (e) => {
884
+ let t = h?.element;
885
+ if (!t) return;
886
+ let n = "";
887
+ e === "horizontal" && (n = "scaleX(-1)"), e === "vertical" && (n = "scaleY(-1)"), t.style.transform = n, r.setState((t) => ({
888
+ ...t,
889
+ flip: e
890
+ }));
891
+ },
892
+ setAspectRatio: (e) => {
893
+ let t = q(e), n = h?.element;
894
+ if (!n) return;
895
+ let i = W[t];
896
+ i ? n.style.setProperty("--vplayer-media-aspect-ratio", i) : n.style.removeProperty("--vplayer-media-aspect-ratio"), n.style.objectFit = J(t), n.style.setProperty("--vplayer-media-object-fit", J(t)), m && (K(m), m.classList.add(`vplayer--media-${G[t]}`)), r.setState((e) => ({
897
+ ...e,
898
+ aspectRatio: t
899
+ }));
900
+ },
901
+ cycleAspectRatio: () => {
902
+ let e = r.state.aspectRatio, t = U[(U.indexOf(e) + 1) % U.length] ?? "default";
903
+ E.setAspectRatio(t);
904
+ },
905
+ toggleLoop: () => {
906
+ let e = h;
907
+ e && (e.setLooping(!e.looping), r.setState((t) => ({
908
+ ...t,
909
+ isLooping: e.looping
910
+ })));
911
+ },
912
+ toggleInfoPanel: () => {
913
+ r.setState((e) => ({
914
+ ...e,
915
+ infoPanelVisible: !e.infoPanelVisible
916
+ }));
917
+ }
918
+ };
919
+ function D(e) {
920
+ return [
921
+ e.on("play", () => {
922
+ r.setState((e) => ({
923
+ ...e,
924
+ status: "playing",
925
+ isPlaying: !0,
926
+ isPaused: !1,
927
+ isBuffering: !1,
928
+ isEnded: !1,
929
+ error: null
930
+ })), S = 0;
931
+ }),
932
+ e.on("pause", () => {
933
+ r.setState((e) => ({
934
+ ...e,
935
+ status: e.isEnded ? "ended" : "paused",
936
+ isPlaying: !1,
937
+ isPaused: !e.isEnded,
938
+ isBuffering: !1,
939
+ controlsVisible: !0
940
+ }));
941
+ }),
942
+ e.on("ended", () => {
943
+ r.setState((e) => ({
944
+ ...e,
945
+ status: "ended",
946
+ isPlaying: !1,
947
+ isPaused: !1,
948
+ isBuffering: !1,
949
+ isEnded: !0,
950
+ controlsVisible: !0
951
+ })), i.onEnded?.();
952
+ }),
953
+ e.on("timeupdate", () => {
954
+ r.setState((t) => ({
955
+ ...t,
956
+ currentTime: e.currentTime
957
+ })), i.onTimeUpdate?.(e.currentTime);
958
+ }),
959
+ e.on("loadedmetadata", () => {
960
+ r.setState((t) => ({
961
+ ...t,
962
+ status: t.status === "idle" || t.status === "loading" ? "ready" : t.status,
963
+ duration: f(e.duration) ? e.duration : 0,
964
+ isLive: !f(e.duration),
965
+ volume: e.volume,
966
+ isMuted: e.muted,
967
+ playbackRate: e.playbackRate
968
+ }));
969
+ }),
970
+ e.on("progress", () => {
971
+ let t = e.buffered;
972
+ if (t.length === 0) return;
973
+ let n = t.end(t.length - 1);
974
+ r.setState((t) => ({
975
+ ...t,
976
+ bufferedPercent: f(e.duration) ? n / e.duration * 100 : 0
977
+ }));
978
+ }),
979
+ e.on("waiting", () => {
980
+ r.setState((e) => ({
981
+ ...e,
982
+ status: "buffering",
983
+ isBuffering: !0
984
+ }));
985
+ }),
986
+ e.on("canplay", () => {
987
+ r.setState((e) => ({
988
+ ...e,
989
+ status: e.isPlaying ? "playing" : "ready",
990
+ isBuffering: !1
991
+ }));
992
+ }),
993
+ e.on("durationchange", () => {
994
+ r.setState((t) => ({
995
+ ...t,
996
+ duration: f(e.duration) ? e.duration : 0,
997
+ isLive: !f(e.duration)
998
+ }));
999
+ }),
1000
+ e.on("seeking", () => {
1001
+ r.setState((e) => ({
1002
+ ...e,
1003
+ status: "seeking"
1004
+ }));
1005
+ }),
1006
+ e.on("seeked", () => {
1007
+ r.setState((e) => ({
1008
+ ...e,
1009
+ status: e.isPlaying ? "playing" : "ready"
1010
+ }));
1011
+ }),
1012
+ e.on("playing", () => {
1013
+ r.setState((e) => ({
1014
+ ...e,
1015
+ status: "playing",
1016
+ isPlaying: !0,
1017
+ isPaused: !1,
1018
+ isBuffering: !1
1019
+ }));
1020
+ }),
1021
+ e.on("volumechange", () => {
1022
+ r.setState((t) => ({
1023
+ ...t,
1024
+ volume: e.volume,
1025
+ isMuted: e.muted
1026
+ }));
1027
+ }),
1028
+ e.on("ratechange", () => {
1029
+ r.setState((t) => ({
1030
+ ...t,
1031
+ playbackRate: e.playbackRate
1032
+ }));
1033
+ }),
1034
+ e.on("playblocked", (e) => {
1035
+ let t = e?.message ?? "Playback was blocked by the browser";
1036
+ r.setState((e) => ({
1037
+ ...e,
1038
+ status: e.isPlaying ? e.status : "paused",
1039
+ error: {
1040
+ message: t,
1041
+ reconnectAttempt: S,
1042
+ isReconnecting: !1
1043
+ }
1044
+ })), i.onError?.(t);
1045
+ }),
1046
+ e.on("error", () => {
1047
+ let t = e.error?.message ?? "Video playback error";
1048
+ r.setState((e) => ({
1049
+ ...e,
1050
+ status: "error",
1051
+ error: {
1052
+ message: t,
1053
+ reconnectAttempt: S,
1054
+ isReconnecting: !1
1055
+ }
1056
+ })), i.onError?.(t), o.emit("video:error", { message: t }), S < u && (r.setState((e) => ({
1057
+ ...e,
1058
+ error: {
1059
+ message: t,
1060
+ reconnectAttempt: S,
1061
+ isReconnecting: !0
1062
+ }
1063
+ })), o.emit("video:reconnecting", { attempt: S + 1 }), v !== null && clearTimeout(v), v = setTimeout(() => {
1064
+ v = null, S++, r.setState((e) => ({
1065
+ ...e,
1066
+ error: {
1067
+ message: t,
1068
+ reconnectAttempt: S,
1069
+ isReconnecting: !1
1070
+ }
1071
+ })), o.emit("video:reconnect", { attempt: S }), e.load();
1072
+ }, p));
1073
+ })
1074
+ ];
1075
+ }
1076
+ function O() {
1077
+ k(), _ = setInterval(() => {
1078
+ let e = h;
1079
+ e && s.set(M.PLAYBACK_PROGRESS, {
1080
+ time: e.currentTime,
1081
+ duration: e.duration
1082
+ });
1083
+ }, 5e3);
1084
+ }
1085
+ function k() {
1086
+ _ !== null && (clearInterval(_), _ = null);
1087
+ }
1088
+ let A = r.subscribe(() => {
1089
+ let e = r.state;
1090
+ e.isPlaying && e.duration > 0 ? _ === null && O() : k();
1091
+ }), N = null;
1092
+ function P() {
1093
+ if (!i.persistPreferences) return;
1094
+ let e = s.get(M.VOLUME), t = s.get(M.MUTED), n = s.get(M.PLAYBACK_RATE), a = s.get(M.LOOP), o = s.get(M.FLIP), c = s.get(M.ASPECT_RATIO);
1095
+ r.setState((r) => ({
1096
+ ...r,
1097
+ volume: e ?? r.volume,
1098
+ isMuted: t ?? r.isMuted,
1099
+ playbackRate: n ?? r.playbackRate,
1100
+ isLooping: a ?? r.isLooping,
1101
+ flip: o ?? r.flip,
1102
+ aspectRatio: q(c)
1103
+ })), N = r.subscribe(() => {
1104
+ let e = r.state;
1105
+ e.volume !== 1 && s.set(M.VOLUME, e.volume), e.isMuted && s.set(M.MUTED, !0), e.playbackRate !== 1 && s.set(M.PLAYBACK_RATE, e.playbackRate), e.isLooping ? s.set(M.LOOP, !0) : s.remove(M.LOOP), e.flip === "normal" ? s.remove(M.FLIP) : s.set(M.FLIP, e.flip), e.aspectRatio === "default" ? s.remove(M.ASPECT_RATIO) : s.set(M.ASPECT_RATIO, e.aspectRatio);
1106
+ });
1107
+ }
1108
+ function F() {
1109
+ N &&= (N(), null);
1110
+ }
1111
+ function I(e) {
1112
+ if (C?.abort(), C = null, !e) {
1113
+ r.setState((e) => ({
1114
+ ...e,
1115
+ thumbnailCues: []
1116
+ }));
1117
+ return;
1118
+ }
1119
+ let t = new AbortController();
1120
+ C = t, V(e, t.signal).then((e) => {
1121
+ t.signal.aborted || r.setState((t) => ({
1122
+ ...t,
1123
+ thumbnailCues: e
1124
+ }));
1125
+ }).catch((e) => {
1126
+ t.signal.aborted || (console.warn("[vplayer] thumbnail VTT failed:", e), r.setState((e) => ({
1127
+ ...e,
1128
+ thumbnailCues: []
1129
+ })));
1130
+ });
1131
+ }
1132
+ function L(e) {
1133
+ return {
1134
+ name: e,
1135
+ store: r,
1136
+ remote: E,
1137
+ events: o,
1138
+ storage: s,
1139
+ hotkeys: l,
1140
+ i18n: c,
1141
+ context: {
1142
+ containerRef: { get current() {
1143
+ return m;
1144
+ } },
1145
+ videoRef: { get current() {
1146
+ return h?.element;
1147
+ } }
1148
+ },
1149
+ addControl: (e) => (r.setState((t) => ({
1150
+ ...t,
1151
+ controls: [...t.controls.filter((t) => t.name !== e.name), e]
1152
+ })), () => {
1153
+ r.setState((t) => ({
1154
+ ...t,
1155
+ controls: t.controls.filter((t) => t.name !== e.name)
1156
+ }));
1157
+ }),
1158
+ removeControl: (e) => {
1159
+ r.setState((t) => ({
1160
+ ...t,
1161
+ controls: t.controls.filter((t) => t.name !== e)
1162
+ }));
1163
+ },
1164
+ addSetting: (e) => (r.setState((t) => ({
1165
+ ...t,
1166
+ settings: [...t.settings.filter((t) => t.name !== e.name), e]
1167
+ })), () => {
1168
+ r.setState((t) => ({
1169
+ ...t,
1170
+ settings: t.settings.filter((t) => t.name !== e.name)
1171
+ }));
1172
+ }),
1173
+ removeSetting: (e) => {
1174
+ r.setState((t) => ({
1175
+ ...t,
1176
+ settings: t.settings.filter((t) => t.name !== e)
1177
+ }));
1178
+ },
1179
+ addLayer: (e) => (r.setState((t) => ({
1180
+ ...t,
1181
+ layers: [...t.layers.filter((t) => t.name !== e.name), e]
1182
+ })), () => {
1183
+ r.setState((t) => ({
1184
+ ...t,
1185
+ layers: t.layers.filter((t) => t.name !== e.name)
1186
+ }));
1187
+ }),
1188
+ removeLayer: (e) => {
1189
+ r.setState((t) => ({
1190
+ ...t,
1191
+ layers: t.layers.filter((t) => t.name !== e)
1192
+ }));
1193
+ },
1194
+ addHotkey: (e) => l.register({ ...e }),
1195
+ addContextMenuItems: (e) => (r.setState((t) => ({
1196
+ ...t,
1197
+ contextMenuItems: [...t.contextMenuItems, ...e]
1198
+ })), () => {
1199
+ r.setState((t) => ({
1200
+ ...t,
1201
+ contextMenuItems: t.contextMenuItems.filter((t) => !e.includes(t))
1202
+ }));
1203
+ }),
1204
+ notify: (e, t = 3e3) => {
1205
+ r.setState((n) => ({
1206
+ ...n,
1207
+ notification: {
1208
+ message: e,
1209
+ duration: t
1210
+ }
1211
+ }));
1212
+ }
1213
+ };
1214
+ }
1215
+ let R = [];
1216
+ function z() {
1217
+ for (let e of R) e();
1218
+ R = [], h && (h.destroy(), h = null, Y.engine = null);
1219
+ }
1220
+ function B(e) {
1221
+ let t = y(i), n = b(e, i);
1222
+ h = n, Y.engine = n, R = D(n), e.playsInline = !0, e.autoplay = !!i.autoPlay, e.preload = e.preload || "metadata", r.setState((n) => ({
1223
+ ...n,
1224
+ status: "loading",
1225
+ source: t,
1226
+ isPlaying: !1,
1227
+ isPaused: !0,
1228
+ isBuffering: !1,
1229
+ isEnded: !1,
1230
+ currentTime: 0,
1231
+ duration: 0,
1232
+ bufferedPercent: 0,
1233
+ capabilities: d(e, m),
1234
+ error: null
1235
+ })), i.autoPlay && n.play();
1236
+ }
1237
+ function H() {
1238
+ let e = h?.element;
1239
+ if (e) {
1240
+ for (z(), e.pause(), e.removeAttribute("src"); e.firstChild;) e.removeChild(e.firstChild);
1241
+ e.load(), B(e);
1242
+ }
1243
+ }
1244
+ let Y = {
1245
+ store: r,
1246
+ remote: E,
1247
+ events: o,
1248
+ storage: s,
1249
+ i18n: c,
1250
+ hotkeys: l,
1251
+ engine: null,
1252
+ updateOptions(e) {
1253
+ let t = typeof e.src == "string" && e.src !== i.src, n = Object.hasOwn(e, "type") && e.type !== i.type;
1254
+ i = {
1255
+ ...i,
1256
+ ...e
1257
+ }, r.setState((t) => {
1258
+ let n = e.subtitles ?? t.subtitleTracks, r = e.qualities ?? t.qualities;
1259
+ return {
1260
+ ...t,
1261
+ subtitleTracks: n,
1262
+ qualities: r,
1263
+ activeSubtitle: e.subtitles ? t.activeSubtitle && e.subtitles.some((e) => e.lang === t.activeSubtitle.lang) ? t.activeSubtitle : e.subtitles.find((e) => e.default) ?? e.subtitles[0] ?? null : t.activeSubtitle,
1264
+ activeQuality: e.qualities ? e.qualities.includes(t.activeQuality) ? t.activeQuality : e.qualities[0] ?? "Auto" : t.activeQuality
1265
+ };
1266
+ }), Object.hasOwn(e, "thumbnails") && I(e.thumbnails), (t || n) && H();
1267
+ },
1268
+ setThumbnails(e) {
1269
+ i = {
1270
+ ...i,
1271
+ thumbnails: e
1272
+ }, I(e);
1273
+ },
1274
+ initPlugins(e) {
1275
+ let t = [];
1276
+ for (let n of e) {
1277
+ let e = L(n.name);
1278
+ try {
1279
+ let r = n.setup?.(e);
1280
+ typeof r == "function" && t.push(r);
1281
+ } catch (e) {
1282
+ console.error(`[vplayer] Plugin "${n.name}" setup error:`, e);
1283
+ }
1284
+ }
1285
+ return o.emit("pluginregistered"), () => {
1286
+ for (let e of t) try {
1287
+ e();
1288
+ } catch (e) {
1289
+ console.error("[vplayer] plugin cleanup error:", e);
1290
+ }
1291
+ };
1292
+ },
1293
+ mount(e, t) {
1294
+ h && this.unmount(), m = t, B(e), g = T, document.addEventListener("fullscreenchange", g), document.addEventListener("webkitfullscreenchange", g), I(i.thumbnails), P(), E.setAspectRatio(r.state.aspectRatio);
1295
+ },
1296
+ unmount() {
1297
+ z(), m = null, k(), C?.abort(), C = null, F(), v !== null && (clearTimeout(v), v = null), g &&= (document.removeEventListener("fullscreenchange", g), document.removeEventListener("webkitfullscreenchange", g), null), r.setState((e) => ({
1298
+ ...e,
1299
+ status: "idle",
1300
+ isPlaying: !1,
1301
+ isPaused: !0,
1302
+ isBuffering: !1,
1303
+ isEnded: !1
1304
+ }));
1305
+ },
1306
+ destroy() {
1307
+ this.unmount(), A(), o.clear();
1308
+ }
1309
+ };
1310
+ return Y;
1311
+ }
1312
+ //#endregion
1313
+ //#region src/gesture-engine.ts
1314
+ function X(e, t) {
1315
+ let n = null, r = null, i = null, a = typeof window < "u" && "ontouchstart" in window;
1316
+ function o(t) {
1317
+ if (!a || t.touches.length !== 1) return;
1318
+ let r = t.touches[0], o = e();
1319
+ i = t.currentTarget, n = {
1320
+ startX: r.clientX,
1321
+ startY: r.clientY,
1322
+ startTime: Date.now(),
1323
+ startCurrentTime: o.currentTime,
1324
+ startVolume: o.volume,
1325
+ gesture: null
1326
+ };
1327
+ }
1328
+ function s(r) {
1329
+ let a = n;
1330
+ if (!a || r.touches.length !== 1) return;
1331
+ let o = r.touches[0], s = o.clientX - a.startX, c = o.clientY - a.startY, l = Math.abs(s), u = Math.abs(c);
1332
+ if (a.gesture || (l > u && l > 20 ? a.gesture = "seek" : u > l && u > 20 && (a.gesture = "volume")), a.gesture === "seek") {
1333
+ r.preventDefault();
1334
+ let { duration: n } = e();
1335
+ if (n <= 0) return;
1336
+ let i = s / 300 * n, o = Math.max(0, Math.min(n, a.startCurrentTime + i));
1337
+ t.seek(o);
1338
+ } else if (a.gesture === "volume") {
1339
+ let e = i;
1340
+ if (!e) return;
1341
+ let n = e.getBoundingClientRect();
1342
+ if (o.clientX - n.left < n.width / 2) return;
1343
+ r.preventDefault();
1344
+ let s = -c / 200, l = Math.max(0, Math.min(1, a.startVolume + s));
1345
+ t.setVolume(l);
1346
+ }
1347
+ }
1348
+ function c(e) {
1349
+ let a = n;
1350
+ if (a) {
1351
+ if (Date.now() - a.startTime < 300 && Math.abs(e.changedTouches[0].clientX - a.startX) < 20) {
1352
+ let n = Date.now();
1353
+ if (r && n - r.time < 350) {
1354
+ e.preventDefault();
1355
+ let n = i;
1356
+ if (n) {
1357
+ let e = n.getBoundingClientRect();
1358
+ a.startX - e.left < e.width / 2 ? t.skip(-10) : t.skip(10);
1359
+ }
1360
+ r = null;
1361
+ } else r = { time: n };
1362
+ }
1363
+ n = null;
1364
+ }
1365
+ }
1366
+ return {
1367
+ onTouchStart: o,
1368
+ onTouchMove: s,
1369
+ onTouchEnd: c
1370
+ };
1371
+ }
1372
+ //#endregion
1373
+ //#region src/utils.ts
1374
+ function Z(e) {
1375
+ if (!Number.isFinite(e) || e < 0) return "0:00";
1376
+ let t = Math.floor(e / 3600), n = Math.floor(e % 3600 / 60), r = Math.floor(e % 60);
1377
+ return t > 0 ? `${t}:${String(n).padStart(2, "0")}:${String(r).padStart(2, "0")}` : `${n}:${String(r).padStart(2, "0")}`;
1378
+ }
1379
+ //#endregion
1380
+ //#region src/defaults.ts
1381
+ var Q = {
1382
+ play: "Play",
1383
+ pause: "Pause",
1384
+ replay: "Replay",
1385
+ mute: "Mute",
1386
+ unmute: "Unmute",
1387
+ settings: "Settings",
1388
+ pip: "Picture in Picture",
1389
+ pipExit: "Exit Picture in Picture",
1390
+ miniPlayer: "Mini player",
1391
+ exitMiniPlayer: "Exit mini player",
1392
+ fullscreen: "Fullscreen",
1393
+ fullscreenExit: "Exit fullscreen",
1394
+ speed: "Speed",
1395
+ quality: "Quality",
1396
+ subtitles: "Subtitles",
1397
+ off: "Off",
1398
+ endedTitle: "You've reached the end",
1399
+ screenshot: "Screenshot",
1400
+ flip: "Flip",
1401
+ flipNormal: "Normal",
1402
+ flipHorizontal: "Horizontal",
1403
+ flipVertical: "Vertical",
1404
+ aspectRatio: "Aspect Ratio",
1405
+ aspectRatioDefault: "Default",
1406
+ aspectRatio16: "16 : 9",
1407
+ aspectRatio4: "4 : 3",
1408
+ aspectRatioFill: "Fill",
1409
+ aspectRatioCover: "Crop / Cover",
1410
+ aspectRatio21: "21 : 9",
1411
+ continue: "Continue",
1412
+ continuePlay: "Continue from",
1413
+ continueStartOver: "Start over",
1414
+ error: "An error occurred",
1415
+ retry: "Retry",
1416
+ contextMenuPlay: "Play",
1417
+ contextMenuPause: "Pause",
1418
+ contextMenuLoop: "Loop",
1419
+ infoPanel: "Info",
1420
+ loop: "Loop"
1421
+ }, $ = {
1422
+ play: "lucide:play",
1423
+ pause: "lucide:pause",
1424
+ replay: "lucide:rotate-ccw",
1425
+ skipBack: "lucide:skip-back",
1426
+ skipForward: "lucide:skip-forward",
1427
+ volumeHigh: "lucide:volume-2",
1428
+ volumeLow: "lucide:volume-1",
1429
+ volumeOff: "lucide:volume-x",
1430
+ settings: "lucide:settings-2",
1431
+ pip: "lucide:picture-in-picture-2",
1432
+ miniPlayer: "lucide:minimize-2",
1433
+ close: "lucide:x",
1434
+ fullscreen: "lucide:maximize",
1435
+ fullscreenExit: "lucide:minimize",
1436
+ chevronLeft: "lucide:chevron-left",
1437
+ check: "lucide:check",
1438
+ spinner: "lucide:loader-2",
1439
+ screenshot: "lucide:camera",
1440
+ flip: "lucide:flip-horizontal-2",
1441
+ aspectRatio: "lucide:monitor",
1442
+ info: "lucide:info",
1443
+ loop: "lucide:repeat"
1444
+ };
1445
+ //#endregion
1446
+ export { p as BaseMediaEngine, g as DashMediaEngine, t as EventBus, h as HlsMediaEngine, n as HotkeyRegistry, a as I18n, m as NativeVideoEngine, M as STORAGE_KEYS, j as Storage, c as canUseFullscreen, o as canUseMSE, s as canUseNativeHLS, l as canUsePictureInPicture, u as canUseTextTracks, X as createGestureEngine, x as createMediaStore, Y as createPlayer, b as createResolvedMediaEngine, $ as defaultPlayerIcons, Q as defaultPlayerLabels, v as detectSourceKind, I as fetchSubtitles, V as fetchThumbnails, Z as formatTime, L as getActiveCue, S as getInitialMediaState, d as getMediaCapabilities, H as getThumbnailAtTime, f as isFiniteDuration, P as parseSRT, z as parseThumbnailVTT, N as parseTimestamp, F as parseVTT, w as selectAudio, k as selectError, C as selectMedia, D as selectPlugins, T as selectPreferences, O as selectThumbnails, E as selectUI, y as toPlayerSource };