Support WebP cover images: convert to JPEG via PIL, correct MIME type fallback

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-04-29 05:50:46 +02:00
commit f86db982a5

31
cover_handler.py Normal file → Executable file
View file

@ -97,12 +97,38 @@ def download_cover(release_mbid: Optional[str], dest_dir: Path) -> Optional[Path
return None 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: def embed_cover(audio_path: Path, cover_path: Path) -> bool:
if not HAS_MUTAGEN: if not HAS_MUTAGEN:
return False return False
try: try:
img_data = cover_path.read_bytes() img_data, mime = _load_cover_data(cover_path)
mime = "image/jpeg" if cover_path.suffix.lower() in (".jpg", ".jpeg") else "image/png"
ext = audio_path.suffix.lower() ext = audio_path.suffix.lower()
if ext == ".mp3": if ext == ".mp3":
@ -130,6 +156,7 @@ def embed_cover(audio_path: Path, cover_path: Path) -> bool:
elif ext == ".m4a": elif ext == ".m4a":
audio = MP4(str(audio_path)) audio = MP4(str(audio_path))
fmt = MP4Cover.FORMAT_JPEG if mime == "image/jpeg" else MP4Cover.FORMAT_PNG 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.tags["covr"] = [MP4Cover(img_data, imageformat=fmt)]
audio.save() audio.save()
return True return True