Tighten metadata helper boundaries

- remove stale wrapper helpers from web_server and metadata_common
- import provider helpers directly in metadata_source
- keep the metadata modules' public surface explicit
This commit is contained in:
Antti Kettunen 2026-04-24 21:52:06 +03:00
parent edd9048f86
commit b9269b4f16
No known key found for this signature in database
GPG key ID: C6B2A3D250359BD7
7 changed files with 131 additions and 154 deletions

View file

@ -51,18 +51,16 @@ from core.import_runtime_state import (
_processed_download_ids,
tasks_lock,
)
from core.metadata_enrichment import (
download_cover_art,
enhance_file_metadata,
generate_lrc_file,
wipe_source_tags,
)
from core.metadata_artwork import download_cover_art
from core.metadata_common import wipe_source_tags
from core.metadata_enrichment import enhance_file_metadata
from core.import_paths import (
build_final_path_for_track,
build_simple_download_destination,
docker_resolve_path,
)
from core.import_album_naming import resolve_album_group
from core.metadata_lyrics import generate_lrc_file
from database.music_database import get_database
from utils.logging_config import get_logger

View file

@ -8,17 +8,22 @@ import urllib.request
from core.import_context import get_import_context_album
from core.metadata_common import (
_get_config_manager,
_get_image_dimensions,
_get_logger,
_get_mutagen_symbols,
get_config_manager,
get_image_dimensions,
get_logger,
get_mutagen_symbols,
)
__all__ = [
"embed_album_art_metadata",
"download_cover_art",
]
def embed_album_art_metadata(audio_file, metadata: dict):
cfg = _get_config_manager()
logger_ = _get_logger()
symbols = _get_mutagen_symbols()
cfg = get_config_manager()
logger_ = get_logger()
symbols = get_mutagen_symbols()
if not symbols:
return
@ -59,7 +64,7 @@ def embed_album_art_metadata(audio_file, metadata: dict):
picture.data = image_data
picture.type = 3
picture.mime = mime_type
width, height = _get_image_dimensions(image_data)
width, height = get_image_dimensions(image_data)
picture.width = width or 640
picture.height = height or 640
picture.depth = 24
@ -74,8 +79,8 @@ def embed_album_art_metadata(audio_file, metadata: dict):
def download_cover_art(album_info: dict, target_dir: str, context: dict = None):
cfg = _get_config_manager()
logger_ = _get_logger()
cfg = get_config_manager()
logger_ = get_logger()
if cfg.get("metadata_enhancement.cover_art_download", True) is False:
return

View file

