@vplayer/core 0.2.2 → 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
@@ -246,17 +246,26 @@ var ee = "vplayer", p = class {
246
246
  ASPECT_RATIO: "aspectRatio"
247
247
  }, te = class {
248
248
  storage;
249
- constructor(e = new p({ prefix: "vplayer:progress" })) {
250
- this.storage = e;
249
+ maxEntries;
250
+ constructor(e = new p(), t = 100) {
251
+ this.storage = e, this.maxEntries = t;
251
252
  }
252
253
  async load(e) {
253
- return this.storage.get(encodeURIComponent(e)) ?? null;
254
+ return this.storage.get("progress")?.[e] ?? null;
254
255
  }
255
256
  async save(e, t) {
256
- 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);
257
265
  }
258
266
  async clear(e) {
259
- 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);
260
269
  }
261
270
  }, h = class {
262
271
  element;
@@ -657,13 +666,13 @@ function F(e, t) {
657
666
  return e;
658
667
  }
659
668
  }
660
- async function re(e, t, n) {
669
+ async function I(e, t, n) {
661
670
  let r = await fetch(e, { signal: t });
662
671
  if (!r.ok) throw Error(`Failed to fetch thumbnail VTT: ${r.status}`);
663
672
  let i = r.url || e, a = await r.text();
664
673
  return P(n ? await n(a, i) : a).map((e) => (e.src = F(e.src, i), e));
665
674
  }
666
- function I(e, t) {
675
+ function L(e, t) {
667
676
  if (e.length === 0) return null;
668
677
  let n = 0, r = e.length - 1;
669
678
  for (; n <= r;) {
@@ -676,10 +685,10 @@ function I(e, t) {
676
685
  }
677
686
  //#endregion
678
687
  //#region src/state/slices.ts
679
- function ie() {
680
- return new e(L());
688
+ function re() {
689
+ return new e(R());
681
690
  }
682
- function L() {
691
+ function R() {
683
692
  return {
684
693
  status: "idle",
685
694
  source: null,
@@ -730,7 +739,7 @@ function L() {
730
739
  resumeState: { status: "idle" }
731
740
  };
732
741
  }
733
- var R = (e) => ({
742
+ var ie = (e) => ({
734
743
  status: e.status,
735
744
  source: e.source,
736
745
  isPlaying: e.isPlaying,
@@ -743,10 +752,10 @@ var R = (e) => ({
743
752
  playbackRate: e.playbackRate,
744
753
  isLive: e.isLive,
745
754
  resumeState: e.resumeState
746
- }), ae = (e) => ({
755
+ }), z = (e) => ({
747
756
  volume: e.volume,
748
757
  isMuted: e.isMuted
749
- }), z = (e) => ({
758
+ }), B = (e) => ({
750
759
  isLooping: e.isLooping,
751
760
  flip: e.flip,
752
761
  aspectRatio: e.aspectRatio,
@@ -762,30 +771,39 @@ var R = (e) => ({
762
771
  captionSettings: e.captionSettings,
763
772
  activeQuality: e.activeQuality,
764
773
  qualities: e.qualities
765
- }), B = (e) => ({
774
+ }), ae = (e) => ({
766
775
  controlsVisible: e.controlsVisible,
767
776
  capabilities: e.capabilities,
768
777
  isFullscreen: e.isFullscreen,
769
778
  infoPanelVisible: e.infoPanelVisible,
770
779
  notification: e.notification
771
- }), oe = (e) => ({
780
+ }), V = (e) => ({
772
781
  controls: e.controls,
773
782
  settings: e.settings,
774
783
  layers: e.layers,
775
784
  contextMenuItems: e.contextMenuItems,
776
785
  contextMenuEnabled: e.contextMenuEnabled
777
- }), V = (e) => ({ thumbnailCues: e.thumbnailCues }), H = (e) => e.error, U = [
786
+ }), H = (e) => ({ thumbnailCues: e.thumbnailCues }), U = (e) => e.error, W = [
778
787
  "default",
779
788
  "16:9",
780
789
  "4:3",
781
790
  "21:9",
782
791
  "cover",
783
792
  "fill"
784
- ], se = 5e3, ce = 2, le = {
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 = {
785
803
  "16:9": "16 / 9",
786
804
  "4:3": "4 / 3",
787
805
  "21:9": "21 / 9"
788
- }, ue = {
806
+ }, G = {
789
807
  default: "default",
790
808
  "16:9": "16-9",
791
809
  "4:3": "4-3",
@@ -793,67 +811,68 @@ var R = (e) => ({
793
811
  cover: "cover",
794
812
  fill: "fill"
795
813
  };
796
- function de(e) {
814
+ function ue(e) {
797
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");
798
816
  }
799
- function fe(e) {
800
- return typeof e == "string" && e in ue ? e : "default";
817
+ function de(e) {
818
+ return typeof e == "string" && e in G ? e : "default";
801
819
  }
802
- function pe(e) {
820
+ function fe(e) {
803
821
  return e === "cover" ? "cover" : e === "fill" ? "fill" : "contain";
804
822
  }
805
- function W(e) {
823
+ function K(e) {
806
824
  return {
807
825
  ...e,
808
826
  id: e.id ?? `${e.local ? "local" : "track"}:${e.src ?? e.label}:${e.lang}`
809
827
  };
810
828
  }
811
- function G(e) {
812
- let r = ie(), i = { ...e }, o = new t(), s = new p(), c = new a(i.lang);
829
+ function q(e) {
830
+ let r = re(), i = { ...e }, o = new t(), s = new p(), c = new a(i.lang);
813
831
  i.translations && c.addTranslations(i.lang ?? "en", i.translations);
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) {
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));
816
835
  return {
817
836
  generation: k,
818
- id: e.playbackProgress?.id ?? e.src,
837
+ id: t,
819
838
  store: e.playbackProgress?.store ?? O
820
839
  };
821
840
  }
822
- let L = I(i);
841
+ let L = F(i);
823
842
  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) => {
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) => {
827
846
  console.warn(e.kind === "save" ? "[vplayer] playback progress save failed:" : "[vplayer] playback progress clear failed:", t);
828
847
  }).finally(() => {
829
- F = !1, R();
848
+ P = !1, R();
830
849
  }));
831
850
  }
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({
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({
835
854
  kind: "save",
836
855
  target: e,
837
856
  progress: t
838
857
  }), R();
839
858
  }
840
859
  function z(e) {
841
- P.push({
860
+ N.push({
842
861
  kind: "clear",
843
862
  target: e
844
863
  }), R();
845
864
  }
846
865
  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, {
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, {
848
867
  time: t.currentTime,
849
868
  duration: t.duration
850
869
  }));
851
870
  }
852
- function oe(e) {
853
- !r.state.isPlaying || Date.now() - v < se || Number.isFinite(y) && Math.abs(e.currentTime - y) < ce || B(L, e);
871
+ function ae(e) {
872
+ !r.state.isPlaying || Date.now() - v < oe || Number.isFinite(y) && Math.abs(e.currentTime - y) < se || B(L, e);
854
873
  }
855
874
  function V() {
856
- k++, L = I(i), A = !1, M = !1, v = 0, y = NaN, r.setState((e) => ({
875
+ k++, L = F(i), A = !1, v = 0, y = NaN, r.setState((e) => ({
857
876
  ...e,
858
877
  resumeState: { status: "idle" }
859
878
  }));
@@ -865,24 +884,20 @@ function G(e) {
865
884
  r.setState((e) => ({
866
885
  ...e,
867
886
  resumeState: { status: "loading" }
868
- })), t.store.load(t.id).then((a) => {
869
- let o = i.autoPlay === !0;
887
+ })), t.store.load(t.id).then((i) => {
870
888
  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)) {
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)) {
872
890
  r.setState((e) => ({
873
891
  ...e,
874
892
  resumeState: { status: "idle" }
875
893
  }));
876
894
  return;
877
895
  }
878
- o ? (e.seek(a.time), r.setState((e) => ({
879
- ...e,
880
- resumeState: { status: "idle" }
881
- }))) : r.setState((e) => ({
896
+ r.setState((e) => ({
882
897
  ...e,
883
898
  resumeState: {
884
899
  status: "prompt",
885
- progress: a
900
+ progress: i
886
901
  }
887
902
  }));
888
903
  }
@@ -893,11 +908,11 @@ function G(e) {
893
908
  })), console.warn("[vplayer] playback progress load failed:", n);
894
909
  });
895
910
  }
896
- function G(e) {
911
+ function U(e) {
897
912
  r.setState((t) => {
898
913
  let n = new Map(t.subtitleTracks.map((e) => [e.id, e]));
899
914
  for (let t of e) {
900
- let e = W(t);
915
+ let e = K(t);
901
916
  n.set(e.id, e);
902
917
  }
903
918
  return {
@@ -906,7 +921,7 @@ function G(e) {
906
921
  };
907
922
  });
908
923
  }
909
- function K(e) {
924
+ function q(e) {
910
925
  T?.abort();
911
926
  let t = new AbortController();
912
927
  T = t, r.setState((t) => ({
@@ -931,7 +946,7 @@ function G(e) {
931
946
  }));
932
947
  });
933
948
  }
934
- function q() {
949
+ function J() {
935
950
  let e = (i.subtitleProviders ?? []).map(({ id: e, label: t }) => ({
936
951
  id: e,
937
952
  label: t
@@ -944,7 +959,7 @@ function G(e) {
944
959
  subtitleSearchError: null
945
960
  }));
946
961
  }
947
- function me(e = {}) {
962
+ function pe(e = {}) {
948
963
  E?.abort();
949
964
  let t = i.subtitleProviders ?? [], n = e.providerId ? t.filter((t) => t.id === e.providerId) : t;
950
965
  if (n.length === 0) {
@@ -984,7 +999,7 @@ function G(e) {
984
999
  }));
985
1000
  });
986
1001
  }
987
- function he(e) {
1002
+ function me(e) {
988
1003
  T?.abort();
989
1004
  let t = (i.subtitleProviders ?? []).find((t) => t.id === e.providerId);
990
1005
  if (!t) {
@@ -1004,7 +1019,7 @@ function G(e) {
1004
1019
  subtitleError: null
1005
1020
  })), (async () => {
1006
1021
  try {
1007
- let i = await t.fetch(e, n.signal), a = W({
1022
+ let i = await t.fetch(e, n.signal), a = K({
1008
1023
  id: `provider:${t.id}:${e.id}`,
1009
1024
  lang: e.language,
1010
1025
  label: e.label,
@@ -1012,7 +1027,7 @@ function G(e) {
1012
1027
  ...i.content === void 0 ? { src: i.src } : { content: i.content }
1013
1028
  }), o = await j(a, n.signal);
1014
1029
  if (n.signal.aborted) return;
1015
- G([a]), r.setState((e) => ({
1030
+ U([a]), r.setState((e) => ({
1016
1031
  ...e,
1017
1032
  activeSubtitle: a,
1018
1033
  subtitleCues: o,
@@ -1030,15 +1045,15 @@ function G(e) {
1030
1045
  }
1031
1046
  })();
1032
1047
  }
1033
- i.subtitles?.length && G(i.subtitles), q();
1034
- function ge() {
1048
+ i.subtitles?.length && U(i.subtitles), J();
1049
+ function he() {
1035
1050
  D && typeof navigator < "u" && "mediaSession" in navigator && navigator.mediaSession.metadata === D && (navigator.mediaSession.metadata = null), D = null;
1036
1051
  }
1037
- function _e() {
1052
+ function ge() {
1038
1053
  if (typeof navigator > "u" || !("mediaSession" in navigator) || typeof MediaMetadata > "u") return;
1039
1054
  let e = i.title?.trim();
1040
1055
  if (!e) {
1041
- ge();
1056
+ he();
1042
1057
  return;
1043
1058
  }
1044
1059
  let t = new MediaMetadata({
@@ -1047,60 +1062,60 @@ function G(e) {
1047
1062
  });
1048
1063
  navigator.mediaSession.metadata = t, D = t;
1049
1064
  }
1050
- function ve() {
1065
+ function _e() {
1051
1066
  l.register({
1052
1067
  key: "Space",
1053
1068
  description: "Toggle play/pause",
1054
1069
  handler: (e) => {
1055
- e.preventDefault(), J.togglePlay();
1070
+ e.preventDefault(), Y.togglePlay();
1056
1071
  }
1057
1072
  }), l.register({
1058
1073
  key: "KeyK",
1059
1074
  description: "Toggle play/pause",
1060
1075
  handler: (e) => {
1061
- e.preventDefault(), J.togglePlay();
1076
+ e.preventDefault(), Y.togglePlay();
1062
1077
  }
1063
1078
  }), l.register({
1064
1079
  key: "KeyL",
1065
1080
  description: "Toggle loop",
1066
1081
  handler: (e) => {
1067
- e.preventDefault(), J.toggleLoop();
1082
+ e.preventDefault(), Y.toggleLoop();
1068
1083
  }
1069
1084
  }), l.register({
1070
1085
  key: "KeyI",
1071
1086
  description: "Toggle info panel",
1072
1087
  handler: (e) => {
1073
- e.preventDefault(), J.toggleInfoPanel();
1088
+ e.preventDefault(), Y.toggleInfoPanel();
1074
1089
  }
1075
1090
  }), l.register({
1076
1091
  key: "KeyF",
1077
1092
  description: "Toggle fullscreen",
1078
1093
  handler: (e) => {
1079
- e.preventDefault(), J.toggleFullscreen();
1094
+ e.preventDefault(), Y.toggleFullscreen();
1080
1095
  }
1081
1096
  }), l.register({
1082
1097
  key: "KeyA",
1083
1098
  description: "Cycle aspect ratio",
1084
1099
  handler: (e) => {
1085
- e.preventDefault(), J.cycleAspectRatio();
1100
+ e.preventDefault(), Y.cycleAspectRatio();
1086
1101
  }
1087
1102
  }), l.register({
1088
1103
  key: "KeyM",
1089
1104
  description: "Toggle mute",
1090
1105
  handler: (e) => {
1091
- e.preventDefault(), J.toggleMute();
1106
+ e.preventDefault(), Y.toggleMute();
1092
1107
  }
1093
1108
  }), l.register({
1094
1109
  key: "ArrowLeft",
1095
1110
  description: "Seek backward 5s",
1096
1111
  handler: (e) => {
1097
- e.preventDefault(), J.skip(-5);
1112
+ e.preventDefault(), Y.skip(-5);
1098
1113
  }
1099
1114
  }), l.register({
1100
1115
  key: "ArrowRight",
1101
1116
  description: "Seek forward 5s",
1102
1117
  handler: (e) => {
1103
- e.preventDefault(), J.skip(5);
1118
+ e.preventDefault(), Y.skip(5);
1104
1119
  }
1105
1120
  }), l.register({
1106
1121
  key: "ArrowUp",
@@ -1108,7 +1123,7 @@ function G(e) {
1108
1123
  handler: (e) => {
1109
1124
  e.preventDefault();
1110
1125
  let t = Math.min(1, r.state.volume + .1);
1111
- J.setVolume(t);
1126
+ Y.setVolume(t);
1112
1127
  }
1113
1128
  }), l.register({
1114
1129
  key: "ArrowDown",
@@ -1116,12 +1131,12 @@ function G(e) {
1116
1131
  handler: (e) => {
1117
1132
  e.preventDefault();
1118
1133
  let t = Math.max(0, r.state.volume - .1);
1119
- J.setVolume(t);
1134
+ Y.setVolume(t);
1120
1135
  }
1121
1136
  });
1122
1137
  }
1123
- i.defaultHotkeys !== !1 && ve();
1124
- function ye() {
1138
+ i.defaultHotkeys !== !1 && _e();
1139
+ function ve() {
1125
1140
  if (typeof document > "u") return;
1126
1141
  let e = document;
1127
1142
  r.setState((t) => ({
@@ -1130,7 +1145,7 @@ function G(e) {
1130
1145
  capabilities: d(g?.element ?? void 0, h)
1131
1146
  }));
1132
1147
  }
1133
- let J = {
1148
+ let Y = {
1134
1149
  play: () => {
1135
1150
  g?.play();
1136
1151
  },
@@ -1153,6 +1168,12 @@ function G(e) {
1153
1168
  resumeState: { status: "idle" }
1154
1169
  })), g?.seek(0), z(e);
1155
1170
  },
1171
+ dismissSavedProgress: () => {
1172
+ r.setState((e) => ({
1173
+ ...e,
1174
+ resumeState: { status: "idle" }
1175
+ }));
1176
+ },
1156
1177
  seek: (e) => g?.seek(e),
1157
1178
  skip: (e) => {
1158
1179
  let t = g;
@@ -1187,7 +1208,7 @@ function G(e) {
1187
1208
  toggleFullscreen: () => {
1188
1209
  if (!h || typeof document > "u") return;
1189
1210
  let e = h, t = document, n = !!(document.fullscreenElement || t.webkitFullscreenElement), r = () => {
1190
- h?.focus({ preventScroll: !0 }), ye();
1211
+ h?.focus({ preventScroll: !0 }), ve();
1191
1212
  }, i = n ? typeof document.exitFullscreen == "function" ? document.exitFullscreen() : t.webkitExitFullscreen?.() : typeof h.requestFullscreen == "function" ? h.requestFullscreen() : e.webkitRequestFullscreen?.();
1192
1213
  Promise.resolve(i).then(r, r);
1193
1214
  },
@@ -1206,20 +1227,20 @@ function G(e) {
1206
1227
  }));
1207
1228
  return;
1208
1229
  }
1209
- K(e);
1230
+ q(e);
1210
1231
  },
1211
1232
  addSubtitleTrack: (e) => {
1212
- let t = W(e);
1213
- G([t]), K(t);
1233
+ let t = K(e);
1234
+ U([t]), q(t);
1214
1235
  },
1215
1236
  removeSubtitleTrack: (e) => {
1216
- r.state.activeSubtitle?.id === e && J.setActiveSubtitle(null), r.setState((t) => ({
1237
+ r.state.activeSubtitle?.id === e && Y.setActiveSubtitle(null), r.setState((t) => ({
1217
1238
  ...t,
1218
1239
  subtitleTracks: t.subtitleTracks.filter((t) => t.id !== e)
1219
1240
  }));
1220
1241
  },
1221
- searchSubtitles: me,
1222
- selectSubtitleResult: he,
1242
+ searchSubtitles: pe,
1243
+ selectSubtitleResult: me,
1223
1244
  clearSubtitleSearch: () => {
1224
1245
  E?.abort(), E = null, r.setState((e) => ({
1225
1246
  ...e,
@@ -1273,17 +1294,17 @@ function G(e) {
1273
1294
  }));
1274
1295
  },
1275
1296
  setAspectRatio: (e) => {
1276
- let t = fe(e), n = g?.element;
1297
+ let t = de(e), n = g?.element;
1277
1298
  if (!n) return;
1278
1299
  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) => ({
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) => ({
1280
1301
  ...e,
1281
1302
  aspectRatio: t
1282
1303
  }));
1283
1304
  },
1284
1305
  cycleAspectRatio: () => {
1285
- let e = r.state.aspectRatio, t = U[(U.indexOf(e) + 1) % U.length] ?? "default";
1286
- J.setAspectRatio(t);
1306
+ let e = r.state.aspectRatio, t = W[(W.indexOf(e) + 1) % W.length] ?? "default";
1307
+ Y.setAspectRatio(t);
1287
1308
  },
1288
1309
  toggleLoop: () => {
1289
1310
  let e = g;
@@ -1299,13 +1320,10 @@ function G(e) {
1299
1320
  }));
1300
1321
  }
1301
1322
  };
1302
- function be(e) {
1323
+ function ye(e) {
1303
1324
  return [
1304
1325
  e.on("play", () => {
1305
- M = !0, r.setState((e) => ({
1306
- ...e,
1307
- resumeState: { status: "idle" }
1308
- })), _e(), r.setState((e) => ({
1326
+ ge(), r.setState((e) => ({
1309
1327
  ...e,
1310
1328
  status: "playing",
1311
1329
  isPlaying: !0,
@@ -1327,9 +1345,9 @@ function G(e) {
1327
1345
  }),
1328
1346
  e.on("ended", () => {
1329
1347
  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);
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);
1333
1351
  }
1334
1352
  z(L), r.setState((e) => ({
1335
1353
  ...e,
@@ -1346,7 +1364,7 @@ function G(e) {
1346
1364
  r.setState((t) => ({
1347
1365
  ...t,
1348
1366
  currentTime: e.currentTime
1349
- })), i.onTimeUpdate?.(e.currentTime), oe(e);
1367
+ })), i.onTimeUpdate?.(e.currentTime), ae(e);
1350
1368
  }),
1351
1369
  e.on("loadedmetadata", () => {
1352
1370
  b !== null && (clearTimeout(b), b = null), C = 0, r.setState((t) => ({
@@ -1404,13 +1422,12 @@ function G(e) {
1404
1422
  })), B(L, e);
1405
1423
  }),
1406
1424
  e.on("playing", () => {
1407
- M = !0, r.setState((e) => ({
1425
+ r.setState((e) => ({
1408
1426
  ...e,
1409
1427
  status: "playing",
1410
1428
  isPlaying: !0,
1411
1429
  isPaused: !1,
1412
- isBuffering: !1,
1413
- resumeState: { status: "idle" }
1430
+ isBuffering: !1
1414
1431
  }));
1415
1432
  }),
1416
1433
  e.on("volumechange", () => {
@@ -1461,8 +1478,8 @@ function G(e) {
1461
1478
  })
1462
1479
  ];
1463
1480
  }
1464
- let Y = null;
1465
- function xe() {
1481
+ let X = null;
1482
+ function be() {
1466
1483
  if (!i.persistPreferences) return;
1467
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);
1468
1485
  r.setState((r) => ({
@@ -1472,21 +1489,24 @@ function G(e) {
1472
1489
  playbackRate: n ?? r.playbackRate,
1473
1490
  isLooping: a ?? r.isLooping,
1474
1491
  flip: o ?? r.flip,
1475
- aspectRatio: fe(c),
1492
+ aspectRatio: de(c),
1476
1493
  captionSettings: l ? {
1477
1494
  ...S,
1478
1495
  ...l,
1479
1496
  backgroundOpacity: Math.max(0, Math.min(1, l.backgroundOpacity))
1480
1497
  } : r.captionSettings
1481
- })), Y = r.subscribe(() => {
1498
+ })), X = r.subscribe(() => {
1482
1499
  let e = r.state;
1483
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);
1484
1501
  });
1485
1502
  }
1486
- function Se() {
1487
- Y &&= (Y.unsubscribe(), null);
1503
+ function xe() {
1504
+ if (X) {
1505
+ let e = X;
1506
+ typeof e == "function" ? e() : e.unsubscribe(), X = null;
1507
+ }
1488
1508
  }
1489
- function X(e) {
1509
+ function Z(e) {
1490
1510
  if (w?.abort(), w = null, !e) {
1491
1511
  r.setState((e) => ({
1492
1512
  ...e,
@@ -1495,7 +1515,7 @@ function G(e) {
1495
1515
  return;
1496
1516
  }
1497
1517
  let t = new AbortController();
1498
- w = t, re(e, t.signal, i.transformThumbnailVTT).then((e) => {
1518
+ w = t, I(e, t.signal, i.transformThumbnailVTT).then((e) => {
1499
1519
  t.signal.aborted || r.setState((t) => ({
1500
1520
  ...t,
1501
1521
  thumbnailCues: e
@@ -1507,11 +1527,11 @@ function G(e) {
1507
1527
  })));
1508
1528
  });
1509
1529
  }
1510
- function Ce(e) {
1530
+ function Se(e) {
1511
1531
  return {
1512
1532
  name: e,
1513
1533
  store: r,
1514
- remote: J,
1534
+ remote: Y,
1515
1535
  events: o,
1516
1536
  storage: s,
1517
1537
  hotkeys: l,
@@ -1590,15 +1610,15 @@ function G(e) {
1590
1610
  }
1591
1611
  };
1592
1612
  }
1593
- let Z = [];
1594
- function we(e = !0) {
1613
+ let Q = [];
1614
+ function Ce(e = !0) {
1595
1615
  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);
1616
+ for (let e of Q) e();
1617
+ Q = [], g && (e && B(L, g), g.destroy(), g = null, $.engine = null);
1598
1618
  }
1599
- function Q(e) {
1619
+ function we(e) {
1600
1620
  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) => ({
1621
+ g = n, $.engine = n, Q = ye(n), e.playsInline = !0, e.autoplay = !!i.autoPlay, e.preload = e.preload || "metadata", r.setState((n) => ({
1602
1622
  ...n,
1603
1623
  status: "loading",
1604
1624
  source: t,
@@ -1616,13 +1636,13 @@ function G(e) {
1616
1636
  function Te(e = !0) {
1617
1637
  let t = g?.element;
1618
1638
  if (t) {
1619
- for (we(e), t.pause(), t.removeAttribute("src"); t.firstChild;) t.removeChild(t.firstChild);
1620
- t.load(), Q(t);
1639
+ for (Ce(e), t.pause(), t.removeAttribute("src"); t.firstChild;) t.removeChild(t.firstChild);
1640
+ t.load(), we(t);
1621
1641
  }
1622
1642
  }
1623
1643
  let $ = {
1624
1644
  store: r,
1625
- remote: J,
1645
+ remote: Y,
1626
1646
  events: o,
1627
1647
  storage: s,
1628
1648
  i18n: c,
@@ -1632,30 +1652,30 @@ function G(e) {
1632
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 = {
1633
1653
  ...i,
1634
1654
  ...e
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) => {
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) => {
1637
1657
  let n = e.qualities ?? t.qualities;
1638
1658
  return {
1639
1659
  ...t,
1640
1660
  qualities: n,
1641
1661
  activeQuality: e.qualities ? e.qualities.includes(t.activeQuality) ? t.activeQuality : e.qualities[0] ?? "Auto" : t.activeQuality
1642
1662
  };
1643
- }), e.subtitles && (G(e.subtitles), !r.state.activeSubtitle)) {
1663
+ }), e.subtitles && (U(e.subtitles), !r.state.activeSubtitle)) {
1644
1664
  let t = e.subtitles.find((e) => e.default) ?? null;
1645
- t && J.setActiveSubtitle(W(t));
1665
+ t && Y.setActiveSubtitle(K(t));
1646
1666
  }
1647
- s && (E?.abort(), E = null, q()), (a || o) && X(i.thumbnails), t || n ? Te(!(t || u)) : u && g && f(g.duration) && H(g);
1667
+ s && (E?.abort(), E = null, J()), (a || o) && Z(i.thumbnails), t || n ? Te(!(t || u)) : u && g && f(g.duration) && H(g);
1648
1668
  },
1649
1669
  setThumbnails(e) {
1650
1670
  i = {
1651
1671
  ...i,
1652
1672
  thumbnails: e
1653
- }, X(e);
1673
+ }, Z(e);
1654
1674
  },
1655
1675
  initPlugins(e) {
1656
1676
  let t = [];
1657
1677
  for (let n of e) {
1658
- let e = Ce(n.name);
1678
+ let e = Se(n.name);
1659
1679
  try {
1660
1680
  let r = n.setup?.(e);
1661
1681
  typeof r == "function" && t.push(r);
@@ -1672,12 +1692,12 @@ function G(e) {
1672
1692
  };
1673
1693
  },
1674
1694
  mount(e, t) {
1675
- g && this.unmount(), h = t, Q(e), _ = ye, document.addEventListener("fullscreenchange", _), document.addEventListener("webkitfullscreenchange", _), N = () => B(), window.addEventListener("pagehide", N), X(i.thumbnails);
1695
+ g && this.unmount(), h = t, we(e), _ = ve, document.addEventListener("fullscreenchange", _), document.addEventListener("webkitfullscreenchange", _), M = () => B(), window.addEventListener("pagehide", M), Z(i.thumbnails);
1676
1696
  let n = r.state.subtitleTracks.find((e) => e.default);
1677
- n && J.setActiveSubtitle(n), xe(), J.setAspectRatio(r.state.aspectRatio);
1697
+ n && Y.setActiveSubtitle(n), be(), Y.setAspectRatio(r.state.aspectRatio);
1678
1698
  },
1679
1699
  unmount() {
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) => ({
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) => ({
1681
1701
  ...e,
1682
1702
  activeSubtitle: null,
1683
1703
  subtitleTracks: e.subtitleTracks.filter((e) => !e.local),
@@ -1699,7 +1719,7 @@ function G(e) {
1699
1719
  }
1700
1720
  //#endregion
1701
1721
  //#region src/gesture-engine.ts
1702
- function K(e, t) {
1722
+ function J(e, t) {
1703
1723
  let n = null, r = null, i = null, a = typeof window < "u" && "ontouchstart" in window;
1704
1724
  function o(t) {
1705
1725
  if (!a || t.touches.length !== 1) return;
@@ -1759,7 +1779,7 @@ function K(e, t) {
1759
1779
  }
1760
1780
  //#endregion
1761
1781
  //#region src/utils.ts
1762
- function q(e) {
1782
+ function pe(e) {
1763
1783
  if (!Number.isFinite(e) || e < 0) return "0:00";
1764
1784
  let t = Math.floor(e / 3600), n = Math.floor(e % 3600 / 60), r = Math.floor(e % 60);
1765
1785
  return t > 0 ? `${t}:${String(n).padStart(2, "0")}:${String(r).padStart(2, "0")}` : `${n}:${String(r).padStart(2, "0")}`;
@@ -1831,6 +1851,7 @@ var me = {
1831
1851
  continue: "Continue",
1832
1852
  continuePlay: "Continue playing at",
1833
1853
  continueStartOver: "Start over",
1854
+ dismiss: "Dismiss",
1834
1855
  error: "An error occurred",
1835
1856
  retry: "Retry",
1836
1857
  contextMenuPlay: "Play",
@@ -1840,4 +1861,4 @@ var me = {
1840
1861
  loop: "Loop"
1841
1862
  };
1842
1863
  //#endregion
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 };
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 };
@@ -11,10 +11,15 @@ export interface PlaybackProgressStore {
11
11
  export interface PlaybackProgressOptions {
12
12
  id?: string;
13
13
  store?: PlaybackProgressStore;
14
+ /** Normalize the media URL used as the progress key. Defaults to true. */
15
+ normalizeUrl?: boolean;
16
+ /** Milliseconds before the resume prompt dismisses itself. Use 0 to keep it visible. Defaults to 5000. */
17
+ resumePromptTimeout?: number;
14
18
  }
15
19
  export declare class LocalPlaybackProgressStore implements PlaybackProgressStore {
16
20
  private readonly storage;
17
- constructor(storage?: Storage);
21
+ private readonly maxEntries;
22
+ constructor(storage?: Storage, maxEntries?: number);
18
23
  load(mediaId: string): Promise<PlaybackProgress | null>;
19
24
  save(mediaId: string, progress: PlaybackProgress): Promise<void>;
20
25
  clear(mediaId: string): Promise<void>;
@@ -10,6 +10,7 @@ export interface RemoteRef {
10
10
  seek: (time: number) => void;
11
11
  resumeFromSavedProgress: () => void;
12
12
  startPlaybackOver: () => void;
13
+ dismissSavedProgress: () => void;
13
14
  skip: (seconds: number) => void;
14
15
  setVolume: (v: number) => void;
15
16
  toggleMute: () => void;
package/dist/types.d.ts CHANGED
@@ -80,6 +80,7 @@ export interface MediaRemote {
80
80
  togglePlay: () => void;
81
81
  resumeFromSavedProgress: () => void;
82
82
  startPlaybackOver: () => void;
83
+ dismissSavedProgress: () => void;
83
84
  seek: (time: number) => void;
84
85
  skip: (seconds: number) => void;
85
86
  setVolume: (v: number) => void;
@@ -168,6 +169,7 @@ export interface PlayerLabels {
168
169
  continue: string;
169
170
  continuePlay: string;
170
171
  continueStartOver: string;
172
+ dismiss: string;
171
173
  error: string;
172
174
  retry: string;
173
175
  contextMenuPlay: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vplayer/core",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",