Media-Previews: _preview.jpg bei Upload, alle Listenansichten — SW by-v437, APP_VER 416
- media_utils: generate_preview() (Pillow, max 800px, JPEG q72) + preview_url_from() - diary.py: Preview beim Bild-Upload, preview_url in media_items + cover_preview_url in Kalender-, Karten- und Listenabfragen - forum.py: Preview in _save_upload(), foto_preview_url in Thread-Listen - Frontend diary.js: cover_preview_url in Listenansicht, Mediengalerie, Kalender, Karten-Marker + Popup; onerror-Fallback auf Original - Frontend forum.js: foto_preview_url in Thread-Karten-Thumbnails - Admin: 'Previews generieren (Bestand)' Button → POST /admin/media/generate-previews
This commit is contained in:
parent
faf433f4cf
commit
5bd07d9598
9 changed files with 145 additions and 17 deletions
|
|
@ -157,6 +157,41 @@ def convert_media(data: bytes, filename: str) -> Tuple[bytes, str]:
|
|||
return data, ext or ".bin"
|
||||
|
||||
|
||||
_PREVIEW_EXTS = {".jpg", ".jpeg", ".png", ".webp", ".gif", ".heic", ".heif"}
|
||||
_PREVIEW_MAX = 800 # längste Seite in Pixeln
|
||||
|
||||
|
||||
def generate_preview(data: bytes, ext: str) -> bytes | None:
|
||||
"""Erzeugt ein JPEG-Preview (max _PREVIEW_MAX px). Gibt None zurück bei Videos/PDFs/Fehler."""
|
||||
if ext.lower() not in _PREVIEW_EXTS:
|
||||
return None
|
||||
try:
|
||||
from PIL import Image, ImageOps
|
||||
img = Image.open(io.BytesIO(data))
|
||||
img = ImageOps.exif_transpose(img)
|
||||
img = img.convert("RGB")
|
||||
img.thumbnail((_PREVIEW_MAX, _PREVIEW_MAX), Image.LANCZOS)
|
||||
buf = io.BytesIO()
|
||||
img.save(buf, format="JPEG", quality=72, optimize=True)
|
||||
return buf.getvalue()
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def preview_url_from(url: str | None) -> str | None:
|
||||
"""Leitet die Preview-URL aus der Original-URL ab (fügt _preview vor Extension ein).
|
||||
Gibt None für Videos, PDFs, bereits generierte Previews und leere URLs zurück."""
|
||||
if not url:
|
||||
return None
|
||||
low = url.lower()
|
||||
if any(low.endswith(s) for s in (
|
||||
".mp4", ".webm", ".mov", ".avi", ".pdf", "_thumb.jpg", "_preview.jpg"
|
||||
)):
|
||||
return None
|
||||
base, _ = os.path.splitext(url)
|
||||
return base + "_preview.jpg"
|
||||
|
||||
|
||||
def extract_video_thumb(video_path: str) -> str | None:
|
||||
"""Extract a frame at ~1s from video_path and save as <basename>_thumb.jpg.
|
||||
Returns the thumb path on success, None on failure."""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue