Commit Graph
26 Commits
Author SHA1 Message Date
yonlu 19a803d1fc feat: multi-source artist images with thumbnails + grid integration
Complete rewrite of the artist image pipeline:

STORAGE:
- Migration 16: artist_images table tracking source, URL, path,
  primary flag, dimensions per image (up to 10 per artist)
- Directory structure: artist-images/{mbid[:2]}/{mbid}/ with
  primary.jpg + primary_sm.jpg/_md.jpg/_lg.jpg thumbnails
- Miss marker (.miss file) prevents re-fetching artists with no image

SOURCES (priority order):
1. MusicBrainz direct image relations (Wikimedia Commons)
2. Wikidata P18 property (Wikimedia Commons)
3. Wikipedia lead image (NEW — via Wikidata sitelinks → Wikipedia API)

Each source is checked, deduplicated, and the first available
image becomes the primary with sm/md/lg thumbnail generation
(100px/200px/400px, matching cover art tier sizes).

ASSET SERVING:
- /artist-images/ path registered with Wails asset handler
- Serves files via http.FileServer from the artist-images directory
- Same pattern as /covers/ for cover art

ARTIST MODEL:
- Artist struct gains ImageSmall/ImageMedium/ImageLarge fields
- resolveArtistImages does bulk MBID lookup → disk stat for each
- Populated in GetAllArtists and GetAllArtistsByLibrary

GRID VIEW:
- artists-view uses model URLs directly (no more base64 data URLs)
- Size selection based on imageSize * devicePixelRatio (like cover-grid)
- Removed batch GetArtistImages call and in-memory cache — no longer needed
2026-03-29 08:33:32 -04:00
yonlu 15a0b94348 fix: invalidate index discographies after library rescan
The search index's Tier 3 (library artists) depends on MBIDs from
the artists table. If the index built before a rescan populated
those MBIDs, library artists like Flatbush Zombies wouldn't be
indexed — they're not in the sitewide top 1000 and their name
didn't match via fuzzy matching.

Fix: OnAllScansComplete hook now calls InvalidateIndexDiscographies
before StartIndexBuild. This clears the discog_built timestamp so
Tiers 2-4 re-run incrementally, picking up any new library artists
whose MBIDs were just populated by the scan.

The rebuild is incremental — only artists not already in the index
get their discographies fetched.
2026-03-28 12:40:23 -04:00
yonlu 3c3102aac6 fix: start index build only after ALL library scans complete
FullRescan scans the first library directly, then queues the rest.
The PostScan hook was restarting the index build after the FIRST
library, which starved the queued libraries for DB access — they
never scanned, leaving the library with only 6 tracks.

Fix: move StartIndexBuild to the OnAllScansComplete hook, which
fires when drainQueue finds no more libraries to scan. This ensures
ALL libraries finish scanning before the index build starts.

For startup soft scans: if no scans were queued (library unchanged),
start the index build directly. If scans WERE queued, the hook
handles it.

Added OnAllScansComplete callback to ScanHooks. Called from
drainQueue when the scan pipeline goes idle.
2026-03-28 10:25:04 -04:00
yonlu bb015092d4 fix: prevent search index build from starving library scan for DB access
The search index build and library scan both write to the same
single-connection SQLite DB. The index build runs continuous batch
transactions that can starve the scan's clearLibraryTables call,
causing the scan to silently hang without logging.

Fix: decouple index build from SetContext. The build now starts
AFTER the soft scan completes on startup. For full rescans, the
PreClear hook stops the index build, and PostScan restarts it.

Also made StartBuild/StopBuild safe for multiple calls:
- StartBuild is a no-op if already running
- StopBuild is a no-op if not running (no deadlock on done channel)
- done channel created per-build, not in constructor
2026-03-26 15:21:01 -04:00
yonlu 1ff53d8084 chore(M004/S01): auto-commit after complete-slice 2026-03-23 16:55:22 -04:00
yonlu 64322f9353 feat(16-03): WriteTrackTags pipeline with player safety, scan mutex, events, and app wiring
- TagWriter struct with WriteTrackTags entry point orchestrating full pipeline
- PlayerStopper interface + playerAdapter for import-cycle-free player safety
- PipelineLocker interface + pipelineMu on Library for scan/write mutual exclusion
- TrackMetadataChanged event constant + auto-generated TypeScript events
- TagWriter wired into app.go as Wails binding with SetContext in OnStartup
- 5 pipeline integration tests: player safety, scan mutex, orphan cleanup, genre relink, full DB sync
- Lint fixes: static error, else-if, wsl cuddle, golines
2026-03-17 10:55:10 -04:00
yonlu 9f595b7ac1 fix(13-02): resolve phantom playlist tracks using M3U8 paths after scan
- Add ScanHooks callback struct to library package (follows RemovalHooks pattern)
- Move phantom resolution from library to playlist service via hook
- New ResolvePhantomTracksAfterScan reads M3U8 files and resolves paths
  against current audio_files using multi-root resolution
