Commit Graph
5 Commits
Author SHA1 Message Date
yonluandClaude Opus 5 20fbf28f2a perf(explore): make the owned-artist backfill yield, mark, and stop
The post-scan backfills share MusicBrainz's rate limiters with every
page the user can open, and both were FIFO — so a thousand-artist
enrichment put an album page behind an hour of queued work.
WithBackgroundLane/WithBackgroundPriority add a slower second lane: a
marked wait takes no token while any interactive wait is outstanding.
It is a context marker rather than a parameter because a backfill calls
the same client methods a detail page does. A long backfill also has to
be visible and stoppable, so jobs.KindCatalogEnrich registers both with
progress and cancel — after the work is counted, since these passes are
a no-op on every launch once the library is covered.

What it does not fetch is the point. It ran for hours against a
900-artist library and marked nothing, because three of the four things
it did per artist were work nobody asked for: similar artists, which
the artist page already resolves on view, and a full GetArtistImage
(fanart.tv, TheAudioDB, Wikidata, Wikipedia, ten portraits) reached
only to warm the MB artist lookup EnsureArtistRels does alone. It was
also serial across artists while every limiter is per-host and idle.

The marks are a table rather than more explore_index columns, because
artifactimport merges by column list and a flag added there is a second
place to remember. BrowseReleaseGroupsAll pages to exhaustion, where
the old call silently cut a prolific artist at 100 release groups.

One portrait is downloaded now; the rest are remembered as URLs.
resolveAllSources downloaded every candidate, up to ten, full size,
while nothing reads anything but primary.jpg — 5.3 GB measured on a
real cache, 4.1 GB of it unreachable. OrphanedArtistImagesJob is why
that survived: it joined the bare MBID onto the images directory, but
artist directories are sharded under a two-character prefix, so it
named a path that never existed and deleted the rows that were the only
record of the files it left behind.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UDCbcCZQepnpSQYJ6SxxZm
2026-08-14 13:33:54 -04:00
yonluandClaude Opus 5 dc890d1fcc feat(library): remove a track from the library without deleting the file
RemoveFromLibrary deletes the audio_files rows the way the scan's own
orphan cleanup does and records each path in excluded_paths. The
exclusion is not an enhancement: without it the next scan finds the
file, sees no row and imports it again, so the button undoes itself.

The soft scan compares files on disk against rows in the database, so
surveyAudioFiles and countAudioFiles both take the exclusion set —
otherwise an excluded path makes the two disagree forever and queues a
full scan on every launch. Deleting a row cascades to queue_tracks, so
the removal calls the same CompactQueue hook RemoveLibrary does.

Also lands the requested badge: library-status-indicator is a button
again where it can act, utils/library-status.ts states once what owning
and wanting mean, and the long-declared queued state finally has a
producer.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UDCbcCZQepnpSQYJ6SxxZm
2026-08-14 13:12:01 -04:00
yonluandClaude Sonnet 5 65333857e2 refactor(download): rename Want/Request to Request/Download, unify downloads flow, add auto-download guardrails
Build & publish Arch package / arch-package (push) Successful in 2m2s
Search index maintenance / maintain-index (push) Successful in 7s
The durable "I asked for this" record was called Want, and the one-shot
search-and-grab attempt was called Request — names that didn't match
what either actually did. Want is now Request, and the old Request/Item
is now Download/DownloadItem, with a table-rename migration
(download_wants -> download_requests, old download_requests ->
download_downloads) safe against both fresh installs and existing data.

Every anchored manual download now upserts/reuses a durable Request
before running, so a "download now" that finds nothing is picked up by
the background reconciler automatically instead of just failing with
no trace — the gap that caused this session's repeated "no candidates
found" failures on the same album.

Also adds auto-download guardrails (file-size min/max with a preferred
target, allowed file types) that gate what the pipeline may grab
unattended, live-editable from a new settings section. The frontend's
wanted-view becomes downloads-view, with a new Downloads tab showing
attempt/transfer history that previously had no UI at all.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y2Agd9af5hE7qzti2ackiS
2026-08-10 14:35:57 -04:00
yonluandClaude Sonnet 5 cbd82a5a74 feat: autotag mixed-bag splitting, search relevance fixes, and multi-library download imports
Build & publish Arch package / arch-package (push) Successful in 2m2s
Search index maintenance / maintain-index (push) Successful in 7s
Autotag: detect "junk drawer" folders with no artist/album consensus
and split them into synthetic per-cluster groups instead of forcing
one match on an unrelated pile of tracks; repair tagging_items rows
left behind by a prior scan orphan-cleanup gap.

Explore: fix an exact artist-name search being drowned out by its own
catalog entries in intent-prior scoring, and prune stale in_library
bookkeeping left behind when a referenced library row is deleted.

Download: fix a multi-library regression where every import failed
with "no library root configured" — the importer resolved the
library root from a legacy single-library config field that nothing
populates in the current multi-library model. It now resolves the
destination library per-request from the request's own library_id.
Also widen the Soulseek search window (12s -> 20s), measured against
real request history to be missing available peers on live queries.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y2Agd9af5hE7qzti2ackiS
2026-08-10 11:52:26 -04:00
yonluandClaude Sonnet 5 e190fd75b9 feat: data lifecycle rewrite, download clients, wanted list, and central catalog index
Build & publish Arch package / arch-package (push) Successful in 2m12s
Search index maintenance / maintain-index (push) Successful in 2h22m28s
Ships the fresh-start schema cleanup: rebuilt explore catalog index
pipeline (dump import, artifact fetch/build, incremental listen-count
refresh), a new download subsystem (Lidarr/Prowlarr/qBittorrent/SABnzbd/
slskd/yt-dlp providers, staging, reconciliation, wanted list), and the
supporting schema/query/store changes across backend and frontend.

Also includes two smaller follow-ups: bump the central index's
rebuild-after cadence from 90 to 180 days, and remove the Explore
"library only" online/offline toggle entirely (frontend-only, no
backend counterpart) rather than carry unused UI/state.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y2Agd9af5hE7qzti2ackiS
2026-08-06 17:12:01 -04:00