@scarlett-player/embed 0.5.2 → 0.5.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/embed.audio.js +77 -4
- package/dist/embed.audio.js.map +1 -1
- package/dist/embed.audio.umd.cjs +1 -1
- package/dist/embed.audio.umd.cjs.map +1 -1
- package/dist/embed.js +83 -4
- package/dist/embed.js.map +1 -1
- package/dist/embed.umd.cjs +1 -1
- package/dist/embed.umd.cjs.map +1 -1
- package/dist/embed.video.js +77 -4
- package/dist/embed.video.js.map +1 -1
- package/dist/embed.video.umd.cjs +1 -1
- package/dist/embed.video.umd.cjs.map +1 -1
- package/package.json +9 -9
package/dist/embed.audio.js
CHANGED
|
@@ -123,12 +123,44 @@ function setupHlsEventHandlers(hls, api, callbacks) {
|
|
|
123
123
|
addHandler("hlsLevelLoaded", (_event, data) => {
|
|
124
124
|
if (data.details?.live !== void 0) {
|
|
125
125
|
api.setState("live", data.details.live);
|
|
126
|
+
if (data.details.live) {
|
|
127
|
+
const video = hls.media;
|
|
128
|
+
if (video && video.seekable && video.seekable.length > 0) {
|
|
129
|
+
const start = video.seekable.start(0);
|
|
130
|
+
const end = video.seekable.end(video.seekable.length - 1);
|
|
131
|
+
api.setState("seekableRange", { start, end });
|
|
132
|
+
const threshold = (data.details.targetduration ?? 3) * 3;
|
|
133
|
+
const isAtLiveEdge = end - video.currentTime < threshold;
|
|
134
|
+
api.setState("liveEdge", isAtLiveEdge);
|
|
135
|
+
const latency = end - video.currentTime;
|
|
136
|
+
api.setState("liveLatency", Math.max(0, latency));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
126
139
|
callbacks.onLiveUpdate?.();
|
|
127
140
|
}
|
|
128
141
|
});
|
|
129
142
|
addHandler("hlsError", (_event, data) => {
|
|
130
143
|
const error = parseHlsError(data);
|
|
131
|
-
|
|
144
|
+
const isBufferHoleSeek = !error.fatal && (error.details?.includes("bufferStalledError") || data.reason?.includes("buffer holes"));
|
|
145
|
+
if (isBufferHoleSeek) {
|
|
146
|
+
api.logger.debug(`HLS buffer recovery: ${error.reason || error.details}`, {
|
|
147
|
+
details: error.details,
|
|
148
|
+
reason: error.reason
|
|
149
|
+
});
|
|
150
|
+
} else if (error.fatal) {
|
|
151
|
+
api.logger.error(`HLS fatal error: ${error.details} (type=${error.type})`, {
|
|
152
|
+
type: error.type,
|
|
153
|
+
details: error.details,
|
|
154
|
+
url: error.url
|
|
155
|
+
});
|
|
156
|
+
} else {
|
|
157
|
+
api.logger.warn(`HLS error: ${error.details} (type=${error.type}, fatal=${error.fatal})`, {
|
|
158
|
+
type: error.type,
|
|
159
|
+
details: error.details,
|
|
160
|
+
fatal: error.fatal,
|
|
161
|
+
url: error.url
|
|
162
|
+
});
|
|
163
|
+
}
|
|
132
164
|
callbacks.onError?.(error);
|
|
133
165
|
});
|
|
134
166
|
return () => {
|
|
@@ -150,6 +182,8 @@ function setupVideoEventHandlers(video, api) {
|
|
|
150
182
|
addHandler("playing", () => {
|
|
151
183
|
api.setState("playing", true);
|
|
152
184
|
api.setState("paused", false);
|
|
185
|
+
api.setState("waiting", false);
|
|
186
|
+
api.setState("buffering", false);
|
|
153
187
|
api.setState("playbackState", "playing");
|
|
154
188
|
});
|
|
155
189
|
addHandler("pause", () => {
|
|
@@ -166,6 +200,15 @@ function setupVideoEventHandlers(video, api) {
|
|
|
166
200
|
addHandler("timeupdate", () => {
|
|
167
201
|
api.setState("currentTime", video.currentTime);
|
|
168
202
|
api.emit("playback:timeupdate", { currentTime: video.currentTime });
|
|
203
|
+
const isLive = api.getState("live");
|
|
204
|
+
if (isLive && video.seekable && video.seekable.length > 0) {
|
|
205
|
+
const start = video.seekable.start(0);
|
|
206
|
+
const end = video.seekable.end(video.seekable.length - 1);
|
|
207
|
+
api.setState("seekableRange", { start, end });
|
|
208
|
+
const isAtLiveEdge = end - video.currentTime < 10;
|
|
209
|
+
api.setState("liveEdge", isAtLiveEdge);
|
|
210
|
+
api.setState("liveLatency", Math.max(0, end - video.currentTime));
|
|
211
|
+
}
|
|
169
212
|
});
|
|
170
213
|
addHandler("durationchange", () => {
|
|
171
214
|
api.setState("duration", video.duration || 0);
|
|
@@ -3880,8 +3923,9 @@ class ScarlettPlayer {
|
|
|
3880
3923
|
*/
|
|
3881
3924
|
setPlaybackRate(rate) {
|
|
3882
3925
|
this.checkDestroyed();
|
|
3883
|
-
|
|
3884
|
-
this.
|
|
3926
|
+
const clampedRate = Math.max(0.0625, Math.min(16, rate));
|
|
3927
|
+
this.stateManager.set("playbackRate", clampedRate);
|
|
3928
|
+
this.eventBus.emit("playback:ratechange", { rate: clampedRate });
|
|
3885
3929
|
}
|
|
3886
3930
|
/**
|
|
3887
3931
|
* Set autoplay state.
|
|
@@ -4010,6 +4054,13 @@ class ScarlettPlayer {
|
|
|
4010
4054
|
}
|
|
4011
4055
|
const provider = this._currentProvider;
|
|
4012
4056
|
if (typeof provider.setLevel === "function") {
|
|
4057
|
+
if (index !== -1) {
|
|
4058
|
+
const levels = this.getQualities();
|
|
4059
|
+
if (levels.length > 0 && (index < 0 || index >= levels.length)) {
|
|
4060
|
+
this.logger.warn(`Invalid quality index: ${index} (available: ${levels.length})`);
|
|
4061
|
+
return;
|
|
4062
|
+
}
|
|
4063
|
+
}
|
|
4013
4064
|
provider.setLevel(index);
|
|
4014
4065
|
this.eventBus.emit("quality:change", {
|
|
4015
4066
|
quality: index === -1 ? "auto" : `level-${index}`,
|
|
@@ -4250,18 +4301,40 @@ class ScarlettPlayer {
|
|
|
4250
4301
|
* @private
|
|
4251
4302
|
*/
|
|
4252
4303
|
detectMimeType(source) {
|
|
4253
|
-
|
|
4304
|
+
let path = source;
|
|
4305
|
+
try {
|
|
4306
|
+
path = new URL(source).pathname;
|
|
4307
|
+
} catch {
|
|
4308
|
+
const noQuery = source.split("?")[0] ?? source;
|
|
4309
|
+
path = noQuery.split("#")[0] ?? noQuery;
|
|
4310
|
+
}
|
|
4311
|
+
const ext = path.split(".").pop()?.toLowerCase() ?? "";
|
|
4254
4312
|
switch (ext) {
|
|
4255
4313
|
case "m3u8":
|
|
4256
4314
|
return "application/x-mpegURL";
|
|
4257
4315
|
case "mpd":
|
|
4258
4316
|
return "application/dash+xml";
|
|
4259
4317
|
case "mp4":
|
|
4318
|
+
case "m4v":
|
|
4260
4319
|
return "video/mp4";
|
|
4261
4320
|
case "webm":
|
|
4262
4321
|
return "video/webm";
|
|
4263
4322
|
case "ogg":
|
|
4323
|
+
case "ogv":
|
|
4264
4324
|
return "video/ogg";
|
|
4325
|
+
case "mov":
|
|
4326
|
+
return "video/quicktime";
|
|
4327
|
+
case "mkv":
|
|
4328
|
+
return "video/x-matroska";
|
|
4329
|
+
case "mp3":
|
|
4330
|
+
return "audio/mpeg";
|
|
4331
|
+
case "wav":
|
|
4332
|
+
return "audio/wav";
|
|
4333
|
+
case "flac":
|
|
4334
|
+
return "audio/flac";
|
|
4335
|
+
case "aac":
|
|
4336
|
+
case "m4a":
|
|
4337
|
+
return "audio/mp4";
|
|
4265
4338
|
default:
|
|
4266
4339
|
return "video/mp4";
|
|
4267
4340
|
}
|