ae1dd7481d
resolve conflicts
84 lines
2.8 KiB
Python
84 lines
2.8 KiB
Python
"""
|
|
Author: Uyanide pywang0608@foxmail.com
|
|
Date: 2026-03-31 06:08:44
|
|
Description: Enricher that parses metadata from the audio file path
|
|
"""
|
|
|
|
import re
|
|
from typing import Optional
|
|
from loguru import logger
|
|
|
|
from .base import BaseEnricher
|
|
from ..models import TrackMeta
|
|
from ..lrc import get_audio_path
|
|
|
|
|
|
# Common track-number prefixes: "01 - ", "01. ", "1 - ", etc.
|
|
_TRACK_NUM_RE = re.compile(r"^\d{1,3}[\s.\-]+")
|
|
|
|
|
|
class FileNameEnricher(BaseEnricher):
|
|
"""Derive artist / title from the file path when tags are unavailable.
|
|
|
|
Heuristics (applied to the stem of the filename):
|
|
- "Artist - Title" → artist, title
|
|
- "01 - Title" → title only (leading track number stripped)
|
|
- "Title" → title only
|
|
|
|
If artist is still missing after parsing the filename, the parent
|
|
directory name is used as a guess (common layout: ``Artist/Album/track``).
|
|
"""
|
|
|
|
@property
|
|
def name(self) -> str:
|
|
return "file-name"
|
|
|
|
def enrich(self, track: TrackMeta) -> Optional[dict]:
|
|
if not track.is_local or not track.url:
|
|
return None
|
|
|
|
audio_path = get_audio_path(track.url, ensure_exists=False)
|
|
if not audio_path:
|
|
return None
|
|
|
|
updates: dict = {}
|
|
stem = audio_path.stem
|
|
|
|
# Try "Artist - Title" split
|
|
if " - " in stem:
|
|
left, right = stem.split(" - ", 1)
|
|
left = _TRACK_NUM_RE.sub("", left).strip()
|
|
right = right.strip()
|
|
|
|
if left and right:
|
|
# Both sides non-empty after stripping track number
|
|
if not track.artist:
|
|
updates["artist"] = left
|
|
if not track.title:
|
|
updates["title"] = right
|
|
elif right:
|
|
# Left was only a track number → right is the title
|
|
if not track.title:
|
|
updates["title"] = right
|
|
else:
|
|
# No separator: strip track number, remainder is title
|
|
title_guess = _TRACK_NUM_RE.sub("", stem).strip()
|
|
if title_guess and not track.title:
|
|
updates["title"] = title_guess
|
|
|
|
# Use parent directory as artist fallback
|
|
# Typical layout: /Music/Artist/Album/01 - Track.flac
|
|
if not track.artist and "artist" not in updates:
|
|
parents = audio_path.parents
|
|
if len(parents) >= 2:
|
|
album_dir = parents[0].name
|
|
artist_dir = parents[1].name
|
|
if artist_dir and artist_dir not in (".", "/"):
|
|
updates["artist"] = artist_dir
|
|
if not track.album and album_dir and album_dir != artist_dir:
|
|
updates["album"] = album_dir
|
|
|
|
if updates:
|
|
logger.debug(f"FileName: enriched fields: {list(updates.keys())}")
|
|
return updates or None
|