Add --status flag: library health report (missing covers, bad tags)
Scans all album directories and reports: - Albums without any cover image - Albums where the first 3 audio files have missing/placeholder tags (title or artist empty, 'Unknown', 'AudioTrack') Exits without writing anything. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d06c0bbcc9
commit
b54d83ecb5
1 changed files with 73 additions and 0 deletions
|
|
@ -228,6 +228,71 @@ def process_album(
|
||||||
return stats
|
return stats
|
||||||
|
|
||||||
|
|
||||||
|
def _print_status(args: argparse.Namespace) -> None:
|
||||||
|
"""Scannt die Bibliothek und zeigt Alben mit fehlenden/schlechten Metadaten."""
|
||||||
|
from mutagen import File as MutagenFile
|
||||||
|
|
||||||
|
IMAGE_EXTS = {".jpg", ".jpeg", ".png", ".webp"}
|
||||||
|
AUDIO_EXTS = {".mp3", ".flac", ".m4a", ".wav", ".ogg", ".opus"}
|
||||||
|
|
||||||
|
album_dirs: List[Path] = []
|
||||||
|
if args.album:
|
||||||
|
album_dirs.append(args.album.expanduser().resolve())
|
||||||
|
for raw in args.paths:
|
||||||
|
root = Path(raw).expanduser().resolve()
|
||||||
|
if root.is_dir():
|
||||||
|
album_dirs.extend(collect_album_dirs(root))
|
||||||
|
|
||||||
|
no_cover, bad_tags, ok = [], [], []
|
||||||
|
|
||||||
|
for album_dir in sorted(album_dirs):
|
||||||
|
has_cover = any(
|
||||||
|
f.suffix.lower() in IMAGE_EXTS
|
||||||
|
for f in album_dir.rglob("*") if f.is_file()
|
||||||
|
)
|
||||||
|
audio_files = [
|
||||||
|
f for f in sorted(album_dir.rglob("*"))
|
||||||
|
if f.is_file() and f.suffix.lower() in AUDIO_EXTS
|
||||||
|
]
|
||||||
|
missing_tags = []
|
||||||
|
for af in audio_files[:3]: # nur erste 3 prüfen (schnell)
|
||||||
|
try:
|
||||||
|
tags = MutagenFile(str(af), easy=True)
|
||||||
|
if tags is None:
|
||||||
|
missing_tags.append(af.name)
|
||||||
|
continue
|
||||||
|
title = (tags.get("title") or [""])[0].strip()
|
||||||
|
artist = (tags.get("artist") or [""])[0].strip()
|
||||||
|
if not title or title.lower() in ("unknown", "audiotrack", "") \
|
||||||
|
or not artist or artist.lower() in ("unknown", ""):
|
||||||
|
missing_tags.append(af.name)
|
||||||
|
except Exception:
|
||||||
|
missing_tags.append(af.name)
|
||||||
|
|
||||||
|
problems = []
|
||||||
|
if not has_cover:
|
||||||
|
problems.append("kein Cover")
|
||||||
|
if missing_tags:
|
||||||
|
problems.append(f"schlechte Tags ({len(missing_tags)}/{min(3,len(audio_files))} geprüft)")
|
||||||
|
|
||||||
|
if problems:
|
||||||
|
bad_tags.append((album_dir, problems))
|
||||||
|
else:
|
||||||
|
ok.append(album_dir)
|
||||||
|
|
||||||
|
print(f"\n{'=' * 60}")
|
||||||
|
print(f"📊 Bibliotheksstatus — {len(album_dirs)} Alben")
|
||||||
|
print(f"{'=' * 60}")
|
||||||
|
print(f" ✅ In Ordnung: {len(ok)}")
|
||||||
|
print(f" ⚠️ Mit Problemen: {len(bad_tags)}")
|
||||||
|
print()
|
||||||
|
for album_dir, problems in bad_tags:
|
||||||
|
print(f" 💿 {album_dir.name}")
|
||||||
|
for p in problems:
|
||||||
|
print(f" → {p}")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description="KI-gestützter Musik-Metadaten-Enricher für Jellyfin",
|
description="KI-gestützter Musik-Metadaten-Enricher für Jellyfin",
|
||||||
|
|
@ -262,9 +327,17 @@ def main() -> None:
|
||||||
parser.add_argument("--playlist-generator", type=Path, dest="playlist_generator",
|
parser.add_argument("--playlist-generator", type=Path, dest="playlist_generator",
|
||||||
help="Pfad zu jellyfin_playlist_generator.py\n"
|
help="Pfad zu jellyfin_playlist_generator.py\n"
|
||||||
"(Standard: ../Jellyfin_Playlist_Generator/jellyfin_playlist_generator.py)")
|
"(Standard: ../Jellyfin_Playlist_Generator/jellyfin_playlist_generator.py)")
|
||||||
|
parser.add_argument("--status", action="store_true",
|
||||||
|
help="Bibliotheksstatus anzeigen (fehlende Cover, schlechte Tags) — nichts schreiben")
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.status:
|
||||||
|
if not args.paths and not args.album:
|
||||||
|
parser.error("--status benötigt mindestens einen Pfad.")
|
||||||
|
_print_status(args)
|
||||||
|
return
|
||||||
|
|
||||||
if not args.album and not args.paths:
|
if not args.album and not args.paths:
|
||||||
parser.error("Mindestens ein Pfad oder --album erforderlich.")
|
parser.error("Mindestens ein Pfad oder --album erforderlich.")
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue