@scarlett-player/hls 1.7.0 → 1.8.1

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/README.md CHANGED
@@ -11,16 +11,14 @@ npm install @scarlett-player/core @scarlett-player/hls
11
11
  ## Usage
12
12
 
13
13
  ```typescript
14
- import { ScarlettPlayer } from '@scarlett-player/core';
14
+ import { createPlayer } from '@scarlett-player/core';
15
15
  import { createHLSPlugin } from '@scarlett-player/hls';
16
16
 
17
- const player = new ScarlettPlayer({
17
+ const player = await createPlayer({
18
18
  container: document.getElementById('player'),
19
+ src: 'https://example.com/video.m3u8',
19
20
  plugins: [createHLSPlugin()],
20
21
  });
21
-
22
- await player.init();
23
- await player.load('https://example.com/video.m3u8');
24
22
  ```
25
23
 
26
24
  ## Features
@@ -44,6 +42,8 @@ All options are optional; defaults shown.
44
42
 
45
43
  ```typescript
46
44
  createHLSPlugin({
45
+ debug: false, // hls.js debug logging
46
+
47
47
  // Buffering
48
48
  maxBufferLength: 30, // Forward buffer target (seconds)
49
49
  maxMaxBufferLength: 600, // Hard forward buffer cap (seconds)
@@ -96,15 +96,15 @@ import { createHLSPlugin } from '@scarlett-player/hls/light';
96
96
  ## Quality Selection
97
97
 
98
98
  ```typescript
99
- // Get available qualities
99
+ // Get available qualities (HLSQualityLevel[], empty on native Safari HLS)
100
100
  const qualities = player.getQualities();
101
- // [{ index: 0, height: 1080, bitrate: 5000000 }, ...]
101
+ // [{ index: 0, width: 1920, height: 1080, bitrate: 5000000, label: '1080p', codec: 'avc1,mp4a' }, ...]
102
102
 
103
- // Set quality (use -1 for auto)
104
- player.setQuality(0); // Highest quality
103
+ // Set quality by index (use -1 for auto)
104
+ player.setQuality(0);
105
105
  player.setQuality(-1); // Auto/ABR
106
106
 
107
- // Get current quality
107
+ // Get current quality index (-1 while auto)
108
108
  const current = player.getCurrentQuality();
