soulsync/core/imports/folder_artist.py

52 lines
2.1 KiB
Python

"""Opt-in "parent folder artist" resolution for imports.
Historically the auto-import worker derived the artist from the top Staging
folder whenever the path had >=2 levels and that folder wasn't a category word
(albums/singles/eps/...). It did so *unconditionally*, overriding even a
confidently metadata-identified artist — which mass-mislabelled files when a
user staged everything under one container folder (see the "soulsync" incident).
This module isolates that decision as a pure function so it can be:
- gated behind an opt-in setting (``import.folder_artist_override``,
default on for legacy compatibility), and
- unit-tested without standing up the whole import worker.
"""
import os
# Top-level folder names that denote a *category*, not an artist.
DEFAULT_CATEGORY_NAMES = frozenset({
'albums', 'singles', 'eps', 'compilations', 'mixtapes',
'discography', 'music', 'downloads',
})
def resolve_folder_artist(rel_path, identified_artist, enabled,
category_names=DEFAULT_CATEGORY_NAMES):
"""Return the folder-derived artist to use, or ``None`` to keep the
already-identified artist.
When ``enabled`` is False this always returns ``None`` — the import keeps
whatever artist the metadata match produced. Only when explicitly enabled
does it fall back to the staging folder name, and even then never when the
folder already equals the identified artist.
``rel_path`` is the candidate's path relative to the staging root.
"""
if not enabled:
return None
parts = [p for p in rel_path.replace('\\', '/').split('/') if p]
folder_artist = None
if len(parts) >= 2:
if len(parts) >= 3 and parts[1].lower() in category_names:
# Artist/Albums/AlbumFolder -> parts[0] is the artist
folder_artist = parts[0]
elif parts[0].lower() not in category_names:
# Artist/AlbumFolder -> parts[0] is the artist
folder_artist = parts[0]
if folder_artist and folder_artist.lower() != (identified_artist or '').lower():
return folder_artist
return None