@ -7,10 +7,24 @@ import threading
from types import SimpleNamespace
from typing import Any, Dict
from utils.logging_config import get_logger
from utils.logging_config import get_logger as _create_logger
logger = get_logger("metadata_enrichment")
logger = _create_logger("metadata_common")
__all__ = [
"get_logger",
"get_config_manager",
"get_mutagen_symbols",
"get_file_lock",
"is_ogg_opus",
"is_vorbis_like",
"save_audio_file",
"get_image_dimensions",
"strip_all_non_audio_tags",
"verify_metadata_written",
"wipe_source_tags",
]
_FILE_LOCKS: Dict[str, threading.Lock] = {}
_FILE_LOCKS_LOCK = threading.Lock()
@ -21,11 +35,11 @@ class _NullConfigManager:
return default
def _get_logger():
def get_logger():
return logger
def _get_config_manager():
def get_config_manager():
try:
from config.settings import config_manager as settings_config_manager
@ -34,33 +48,7 @@ def _get_config_manager():
return _NullConfigManager()
def _get_database():
try:
from database.music_database import get_database
return get_database()
except Exception:
return None
def _get_itunes_client():
try:
from core.metadata_service import get_itunes_client
return get_itunes_client()
except Exception:
return None
def _extract_artist_name(artist: Any) -> str:
if isinstance(artist, dict):
return str(artist.get("name", "") or "")
if hasattr(artist, "name"):
return str(getattr(artist, "name") or "")
return str(artist) if artist else ""
def _get_mutagen_symbols():
def get_mutagen_symbols():
"""Lazy mutagen import so tests can monkeypatch this without the package installed."""
try:
from mutagen import File as MutagenFile
@ -128,7 +116,7 @@ def _get_mutagen_symbols():
)
def _get_file_lock(file_path: str) -> threading.Lock:
def get_file_lock(file_path: str) -> threading.Lock:
with _FILE_LOCKS_LOCK:
lock = _FILE_LOCKS.get(file_path)
if lock is None:
@ -137,21 +125,21 @@ def _get_file_lock(file_path: str) -> threading.Lock:
return lock
def _is_ogg_opus(audio_file: Any) -> bool:
def is_ogg_opus(audio_file: Any) -> bool:
return type(audio_file).__name__ == "OggOpus"
def _is_vorbis_like(audio_file: Any, symbols: Any) -> bool:
def is_vorbis_like(audio_file: Any, symbols: Any) -> bool:
vorbis_classes = tuple(
cls for cls in (
getattr(symbols, "FLAC", None),
getattr(symbols, "OggVorbis", None),
) if cls is not None
)
return bool(vorbis_classes) and isinstance(audio_file, vorbis_classes) or _is_ogg_opus(audio_file)
return bool(vorbis_classes) and isinstance(audio_file, vorbis_classes) or is_ogg_opus(audio_file)
def _save_audio_file(audio_file: Any, symbols: Any) -> None:
def save_audio_file(audio_file: Any, symbols: Any) -> None:
if isinstance(audio_file.tags, symbols.ID3):
audio_file.save(v1=0, v2_version=4)
elif isinstance(audio_file, symbols.FLAC):
@ -160,7 +148,7 @@ def _save_audio_file(audio_file: Any, symbols: Any) -> None:
audio_file.save()
def _get_image_dimensions(data: bytes):
def get_image_dimensions(data: bytes):
try:
if data[:8] == b"\x89PNG\r\n\x1a\n":
import struct
@ -185,12 +173,12 @@ def _get_image_dimensions(data: bytes):
return None, None
def _strip_all_non_audio_tags(file_path: str) -> dict:
def strip_all_non_audio_tags(file_path: str) -> dict:
summary = {"apev2_stripped": False, "apev2_tag_count": 0}
if os.path.splitext(file_path)[1].lower() != ".mp3":
return summary
symbols = _get_mutagen_symbols()
symbols = get_mutagen_symbols()
if not symbols:
return summary
@ -209,8 +197,8 @@ def _strip_all_non_audio_tags(file_path: str) -> dict:
return summary
def _verify_metadata_written(file_path: str) -> bool:
symbols = _get_mutagen_symbols()
def verify_metadata_written(file_path: str) -> bool:
symbols = get_mutagen_symbols()
if not symbols:
return False
@ -231,7 +219,7 @@ def _verify_metadata_written(file_path: str) -> bool:
return False
except symbols.APENoHeaderError:
pass
elif _is_vorbis_like(check, symbols):
elif is_vorbis_like(check, symbols):
title_found = bool(check.get("title"))
artist_found = bool(check.get("artist"))
elif isinstance(check, symbols.MP4):
@ -251,8 +239,8 @@ def _verify_metadata_written(file_path: str) -> bool:
def wipe_source_tags(file_path: str) -> bool:
try:
_strip_all_non_audio_tags(file_path)
symbols = _get_mutagen_symbols()
strip_all_non_audio_tags(file_path)
symbols = get_mutagen_symbols()
if not symbols:
return False
@ -267,7 +255,7 @@ def wipe_source_tags(file_path: str) -> bool:
else:
audio.add_tags()
tag_count = 0
_save_audio_file(audio, symbols)
save_audio_file(audio, symbols)
if tag_count > 0:
logger.info("[Tag Wipe] Stripped %s source tags from: %s", tag_count, os.path.basename(file_path))
return True

View file