109
109
  ```
110
110
 
@@ -222,8 +222,14 @@ function setupVideoEventHandlers(video, api) {
222
222
  video.addEventListener(event, handler);
223
223
  handlers.push({ event, handler });
224
224
  };
225
+ const syncEndedFromElement = () => {
226
+ if (video.ended || !api.getState("ended")) return;
227
+ api.setState("ended", false);
228
+ api.setState("playbackState", video.paused ? "paused" : "playing");
229
+ };
225
230
  addHandler("play", () => {
226
231
  api.setState("paused", false);
232
+ syncEndedFromElement();
227
233
  });
228
234
  addHandler("playing", () => {
229
235
  api.setState("playing", true);
@@ -231,6 +237,7 @@ function setupVideoEventHandlers(video, api) {
231
237
  api.setState("waiting", false);
232
238
  api.setState("buffering", false);
233
239
  api.setState("playbackState", "playing");
240
+ syncEndedFromElement();
234
241
  });
235
242
  addHandler("pause", () => {
236
243
  api.setState("playing", false);
@@ -285,6 +292,7 @@ function setupVideoEventHandlers(video, api) {
285
292
  });
286
293
  addHandler("seeking", () => {
287
294
  api.setState("seeking", true);
295
+ syncEndedFromElement();
288
296
  });
289
297
  addHandler("seeked", () => {
290
298
  api.setState("seeking", false);
@@ -392,6 +400,9 @@ function createValidatingPlaylistLoader(Hls) {
392
400
  };
393
401
  }
394
402
 
403
+ // src/version.ts
404
+ var PKG_VERSION = true ? "1.8.1" : "0.0.0-dev";
405
+
395
406
  // src/create-hls-plugin.ts
396
407
  var DEFAULT_CONFIG = {
397
408
  debug: false,
@@ -450,6 +461,10 @@ function createHLSPluginWith(loader, variant, config) {
450
461
  let onlineListener = null;
451
462
  let reconnectTriggerError = null;
452
463
  let reconnectExhausted = false;
464
+ const applyPoster = () => {
465
+ if (!video) return;
466
+ video.poster = api?.getState("poster") || "";
467
+ };
453
468
  const getOrCreateVideo = () => {
454
469
  if (video) return video;
455
470
  const existing = api?.container.querySelector("video");
@@ -462,10 +477,7 @@ function createHLSPluginWith(loader, variant, config) {
462
477
  video.preload = "metadata";
463
478
  video.controls = false;
464
479
  video.playsInline = true;
465
- const poster = api?.getState("poster");
466
- if (poster) {
467
- video.poster = poster;
468
- }
480
+ applyPoster();
469
481
  api?.container.appendChild(video);
470
482
  return video;
471
483
  };
@@ -1008,7 +1020,7 @@ function createHLSPluginWith(loader, variant, config) {
1008
1020
  const plugin = {
1009
1021
  id: "hls-provider",
1010
1022
  name: variant.name,
1011
- version: "1.0.0",
1023
+ version: PKG_VERSION,
1012
1024
  type: "provider",
1013
1025
  description: variant.description,
1014
1026
  canPlay(src) {
@@ -1099,6 +1111,9 @@ function createHLSPluginWith(loader, variant, config) {
1099
1111
  };
1100
1112
  window.addEventListener("online", onlineListener);
1101
1113
  }
1114
+ const unsubPoster = api.subscribeToState((event) => {
1115
+ if (event.key === "poster") applyPoster();
1116
+ });
1102
1117
  api.onDestroy(() => {
1103
1118
  unsubPlay();
1104
1119
  unsubPause();
@@ -1107,6 +1122,7 @@ function createHLSPluginWith(loader, variant, config) {
1107
1122
  unsubMute();
1108
1123
  unsubRate();
1109
1124
  unsubQuality();
1125
+ unsubPoster();
1110
1126
  });
1111
1127
  },
1112
1128
  async destroy() {
@@ -1132,6 +1148,7 @@ function createHLSPluginWith(loader, variant, config) {
1132
1148
  hasPlayedContent = false;
1133
1149
  cleanup(new Error("HLS load cancelled: superseded by a new load"));
1134
1150
  currentSrc = src;
1151
+ applyPoster();
1135
1152
  api.setState("playbackState", "loading");
1136
1153
  api.setState("buffering", true);
1137
1154
  if (api.getState("airplayActive") && loader.supportsNativeHLS()) {
package/dist/index.cjs CHANGED
@@ -317,8 +317,14 @@ function setupVideoEventHandlers(video, api) {
317
317
  video.addEventListener(event, handler);
318
318
  handlers.push({ event, handler });
319
319
  };
320
+ const syncEndedFromElement = () => {
321
+ if (video.ended || !api.getState("ended")) return;
322
+ api.setState("ended", false);
323
+ api.setState("playbackState", video.paused ? "paused" : "playing");
324
+ };
320
325
  addHandler("play", () => {
321
326
  api.setState("paused", false);
327
+ syncEndedFromElement();
322
328
  });
323
329
  addHandler("playing", () => {
324
330
  api.setState("playing", true);
@@ -326,6 +332,7 @@ function setupVideoEventHandlers(video, api) {
326
332
  api.setState("waiting", false);
327
333
  api.setState("buffering", false);
328
334
  api.setState("playbackState", "playing");
335
+ syncEndedFromElement();
329
336
  });
330
337
  addHandler("pause", () => {
331
338
  api.setState("playing", false);
@@ -380,6 +387,7 @@ function setupVideoEventHandlers(video, api) {
380
387
  });
381
388
  addHandler("seeking", () => {
382
389
  api.setState("seeking", true);
390
+ syncEndedFromElement();
383
391
  });
384
392
  addHandler("seeked", () => {
385
393
  api.setState("seeking", false);
@@ -498,6 +506,9 @@ function sanitizeUrl(url) {
498
506
  }
499
507
  }
500
508
 
509
+ // src/version.ts
510
+ var PKG_VERSION = true ? "1.8.1" : "0.0.0-dev";
511
+
501
512
  // src/create-hls-plugin.ts
502
513
  var DEFAULT_CONFIG = {
503
514
  debug: false,
@@ -556,6 +567,10 @@ function createHLSPluginWith(loader, variant, config) {
556
567
  let onlineListener = null;
557
568
  let reconnectTriggerError = null;
558
569
  let reconnectExhausted = false;
570
+ const applyPoster = () => {
571
+ if (!video) return;
572
+ video.poster = api?.getState("poster") || "";
573
+ };
559
574
  const getOrCreateVideo = () => {
560
575
  if (video) return video;
561
576
  const existing = api?.container.querySelector("video");
@@ -568,10 +583,7 @@ function createHLSPluginWith(loader, variant, config) {
568
583
  video.preload = "metadata";
569
584
  video.controls = false;
570
585
  video.playsInline = true;
571
- const poster = api?.getState("poster");
572
- if (poster) {
573
- video.poster = poster;
574
- }
586
+ applyPoster();
575
587
  api?.container.appendChild(video);
576
588
  return video;
577
589
  };
@@ -1114,7 +1126,7 @@ function createHLSPluginWith(loader, variant, config) {
1114
1126
  const plugin = {
1115
1127
  id: "hls-provider",
1116
1128
  name: variant.name,
1117
- version: "1.0.0",
1129
+ version: PKG_VERSION,
1118
1130
  type: "provider",
1119
1131
  description: variant.description,
1120
1132
  canPlay(src) {
@@ -1205,6 +1217,9 @@ function createHLSPluginWith(loader, variant, config) {
1205
1217
  };
1206
1218
  window.addEventListener("online", onlineListener);
1207
1219
  }
1220
+ const unsubPoster = api.subscribeToState((event) => {
1221
+ if (event.key === "poster") applyPoster();
1222
+ });
1208
1223
  api.onDestroy(() => {
1209
1224
  unsubPlay();
1210
1225
  unsubPause();
@@ -1213,6 +1228,7 @@ function createHLSPluginWith(loader, variant, config) {
1213
1228
  unsubMute();
1214
1229
  unsubRate();
1215
1230
  unsubQuality();
1231
+ unsubPoster();
1216
1232
  });
1217
1233
  },
1218
1234
  async destroy() {
@@ -1238,6 +1254,7 @@ function createHLSPluginWith(loader, variant, config) {
1238
1254
  hasPlayedContent = false;
1239
1255
  cleanup(new Error("HLS load cancelled: superseded by a new load"));
1240
1256
  currentSrc = src;
1257
+ applyPoster();
1241
1258
  api.setState("playbackState", "loading");
1242
1259
  api.setState("buffering", true);
1243
1260
  if (api.getState("airplayActive") && loader.supportsNativeHLS()) {
package/dist/index.d.cts CHANGED
@@ -20,9 +20,10 @@ import '@scarlett-player/core';
20
20
  *
21
21
  * @example
22
22
  * ```ts
