Improve album grouping and normalize suffixes
Expand track title normalization and refine album grouping logic. - core/acoustid_verification.py: Broadened the parenthetical-suffix regex to strip year-based remasters and additional variants (e.g. "2025 Remaster", "single edit", "album edit") while still removing common extras like (Live), (Deluxe), (Radio Edit), and featuring tags. - web_server.py: Restrict the smart album grouping to only run for singles/auto-detected albums; explicit album downloads now preserve the original Spotify album name to avoid mangling names (e.g. reworked/remastered vs deluxe). Added explicit logging for both smart grouping and skipped grouping paths. The verification post-processing worker now checks an is_album_download flag in context and skips re-grouping when true, with fallback logging on errors. These changes prevent unintended renaming of explicit album downloads and improve normalization of common title suffixes.
This commit is contained in:
parent
4bff57cb70
commit
a0828c7aad
2 changed files with 30 additions and 23 deletions
|
|
@ -38,8 +38,8 @@ def _normalize(text: str) -> str:
|
|||
if not text:
|
||||
return ""
|
||||
s = text.lower().strip()
|
||||
# Remove common parenthetical suffixes like (Live), (Remastered), (Radio Edit)
|
||||
s = re.sub(r'\s*\((?:live|remaster(?:ed)?|deluxe|bonus|radio\s*edit|single\s*version|visualize.*?)\)', '', s, flags=re.IGNORECASE)
|
||||
# Remove common parenthetical suffixes like (Live), (Remastered), (2025 Remaster), (Radio Edit)
|
||||
s = re.sub(r'\s*\((?:live|(?:\d{4}\s*)?remaster(?:ed)?(?:\s*\d{4})?|deluxe|bonus|radio\s*edit|single\s*edit|album\s*edit|single\s*version|visualize.*?)\)', '', s, flags=re.IGNORECASE)
|
||||
# Remove featuring info: "(feat. ...)", "(ft. ...)", "(featuring ...)"
|
||||
s = re.sub(r'\s*\((?:feat\.?|ft\.?|featuring)\s+[^)]*\)', '', s, flags=re.IGNORECASE)
|
||||
# Remove trailing featuring info: "feat. ...", "ft. ...", "featuring ..."
|
||||
|
|
|
|||
|
|
@ -10410,23 +10410,28 @@ def _post_process_matched_download(context_key, context, file_path):
|
|||
print("🎵 Single track download - attempting album detection")
|
||||
album_info = _detect_album_info_web(context, spotify_artist)
|
||||
|
||||
# --- CRITICAL FIX: Add GUI album grouping resolution ---
|
||||
# This ensures consistent album naming across tracks like the GUI
|
||||
if album_info and album_info['is_album']:
|
||||
# --- Album grouping resolution ---
|
||||
# Only run smart grouping for singles/auto-detected albums.
|
||||
# Explicit album downloads already have the correct Spotify album name —
|
||||
# re-grouping would mangle names like "(Reworked and Remastered)" into "(Deluxe Edition)".
|
||||
if album_info and album_info['is_album'] and not is_album_download:
|
||||
print(f"\n🎯 SMART ALBUM GROUPING for track: '{album_info.get('clean_track_name', 'Unknown')}'")
|
||||
print(f" Original album: '{album_info.get('album_name', 'None')}'")
|
||||
|
||||
|
||||
# Get original album name from context if available
|
||||
original_album = None
|
||||
if context.get("original_search_result", {}).get("album"):
|
||||
original_album = context["original_search_result"]["album"]
|
||||
|
||||
|
||||
# Use the GUI's smart album grouping algorithm
|
||||
consistent_album_name = _resolve_album_group(spotify_artist, album_info, original_album)
|
||||
album_info['album_name'] = consistent_album_name
|
||||
|
||||
|
||||
print(f" Final album name: '{consistent_album_name}'")
|
||||
print(f"🔗 ✅ Album grouping complete!\n")
|
||||
elif album_info and album_info['is_album'] and is_album_download:
|
||||
print(f"\n🎯 EXPLICIT ALBUM DOWNLOAD - preserving Spotify album name: '{album_info.get('album_name', 'None')}'")
|
||||
print(f" Skipping smart grouping (not needed for explicit album downloads)\n")
|
||||
|
||||
# 1. Get transfer path and create artist directory
|
||||
transfer_dir = docker_resolve_path(config_manager.get('soulseek.transfer_path', './Transfer'))
|
||||
|
|
@ -14997,21 +15002,23 @@ def _run_post_processing_worker(task_id, batch_id):
|
|||
}
|
||||
|
||||
# Apply album grouping for consistency with stream processor path.
|
||||
# Without this, the verification worker could write a different album
|
||||
# name than the stream processor (e.g. raw API name vs resolved name),
|
||||
# causing media servers to split tracks into separate albums.
|
||||
try:
|
||||
raw_album_ctx = original_search.get('album')
|
||||
if isinstance(raw_album_ctx, str):
|
||||
original_album_ctx = raw_album_ctx
|
||||
elif isinstance(raw_album_ctx, dict) and 'name' in raw_album_ctx:
|
||||
original_album_ctx = raw_album_ctx['name']
|
||||
else:
|
||||
original_album_ctx = None
|
||||
consistent_album_name = _resolve_album_group(spotify_artist, album_info, original_album_ctx)
|
||||
album_info['album_name'] = consistent_album_name
|
||||
except Exception as group_err:
|
||||
print(f"⚠️ [Verification] Album grouping failed, using raw name: {group_err}")
|
||||
# Only for singles/auto-detected — explicit album downloads already
|
||||
# have the correct Spotify name and re-grouping would mangle it.
|
||||
if not context.get("is_album_download", False):
|
||||
try:
|
||||
raw_album_ctx = original_search.get('album')
|
||||
if isinstance(raw_album_ctx, str):
|
||||
original_album_ctx = raw_album_ctx
|
||||
elif isinstance(raw_album_ctx, dict) and 'name' in raw_album_ctx:
|
||||
original_album_ctx = raw_album_ctx['name']
|
||||
else:
|
||||
original_album_ctx = None
|
||||
consistent_album_name = _resolve_album_group(spotify_artist, album_info, original_album_ctx)
|
||||
album_info['album_name'] = consistent_album_name
|
||||
except Exception as group_err:
|
||||
print(f"⚠️ [Verification] Album grouping failed, using raw name: {group_err}")
|
||||
else:
|
||||
print(f"🎯 [Verification] Explicit album download - preserving Spotify album name: '{album_info['album_name']}'")
|
||||
|
||||
print(f"🎯 [Verification] Created proper album_info - track_number: {track_number}, album: {album_info['album_name']}")
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue