The Duplicate Cleaner moves de-duplicated files into <transfer>/deleted/. If a user's media server scans the transfer folder (e.g. a /music root holding both the library and the transfer dir), those quarantined files get real track rows in SoulSync's DB. Reorganize is purely DB-driven — it acts on each track's stored file_path — so it would dutifully move a quarantined file back OUT of /deleted to the template location, exactly what Tacobell444 reported. We can't stop the rows from existing (they come from the media server, which the app doesn't control), so the fix is bounded to Reorganize, as the reporter asked: skip any track whose resolved path is under <transfer>/deleted. Surfaced as a non-matched 'In deleted/quarantine folder — skipped' in the preview; apply mirrors it (post-process never runs, file left in place, counted as skipped). Detection is anchored to the <transfer>/deleted PREFIX (not a bare substring) so a real album like 'Deleted Scenes' is kept; falls back to an exact 'deleted' path-segment match when transfer_dir is unavailable (mirrors the cleaner's own 'if deleted in dirs' skip). The one unavoidable ambiguity — an artist folder named exactly 'deleted' at the transfer root — is pinned in a test as intentional. Guard added once where both consumers see it: preview_album_reorganize and the apply worker (_RunContext gains transfer_dir). Tests: tests/test_reorganize_deleted_quarantine.py (8 unit) + test_library_reorganize_orchestrator.py (preview + apply integration, differential-verified they fail without the fix). 128 adjacent reorganize tests still green.
72 lines
3.4 KiB
Python
72 lines
3.4 KiB
Python
"""Reorganize must skip files in the duplicate-cleaner quarantine (#746).
|
|
|
|
The Duplicate Cleaner moves de-duplicated files into ``<transfer>/deleted/``.
|
|
If the user's media server scans the transfer folder (e.g. a ``/music`` root
|
|
holding both the library and the transfer dir), those quarantined files get real
|
|
rows in SoulSync's DB. Reorganize is purely DB-driven, so without a guard it
|
|
would move them back OUT of /deleted to the template location.
|
|
|
|
These tests pin:
|
|
1. ``_is_in_deleted_quarantine`` — the anchored detection, including the
|
|
false-positive guard (an album literally named "Deleted" elsewhere is kept).
|
|
2. ``preview_album_reorganize`` — a quarantined track is surfaced as a skip,
|
|
a normal track is not (proves the planner-shared guard fires on the path
|
|
both preview AND apply run through).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
|
|
from core.library_reorganize import _is_in_deleted_quarantine
|
|
|
|
|
|
TRANSFER = os.path.join(os.sep, "music", "soulsync")
|
|
|
|
|
|
class TestIsInDeletedQuarantine:
|
|
def test_file_directly_in_quarantine_is_flagged(self):
|
|
p = os.path.join(TRANSFER, "deleted", "Artist", "Album", "01.flac")
|
|
assert _is_in_deleted_quarantine(p, TRANSFER) is True
|
|
|
|
def test_file_in_normal_album_is_not_flagged(self):
|
|
p = os.path.join(TRANSFER, "Artist", "Album", "01.flac")
|
|
assert _is_in_deleted_quarantine(p, TRANSFER) is False
|
|
|
|
def test_album_with_deleted_in_name_is_kept(self):
|
|
"""Anchored to the <transfer>/deleted PREFIX, not a substring — a
|
|
real album like 'Deleted Scenes' nested under an artist must NOT be
|
|
skipped."""
|
|
p = os.path.join(TRANSFER, "Artist", "Deleted Scenes", "01.flac")
|
|
assert _is_in_deleted_quarantine(p, TRANSFER) is False
|
|
|
|
def test_known_unavoidable_collision_is_documented(self):
|
|
"""The ONE genuine ambiguity: an artist folder named exactly
|
|
'deleted' sitting directly at the transfer root occupies the same
|
|
path as the duplicate-cleaner quarantine, so it IS treated as
|
|
quarantine. This is unavoidable (we can't tell a real 'deleted'
|
|
artist from the cleaner's dir) and accepted — pinned here so the
|
|
behavior is intentional, not a surprise. Differently-cased or
|
|
nested 'Deleted' names are safe (see the other tests)."""
|
|
collision = os.path.join(TRANSFER, "deleted", "Album", "01.flac")
|
|
assert _is_in_deleted_quarantine(collision, TRANSFER) is True
|
|
|
|
def test_substring_not_matched(self):
|
|
"""'Undeleted' / 'deleted_scenes' as a segment must not trip the
|
|
exact-segment / prefix check."""
|
|
p = os.path.join(TRANSFER, "Undeleted", "Album", "01.flac")
|
|
assert _is_in_deleted_quarantine(p, TRANSFER) is False
|
|
|
|
def test_no_transfer_dir_falls_back_to_segment_match(self):
|
|
p = os.path.join(os.sep, "anywhere", "deleted", "x.flac")
|
|
assert _is_in_deleted_quarantine(p, None) is True
|
|
p2 = os.path.join(os.sep, "anywhere", "Undeleted", "x.flac")
|
|
assert _is_in_deleted_quarantine(p2, None) is False
|
|
|
|
def test_empty_path_is_safe(self):
|
|
assert _is_in_deleted_quarantine(None, TRANSFER) is False
|
|
assert _is_in_deleted_quarantine("", TRANSFER) is False
|
|
|
|
def test_nested_subfolders_under_quarantine_flagged(self):
|
|
p = os.path.join(TRANSFER, "deleted", "a", "b", "c", "track.flac")
|
|
assert _is_in_deleted_quarantine(p, TRANSFER) is True
|