diff --git a/src/musiksammlung/tagger.py b/src/musiksammlung/tagger.py index 4900381..c4f6744 100644 --- a/src/musiksammlung/tagger.py +++ b/src/musiksammlung/tagger.py @@ -2,12 +2,14 @@ from __future__ import annotations +import io import logging from pathlib import Path from mutagen import File as MutagenFile from mutagen.flac import FLAC, Picture from mutagen.id3 import APIC, ID3 +from PIL import Image from musiksammlung.models import Album, Disc, Track @@ -75,11 +77,31 @@ def embed_album_cover(album: Album, album_dir: Path, cover_path: Path) -> None: embed_cover(audio_file, cover_path) -def embed_cover(audio_path: Path, cover_path: Path) -> None: - """Bettet ein Cover-Bild in eine Audiodatei ein.""" - cover_data = cover_path.read_bytes() - mime = "image/jpeg" if cover_path.suffix.lower() in (".jpg", ".jpeg") else "image/png" +# Maximale Auflösung für eingebettete Cover (längste Seite in Pixeln). +# Kleiner als das gespeicherte Originalbild (1200 px), aber auf HiDPI-Displays +# noch scharf genug. Typische Dateigröße: 40–100 KB statt 200–500 KB. +EMBED_COVER_MAX_SIZE = 500 + +def _scale_cover_for_embed(cover_path: Path, max_size: int) -> tuple[bytes, str]: + """Skaliert ein Coverbild für das Einbetten und gibt (bytes, mime) zurück.""" + img = Image.open(cover_path) + if max(img.size) > max_size: + img.thumbnail((max_size, max_size), Image.LANCZOS) + if img.mode in ("RGBA", "P"): + img = img.convert("RGB") + buf = io.BytesIO() + img.save(buf, "JPEG", quality=85) + return buf.getvalue(), "image/jpeg" + + +def embed_cover(audio_path: Path, cover_path: Path) -> None: + """Bettet ein Cover-Bild in eine Audiodatei ein. + + Das Bild wird auf EMBED_COVER_MAX_SIZE herunterskaliert, damit die + eingebetteten Cover die Audiodateigröße nicht wesentlich vergrößern. + """ + cover_data, mime = _scale_cover_for_embed(cover_path, EMBED_COVER_MAX_SIZE) suffix = audio_path.suffix.lower() if suffix == ".flac":