diff --git a/core/library/path_resolver.py b/core/library/path_resolver.py index 712ec3c2..0e40e678 100644 --- a/core/library/path_resolver.py +++ b/core/library/path_resolver.py @@ -224,10 +224,23 @@ def resolve_library_file_path_with_diagnostic( if not base_dirs: return None, attempt - # Skip index 0 to avoid drive-letter / leading-slash artifacts - # (e.g. "E:" or "" from a leading "/"). + # Try progressively shorter path suffixes against each base dir. + # + # Start at index 0 so a clean RELATIVE library path is tried in FULL first. + # SoulSync's own library scanner stores paths like + # "Asketa/Another Side/01 - Track.flac" (no leading slash) — index 0 is the + # artist folder and dropping it (the old range(1, ...)) meant the artist + # segment was never joined, so nothing under transfer/ ever resolved and + # every track looked unreadable to the quality scanner. + # + # For ABSOLUTE media-server paths ("/music/Artist/Album/track.flac") index 0 + # is the empty leading segment and i=0 yields os.path.join(base, "", ...) == + # base/Artist/... which simply won't exist and harmlessly falls through to + # i=1 ("music/...") etc. A Windows drive part ("E:") at i=0 likewise just + # fails on POSIX and falls through. So starting at 0 is safe for every form + # and only ADDS the relative-full-path match that was missing. for base in base_dirs: - for i in range(1, len(path_parts)): + for i in range(0, len(path_parts)): candidate = os.path.join(base, *path_parts[i:]) if os.path.exists(candidate): return candidate, attempt diff --git a/tests/library/test_path_resolver.py b/tests/library/test_path_resolver.py index 713fc8ae..de77b738 100644 --- a/tests/library/test_path_resolver.py +++ b/tests/library/test_path_resolver.py @@ -74,6 +74,25 @@ def test_finds_file_via_transfer_folder_suffix_walk(tmp_path: Path) -> None: assert result == str(actual) +def test_finds_file_via_relative_db_path_full_suffix(tmp_path: Path) -> None: + """SoulSync's own library scanner stores RELATIVE paths with NO leading + slash, e.g. "Artist/Album/track.flac". Index 0 is the artist folder, so the + resolver must try the FULL path first — the old range(1, ...) dropped the + artist segment and every such track came back unresolved (quality scanner: + "could not be probed"). Regression guard for that fix.""" + transfer = tmp_path / "Transfer" + (transfer / "Asketa" / "Another Side").mkdir(parents=True) + actual = transfer / "Asketa" / "Another Side" / "01 - Another Side.flac" + actual.write_bytes(b"audio") + + result = resolve_library_file_path( + "Asketa/Another Side/01 - Another Side.flac", + transfer_folder=str(transfer), + ) + + assert result == str(actual) + + def test_finds_file_via_download_folder_when_transfer_misses(tmp_path: Path) -> None: transfer = tmp_path / "Transfer" transfer.mkdir()