@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.video.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);
|
|
@@ -5259,8 +5302,9 @@ class ScarlettPlayer {
|
|
|
5259
5302
|
*/
|
|
5260
5303
|
setPlaybackRate(rate) {
|
|
5261
5304
|
this.checkDestroyed();
|
|
5262
|
-
|
|
5263
|
-
this.
|
|
5305
|
+
const clampedRate = Math.max(0.0625, Math.min(16, rate));
|
|
5306
|
+
this.stateManager.set("playbackRate", clampedRate);
|
|
5307
|
+
this.eventBus.emit("playback:ratechange", { rate: clampedRate });
|
|
5264
5308
|
}
|
|
5265
5309
|
/**
|
|
5266
5310
|
* Set autoplay state.
|
|
@@ -5389,6 +5433,13 @@ class ScarlettPlayer {
|
|
|
5389
5433
|
}
|
|
5390
5434
|
const provider = this._currentProvider;
|
|
5391
5435
|
if (typeof provider.setLevel === "function") {
|
|
5436
|
+
if (index !== -1) {
|
|
5437
|
+
const levels = this.getQualities();
|
|
5438
|
+
if (levels.length > 0 && (index < 0 || index >= levels.length)) {
|
|
5439
|
+
this.logger.warn(`Invalid quality index: ${index} (available: ${levels.length})`);
|
|
5440
|
+
return;
|
|
5441
|
+
}
|
|
5442
|
+
}
|
|
5392
5443
|
provider.setLevel(index);
|
|
5393
5444
|
this.eventBus.emit("quality:change", {
|
|
5394
5445
|
quality: index === -1 ? "auto" : `level-${index}`,
|
|
@@ -5629,18 +5680,40 @@ class ScarlettPlayer {
|
|
|
5629
5680
|
* @private
|
|
5630
5681
|
*/
|
|
5631
5682
|
detectMimeType(source) {
|
|
5632
|
-
|
|
5683
|
+
let path = source;
|
|
5684
|
+
try {
|
|
5685
|
+
path = new URL(source).pathname;
|
|
5686
|
+
} catch {
|
|
5687
|
+
const noQuery = source.split("?")[0] ?? source;
|
|
5688
|
+
path = noQuery.split("#")[0] ?? noQuery;
|
|
5689
|
+
}
|
|
5690
|
+
const ext = path.split(".").pop()?.toLowerCase() ?? "";
|
|
5633
5691
|
switch (ext) {
|
|
5634
5692
|
case "m3u8":
|
|
5635
5693
|
return "application/x-mpegURL";
|
|
5636
5694
|
case "mpd":
|
|
5637
5695
|
return "application/dash+xml";
|
|
5638
5696
|
case "mp4":
|
|
5697
|
+
case "m4v":
|
|
5639
5698
|
return "video/mp4";
|
|
5640
5699
|
case "webm":
|
|
5641
5700
|
return "video/webm";
|
|
5642
5701
|
case "ogg":
|
|
5702
|
+
case "ogv":
|
|
5643
5703
|
return "video/ogg";
|
|
5704
|
+
case "mov":
|
|
5705
|
+
return "video/quicktime";
|
|
5706
|
+
case "mkv":
|
|
5707
|
+
return "video/x-matroska";
|
|
5708
|
+
case "mp3":
|
|
5709
|
+
return "audio/mpeg";
|
|
5710
|
+
case "wav":
|
|
5711
|
+
return "audio/wav";
|
|
5712
|
+
case "flac":
|
|
5713
|
+
return "audio/flac";
|
|
5714
|
+
case "aac":
|
|
5715
|
+
case "m4a":
|
|
5716
|
+
return "audio/mp4";
|
|
5644
5717
|
default:
|
|
5645
5718
|
return "video/mp4";
|
|
5646
5719
|
}
|