@vplayer/core 0.2.1 → 0.2.3

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 CHANGED
@@ -189,11 +189,11 @@ function f(e) {
189
189
  }
190
190
  //#endregion
191
191
  //#region src/storage.ts
192
- var p = "vplayer", m = class {
192
+ var ee = "vplayer", p = class {
193
193
  fallback = /* @__PURE__ */ new Map();
194
194
  prefix;
195
195
  constructor(e = {}) {
196
- this.prefix = e.prefix ?? p;
196
+ this.prefix = e.prefix ?? ee;
197
197
  }
198
198
  fullKey(e) {
199
199
  return `${this.prefix}:${e}`;
@@ -234,30 +234,40 @@ var p = "vplayer", m = class {
234
234
  } catch {}
235
235
  this.fallback.clear();
236
236
  }
237
- }, h = {
237
+ }, m = {
238
238
  VOLUME: "volume",
239
239
  MUTED: "muted",
240
240
  PLAYBACK_RATE: "playbackRate",
241
241
  SUBTITLE_LANG: "subtitleLang",
242
+ CAPTION_SETTINGS: "captionSettings",
242
243
  QUALITY: "quality",
243
244
  LOOP: "loop",
244
245
  FLIP: "flip",
245
246
  ASPECT_RATIO: "aspectRatio"
246
- }, g = class {
247
+ }, te = class {
247
248
  storage;
248
- constructor(e = new m({ prefix: "vplayer:progress" })) {
249
- this.storage = e;
249
+ maxEntries;
250
+ constructor(e = new p(), t = 100) {
251
+ this.storage = e, this.maxEntries = t;
250
252
  }
251
253
  async load(e) {
252
- return this.storage.get(encodeURIComponent(e)) ?? null;
254
+ return this.storage.get("progress")?.[e] ?? null;
253
255
  }
254
256
  async save(e, t) {
255
- this.storage.set(encodeURIComponent(e), t);
257
+ let n = this.storage.get("progress") ?? {};
258
+ delete n[e], n[e] = t;
259
+ let r = Object.keys(n);
260
+ for (; r.length > this.maxEntries;) {
261
+ let e = r.shift();
262
+ e !== void 0 && delete n[e];
263
+ }
264
+ this.storage.set("progress", n);
256
265
  }
257
266
  async clear(e) {
258
- this.storage.remove(encodeURIComponent(e));
267
+ let t = this.storage.get("progress") ?? {};
268
+ delete t[e], Object.keys(t).length === 0 ? this.storage.remove("progress") : this.storage.set("progress", t);
259
269
  }
260
- }, _ = class {
270
+ }, h = class {
261
271
  element;
262
272
  destroyed = !1;
263
273
  listeners = /* @__PURE__ */ new Map();
@@ -407,7 +417,7 @@ var p = "vplayer", m = class {
407
417
  destroy() {
408
418
  this.destroyed || (this.destroyed = !0, this.detachDOMListeners(), this.listeners.clear());
409
419
  }
410
- }, v = class extends _ {}, y = class extends _ {
420
+ }, g = class extends h {}, _ = class extends h {
411
421
  hls = null;
412
422
  hlsSrc;
413
423
  hlsConfig;
@@ -435,9 +445,7 @@ var p = "vplayer", m = class {
435
445
  case t.ErrorTypes.MEDIA_ERROR:
436
446
  this.hls?.recoverMediaError();
437
447
  break;
438
- default:
439
- this.emit("error", { message: `HLS fatal error: ${n.type} — ${n.details}` });
440
- break;
448
+ default: this.emit("error", { message: `HLS fatal error: ${n.type} — ${n.details}` });
441
449
  }
442
450
  }), 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);
443
451
  }
