From d06c0bbcc9a83eb93e7523127d99f43c330cf7b3 Mon Sep 17 00:00:00 2001 From: dschlueter Date: Wed, 29 Apr 2026 08:41:43 +0200 Subject: [PATCH] Normalize all cover art to folder.jpg (Jellyfin standard) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add normalize_cover_to_folder_jpg(): renames/converts any local cover (Front.jpg, front.webp, cover.jpg, …) to folder.jpg in-place; WebP/PNG are converted to JPEG via PIL - resolve_cover() now calls normalize_cover_to_folder_jpg() automatically after finding a local cover, so future enrichment runs always produce folder.jpg - One-time batch: 38 existing library covers renamed/converted to folder.jpg Co-Authored-By: Claude Sonnet 4.6 --- cover_handler.py | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/cover_handler.py b/cover_handler.py index 4debeae..1a10322 100755 --- a/cover_handler.py +++ b/cover_handler.py @@ -48,7 +48,6 @@ def _image_ok(path: Path) -> bool: def find_local_cover(image_files: List[Path]) -> Optional[Path]: priority = ("folder", "front", "cover", "album") - # Sort by priority keyword, then size descending def key(p: Path): name = p.name.lower() score = next((i for i, kw in enumerate(priority) if kw in name), len(priority)) @@ -61,6 +60,41 @@ def find_local_cover(image_files: List[Path]) -> Optional[Path]: return None +def normalize_cover_to_folder_jpg(cover_path: Path) -> Path: + """ + Stellt sicher dass das Cover als folder.jpg (JPEG) im Album-Verzeichnis liegt. + - Ist es bereits folder.jpg → unverändert zurückgeben. + - Ist es eine andere JPEG → umbenennen. + - Ist es WebP oder PNG → zu JPEG konvertieren, Original löschen. + Gibt den Pfad zur folder.jpg zurück. + """ + dest = cover_path.parent / "folder.jpg" + if cover_path.resolve() == dest.resolve(): + return dest + + suffix = cover_path.suffix.lower() + try: + if suffix in (".jpg", ".jpeg"): + cover_path.rename(dest) + elif HAS_PIL: + import io + with cover_path.open("rb") as f: + raw = f.read() + with Image.open(io.BytesIO(raw)) as img: + buf = io.BytesIO() + img.convert("RGB").save(buf, format="JPEG", quality=92) + dest.write_bytes(buf.getvalue()) + cover_path.unlink() + else: + # PIL nicht verfügbar: einfach umbenennen, auch wenn es kein JPEG ist + cover_path.rename(dest) + print(f" 🖼️ Cover normalisiert → folder.jpg ({cover_path.name})") + except Exception as e: + print(f" ⚠️ Cover-Normalisierung fehlgeschlagen: {e}", file=sys.stderr) + return cover_path + return dest + + def _mb_cover_url(release_mbid: str) -> Optional[str]: url = f"https://coverartarchive.org/release/{release_mbid}/front" if not HAS_REQUESTS: @@ -195,6 +229,7 @@ def resolve_cover( """Returns (cover_path, source_label).""" local = find_local_cover(image_files) if local: + local = normalize_cover_to_folder_jpg(local) return local, "local" if release_mbid: