soulsync/core
BoulderBadgeDad 38461295c2 Spotify: enrichment can prefer Free, and the budget→Free bridge actually diverts
Two related fixes at one root cause. Every catalog method gated the official API
on `use_spotify = is_spotify_authenticated()` and only fell to Free *after*
official failed. So when the client was authed but should defer to Free —
specifically when the worker's daily real-API budget was spent — it kept hitting
the official API anyway (just stopped *counting* it). The budget "bridge" never
actually diverted; it only stopped pausing.

Root-cause fix: the official gate is now `is_spotify_authenticated() and not
self._free_active()` across all 8 catalog methods (search_artists/albums/tracks,
get_artist/album/album_tracks/track_details/artist_albums). No-auth and
rate-limited are unchanged (auth is already False there); the change only affects
the cases where auth is True but we deliberately defer to Free. The user-account
methods and the metadata-availability helper are untouched.

New opt-in: metadata.spotify_free_enrichment. When set, the worker puts
`_prefer_free` on its OWN client and _free_active() honors it (needs only the
package installed — the flag is the opt-in — not the 'Spotify Free' source
choice). So a connected user can run bulk enrichment on the no-creds source to
spare their official quota, while interactive search/resolve stay official-first
(they use a different client that never sets the flag). Default off.

Tests: _free_active honors prefer_free (and is inert without the package);
search_albums defers to Free — official .sp raises if touched — both under
prefer_free AND under budget-exhaustion (the divert that previously never
happened). 215 Spotify tests pass.
2026-06-09 12:24:57 -07:00
..
artists
automation Merge pull request #780 from kekkokk/feature/organize-by-playlist-library 2026-06-03 20:33:18 -07:00
blocklist Blocklist Phase 1 (backfill + API + modal): the Blocklist button on the watchlist page 2026-06-07 15:25:52 -07:00
diagnostics #802: on-demand memory-growth diagnostic (tracemalloc, browser-drivable) 2026-06-06 18:31:14 -07:00
discovery Sync: append mode preserves the playlist image like reconcile (#811) 2026-06-07 23:25:42 -07:00
download_engine
download_plugins Torrents: stalled-torrent handling — abandon a dead magnet instead of holding a worker 6h (noldevin) 2026-06-07 12:38:51 -07:00
downloads Wishlist: serialize album-bundle downloads so they stop flooding the search pool (Sokhi #740) 2026-06-09 10:06:53 -07:00
enrichment Import speed: downloads pause ALL enrichment workers, discovery pauses the contention five 2026-06-06 19:05:56 -07:00
imports Import: don't duration-quarantine manual imports against a re-resolved release (#804) 2026-06-07 23:02:34 -07:00
library Expired Download Cleaner: retention-based cleanup of watchlist/playlist downloads (Boulder) 2026-06-07 22:06:56 -07:00
maintenance Add one-off repair for source ids shared across multiple artists 2026-06-05 08:38:55 -07:00
matching #797: stop AcoustID quarantining correct non-English-artist downloads 2026-06-05 16:02:01 -07:00
media_server
metadata Cover Art Filler: write cover.jpg to the RESOLVED folder, not the raw DB path (Sokhi — the actual bug) 2026-06-08 18:25:50 -07:00
personalized
playback
playlists PR #780 follow-ups: snapshot-based stale check + submit guard + dead code 2026-06-03 20:45:17 -07:00
radio
repair_jobs Cover Art Filler: scan falls back to the raw file path when mapping fails (Sokhi #fix) 2026-06-08 17:32:38 -07:00
search Search: extend pasted-link resolution to Discogs (#813) 2026-06-08 14:37:48 -07:00
stats
streaming #809 Navidrome playback: stream via the server's API when the library isn't mounted on disk 2026-06-07 13:52:14 -07:00
sync Fix #792: reconcile sync mode was clamped back to 'replace' in the backend 2026-06-04 15:57:40 -07:00
text Cover art: a numeric difference is a different release — Vol.4 stops wearing Vol.4.5's cover 2026-06-07 10:21:23 -07:00
torrent_clients Fix #790: torrent client URL without http:// scheme fails to connect 2026-06-04 11:57:53 -07:00
usenet_clients
watchlist
webui
wishlist Wishlist: manual "add to wishlist" now skips already-owned tracks (#825) 2026-06-09 10:55:45 -07:00
workers
acoustid_client.py
acoustid_verification.py #797: stop AcoustID quarantining correct non-English-artist downloads 2026-06-05 16:02:01 -07:00
album_consistency.py
amazon_client.py
amazon_download_client.py
amazon_outage.py
amazon_worker.py Enrichment manager: 'process this group first' + refined hero header 2026-06-02 19:45:04 -07:00
api_call_tracker.py
archive_pipeline.py
artist_source_detail.py
artist_source_lookup.py Fix artist-detail showing wrong artist when a source id is duplicated 2026-06-05 07:24:51 -07:00
audiodb_client.py
audiodb_worker.py Tighten artist matching: 0.85 gate + shared uniqueness guard 2026-06-05 10:01:17 -07:00
auto_import_worker.py
automation_engine.py Wire automation engine through next_run_at + register monthly_time (PR 2/4) 2026-05-27 12:03:41 -07:00
connection_detect.py
connection_test.py
database_update_worker.py Run auto-reconcile as a scan phase inside the running window 2026-06-05 19:10:31 -07:00
db_integrity.py DB backups: verify integrity + never evict the last good backup 2026-05-30 21:13:04 -07:00
debug_info.py
deezer_client.py
deezer_download_client.py
deezer_worker.py Tighten artist matching: 0.85 gate + shared uniqueness guard 2026-06-05 10:01:17 -07:00
discogs_client.py
discogs_worker.py Tighten artist matching: 0.85 gate + shared uniqueness guard 2026-06-05 10:01:17 -07:00
download_orchestrator.py
genius_client.py Genius 429 backoff: fail-fast gate instead of napping the import pipeline 2026-06-06 20:51:33 -07:00
genius_worker.py Enrichment manager: 'process this group first' + refined hero header 2026-06-02 19:45:04 -07:00
genre_filter.py
hifi_client.py
hydrabase_client.py
hydrabase_worker.py
image_cache.py
itunes_client.py
itunes_worker.py Full release dates: store + write yyyy-mm-dd end to end (#824 part 2) 2026-06-08 23:32:42 -07:00
jellyfin_client.py Jellyfin/Emby: populate album thumb_url during the library scan (root cause of "flags every album") 2026-06-08 09:40:27 -07:00
lastfm_client.py
lastfm_worker.py Enrichment manager: 'process this group first' + refined hero header 2026-06-02 19:45:04 -07:00
library_reorganize.py #767-2: reorganize finds the right album edition instead of mislabeling singles as deluxe 2026-06-06 10:53:13 -07:00
lidarr_download_client.py
listenbrainz_client.py
listenbrainz_manager.py
listening_stats_worker.py
lyrics_client.py Lyrics: add a "Lyrics Filler" maintenance job + lyrics option in the Re-tag tool (Sokhi) 2026-06-07 17:27:52 -07:00
matching_engine.py fix(tidal): honour version field in matching and back off on rate limits 2026-06-08 13:50:19 -04:00
metadata_service.py
musicbrainz_client.py
musicbrainz_search.py
musicbrainz_service.py Cover art: a numeric difference is a different release — Vol.4 stops wearing Vol.4.5's cover 2026-06-07 10:21:23 -07:00
musicbrainz_worker.py Tighten artist matching: 0.85 gate + shared uniqueness guard 2026-06-05 10:01:17 -07:00
navidrome_client.py #809 Navidrome playback: stream via the server's API when the library isn't mounted on disk 2026-06-07 13:52:14 -07:00
personalized_playlists.py Blocklist Phase 1 (backend): artist/album/track bans enforced at the wishlist chokepoint 2026-06-07 15:18:25 -07:00
plex_client.py Fix #792: 'reconcile' playlist sync mode (edit in place, keep image/description) 2026-06-04 15:15:49 -07:00
prowlarr_client.py
qobuz_client.py
qobuz_worker.py Tighten artist matching: 0.85 gate + shared uniqueness guard 2026-06-05 10:01:17 -07:00
reorganize_queue.py
reorganize_runner.py
repair_worker.py Cover Art Filler: write cover.jpg to the RESOLVED folder, not the raw DB path (Sokhi — the actual bug) 2026-06-08 18:25:50 -07:00
replaygain.py
runtime_state.py
seasonal_discovery.py
similar_artists_worker.py Lint: fix ruff B905 (zip strict=) + S110 (try/except/pass) in similar-artists worker + perf endpoint 2026-06-03 16:35:19 -07:00
socketio_cors.py
soulid_worker.py
soulseek_client.py Fix #796: Soulseek album bundle left completed files in slskd download folder 2026-06-04 21:56:07 -07:00
soulsync_client.py
soundcloud_client.py
source_ids.py
spotify_client.py Spotify: enrichment can prefer Free, and the budget→Free bridge actually diverts 2026-06-09 12:24:57 -07:00
spotify_free_metadata.py Spotify Free: close the album-search gap via the artist's discography 2026-06-09 12:05:40 -07:00
spotify_public_api.py SpotipyFree integration confirmed working (236 tracks live); deps + meta tweak 2026-06-02 22:50:04 -07:00
spotify_public_scraper.py Diagnostics: route public-fetch logs to soulsync namespace + log HTTP status 2026-06-02 22:09:51 -07:00
spotify_token_cache.py Spotify tokens move into the database — daily Docker deauth fixed (wolf39us) 2026-06-07 12:01:33 -07:00
spotify_worker.py Spotify: enrichment can prefer Free, and the budget→Free bridge actually diverts 2026-06-09 12:24:57 -07:00
tag_writer.py Full release dates: store + write yyyy-mm-dd end to end (#824 part 2) 2026-06-08 23:32:42 -07:00
tidal_client.py
tidal_download_client.py fix(tidal): honour version field in matching and back off on rate limits 2026-06-08 13:50:19 -04:00
tidal_worker.py Tighten artist matching: 0.85 gate + shared uniqueness guard 2026-06-05 10:01:17 -07:00
watchlist_scanner.py Watchlist: stop treating different decimal-volume albums as duplicates (Sokhi — the real bug) 2026-06-08 20:46:40 -07:00
web_scan_manager.py
wishlist_service.py
worker_utils.py Tighten artist matching: 0.85 gate + shared uniqueness guard 2026-06-05 10:01:17 -07:00
youtube_client.py YouTube: ship the JS runtime + nightly yt-dlp so streams/music videos work out of the box 2026-06-06 16:50:24 -07:00