@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.
@@ -16,7 +16,7 @@ import type { PlaybackProgress } from '../playback-progress';
16
16
  import type { ControlRegistration, ContextMenuItem, FlipState, AspectRatioState } from '../plugin-api';
17
17
  import type { LayerRegistration, SettingRegistration } from '../plugin-api';
18
18
  import type { PlayerSource } from '../source-resolver';
19
- import type { SubtitleTrack, ThumbnailCue } from '../subtitle-parser';
19
+ import type { CaptionSettings, SubtitleCue, SubtitleProviderInfo, SubtitleProviderResult, SubtitleTrack, ThumbnailCue } from '../subtitle-parser';
20
20
  export type PlaybackStatus = 'idle' | 'loading' | 'ready' | 'playing' | 'paused' | 'buffering' | 'seeking' | 'ended' | 'error';
21
21
  export interface MediaSlice {
22
22
  status: PlaybackStatus;
@@ -41,6 +41,14 @@ export interface PreferencesSlice {
41
41
  aspectRatio: AspectRatioState;
42
42
  activeSubtitle: SubtitleTrack | null;
43
43
  subtitleTracks: SubtitleTrack[];
44
+ subtitleCues: SubtitleCue[];
45
+ subtitleStatus: 'idle' | 'loading' | 'ready' | 'error';
46
+ subtitleError: string | null;
47
+ subtitleProviders: SubtitleProviderInfo[];
48
+ subtitleSearchResults: SubtitleProviderResult[];
49
+ subtitleSearchStatus: 'idle' | 'loading' | 'ready' | 'error';
50
+ subtitleSearchError: string | null;
51
+ captionSettings: CaptionSettings;
44
52
  activeQuality: string;
45
53
  qualities: string[];
46
54
  }
@@ -71,8 +79,16 @@ export interface ErrorSlice {
71
79
  isReconnecting: boolean;
72
80
  } | null;
73
81
  }
82
+ export type ResumeState = {
83
+ status: 'idle';
84
+ } | {
85
+ status: 'loading';
86
+ } | {
87
+ status: 'prompt';
88
+ progress: PlaybackProgress;
89
+ };
74
90
  export interface PlaybackProgressSlice {
75
- resumeProgress: PlaybackProgress | null;
91
+ resumeState: ResumeState;
76
92
  }
77
93
  /**
78
94
  * Full MediaState — flat at runtime, logically organized here.
@@ -97,7 +113,7 @@ export declare const selectMedia: (s: MediaState) => {
97
113
  bufferedPercent: number;
98
114
  playbackRate: number;
99
115
  isLive: boolean;
100
- resumeProgress: PlaybackProgress | null;
116
+ resumeState: ResumeState;
101
117
  };
102
118
  export declare const selectAudio: (s: MediaState) => {
103
119
  volume: number;
@@ -109,6 +125,14 @@ export declare const selectPreferences: (s: MediaState) => {
109
125
  aspectRatio: AspectRatioState;
110
126
  activeSubtitle: SubtitleTrack | null;
111
127
  subtitleTracks: SubtitleTrack[];
128
+ subtitleCues: SubtitleCue[];
129
+ subtitleStatus: "error" | "idle" | "loading" | "ready";
130
+ subtitleError: string | null;
131
+ subtitleProviders: SubtitleProviderInfo[];
132
+ subtitleSearchResults: SubtitleProviderResult[];
133
+ subtitleSearchStatus: "error" | "idle" | "loading" | "ready";
134
+ subtitleSearchError: string | null;
135
+ captionSettings: CaptionSettings;
112
136
  activeQuality: string;
113
137
  qualities: string[];
114
138
  };
package/dist/storage.d.ts CHANGED
@@ -13,12 +13,13 @@ export declare class Storage {
13
13
  }
14
14
  /** Pre-defined persistence keys */
15
15
  export declare const STORAGE_KEYS: {
16
- readonly VOLUME: "volume";
17
- readonly MUTED: "muted";
18
- readonly PLAYBACK_RATE: "playbackRate";
19
- readonly SUBTITLE_LANG: "subtitleLang";
20
- readonly QUALITY: "quality";
21
- readonly LOOP: "loop";
22
- readonly FLIP: "flip";
23
- readonly ASPECT_RATIO: "aspectRatio";
16
+ readonly VOLUME: 'volume';
17
+ readonly MUTED: 'muted';
18
+ readonly PLAYBACK_RATE: 'playbackRate';
19
+ readonly SUBTITLE_LANG: 'subtitleLang';
20
+ readonly CAPTION_SETTINGS: 'captionSettings';
21
+ readonly QUALITY: 'quality';
22
+ readonly LOOP: 'loop';
23
+ readonly FLIP: 'flip';
24
+ readonly ASPECT_RATIO: 'aspectRatio';
24
25
  };
@@ -1,23 +1,105 @@
1
+ export type SubtitleFormat = 'vtt' | 'srt';
1
2
  export interface SubtitleCue {
2
3
  index: number;
3
4
  start: number;
4
5
  end: number;
5
6
  text: string;
7
+ id?: string;
8
+ settings?: string;
6
9
  }
