@scarlett-player/playlist 1.8.1 → 1.9.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/index.cjs CHANGED
@@ -37,6 +37,7 @@ __export(index_exports, {
37
37
  default: () => index_default
38
38
  });
39
39
  module.exports = __toCommonJS(index_exports);
40
+ var import_core2 = require("@scarlett-player/core");
40
41
 
41
42
  // src/controls.ts
42
43
  var PLAYLIST_ICONS = {
@@ -197,6 +198,7 @@ var PlaylistPanel = class {
197
198
  };
198
199
 
199
200
  // src/styles.ts
201
+ var import_core = require("@scarlett-player/core");
200
202
  var STYLE_ID = "sp-playlist-styles";
201
203
  var styles = `
202
204
  .sp-playlist-skip[disabled] {
@@ -298,18 +300,11 @@ var styles = `
298
300
  }
299
301
  `;
300
302
  function injectStyles() {
301
- if (typeof document === "undefined" || document.getElementById(STYLE_ID)) {
302
- return null;
303
- }
304
- const el = document.createElement("style");
305
- el.id = STYLE_ID;
306
- el.textContent = styles;
307
- document.head.appendChild(el);
308
- return el;
303
+ return (0, import_core.injectSharedStyles)(STYLE_ID, styles);
309
304
  }
310
305
 
311
306
  // src/version.ts
312
- var PKG_VERSION = true ? "1.8.1" : "0.0.0-dev";
307
+ var PKG_VERSION = true ? "1.9.0" : "0.0.0-dev";
313
308
 
314
309
  // src/index.ts
315
310
  var DEFAULT_CONFIG = {
@@ -336,6 +331,9 @@ function shuffleArray(array) {
336
331
  function createPlaylistPlugin(config) {
337
332
  const mergedConfig = { ...DEFAULT_CONFIG, ...config };
338
333
  let api = null;
334
+ let releaseStyles = null;
335
+ let releaseControls = null;
336
+ let lifecycle = 0;
339
337
  let tracks = mergedConfig.tracks || [];
340
338
  let currentIndex = mergedConfig.initialIndex ?? -1;
341
339
  if (currentIndex < -1 || currentIndex >= tracks.length) {
@@ -458,7 +456,7 @@ function createPlaylistPlugin(config) {
458
456
  }
459
457
  const track = tracks[index];
460
458
  currentIndex = index;
461
- api?.logger.info("Track changed", { index, title: track.title, src: track.src });
459
+ api?.logger.info("Track changed", { index, title: track.title, src: (0, import_core2.sanitizeUrl)(track.src) });
462
460
  api?.setState("title", track.title || "");
463
461
  api?.setState("poster", track.artwork || "");
464
462
  api?.setState("mediaType", track.type || "audio");
@@ -474,6 +472,7 @@ function createPlaylistPlugin(config) {
474
472
  type: "feature",
475
473
  description: "Playlist management with shuffle, repeat, and gapless playback",
476
474
  async init(pluginApi) {
475
+ const generation = ++lifecycle;
477
476
  api = pluginApi;
478
477
  api.logger.info("Playlist plugin initialized");
479
478
  loadPersistedPlaylist();
@@ -499,20 +498,31 @@ function createPlaylistPlugin(config) {
499
498
  api?.emit("playlist:ended", void 0);
500
499
  }
501
500
  });
502
- injectStyles();
503
- void import("@scarlett-player/ui").then(({ registerControl }) => {
501
+ releaseStyles = injectStyles();
502
+ const owner = api.container;
503
+ void import("@scarlett-player/ui").then(({ registerControl, unregisterControl }) => {
504
+ if (generation !== lifecycle) return;
504
505
  const self = plugin;
505
506
  registerControl(
506
507
  "playlist-previous",
507
- () => new PlaylistSkipButton(self, "previous")
508
+ () => new PlaylistSkipButton(self, "previous"),
509
+ { owner }
508
510
  );
509
- registerControl("playlist-next", () => new PlaylistSkipButton(self, "next"));
511
+ registerControl("playlist-next", () => new PlaylistSkipButton(self, "next"), {
512
+ owner
513
+ });
510
514
  registerControl(
511
515
  "playlist",
512
516
  () => new PlaylistPanel(self, {
513
517
  onSelect: (index) => self.play(index)
514
- })
518
+ }),
519
+ { owner }
515
520
  );
521
+ releaseControls = () => {
522
+ unregisterControl("playlist-previous", { owner });
523
+ unregisterControl("playlist-next", { owner });
524
+ unregisterControl("playlist", { owner });
525
+ };
516
526
  }).catch(() => {
517
527
  api?.logger.debug("@scarlett-player/ui not present, playlist controls not registered");
518
528
  });
@@ -543,8 +553,13 @@ function createPlaylistPlugin(config) {
543
553
  });
544
554
  },
545
555
  async destroy() {
556
+ lifecycle++;
546
557
  api?.logger.info("Playlist plugin destroying");
547
558
  persistPlaylist();
559
+ releaseStyles?.();
560
+ releaseStyles = null;
561
+ releaseControls?.();
562
+ releaseControls = null;
548
563
  api = null;
549
564
  },
550
565
  add(trackOrTracks) {
package/dist/index.js CHANGED
@@ -1,3 +1,6 @@
1
+ // src/index.ts
2
+ import { sanitizeUrl } from "@scarlett-player/core";
3
+
1
4
  // src/controls.ts
2
5
  var PLAYLIST_ICONS = {
3
6
  previous: '<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false"><path d="M6 6h2v12H6V6zm3.5 6L18 6v12l-8.5-6z"/></svg>',
@@ -157,6 +160,7 @@ var PlaylistPanel = class {
157
160
  };
158
161
 
159
162
  // src/styles.ts
163
+ import { injectSharedStyles } from "@scarlett-player/core";
160
164
  var STYLE_ID = "sp-playlist-styles";
161
165
  var styles = `
