soulsync/core/imports
BoulderBadgeDad 1d16ac7978 Downloads: reuse an album's existing folder so batches don't split it (#829)
Tacobell444: when tracks land in an album across multiple batches (a wishlist
run, the Album Completeness job, a missed track re-downloaded later), the folder
is rebuilt from API metadata each time — so when $albumtype or $year come back
blank/different on a later batch, the folder NAME changes and the album splits,
forcing a Reorganize.

Fix: build_final_path_for_track now checks whether the album already lives in a
single folder on disk and, if so, drops the new track there instead of a freshly
templated folder. Match (chosen): exact stored Spotify album id first, then a
STRICT >=0.85 name+artist match (vs the 0.7 used elsewhere) — a wrong match here
misplaces a file. New core/library/existing_album_folder.resolve_existing_album_folder
holds the logic; always-on with template fallback.

Safety rails: only returns a folder UNDER the transfer dir (never a read-only
library/NAS mount), only when the album lives in EXACTLY ONE folder (multiple =
disc subfolders, which DatabaseTrack can't disambiguate — those defer to the
template), and any failure falls through to the template path. Added
MusicDatabase.get_album_by_spotify_album_id for the id-first lookup.

Tests: single-folder reuse, no-match, below-threshold, multi-folder defer,
outside-transfer reject, id-first, missing transfer dir, no-files-on-disk.
8 tests; 1556 path/import/download tests pass (only the known soundcloud
failures remain).
2026-06-09 13:47:25 -07:00
..
__init__.py Rehome import helpers into core/imports 2026-04-27 19:54:44 +03:00
album.py Show MusicBrainz release variants in import 2026-05-24 09:33:19 -07:00
album_matching.py Auto-import matching: fix Deezer source classification + bump tolerance 2026-05-09 15:53:17 -07:00
album_naming.py Rehome import helpers into core/imports 2026-04-27 19:54:44 +03:00
context.py Wishlist payloads: preserve real track_number + release_date end-to-end 2026-05-27 14:25:03 -07:00
file_integrity.py Import: don't duration-quarantine manual imports against a re-resolved release (#804) 2026-06-07 23:02:34 -07:00
file_ops.py Surface silent exceptions across remaining modules — ~70 sites 2026-05-07 10:28:58 -07:00
filename.py Fix album-bundle downloads landing every track as track 1 2026-05-26 21:04:27 -07:00
guards.py Quarantine management — list, approve, delete, recover 2026-05-14 08:06:19 -07:00
paths.py Downloads: reuse an album's existing folder so batches don't split it (#829) 2026-06-09 13:47:25 -07:00
pipeline.py Import: don't duration-quarantine manual imports against a re-resolved release (#804) 2026-06-07 23:02:34 -07:00
quarantine.py Quarantine: manage a quarantined file from the download modal (Listen / Accept / Search) 2026-05-31 15:41:04 -07:00
resolution.py Surface silent exceptions across remaining modules — ~70 sites 2026-05-07 10:28:58 -07:00
routes.py Import: don't duration-quarantine manual imports against a re-resolved release (#804) 2026-06-07 23:02:34 -07:00
side_effects.py Download Origins: see (and delete) exactly what watchlist + playlist syncs downloaded 2026-06-07 00:15:31 -07:00
staging.py Fix album-bundle downloads landing every track as track 1 2026-05-26 21:04:27 -07:00
tag_policy.py Import: never wipe a clean/matched import's tags when enhancement fails (#804) 2026-06-07 22:44:43 -07:00
track_number.py Wishlist: fix three regressions causing all imports to land as track 01 with no year 2026-05-27 15:39:22 -07:00
version_mismatch_fallback.py Post-merge #801 follow-ups: un-silence the retry engine's logs + register origin-history.js 2026-06-07 00:58:09 -07:00