@vplayer/core 0.2.0 → 0.2.2

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