162
166
  .sp-playlist-skip[disabled] {
@@ -258,18 +262,11 @@ var styles = `
258
262
  }
259
263
  `;
260
264
  function injectStyles() {
261
- if (typeof document === "undefined" || document.getElementById(STYLE_ID)) {
262
- return null;
263
- }
264
- const el = document.createElement("style");
265
- el.id = STYLE_ID;
266
- el.textContent = styles;
267
- document.head.appendChild(el);
268
- return el;
265
+ return injectSharedStyles(STYLE_ID, styles);
269
266
  }
270
267
 
271
268
  // src/version.ts
272
- var PKG_VERSION = true ? "1.8.1" : "0.0.0-dev";
269
+ var PKG_VERSION = true ? "1.9.0" : "0.0.0-dev";
273
270
 
274
271
  // src/index.ts
275
272
  var DEFAULT_CONFIG = {
@@ -296,6 +293,9 @@ function shuffleArray(array) {
296
293
  function createPlaylistPlugin(config) {
297
294
  const mergedConfig = { ...DEFAULT_CONFIG, ...config };
298
295
  let api = null;
296
+ let releaseStyles = null;
297
+ let releaseControls = null;
298
+ let lifecycle = 0;
299
299
  let tracks = mergedConfig.tracks || [];
300
300
  let currentIndex = mergedConfig.initialIndex ?? -1;
301
301
  if (currentIndex < -1 || currentIndex >= tracks.length) {
@@ -418,7 +418,7 @@ function createPlaylistPlugin(config) {
418
418
  }
419
419
  const track = tracks[index];
420
420
  currentIndex = index;
421
- api?.logger.info("Track changed", { index, title: track.title, src: track.src });
421
+ api?.logger.info("Track changed", { index, title: track.title, src: sanitizeUrl(track.src) });
422
422
  api?.setState("title", track.title || "");
423
423
  api?.setState("poster", track.artwork || "");
424
424
  api?.setState("mediaType", track.type || "audio");
@@ -434,6 +434,7 @@ function createPlaylistPlugin(config) {
434
434
  type: "feature",
435
435
  description: "Playlist management with shuffle, repeat, and gapless playback",
436
436
  async init(pluginApi) {
437
+ const generation = ++lifecycle;
437
438
  api = pluginApi;
438
439
  api.logger.info("Playlist plugin initialized");
439
440
  loadPersistedPlaylist();
@@ -459,20 +460,31 @@ function createPlaylistPlugin(config) {
459
460
  api?.emit("playlist:ended", void 0);
460
461
  }
461
462
  });
462
- injectStyles();
463
- void import("@scarlett-player/ui").then(({ registerControl }) => {
463
+ releaseStyles = injectStyles();
464
+ const owner = api.container;
465
+ void import("@scarlett-player/ui").then(({ registerControl, unregisterControl }) => {
466
+ if (generation !== lifecycle) return;
464
467
  const self = plugin;
465
468
  registerControl(
466
469
  "playlist-previous",
467
- () => new PlaylistSkipButton(self, "previous")
470
+ () => new PlaylistSkipButton(self, "previous"),
471
+ { owner }
468
472
  );
469
- registerControl("playlist-next", () => new PlaylistSkipButton(self, "next"));
473
+ registerControl("playlist-next", () => new PlaylistSkipButton(self, "next"), {
474
+ owner
475
+ });
470
476
  registerControl(
471
477
  "playlist",
472
478
  () => new PlaylistPanel(self, {
473
479
  onSelect: (index) => self.play(index)
474
- })
480
+ }),
481
+ { owner }
475
482
  );
483
+ releaseControls = () => {
484
+ unregisterControl("playlist-previous", { owner });
485
+ unregisterControl("playlist-next", { owner });
486
+ unregisterControl("playlist", { owner });
487
+ };
476
488
  }).catch(() => {
477
489
  api?.logger.debug("@scarlett-player/ui not present, playlist controls not registered");
478
490
  });
@@ -503,8 +515,13 @@ function createPlaylistPlugin(config) {
503
515
  });
504
516
  },
505
517
  async destroy() {
518
+ lifecycle++;
506
519
  api?.logger.info("Playlist plugin destroying");
507
520
  persistPlaylist();
521
+ releaseStyles?.();
522
+ releaseStyles = null;
523
+ releaseControls?.();
524
+ releaseControls = null;
508
525
  api = null;
509
526
  },
510
527
  add(trackOrTracks) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scarlett-player/playlist",
3
- "version": "1.8.1",
3
+ "version": "1.9.0",
4
4
  "description": "Playlist Plugin for Scarlett Player - Queue management, shuffle, repeat, and gapless playback",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -30,8 +30,8 @@
30
30
  "typescript": "^5.3.0",
31
31
  "vitest": "^1.6.0",
32
32
  "jsdom": "^24.0.0",
33
- "@scarlett-player/core": "1.8.1",
34
- "@scarlett-player/ui": "1.8.1"
33
+ "@scarlett-player/core": "1.9.0",
34
+ "@scarlett-player/ui": "1.9.0"
35
35
  },
36
36
  "keywords": [
37
37
  "video",
@@ -65,6 +65,6 @@
65
65
  "dev": "tsup --watch",
66
66
  "test": "vitest --run",
67
67
  "test:watch": "vitest",
68
- "typecheck": "tsc --noEmit"
68
+ "typecheck": "tsc --noEmit -p tsconfig.typecheck.json"
69
69
  }
70
70
  }