From f86db982a59bd0fdc3c6aeed07dd12e655dfc6e9 Mon Sep 17 00:00:00 2001 From: dschlueter Date: Wed, 29 Apr 2026 05:50:46 +0200 Subject: [PATCH] Support WebP cover images: convert to JPEG via PIL, correct MIME type fallback Co-Authored-By: Claude Sonnet 4.6 --- cover_handler.py | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) mode change 100644 => 100755 cover_handler.py diff --git a/cover_handler.py b/cover_handler.py old mode 100644 new mode 100755 index 221c772..2b65187 --- a/cover_handler.py +++ b/cover_handler.py @@ -97,12 +97,38 @@ def download_cover(release_mbid: Optional[str], dest_dir: Path) -> Optional[Path return None +def _load_cover_data(cover_path: Path) -> tuple[bytes, str]: + """ + Liest Cover-Bilddaten und gibt (bytes, mime_type) zurück. + WebP wird zu JPEG konvertiert wenn PIL verfügbar (bessere Player-Kompatibilität). + """ + suffix = cover_path.suffix.lower() + if suffix in (".jpg", ".jpeg"): + return cover_path.read_bytes(), "image/jpeg" + if suffix == ".webp" and HAS_PIL: + try: + with Image.open(cover_path) as img: + img = img.convert("RGB") + buf = tempfile.SpooledTemporaryFile(max_size=10 * 1024 * 1024) + img.save(buf, format="JPEG", quality=90) + buf.seek(0) + return buf.read(), "image/jpeg" + except Exception as e: + print(f" ⚠️ WebP→JPEG-Konvertierung fehlgeschlagen ({cover_path.name}): {e}", + file=sys.stderr) + if suffix == ".webp": + return cover_path.read_bytes(), "image/webp" + if suffix == ".png": + return cover_path.read_bytes(), "image/png" + # Fallback: raw bytes, JPEG assumed + return cover_path.read_bytes(), "image/jpeg" + + def embed_cover(audio_path: Path, cover_path: Path) -> bool: if not HAS_MUTAGEN: return False try: - img_data = cover_path.read_bytes() - mime = "image/jpeg" if cover_path.suffix.lower() in (".jpg", ".jpeg") else "image/png" + img_data, mime = _load_cover_data(cover_path) ext = audio_path.suffix.lower() if ext == ".mp3": @@ -130,6 +156,7 @@ def embed_cover(audio_path: Path, cover_path: Path) -> bool: elif ext == ".m4a": audio = MP4(str(audio_path)) fmt = MP4Cover.FORMAT_JPEG if mime == "image/jpeg" else MP4Cover.FORMAT_PNG + # WebP wurde bereits zu JPEG konvertiert, mime ist dann "image/jpeg" audio.tags["covr"] = [MP4Cover(img_data, imageformat=fmt)] audio.save() return True