Files
yellowjacket/.planning/plans/completed/002-v1.1-multi-library.md
T
2026-05-01 11:52:50 -04:00

2.3 KiB

002 — v1.1 Multi-Library Support

Lets users register and manage multiple music library directories with per-library scanning, filtered views, cross-library playlists, and phantom-track preservation when a library is removed.

Shipped: 2026-03-16 · Phases: 9-14

What landed

  • Phase 9 — Scan cancellation & keyboard shortcuts. Cancellable/pausable library scans via per-scan context; configurable shortcuts with record-style capture, scope-aware dispatch, conflict detection.
  • Phase 10 — Schema & migration. New libraries table, library_id FK on audio_files, phantom columns on playlist_tracks, seamless single-directory → named-library migration on first launch.
  • Phase 11 — Per-library scan pipeline. Sequential scan-queue coordinator (single writer is the SQLite reality); per-library progress UI with library name; cancel scope respects the active library.
  • Phase 12 — Library CRUD & data integrity. Add/rename/remove library through UI; atomic orphan cleanup (shared artists/albums/genres survive); FTS5 entries removed; queue tracks from a removed library cascade-deleted with playback continuing.
  • Phase 13 — Library views & phantom tracks. Library filter dropdown across all views; tracks/albums/artists/genres/search respect the active filter; cross-library playlists work naturally; removed-library tracks become greyed-out phantoms with preserved metadata, auto-resolved on rescan via ScanHooks + M3U8 matching.
  • Phase 14 — Performance optimization. CSS containment + GPU promotion on scroll containers; view caching (display toggle, no DOM destruction); event delegation on virtualizer; queueMicrotask notification batching; pprof profiling guide.

Key decisions retained

  • Hybrid model — library_id only on audio_files. Physical files belong to a library; logical entities (artist/album/genre) are shared.
  • Libraries live in DB, not TOML. UI-driven CRUD shouldn't require TOML manipulation.
  • SET NULL on playlist_tracks FK. Phantom rows preserve playlist structure when a library is removed.
  • Backend filters, frontend doesn't. ByLibrary SQL variants keep the UI responsive at 150k tracks.
  • Sequential scanning. SQLite single-writer makes parallel scans pointless.
  • ScanHooks callback pattern. Breaks the library → playlist circular dep needed for phantom resolution.