7
10
  export interface SubtitleTrack {
8
- src: string;
11
+ id?: string;
12
+ src?: string;
13
+ content?: string;
9
14
  lang: string;
10
15
  label: string;
16
+ format?: SubtitleFormat;
11
17
  default?: boolean;
18
+ local?: boolean;
19
+ }
20
+ export interface SubtitleSearchQuery {
21
+ query?: string;
22
+ title?: string;
23
+ year?: number;
24
+ season?: number;
25
+ episode?: number;
26
+ imdbId?: string;
27
+ languages?: string[];
28
+ providerId?: string;
29
+ }
30
+ export interface SubtitleSearchItem {
31
+ id: string;
32
+ label: string;
33
+ language: string;
34
+ format?: SubtitleFormat;
35
+ release?: string;
36
+ downloads?: number;
37
+ hearingImpaired?: boolean;
38
+ machineTranslated?: boolean;
39
+ providerData?: unknown;
40
+ }
41
+ export interface SubtitleProviderResult extends SubtitleSearchItem {
42
+ providerId: string;
43
+ providerLabel: string;
44
+ }
45
+ export interface SubtitleSearchResult {
46
+ items: SubtitleSearchItem[];
47
+ }
48
+ export type SubtitleSource = {
49
+ content: string;
50
+ src?: never;
51
+ format?: SubtitleFormat;
52
+ } | {
53
+ src: string;
54
+ content?: never;
55
+ format?: SubtitleFormat;
56
+ };
57
+ export interface SubtitleProvider {
58
+ id: string;
59
+ label: string;
60
+ search(query: SubtitleSearchQuery, signal: AbortSignal): Promise<SubtitleSearchResult | SubtitleSearchItem[]>;
61
+ fetch(item: SubtitleSearchItem, signal: AbortSignal): Promise<SubtitleSource>;
62
+ }
63
+ export type SubtitleProviderInfo = Pick<SubtitleProvider, 'id' | 'label'>;
64
+ export interface CaptionSettings {
65
+ fontSize: 'small' | 'medium' | 'large';
66
+ fontScale: number;
67
+ fontFamily: 'sans' | 'serif' | 'monospace';
68
+ textColor: string;
69
+ textOpacity: number;
70
+ backgroundColor: string;
71
+ backgroundOpacity: number;
72
+ edgeStyle: 'none' | 'shadow' | 'outline';
73
+ edgeColor: string;
74
+ position: number;
75
+ lineHeight: number;
76
+ delay: number;
77
+ }
78
+ export declare const DEFAULT_CAPTION_SETTINGS: CaptionSettings;
79
+ export interface SubtitleParseError {
80
+ code: 'unsupported-format' | 'malformed';
81
+ message: string;
12
82
  }
13
- /** Parse HH:MM:SS.mmm or HH:MM:SS,mmm timestamp → total seconds */
14
- export declare function parseTimestamp(ts: string): number;
15
- /** Parse SRT format text into cues */
83
+ export type SubtitleParseResult = {
84
+ ok: true;
85
+ format: SubtitleFormat;
86
+ cues: SubtitleCue[];
87
+ } | {
88
+ ok: false;
89
+ format?: undefined;
90
+ error: SubtitleParseError;
91
+ };
92
+ /** Parse HH:MM:SS.mmm, MM:SS.mmm, and comma-separated variants. */
93
+ export declare function parseTimestamp(timestamp: string): number;
16
94
  export declare function parseSRT(content: string): SubtitleCue[];
17
- /** Parse VTT format text into cues */
18
95
  export declare function parseVTT(content: string): SubtitleCue[];
19
- /** Fetch and parse subtitles from URL */
20
- export declare function fetchSubtitles(track: SubtitleTrack): Promise<SubtitleCue[]>;
96
+ export declare function parseSubtitles(content: string, hint?: {
97
+ format?: SubtitleFormat;
98
+ fileName?: string;
99
+ mimeType?: string;
100
+ }): SubtitleParseResult;
101
+ /** Fetch and parse subtitles from URL. */
102
+ export declare function fetchSubtitles(track: SubtitleTrack, signal?: AbortSignal): Promise<SubtitleCue[]>;
21
103
  /** Get active cue at a given time */
22
104
  export declare function getActiveCue(cues: SubtitleCue[], time: number): SubtitleCue | null;
