soulsync/tests/imports
BoulderBadgeDad 9d091207f6 fix: atomic file placement so Jellyfin can't index a half-written track (null-disc)
safe_move_file used shutil.move, which for a CROSS-filesystem move (downloads volume ->
library volume, common in Docker/NAS) copies the file to the FINAL path incrementally. A
media-server real-time watcher (Jellyfin) can catch that partial file mid-write and cache it
with null/incomplete metadata — tracks landing with no disc. Inconsistent because it only bites
cross-fs and races the scan tick; 're-add library' fixes it (rescan reads the now-complete file)
and the on-disk tags are fine — exactly the reported symptoms.

Fix: same-fs uses an atomic os.replace (also overwrites dst); cross-fs copies to a HIDDEN temp
sibling, fsyncs, then atomic os.replace into place (+ temp cleanup on failure). A watcher only
ever sees the COMPLETE file. EXDEV/EPERM/EACCES + the old string check route here, so detection
is strictly broader than before.

Tests: same-fs move, simulated EXDEV routes to the atomic path and leaves no partial temp, helper
completes+cleans, helper cleans temp + preserves source on failure. Existing replace-destination
test still green; 574 imports+relocate tests pass.
2026-06-23 23:17:50 -07:00
..
test_album_grouping.py Library: group imported albums by canonical release id, not just the name string 2026-06-18 09:16:00 -07:00
test_album_matching_exact_id.py
test_album_matching_helper.py
test_album_position.py Auto-download: resolve an album track's real position from its album (not 1/1) 2026-06-22 13:32:24 -07:00
test_album_search_scoring.py
test_auto_import_clear_completed_endpoint.py
test_auto_import_context_shape.py
test_auto_import_executor.py
test_auto_import_live_progress.py
test_auto_import_multi_disc_matching.py
test_auto_import_multi_source_fallback.py
test_auto_import_scanner_grouping.py
test_auto_import_tag_reader_real_files.py
test_build_single_import_context_typed_path.py
test_dedup_orphan_cleanup.py
test_duration_tolerance_resolution.py
test_expected_duration_for_check.py Import: don't duration-quarantine manual imports against a re-resolved release (#804) 2026-06-07 23:02:34 -07:00
test_file_integrity.py Integrity check: don't quarantine valid streamed FLAC as 'zero-length' (#756) 2026-05-31 11:28:40 -07:00
test_folder_artist_override.py Fix import artist override and verification review 2026-06-11 01:28:31 +02:00
test_import_album.py
test_import_context.py Multi-artist tags: Search → Download Now finally knows its metadata source (Netti93) 2026-06-09 17:20:16 -07:00
test_import_file_ops.py fix: atomic file placement so Jellyfin can't index a half-written track (null-disc) 2026-06-23 23:17:50 -07:00
test_import_filename.py
test_import_guards.py
test_import_paths.py Fix #767: Library Organizer dry run no longer creates folders 2026-06-02 10:32:06 -07:00
test_import_pipeline.py PR #801 follow-up: default-config template contradicted the retry engine's documented default 2026-06-07 11:04:28 -07:00
test_import_rejection_reason.py Fix #764: manual import reported quarantined files as a successful "Done" 2026-06-02 08:40:26 -07:00
test_import_resolution_single_track_context.py
test_import_routes.py Import: don't duration-quarantine manual imports against a re-resolved release (#804) 2026-06-07 23:02:34 -07:00
test_import_side_effects.py
test_import_singles_route_through_album_path.py
test_import_staging.py Show MusicBrainz release variants in import 2026-05-24 09:33:19 -07:00
test_lossy_copy_delete_original.py
test_normalize_disc_number.py Multi-disc: file the track in the disc folder that matches its tag (Sokhi) 2026-06-22 10:56:53 -07:00
test_quarantine_management.py #876: group quarantine alternatives by target track-id + auto-clear siblings on approve 2026-06-15 22:12:06 -07:00
test_rematch_apply.py #889 Phase 4: the Re-identify modal + apply backend 2026-06-18 15:37:56 -07:00
test_rematch_hints.py #889 Phase 1: re-identify hint store (DB table + pure create/find/consume seam) 2026-06-18 15:15:41 -07:00
test_rematch_hints_seam.py #889: FIX data loss — re-identify to the same release no longer deletes the file 2026-06-18 17:13:46 -07:00
test_rematch_search.py #889 Phase 3: re-identify search — multi-source track→release lookup + API 2026-06-18 15:31:33 -07:00
test_search_match_endpoints.py
test_single_to_album.py Library: wire single->album resolution into import detection (gated, fail-safe) 2026-06-18 09:30:11 -07:00
test_track_number_resolver.py Track "01" bug: recover real track position instead of fabricating 1 2026-06-15 23:35:48 -07:00
test_track_number_strip.py #890: strip leading track-number prefix from filename-derived titles 2026-06-18 18:35:04 -07:00
test_version_mismatch_fallback.py Downloads: opt-in last-resort acceptance of repeated version mismatches 2026-06-06 16:44:14 +02:00