- Handles pre-existing phantoms (match by M3U8 position) and new ones
  (match by phantom_file_path)
- Delete old resolvePhantomTracks method that required phantom_file_path
- Wire ScanHooks in app.go OnStartup
2026-03-16 12:47:42 -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 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 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 0860b2fd4b fix(02-01): log MPRIS callback errors instead of discarding them
- OnPause, OnPlayPause, OnStop, OnSeek now check errors and log at Warn level
- All four MPRIS closures use yj.logger.Warn for non-fatal error reporting
- No more silently discarded player.Pause() / player.Seek() errors
2026-03-02 18:39:54 -05:00
yonlu 2a86408201 fix(02-01): eliminate package-level startupErr and fix config file permissions
- Move startupErr from package-level var to YellowJacketApp struct field
- Update OnStartup and OnDomReady to reference yj.startupErr
- Change config.Save() file permissions from 0o666 to 0o644
- Fix nlreturn lint in database/errors.go (pre-existing, blocking commit hook)
2026-03-02 18:39:15 -05:00
yonlu d01f5e5d14 added "default playlist"/ favorites system 2026-02-25 22:53:57 -05:00
yonlu 4f3244c992 added mpris (linux media player controls) support 2026-02-25 20:51:29 -05:00
yonlu 012131283c fixed startup ondomready call to use wails bindings and call when complete 2026-02-25 19:10:37 -05:00
yonlu cf144bf0dd refactored many events to use wails bindings, reducing boilerplate 2026-02-25 18:51:07 -05:00
yonlu baa4644ece extracted cover art handling from library package 2026-02-25 15:31:05 -05:00
yonlu ff7649600b refactored full rescan to use hook/lifecycle pattern and added rescan package 2026-02-24 16:11:41 -05:00
yonlu 352fa9da61 split queue package into multiple files. other minor fixes 2026-02-24 08:34:28 -05:00
logan 2a3a79652c add dev-only profiling with pprof, runtime/trace, and operation timing
Wire up Go's standard profiling toolkit so it's automatically available
in dev builds and completely absent from production. The profiling
package uses build tags (dev/!dev) to eliminate all pprof, trace, and
timing code from release binaries with zero new dependencies.

- backend/profiling: pprof HTTP server on :6060, /debug/trace endpoint,
  block/mutex profiling, and TimeOp helper for structured operation timing
- scripts/profile.sh: interactive menu-driven script that auto-selects
  free ports (8080-8089) so multiple profiles can be open simultaneously
- Instrumented key operations: app init, database init, player load/restore,
  queue set/restore
- Makefile targets: profile, profile-cpu, profile-heap, profile-trace
- .gitignore: exclude trace-*.out and *.pprof artifacts
2026-02-20 18:27:25 -06:00
yonlu 88c3736110 added color/ theme settings, new config window 2026-02-20 14:43:35 -05:00
yonlu 560ab3a3b5 playlists now save to files, can be restored from files 2026-02-19 23:10:20 -05:00
yonlu 81793975b4 improved library scan speeds, added library manager component
-libraries tab now opens a library manager
-choose library directory, manually soft scan and rescan
-batched db queues
-mp3 header-based duration extraction
2026-02-19 10:17:09 -05:00
yonlu 6fbe16a84b window size saved to config, smaller font in track-list 2026-02-16 03:48:53 -05:00
yonlu 4c09e7abee playlist creation, viewing, integration with other views. still wip for full playlist functionality 2026-02-16 00:27:36 -05:00
logan d78c0584e2 Squash merge audio-player-component into main 2026-02-13 20:39:23 -06:00