import subprocess from pathlib import Path from PIL import Image from app.config import THUMBNAIL_DIR THUMB_SIZE = (400, 400) def thumbnail_path(media_id: int) -> Path: return THUMBNAIL_DIR / f"{media_id}.jpg" def generate_image_thumbnail(src: Path, dest: Path) -> None: with Image.open(src) as img: img.thumbnail(THUMB_SIZE) img = img.convert("RGB") img.save(dest, "JPEG", quality=85) def generate_video_thumbnail(src: Path, dest: Path) -> None: # Extract frame at 10% of duration subprocess.run( [ "ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", str(src), ], capture_output=True, text=True, check=False, ) subprocess.run( [ "ffmpeg", "-y", "-ss", "00:00:05", "-i", str(src), "-vframes", "1", "-vf", f"scale={THUMB_SIZE[0]}:-1", str(dest), ], capture_output=True, check=False, ) def get_or_create_thumbnail(media_id: int, abs_path: str, media_type: str) -> Path | None: dest = thumbnail_path(media_id) if dest.exists(): return dest src = Path(abs_path) if not src.exists(): return None try: if media_type == "image": generate_image_thumbnail(src, dest) else: generate_video_thumbnail(src, dest) return dest if dest.exists() else None except Exception: return None