@scarlett-player/hls 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.
@@ -128,12 +128,44 @@ function setupHlsEventHandlers(hls, api, callbacks) {
128
128
  addHandler("hlsLevelLoaded", (_event, data) => {
129
129
  if (data.details?.live !== void 0) {
130
130
  api.setState("live", data.details.live);
131
+ if (data.details.live) {
132
+ const video = hls.media;
133
+ if (video && video.seekable && video.seekable.length > 0) {
134
+ const start = video.seekable.start(0);
135
+ const end = video.seekable.end(video.seekable.length - 1);
136
+ api.setState("seekableRange", { start, end });
137
+ const threshold = (data.details.targetduration ?? 3) * 3;
138
+ const isAtLiveEdge = end - video.currentTime < threshold;
139
+ api.setState("liveEdge", isAtLiveEdge);
140
+ const latency = end - video.currentTime;
141
+ api.setState("liveLatency", Math.max(0, latency));
142
+ }
143
+ }
131
144
  callbacks.onLiveUpdate?.();
132
145
  }
133
146
  });
134
147
  addHandler("hlsError", (_event, data) => {
135
148
  const error = parseHlsError(data);
136
- api.logger.warn("HLS error", { error });
149
+ const isBufferHoleSeek = !error.fatal && (error.details?.includes("bufferStalledError") || data.reason?.includes("buffer holes"));
150
+ if (isBufferHoleSeek) {
151
+ api.logger.debug(`HLS buffer recovery: ${error.reason || error.details}`, {
152
+ details: error.details,
153
+ reason: error.reason
154
+ });
155
+ } else if (error.fatal) {
156
+ api.logger.error(`HLS fatal error: ${error.details} (type=${error.type})`, {
157
+ type: error.type,
158
+ details: error.details,
159
+ url: error.url
160
+ });
161
+ } else {
162
+ api.logger.warn(`HLS error: ${error.details} (type=${error.type}, fatal=${error.fatal})`, {
163
+ type: error.type,
164
+ details: error.details,
165
+ fatal: error.fatal,
166
+ url: error.url
167
+ });
168
+ }
137
169
  callbacks.onError?.(error);
138
170
  });
139
171
  return () => {
@@ -155,6 +187,8 @@ function setupVideoEventHandlers(video, api) {
155
187
  addHandler("playing", () => {
156
188
  api.setState("playing", true);
157
189
  api.setState("paused", false);
190
+ api.setState("waiting", false);
191
+ api.setState("buffering", false);
158
192
  api.setState("playbackState", "playing");
159
193
  });
160
194
  addHandler("pause", () => {
@@ -171,6 +205,15 @@ function setupVideoEventHandlers(video, api) {
171
205
  addHandler("timeupdate", () => {
172
206
  api.setState("currentTime", video.currentTime);
173
207
  api.emit("playback:timeupdate", { currentTime: video.currentTime });
208
+ const isLive = api.getState("live");
209
+ if (isLive && video.seekable && video.seekable.length > 0) {
210
+ const start = video.seekable.start(0);
211
+ const end = video.seekable.end(video.seekable.length - 1);
212
+ api.setState("seekableRange", { start, end });
213
+ const isAtLiveEdge = end - video.currentTime < 10;
214
+ api.setState("liveEdge", isAtLiveEdge);
215
+ api.setState("liveLatency", Math.max(0, end - video.currentTime));
216
+ }
174
217
  });
175
218
  addHandler("durationchange", () => {
176
219
  api.setState("duration", video.duration || 0);
package/dist/index.cjs CHANGED
@@ -217,12 +217,44 @@ function setupHlsEventHandlers(hls, api, callbacks) {
217
217
  addHandler("hlsLevelLoaded", (_event, data) => {
218
218
  if (data.details?.live !== void 0) {
219
219
  api.setState("live", data.details.live);
220
+ if (data.details.live) {
221
+ const video = hls.media;
222
+ if (video && video.seekable && video.seekable.length > 0) {
223
+ const start = video.seekable.start(0);
224
+ const end = video.seekable.end(video.seekable.length - 1);
225
+ api.setState("seekableRange", { start, end });
226
+ const threshold = (data.details.targetduration ?? 3) * 3;
227
+ const isAtLiveEdge = end - video.currentTime < threshold;
228
+ api.setState("liveEdge", isAtLiveEdge);
229
+ const latency = end - video.currentTime;
230
+ api.setState("liveLatency", Math.max(0, latency));
231
+ }
232
+ }
220
233
  callbacks.onLiveUpdate?.();
221
234
  }
222
235
  });
223
236
  addHandler("hlsError", (_event, data) => {
224
237
  const error = parseHlsError(data);
225
- api.logger.warn("HLS error", { error });
238
+ const isBufferHoleSeek = !error.fatal && (error.details?.includes("bufferStalledError") || data.reason?.includes("buffer holes"));
239
+ if (isBufferHoleSeek) {
240
+ api.logger.debug(`HLS buffer recovery: ${error.reason || error.details}`, {
241
+ details: error.details,
242
+ reason: error.reason
243
+ });
244
+ } else if (error.fatal) {
245
+ api.logger.error(`HLS fatal error: ${error.details} (type=${error.type})`, {
246
+ type: error.type,
247
+ details: error.details,
248
+ url: error.url
249
+ });
250
+ } else {
251
+ api.logger.warn(`HLS error: ${error.details} (type=${error.type}, fatal=${error.fatal})`, {
252
+ type: error.type,
253
+ details: error.details,
254
+ fatal: error.fatal,
255
+ url: error.url
256
+ });
257
+ }
226
258
  callbacks.onError?.(error);
227
259
  });
228
260
  return () => {
@@ -244,6 +276,8 @@ function setupVideoEventHandlers(video, api) {
244
276
  addHandler("playing", () => {
245
277
  api.setState("playing", true);
246
278
  api.setState("paused", false);
279
+ api.setState("waiting", false);
280
+ api.setState("buffering", false);
247
281
  api.setState("playbackState", "playing");
248
282
  });
249
283
  addHandler("pause", () => {
@@ -260,6 +294,15 @@ function setupVideoEventHandlers(video, api) {
260
294
  addHandler("timeupdate", () => {
261
295
  api.setState("currentTime", video.currentTime);
262
296
  api.emit("playback:timeupdate", { currentTime: video.currentTime });
297
+ const isLive = api.getState("live");
298
+ if (isLive && video.seekable && video.seekable.length > 0) {
299
+ const start = video.seekable.start(0);
300
+ const end = video.seekable.end(video.seekable.length - 1);
301
+ api.setState("seekableRange", { start, end });
302
+ const isAtLiveEdge = end - video.currentTime < 10;
303
+ api.setState("liveEdge", isAtLiveEdge);
304
+ api.setState("liveLatency", Math.max(0, end - video.currentTime));
305
+ }
263
306
  });
264
307
  addHandler("durationchange", () => {
265
308
  api.setState("duration", video.duration || 0);
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  mapLevels,
4
4
  setupHlsEventHandlers,
5
5
  setupVideoEventHandlers
6
- } from "./chunk-2BPI5GEH.js";
6
+ } from "./chunk-5JANLXKE.js";
7
7
 
8
8
  // src/hls-loader.ts
9
9
  var hlsConstructor = null;
package/dist/light.cjs CHANGED
@@ -217,12 +217,44 @@ function setupHlsEventHandlers(hls, api, callbacks) {
217
217
  addHandler("hlsLevelLoaded", (_event, data) => {
218
218
  if (data.details?.live !== void 0) {
219
219
  api.setState("live", data.details.live);
220
+ if (data.details.live) {
221
+ const video = hls.media;
222
+ if (video && video.seekable && video.seekable.length > 0) {
223
+ const start = video.seekable.start(0);
224
+ const end = video.seekable.end(video.seekable.length - 1);
225
+ api.setState("seekableRange", { start, end });
226
+ const threshold = (data.details.targetduration ?? 3) * 3;
227
+ const isAtLiveEdge = end - video.currentTime < threshold;
228
+ api.setState("liveEdge", isAtLiveEdge);
229
+ const latency = end - video.currentTime;
230
+ api.setState("liveLatency", Math.max(0, latency));
231
+ }
232
+ }
220
233
  callbacks.onLiveUpdate?.();
221
234
  }
222
235
  });
223
236
  addHandler("hlsError", (_event, data) => {
224
237
  const error = parseHlsError(data);
225
- api.logger.warn("HLS error", { error });
238
+ const isBufferHoleSeek = !error.fatal && (error.details?.includes("bufferStalledError") || data.reason?.includes("buffer holes"));
239
+ if (isBufferHoleSeek) {
240
+ api.logger.debug(`HLS buffer recovery: ${error.reason || error.details}`, {
241
+ details: error.details,
242
+ reason: error.reason
243
+ });
244
+ } else if (error.fatal) {
245
+ api.logger.error(`HLS fatal error: ${error.details} (type=${error.type})`, {
246
+ type: error.type,
247
+ details: error.details,
248
+ url: error.url
249
+ });
250
+ } else {
251
+ api.logger.warn(`HLS error: ${error.details} (type=${error.type}, fatal=${error.fatal})`, {
252
+ type: error.type,
253
+ details: error.details,
254
+ fatal: error.fatal,
255
+ url: error.url
256
+ });
257
+ }
226
258
  callbacks.onError?.(error);
227
259
  });
228
260
  return () => {
@@ -244,6 +276,8 @@ function setupVideoEventHandlers(video, api) {
244
276
  addHandler("playing", () => {
245
277
  api.setState("playing", true);
246
278
  api.setState("paused", false);
279
+ api.setState("waiting", false);
280
+ api.setState("buffering", false);
247
281
  api.setState("playbackState", "playing");
248
282
  });
249
283
  addHandler("pause", () => {
@@ -260,6 +294,15 @@ function setupVideoEventHandlers(video, api) {
260
294
  addHandler("timeupdate", () => {
261
295
  api.setState("currentTime", video.currentTime);
262
296
  api.emit("playback:timeupdate", { currentTime: video.currentTime });
297
+ const isLive = api.getState("live");
298
+ if (isLive && video.seekable && video.seekable.length > 0) {
299
+ const start = video.seekable.start(0);
300
+ const end = video.seekable.end(video.seekable.length - 1);
301
+ api.setState("seekableRange", { start, end });
302
+ const isAtLiveEdge = end - video.currentTime < 10;
303
+ api.setState("liveEdge", isAtLiveEdge);
304
+ api.setState("liveLatency", Math.max(0, end - video.currentTime));
305
+ }
263
306
  });
264
307
  addHandler("durationchange", () => {
265
308
  api.setState("duration", video.duration || 0);
package/dist/light.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  mapLevels,
4
4
  setupHlsEventHandlers,
5
5
  setupVideoEventHandlers
6
- } from "./chunk-2BPI5GEH.js";
6
+ } from "./chunk-5JANLXKE.js";
7
7
 
8
8
  // src/hls-loader-light.ts
9
9
  var hlsConstructor = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scarlett-player/hls",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "HLS Provider Plugin for Scarlett Player",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -22,8 +22,8 @@
22
22
  "dist"
23
23
  ],
24
24
  "peerDependencies": {
25
- "@scarlett-player/core": "^0.5.2",
26
- "hls.js": "^1.4.0"
25
+ "@scarlett-player/core": "^0.5.3",
26
+ "hls.js": "^1.5.0"
27
27
  },
28
28
  "peerDependenciesMeta": {
29
29
  "hls.js": {
@@ -31,13 +31,13 @@
31
31
  }
32
32
  },
33
33
  "devDependencies": {
34
- "hls.js": "^1.5.0",
34
+ "hls.js": "^1.6.0",
35
35
  "typescript": "^5.3.0",
36
36
  "tsup": "^8.0.0",
37
37
  "vitest": "^1.6.0",
38
38
  "@vitest/coverage-v8": "^1.6.0",
39
39
  "jsdom": "^24.0.0",
40
- "@scarlett-player/core": "0.5.2"
40
+ "@scarlett-player/core": "0.5.3"
41
41
  },
42
42
  "keywords": [
43
43
  "video",