fix(images): add proxy fallback to direct source url rendering

This commit is contained in:
Oliver 2026-02-18 10:20:47 +01:00
parent 910ca72c81
commit fb3465fb10
4 changed files with 26 additions and 8 deletions

View file

@ -3,6 +3,7 @@ from __future__ import annotations
import json
from pathlib import Path
import re
from urllib.parse import urlparse
from urllib.parse import urlencode
from urllib.request import Request as UrlRequest, urlopen
@ -124,6 +125,14 @@ def _is_probably_irrelevant_image(url: str) -> bool:
return any(re.search(pattern, lowered) for pattern in patterns)
def _is_http_image_url(url: str) -> bool:
try:
parsed = urlparse(url)
except Exception:
return False
return parsed.scheme in {"http", "https"} and bool(parsed.netloc)
def _build_image_entries(article: dict, extraction: dict, meta: dict) -> list[dict[str, object]]:
all_images = _read_article_images(article, extraction)
image_review = meta.get("image_review") if isinstance(meta.get("image_review"), dict) else {}
@ -371,15 +380,19 @@ def admin_article_image_decision(
@router.get("/admin/images/proxy")
def admin_image_proxy(request: Request, url: str):
user = _admin_user(request)
if not user:
return Response(status_code=401)
if not (url.startswith("http://") or url.startswith("https://")):
if not _is_http_image_url(url):
return Response(status_code=400)
try:
req = UrlRequest(url=url, headers={"User-Agent": IMAGE_PROXY_USER_AGENT, "Referer": url})
referer = request.headers.get("referer", "")
req = UrlRequest(
url=url,
headers={
"User-Agent": IMAGE_PROXY_USER_AGENT,
"Accept": "image/avif,image/webp,image/apng,image/*,*/*;q=0.8",
"Referer": referer or url,
},
)
with urlopen(req, timeout=10) as resp:
body = resp.read()
content_type = resp.headers.get("Content-Type", "application/octet-stream")

View file

@ -210,6 +210,11 @@ button.secondary {
background: #f8fafc;
}
.img-failed {
opacity: 0.3;
filter: grayscale(1);
}
.image-meta {
margin-top: 6px;
display: flex;

View file

@ -79,7 +79,7 @@
{% for image in article.image_entries %}
<article class="image-card {{ 'image-selected' if image.is_selected else '' }} {{ 'image-excluded' if image.is_excluded else '' }}">
<a href="{{ image.url }}" target="_blank" rel="noopener">
<img src="{{ image.proxy_url }}" alt="Artikelbild" loading="lazy" />
<img src="{{ image.proxy_url }}" data-fallback-src="{{ image.url }}" alt="Artikelbild" loading="lazy" onerror="if(!this.dataset.fallbackUsed){this.dataset.fallbackUsed='1';this.src=this.dataset.fallbackSrc;}else{this.classList.add('img-failed');}" />
</a>
<div class="image-meta">
{% if image.is_selected %}<span class="badge ok">Ausgewählt</span>{% endif %}

View file

@ -157,7 +157,7 @@
<div class="subtle">Legal: {{ "OK" if a.legal_checked else "offen" }}</div>
{% if a.selected_image_url %}
<div class="subtle">Hauptbild gesetzt</div>
<a href="{{ a.selected_image_url }}" target="_blank" rel="noopener"><img src="{{ a.selected_image_proxy_url }}" alt="Hauptbild" class="thumb" loading="lazy" /></a>
<a href="{{ a.selected_image_url }}" target="_blank" rel="noopener"><img src="{{ a.selected_image_proxy_url }}" data-fallback-src="{{ a.selected_image_url }}" alt="Hauptbild" class="thumb" loading="lazy" onerror="if(!this.dataset.fallbackUsed){this.dataset.fallbackUsed='1';this.src=this.dataset.fallbackSrc;}else{this.classList.add('img-failed');}" /></a>
{% endif %}
{% if a.summary %}
<div><strong>Summary:</strong> {{ a.summary }}</div>