@scarlett-player/hls 0.5.2 → 1.0.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/{chunk-2BPI5GEH.js → chunk-OEPNMGNQ.js} +65 -1
- package/dist/index.cjs +71 -2
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +9 -2
- package/dist/light.cjs +52 -1
- package/dist/light.d.cts +2 -2
- package/dist/light.d.ts +2 -2
- package/dist/light.js +1 -1
- package/dist/{types-Df2TUpPu.d.cts → types-CRKmNxEW.d.cts} +4 -0
- package/dist/{types-Df2TUpPu.d.ts → types-CRKmNxEW.d.ts} +4 -0
- package/package.json +5 -5
|
@@ -44,6 +44,18 @@ function mapLevels(levels, _currentLevel) {
|
|
|
44
44
|
codec: level.codecSet
|
|
45
45
|
}));
|
|
46
46
|
}
|
|
47
|
+
function getInitialBandwidthEstimate(overrideBps) {
|
|
48
|
+
const HLS_DEFAULT_ESTIMATE = 5e5;
|
|
49
|
+
if (overrideBps !== void 0 && overrideBps > 0) {
|
|
50
|
+
return overrideBps;
|
|
51
|
+
}
|
|
52
|
+
const connection = navigator.connection;
|
|
53
|
+
if (connection?.downlink && connection.downlink > 0) {
|
|
54
|
+
const bps = connection.downlink * 1e6;
|
|
55
|
+
return Math.round(bps * 0.85);
|
|
56
|
+
}
|
|
57
|
+
return HLS_DEFAULT_ESTIMATE;
|
|
58
|
+
}
|
|
47
59
|
|
|
48
60
|
// src/event-map.ts
|
|
49
61
|
var HLS_ERROR_TYPES = {
|
|
@@ -118,6 +130,14 @@ function setupHlsEventHandlers(hls, api, callbacks) {
|
|
|
118
130
|
});
|
|
119
131
|
callbacks.onLevelSwitched?.(data.level);
|
|
120
132
|
});
|
|
133
|
+
let lastBandwidthUpdate = 0;
|
|
134
|
+
addHandler("hlsFragLoaded", () => {
|
|
135
|
+
const now = Date.now();
|
|
136
|
+
if (now - lastBandwidthUpdate >= 2e3 && hls.bandwidthEstimate) {
|
|
137
|
+
lastBandwidthUpdate = now;
|
|
138
|
+
api.setState("bandwidth", Math.round(hls.bandwidthEstimate));
|
|
139
|
+
}
|
|
140
|
+
});
|
|
121
141
|
addHandler("hlsFragBuffered", () => {
|
|
122
142
|
api.setState("buffering", false);
|
|
123
143
|
callbacks.onBufferUpdate?.();
|
|
@@ -128,12 +148,44 @@ function setupHlsEventHandlers(hls, api, callbacks) {
|
|
|
128
148
|
addHandler("hlsLevelLoaded", (_event, data) => {
|
|
129
149
|
if (data.details?.live !== void 0) {
|
|
130
150
|
api.setState("live", data.details.live);
|
|
151
|
+
if (data.details.live) {
|
|
152
|
+
const video = hls.media;
|
|
153
|
+
if (video && video.seekable && video.seekable.length > 0) {
|
|
154
|
+
const start = video.seekable.start(0);
|
|
155
|
+
const end = video.seekable.end(video.seekable.length - 1);
|
|
156
|
+
api.setState("seekableRange", { start, end });
|
|
157
|
+
const threshold = (data.details.targetduration ?? 3) * 3;
|
|
158
|
+
const isAtLiveEdge = end - video.currentTime < threshold;
|
|
159
|
+
api.setState("liveEdge", isAtLiveEdge);
|
|
160
|
+
const latency = end - video.currentTime;
|
|
161
|
+
api.setState("liveLatency", Math.max(0, latency));
|
|
162
|
+
}
|
|
163
|
+
}
|
|
131
164
|
callbacks.onLiveUpdate?.();
|
|
132
165
|
}
|
|
133
166
|
});
|
|
134
167
|
addHandler("hlsError", (_event, data) => {
|
|
135
168
|
const error = parseHlsError(data);
|
|
136
|
-
|
|
169
|
+
const isBufferHoleSeek = !error.fatal && (error.details?.includes("bufferStalledError") || data.reason?.includes("buffer holes"));
|
|
170
|
+
if (isBufferHoleSeek) {
|
|
171
|
+
api.logger.debug(`HLS buffer recovery: ${error.reason || error.details}`, {
|
|
172
|
+
details: error.details,
|
|
173
|
+
reason: error.reason
|
|
174
|
+
});
|
|
175
|
+
} else if (error.fatal) {
|
|
176
|
+
api.logger.error(`HLS fatal error: ${error.details} (type=${error.type})`, {
|
|
177
|
+
type: error.type,
|
|
178
|
+
details: error.details,
|
|
179
|
+
url: error.url
|
|
180
|
+
});
|
|
181
|
+
} else {
|
|
182
|
+
api.logger.warn(`HLS error: ${error.details} (type=${error.type}, fatal=${error.fatal})`, {
|
|
183
|
+
type: error.type,
|
|
184
|
+
details: error.details,
|
|
185
|
+
fatal: error.fatal,
|
|
186
|
+
url: error.url
|
|
187
|
+
});
|
|
188
|
+
}
|
|
137
189
|
callbacks.onError?.(error);
|
|
138
190
|
});
|
|
139
191
|
return () => {
|
|
@@ -155,6 +207,8 @@ function setupVideoEventHandlers(video, api) {
|
|
|
155
207
|
addHandler("playing", () => {
|
|
156
208
|
api.setState("playing", true);
|
|
157
209
|
api.setState("paused", false);
|
|
210
|
+
api.setState("waiting", false);
|
|
211
|
+
api.setState("buffering", false);
|
|
158
212
|
api.setState("playbackState", "playing");
|
|
159
213
|
});
|
|
160
214
|
addHandler("pause", () => {
|
|
@@ -171,6 +225,15 @@ function setupVideoEventHandlers(video, api) {
|
|
|
171
225
|
addHandler("timeupdate", () => {
|
|
172
226
|
api.setState("currentTime", video.currentTime);
|
|
173
227
|
api.emit("playback:timeupdate", { currentTime: video.currentTime });
|
|
228
|
+
const isLive = api.getState("live");
|
|
229
|
+
if (isLive && video.seekable && video.seekable.length > 0) {
|
|
230
|
+
const start = video.seekable.start(0);
|
|
231
|
+
const end = video.seekable.end(video.seekable.length - 1);
|
|
232
|
+
api.setState("seekableRange", { start, end });
|
|
233
|
+
const isAtLiveEdge = end - video.currentTime < 10;
|
|
234
|
+
api.setState("liveEdge", isAtLiveEdge);
|
|
235
|
+
api.setState("liveLatency", Math.max(0, end - video.currentTime));
|
|
236
|
+
}
|
|
174
237
|
});
|
|
175
238
|
addHandler("durationchange", () => {
|
|
176
239
|
api.setState("duration", video.duration || 0);
|
|
@@ -262,6 +325,7 @@ function setupVideoEventHandlers(video, api) {
|
|
|
262
325
|
export {
|
|
263
326
|
formatLevel,
|
|
264
327
|
mapLevels,
|
|
328
|
+
getInitialBandwidthEstimate,
|
|
265
329
|
setupHlsEventHandlers,
|
|
266
330
|
setupVideoEventHandlers
|
|
267
331
|
};
|
package/dist/index.cjs
CHANGED
|
@@ -133,6 +133,18 @@ function mapLevels(levels, _currentLevel) {
|
|
|
133
133
|
codec: level.codecSet
|
|
134
134
|
}));
|
|
135
135
|
}
|
|
136
|
+
function getInitialBandwidthEstimate(overrideBps) {
|
|
137
|
+
const HLS_DEFAULT_ESTIMATE = 5e5;
|
|
138
|
+
if (overrideBps !== void 0 && overrideBps > 0) {
|
|
139
|
+
return overrideBps;
|
|
140
|
+
}
|
|
141
|
+
const connection = navigator.connection;
|
|
142
|
+
if (connection?.downlink && connection.downlink > 0) {
|
|
143
|
+
const bps = connection.downlink * 1e6;
|
|
144
|
+
return Math.round(bps * 0.85);
|
|
145
|
+
}
|
|
146
|
+
return HLS_DEFAULT_ESTIMATE;
|
|
147
|
+
}
|
|
136
148
|
|
|
137
149
|
// src/event-map.ts
|
|
138
150
|
var HLS_ERROR_TYPES = {
|
|
@@ -207,6 +219,14 @@ function setupHlsEventHandlers(hls, api, callbacks) {
|
|
|
207
219
|
});
|
|
208
220
|
callbacks.onLevelSwitched?.(data.level);
|
|
209
221
|
});
|
|
222
|
+
let lastBandwidthUpdate = 0;
|
|
223
|
+
addHandler("hlsFragLoaded", () => {
|
|
224
|
+
const now = Date.now();
|
|
225
|
+
if (now - lastBandwidthUpdate >= 2e3 && hls.bandwidthEstimate) {
|
|
226
|
+
lastBandwidthUpdate = now;
|
|
227
|
+
api.setState("bandwidth", Math.round(hls.bandwidthEstimate));
|
|
228
|
+
}
|
|
229
|
+
});
|
|
210
230
|
addHandler("hlsFragBuffered", () => {
|
|
211
231
|
api.setState("buffering", false);
|
|
212
232
|
callbacks.onBufferUpdate?.();
|
|
@@ -217,12 +237,44 @@ function setupHlsEventHandlers(hls, api, callbacks) {
|
|
|
217
237
|
addHandler("hlsLevelLoaded", (_event, data) => {
|
|
218
238
|
if (data.details?.live !== void 0) {
|
|
219
239
|
api.setState("live", data.details.live);
|
|
240
|
+
if (data.details.live) {
|
|
241
|
+
const video = hls.media;
|
|
242
|
+
if (video && video.seekable && video.seekable.length > 0) {
|
|
243
|
+
const start = video.seekable.start(0);
|
|
244
|
+
const end = video.seekable.end(video.seekable.length - 1);
|
|
245
|
+
api.setState("seekableRange", { start, end });
|
|
246
|
+
const threshold = (data.details.targetduration ?? 3) * 3;
|
|
247
|
+
const isAtLiveEdge = end - video.currentTime < threshold;
|
|
248
|
+
api.setState("liveEdge", isAtLiveEdge);
|
|
249
|
+
const latency = end - video.currentTime;
|
|
250
|
+
api.setState("liveLatency", Math.max(0, latency));
|
|
251
|
+
}
|
|
252
|
+
}
|
|
220
253
|
callbacks.onLiveUpdate?.();
|
|
221
254
|
}
|
|
222
255
|
});
|
|
223
256
|
addHandler("hlsError", (_event, data) => {
|
|
224
257
|
const error = parseHlsError(data);
|
|
225
|
-
|
|
258
|
+
const isBufferHoleSeek = !error.fatal && (error.details?.includes("bufferStalledError") || data.reason?.includes("buffer holes"));
|
|
259
|
+
if (isBufferHoleSeek) {
|
|
260
|
+
api.logger.debug(`HLS buffer recovery: ${error.reason || error.details}`, {
|
|
261
|
+
details: error.details,
|
|
262
|
+
reason: error.reason
|
|
263
|
+
});
|
|
264
|
+
} else if (error.fatal) {
|
|
265
|
+
api.logger.error(`HLS fatal error: ${error.details} (type=${error.type})`, {
|
|
266
|
+
type: error.type,
|
|
267
|
+
details: error.details,
|
|
268
|
+
url: error.url
|
|
269
|
+
});
|
|
270
|
+
} else {
|
|
271
|
+
api.logger.warn(`HLS error: ${error.details} (type=${error.type}, fatal=${error.fatal})`, {
|
|
272
|
+
type: error.type,
|
|
273
|
+
details: error.details,
|
|
274
|
+
fatal: error.fatal,
|
|
275
|
+
url: error.url
|
|
276
|
+
});
|
|
277
|
+
}
|
|
226
278
|
callbacks.onError?.(error);
|
|
227
279
|
});
|
|
228
280
|
return () => {
|
|
@@ -244,6 +296,8 @@ function setupVideoEventHandlers(video, api) {
|
|
|
244
296
|
addHandler("playing", () => {
|
|
245
297
|
api.setState("playing", true);
|
|
246
298
|
api.setState("paused", false);
|
|
299
|
+
api.setState("waiting", false);
|
|
300
|
+
api.setState("buffering", false);
|
|
247
301
|
api.setState("playbackState", "playing");
|
|
248
302
|
});
|
|
249
303
|
addHandler("pause", () => {
|
|
@@ -260,6 +314,15 @@ function setupVideoEventHandlers(video, api) {
|
|
|
260
314
|
addHandler("timeupdate", () => {
|
|
261
315
|
api.setState("currentTime", video.currentTime);
|
|
262
316
|
api.emit("playback:timeupdate", { currentTime: video.currentTime });
|
|
317
|
+
const isLive = api.getState("live");
|
|
318
|
+
if (isLive && video.seekable && video.seekable.length > 0) {
|
|
319
|
+
const start = video.seekable.start(0);
|
|
320
|
+
const end = video.seekable.end(video.seekable.length - 1);
|
|
321
|
+
api.setState("seekableRange", { start, end });
|
|
322
|
+
const isAtLiveEdge = end - video.currentTime < 10;
|
|
323
|
+
api.setState("liveEdge", isAtLiveEdge);
|
|
324
|
+
api.setState("liveLatency", Math.max(0, end - video.currentTime));
|
|
325
|
+
}
|
|
263
326
|
});
|
|
264
327
|
addHandler("durationchange", () => {
|
|
265
328
|
api.setState("duration", video.duration || 0);
|
|
@@ -358,6 +421,7 @@ var DEFAULT_CONFIG = {
|
|
|
358
421
|
maxMaxBufferLength: 600,
|
|
359
422
|
backBufferLength: 30,
|
|
360
423
|
enableWorker: true,
|
|
424
|
+
capLevelToPlayerSize: true,
|
|
361
425
|
// Error recovery settings
|
|
362
426
|
maxNetworkRetries: 3,
|
|
363
427
|
maxMediaRetries: 2,
|
|
@@ -427,11 +491,13 @@ function createHLSPlugin(config) {
|
|
|
427
491
|
startPosition: mergedConfig.startPosition,
|
|
428
492
|
startLevel: -1,
|
|
429
493
|
// Auto quality selection (ABR)
|
|
494
|
+
abrEwmaDefaultEstimate: getInitialBandwidthEstimate(mergedConfig.initialBandwidthEstimate),
|
|
430
495
|
lowLatencyMode: mergedConfig.lowLatencyMode,
|
|
431
496
|
maxBufferLength: mergedConfig.maxBufferLength,
|
|
432
497
|
maxMaxBufferLength: mergedConfig.maxMaxBufferLength,
|
|
433
498
|
backBufferLength: mergedConfig.backBufferLength,
|
|
434
499
|
enableWorker: mergedConfig.enableWorker,
|
|
500
|
+
capLevelToPlayerSize: mergedConfig.capLevelToPlayerSize,
|
|
435
501
|
// Minimize hls.js internal retries - we handle retries ourselves
|
|
436
502
|
fragLoadingMaxRetry: 1,
|
|
437
503
|
manifestLoadingMaxRetry: 1,
|
|
@@ -702,7 +768,10 @@ function createHLSPlugin(config) {
|
|
|
702
768
|
currentSrc = src;
|
|
703
769
|
api.setState("playbackState", "loading");
|
|
704
770
|
api.setState("buffering", true);
|
|
705
|
-
if (
|
|
771
|
+
if (api.getState("airplayActive") && supportsNativeHLS()) {
|
|
772
|
+
api.logger.info("Using native HLS (AirPlay active)");
|
|
773
|
+
await loadNative(src);
|
|
774
|
+
} else if (isHlsJsSupported()) {
|
|
706
775
|
api.logger.info("Using hls.js for HLS playback");
|
|
707
776
|
await loadWithHlsJs(src);
|
|
708
777
|
} else if (supportsNativeHLS()) {
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { H as HLSPluginConfig, I as IHLSPlugin } from './types-
|
|
2
|
-
export { a as HLSError, b as HLSLiveInfo, c as HLSQualityLevel } from './types-
|
|
1
|
+
import { H as HLSPluginConfig, I as IHLSPlugin } from './types-CRKmNxEW.cjs';
|
|
2
|
+
export { a as HLSError, b as HLSLiveInfo, c as HLSQualityLevel } from './types-CRKmNxEW.cjs';
|
|
3
3
|
import '@scarlett-player/core';
|
|
4
4
|
|
|
5
5
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { H as HLSPluginConfig, I as IHLSPlugin } from './types-
|
|
2
|
-
export { a as HLSError, b as HLSLiveInfo, c as HLSQualityLevel } from './types-
|
|
1
|
+
import { H as HLSPluginConfig, I as IHLSPlugin } from './types-CRKmNxEW.js';
|
|
2
|
+
export { a as HLSError, b as HLSLiveInfo, c as HLSQualityLevel } from './types-CRKmNxEW.js';
|
|
3
3
|
import '@scarlett-player/core';
|
|
4
4
|
|
|
5
5
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
formatLevel,
|
|
3
|
+
getInitialBandwidthEstimate,
|
|
3
4
|
mapLevels,
|
|
4
5
|
setupHlsEventHandlers,
|
|
5
6
|
setupVideoEventHandlers
|
|
6
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-OEPNMGNQ.js";
|
|
7
8
|
|
|
8
9
|
// src/hls-loader.ts
|
|
9
10
|
var hlsConstructor = null;
|
|
@@ -67,6 +68,7 @@ var DEFAULT_CONFIG = {
|
|
|
67
68
|
maxMaxBufferLength: 600,
|
|
68
69
|
backBufferLength: 30,
|
|
69
70
|
enableWorker: true,
|
|
71
|
+
capLevelToPlayerSize: true,
|
|
70
72
|
// Error recovery settings
|
|
71
73
|
maxNetworkRetries: 3,
|
|
72
74
|
maxMediaRetries: 2,
|
|
@@ -136,11 +138,13 @@ function createHLSPlugin(config) {
|
|
|
136
138
|
startPosition: mergedConfig.startPosition,
|
|
137
139
|
startLevel: -1,
|
|
138
140
|
// Auto quality selection (ABR)
|
|
141
|
+
abrEwmaDefaultEstimate: getInitialBandwidthEstimate(mergedConfig.initialBandwidthEstimate),
|
|
139
142
|
lowLatencyMode: mergedConfig.lowLatencyMode,
|
|
140
143
|
maxBufferLength: mergedConfig.maxBufferLength,
|
|
141
144
|
maxMaxBufferLength: mergedConfig.maxMaxBufferLength,
|
|
142
145
|
backBufferLength: mergedConfig.backBufferLength,
|
|
143
146
|
enableWorker: mergedConfig.enableWorker,
|
|
147
|
+
capLevelToPlayerSize: mergedConfig.capLevelToPlayerSize,
|
|
144
148
|
// Minimize hls.js internal retries - we handle retries ourselves
|
|
145
149
|
fragLoadingMaxRetry: 1,
|
|
146
150
|
manifestLoadingMaxRetry: 1,
|
|
@@ -411,7 +415,10 @@ function createHLSPlugin(config) {
|
|
|
411
415
|
currentSrc = src;
|
|
412
416
|
api.setState("playbackState", "loading");
|
|
413
417
|
api.setState("buffering", true);
|
|
414
|
-
if (
|
|
418
|
+
if (api.getState("airplayActive") && supportsNativeHLS()) {
|
|
419
|
+
api.logger.info("Using native HLS (AirPlay active)");
|
|
420
|
+
await loadNative(src);
|
|
421
|
+
} else if (isHlsJsSupported()) {
|
|
415
422
|
api.logger.info("Using hls.js for HLS playback");
|
|
416
423
|
await loadWithHlsJs(src);
|
|
417
424
|
} else if (supportsNativeHLS()) {
|
package/dist/light.cjs
CHANGED
|
@@ -207,6 +207,14 @@ function setupHlsEventHandlers(hls, api, callbacks) {
|
|
|
207
207
|
});
|
|
208
208
|
callbacks.onLevelSwitched?.(data.level);
|
|
209
209
|
});
|
|
210
|
+
let lastBandwidthUpdate = 0;
|
|
211
|
+
addHandler("hlsFragLoaded", () => {
|
|
212
|
+
const now = Date.now();
|
|
213
|
+
if (now - lastBandwidthUpdate >= 2e3 && hls.bandwidthEstimate) {
|
|
214
|
+
lastBandwidthUpdate = now;
|
|
215
|
+
api.setState("bandwidth", Math.round(hls.bandwidthEstimate));
|
|
216
|
+
}
|
|
217
|
+
});
|
|
210
218
|
addHandler("hlsFragBuffered", () => {
|
|
211
219
|
api.setState("buffering", false);
|
|
212
220
|
callbacks.onBufferUpdate?.();
|
|
@@ -217,12 +225,44 @@ function setupHlsEventHandlers(hls, api, callbacks) {
|
|
|
217
225
|
addHandler("hlsLevelLoaded", (_event, data) => {
|
|
218
226
|
if (data.details?.live !== void 0) {
|
|
219
227
|
api.setState("live", data.details.live);
|
|
228
|
+
if (data.details.live) {
|
|
229
|
+
const video = hls.media;
|
|
230
|
+
if (video && video.seekable && video.seekable.length > 0) {
|
|
231
|
+
const start = video.seekable.start(0);
|
|
232
|
+
const end = video.seekable.end(video.seekable.length - 1);
|
|
233
|
+
api.setState("seekableRange", { start, end });
|
|
234
|
+
const threshold = (data.details.targetduration ?? 3) * 3;
|
|
235
|
+
const isAtLiveEdge = end - video.currentTime < threshold;
|
|
236
|
+
api.setState("liveEdge", isAtLiveEdge);
|
|
237
|
+
const latency = end - video.currentTime;
|
|
238
|
+
api.setState("liveLatency", Math.max(0, latency));
|
|
239
|
+
}
|
|
240
|
+
}
|
|
220
241
|
callbacks.onLiveUpdate?.();
|
|
221
242
|
}
|
|
222
243
|
});
|
|
223
244
|
addHandler("hlsError", (_event, data) => {
|
|
224
245
|
const error = parseHlsError(data);
|
|
225
|
-
|
|
246
|
+
const isBufferHoleSeek = !error.fatal && (error.details?.includes("bufferStalledError") || data.reason?.includes("buffer holes"));
|
|
247
|
+
if (isBufferHoleSeek) {
|
|
248
|
+
api.logger.debug(`HLS buffer recovery: ${error.reason || error.details}`, {
|
|
249
|
+
details: error.details,
|
|
250
|
+
reason: error.reason
|
|
251
|
+
});
|
|
252
|
+
} else if (error.fatal) {
|
|
253
|
+
api.logger.error(`HLS fatal error: ${error.details} (type=${error.type})`, {
|
|
254
|
+
type: error.type,
|
|
255
|
+
details: error.details,
|
|
256
|
+
url: error.url
|
|
257
|
+
});
|
|
258
|
+
} else {
|
|
259
|
+
api.logger.warn(`HLS error: ${error.details} (type=${error.type}, fatal=${error.fatal})`, {
|
|
260
|
+
type: error.type,
|
|
261
|
+
details: error.details,
|
|
262
|
+
fatal: error.fatal,
|
|
263
|
+
url: error.url
|
|
264
|
+
});
|
|
265
|
+
}
|
|
226
266
|
callbacks.onError?.(error);
|
|
227
267
|
});
|
|
228
268
|
return () => {
|
|
@@ -244,6 +284,8 @@ function setupVideoEventHandlers(video, api) {
|
|
|
244
284
|
addHandler("playing", () => {
|
|
245
285
|
api.setState("playing", true);
|
|
246
286
|
api.setState("paused", false);
|
|
287
|
+
api.setState("waiting", false);
|
|
288
|
+
api.setState("buffering", false);
|
|
247
289
|
api.setState("playbackState", "playing");
|
|
248
290
|
});
|
|
249
291
|
addHandler("pause", () => {
|
|
@@ -260,6 +302,15 @@ function setupVideoEventHandlers(video, api) {
|
|
|
260
302
|
addHandler("timeupdate", () => {
|
|
261
303
|
api.setState("currentTime", video.currentTime);
|
|
262
304
|
api.emit("playback:timeupdate", { currentTime: video.currentTime });
|
|
305
|
+
const isLive = api.getState("live");
|
|
306
|
+
if (isLive && video.seekable && video.seekable.length > 0) {
|
|
307
|
+
const start = video.seekable.start(0);
|
|
308
|
+
const end = video.seekable.end(video.seekable.length - 1);
|
|
309
|
+
api.setState("seekableRange", { start, end });
|
|
310
|
+
const isAtLiveEdge = end - video.currentTime < 10;
|
|
311
|
+
api.setState("liveEdge", isAtLiveEdge);
|
|
312
|
+
api.setState("liveLatency", Math.max(0, end - video.currentTime));
|
|
313
|
+
}
|
|
263
314
|
});
|
|
264
315
|
addHandler("durationchange", () => {
|
|
265
316
|
api.setState("duration", video.duration || 0);
|
package/dist/light.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { H as HLSPluginConfig, I as IHLSPlugin } from './types-
|
|
2
|
-
export { a as HLSError, b as HLSLiveInfo, c as HLSQualityLevel } from './types-
|
|
1
|
+
import { H as HLSPluginConfig, I as IHLSPlugin } from './types-CRKmNxEW.cjs';
|
|
2
|
+
export { a as HLSError, b as HLSLiveInfo, c as HLSQualityLevel } from './types-CRKmNxEW.cjs';
|
|
3
3
|
import '@scarlett-player/core';
|
|
4
4
|
|
|
5
5
|
/**
|
package/dist/light.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { H as HLSPluginConfig, I as IHLSPlugin } from './types-
|
|
2
|
-
export { a as HLSError, b as HLSLiveInfo, c as HLSQualityLevel } from './types-
|
|
1
|
+
import { H as HLSPluginConfig, I as IHLSPlugin } from './types-CRKmNxEW.js';
|
|
2
|
+
export { a as HLSError, b as HLSLiveInfo, c as HLSQualityLevel } from './types-CRKmNxEW.js';
|
|
3
3
|
import '@scarlett-player/core';
|
|
4
4
|
|
|
5
5
|
/**
|
package/dist/light.js
CHANGED
|
@@ -26,6 +26,10 @@ interface HLSPluginConfig {
|
|
|
26
26
|
maxNetworkRetries?: number;
|
|
27
27
|
/** Max media error retries before giving up (default: 2) */
|
|
28
28
|
maxMediaRetries?: number;
|
|
29
|
+
/** Cap quality to player element dimensions (default: true) */
|
|
30
|
+
capLevelToPlayerSize?: boolean;
|
|
31
|
+
/** Override initial bandwidth estimate in bits per second */
|
|
32
|
+
initialBandwidthEstimate?: number;
|
|
29
33
|
/** Base retry delay in milliseconds (default: 1000) */
|
|
30
34
|
retryDelayMs?: number;
|
|
31
35
|
/** Exponential backoff multiplier (default: 2) */
|
|
@@ -26,6 +26,10 @@ interface HLSPluginConfig {
|
|
|
26
26
|
maxNetworkRetries?: number;
|
|
27
27
|
/** Max media error retries before giving up (default: 2) */
|
|
28
28
|
maxMediaRetries?: number;
|
|
29
|
+
/** Cap quality to player element dimensions (default: true) */
|
|
30
|
+
capLevelToPlayerSize?: boolean;
|
|
31
|
+
/** Override initial bandwidth estimate in bits per second */
|
|
32
|
+
initialBandwidthEstimate?: number;
|
|
29
33
|
/** Base retry delay in milliseconds (default: 1000) */
|
|
30
34
|
retryDelayMs?: number;
|
|
31
35
|
/** Exponential backoff multiplier (default: 2) */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scarlett-player/hls",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
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.
|
|
26
|
-
"hls.js": "^1.
|
|
25
|
+
"@scarlett-player/core": "^1.0.0",
|
|
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.
|
|
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.
|
|
40
|
+
"@scarlett-player/core": "1.0.0"
|
|
41
41
|
},
|
|
42
42
|
"keywords": [
|
|
43
43
|
"video",
|