Quellen-Seite: PDF-Thumbnails der ersten Seite + Thumbnail-API-Endpoint

This commit is contained in:
Dotty Dotter 2026-04-10 18:40:13 +02:00
parent 11e4da0bf3
commit ee08cb0c29
2 changed files with 50 additions and 5 deletions

View File

@ -875,6 +875,37 @@ neu analysiert, um verifizierte Zitate zu erzeugen.</p>
) )
@app.get("/api/programme/thumbnail/{programm_id}")
async def programme_thumbnail(programm_id: str):
"""Thumbnail der ersten Seite eines Wahlprogramm-PDFs (PNG, 200px breit).
Wird auf der Quellen-Seite als Vorschau angezeigt. Cached 24h.
"""
import fitz
if programm_id not in PROGRAMME:
raise HTTPException(status_code=404)
info = PROGRAMME[programm_id]
pdf_path = static_dir / "referenzen" / info["pdf"]
if not pdf_path.exists():
raise HTTPException(status_code=404)
try:
doc = fitz.open(str(pdf_path))
page = doc[0]
# 200px Breite, proportional skaliert
zoom = 200 / page.rect.width
mat = fitz.Matrix(zoom, zoom)
pix = page.get_pixmap(matrix=mat)
png_bytes = pix.tobytes("png")
doc.close()
return Response(
content=png_bytes,
media_type="image/png",
headers={"Cache-Control": "public, max-age=86400"},
)
except Exception:
raise HTTPException(status_code=500)
@app.get("/api/programme") @app.get("/api/programme")
async def list_programme(): async def list_programme():
"""List all available programmes.""" """List all available programmes."""

View File

@ -221,7 +221,13 @@
<h2>Wahlprogramme NRW 2022</h2> <h2>Wahlprogramme NRW 2022</h2>
<div class="programme-grid"> <div class="programme-grid">
{% for prog in programmes if prog.typ == 'wahlprogramm' %} {% for prog in programmes if prog.typ == 'wahlprogramm' %}
<div class="programme-card"> <div class="programme-card" style="display: flex; gap: 1rem;">
<a href="{{ prog.pdf_url }}" target="_blank" style="flex-shrink: 0;">
<img src="/api/programme/thumbnail/{{ prog.id }}" alt="{{ prog.name }}"
style="width: 80px; border: 1px solid #ddd; border-radius: 4px;"
loading="lazy" onerror="this.style.display='none'">
</a>
<div>
<h3> <h3>
<span class="programme-badge badge-{{ prog.partei|lower }}">{{ prog.partei }}</span> <span class="programme-badge badge-{{ prog.partei|lower }}">{{ prog.partei }}</span>
{{ prog.name }} {{ prog.name }}
@ -230,7 +236,7 @@
<span class="programme-badge badge-wahlprogramm">Wahlprogramm</span> <span class="programme-badge badge-wahlprogramm">Wahlprogramm</span>
{% if prog.bundesland %}{{ prog.bundesland }}{% endif %} {% if prog.bundesland %}{{ prog.bundesland }}{% endif %}
</div> </div>
<div style="margin-top: 1rem;"> <div style="margin-top: 0.5rem;">
<a href="{{ prog.pdf_url }}" target="_blank" class="btn btn-primary"> <a href="{{ prog.pdf_url }}" target="_blank" class="btn btn-primary">
📄 PDF herunterladen 📄 PDF herunterladen
</a> </a>
@ -240,14 +246,21 @@
</span> </span>
{% endfor %} {% endfor %}
</div> </div>
</div>
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
<h2>Grundsatzprogramme</h2> <h2>Grundsatzprogramme</h2>
<div class="programme-grid"> <div class="programme-grid">
{% for prog in programmes if prog.typ == 'parteiprogramm' %} {% for prog in programmes if prog.typ == 'parteiprogramm' %}
<div class="programme-card"> <div class="programme-card" style="display: flex; gap: 1rem;">
<a href="{{ prog.pdf_url }}" target="_blank" style="flex-shrink: 0;">
<img src="/api/programme/thumbnail/{{ prog.id }}" alt="{{ prog.name }}"
style="width: 80px; border: 1px solid #ddd; border-radius: 4px;"
loading="lazy" onerror="this.style.display='none'">
</a>
<div>
<h3> <h3>
<span class="programme-badge badge-{{ prog.partei|lower }}">{{ prog.partei }}</span> <span class="programme-badge badge-{{ prog.partei|lower }}">{{ prog.partei }}</span>
{{ prog.name }} {{ prog.name }}
@ -255,7 +268,7 @@
<div class="programme-meta"> <div class="programme-meta">
<span class="programme-badge badge-parteiprogramm">Grundsatzprogramm</span> <span class="programme-badge badge-parteiprogramm">Grundsatzprogramm</span>
</div> </div>
<div style="margin-top: 1rem;"> <div style="margin-top: 0.5rem;">
<a href="{{ prog.pdf_url }}" target="_blank" class="btn btn-primary"> <a href="{{ prog.pdf_url }}" target="_blank" class="btn btn-primary">
📄 PDF herunterladen 📄 PDF herunterladen
</a> </a>
@ -265,6 +278,7 @@
</span> </span>
{% endfor %} {% endfor %}
</div> </div>
</div>
</div> </div>
{% endfor %} {% endfor %}
</div> </div>