"""Fetch landing-page photos (one-time + re-runnable). Downloads royalty-free originals (see SOURCES.md next to the photos), resizes to max 1600px wide and stores them as WebP q80 in frontend/public/photos/ (self-hosted: no hotlinking, no tracking). Run in the api container (has network + Pillow): docker compose exec api /opt/venv/bin/python \\ /srv/kirche-einfach/frontend/scripts/fetch-photos.py """ from __future__ import annotations import sys import urllib.request from io import BytesIO from pathlib import Path try: from PIL import Image except ImportError: sys.exit("Pillow required (present in the api image)") ROOT = Path(__file__).resolve().parent.parent.parent OUT = ROOT / "frontend" / "public" / "photos" def pexels(photo_id: int) -> str: return ( f"https://images.pexels.com/photos/{photo_id}/" f"pexels-photo-{photo_id}.jpeg?auto=compress&cs=tinysrgb&w=1600" ) PHOTOS = { # target file -> (direct file URL, source page for SOURCES.md) "hero-church.webp": ( pexels(31630127), "https://www.pexels.com/photo/historic-church-with-bell-tower-in-germany-31630127/", ), "church-pews.webp": ( pexels(7566207), "https://www.pexels.com/photo/church-pews-7566207/", ), "paperwork-desk.webp": ( pexels(18687845), "https://www.pexels.com/photo/desk-with-documents-and-stamps-18687845/", ), "team-laptop.webp": ( pexels(7793702), "https://www.pexels.com/photo/a-team-looking-at-a-laptop-7793702/", ), "pilot-meeting.webp": ( pexels(5668858), "https://www.pexels.com/photo/two-people-shaking-hands-5668858/", ), } def fetch(url: str) -> bytes: req = urllib.request.Request(url, headers={"User-Agent": "kirche-einfach/1.0"}) with urllib.request.urlopen(req, timeout=120) as response: return response.read() def main() -> None: OUT.mkdir(parents=True, exist_ok=True) for filename, (url, _page) in PHOTOS.items(): raw = fetch(url) with Image.open(BytesIO(raw)) as img: img = img.convert("RGB") if img.width > 1600: img = img.resize( (1600, round(img.height * 1600 / img.width)), Image.LANCZOS ) target = OUT / Path(filename).with_suffix(".webp").name img.save(target, "WEBP", quality=80, method=6) print(f"wrote {target} ({target.stat().st_size // 1024} KB)") if __name__ == "__main__": main()