@ -4,53 +4,30 @@ from __future__ import annotations
import os
from core.metadata_artwork import (
download_cover_art as _download_cover_art_impl,
embed_album_art_metadata,
)
from core.metadata_artwork import embed_album_art_metadata
from core.metadata_common import (
_get_config_manager,
_get_file_lock,
_get_image_dimensions as _common_get_image_dimensions,
_get_logger,
_get_mutagen_symbols,
_is_ogg_opus as _common_is_ogg_opus,
_is_vorbis_like,
_save_audio_file,
_strip_all_non_audio_tags,
_verify_metadata_written,
wipe_source_tags as _common_wipe_source_tags,
get_config_manager,
get_file_lock,
get_logger,
get_mutagen_symbols,
is_vorbis_like,
save_audio_file,
strip_all_non_audio_tags,
verify_metadata_written,
)
from core.metadata_lyrics import generate_lrc_file as _generate_lrc_file_impl
from core.metadata_source import embed_source_ids, extract_source_metadata
logger = _get_logger()
def _get_image_dimensions(data: bytes):
return _common_get_image_dimensions(data)
def _is_ogg_opus(audio_file):
return _common_is_ogg_opus(audio_file)
def wipe_source_tags(file_path: str) -> bool:
return _common_wipe_source_tags(file_path)
def generate_lrc_file(file_path: str, context: dict, artist: dict, album_info: dict) -> bool:
return _generate_lrc_file_impl(file_path, context, artist, album_info)
def download_cover_art(album_info: dict, target_dir: str, context: dict = None):
return _download_cover_art_impl(album_info, target_dir, context)
__all__ = [
"enhance_file_metadata",
"extract_source_metadata",
"embed_source_ids",
]
def enhance_file_metadata(file_path: str, context: dict, artist: dict, album_info: dict) -> bool:
cfg = _get_config_manager()
logger_ = _get_logger()
cfg = get_config_manager()
logger_ = get_logger()
if cfg.get("metadata_enhancement.enabled", True) is False:
logger_.warning("Metadata enhancement disabled in config.")
return True
@ -58,16 +35,16 @@ def enhance_file_metadata(file_path: str, context: dict, artist: dict, album_inf
if album_info is None:
album_info = {}
symbols = _get_mutagen_symbols()
symbols = get_mutagen_symbols()
if not symbols:
logger_.error("Mutagen is unavailable, cannot enhance metadata.")
return False
file_lock = _get_file_lock(file_path)
file_lock = get_file_lock(file_path)
with file_lock:
logger_.info("Enhancing metadata for: %s", os.path.basename(file_path))
try:
_strip_all_non_audio_tags(file_path)
strip_all_non_audio_tags(file_path)
audio_file = symbols.File(file_path)
if audio_file is None:
logger_.error("Could not load audio file with Mutagen: %s", file_path)
@ -84,12 +61,12 @@ def enhance_file_metadata(file_path: str, context: dict, artist: dict, album_inf
else:
audio_file.add_tags()
_save_audio_file(audio_file, symbols)
save_audio_file(audio_file, symbols)
metadata = extract_source_metadata(context, artist, album_info)
if not metadata:
logger_.error("Could not extract source metadata, saving with cleared tags.")
_save_audio_file(audio_file, symbols)
save_audio_file(audio_file, symbols)
return True
track_num_str = f"{metadata.get('track_number', 1)}/{metadata.get('total_tracks', 1)}"
@ -114,7 +91,7 @@ def enhance_file_metadata(file_path: str, context: dict, artist: dict, album_inf
audio_file.tags.add(symbols.TRCK(encoding=3, text=[track_num_str]))
if metadata.get("disc_number"):
audio_file.tags.add(symbols.TPOS(encoding=3, text=[str(metadata["disc_number"])]))
elif _is_vorbis_like(audio_file, symbols):
elif is_vorbis_like(audio_file, symbols):
if metadata.get("title"):
audio_file["title"] = [metadata["title"]]
if metadata.get("artist"):
@ -161,14 +138,14 @@ def enhance_file_metadata(file_path: str, context: dict, artist: dict, album_inf
if quality and cfg.get("metadata_enhancement.tags.quality_tag", True) is not False:
if isinstance(audio_file.tags, symbols.ID3):
audio_file.tags.add(symbols.TXXX(encoding=3, desc="QUALITY", text=[quality]))
elif _is_vorbis_like(audio_file, symbols):
elif is_vorbis_like(audio_file, symbols):
audio_file["quality"] = [quality]
elif isinstance(audio_file, symbols.MP4):
audio_file["----:com.apple.iTunes:QUALITY"] = [symbols.MP4FreeForm(quality.encode("utf-8"))]
_save_audio_file(audio_file, symbols)
save_audio_file(audio_file, symbols)
verified = _verify_metadata_written(file_path)
verified = verify_metadata_written(file_path)
if verified:
logger_.info("Metadata enhanced successfully.")
else:

View file

@ -9,12 +9,16 @@ from core.import_context import (
get_import_original_search,
normalize_import_context,
)
from core.metadata_common import _get_config_manager, _get_logger
from core.metadata_common import get_config_manager, get_logger
__all__ = [
"generate_lrc_file",
]
def generate_lrc_file(file_path: str, context: dict, artist: dict, album_info: dict) -> bool:
cfg = _get_config_manager()
logger_ = _get_logger()
cfg = get_config_manager()
logger_ = get_logger()
if cfg.get("metadata_enhancement.lrclib_enabled", True) is False:
return False

View file

@ -8,6 +8,7 @@ import time
from typing import Any, Dict
from core.import_context import (
extract_artist_name,
get_import_clean_artist,
get_import_clean_title,
get_import_context_album,
@ -18,16 +19,20 @@ from core.import_context import (
get_source_tag_names,
normalize_import_context,
)
from core.metadata_service import get_itunes_client
from database.music_database import get_database
from core.metadata_common import (
_extract_artist_name,
_get_config_manager,
_get_database,
_get_itunes_client,
_get_logger,
_get_mutagen_symbols,
_is_vorbis_like,
get_config_manager,
get_logger,
get_mutagen_symbols,
is_vorbis_like,
)
__all__ = [
"extract_source_metadata",
"embed_source_ids",
]
_MB_RELEASE_CACHE: Dict[tuple, str] = {}
_MB_RELEASE_CACHE_LOCK = threading.RLock()
@ -48,7 +53,7 @@ _EDITION_BARE_RE = re.compile(
)
def _normalize_album_cache_key(album_name: str) -> str:
def normalize_album_cache_key(album_name: str) -> str:
result = _EDITION_PAREN_RE.sub("", album_name or "")
result = _EDITION_BARE_RE.sub("", result)
return result.lower().strip()
@ -58,8 +63,8 @@ def extract_source_metadata(context: dict, artist: dict, album_info: dict) -> di
if album_info is None:
album_info = {}
cfg = _get_config_manager()
logger_ = _get_logger()
cfg = get_config_manager()
logger_ = get_logger()
context = normalize_import_context(context)
original_search = get_import_original_search(context)
album_ctx = get_import_context_album(context)
@ -68,7 +73,7 @@ def extract_source_metadata(context: dict, artist: dict, album_info: dict) -> di
source_ids = get_import_source_ids(context)
artist_dict = artist if isinstance(artist, dict) else {
"name": _extract_artist_name(artist),
"name": extract_artist_name(artist),
"id": getattr(artist, "id", ""),
"genres": list(getattr(artist, "genres", []) or []),
}
@ -135,7 +140,7 @@ def extract_source_metadata(context: dict, artist: dict, album_info: dict) -> di
artist_id = str(artist_dict.get("id", ""))
if source == "itunes" and artist_id.isdigit():
try:
itunes_client = _get_itunes_client()
itunes_client = get_itunes_client()
if itunes_client and hasattr(itunes_client, "resolve_primary_artist"):
resolved = itunes_client.resolve_primary_artist(artist_id)
if resolved and resolved != raw_album_artist:
@ -199,9 +204,9 @@ def extract_source_metadata(context: dict, artist: dict, album_info: dict) -> di
def embed_source_ids(audio_file, metadata: dict, context: dict = None, runtime=None):
cfg = _get_config_manager()
logger_ = _get_logger()
symbols = _get_mutagen_symbols()
cfg = get_config_manager()
logger_ = get_logger()
symbols = get_mutagen_symbols()
if not symbols:
return
@ -323,7 +328,7 @@ def embed_source_ids(audio_file, metadata: dict, context: dict = None, runtime=N
if not isinstance(source_order, list) or not source_order:
source_order = ["musicbrainz", "deezer", "audiodb", "tidal", "qobuz", "lastfm", "genius"]
db = _get_database()
db = get_database()
for source_name in source_order:
if source_name == "musicbrainz":
@ -723,7 +728,7 @@ def embed_source_ids(audio_file, metadata: dict, context: dict = None, runtime=N
key = f"----:com.apple.iTunes:{mp4_tag_map.get(tag_name, tag_name)}"
audio_file[key] = [symbols.MP4FreeForm(str(value).encode("utf-8"))]
written.append(key)
elif _is_vorbis_like(audio_file, symbols):
elif is_vorbis_like(audio_file, symbols):
for tag_name, value in filtered_tags.items():
audio_file[vorbis_tag_map.get(tag_name, tag_name)] = [str(value)]
written.append(vorbis_tag_map.get(tag_name, tag_name))
@ -737,7 +742,7 @@ def embed_source_ids(audio_file, metadata: dict, context: dict = None, runtime=N
metadata["date"] = release_year
if isinstance(audio_file.tags, symbols.ID3):
audio_file.tags.add(symbols.TDRC(encoding=3, text=[release_year]))
elif _is_vorbis_like(audio_file, symbols):
elif is_vorbis_like(audio_file, symbols):
audio_file["date"] = [release_year]
elif isinstance(audio_file, symbols.MP4):
audio_file["\xa9day"] = [release_year]
@ -747,7 +752,7 @@ def embed_source_ids(audio_file, metadata: dict, context: dict = None, runtime=N
bpm_int = int(pp["deezer_bpm"])
if isinstance(audio_file.tags, symbols.ID3):
audio_file.tags.add(symbols.TBPM(encoding=3, text=[str(bpm_int)]))
elif _is_vorbis_like(audio_file, symbols):
elif is_vorbis_like(audio_file, symbols):
audio_file["BPM"] = [str(bpm_int)]
elif isinstance(audio_file, symbols.MP4):
audio_file["tmpo"] = [bpm_int]
@ -756,7 +761,7 @@ def embed_source_ids(audio_file, metadata: dict, context: dict = None, runtime=N
if _tag_enabled("audiodb.tags.mood") and pp["audiodb_mood"]:
if isinstance(audio_file.tags, symbols.ID3):
audio_file.tags.add(symbols.TXXX(encoding=3, desc="MOOD", text=[pp["audiodb_mood"]]))
elif _is_vorbis_like(audio_file, symbols):
elif is_vorbis_like(audio_file, symbols):
audio_file["MOOD"] = [pp["audiodb_mood"]]
elif isinstance(audio_file, symbols.MP4):
audio_file["----:com.apple.iTunes:MOOD"] = [symbols.MP4FreeForm(pp["audiodb_mood"].encode("utf-8"))]
@ -764,7 +769,7 @@ def embed_source_ids(audio_file, metadata: dict, context: dict = None, runtime=N
if _tag_enabled("audiodb.tags.style") and pp["audiodb_style"]:
if isinstance(audio_file.tags, symbols.ID3):
audio_file.tags.add(symbols.TXXX(encoding=3, desc="STYLE", text=[pp["audiodb_style"]]))
elif _is_vorbis_like(audio_file, symbols):
elif is_vorbis_like(audio_file, symbols):
audio_file["STYLE"] = [pp["audiodb_style"]]
elif isinstance(audio_file, symbols.MP4):
audio_file["----:com.apple.iTunes:STYLE"] = [symbols.MP4FreeForm(pp["audiodb_style"].encode("utf-8"))]
@ -795,7 +800,7 @@ def embed_source_ids(audio_file, metadata: dict, context: dict = None, runtime=N
genre_string = ", ".join(merged)
if isinstance(audio_file.tags, symbols.ID3):
audio_file.tags.add(symbols.TCON(encoding=3, text=[genre_string]))
elif _is_vorbis_like(audio_file, symbols):
elif is_vorbis_like(audio_file, symbols):
audio_file["GENRE"] = [genre_string]
elif isinstance(audio_file, symbols.MP4):
audio_file["\xa9gen"] = [genre_string]
@ -814,7 +819,7 @@ def embed_source_ids(audio_file, metadata: dict, context: dict = None, runtime=N
isrc_source, final_isrc = isrc_candidates[0]
if isinstance(audio_file.tags, symbols.ID3):
audio_file.tags.add(symbols.TSRC(encoding=3, text=[final_isrc]))
elif _is_vorbis_like(audio_file, symbols):
elif is_vorbis_like(audio_file, symbols):
audio_file["ISRC"] = [final_isrc]
elif isinstance(audio_file, symbols.MP4):
audio_file["----:com.apple.iTunes:ISRC"] = [symbols.MP4FreeForm(final_isrc.encode("utf-8"))]
@ -829,7 +834,7 @@ def embed_source_ids(audio_file, metadata: dict, context: dict = None, runtime=N
copyright_source, final_copyright = copyright_candidates[0]
if isinstance(audio_file.tags, symbols.ID3):
audio_file.tags.add(symbols.TCOP(encoding=3, text=[final_copyright]))
elif _is_vorbis_like(audio_file, symbols):
elif is_vorbis_like(audio_file, symbols):
audio_file["COPYRIGHT"] = [final_copyright]
elif isinstance(audio_file, symbols.MP4):
audio_file["cprt"] = [final_copyright]
@ -838,7 +843,7 @@ def embed_source_ids(audio_file, metadata: dict, context: dict = None, runtime=N
if _tag_enabled("qobuz.tags.label") and pp["qobuz_label"]:
if isinstance(audio_file.tags, symbols.ID3):
audio_file.tags.add(symbols.TPUB(encoding=3, text=[pp["qobuz_label"]]))
elif _is_vorbis_like(audio_file, symbols):
elif is_vorbis_like(audio_file, symbols):
audio_file["LABEL"] = [pp["qobuz_label"]]
elif isinstance(audio_file, symbols.MP4):
audio_file["----:com.apple.iTunes:LABEL"] = [symbols.MP4FreeForm(pp["qobuz_label"].encode("utf-8"))]
@ -846,7 +851,7 @@ def embed_source_ids(audio_file, metadata: dict, context: dict = None, runtime=N
if _tag_enabled("lastfm.tags.url") and pp["lastfm_url"]:
if isinstance(audio_file.tags, symbols.ID3):
audio_file.tags.add(symbols.TXXX(encoding=3, desc="LASTFM_URL", text=[pp["lastfm_url"]]))
elif _is_vorbis_like(audio_file, symbols):
elif is_vorbis_like(audio_file, symbols):
audio_file["LASTFM_URL"] = [pp["lastfm_url"]]
elif isinstance(audio_file, symbols.MP4):
audio_file["----:com.apple.iTunes:LASTFM_URL"] = [symbols.MP4FreeForm(pp["lastfm_url"].encode("utf-8"))]
@ -854,7 +859,7 @@ def embed_source_ids(audio_file, metadata: dict, context: dict = None, runtime=N
if _tag_enabled("genius.tags.url") and pp["genius_url"]:
if isinstance(audio_file.tags, symbols.ID3):
audio_file.tags.add(symbols.TXXX(encoding=3, desc="GENIUS_URL", text=[pp["genius_url"]]))
elif _is_vorbis_like(audio_file, symbols):
elif is_vorbis_like(audio_file, symbols):
audio_file["GENIUS_URL"] = [pp["genius_url"]]
elif isinstance(audio_file, symbols.MP4):
audio_file["----:com.apple.iTunes:GENIUS_URL"] = [symbols.MP4FreeForm(pp["genius_url"].encode("utf-8"))]

View file

@ -110,8 +110,8 @@ def _fake_symbols(audio):
def test_extract_source_metadata_keeps_neutral_fields_and_skips_itunes_fallback_for_non_itunes_sources(monkeypatch):
monkeypatch.setattr(ms, "_get_config_manager", lambda: _Config({"file_organization.collab_artist_mode": "first"}))
monkeypatch.setattr(ms, "_get_itunes_client", lambda: (_ for _ in ()).throw(AssertionError("itunes fallback should not run for non-itunes sources")))
monkeypatch.setattr(ms, "get_config_manager", lambda: _Config({"file_organization.collab_artist_mode": "first"}))
monkeypatch.setattr(ms, "get_itunes_client", lambda: (_ for _ in ()).throw(AssertionError("itunes fallback should not run for non-itunes sources")))
context = {
"source": "spotify",
@ -160,9 +160,9 @@ def test_extract_source_metadata_keeps_neutral_fields_and_skips_itunes_fallback_
def test_embed_source_ids_uses_current_source_ids_and_legacy_fallback(monkeypatch):
audio = _FakeAudio()
symbols = _fake_symbols(audio)
monkeypatch.setattr(ms, "_get_config_manager", lambda: _Config())
monkeypatch.setattr(ms, "_get_mutagen_symbols", lambda: symbols)
monkeypatch.setattr(ms, "_get_database", lambda: None)
monkeypatch.setattr(ms, "get_config_manager", lambda: _Config())
monkeypatch.setattr(ms, "get_mutagen_symbols", lambda: symbols)
monkeypatch.setattr(ms, "get_database", lambda: None)
current_metadata = {
"source": "deezer",
@ -182,7 +182,7 @@ def test_embed_source_ids_uses_current_source_ids_and_legacy_fallback(monkeypatc
audio = _FakeAudio()
symbols = _fake_symbols(audio)
monkeypatch.setattr(ms, "_get_mutagen_symbols", lambda: symbols)
monkeypatch.setattr(ms, "get_mutagen_symbols", lambda: symbols)
legacy_metadata = {
"source": "",
@ -214,18 +214,18 @@ def test_enhance_file_metadata_writes_tags_and_propagates_release_id(monkeypatch
strip_calls = []
verify_calls = []
monkeypatch.setattr(me, "_get_config_manager", lambda: _Config(
monkeypatch.setattr(me, "get_config_manager", lambda: _Config(
{
"metadata_enhancement.enabled": True,
"metadata_enhancement.embed_album_art": False,
"metadata_enhancement.tags.write_multi_artist": False,
}
))
monkeypatch.setattr(ms, "_get_config_manager", lambda: _Config())
monkeypatch.setattr(me, "_get_mutagen_symbols", lambda: symbols)
monkeypatch.setattr(ms, "_get_mutagen_symbols", lambda: symbols)
monkeypatch.setattr(ms, "_get_database", lambda: None)
monkeypatch.setattr(me, "_strip_all_non_audio_tags", lambda file_path: strip_calls.append(file_path) or {"apev2_stripped": False, "apev2_tag_count": 0})
monkeypatch.setattr(ms, "get_config_manager", lambda: _Config())
monkeypatch.setattr(me, "get_mutagen_symbols", lambda: symbols)
monkeypatch.setattr(ms, "get_mutagen_symbols", lambda: symbols)
monkeypatch.setattr(ms, "get_database", lambda: None)
monkeypatch.setattr(me, "strip_all_non_audio_tags", lambda file_path: strip_calls.append(file_path) or {"apev2_stripped": False, "apev2_tag_count": 0})
monkeypatch.setattr(
me,
"extract_source_metadata",
@ -247,7 +247,7 @@ def test_enhance_file_metadata_writes_tags_and_propagates_release_id(monkeypatch
},
)
monkeypatch.setattr(me, "embed_album_art_metadata", lambda *args, **kwargs: None)
monkeypatch.setattr(me, "_verify_metadata_written", lambda file_path: verify_calls.append(file_path) or True)
monkeypatch.setattr(me, "verify_metadata_written", lambda file_path: verify_calls.append(file_path) or True)
album_info = {}
result = me.enhance_file_metadata(
@ -269,7 +269,7 @@ def test_enhance_file_metadata_writes_tags_and_propagates_release_id(monkeypatch
def test_download_cover_art_uses_album_context_image_url(tmp_path, monkeypatch):
monkeypatch.setattr(ma, "_get_config_manager", lambda: _Config(
monkeypatch.setattr(ma, "get_config_manager", lambda: _Config(
{
"metadata_enhancement.cover_art_download": True,
"metadata_enhancement.prefer_caa_art": False,
@ -281,7 +281,7 @@ def test_download_cover_art_uses_album_context_image_url(tmp_path, monkeypatch):
target_dir = tmp_path / "Album One"
target_dir.mkdir()
me.download_cover_art(
ma.download_cover_art(
{},
str(target_dir),
{"album": {"image_url": "https://img.example/album.jpg"}},