Recursive album discovery + Jellyfin Playlist Generator integration

scanner.py: collect_album_dirs() now recursively finds album dirs
- Dirs with audio files at root → album
- Dirs with disc subdirs (CD1/CD2) and no root audio → multi-CD album
- Container dirs without audio → recurse into subdirs

music_enricher.py:
- After execute_album(), auto-discovers jellyfin_playlist_generator.py
  in ../Jellyfin_Playlist_Generator/ (or via --playlist-generator PATH)
- Calls generate_playlist() directly via importlib — no subprocess,
  no destructive cleanup_all_playlists, targeted to the enriched album
- New --playlist-generator CLI option for custom generator path

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-04-29 07:07:55 +02:00
commit 776c977573
2 changed files with 96 additions and 8 deletions

View file

@ -89,11 +89,49 @@ def _scan_dir(current: Path, album_dir: Path, result: AlbumScan, recurse: bool)
def collect_album_dirs(root: Path) -> List[Path]:
dirs: List[Path] = []
"""
Findet rekursiv alle Album-Verzeichnisse unterhalb von root.
Ein Verzeichnis gilt als Album wenn:
- es direkt Audio-Dateien enthält, ODER
- es keine direkten Audio-Dateien hat aber Disc-Unterordner mit Audio (Multi-CD).
Container-Verzeichnisse ohne Audio werden rekursiv durchsucht.
"""
result: List[Path] = []
_find_albums(root, result)
return result
def _has_local_audio(path: Path) -> bool:
try:
for item in sorted(root.iterdir()):
if item.is_dir() and not _is_hidden(item.name):
dirs.append(item)
return any(
e.suffix.lower() in AUDIO_EXTENSIONS
for e in path.iterdir()
if e.is_file() and not _is_hidden(e.name)
)
except (PermissionError, OSError):
return False
def _find_albums(current: Path, result: List[Path]) -> None:
try:
entries = sorted(current.iterdir())
subdirs = [e for e in entries if e.is_dir() and not _is_hidden(e.name)]
except (PermissionError, OSError) as e:
print(f"⚠️ Lesefehler {root}: {e}", file=sys.stderr)
return dirs
print(f"⚠️ Lesefehler {current}: {e}", file=sys.stderr)
return
# Verzeichnis enthält direkt Audio → Album
if any(e.is_file() and not _is_hidden(e.name) and e.suffix.lower() in AUDIO_EXTENSIONS
for e in entries):
result.append(current)
return
# Disc-Unterordner mit Audio → Multi-CD-Album (scan_album übernimmt die Disc-Logik)
disc_dirs = [d for d in subdirs if _is_disc_dir(d.name)]
if disc_dirs and any(_has_local_audio(d) for d in disc_dirs):
result.append(current)
return
# Container-Verzeichnis → rekursiv weiter suchen
for subdir in subdirs:
_find_albums(subdir, result)