@scarlett-player/captions 1.15.3 → 1.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.cjs +29 -5
- package/dist/index.d.cts +7 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +29 -5
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -54,7 +54,7 @@ const player = await createPlayer({
|
|
|
54
54
|
| `label` | `string` | required | Human readable name shown in the picker |
|
|
55
55
|
| `src` | `string` | required | WebVTT URL. Cross-origin URLs need CORS |
|
|
56
56
|
| `kind` | `'subtitles' \| 'captions'` | `'subtitles'` | Track kind |
|
|
57
|
-
| `default` | `boolean` | - |
|
|
57
|
+
| `default` | `boolean` | - | Select this source once the media loads. Beats `defaultLanguage` and applies even with `autoSelect` off, so it is how you name one specific track. A track the browser is already showing still wins, and selection happens once per media. Mark at most one source |
|
|
58
58
|
|
|
59
59
|
## How tracks reach the player
|
|
60
60
|
|
package/dist/index.cjs
CHANGED
|
@@ -26,7 +26,7 @@ __export(index_exports, {
|
|
|
26
26
|
module.exports = __toCommonJS(index_exports);
|
|
27
27
|
|
|
28
28
|
// src/version.ts
|
|
29
|
-
var PKG_VERSION = true ? "1.
|
|
29
|
+
var PKG_VERSION = true ? "1.16.0" : "0.0.0-dev";
|
|
30
30
|
|
|
31
31
|
// src/index.ts
|
|
32
32
|
var HLS_SUBTITLE_TRACKS_UPDATED = "hlsSubtitleTracksUpdated";
|
|
@@ -36,6 +36,7 @@ function createCaptionsPlugin(config = {}) {
|
|
|
36
36
|
let api = null;
|
|
37
37
|
let video = null;
|
|
38
38
|
let addedTrackElements = [];
|
|
39
|
+
let defaultTrackElement = null;
|
|
39
40
|
let hlsSubtitleHandler = null;
|
|
40
41
|
let hlsSubtitleSwitchHandler = null;
|
|
41
42
|
let observedTextTracks = null;
|
|
@@ -45,6 +46,7 @@ function createCaptionsPlugin(config = {}) {
|
|
|
45
46
|
const extractFromHLS = config.extractFromHLS !== false;
|
|
46
47
|
const autoSelect = config.autoSelect ?? false;
|
|
47
48
|
const defaultLanguage = config.defaultLanguage ?? "en";
|
|
49
|
+
const defaultSource = config.sources?.find((source) => source.default) ?? null;
|
|
48
50
|
const getVideo = () => {
|
|
49
51
|
if (video) return video;
|
|
50
52
|
video = api?.container.querySelector("video") ?? null;
|
|
@@ -55,6 +57,7 @@ function createCaptionsPlugin(config = {}) {
|
|
|
55
57
|
trackEl.parentNode?.removeChild(trackEl);
|
|
56
58
|
}
|
|
57
59
|
addedTrackElements = [];
|
|
60
|
+
defaultTrackElement = null;
|
|
58
61
|
api?.setState("textTracks", []);
|
|
59
62
|
api?.setState("currentTextTrack", null);
|
|
60
63
|
};
|
|
@@ -113,17 +116,37 @@ function createCaptionsPlugin(config = {}) {
|
|
|
113
116
|
}
|
|
114
117
|
syncTracksToState();
|
|
115
118
|
};
|
|
119
|
+
const markedTrack = (tracks) => {
|
|
120
|
+
if (!defaultSource) return void 0;
|
|
121
|
+
const videoEl = getVideo();
|
|
122
|
+
const textTrack = defaultTrackElement?.track;
|
|
123
|
+
if (videoEl && textTrack) {
|
|
124
|
+
for (let i = 0; i < videoEl.textTracks.length; i++) {
|
|
125
|
+
if (videoEl.textTracks[i] !== textTrack) continue;
|
|
126
|
+
const own = tracks.find((t) => t.id === `track-${i}`);
|
|
127
|
+
if (own) return own;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return tracks.find(
|
|
131
|
+
(t) => t.language === defaultSource.language && (!defaultSource.label || t.label === defaultSource.label)
|
|
132
|
+
);
|
|
133
|
+
};
|
|
116
134
|
const maybeAutoSelect = () => {
|
|
117
|
-
if (!autoSelect || hasAutoSelected) return;
|
|
135
|
+
if (!autoSelect && !defaultSource || hasAutoSelected) return;
|
|
118
136
|
if (api?.getState("currentTextTrack")) {
|
|
119
137
|
hasAutoSelected = true;
|
|
120
138
|
return;
|
|
121
139
|
}
|
|
122
140
|
const tracks = api?.getState("textTracks") || [];
|
|
123
|
-
const
|
|
141
|
+
const marked = markedTrack(tracks);
|
|
142
|
+
const match = marked ?? (autoSelect ? tracks.find((t) => t.language === defaultLanguage) : void 0);
|
|
124
143
|
if (!match) return;
|
|
125
144
|
selectTrack(match.id);
|
|
126
|
-
api?.logger.debug("
|
|
145
|
+
api?.logger.debug("Selected caption track on load", {
|
|
146
|
+
language: match.language,
|
|
147
|
+
id: match.id,
|
|
148
|
+
reason: marked ? "source default" : "defaultLanguage"
|
|
149
|
+
});
|
|
127
150
|
};
|
|
128
151
|
const handleTextTracksChanged = () => {
|
|
129
152
|
syncTracksToState();
|
|
@@ -203,7 +226,8 @@ function createCaptionsPlugin(config = {}) {
|
|
|
203
226
|
const initSources = () => {
|
|
204
227
|
if (!config.sources?.length) return;
|
|
205
228
|
for (const source of config.sources) {
|
|
206
|
-
addTrackElement(source);
|
|
229
|
+
const trackEl = addTrackElement(source);
|
|
230
|
+
if (source === defaultSource) defaultTrackElement = trackEl;
|
|
207
231
|
}
|
|
208
232
|
};
|
|
209
233
|
return {
|
package/dist/index.d.cts
CHANGED
|
@@ -12,7 +12,13 @@ interface CaptionSource {
|
|
|
12
12
|
src: string;
|
|
13
13
|
/** Track kind - default: 'subtitles' */
|
|
14
14
|
kind?: 'subtitles' | 'captions';
|
|
15
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* Select this track once the media loads.
|
|
17
|
+
*
|
|
18
|
+
* Beats `defaultLanguage`, and applies even with `autoSelect` off. A
|
|
19
|
+
* viewer's own pick still wins: selection happens once per media, and a
|
|
20
|
+
* track already showing stands. Mark at most one source.
|
|
21
|
+
*/
|
|
16
22
|
default?: boolean;
|
|
17
23
|
}
|
|
18
24
|
interface CaptionsPluginConfig {
|
package/dist/index.d.ts
CHANGED
|
@@ -12,7 +12,13 @@ interface CaptionSource {
|
|
|
12
12
|
src: string;
|
|
13
13
|
/** Track kind - default: 'subtitles' */
|
|
14
14
|
kind?: 'subtitles' | 'captions';
|
|
15
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* Select this track once the media loads.
|
|
17
|
+
*
|
|
18
|
+
* Beats `defaultLanguage`, and applies even with `autoSelect` off. A
|
|
19
|
+
* viewer's own pick still wins: selection happens once per media, and a
|
|
20
|
+
* track already showing stands. Mark at most one source.
|
|
21
|
+
*/
|
|
16
22
|
default?: boolean;
|
|
17
23
|
}
|
|
18
24
|
interface CaptionsPluginConfig {
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/version.ts
|
|
2
|
-
var PKG_VERSION = true ? "1.
|
|
2
|
+
var PKG_VERSION = true ? "1.16.0" : "0.0.0-dev";
|
|
3
3
|
|
|
4
4
|
// src/index.ts
|
|
5
5
|
var HLS_SUBTITLE_TRACKS_UPDATED = "hlsSubtitleTracksUpdated";
|
|
@@ -9,6 +9,7 @@ function createCaptionsPlugin(config = {}) {
|
|
|
9
9
|
let api = null;
|
|
10
10
|
let video = null;
|
|
11
11
|
let addedTrackElements = [];
|
|
12
|
+
let defaultTrackElement = null;
|
|
12
13
|
let hlsSubtitleHandler = null;
|
|
13
14
|
let hlsSubtitleSwitchHandler = null;
|
|
14
15
|
let observedTextTracks = null;
|
|
@@ -18,6 +19,7 @@ function createCaptionsPlugin(config = {}) {
|
|
|
18
19
|
const extractFromHLS = config.extractFromHLS !== false;
|
|
19
20
|
const autoSelect = config.autoSelect ?? false;
|
|
20
21
|
const defaultLanguage = config.defaultLanguage ?? "en";
|
|
22
|
+
const defaultSource = config.sources?.find((source) => source.default) ?? null;
|
|
21
23
|
const getVideo = () => {
|
|
22
24
|
if (video) return video;
|
|
23
25
|
video = api?.container.querySelector("video") ?? null;
|
|
@@ -28,6 +30,7 @@ function createCaptionsPlugin(config = {}) {
|
|
|
28
30
|
trackEl.parentNode?.removeChild(trackEl);
|
|
29
31
|
}
|
|
30
32
|
addedTrackElements = [];
|
|
33
|
+
defaultTrackElement = null;
|
|
31
34
|
api?.setState("textTracks", []);
|
|
32
35
|
api?.setState("currentTextTrack", null);
|
|
33
36
|
};
|
|
@@ -86,17 +89,37 @@ function createCaptionsPlugin(config = {}) {
|
|
|
86
89
|
}
|
|
87
90
|
syncTracksToState();
|
|
88
91
|
};
|
|
92
|
+
const markedTrack = (tracks) => {
|
|
93
|
+
if (!defaultSource) return void 0;
|
|
94
|
+
const videoEl = getVideo();
|
|
95
|
+
const textTrack = defaultTrackElement?.track;
|
|
96
|
+
if (videoEl && textTrack) {
|
|
97
|
+
for (let i = 0; i < videoEl.textTracks.length; i++) {
|
|
98
|
+
if (videoEl.textTracks[i] !== textTrack) continue;
|
|
99
|
+
const own = tracks.find((t) => t.id === `track-${i}`);
|
|
100
|
+
if (own) return own;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return tracks.find(
|
|
104
|
+
(t) => t.language === defaultSource.language && (!defaultSource.label || t.label === defaultSource.label)
|
|
105
|
+
);
|
|
106
|
+
};
|
|
89
107
|
const maybeAutoSelect = () => {
|
|
90
|
-
if (!autoSelect || hasAutoSelected) return;
|
|
108
|
+
if (!autoSelect && !defaultSource || hasAutoSelected) return;
|
|
91
109
|
if (api?.getState("currentTextTrack")) {
|
|
92
110
|
hasAutoSelected = true;
|
|
93
111
|
return;
|
|
94
112
|
}
|
|
95
113
|
const tracks = api?.getState("textTracks") || [];
|
|
96
|
-
const
|
|
114
|
+
const marked = markedTrack(tracks);
|
|
115
|
+
const match = marked ?? (autoSelect ? tracks.find((t) => t.language === defaultLanguage) : void 0);
|
|
97
116
|
if (!match) return;
|
|
98
117
|
selectTrack(match.id);
|
|
99
|
-
api?.logger.debug("
|
|
118
|
+
api?.logger.debug("Selected caption track on load", {
|
|
119
|
+
language: match.language,
|
|
120
|
+
id: match.id,
|
|
121
|
+
reason: marked ? "source default" : "defaultLanguage"
|
|
122
|
+
});
|
|
100
123
|
};
|
|
101
124
|
const handleTextTracksChanged = () => {
|
|
102
125
|
syncTracksToState();
|
|
@@ -176,7 +199,8 @@ function createCaptionsPlugin(config = {}) {
|
|
|
176
199
|
const initSources = () => {
|
|
177
200
|
if (!config.sources?.length) return;
|
|
178
201
|
for (const source of config.sources) {
|
|
179
|
-
addTrackElement(source);
|
|
202
|
+
const trackEl = addTrackElement(source);
|
|
203
|
+
if (source === defaultSource) defaultTrackElement = trackEl;
|
|
180
204
|
}
|
|
181
205
|
};
|
|
182
206
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scarlett-player/captions",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.16.0",
|
|
4
4
|
"description": "Captions Plugin for Scarlett Player - WebVTT subtitles and closed captions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"tsup": "^8.5.1",
|
|
31
31
|
"typescript": "^5.3.0",
|
|
32
32
|
"vitest": "^1.6.0",
|
|
33
|
-
"@scarlett-player/core": "1.
|
|
33
|
+
"@scarlett-player/core": "1.16.0"
|
|
34
34
|
},
|
|
35
35
|
"keywords": [
|
|
36
36
|
"video",
|