23
105
  export interface ThumbnailCue {
package/dist/types.d.ts CHANGED
@@ -8,11 +8,10 @@ import type { PlaybackProgressOptions } from './playback-progress';
8
8
  import type { PlayerPlugin } from './plugin-api';
9
9
  import type { AspectRatioState, FlipState } from './plugin-api';
10
10
  import type { PlayerSource } from './source-resolver';
11
- import type { PlaybackStatus } from './state/slices';
12
- import type { MediaState } from './state/slices';
11
+ import type { MediaState, PlaybackStatus, ResumeState } from './state/slices';
13
12
  import type { Storage } from './storage';
14
- import type { SubtitleTrack } from './subtitle-parser';
15
- export type { MediaState };
13
+ import type { CaptionSettings, SubtitleProvider, SubtitleProviderResult, SubtitleSearchQuery, SubtitleTrack } from './subtitle-parser';
14
+ export type { MediaState, ResumeState };
16
15
  export interface PlayerOptions {
17
16
  src: string;
18
17
  /** MIME/content type hint used by source provider selection. */
@@ -21,6 +20,7 @@ export interface PlayerOptions {
21
20
  title?: string;
22
21
  poster?: string;
23
22
  subtitles?: SubtitleTrack[];
23
+ subtitleProviders?: SubtitleProvider[];
24
24
  qualities?: string[];
25
25
  autoPlay?: boolean;
26
26
  thumbnails?: string;
@@ -88,6 +88,13 @@ export interface MediaRemote {
88
88
  toggleFullscreen: () => void;
89
89
  togglePiP: () => void;
90
90
  setActiveSubtitle: (track: SubtitleTrack | null) => void;
91
+ addSubtitleTrack: (track: SubtitleTrack) => void;
92
+ removeSubtitleTrack: (id: string) => void;
93
+ searchSubtitles: (query?: SubtitleSearchQuery) => void;
94
+ selectSubtitleResult: (result: SubtitleProviderResult) => void;
95
+ clearSubtitleSearch: () => void;
96
+ setCaptionSettings: (patch: Partial<CaptionSettings>) => void;
97
+ resetCaptionSettings: () => void;
91
98
  setActiveQuality: (q: string) => void;
92
99
  takeScreenshot: () => void;
93
100
  setFlip: (flip: FlipState) => void;
@@ -113,6 +120,38 @@ export interface PlayerLabels {
113
120
  quality: string;
114
121
  subtitles: string;
115
122
  off: string;
123
+ loadSubtitleFile: string;
124
+ findSubtitlesOnline: string;
125
+ subtitleSearch: string;
126
+ subtitleSearchPlaceholder: string;
127
+ subtitleSource: string;
128
+ subtitleAllSources: string;
129
+ subtitleLanguage: string;
130
+ subtitleAllLanguages: string;
131
+ subtitleNoResults: string;
132
+ subtitleSearching: string;
133
+ captionAppearance: string;
134
+ captionSize: string;
135
+ captionTextColor: string;
136
+ captionBackgroundColor: string;
137
+ captionBackgroundOpacity: string;
138
+ captionSmall: string;
139
+ captionMedium: string;
140
+ captionLarge: string;
141
+ captionFontFamily: string;
142
+ captionFontScale: string;
143
+ captionTextOpacity: string;
144
+ captionEdgeStyle: string;
145
+ captionEdgeNone: string;
146
+ captionEdgeShadow: string;
147
+ captionEdgeOutline: string;
148
+ captionEdgeColor: string;
149
+ captionPosition: string;
150
+ captionLineHeight: string;
151
+ captionDelay: string;
152
+ captionPreview: string;
153
+ captionReset: string;
154
+ subtitleLoadError: string;
116
155
  endedTitle: string;
117
156
  screenshot: string;
118
157
  flip: string;
@@ -152,7 +191,7 @@ export interface PlayerInstance {
152
191
  hotkeys: HotkeyRegistry;
153
192
  /** The active media engine. Null before mount and after unmount. */
154
193
  engine: MediaEngine | null;
155
- updateOptions(opts: Partial<Pick<PlayerOptions, 'src' | 'type' | 'title' | 'poster' | 'autoPlay' | 'subtitles' | 'qualities' | 'thumbnails' | 'transformThumbnailVTT' | 'playbackProgress'>>): void;
194
+ updateOptions(opts: Partial<Pick<PlayerOptions, 'src' | 'type' | 'title' | 'poster' | 'autoPlay' | 'subtitles' | 'subtitleProviders' | 'qualities' | 'thumbnails' | 'transformThumbnailVTT' | 'playbackProgress'>>): void;
156
195
  setThumbnails(url?: string): void;
157
196
  initPlugins(plugins: PlayerPlugin[]): () => void;
158
197
  mount(videoEl: HTMLVideoElement, containerEl: HTMLDivElement): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vplayer/core",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -33,12 +33,12 @@
33
33
  "test:coverage": "vitest run --coverage"
34
34
  },
35
35
  "dependencies": {
36
- "@tanstack/store": "^0.8.0",
37
- "dashjs": "^5.1.1",
38
- "hls.js": "^1.6.16"
36
+ "@tanstack/store": "^0.11.1",
37
+ "dashjs": "^5.2.1",
38
+ "hls.js": "^1.7.1"
39
39
  },
40
40
  "devDependencies": {
41
- "typescript": "^6.0.2",
42
- "vite": "^8.0.0"
41
+ "typescript": "^7.0.2",
42
+ "vite": "^8.2.2"
43
43
  }
44
44
  }