@scarlett-player/captions 1.2.0 → 1.4.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/dist/index.cjs +110 -31
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +110 -31
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -24,11 +24,18 @@ __export(index_exports, {
|
|
|
24
24
|
default: () => index_default
|
|
25
25
|
});
|
|
26
26
|
module.exports = __toCommonJS(index_exports);
|
|
27
|
+
var HLS_SUBTITLE_TRACKS_UPDATED = "hlsSubtitleTracksUpdated";
|
|
28
|
+
var HLS_INSTANCE_RETRY_MS = 500;
|
|
27
29
|
function createCaptionsPlugin(config = {}) {
|
|
28
30
|
let api = null;
|
|
29
31
|
let video = null;
|
|
30
32
|
let addedTrackElements = [];
|
|
33
|
+
let hlsTrackElements = [];
|
|
31
34
|
let hlsSubtitleHandler = null;
|
|
35
|
+
let observedTextTracks = null;
|
|
36
|
+
let hlsRetryTimer = null;
|
|
37
|
+
let hlsRetryUsed = false;
|
|
38
|
+
let hasAutoSelected = false;
|
|
32
39
|
const extractFromHLS = config.extractFromHLS !== false;
|
|
33
40
|
const autoSelect = config.autoSelect ?? false;
|
|
34
41
|
const defaultLanguage = config.defaultLanguage ?? "en";
|
|
@@ -42,10 +49,18 @@ function createCaptionsPlugin(config = {}) {
|
|
|
42
49
|
trackEl.parentNode?.removeChild(trackEl);
|
|
43
50
|
}
|
|
44
51
|
addedTrackElements = [];
|
|
52
|
+
hlsTrackElements = [];
|
|
45
53
|
api?.setState("textTracks", []);
|
|
46
54
|
api?.setState("currentTextTrack", null);
|
|
47
55
|
};
|
|
48
|
-
const
|
|
56
|
+
const removeHlsTrackElements = () => {
|
|
57
|
+
for (const trackEl of hlsTrackElements) {
|
|
58
|
+
trackEl.parentNode?.removeChild(trackEl);
|
|
59
|
+
addedTrackElements = addedTrackElements.filter((el) => el !== trackEl);
|
|
60
|
+
}
|
|
61
|
+
hlsTrackElements = [];
|
|
62
|
+
};
|
|
63
|
+
const addTrackElement = (source, origin = "config") => {
|
|
49
64
|
const videoEl = getVideo();
|
|
50
65
|
if (!videoEl) throw new Error("No video element");
|
|
51
66
|
const trackEl = document.createElement("track");
|
|
@@ -56,6 +71,9 @@ function createCaptionsPlugin(config = {}) {
|
|
|
56
71
|
trackEl.default = false;
|
|
57
72
|
videoEl.appendChild(trackEl);
|
|
58
73
|
addedTrackElements.push(trackEl);
|
|
74
|
+
if (origin === "hls") {
|
|
75
|
+
hlsTrackElements.push(trackEl);
|
|
76
|
+
}
|
|
59
77
|
if (trackEl.track) {
|
|
60
78
|
trackEl.track.mode = "disabled";
|
|
61
79
|
}
|
|
@@ -87,6 +105,7 @@ function createCaptionsPlugin(config = {}) {
|
|
|
87
105
|
const selectTrack = (trackId) => {
|
|
88
106
|
const videoEl = getVideo();
|
|
89
107
|
if (!videoEl) return;
|
|
108
|
+
hasAutoSelected = true;
|
|
90
109
|
for (let i = 0; i < videoEl.textTracks.length; i++) {
|
|
91
110
|
const track = videoEl.textTracks[i];
|
|
92
111
|
if (track.kind !== "subtitles" && track.kind !== "captions") continue;
|
|
@@ -99,6 +118,43 @@ function createCaptionsPlugin(config = {}) {
|
|
|
99
118
|
}
|
|
100
119
|
syncTracksToState();
|
|
101
120
|
};
|
|
121
|
+
const maybeAutoSelect = () => {
|
|
122
|
+
if (!autoSelect || hasAutoSelected) return;
|
|
123
|
+
if (api?.getState("currentTextTrack")) {
|
|
124
|
+
hasAutoSelected = true;
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const tracks = api?.getState("textTracks") || [];
|
|
128
|
+
const match = tracks.find((t) => t.language === defaultLanguage);
|
|
129
|
+
if (!match) return;
|
|
130
|
+
selectTrack(match.id);
|
|
131
|
+
api?.logger.debug("Auto-selected caption track", { language: defaultLanguage, id: match.id });
|
|
132
|
+
};
|
|
133
|
+
const handleTextTracksChanged = () => {
|
|
134
|
+
syncTracksToState();
|
|
135
|
+
maybeAutoSelect();
|
|
136
|
+
};
|
|
137
|
+
const observeTextTracks = () => {
|
|
138
|
+
const videoEl = getVideo();
|
|
139
|
+
if (!videoEl || observedTextTracks === videoEl.textTracks) return;
|
|
140
|
+
unobserveTextTracks();
|
|
141
|
+
const list = videoEl.textTracks;
|
|
142
|
+
if (typeof list?.addEventListener !== "function") return;
|
|
143
|
+
observedTextTracks = list;
|
|
144
|
+
observedTextTracks.addEventListener("addtrack", handleTextTracksChanged);
|
|
145
|
+
observedTextTracks.addEventListener("removetrack", handleTextTracksChanged);
|
|
146
|
+
observedTextTracks.addEventListener("change", handleTextTracksChanged);
|
|
147
|
+
};
|
|
148
|
+
const unobserveTextTracks = () => {
|
|
149
|
+
if (typeof observedTextTracks?.removeEventListener !== "function") {
|
|
150
|
+
observedTextTracks = null;
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
observedTextTracks.removeEventListener("addtrack", handleTextTracksChanged);
|
|
154
|
+
observedTextTracks.removeEventListener("removetrack", handleTextTracksChanged);
|
|
155
|
+
observedTextTracks.removeEventListener("change", handleTextTracksChanged);
|
|
156
|
+
observedTextTracks = null;
|
|
157
|
+
};
|
|
102
158
|
const extractHlsSubtitles = () => {
|
|
103
159
|
if (!extractFromHLS || !api) return;
|
|
104
160
|
const hlsPlugin = api.getPlugin("hls-provider");
|
|
@@ -108,35 +164,55 @@ function createCaptionsPlugin(config = {}) {
|
|
|
108
164
|
api.logger.debug("Extracting HLS subtitle tracks", {
|
|
109
165
|
count: hlsInstance.subtitleTracks.length
|
|
110
166
|
});
|
|
167
|
+
removeHlsTrackElements();
|
|
111
168
|
for (const hlsTrack of hlsInstance.subtitleTracks) {
|
|
112
|
-
addTrackElement(
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
169
|
+
addTrackElement(
|
|
170
|
+
{
|
|
171
|
+
language: hlsTrack.lang || "unknown",
|
|
172
|
+
label: hlsTrack.name || `Subtitle ${hlsTrack.id}`,
|
|
173
|
+
src: hlsTrack.url,
|
|
174
|
+
kind: "subtitles"
|
|
175
|
+
},
|
|
176
|
+
"hls"
|
|
177
|
+
);
|
|
118
178
|
}
|
|
119
179
|
syncTracksToState();
|
|
120
|
-
|
|
121
|
-
|
|
180
|
+
maybeAutoSelect();
|
|
181
|
+
};
|
|
182
|
+
const unsubscribeFromHls = () => {
|
|
183
|
+
if (hlsRetryTimer) {
|
|
184
|
+
clearTimeout(hlsRetryTimer);
|
|
185
|
+
hlsRetryTimer = null;
|
|
122
186
|
}
|
|
187
|
+
if (!hlsSubtitleHandler) return;
|
|
188
|
+
const hlsInstance = api?.getPlugin("hls-provider")?.getHlsInstance();
|
|
189
|
+
hlsInstance?.off(HLS_SUBTITLE_TRACKS_UPDATED, hlsSubtitleHandler);
|
|
190
|
+
hlsSubtitleHandler = null;
|
|
123
191
|
};
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
const
|
|
127
|
-
if (
|
|
128
|
-
|
|
129
|
-
|
|
192
|
+
const syncFromHls = () => {
|
|
193
|
+
if (!extractFromHLS || !api) return;
|
|
194
|
+
const hlsPlugin = api.getPlugin("hls-provider");
|
|
195
|
+
if (!hlsPlugin || hlsPlugin.isNativeHLS()) return;
|
|
196
|
+
const hlsInstance = hlsPlugin.getHlsInstance();
|
|
197
|
+
if (!hlsInstance) {
|
|
198
|
+
if (!hlsRetryUsed) {
|
|
199
|
+
hlsRetryUsed = true;
|
|
200
|
+
hlsRetryTimer = setTimeout(() => {
|
|
201
|
+
hlsRetryTimer = null;
|
|
202
|
+
syncFromHls();
|
|
203
|
+
}, HLS_INSTANCE_RETRY_MS);
|
|
204
|
+
}
|
|
205
|
+
return;
|
|
130
206
|
}
|
|
207
|
+
unsubscribeFromHls();
|
|
208
|
+
hlsSubtitleHandler = () => extractHlsSubtitles();
|
|
209
|
+
hlsInstance.on(HLS_SUBTITLE_TRACKS_UPDATED, hlsSubtitleHandler);
|
|
210
|
+
extractHlsSubtitles();
|
|
131
211
|
};
|
|
132
212
|
const initSources = () => {
|
|
133
213
|
if (!config.sources?.length) return;
|
|
134
214
|
for (const source of config.sources) {
|
|
135
|
-
addTrackElement(source);
|
|
136
|
-
}
|
|
137
|
-
syncTracksToState();
|
|
138
|
-
if (autoSelect) {
|
|
139
|
-
autoSelectTrack();
|
|
215
|
+
addTrackElement(source, "config");
|
|
140
216
|
}
|
|
141
217
|
};
|
|
142
218
|
return {
|
|
@@ -155,33 +231,36 @@ function createCaptionsPlugin(config = {}) {
|
|
|
155
231
|
});
|
|
156
232
|
const unsubLoaded = api.on("media:loaded", () => {
|
|
157
233
|
video = null;
|
|
234
|
+
hasAutoSelected = false;
|
|
235
|
+
hlsRetryUsed = false;
|
|
158
236
|
cleanupTracks();
|
|
159
237
|
initSources();
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
238
|
+
observeTextTracks();
|
|
239
|
+
syncTracksToState();
|
|
240
|
+
maybeAutoSelect();
|
|
241
|
+
syncFromHls();
|
|
163
242
|
});
|
|
164
243
|
const unsubLoadRequest = api.on("media:load-request", () => {
|
|
165
244
|
video = null;
|
|
245
|
+
hasAutoSelected = false;
|
|
246
|
+
hlsRetryUsed = false;
|
|
247
|
+
unsubscribeFromHls();
|
|
248
|
+
unobserveTextTracks();
|
|
166
249
|
cleanupTracks();
|
|
167
250
|
});
|
|
168
251
|
api.onDestroy(() => {
|
|
169
252
|
unsubTrackText();
|
|
170
253
|
unsubLoaded();
|
|
171
254
|
unsubLoadRequest();
|
|
255
|
+
unsubscribeFromHls();
|
|
256
|
+
unobserveTextTracks();
|
|
172
257
|
cleanupTracks();
|
|
173
|
-
if (hlsSubtitleHandler) {
|
|
174
|
-
const hlsPlugin = api?.getPlugin("hls-provider");
|
|
175
|
-
const hlsInstance = hlsPlugin?.getHlsInstance();
|
|
176
|
-
if (hlsInstance) {
|
|
177
|
-
hlsInstance.off("SUBTITLE_TRACKS_UPDATED", hlsSubtitleHandler);
|
|
178
|
-
}
|
|
179
|
-
hlsSubtitleHandler = null;
|
|
180
|
-
}
|
|
181
258
|
});
|
|
182
259
|
},
|
|
183
260
|
destroy() {
|
|
184
261
|
api?.logger.debug("Captions plugin destroyed");
|
|
262
|
+
unsubscribeFromHls();
|
|
263
|
+
unobserveTextTracks();
|
|
185
264
|
cleanupTracks();
|
|
186
265
|
video = null;
|
|
187
266
|
api = null;
|
package/dist/index.d.cts
CHANGED
|
@@ -33,7 +33,9 @@ interface CaptionsPluginConfig {
|
|
|
33
33
|
*
|
|
34
34
|
* Provides WebVTT subtitle/caption support with:
|
|
35
35
|
* - External WebVTT file loading via <track> elements
|
|
36
|
-
* - HLS.js subtitle track extraction
|
|
36
|
+
* - HLS.js subtitle track extraction, driven by Hls.Events.SUBTITLE_TRACKS_UPDATED
|
|
37
|
+
* (emitted as 'hlsSubtitleTracksUpdated')
|
|
38
|
+
* - Native HLS support (Safari/iOS) by observing the video's TextTrackList
|
|
37
39
|
* - Browser-native rendering (no custom VTT parser)
|
|
38
40
|
* - State sync with core textTracks/currentTextTrack
|
|
39
41
|
* - Automatic cleanup on source change
|
package/dist/index.d.ts
CHANGED
|
@@ -33,7 +33,9 @@ interface CaptionsPluginConfig {
|
|
|
33
33
|
*
|
|
34
34
|
* Provides WebVTT subtitle/caption support with:
|
|
35
35
|
* - External WebVTT file loading via <track> elements
|
|
36
|
-
* - HLS.js subtitle track extraction
|
|
36
|
+
* - HLS.js subtitle track extraction, driven by Hls.Events.SUBTITLE_TRACKS_UPDATED
|
|
37
|
+
* (emitted as 'hlsSubtitleTracksUpdated')
|
|
38
|
+
* - Native HLS support (Safari/iOS) by observing the video's TextTrackList
|
|
37
39
|
* - Browser-native rendering (no custom VTT parser)
|
|
38
40
|
* - State sync with core textTracks/currentTextTrack
|
|
39
41
|
* - Automatic cleanup on source change
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
+
var HLS_SUBTITLE_TRACKS_UPDATED = "hlsSubtitleTracksUpdated";
|
|
3
|
+
var HLS_INSTANCE_RETRY_MS = 500;
|
|
2
4
|
function createCaptionsPlugin(config = {}) {
|
|
3
5
|
let api = null;
|
|
4
6
|
let video = null;
|
|
5
7
|
let addedTrackElements = [];
|
|
8
|
+
let hlsTrackElements = [];
|
|
6
9
|
let hlsSubtitleHandler = null;
|
|
10
|
+
let observedTextTracks = null;
|
|
11
|
+
let hlsRetryTimer = null;
|
|
12
|
+
let hlsRetryUsed = false;
|
|
13
|
+
let hasAutoSelected = false;
|
|
7
14
|
const extractFromHLS = config.extractFromHLS !== false;
|
|
8
15
|
const autoSelect = config.autoSelect ?? false;
|
|
9
16
|
const defaultLanguage = config.defaultLanguage ?? "en";
|
|
@@ -17,10 +24,18 @@ function createCaptionsPlugin(config = {}) {
|
|
|
17
24
|
trackEl.parentNode?.removeChild(trackEl);
|
|
18
25
|
}
|
|
19
26
|
addedTrackElements = [];
|
|
27
|
+
hlsTrackElements = [];
|
|
20
28
|
api?.setState("textTracks", []);
|
|
21
29
|
api?.setState("currentTextTrack", null);
|
|
22
30
|
};
|
|
23
|
-
const
|
|
31
|
+
const removeHlsTrackElements = () => {
|
|
32
|
+
for (const trackEl of hlsTrackElements) {
|
|
33
|
+
trackEl.parentNode?.removeChild(trackEl);
|
|
34
|
+
addedTrackElements = addedTrackElements.filter((el) => el !== trackEl);
|
|
35
|
+
}
|
|
36
|
+
hlsTrackElements = [];
|
|
37
|
+
};
|
|
38
|
+
const addTrackElement = (source, origin = "config") => {
|
|
24
39
|
const videoEl = getVideo();
|
|
25
40
|
if (!videoEl) throw new Error("No video element");
|
|
26
41
|
const trackEl = document.createElement("track");
|
|
@@ -31,6 +46,9 @@ function createCaptionsPlugin(config = {}) {
|
|
|
31
46
|
trackEl.default = false;
|
|
32
47
|
videoEl.appendChild(trackEl);
|
|
33
48
|
addedTrackElements.push(trackEl);
|
|
49
|
+
if (origin === "hls") {
|
|
50
|
+
hlsTrackElements.push(trackEl);
|
|
51
|
+
}
|
|
34
52
|
if (trackEl.track) {
|
|
35
53
|
trackEl.track.mode = "disabled";
|
|
36
54
|
}
|
|
@@ -62,6 +80,7 @@ function createCaptionsPlugin(config = {}) {
|
|
|
62
80
|
const selectTrack = (trackId) => {
|
|
63
81
|
const videoEl = getVideo();
|
|
64
82
|
if (!videoEl) return;
|
|
83
|
+
hasAutoSelected = true;
|
|
65
84
|
for (let i = 0; i < videoEl.textTracks.length; i++) {
|
|
66
85
|
const track = videoEl.textTracks[i];
|
|
67
86
|
if (track.kind !== "subtitles" && track.kind !== "captions") continue;
|
|
@@ -74,6 +93,43 @@ function createCaptionsPlugin(config = {}) {
|
|
|
74
93
|
}
|
|
75
94
|
syncTracksToState();
|
|
76
95
|
};
|
|
96
|
+
const maybeAutoSelect = () => {
|
|
97
|
+
if (!autoSelect || hasAutoSelected) return;
|
|
98
|
+
if (api?.getState("currentTextTrack")) {
|
|
99
|
+
hasAutoSelected = true;
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const tracks = api?.getState("textTracks") || [];
|
|
103
|
+
const match = tracks.find((t) => t.language === defaultLanguage);
|
|
104
|
+
if (!match) return;
|
|
105
|
+
selectTrack(match.id);
|
|
106
|
+
api?.logger.debug("Auto-selected caption track", { language: defaultLanguage, id: match.id });
|
|
107
|
+
};
|
|
108
|
+
const handleTextTracksChanged = () => {
|
|
109
|
+
syncTracksToState();
|
|
110
|
+
maybeAutoSelect();
|
|
111
|
+
};
|
|
112
|
+
const observeTextTracks = () => {
|
|
113
|
+
const videoEl = getVideo();
|
|
114
|
+
if (!videoEl || observedTextTracks === videoEl.textTracks) return;
|
|
115
|
+
unobserveTextTracks();
|
|
116
|
+
const list = videoEl.textTracks;
|
|
117
|
+
if (typeof list?.addEventListener !== "function") return;
|
|
118
|
+
observedTextTracks = list;
|
|
119
|
+
observedTextTracks.addEventListener("addtrack", handleTextTracksChanged);
|
|
120
|
+
observedTextTracks.addEventListener("removetrack", handleTextTracksChanged);
|
|
121
|
+
observedTextTracks.addEventListener("change", handleTextTracksChanged);
|
|
122
|
+
};
|
|
123
|
+
const unobserveTextTracks = () => {
|
|
124
|
+
if (typeof observedTextTracks?.removeEventListener !== "function") {
|
|
125
|
+
observedTextTracks = null;
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
observedTextTracks.removeEventListener("addtrack", handleTextTracksChanged);
|
|
129
|
+
observedTextTracks.removeEventListener("removetrack", handleTextTracksChanged);
|
|
130
|
+
observedTextTracks.removeEventListener("change", handleTextTracksChanged);
|
|
131
|
+
observedTextTracks = null;
|
|
132
|
+
};
|
|
77
133
|
const extractHlsSubtitles = () => {
|
|
78
134
|
if (!extractFromHLS || !api) return;
|
|
79
135
|
const hlsPlugin = api.getPlugin("hls-provider");
|
|
@@ -83,35 +139,55 @@ function createCaptionsPlugin(config = {}) {
|
|
|
83
139
|
api.logger.debug("Extracting HLS subtitle tracks", {
|
|
84
140
|
count: hlsInstance.subtitleTracks.length
|
|
85
141
|
});
|
|
142
|
+
removeHlsTrackElements();
|
|
86
143
|
for (const hlsTrack of hlsInstance.subtitleTracks) {
|
|
87
|
-
addTrackElement(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
144
|
+
addTrackElement(
|
|
145
|
+
{
|
|
146
|
+
language: hlsTrack.lang || "unknown",
|
|
147
|
+
label: hlsTrack.name || `Subtitle ${hlsTrack.id}`,
|
|
148
|
+
src: hlsTrack.url,
|
|
149
|
+
kind: "subtitles"
|
|
150
|
+
},
|
|
151
|
+
"hls"
|
|
152
|
+
);
|
|
93
153
|
}
|
|
94
154
|
syncTracksToState();
|
|
95
|
-
|
|
96
|
-
|
|
155
|
+
maybeAutoSelect();
|
|
156
|
+
};
|
|
157
|
+
const unsubscribeFromHls = () => {
|
|
158
|
+
if (hlsRetryTimer) {
|
|
159
|
+
clearTimeout(hlsRetryTimer);
|
|
160
|
+
hlsRetryTimer = null;
|
|
97
161
|
}
|
|
162
|
+
if (!hlsSubtitleHandler) return;
|
|
163
|
+
const hlsInstance = api?.getPlugin("hls-provider")?.getHlsInstance();
|
|
164
|
+
hlsInstance?.off(HLS_SUBTITLE_TRACKS_UPDATED, hlsSubtitleHandler);
|
|
165
|
+
hlsSubtitleHandler = null;
|
|
98
166
|
};
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
const
|
|
102
|
-
if (
|
|
103
|
-
|
|
104
|
-
|
|
167
|
+
const syncFromHls = () => {
|
|
168
|
+
if (!extractFromHLS || !api) return;
|
|
169
|
+
const hlsPlugin = api.getPlugin("hls-provider");
|
|
170
|
+
if (!hlsPlugin || hlsPlugin.isNativeHLS()) return;
|
|
171
|
+
const hlsInstance = hlsPlugin.getHlsInstance();
|
|
172
|
+
if (!hlsInstance) {
|
|
173
|
+
if (!hlsRetryUsed) {
|
|
174
|
+
hlsRetryUsed = true;
|
|
175
|
+
hlsRetryTimer = setTimeout(() => {
|
|
176
|
+
hlsRetryTimer = null;
|
|
177
|
+
syncFromHls();
|
|
178
|
+
}, HLS_INSTANCE_RETRY_MS);
|
|
179
|
+
}
|
|
180
|
+
return;
|
|
105
181
|
}
|
|
182
|
+
unsubscribeFromHls();
|
|
183
|
+
hlsSubtitleHandler = () => extractHlsSubtitles();
|
|
184
|
+
hlsInstance.on(HLS_SUBTITLE_TRACKS_UPDATED, hlsSubtitleHandler);
|
|
185
|
+
extractHlsSubtitles();
|
|
106
186
|
};
|
|
107
187
|
const initSources = () => {
|
|
108
188
|
if (!config.sources?.length) return;
|
|
109
189
|
for (const source of config.sources) {
|
|
110
|
-
addTrackElement(source);
|
|
111
|
-
}
|
|
112
|
-
syncTracksToState();
|
|
113
|
-
if (autoSelect) {
|
|
114
|
-
autoSelectTrack();
|
|
190
|
+
addTrackElement(source, "config");
|
|
115
191
|
}
|
|
116
192
|
};
|
|
117
193
|
return {
|
|
@@ -130,33 +206,36 @@ function createCaptionsPlugin(config = {}) {
|
|
|
130
206
|
});
|
|
131
207
|
const unsubLoaded = api.on("media:loaded", () => {
|
|
132
208
|
video = null;
|
|
209
|
+
hasAutoSelected = false;
|
|
210
|
+
hlsRetryUsed = false;
|
|
133
211
|
cleanupTracks();
|
|
134
212
|
initSources();
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
213
|
+
observeTextTracks();
|
|
214
|
+
syncTracksToState();
|
|
215
|
+
maybeAutoSelect();
|
|
216
|
+
syncFromHls();
|
|
138
217
|
});
|
|
139
218
|
const unsubLoadRequest = api.on("media:load-request", () => {
|
|
140
219
|
video = null;
|
|
220
|
+
hasAutoSelected = false;
|
|
221
|
+
hlsRetryUsed = false;
|
|
222
|
+
unsubscribeFromHls();
|
|
223
|
+
unobserveTextTracks();
|
|
141
224
|
cleanupTracks();
|
|
142
225
|
});
|
|
143
226
|
api.onDestroy(() => {
|
|
144
227
|
unsubTrackText();
|
|
145
228
|
unsubLoaded();
|
|
146
229
|
unsubLoadRequest();
|
|
230
|
+
unsubscribeFromHls();
|
|
231
|
+
unobserveTextTracks();
|
|
147
232
|
cleanupTracks();
|
|
148
|
-
if (hlsSubtitleHandler) {
|
|
149
|
-
const hlsPlugin = api?.getPlugin("hls-provider");
|
|
150
|
-
const hlsInstance = hlsPlugin?.getHlsInstance();
|
|
151
|
-
if (hlsInstance) {
|
|
152
|
-
hlsInstance.off("SUBTITLE_TRACKS_UPDATED", hlsSubtitleHandler);
|
|
153
|
-
}
|
|
154
|
-
hlsSubtitleHandler = null;
|
|
155
|
-
}
|
|
156
233
|
});
|
|
157
234
|
},
|
|
158
235
|
destroy() {
|
|
159
236
|
api?.logger.debug("Captions plugin destroyed");
|
|
237
|
+
unsubscribeFromHls();
|
|
238
|
+
unobserveTextTracks();
|
|
160
239
|
cleanupTracks();
|
|
161
240
|
video = null;
|
|
162
241
|
api = null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scarlett-player/captions",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.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.4.0"
|
|
34
34
|
},
|
|
35
35
|
"keywords": [
|
|
36
36
|
"video",
|