Commit Graph
520 Commits
Author SHA1 Message Date
yonlu ad9104374a perf(14-02): replace innerHTML navigation with view caching system
- Primary views (tracks, albums, artists, genres, playlists, settings) created once and kept in DOM
- Navigation toggles display:none/display:'' instead of destroying/recreating components
- viewCache Map bounded to 6 entries — no memory leaks
- Detail views (artist-details, playlist-details, genre-details) remain ephemeral
- Scroll positions naturally preserved by keeping DOM alive
- No virtualizer reinit, no data refetch, no image reload on navigation
2026-03-14 13:44:37 -04:00
yonlu efa06f7edf perf(14-01): add CSS containment to app shell layout boundaries
- contain: layout style on .content-area to isolate main+queue from header/sidebar
- contain: strict on .main-panel for maximum layout isolation
- contain: layout style paint on .main-panel > * for paint containment per view
- contain: layout style paint on sidebar to isolate from main panel
- contain: layout style on .bottom-bar to isolate footer from content reflows
2026-03-14 13:44:22 -04:00
yonlu a8b5274775 docs(14-performance-optimization): create phase plan with 4 plans in 2 waves 2026-03-14 13:31:20 -04:00
yonlu 12c678284c feat(12-02): make config sections collapsible with chevron dropdown
Sections start collapsed showing only heading, description, and a
chevron icon. Click to expand and reveal the fields. The open property
allows sections to start expanded if needed.
2026-03-14 12:57:35 -04:00
yonlu 649e516aa3 fix(12-02): keep Add Library button visible during scan
Add Library is now outside the scanning/not-scanning conditional so
it's always accessible, even while a scan is in progress.
2026-03-14 12:42:15 -04:00
yonlu df824c6989 feat(12-02): show scan progress bar inline in library list entry
Progress bar now renders below the library row being scanned, with
a small status label (phase + percent) after the library name. Removed
the separate status-bar progress display.
2026-03-14 12:30:00 -04:00
yonlu 771345dd9d fix(12-02): move Add Library button inline with scan buttons
Add Library now sits in the same row as Scan and Full Rescan, sharing
the same btn-primary style and size. Removed the standalone button
below the library list.
2026-03-14 12:13:11 -04:00
yonlu ba3f840a28 fix(12-02): move scan buttons above library list, default to none selected
Scan and Full Rescan buttons now sit above the library list for easier
access. Libraries start unchecked — both buttons are disabled until at
least one library is selected.
2026-03-14 12:11:12 -04:00
yonlu ac8cbb3296 fix(12-02): serialize ScanWarning.Err as string instead of error interface
Go's error interface has no exported fields, so json.Marshal produced
{} for the error message. Converting to string at the addWarning call
site preserves the actual error text in the JSON payload.
2026-03-14 12:06:02 -04:00
yonlu 21ea71e257 perf(12-02): increase scan batch size from 50 to 300
Amortizes SQLite fsync cost over 6x fewer transactions. Cuts ~80
fsyncs for a 25K-track library — significant on HDD.
2026-03-14 11:33:03 -04:00
yonlu b093fbb10a fix(12-02): invalidate library store cache on LibraryRemoved event
Track list, albums, artists, and genres views now refresh immediately
after a library is removed instead of showing stale cached data.
2026-03-14 10:46:15 -04:00
yonlu 30f4461e69 perf(12-02): skip FTS5 rebuild during library removal
Contentless FTS5 cannot delete individual rows, but stale entries are
filtered out by the JOIN against track_metadata in search queries.
The index is rebuilt on the next full rescan. Removes ~10s of overhead
for a 25K-track library removal.
2026-03-14 10:24:49 -04:00
yonlu 890284ddb1 fix(12-02): delete artist_credit_artist before artist_credit in removal pipeline
artist_credit_artist.credit_id references artist_credit.id, so the
child table must be cleaned before the parent. Same FK ordering fix
as the earlier recording_genres/recordings swap.
2026-03-14 10:15:37 -04:00
yonlu 1f872aa005 fix(12-02): refresh library track counts after scan completes
loadLibraries() now runs on ScanComplete and ScanQueueDrained so newly
added libraries show their track count without navigating away.
2026-03-14 10:01:35 -04:00
yonlu b648307ac5 docs(12-02): record deferred bulk phantom matching improvement in STATE.md 2026-03-13 22:22:37 -04:00
yonlu 717e249c36 fix(12-02): resolve phantom tracks caused by empty library root after TOML cleanup
getLibraryRoot() returned "" after DirectoryPath was removed from
config.toml during multi-library migration. M3U8 relative paths could
not be resolved to absolute paths, causing every playlist track to
appear as phantom. Now falls back to the first library path from the
database when the legacy config field is empty.
2026-03-13 14:06:21 -04:00
yonlu 1ad099a9d3 fix(12-02): soft scan claims orphaned library_id=0 tracks on startup
Tracks from the pre-multi-library schema have library_id=0 and aren't
counted by CountAudioFilesByLibrary, causing a permanent count mismatch
that triggers a full scan on every launch. SoftScanAllLibraries now
claims matching orphans before comparing counts.
2026-03-13 13:59:18 -04:00
yonlu 92c4d23a9a fix(12-02): soft scan on launch — only scan libraries with changed file counts
SoftScanAllLibraries compares audio file count on disk vs DB track count
per library. Unchanged libraries are silently skipped (no progress bar,
no events). Only libraries where files were added or removed since the
last scan get queued for a full scan.
2026-03-13 13:53:46 -04:00
yonlu 1d735c3a5f fix(12-02): reorder orphan cleanup to delete FK children before recordings
recording_genres and release_group_recordings reference recordings.id,
so they must be deleted BEFORE the recordings table is cleaned.
Also extends toast duration to 8s for readability.
2026-03-13 13:38:39 -04:00
yonlu cf004986c9 fix(12-02): wait for scan to stop before library removal, surface errors in UI
RemoveLibrary now polls until the cancelled scan goroutine finishes
before proceeding with the removal transaction. Also show removal
errors as toast messages instead of only logging to console, and
explicitly reload library list after successful removal.
2026-03-13 11:17:37 -04:00
yonlu f60b6b5255 fix(12-02): claim orphaned tracks when adding library with matching path
Tracks from pre-multi-library schema have library_id=0 (default).
When AddLibrary creates a new library row, UPDATE orphaned tracks
whose file_path falls under the library's directory to use the new
library_id. This prevents the scan from hitting UNIQUE constraints
on every file and ensures track counts are correct immediately.
2026-03-13 10:50:34 -04:00
yonlu 13a42aea22 feat(12-02): selectable library list with checkbox scan targeting
- Add checkboxes to library list with select-all header
- Soft Scan operates on selected libraries (queues each individually)
- Full Rescan stays global (nukes all data, rescans all libraries)
- Remove redundant 'Scan All Libraries' button
- Fix FullRescan Go backend to scan all libraries after wipe, not just first
2026-03-13 10:33:15 -04:00
yonlu b36e472212 fix(12-02): count failed saves as skipped so scan progress bar advances
Files that fail to save (e.g. UNIQUE constraint from pre-existing
tracks with a different library_id) were not counted in any progress
counter, leaving the progress bar stuck at 0%. Now increments skipped
so processed = added + skipped + updated reflects all files visited.
2026-03-13 09:31:28 -04:00
yonlu 9272b060bf fix(12-02): dismiss inline rename on click outside 2026-03-13 09:24:32 -04:00
yonlu cf18c39dbd fix(12-02): downgrade per-file save error to Debug, add warning count to scan summary 2026-03-13 09:17:38 -04:00
yonlu 05598224e4 fix(12-02): replace removed Scan() import with ScanAllLibraries()
Scan() wrapper was deleted in Phase 11 but config-page.ts and
library-manager.ts still imported it. Use ScanAllLibraries() for
soft scan since multi-library model scans all libraries.
2026-03-13 08:27:47 -04:00
yonlu e199712a56 feat(12-02): remove Libraries sidebar nav item and view routing
- Remove 'libraries' from View type union in app-sidebar.ts
- Remove Libraries nav item from sidebar navigation list
- Remove case 'libraries' view routing in index.ts
- Remove library-manager component import from index.ts
2026-03-12 19:51:41 -04:00
yonlu ffc5d9639c feat(12-02): replace config-page library section with full library management UI
- Add library list with name, path, track count per library
- Add Library button opens folder picker, auto-creates library
- Inline rename with Enter/Escape via overflow menu
- Removal confirmation dialog with real impact counts (tracks, playlists, queue)
- Toast notification with removal summary after library removal
- Add GetAllLibrariesWithTrackCounts + Info type to backend Library struct
- Add Wails binding stubs for AddLibrary, RenameLibrary, RemoveLibrary, GetRemovalImpact
- Add Info, RemovalImpact, RemovalSummary types to models.ts
- Remove old single-directory library config UI (GetLibraryDirectory/SetLibraryDirectory)
2026-03-12 19:50:59 -04:00
yonlu 27c773b3d0 docs(12-01): complete library CRUD backend plan
- SUMMARY.md with 2 task commits, 6 files, 6 requirements completed
- STATE.md advanced to Phase 12 Plan 1/2, added Phase 12 decisions
- ROADMAP.md marked 12-01 complete (1/2 plans)
- REQUIREMENTS.md marked LIB-01, LIB-02, LIB-03, DATA-02, DATA-03, PLAY-04 complete
2026-03-12 19:42:41 -04:00
yonlu 5995dfd01d feat(12-01): add queue compaction method and wire removal hooks
- Add CompactAfterLibraryRemoval on Queue: reloads surviving tracks from DB, resets currentIndex, unloads player if current track was removed, clears shuffle order
- Wire RemovalHooks in app.go OnStartup: StopPlayback → player.UnloadTrack, CompactQueue → queue.CompactAfterLibraryRemoval
- All existing tests pass with no regressions
2026-03-12 19:38:36 -04:00
yonlu bd44f8306c feat(12-01): implement library CRUD methods and orphan cleanup pipeline
- Add AddLibrary, RenameLibrary, RemoveLibrary, GetRemovalImpact methods
- RemoveLibrary follows exact order: phantom populate → delete audio_files → orphan cleanup → commit → FTS5 rebuild → cover art file cleanup → queue compact → events
- Add cancelLibraryScan and currentTrackBelongsToLibrary helpers
- Add RemovalHooks type and removalHooks field on Library struct
- Add LibraryAdded, LibraryRenamed, LibraryRemoved event constants
- Regenerate frontend events.ts with new CRUD events
- All hand-crafted SQL has SAFETY comments per project convention
- Dual artist_credit FK check (recordings + release_groups) for orphan cleanup
2026-03-12 19:37:07 -04:00
yonlu e97b849602 docs(12): create phase plan for library CRUD and data integrity 2026-03-12 17:48:46 -04:00
yonlu 721442d1cb docs(12): create phase plan 2026-03-12 17:46:08 -04:00
yonlu de5ee4c301 docs(12): research phase domain 2026-03-12 17:39:32 -04:00
yonlu 10f97047e8 docs(12): capture phase context 2026-03-12 13:53:20 -04:00
yonlu 12f10c5fac docs(phase-11): complete phase execution 2026-03-09 16:23:50 -04:00
yonlu ead68cfb5d docs(11-03): complete wire auto-scan and legacy cleanup plan
- SUMMARY.md documents auto-scan wiring and legacy code removal
- STATE.md updated: plan 3/3 complete, Phase 11 done, session continuity
- ROADMAP.md updated: Phase 11 complete (3/3 plans)
2026-03-09 16:19:59 -04:00
yonlu 1aaf53630d docs(11-02): complete frontend scan UI plan
- SUMMARY.md documents per-library progress display and queue-aware cancel dialog
- STATE.md updated: plan 2/3, session continuity, new decisions
- ROADMAP.md updated: phase 11 progress 2/3
- REQUIREMENTS.md: LSCAN-03 marked complete
2026-03-09 16:13:45 -04:00
yonlu d61f122b56 feat(11-02): update library-manager with per-library progress and Scan All button
- Add libraryId, libraryName, queuedCount to ScanProgress interface
- Show library name in progress label (Scanning: [Library Name])
- Show queue count below progress bar when libraries queued
- Add Scan All Libraries button (calls ScanAllLibraries binding)
- Subscribe to LibraryScanQueued/LibraryScanQueueDrained events
- Scan state properly tracks queue draining (doesn't reset early)
2026-03-09 16:11:23 -04:00
yonlu d01591d6cc feat(11-02): update config-page with per-library progress display and queue-aware cancel dialog
- Add libraryId, libraryName, queuedCount to ScanProgress interface
- Replace CancelScan import with CancelCurrentScan, CancelAllScans
- Add ScanAllLibraries import and Scan All Libraries button
- Show library name in progress label (Scanning: [Library Name])
- Show queue count below progress bar when libraries queued
- Cancel dialog shows scope choice (Cancel This Library / Cancel All) when queue > 0
- Subscribe to LibraryScanQueued and LibraryScanQueueDrained events
- Track scanQueuedCount state for queue-aware UI behavior
2026-03-09 16:09:22 -04:00
yonlu 9308848936 docs(11-01): complete per-library scan pipeline plan
- Create 11-01-SUMMARY.md with execution results
- Update STATE.md: advance to phase 11 plan 1/3
- Update ROADMAP.md: phase 11 at 1/3 plans complete
- Mark LSCAN-01, LSCAN-02, LSCAN-04 complete in REQUIREMENTS.md
2026-03-09 16:05:55 -04:00
yonlu 943db1cf27 feat(11-01): per-library scan pipeline with queue coordinator
Task 1: Schema, events, and progress types
- Add library_id to CreateAudioFile SQL INSERT and regenerate sqlc code
- Add LibraryScanQueued and LibraryScanQueueDrained event constants
- Regenerate TypeScript events via genevents
- Add LibraryID, LibraryName, QueuedCount to ScanProgress
- Add LibraryID, LibraryName to ScanMetrics
- Add libraryID field to importResult for threading through pipeline

Task 2: Scan queue coordinator and per-library scanning
- Create scan_queue.go with ScanLibrary(id), ScanAllLibraries()
- Add CancelCurrentScan(), CancelAllScans() for queue-aware cancellation
- FIFO scan queue with silent dedup (same library already scanning or queued)
- Refactor Scan() -> scanInternal(libraryID, libraryName, libraryPath)
- Replace GetAllAudioFiles with GetAudioFilesByLibrary for per-library loading
- Thread libraryID through DB writer to set CreateAudioFileParams.LibraryID
- drainQueue auto-starts next queued library or emits LibraryScanQueueDrained
- Pause freezes current scan AND queue
- Add GetScanQueueLength() and QueuedLibraryNames() for UI
- Mark CancelScan() and Scan() as deprecated
2026-03-09 16:02:54 -04:00
yonlu 68463f3549 docs(11): create phase plan for per-library scan pipeline 2026-03-09 15:44:07 -04:00
yonlu 025da10d98 docs(11): capture phase context 2026-03-09 15:18:01 -04:00
yonlu 75b2a349eb fix(10-01): move library_id index to migration 6 to fix existing DB startup
On existing databases, CREATE TABLE IF NOT EXISTS audio_files is a no-op
but the standalone CREATE INDEX on library_id would fail because the
column doesn't exist until migration 6 runs. The migration already
creates this index, so removing it from the schema file is correct.
2026-03-09 10:48:11 -04:00
yonlu 9ff850fe23 docs(phase-10): complete phase execution 2026-03-09 09:57:37 -04:00
yonlu 765204e8eb docs(10-02): complete sqlc queries & migration tests plan
- SUMMARY: Library CRUD queries, phantom-aware playlist queries, 5 migration tests
- STATE: Phase 10 complete (2/2 plans), ready for Phase 11
- ROADMAP: Phase 10 marked complete
- REQUIREMENTS: LIB-04, LIB-05 marked complete
2026-03-09 09:54:12 -04:00
yonlu bc151891b5 feat(10-02): add migration 6 integration tests and NewTestDBWithLibrary helper
- Add NewTestDBWithLibrary helper for tests needing a pre-created library
- TestMigration6FreshDB: verify all tables, columns, phantom cols, VIEW, and user_version
- TestMigration6LibraryQueries: verify CRUD operations and unique path constraint
- TestMigration6PhantomPlaylistTracks: verify SET NULL FK preserves phantom metadata
- TestMigration6AudioFilesLibraryFK: verify FK enforcement on library_id
- TestMigration6TrackMetadataViewHasLibraryID: verify VIEW includes library_id
2026-03-09 09:50:14 -04:00
yonlu 02548dd55e feat(10-02): add sqlc queries for libraries and update playlist queries for phantom support
- Create libraries.sql with 7 CRUD queries (create, get, get-by-path, list, update, delete, count)
- Update playlists.sql: AddPlaylistTrack now accepts 9 params including phantom metadata
- Update playlist queries to use LEFT JOIN for nullable audio_file_id
- Add GetTrackPhantomMetadata helper query for eager phantom population
- Add is_phantom computed column to metadata queries
- Add GetAudioFilesByLibrary and CountAudioFilesByLibrary queries
- Regenerate all sqlc code
2026-03-09 09:47:30 -04:00
yonlu 2c77368482 docs(10-01): complete schema & migration plan 2026-03-09 09:44:05 -04:00