From 256be0ae33ff3c3b2cf0e1ff0affbc0f9d7615e7 Mon Sep 17 00:00:00 2001 From: dschlueter Date: Wed, 18 Feb 2026 00:40:11 +0100 Subject: [PATCH] =?UTF-8?q?Cover-Embedding:=20Aufl=C3=B6sung=20auf=20500px?= =?UTF-8?q?=20reduzieren=20vor=20dem=20Einbetten?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Neue Hilfsfunktion _scale_cover_for_embed() skaliert das Coverbild mit Pillow auf max. 500px (EMBED_COVER_MAX_SIZE) und kodiert es als JPEG quality=85 in-memory. embed_cover() liest nicht mehr die rohen Bytes der Originaldatei, sondern nutzt das skalierte Bild. Ergebnis: eingebettete Cover ~40–100 KB statt 200–500 KB des 1200px-Originals, auf HiDPI-Displays noch scharf erkennbar. Co-Authored-By: Claude Sonnet 4.5 --- src/musiksammlung/tagger.py | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) 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":