@@ -447,7 +455,7 @@ var p = "vplayer", m = class {
447
455
  destroy() {
448
456
  this.destroyed || (super.destroy(), this.hls &&= (this.hls.destroy(), null));
449
457
  }
450
- }, b = class extends _ {
458
+ }, v = class extends h {
451
459
  dashPlayer = null;
452
460
  dashSrc;
453
461
  dashConfig;
@@ -475,40 +483,212 @@ var p = "vplayer", m = class {
475
483
  };
476
484
  //#endregion
477
485
  //#region src/source-resolver.ts
478
- function x(e) {
486
+ function y(e) {
479
487
  try {
480
488
  return new URL(e, typeof window < "u" ? window.location.href : "http://localhost").pathname.toLowerCase();
481
489
  } catch {
482
490
  return e.toLowerCase().split("?")[0].split("#")[0];
483
491
  }
484
492
  }
485
- function S(e) {
486
- let t = e.type?.toLowerCase() ?? "", n = x(e.src);
493
+ function b(e) {
494
+ let t = e.type?.toLowerCase() ?? "", n = y(e.src);
487
495
  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";
488
496
  }
489
- function C(e) {
497
+ function x(e) {
490
498
  return {
491
499
  src: e.src,
492
500
  type: e.type
493
501
  };
494
502
  }
495
- function ee(e, t) {
503
+ function ne(e, t) {
496
504
  if (t.engine) return typeof t.engine == "function" ? t.engine(e) : t.engine;
497
- let n = C(t), r = S(n);
498
- return r === "hls" && !s(e) ? new y(e, {
505
+ let n = x(t), r = b(n);
506
+ return r === "hls" && !s(e) ? new _(e, {
499
507
  src: n.src,
500
508
  hlsConfig: t.hlsConfig
501
- }) : r === "dash" ? new b(e, {
509
+ }) : r === "dash" ? new v(e, {
502
510
  src: n.src,
503
511
  dashConfig: t.dashConfig
504
- }) : (e.src = n.src, new v(e));
512
+ }) : (e.src = n.src, new g(e));
513
+ }
514
+ //#endregion
515
+ //#region src/subtitle-parser.ts
516
+ var S = {
517
+ fontSize: "medium",
518
+ fontScale: 100,
519
+ fontFamily: "sans",
520
+ textColor: "#ffffff",
521
+ textOpacity: 1,
522
+ backgroundColor: "#000000",
523
+ backgroundOpacity: .75,
524
+ edgeStyle: "shadow",
525
+ edgeColor: "#000000",
526
+ position: 0,
527
+ lineHeight: 1.35,
528
+ delay: 0
529
+ }, C = "(?:\\d{2}:)?\\d{2}:\\d{2}[.,]\\d{3}", w = RegExp(`^(${C})\\s*-->\\s*(${C})(?:\\s+(.*))?$`);
530
+ function T(e) {
531
+ return e.replace(/^\uFEFF/, "").replace(/\r\n?/g, "\n");
532
+ }
533
+ function E(e) {
534
+ let t = e.replace(",", ".").split(":").map(Number);
535
+ return t.some((e) => !Number.isFinite(e)) ? NaN : t.length === 3 ? t[0] * 3600 + t[1] * 60 + t[2] : t.length === 2 ? t[0] * 60 + t[1] : t[0];
536
+ }
537
+ function D(e, t) {
538
+ let n = T(e).trim();
539
+ if (t === "vtt") {
540
+ let e = n.indexOf("\n");
541
+ n = (e === -1 ? "" : n.slice(e + 1)).trim();
542
+ }
543
+ let r = [];
544
+ for (let e of n.split(/\n{2,}/)) {
545
+ let t = e.split("\n").map((e) => e.trimEnd()), n = t[0]?.trim();
546
+ if (!n || n.startsWith("NOTE") || n === "STYLE" || n === "REGION") continue;
547
+ let i = t.findIndex((e) => w.test(e.trim()));
548
+ if (i === -1) continue;
549
+ let a = w.exec(t[i].trim());
550
+ if (!a) continue;
551
+ let o = E(a[1]), s = E(a[2]), c = t.slice(i + 1).filter((e) => e.trim().length > 0).join("\n");
552
+ if (!Number.isFinite(o) || !Number.isFinite(s) || s <= o || !c) continue;
553
+ let l = i > 0 ? t[i - 1]?.trim() : void 0;
554
+ r.push({
555
+ index: r.length + 1,
556
+ start: o,
557
+ end: s,
558
+ text: c,
559
+ ...l && !/^\d+$/.test(l) ? { id: l } : {},
560
+ ...a[3] ? { settings: a[3] } : {}
561
+ });
562
+ }
563
+ return r;
564
+ }
565
+ function O(e) {
566
+ return D(e, "srt");
567
+ }
568
+ function k(e) {
569
+ return D(e, "vtt");
570
+ }
571
+ function A(e, t = {}) {
572
+ let n = T(e).trimStart(), r = t.fileName?.toLowerCase().match(/\\.(vtt|srt)$/)?.[1], i = t.mimeType === "text/vtt" ? "vtt" : t.mimeType === "application/x-subrip" ? "srt" : void 0, a = n.startsWith("WEBVTT") ? "vtt" : w.test(n.split("\n")[0] ?? "") ? "srt" : void 0, o = t.format ?? i ?? r ?? a;
573
+ if (!o) return {
574
+ ok: !1,
575
+ error: {
576
+ code: "unsupported-format",
577
+ message: "Expected a WebVTT or SRT subtitle file."
578
+ }
579
+ };
580
+ let s = o === "vtt" ? k(n) : O(n);
581
+ return s.length === 0 ? {
582
+ ok: !1,
583
+ error: {
584
+ code: "malformed",
585
+ message: `No valid ${o.toUpperCase()} cues were found.`
586
+ }
587
+ } : {
588
+ ok: !0,
589
+ format: o,
590
+ cues: s
591
+ };
592
+ }
593
+ async function j(e, t) {
594
+ if (e.content !== void 0) {
595
+ let t = A(e.content, {
596
+ format: e.format,
597
+ fileName: e.label
598
+ });
599
+ if (!t.ok) throw Error(t.error.message);
600
+ return t.cues;
601
+ }
602
+ if (!e.src) throw Error("Subtitle track has no source.");
603
+ let n = await fetch(e.src, { signal: t });
604
+ if (!n.ok) throw Error(`Failed to fetch subtitles: ${n.status}`);
605
+ let r = A(await n.text(), {
606
+ format: e.format,
607
+ fileName: e.src,
608
+ mimeType: n.headers.get("content-type")?.split(";")[0]
609
+ });
610
+ if (!r.ok) throw Error(r.error.message);
611
+ return r.cues;
612
+ }
613
+ function M(e, t) {
614
+ let n = 0, r = e.length - 1;
615
+ for (; n <= r;) {
616
+ let i = n + r >> 1, a = e[i];
617
+ if (t < a.start) r = i - 1;
618
+ else if (t > a.end) n = i + 1;
619
+ else return a;
620
+ }
621
+ return null;
622
+ }
623
+ function N(e) {
624
+ let t = e.match(/#xywh=(\d+),(\d+),(\d+),(\d+)/);
625
+ return t ? {
626
+ src: e.replace(/#xywh=.*$/, ""),
627
+ x: Number(t[1]),
628
+ y: Number(t[2]),
629
+ w: Number(t[3]),
630
+ h: Number(t[4])
631
+ } : null;
632
+ }
633
+ function P(e) {
634
+ let t = e.replace(/\r\n/g, "\n"), n = t.indexOf("\n\n");
635
+ return n > 0 && (t = t.slice(n + 2)), t.trim().split(/\n\n+/).map((e) => {
636
+ let t = e.split("\n"), n = t.findIndex((e) => e.includes("-->"));
637
+ if (n === -1) return null;
638
+ let r = t[n].match(/(\d{2}:\d{2}:\d{2}[.,]\d{3})\s*-->\s*(\d{2}:\d{2}:\d{2}[.,]\d{3})/);
639
+ if (!r) return null;
640
+ let i = t.slice(n + 1).find((e) => e.trim().length > 0);
641
+ if (!i) return null;
642
+ let a = i.trim(), o = N(a), s = E(r[1]), c = E(r[2]);
643
+ return o ? {
644
+ start: s,
645
+ end: c,
646
+ src: o.src,
647
+ x: o.x,
648
+ y: o.y,
649
+ w: o.w,
650
+ h: o.h
651
+ } : {
652
+ start: s,
653
+ end: c,
654
+ src: a,
655
+ x: 0,
656
+ y: 0,
657
+ w: 160,
658
+ h: 90
659
+ };
660
+ }).filter((e) => e !== null);
661
+ }
662
+ function F(e, t) {
663
+ try {
664
+ return new URL(e, t).toString();
665
+ } catch {
666
+ return e;
667
+ }
668
+ }
669
+ async function I(e, t, n) {
670
+ let r = await fetch(e, { signal: t });
671
+ if (!r.ok) throw Error(`Failed to fetch thumbnail VTT: ${r.status}`);
672
+ let i = r.url || e, a = await r.text();
673
+ return P(n ? await n(a, i) : a).map((e) => (e.src = F(e.src, i), e));
674
+ }
675
+ function L(e, t) {
676
+ if (e.length === 0) return null;
677
+ let n = 0, r = e.length - 1;
678
+ for (; n <= r;) {
679
+ let i = n + r >> 1, a = e[i];
680
+ if (t < a.start) r = i - 1;
681
+ else if (t >= a.end) n = i + 1;
682
+ else return a;
683
+ }
684
+ return null;
505
685
  }
506
686
  //#endregion
507
687
  //#region src/state/slices.ts
508
- function w() {
509
- return new e(T());
688
+ function re() {
689
+ return new e(R());
510
690
  }
511
- function T() {
691
+ function R() {
512
692
  return {
513
693
  status: "idle",
514
694
  source: null,
@@ -528,6 +708,14 @@ function T() {
528
708
  aspectRatio: "default",
529
709
  activeSubtitle: null,
530
710
  subtitleTracks: [],
711
+ subtitleCues: [],
712
+ subtitleStatus: "idle",
713
+ subtitleError: null,
714
+ subtitleProviders: [],
715
+ subtitleSearchResults: [],
716
+ subtitleSearchStatus: "idle",
717
+ subtitleSearchError: null,
718
+ captionSettings: { ...S },
531
719
  activeQuality: "Auto",
532
720
  qualities: [],
533
721
  controlsVisible: !0,
@@ -548,10 +736,10 @@ function T() {
548
736
  contextMenuEnabled: !0,
549
737
  thumbnailCues: [],
550
738
  error: null,
551
- resumeProgress: null
739
+ resumeState: { status: "idle" }
552
740
  };
553
741
  }
554
- var E = (e) => ({
742
+ var ie = (e) => ({
555
743
  status: e.status,
556
744
  source: e.source,
557
745
  isPlaying: e.isPlaying,
@@ -563,165 +751,59 @@ var E = (e) => ({
563
751
  bufferedPercent: e.bufferedPercent,
564
752
  playbackRate: e.playbackRate,
565
753
  isLive: e.isLive,
566
- resumeProgress: e.resumeProgress
567
- }), D = (e) => ({
754
+ resumeState: e.resumeState
755
+ }), z = (e) => ({
568
756
  volume: e.volume,
569
757
  isMuted: e.isMuted
570
- }), O = (e) => ({
758
+ }), B = (e) => ({
571
759
  isLooping: e.isLooping,
572
760
  flip: e.flip,
573
761
  aspectRatio: e.aspectRatio,
574
762
  activeSubtitle: e.activeSubtitle,
575
763
  subtitleTracks: e.subtitleTracks,
764
+ subtitleCues: e.subtitleCues,
765
+ subtitleStatus: e.subtitleStatus,
766
+ subtitleError: e.subtitleError,
767
+ subtitleProviders: e.subtitleProviders,
768
+ subtitleSearchResults: e.subtitleSearchResults,
769
+ subtitleSearchStatus: e.subtitleSearchStatus,
770
+ subtitleSearchError: e.subtitleSearchError,
771
+ captionSettings: e.captionSettings,
576
772
  activeQuality: e.activeQuality,
577
773
  qualities: e.qualities
578
- }), k = (e) => ({
774
+ }), ae = (e) => ({
579
775
  controlsVisible: e.controlsVisible,
580
776
  capabilities: e.capabilities,
581
777
  isFullscreen: e.isFullscreen,
582
778
  infoPanelVisible: e.infoPanelVisible,
583
779
  notification: e.notification
584
- }), A = (e) => ({
780
+ }), V = (e) => ({
585
781
  controls: e.controls,
586
782
  settings: e.settings,
587
783
  layers: e.layers,
588
784
  contextMenuItems: e.contextMenuItems,
589
785
  contextMenuEnabled: e.contextMenuEnabled
590
- }), j = (e) => ({ thumbnailCues: e.thumbnailCues }), M = (e) => e.error;
591
- //#endregion
592
- //#region src/subtitle-parser.ts
593
- function N(e) {
594
- let t = e.replace(",", ".").split(":");
595
- 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]);
596
- }
597
- function P(e) {
598
- return e.trim().replace(/\r\n/g, "\n").split(/\n\n+/).map((e) => {
599
- let t = e.split("\n");
600
- if (t.length < 3) return null;
601
- let n = Number.parseInt(t[0], 10);
602
- if (Number.isNaN(n)) return null;
603
- let r = t[1].match(/(\d{2}:\d{2}:\d{2}[.,]\d{3})\s*-->\s*(\d{2}:\d{2}:\d{2}[.,]\d{3})/);
604
- if (!r) return null;
605
- let i = t.slice(2).join("\n");
606
- return {
607
- index: n,
608
- start: N(r[1]),
609
- end: N(r[2]),
610
- text: i
611
- };
612
- }).filter((e) => e !== null);
613
- }
614
- function F(e) {
615
- let t = e.replace(/\r\n/g, "\n"), n = t.indexOf("\n\n");
616
- n > 0 && (t = t.slice(n + 2));
617
- let r = t.trim().split(/\n\n+/), i = 0;
618
- return r.map((e) => {
619
- let t = e.split("\n");
620
- if (t[0]?.startsWith("NOTE") || t[0]?.startsWith("STYLE")) return null;
621
- let n = t.findIndex((e) => e.includes("-->"));
622
- if (n === -1) return null;
623
- let r = t[n].match(/(\d{2}:\d{2}:\d{2}[.,]\d{3})\s*-->\s*(\d{2}:\d{2}:\d{2}[.,]\d{3})/);
624
- if (!r) return null;
625
- let a = t.slice(n + 1).filter((e) => e.trim().length > 0);
626
- return a.length === 0 ? null : (i++, {
627
- index: i,
628
- start: N(r[1]),
629
- end: N(r[2]),
630
- text: a.join("\n")
631
- });
632
- }).filter((e) => e !== null);
633
- }
634
- async function I(e) {
635
- let t = await (await fetch(e.src)).text();
636
- return e.src.endsWith(".srt") ? P(t) : F(t);
637
- }
638
- function te(e, t) {
639
- let n = 0, r = e.length - 1;
640
- for (; n <= r;) {
641
- let i = n + r >> 1, a = e[i];
642
- if (t < a.start) r = i - 1;
643
- else if (t > a.end) n = i + 1;
644
- else return a;
645
- }
646
- return null;
647
- }
648
- function L(e) {
649
- let t = e.match(/#xywh=(\d+),(\d+),(\d+),(\d+)/);
650
- return t ? {
651
- src: e.replace(/#xywh=.*$/, ""),
652
- x: Number(t[1]),
653
- y: Number(t[2]),
654
- w: Number(t[3]),
655
- h: Number(t[4])
656
- } : null;
657
- }
658
- function R(e) {
659
- let t = e.replace(/\r\n/g, "\n"), n = t.indexOf("\n\n");
660
- return n > 0 && (t = t.slice(n + 2)), t.trim().split(/\n\n+/).map((e) => {
661
- let t = e.split("\n"), n = t.findIndex((e) => e.includes("-->"));
662
- if (n === -1) return null;
663
- let r = t[n].match(/(\d{2}:\d{2}:\d{2}[.,]\d{3})\s*-->\s*(\d{2}:\d{2}:\d{2}[.,]\d{3})/);
664
- if (!r) return null;
665
- let i = t.slice(n + 1).find((e) => e.trim().length > 0);
666
- if (!i) return null;
667
- let a = i.trim(), o = L(a), s = N(r[1]), c = N(r[2]);
668
- return o ? {
669
- start: s,
670
- end: c,
671
- src: o.src,
672
- x: o.x,
673
- y: o.y,
674
- w: o.w,
675
- h: o.h
676
- } : {
677
- start: s,
678
- end: c,
679
- src: a,
680
- x: 0,
681
- y: 0,
682
- w: 160,
683
- h: 90
684
- };
685
- }).filter((e) => e !== null);
686
- }
687
- function z(e, t) {
688
- try {
689
- return new URL(e, t).toString();
690
- } catch {
691
- return e;
692
- }
693
- }
694
- async function B(e, t, n) {
695
- let r = await fetch(e, { signal: t });
696
- if (!r.ok) throw Error(`Failed to fetch thumbnail VTT: ${r.status}`);
697
- let i = r.url || e, a = await r.text();
698
- return R(n ? await n(a, i) : a).map((e) => (e.src = z(e.src, i), e));
699
- }
700
- function V(e, t) {
701
- if (e.length === 0) return null;
702
- let n = 0, r = e.length - 1;
703
- for (; n <= r;) {
704
- let i = n + r >> 1, a = e[i];
705
- if (t < a.start) r = i - 1;
706
- else if (t >= a.end) n = i + 1;
707
- else return a;
708
- }
709
- return null;
710
- }
711
- //#endregion
712
- //#region src/player.ts
713
- var H = [
786
+ }), H = (e) => ({ thumbnailCues: e.thumbnailCues }), U = (e) => e.error, W = [
714
787
  "default",
715
788
  "16:9",
716
789
  "4:3",
717
790
  "21:9",
718
791
  "cover",
719
792
  "fill"
720
- ], ne = {
793
+ ], oe = 5e3, se = 2;
794
+ function ce(e) {
795
+ try {
796
+ let t = new URL(e, typeof document > "u" ? void 0 : document.baseURI);
797
+ return t.search = "", t.hash = "", t.href;
798
+ } catch {
799
+ return e.split(/[?#]/, 1)[0] ?? e;
800
+ }
801
+ }
802
+ var le = {
721
803
  "16:9": "16 / 9",
722
804
  "4:3": "4 / 3",
723
805
  "21:9": "21 / 9"
724
- }, re = {
806
+ }, G = {
725
807
  default: "default",
726
808
  "16:9": "16-9",
727
809
  "4:3": "4-3",
@@ -729,143 +811,311 @@ var H = [
729
811
  cover: "cover",
730
812
  fill: "fill"
731
813
  };
732
- function ie(e) {
814
+ function ue(e) {
733
815
  e.classList.remove("vplayer--media-default", "vplayer--media-16-9", "vplayer--media-4-3", "vplayer--media-21-9", "vplayer--media-cover", "vplayer--media-fill");
734
816
  }
735
- function ae(e) {
736
- return typeof e == "string" && e in re ? e : "default";
817
+ function de(e) {
818
+ return typeof e == "string" && e in G ? e : "default";
737
819
  }
738
- function U(e) {
820
+ function fe(e) {
739
821
  return e === "cover" ? "cover" : e === "fill" ? "fill" : "contain";
740
822
  }
741
- function W(e) {
742
- let r = w(), i = { ...e }, o = new t(), s = new m(), c = new a(i.lang);
823
+ function K(e) {
824
+ return {
825
+ ...e,
826
+ id: e.id ?? `${e.local ? "local" : "track"}:${e.src ?? e.label}:${e.lang}`
827
+ };
828
+ }
829
+ function q(e) {
830
+ let r = re(), i = { ...e }, o = new t(), s = new p(), c = new a(i.lang);
743
831
  i.translations && c.addTranslations(i.lang ?? "en", i.translations);
744
- let l = new n(), u = i.reconnectMax ?? 3, p = i.reconnectSleep ?? 1500, _ = null, v = null, y = null, b = null, x = null, S = 0, T = null, E = null, D = new g(), O = 0, k = !1, A = !1, j = null, M = [], N = !1;
745
- function P(e) {
832
+ let l = new n(), u = i.reconnectMax ?? 3, ee = i.reconnectSleep ?? 1500, h = null, g = null, _ = null, v = 0, y = NaN, b = null, C = 0, w = null, T = null, E = null, D = null, O = new te(), k = 0, A = !1, M = null, N = [], P = !1;
833
+ function F(e) {
834
+ let t = e.playbackProgress?.id ?? (e.playbackProgress?.normalizeUrl === !1 ? e.src : ce(e.src));
746
835
  return {
747
- generation: O,
748
- id: e.playbackProgress?.id ?? e.src,
749
- store: e.playbackProgress?.store ?? D
836
+ generation: k,
837
+ id: t,
838
+ store: e.playbackProgress?.store ?? O
750
839
  };
751
840
  }
752
- let F = P(i);
753
- function I() {
754
- if (N) return;
755
- let e = M.shift();
756
- e && (N = !0, (e.kind === "save" ? e.target.store.save(e.target.id, e.progress) : e.target.store.clear(e.target.id)).catch((t) => {
841
+ let L = F(i);
842
+ function R() {
843
+ if (P) return;
844
+ let e = N.shift();
845
+ e && (P = !0, (e.kind === "save" ? e.target.store.save(e.target.id, e.progress) : e.target.store.clear(e.target.id)).catch((t) => {
757
846
  console.warn(e.kind === "save" ? "[vplayer] playback progress save failed:" : "[vplayer] playback progress clear failed:", t);
758
847
  }).finally(() => {
759
- N = !1, I();
848
+ P = !1, R();
760
849
  }));
761
850
  }
762
- function te(e, t) {
763
- let n = M.at(-1);
764
- n?.kind === "save" && n.target.generation === e.generation ? n.progress = t : M.push({
851
+ function ie(e, t) {
852
+ let n = N.at(-1);
853
+ n?.kind === "save" && n.target.generation === e.generation ? n.progress = t : N.push({
765
854
  kind: "save",
766
855
  target: e,
767
856
  progress: t
768
- }), I();
857
+ }), R();
769
858
  }
770
- function L(e) {
771
- M.push({
859
+ function z(e) {
860
+ N.push({
772
861
  kind: "clear",
773
862
  target: e
774
- }), I();
863
+ }), R();
775
864
  }
776
- function R(e = F, t = v) {
777
- !t || t.ended || !Number.isFinite(t.currentTime) || t.currentTime < 0 || !f(t.duration) || te(e, {
865
+ function B(e = L, t = g) {
866
+ !t || t.ended || r.state.resumeState.status === "prompt" || !Number.isFinite(t.currentTime) || t.currentTime <= 3 || !f(t.duration) || (v = Date.now(), y = t.currentTime, ie(e, {
778
867
  time: t.currentTime,
779
868
  duration: t.duration
780
- });
869
+ }));
870
+ }
871
+ function ae(e) {
872
+ !r.state.isPlaying || Date.now() - v < oe || Number.isFinite(y) && Math.abs(e.currentTime - y) < se || B(L, e);
781
873
  }
782
- function z() {
783
- O++, F = P(i), k = !1, A = !1, Y(), r.setState((e) => ({
874
+ function V() {
875
+ k++, L = F(i), A = !1, v = 0, y = NaN, r.setState((e) => ({
784
876
  ...e,
785
- resumeProgress: null
877
+ resumeState: { status: "idle" }
878
+ }));
879
+ }
880
+ function H(e) {
881
+ if (A || !f(e.duration)) return;
882
+ A = !0;
883
+ let t = L, n = e.duration;
884
+ r.setState((e) => ({
885
+ ...e,
886
+ resumeState: { status: "loading" }
887
+ })), t.store.load(t.id).then((i) => {
888
+ if (t.generation === k && e === g) {
889
+ if (!i || !Number.isFinite(i.time) || !Number.isFinite(i.duration) || i.time <= 3 || i.time >= n - 3 || Math.abs(i.duration - n) > Math.max(1, n * .01)) {
890
+ r.setState((e) => ({
891
+ ...e,
892
+ resumeState: { status: "idle" }
893
+ }));
894
+ return;
895
+ }
896
+ r.setState((e) => ({
897
+ ...e,
898
+ resumeState: {
899
+ status: "prompt",
900
+ progress: i
901
+ }
902
+ }));
903
+ }
904
+ }).catch((n) => {
905
+ t.generation === k && e === g && r.setState((e) => ({
906
+ ...e,
907
+ resumeState: { status: "idle" }
908
+ })), console.warn("[vplayer] playback progress load failed:", n);
909
+ });
910
+ }
911
+ function U(e) {
912
+ r.setState((t) => {
913
+ let n = new Map(t.subtitleTracks.map((e) => [e.id, e]));
914
+ for (let t of e) {
915
+ let e = K(t);
916
+ n.set(e.id, e);
917
+ }
918
+ return {
919
+ ...t,
920
+ subtitleTracks: [...n.values()]
921
+ };
922
+ });
923
+ }
924
+ function q(e) {
925
+ T?.abort();
926
+ let t = new AbortController();
927
+ T = t, r.setState((t) => ({
928
+ ...t,
929
+ activeSubtitle: e,
930
+ subtitleCues: [],
931
+ subtitleStatus: "loading",
932
+ subtitleError: null
933
+ })), j(e, t.signal).then((e) => {
934
+ t.signal.aborted || r.setState((t) => ({
935
+ ...t,
936
+ subtitleCues: e,
937
+ subtitleStatus: "ready",
938
+ subtitleError: null
939
+ }));
940
+ }, (e) => {
941
+ t.signal.aborted || r.setState((t) => ({
942
+ ...t,
943
+ subtitleCues: [],
944
+ subtitleStatus: "error",
945
+ subtitleError: e instanceof Error ? e.message : String(e)
946
+ }));
947
+ });
948
+ }
949
+ function J() {
950
+ let e = (i.subtitleProviders ?? []).map(({ id: e, label: t }) => ({
951
+ id: e,
952
+ label: t
953
+ }));
954
+ r.setState((t) => ({
955
+ ...t,
956
+ subtitleProviders: e,
957
+ subtitleSearchResults: [],
958
+ subtitleSearchStatus: "idle",
959
+ subtitleSearchError: null
786
960
  }));
787
961
  }
788
- function V(e) {
789
- if (k || !f(e.duration)) return;
790
- k = !0;
791
- let t = F, n = e.duration;
792
- t.store.load(t.id).then((i) => {
793
- !i || t.generation !== O || e !== v || A || e.currentTime !== 0 || !Number.isFinite(i.time) || !Number.isFinite(i.duration) || i.time <= 3 || i.time >= n - 3 || Math.abs(i.duration - n) > Math.max(1, n * .01) || r.setState((e) => ({
962
+ function pe(e = {}) {
963
+ E?.abort();
964
+ let t = i.subtitleProviders ?? [], n = e.providerId ? t.filter((t) => t.id === e.providerId) : t;
965
+ if (n.length === 0) {
966
+ r.setState((e) => ({
794
967
  ...e,
795
- resumeProgress: i
968
+ subtitleSearchResults: [],
969
+ subtitleSearchStatus: "idle",
970
+ subtitleSearchError: null
796
971
  }));
797
- }).catch((e) => console.warn("[vplayer] playback progress load failed:", e));
972
+ return;
973
+ }
974
+ let a = new AbortController();
975
+ E = a;
976
+ let o = {
977
+ ...e,
978
+ title: e.title ?? i.title
979
+ };
980
+ r.setState((e) => ({
981
+ ...e,
982
+ subtitleSearchResults: [],
983
+ subtitleSearchStatus: "loading",
984
+ subtitleSearchError: null
985
+ })), Promise.allSettled(n.map(async (e) => {
986
+ let t = await e.search(o, a.signal);
987
+ return (Array.isArray(t) ? t : t.items).map((t) => Object.assign({}, t, {
988
+ providerId: e.id,
989
+ providerLabel: e.label
990
+ }));
991
+ })).then((e) => {
992
+ if (a.signal.aborted) return;
993
+ let t = e.flatMap((e) => e.status === "fulfilled" ? e.value : []), i = e.flatMap((e, t) => e.status === "rejected" ? [`${n[t]?.label ?? "Subtitle provider"}: ${e.reason instanceof Error ? e.reason.message : String(e.reason)}`] : []);
994
+ r.setState((n) => ({
995
+ ...n,
996
+ subtitleSearchResults: t,
997
+ subtitleSearchStatus: i.length === e.length ? "error" : "ready",
998
+ subtitleSearchError: i.length > 0 ? i.join("; ") : null
999
+ }));
1000
+ });
1001
+ }
1002
+ function me(e) {
1003
+ T?.abort();
1004
+ let t = (i.subtitleProviders ?? []).find((t) => t.id === e.providerId);
1005
+ if (!t) {
1006
+ r.setState((t) => ({
1007
+ ...t,
1008
+ subtitleStatus: "error",
1009
+ subtitleError: `Subtitle provider "${e.providerLabel}" is no longer available.`
1010
+ }));
1011
+ return;
1012
+ }
1013
+ let n = new AbortController();
1014
+ T = n, r.setState((e) => ({
1015
+ ...e,
1016
+ activeSubtitle: null,
1017
+ subtitleCues: [],
1018
+ subtitleStatus: "loading",
1019
+ subtitleError: null
1020
+ })), (async () => {
1021
+ try {
1022
+ let i = await t.fetch(e, n.signal), a = K({
1023
+ id: `provider:${t.id}:${e.id}`,
1024
+ lang: e.language,
1025
+ label: e.label,
1026
+ format: i.format ?? e.format,
1027
+ ...i.content === void 0 ? { src: i.src } : { content: i.content }
1028
+ }), o = await j(a, n.signal);
1029
+ if (n.signal.aborted) return;
1030
+ U([a]), r.setState((e) => ({
1031
+ ...e,
1032
+ activeSubtitle: a,
1033
+ subtitleCues: o,
1034
+ subtitleStatus: "ready",
1035
+ subtitleError: null
1036
+ }));
1037
+ } catch (e) {
1038
+ if (n.signal.aborted) return;
1039
+ r.setState((t) => ({
1040
+ ...t,
1041
+ subtitleCues: [],
1042
+ subtitleStatus: "error",
1043
+ subtitleError: e instanceof Error ? e.message : String(e)
1044
+ }));
1045
+ }
1046
+ })();
798
1047
  }
799
- function W() {
800
- E && typeof navigator < "u" && "mediaSession" in navigator && navigator.mediaSession.metadata === E && (navigator.mediaSession.metadata = null), E = null;
1048
+ i.subtitles?.length && U(i.subtitles), J();
1049
+ function he() {
1050
+ D && typeof navigator < "u" && "mediaSession" in navigator && navigator.mediaSession.metadata === D && (navigator.mediaSession.metadata = null), D = null;
801
1051
  }
802
- function G() {
1052
+ function ge() {
803
1053
  if (typeof navigator > "u" || !("mediaSession" in navigator) || typeof MediaMetadata > "u") return;
804
1054
  let e = i.title?.trim();
805
1055
  if (!e) {
806
- W();
1056
+ he();
807
1057
  return;
808
1058
  }
809
1059
  let t = new MediaMetadata({
810
1060
  title: e,
811
1061
  artwork: i.poster ? [{ src: i.poster }] : []
812
1062
  });
813
- navigator.mediaSession.metadata = t, E = t;
1063
+ navigator.mediaSession.metadata = t, D = t;
814
1064
  }
815
- function K() {
1065
+ function _e() {
816
1066
  l.register({
817
1067
  key: "Space",
818
1068
  description: "Toggle play/pause",
819
1069
  handler: (e) => {
820
- e.preventDefault(), J.togglePlay();
1070
+ e.preventDefault(), Y.togglePlay();
821
1071
  }
822
1072
  }), l.register({
823
1073
  key: "KeyK",
824
1074
  description: "Toggle play/pause",
825
1075
  handler: (e) => {
826
- e.preventDefault(), J.togglePlay();
1076
+ e.preventDefault(), Y.togglePlay();
827
1077
  }
828
1078
  }), l.register({
829
1079
  key: "KeyL",
830
1080
  description: "Toggle loop",
831
1081
  handler: (e) => {
832
- e.preventDefault(), J.toggleLoop();
1082
+ e.preventDefault(), Y.toggleLoop();
833
1083
  }
834
1084
  }), l.register({
835
1085
  key: "KeyI",
836
1086
  description: "Toggle info panel",
837
1087
  handler: (e) => {
838
- e.preventDefault(), J.toggleInfoPanel();
1088
+ e.preventDefault(), Y.toggleInfoPanel();
839
1089
  }
840
1090
  }), l.register({
841
1091
  key: "KeyF",
842
1092
  description: "Toggle fullscreen",
843
1093
  handler: (e) => {
844
- e.preventDefault(), J.toggleFullscreen();
1094
+ e.preventDefault(), Y.toggleFullscreen();
845
1095
  }
846
1096
  }), l.register({
847
1097
  key: "KeyA",
848
1098
  description: "Cycle aspect ratio",
849
1099
  handler: (e) => {
850
- e.preventDefault(), J.cycleAspectRatio();
1100
+ e.preventDefault(), Y.cycleAspectRatio();
851
1101
  }
852
1102
  }), l.register({
853
1103
  key: "KeyM",
854
1104
  description: "Toggle mute",
855
1105
  handler: (e) => {
856
- e.preventDefault(), J.toggleMute();
1106
+ e.preventDefault(), Y.toggleMute();
857
1107
  }
858
1108
  }), l.register({
859
1109
  key: "ArrowLeft",
860
1110
  description: "Seek backward 5s",
861
1111
  handler: (e) => {
862
- e.preventDefault(), J.skip(-5);
1112
+ e.preventDefault(), Y.skip(-5);
863
1113
  }
864
1114
  }), l.register({
865
1115
  key: "ArrowRight",
866
1116
  description: "Seek forward 5s",
867
1117
  handler: (e) => {
868
- e.preventDefault(), J.skip(5);
1118
+ e.preventDefault(), Y.skip(5);
869
1119
  }
870
1120
  }), l.register({
871
1121
  key: "ArrowUp",
@@ -873,7 +1123,7 @@ function W(e) {
873
1123
  handler: (e) => {
874
1124
  e.preventDefault();
875
1125
  let t = Math.min(1, r.state.volume + .1);
876
- J.setVolume(t);
1126
+ Y.setVolume(t);
877
1127
  }
878
1128
  }), l.register({
879
1129
  key: "ArrowDown",
@@ -881,52 +1131,58 @@ function W(e) {
881
1131
  handler: (e) => {
882
1132
  e.preventDefault();
883
1133
  let t = Math.max(0, r.state.volume - .1);
884
- J.setVolume(t);
1134
+ Y.setVolume(t);
885
1135
  }
886
1136
  });
887
1137
  }
888
- i.defaultHotkeys !== !1 && K();
889
- function q() {
1138
+ i.defaultHotkeys !== !1 && _e();
1139
+ function ve() {
890
1140
  if (typeof document > "u") return;
891
1141
  let e = document;
892
1142
  r.setState((t) => ({
893
1143
  ...t,
894
1144
  isFullscreen: !!(document.fullscreenElement || e.webkitFullscreenElement),
895
- capabilities: d(v?.element ?? void 0, _)
1145
+ capabilities: d(g?.element ?? void 0, h)
896
1146
  }));
897
1147
  }
898
- let J = {
1148
+ let Y = {
899
1149
  play: () => {
900
- v?.play();
1150
+ g?.play();
901
1151
  },
902
- pause: () => v?.pause(),
1152
+ pause: () => g?.pause(),
903
1153
  togglePlay: () => {
904
- let e = v;
1154
+ let e = g;
905
1155
  e && (e.paused || e.ended ? e.play() : e.pause());
906
1156
  },
907
1157
  resumeFromSavedProgress: () => {
908
- let e = r.state.resumeProgress;
909
- e && (r.setState((e) => ({
1158
+ let e = r.state.resumeState;
1159
+ e.status === "prompt" && (r.setState((e) => ({
910
1160
  ...e,
911
- resumeProgress: null
912
- })), v?.seek(e.time), v?.play());
1161
+ resumeState: { status: "idle" }
1162
+ })), g?.seek(e.progress.time), g?.play());
913
1163
  },
914
1164
  startPlaybackOver: () => {
915
- let e = F;
1165
+ let e = L;
916
1166
  r.setState((e) => ({
917
1167
  ...e,
918
- resumeProgress: null
919
- })), v?.seek(0), L(e);
1168
+ resumeState: { status: "idle" }
1169
+ })), g?.seek(0), z(e);
1170
+ },
1171
+ dismissSavedProgress: () => {
1172
+ r.setState((e) => ({
1173
+ ...e,
1174
+ resumeState: { status: "idle" }
1175
+ }));
920
1176
  },
921
- seek: (e) => v?.seek(e),
1177
+ seek: (e) => g?.seek(e),
922
1178
  skip: (e) => {
923
- let t = v;
1179
+ let t = g;
924
1180
  if (!t) return;
925
1181
  let n = f(t.duration) ? t.duration : Infinity, r = Math.max(0, Math.min(t.currentTime + e, n));
926
1182
  t.seek(r);
927
1183
  },
928
1184
  setVolume: (e) => {
929
- let t = v;
1185
+ let t = g;
930
1186
  if (!t) return;
931
1187
  let n = Math.max(0, Math.min(1, e));
932
1188
  t.setVolume(n), n > 0 && t.setMuted(!1), r.setState((e) => ({
@@ -936,34 +1192,82 @@ function W(e) {
936
1192
  }));
937
1193
  },
938
1194
  toggleMute: () => {
939
- let e = v;
1195
+ let e = g;
940
1196
  e && (e.setMuted(!e.muted), r.setState((t) => ({
941
1197
  ...t,
942
1198
  isMuted: e.muted
943
1199
  })));
944
1200
  },
945
1201
  setPlaybackRate: (e) => {
946
- let t = v;
1202
+ let t = g;
947
1203
  t && (t.setPlaybackRate(e), r.setState((e) => ({
948
1204
  ...e,
949
1205
  playbackRate: t.playbackRate
950
1206
  })));
951
1207
  },
952
1208
  toggleFullscreen: () => {
953
- if (!_ || typeof document > "u") return;
954
- let e = _, t = document, n = !!(document.fullscreenElement || t.webkitFullscreenElement), r = () => {
955
- _?.focus({ preventScroll: !0 }), q();
956
- }, i = n ? typeof document.exitFullscreen == "function" ? document.exitFullscreen() : t.webkitExitFullscreen?.() : typeof _.requestFullscreen == "function" ? _.requestFullscreen() : e.webkitRequestFullscreen?.();
1209
+ if (!h || typeof document > "u") return;
1210
+ let e = h, t = document, n = !!(document.fullscreenElement || t.webkitFullscreenElement), r = () => {
1211
+ h?.focus({ preventScroll: !0 }), ve();
1212
+ }, i = n ? typeof document.exitFullscreen == "function" ? document.exitFullscreen() : t.webkitExitFullscreen?.() : typeof h.requestFullscreen == "function" ? h.requestFullscreen() : e.webkitRequestFullscreen?.();
957
1213
  Promise.resolve(i).then(r, r);
958
1214
  },
959
1215
  togglePiP: () => {
960
- let e = v;
1216
+ let e = g;
961
1217
  !e || typeof document > "u" || (document.pictureInPictureElement ? e.exitPictureInPicture() : e.requestPictureInPicture());
962
1218
  },
963
1219
  setActiveSubtitle: (e) => {
1220
+ if (!e) {
1221
+ T?.abort(), r.setState((e) => ({
1222
+ ...e,
1223
+ activeSubtitle: null,
1224
+ subtitleCues: [],
1225
+ subtitleStatus: "idle",
1226
+ subtitleError: null
1227
+ }));
1228
+ return;
1229
+ }
1230
+ q(e);
1231
+ },
1232
+ addSubtitleTrack: (e) => {
1233
+ let t = K(e);
1234
+ U([t]), q(t);
1235
+ },
1236
+ removeSubtitleTrack: (e) => {
1237
+ r.state.activeSubtitle?.id === e && Y.setActiveSubtitle(null), r.setState((t) => ({
1238
+ ...t,
1239
+ subtitleTracks: t.subtitleTracks.filter((t) => t.id !== e)
1240
+ }));
1241
+ },
1242
+ searchSubtitles: pe,
1243
+ selectSubtitleResult: me,
1244
+ clearSubtitleSearch: () => {
1245
+ E?.abort(), E = null, r.setState((e) => ({
1246
+ ...e,
1247
+ subtitleSearchResults: [],
1248
+ subtitleSearchStatus: "idle",
1249
+ subtitleSearchError: null
1250
+ }));
1251
+ },
1252
+ setCaptionSettings: (e) => {
964
1253
  r.setState((t) => ({
965
1254
  ...t,
966
- activeSubtitle: e
1255
+ captionSettings: {
1256
+ ...t.captionSettings,
1257
+ ...e,
1258
+ fontScale: Math.max(50, Math.min(200, e.fontScale ?? t.captionSettings.fontScale)),
1259
+ textOpacity: Math.max(0, Math.min(1, e.textOpacity ?? t.captionSettings.textOpacity)),
1260
+ backgroundOpacity: Math.max(0, Math.min(1, e.backgroundOpacity ?? t.captionSettings.backgroundOpacity)),
1261
+ position: Math.max(-20, Math.min(30, e.position ?? t.captionSettings.position)),
1262
+ lineHeight: Math.max(1, Math.min(2, e.lineHeight ?? t.captionSettings.lineHeight)),
1263
+ delay: Math.max(-10, Math.min(10, e.delay ?? t.captionSettings.delay))
1264
+ }
1265
+ }));
1266
+ },
1267
+ resetCaptionSettings: () => {
1268
+ r.setState((e) => ({
1269
+ ...e,
1270
+ captionSettings: { ...S }
967
1271
  }));
968
1272
  },
969
1273
  setActiveQuality: (e) => {
@@ -973,7 +1277,7 @@ function W(e) {
973
1277
  }));
974
1278
  },
975
1279
  takeScreenshot: async () => {
976
- let e = v;
1280
+ let e = g;
977
1281
  if (!e) return;
978
1282
  let t = await e.screenshot();
979
1283
  if (!t) return;
@@ -981,7 +1285,7 @@ function W(e) {
981
1285
  r.href = n, r.download = `vplayer-screenshot-${Date.now()}.png`, r.click(), URL.revokeObjectURL(n);
982
1286
  },
983
1287
  setFlip: (e) => {
984
- let t = v?.element;
1288
+ let t = g?.element;
985
1289
  if (!t) return;
986
1290
  let n = "";
987
1291
  e === "horizontal" && (n = "scaleX(-1)"), e === "vertical" && (n = "scaleY(-1)"), t.style.transform = n, r.setState((t) => ({
@@ -990,20 +1294,20 @@ function W(e) {
990
1294
  }));
991
1295
  },
992
1296
  setAspectRatio: (e) => {
993
- let t = ae(e), n = v?.element;
1297
+ let t = de(e), n = g?.element;
994
1298
  if (!n) return;
995
- let i = ne[t];
996
- i ? n.style.setProperty("--vplayer-media-aspect-ratio", i) : n.style.removeProperty("--vplayer-media-aspect-ratio"), n.style.objectFit = U(t), n.style.setProperty("--vplayer-media-object-fit", U(t)), _ && (ie(_), _.classList.add(`vplayer--media-${re[t]}`)), r.setState((e) => ({
1299
+ let i = le[t];
1300
+ i ? n.style.setProperty("--vplayer-media-aspect-ratio", i) : n.style.removeProperty("--vplayer-media-aspect-ratio"), n.style.objectFit = fe(t), n.style.setProperty("--vplayer-media-object-fit", fe(t)), h && (ue(h), h.classList.add(`vplayer--media-${G[t]}`)), r.setState((e) => ({
997
1301
  ...e,
998
1302
  aspectRatio: t
999
1303
  }));
1000
1304
  },
1001
1305
  cycleAspectRatio: () => {
1002
- let e = r.state.aspectRatio, t = H[(H.indexOf(e) + 1) % H.length] ?? "default";
1003
- J.setAspectRatio(t);
1306
+ let e = r.state.aspectRatio, t = W[(W.indexOf(e) + 1) % W.length] ?? "default";
1307
+ Y.setAspectRatio(t);
1004
1308
  },
1005
1309
  toggleLoop: () => {
1006
- let e = v;
1310
+ let e = g;
1007
1311
  e && (e.setLooping(!e.looping), r.setState((t) => ({
1008
1312
  ...t,
1009
1313
  isLooping: e.looping
@@ -1016,13 +1320,10 @@ function W(e) {
1016
1320
  }));
1017
1321
  }
1018
1322
  };
1019
- function oe(e) {
1323
+ function ye(e) {
1020
1324
  return [
1021
1325
  e.on("play", () => {
1022
- A = !0, r.setState((e) => ({
1023
- ...e,
1024
- resumeProgress: null
1025
- })), G(), r.setState((e) => ({
1326
+ ge(), r.setState((e) => ({
1026
1327
  ...e,
1027
1328
  status: "playing",
1028
1329
  isPlaying: !0,
@@ -1030,7 +1331,7 @@ function W(e) {
1030
1331
  isBuffering: !1,
1031
1332
  isEnded: !1,
1032
1333
  error: null
1033
- })), S = 0;
1334
+ })), C = 0;
1034
1335
  }),
1035
1336
  e.on("pause", () => {
1036
1337
  r.setState((e) => ({
@@ -1040,15 +1341,15 @@ function W(e) {
1040
1341
  isPaused: !e.isEnded,
1041
1342
  isBuffering: !1,
1042
1343
  controlsVisible: !0
1043
- })), e.ended || R(F, e);
1344
+ })), e.ended || B(L, e);
1044
1345
  }),
1045
1346
  e.on("ended", () => {
1046
- Y();
1047
- for (let e = M.length - 1; e >= 0; e--) {
1048
- let t = M[e];
1049
- t?.kind === "save" && t.target.generation === F.generation && M.splice(e, 1);
1347
+ v = 0, y = NaN;
1348
+ for (let e = N.length - 1; e >= 0; e--) {
1349
+ let t = N[e];
1350
+ t?.kind === "save" && t.target.generation === L.generation && N.splice(e, 1);
1050
1351
  }
1051
- L(F), r.setState((e) => ({
1352
+ z(L), r.setState((e) => ({
1052
1353
  ...e,
1053
1354
  status: "ended",
1054
1355
  isPlaying: !1,
@@ -1056,17 +1357,17 @@ function W(e) {
1056
1357
  isBuffering: !1,
1057
1358
  isEnded: !0,
1058
1359
  controlsVisible: !0,
1059
- resumeProgress: null
1360
+ resumeState: { status: "idle" }
1060
1361
  })), i.onEnded?.();
1061
1362
  }),
1062
1363
  e.on("timeupdate", () => {
1063
1364
  r.setState((t) => ({
1064
1365
  ...t,
1065
1366
  currentTime: e.currentTime
1066
- })), i.onTimeUpdate?.(e.currentTime);
1367
+ })), i.onTimeUpdate?.(e.currentTime), ae(e);
1067
1368
  }),
1068
1369
  e.on("loadedmetadata", () => {
1069
- x !== null && (clearTimeout(x), x = null), S = 0, r.setState((t) => ({
1370
+ b !== null && (clearTimeout(b), b = null), C = 0, r.setState((t) => ({
1070
1371
  ...t,
1071
1372
  status: t.status === "idle" || t.status === "loading" || t.status === "error" ? "ready" : t.status,
1072
1373
  duration: f(e.duration) ? e.duration : 0,
@@ -1075,7 +1376,7 @@ function W(e) {
1075
1376
  isMuted: e.muted,
1076
1377
  playbackRate: e.playbackRate,
1077
1378
  error: null
1078
- })), V(e);
1379
+ })), H(e);
1079
1380
  }),
1080
1381
  e.on("progress", () => {
1081
1382
  let t = e.buffered;
@@ -1094,7 +1395,7 @@ function W(e) {
1094
1395
  }));
1095
1396
  }),
1096
1397
  e.on("canplay", () => {
1097
- x !== null && (clearTimeout(x), x = null), S = 0, r.setState((e) => ({
1398
+ b !== null && (clearTimeout(b), b = null), C = 0, r.setState((e) => ({
1098
1399
  ...e,
1099
1400
  status: e.isPlaying ? "playing" : "ready",
1100
1401
  isBuffering: !1,
@@ -1106,7 +1407,7 @@ function W(e) {
1106
1407
  ...t,
1107
1408
  duration: f(e.duration) ? e.duration : 0,
1108
1409
  isLive: !f(e.duration)
1109
- })), V(e);
1410
+ })), H(e);
1110
1411
  }),
1111
1412
  e.on("seeking", () => {
1112
1413
  r.setState((e) => ({
@@ -1118,7 +1419,7 @@ function W(e) {
1118
1419
  r.setState((e) => ({
1119
1420
  ...e,
1120
1421
  status: e.isPlaying ? "playing" : "ready"
1121
- }));
1422
+ })), B(L, e);
1122
1423
  }),
1123
1424
  e.on("playing", () => {
1124
1425
  r.setState((e) => ({
@@ -1149,7 +1450,7 @@ function W(e) {
1149
1450
  status: e.isPlaying ? e.status : "paused",
1150
1451
  error: {
1151
1452
  message: t,
1152
- reconnectAttempt: S,
1453
+ reconnectAttempt: C,
1153
1454
  isReconnecting: !1
1154
1455
  }
1155
1456
  })), i.onError?.(t);
@@ -1161,35 +1462,26 @@ function W(e) {
1161
1462
  status: "error",
1162
1463
  error: {
1163
1464
  message: t,
1164
- reconnectAttempt: S,
1465
+ reconnectAttempt: C,
1165
1466
  isReconnecting: !1
1166
1467
  }
1167
- })), i.onError?.(t), o.emit("video:error", { message: t }), S < u && (r.setState((e) => ({
1468
+ })), i.onError?.(t), o.emit("video:error", { message: t }), C < u && (r.setState((e) => ({
1168
1469
  ...e,
1169
1470
  error: {
1170
1471
  message: t,
1171
- reconnectAttempt: S,
1472
+ reconnectAttempt: C,
1172
1473
  isReconnecting: !0
1173
1474
  }
1174
- })), o.emit("video:reconnecting", { attempt: S + 1 }), x !== null && clearTimeout(x), x = setTimeout(() => {
1175
- x = null, S++, o.emit("video:reconnect", { attempt: S }), e.load();
1176
- }, p));
1475
+ })), o.emit("video:reconnecting", { attempt: C + 1 }), b !== null && clearTimeout(b), b = setTimeout(() => {
1476
+ b = null, C++, o.emit("video:reconnect", { attempt: C }), e.load();
1477
+ }, ee));
1177
1478
  })
1178
1479
  ];
1179
1480
  }
1180
- function se() {
1181
- Y(), b = setInterval(() => R(), 5e3);
1182
- }
1183
- function Y() {
1184
- b !== null && (clearInterval(b), b = null);
1185
- }
1186
- let ce = r.subscribe(() => {
1187
- let e = r.state;
1188
- e.isPlaying && e.duration > 0 && !e.isLive ? b === null && se() : Y();
1189
- }), X = null;
1190
- function le() {
1481
+ let X = null;
1482
+ function be() {
1191
1483
  if (!i.persistPreferences) return;
1192
- let e = s.get(h.VOLUME), t = s.get(h.MUTED), n = s.get(h.PLAYBACK_RATE), a = s.get(h.LOOP), o = s.get(h.FLIP), c = s.get(h.ASPECT_RATIO);
1484
+ 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), l = s.get(m.CAPTION_SETTINGS);
1193
1485
  r.setState((r) => ({
1194
1486
  ...r,
1195
1487
  volume: e ?? r.volume,
@@ -1197,17 +1489,25 @@ function W(e) {
1197
1489
  playbackRate: n ?? r.playbackRate,
1198
1490
  isLooping: a ?? r.isLooping,
1199
1491
  flip: o ?? r.flip,
1200
- aspectRatio: ae(c)
1492
+ aspectRatio: de(c),
1493
+ captionSettings: l ? {
1494
+ ...S,
1495
+ ...l,
1496
+ backgroundOpacity: Math.max(0, Math.min(1, l.backgroundOpacity))
1497
+ } : r.captionSettings
1201
1498
  })), X = r.subscribe(() => {
1202
1499
  let e = r.state;
1203
- e.volume !== 1 && s.set(h.VOLUME, e.volume), e.isMuted && s.set(h.MUTED, !0), e.playbackRate !== 1 && s.set(h.PLAYBACK_RATE, e.playbackRate), e.isLooping ? s.set(h.LOOP, !0) : s.remove(h.LOOP), e.flip === "normal" ? s.remove(h.FLIP) : s.set(h.FLIP, e.flip), e.aspectRatio === "default" ? s.remove(h.ASPECT_RATIO) : s.set(h.ASPECT_RATIO, e.aspectRatio);
1500
+ 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), s.set(m.CAPTION_SETTINGS, e.captionSettings);
1204
1501
  });
1205
1502
  }
1206
- function ue() {
1207
- X &&= (X(), null);
1503
+ function xe() {
1504
+ if (X) {
1505
+ let e = X;
1506
+ typeof e == "function" ? e() : e.unsubscribe(), X = null;
1507
+ }
1208
1508
  }
1209
1509
  function Z(e) {
1210
- if (T?.abort(), T = null, !e) {
1510
+ if (w?.abort(), w = null, !e) {
1211
1511
  r.setState((e) => ({
1212
1512
  ...e,
1213
1513
  thumbnailCues: []
@@ -1215,7 +1515,7 @@ function W(e) {
1215
1515
  return;
1216
1516
  }
1217
1517
  let t = new AbortController();
1218
- T = t, B(e, t.signal, i.transformThumbnailVTT).then((e) => {
1518
+ w = t, I(e, t.signal, i.transformThumbnailVTT).then((e) => {
1219
1519
  t.signal.aborted || r.setState((t) => ({
1220
1520
  ...t,
1221
1521
  thumbnailCues: e
@@ -1227,21 +1527,21 @@ function W(e) {
1227
1527
  })));
1228
1528
  });
1229
1529
  }
1230
- function de(e) {
1530
+ function Se(e) {
1231
1531
  return {
1232
1532
  name: e,
1233
1533
  store: r,
1234
- remote: J,
1534
+ remote: Y,
1235
1535
  events: o,
1236
1536
  storage: s,
1237
1537
  hotkeys: l,
1238
1538
  i18n: c,
1239
1539
  context: {
1240
1540
  containerRef: { get current() {
1241
- return _;
1541
+ return h;
1242
1542
  } },
1243
1543
  videoRef: { get current() {
1244
- return v?.element;
1544
+ return g?.element;
1245
1545
  } }
1246
1546
  },
1247
1547
  addControl: (e) => (r.setState((t) => ({
@@ -1311,14 +1611,14 @@ function W(e) {
1311
1611
  };
1312
1612
  }
1313
1613
  let Q = [];
1314
- function fe(e = !0) {
1315
- x !== null && (clearTimeout(x), x = null), S = 0;
1614
+ function Ce(e = !0) {
1615
+ b !== null && (clearTimeout(b), b = null), C = 0;
1316
1616
  for (let e of Q) e();
1317
- Q = [], v && (e && R(F, v), v.destroy(), v = null, $.engine = null);
1617
+ Q = [], g && (e && B(L, g), g.destroy(), g = null, $.engine = null);
1318
1618
  }
1319
- function pe(e) {
1320
- let t = C(i), n = ee(e, i);
1321
- v = n, $.engine = n, Q = oe(n), e.playsInline = !0, e.autoplay = !!i.autoPlay, e.preload = e.preload || "metadata", r.setState((n) => ({
1619
+ function we(e) {
1620
+ let t = x(i), n = ne(e, i);
1621
+ g = n, $.engine = n, Q = ye(n), e.playsInline = !0, e.autoplay = !!i.autoPlay, e.preload = e.preload || "metadata", r.setState((n) => ({
1322
1622
  ...n,
1323
1623
  status: "loading",
1324
1624
  source: t,
@@ -1329,40 +1629,42 @@ function W(e) {
1329
1629
  currentTime: 0,
1330
1630
  duration: 0,
1331
1631
  bufferedPercent: 0,
1332
- capabilities: d(e, _),
1632
+ capabilities: d(e, h),
1333
1633
  error: null
1334
1634
  })), i.autoPlay && n.play();
1335
1635
  }
1336
- function me(e = !0) {
1337
- let t = v?.element;
1636
+ function Te(e = !0) {
1637
+ let t = g?.element;
1338
1638
  if (t) {
1339
- for (fe(e), t.pause(), t.removeAttribute("src"); t.firstChild;) t.removeChild(t.firstChild);
1340
- t.load(), pe(t);
1639
+ for (Ce(e), t.pause(), t.removeAttribute("src"); t.firstChild;) t.removeChild(t.firstChild);
1640
+ t.load(), we(t);
1341
1641
  }
1342
1642
  }
1343
1643
  let $ = {
1344
1644
  store: r,
1345
- remote: J,
1645
+ remote: Y,
1346
1646
  events: o,
1347
1647
  storage: s,
1348
1648
  i18n: c,
1349
1649
  hotkeys: l,
1350
1650
  engine: null,
1351
1651
  updateOptions(e) {
1352
- let t = typeof e.src == "string" && e.src !== i.src, n = Object.hasOwn(e, "type") && e.type !== i.type, a = Object.hasOwn(e, "thumbnails") && e.thumbnails !== i.thumbnails, o = Object.hasOwn(e, "transformThumbnailVTT") && e.transformThumbnailVTT !== i.transformThumbnailVTT, s = {
1652
+ let t = typeof e.src == "string" && e.src !== i.src, n = Object.hasOwn(e, "type") && e.type !== i.type, a = Object.hasOwn(e, "thumbnails") && e.thumbnails !== i.thumbnails, o = Object.hasOwn(e, "transformThumbnailVTT") && e.transformThumbnailVTT !== i.transformThumbnailVTT, s = Object.hasOwn(e, "subtitleProviders") && e.subtitleProviders !== i.subtitleProviders, c = {
1353
1653
  ...i,
1354
1654
  ...e
1355
- }, c = P(s), l = c.id !== F.id || c.store !== F.store;
1356
- (t || l) && R(F, v), i = s, (t || l) && z(), (r.state.isPlaying || E) && G(), r.setState((t) => {
1357
- let n = e.subtitles ?? t.subtitleTracks, r = e.qualities ?? t.qualities;
1655
+ }, l = F(c), u = l.id !== L.id || l.store !== L.store;
1656
+ if ((t || u) && B(L, g), i = c, (t || u) && V(), (r.state.isPlaying || D) && ge(), r.setState((t) => {
1657
+ let n = e.qualities ?? t.qualities;
1358
1658
  return {
1359
1659
  ...t,
1360
- subtitleTracks: n,
1361
- qualities: r,
1362
- 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,
1660
+ qualities: n,
1363
1661
  activeQuality: e.qualities ? e.qualities.includes(t.activeQuality) ? t.activeQuality : e.qualities[0] ?? "Auto" : t.activeQuality
1364
1662
  };
1365
- }), (a || o) && Z(i.thumbnails), t || n ? me(!(t || l)) : l && v && f(v.duration) && V(v);
1663
+ }), e.subtitles && (U(e.subtitles), !r.state.activeSubtitle)) {
1664
+ let t = e.subtitles.find((e) => e.default) ?? null;
1665
+ t && Y.setActiveSubtitle(K(t));
1666
+ }
1667
+ s && (E?.abort(), E = null, J()), (a || o) && Z(i.thumbnails), t || n ? Te(!(t || u)) : u && g && f(g.duration) && H(g);
1366
1668
  },
1367
1669
  setThumbnails(e) {
1368
1670
  i = {
@@ -1373,7 +1675,7 @@ function W(e) {
1373
1675
  initPlugins(e) {
1374
1676
  let t = [];
1375
1677
  for (let n of e) {
1376
- let e = de(n.name);
1678
+ let e = Se(n.name);
1377
1679
  try {
1378
1680
  let r = n.setup?.(e);
1379
1681
  typeof r == "function" && t.push(r);
@@ -1390,11 +1692,18 @@ function W(e) {
1390
1692
  };
1391
1693
  },
1392
1694
  mount(e, t) {
1393
- v && this.unmount(), _ = t, pe(e), y = q, document.addEventListener("fullscreenchange", y), document.addEventListener("webkitfullscreenchange", y), j = () => R(), window.addEventListener("pagehide", j), Z(i.thumbnails), le(), J.setAspectRatio(r.state.aspectRatio);
1695
+ g && this.unmount(), h = t, we(e), _ = ve, document.addEventListener("fullscreenchange", _), document.addEventListener("webkitfullscreenchange", _), M = () => B(), window.addEventListener("pagehide", M), Z(i.thumbnails);
1696
+ let n = r.state.subtitleTracks.find((e) => e.default);
1697
+ n && Y.setActiveSubtitle(n), be(), Y.setAspectRatio(r.state.aspectRatio);
1394
1698
  },
1395
1699
  unmount() {
1396
- fe(), z(), W(), _ = null, T?.abort(), T = null, ue(), x !== null && (clearTimeout(x), x = null), y &&= (document.removeEventListener("fullscreenchange", y), document.removeEventListener("webkitfullscreenchange", y), null), j &&= (window.removeEventListener("pagehide", j), null), r.setState((e) => ({
1700
+ Ce(), V(), he(), h = null, w?.abort(), w = null, T?.abort(), T = null, E?.abort(), E = null, xe(), b !== null && (clearTimeout(b), b = null), _ &&= (document.removeEventListener("fullscreenchange", _), document.removeEventListener("webkitfullscreenchange", _), null), M &&= (window.removeEventListener("pagehide", M), null), r.setState((e) => ({
1397
1701
  ...e,
1702
+ activeSubtitle: null,
1703
+ subtitleTracks: e.subtitleTracks.filter((e) => !e.local),
1704
+ subtitleCues: [],
1705
+ subtitleStatus: "idle",
1706
+ subtitleError: null,
1398
1707
  status: "idle",
1399
1708
  isPlaying: !1,
1400
1709
  isPaused: !0,
@@ -1403,14 +1712,14 @@ function W(e) {
1403
1712
  }));
1404
1713
  },
1405
1714
  destroy() {
1406
- this.unmount(), ce(), o.clear();
1715
+ this.unmount(), o.clear();
1407
1716
  }
1408
1717
  };
1409
1718
  return $;
1410
1719
  }
1411
1720
  //#endregion
1412
1721
  //#region src/gesture-engine.ts
1413
- function G(e, t) {
1722
+ function J(e, t) {
1414
1723
  let n = null, r = null, i = null, a = typeof window < "u" && "ontouchstart" in window;
1415
1724
  function o(t) {
1416
1725
  if (!a || t.touches.length !== 1) return;
@@ -1470,14 +1779,14 @@ function G(e, t) {
1470
1779
  }
1471
1780
  //#endregion
1472
1781
  //#region src/utils.ts
1473
- function K(e) {
1782
+ function pe(e) {
1474
1783
  if (!Number.isFinite(e) || e < 0) return "0:00";
1475
1784
  let t = Math.floor(e / 3600), n = Math.floor(e % 3600 / 60), r = Math.floor(e % 60);
1476
1785
  return t > 0 ? `${t}:${String(n).padStart(2, "0")}:${String(r).padStart(2, "0")}` : `${n}:${String(r).padStart(2, "0")}`;
1477
1786
  }
1478
1787
  //#endregion
1479
1788
  //#region src/defaults.ts
1480
- var q = {
1789
+ var me = {
1481
1790
  play: "Play",
1482
1791
  pause: "Pause",
1483
1792
  replay: "Replay",
@@ -1494,6 +1803,38 @@ var q = {
1494
1803
  quality: "Quality",
1495
1804
  subtitles: "Subtitles",
1496
1805
  off: "Off",
1806
+ loadSubtitleFile: "Load subtitle file…",
1807
+ findSubtitlesOnline: "Find subtitles online",
1808
+ subtitleSearch: "Search",
1809
+ subtitleSearchPlaceholder: "Search subtitles…",
1810
+ subtitleSource: "Source",
1811
+ subtitleAllSources: "All sources",
1812
+ subtitleLanguage: "Language",
1813
+ subtitleAllLanguages: "All languages",
1814
+ subtitleNoResults: "No subtitles found",
1815
+ subtitleSearching: "Searching…",
1816
+ captionAppearance: "Caption appearance",
1817
+ captionSize: "Text size",
1818
+ captionTextColor: "Text color",
1819
+ captionBackgroundColor: "Background color",
1820
+ captionBackgroundOpacity: "Background opacity",
1821
+ captionSmall: "Small",
1822
+ captionMedium: "Default",
1823
+ captionLarge: "Large",
1824
+ captionReset: "Reset",
1825
+ captionFontFamily: "Font",
1826
+ captionFontScale: "Scale",
1827
+ captionTextOpacity: "Text opacity",
1828
+ captionEdgeStyle: "Edge effect",
1829
+ captionEdgeNone: "None",
1830
+ captionEdgeShadow: "Shadow",
1831
+ captionEdgeOutline: "Outline",
1832
+ captionEdgeColor: "Edge color",
1833
+ captionPosition: "Vertical position",
1834
+ captionLineHeight: "Line spacing",
1835
+ captionDelay: "Subtitle delay",
1836
+ captionPreview: "Caption preview",
1837
+ subtitleLoadError: "Could not load subtitles",
1497
1838
  endedTitle: "You've reached the end",
1498
1839
  screenshot: "Screenshot",
1499
1840
  flip: "Flip",
@@ -1510,6 +1851,7 @@ var q = {
1510
1851
  continue: "Continue",
1511
1852
  continuePlay: "Continue playing at",
1512
1853
  continueStartOver: "Start over",
1854
+ dismiss: "Dismiss",
1513
1855
  error: "An error occurred",
1514
1856
  retry: "Retry",
1515
1857
  contextMenuPlay: "Play",
@@ -1519,4 +1861,4 @@ var q = {
1519
1861
  loop: "Loop"
1520
1862
  };
1521
1863
  //#endregion
1522
- export { _ as BaseMediaEngine, b as DashMediaEngine, t as EventBus, y as HlsMediaEngine, n as HotkeyRegistry, a as I18n, g as LocalPlaybackProgressStore, v as NativeVideoEngine, h as STORAGE_KEYS, m as Storage, c as canUseFullscreen, o as canUseMSE, s as canUseNativeHLS, l as canUsePictureInPicture, u as canUseTextTracks, G as createGestureEngine, w as createMediaStore, W as createPlayer, ee as createResolvedMediaEngine, q as defaultPlayerLabels, S as detectSourceKind, I as fetchSubtitles, B as fetchThumbnails, K as formatTime, te as getActiveCue, T as getInitialMediaState, d as getMediaCapabilities, V as getThumbnailAtTime, f as isFiniteDuration, P as parseSRT, R as parseThumbnailVTT, N as parseTimestamp, F as parseVTT, D as selectAudio, M as selectError, E as selectMedia, A as selectPlugins, O as selectPreferences, j as selectThumbnails, k as selectUI, C as toPlayerSource };
1864
+ export { h as BaseMediaEngine, v as DashMediaEngine, t as EventBus, _ as HlsMediaEngine, n as HotkeyRegistry, a as I18n, te as LocalPlaybackProgressStore, g as NativeVideoEngine, m as STORAGE_KEYS, p as Storage, c as canUseFullscreen, o as canUseMSE, s as canUseNativeHLS, l as canUsePictureInPicture, u as canUseTextTracks, J as createGestureEngine, re as createMediaStore, q as createPlayer, ne as createResolvedMediaEngine, me as defaultPlayerLabels, b as detectSourceKind, j as fetchSubtitles, I as fetchThumbnails, pe as formatTime, M as getActiveCue, R as getInitialMediaState, d as getMediaCapabilities, L as getThumbnailAtTime, f as isFiniteDuration, O as parseSRT, A as parseSubtitles, P as parseThumbnailVTT, E as parseTimestamp, k as parseVTT, z as selectAudio, U as selectError, ie as selectMedia, V as selectPlugins, B as selectPreferences, H as selectThumbnails, ae as selectUI, x as toPlayerSource };