23
+ * import { createPlayer } from '@scarlett-player/core';
23
24
  * import { createHLSPlugin } from '@scarlett-player/hls';
24
25
  *
25
- * const player = new ScarlettPlayer({
26
+ * const player = await createPlayer({
26
27
  * container: document.getElementById('player'),
27
28
  * plugins: [createHLSPlugin()],
28
29
  * });
package/dist/index.d.ts CHANGED
@@ -20,9 +20,10 @@ import '@scarlett-player/core';
20
20
  *
21
21
  * @example
22
22
  * ```ts
23
+ * import { createPlayer } from '@scarlett-player/core';
23
24
  * import { createHLSPlugin } from '@scarlett-player/hls';
24
25
  *
25
- * const player = new ScarlettPlayer({
26
+ * const player = await createPlayer({
26
27
  * container: document.getElementById('player'),
27
28
  * plugins: [createHLSPlugin()],
28
29
  * });
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  __export,
3
3
  createHLSPluginWith,
4
4
  sanitizeUrl
5
- } from "./chunk-NU6WD6KW.js";
5
+ } from "./chunk-VD46AQJB.js";
6
6
 
7
7
  // src/hls-loader.ts
8
8
  var hls_loader_exports = {};
package/dist/light.cjs CHANGED
@@ -317,8 +317,14 @@ function setupVideoEventHandlers(video, api) {
317
317
  video.addEventListener(event, handler);
318
318
  handlers.push({ event, handler });
319
319
  };
320
+ const syncEndedFromElement = () => {
321
+ if (video.ended || !api.getState("ended")) return;
322
+ api.setState("ended", false);
323
+ api.setState("playbackState", video.paused ? "paused" : "playing");
324
+ };
320
325
  addHandler("play", () => {
321
326
  api.setState("paused", false);
327
+ syncEndedFromElement();
322
328
  });
323
329
  addHandler("playing", () => {
324
330
  api.setState("playing", true);
@@ -326,6 +332,7 @@ function setupVideoEventHandlers(video, api) {
326
332
  api.setState("waiting", false);
327
333
  api.setState("buffering", false);
328
334
  api.setState("playbackState", "playing");
335
+ syncEndedFromElement();
329
336
  });
330
337
  addHandler("pause", () => {
331
338
  api.setState("playing", false);
@@ -380,6 +387,7 @@ function setupVideoEventHandlers(video, api) {
380
387
  });
381
388
  addHandler("seeking", () => {
382
389
  api.setState("seeking", true);
390
+ syncEndedFromElement();
383
391
  });
384
392
  addHandler("seeked", () => {
385
393
  api.setState("seeking", false);
@@ -498,6 +506,9 @@ function sanitizeUrl(url) {
498
506
  }
499
507
  }
500
508
 
509
+ // src/version.ts
510
+ var PKG_VERSION = true ? "1.8.1" : "0.0.0-dev";
511
+
501
512
  // src/create-hls-plugin.ts
502
513
  var DEFAULT_CONFIG = {
503
514
  debug: false,
@@ -556,6 +567,10 @@ function createHLSPluginWith(loader, variant, config) {
556
567
  let onlineListener = null;
557
568
  let reconnectTriggerError = null;
558
569
  let reconnectExhausted = false;
570
+ const applyPoster = () => {
571
+ if (!video) return;
572
+ video.poster = api?.getState("poster") || "";
573
+ };
559
574
  const getOrCreateVideo = () => {
560
575
  if (video) return video;
561
576
  const existing = api?.container.querySelector("video");
@@ -568,10 +583,7 @@ function createHLSPluginWith(loader, variant, config) {
568
583
  video.preload = "metadata";
569
584
  video.controls = false;
570
585
  video.playsInline = true;
571
- const poster = api?.getState("poster");
572
- if (poster) {
573
- video.poster = poster;
574
- }
586
+ applyPoster();
575
587
  api?.container.appendChild(video);
576
588
  return video;
577
589
  };
@@ -1114,7 +1126,7 @@ function createHLSPluginWith(loader, variant, config) {
1114
1126
  const plugin = {
1115
1127
  id: "hls-provider",
1116
1128
  name: variant.name,
1117
- version: "1.0.0",
1129
+ version: PKG_VERSION,
1118
1130
  type: "provider",
1119
1131
  description: variant.description,
1120
1132
  canPlay(src) {
@@ -1205,6 +1217,9 @@ function createHLSPluginWith(loader, variant, config) {
1205
1217
  };
1206
1218
  window.addEventListener("online", onlineListener);
1207
1219
  }
1220
+ const unsubPoster = api.subscribeToState((event) => {
1221
+ if (event.key === "poster") applyPoster();
1222
+ });
1208
1223
  api.onDestroy(() => {
1209
1224
  unsubPlay();
1210
1225
  unsubPause();
@@ -1213,6 +1228,7 @@ function createHLSPluginWith(loader, variant, config) {
1213
1228
  unsubMute();
1214
1229
  unsubRate();
1215
1230
  unsubQuality();
1231
+ unsubPoster();
1216
1232
  });
1217
1233
  },
1218
1234
  async destroy() {
@@ -1238,6 +1254,7 @@ function createHLSPluginWith(loader, variant, config) {
1238
1254
  hasPlayedContent = false;
1239
1255
  cleanup(new Error("HLS load cancelled: superseded by a new load"));
1240
1256
  currentSrc = src;
1257
+ applyPoster();
1241
1258
  api.setState("playbackState", "loading");
1242
1259
  api.setState("buffering", true);
1243
1260
  if (api.getState("airplayActive") && loader.supportsNativeHLS()) {
package/dist/light.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  __export,
3
3
  createHLSPluginWith,
4
4
  sanitizeUrl
5
- } from "./chunk-NU6WD6KW.js";
5
+ } from "./chunk-VD46AQJB.js";
6
6
 
7
7
  // src/hls-loader-light.ts
8
8
  var hls_loader_light_exports = {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scarlett-player/hls",
3
- "version": "1.7.0",
3
+ "version": "1.8.1",
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": "^1.0.3",
26
- "hls.js": "^1.5.0"
25
+ "@scarlett-player/core": "^1.8.0",
26
+ "hls.js": "^1.6.0"
27
27
  },
28
28
  "peerDependenciesMeta": {
29
29
  "hls.js": {
@@ -37,7 +37,7 @@
37
37
  "vitest": "^1.6.0",
38
38
  "@vitest/coverage-v8": "^1.6.0",
39
39
  "jsdom": "^24.0.0",
40
- "@scarlett-player/core": "1.7.0"
40
+ "@scarlett-player/core": "1.8.1"
41
41
  },
42
42
  "keywords": [
43
43
  "video",
@@ -58,10 +58,11 @@
58
58
  },
59
59
  "homepage": "https://scarlettplayer.com",
60
60
  "scripts": {
61
- "build": "tsup src/index.ts src/light.ts --format esm,cjs --dts",
62
- "dev": "tsup src/index.ts src/light.ts --format esm,cjs --dts --watch",
61
+ "build": "tsup",
62
+ "dev": "tsup --watch",
63
63
  "test": "vitest --run",
64
64
  "test:watch": "vitest",
65
- "test:coverage": "vitest --coverage"
65
+ "test:coverage": "vitest --coverage",
66
+ "typecheck": "tsc --noEmit -p tsconfig.typecheck.json"
66
67
  }
67
68
  }