Speiseplan-Kacheln (zukünftige Tage), Footer mit Credit (No tracking, Markus F.J. Busche)
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
30
app.py
30
app.py
@@ -8,7 +8,7 @@ import logging
|
||||
import os
|
||||
import threading
|
||||
import time
|
||||
from datetime import datetime
|
||||
from datetime import date, datetime
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
from flask import Flask, Response, render_template, request
|
||||
@@ -29,20 +29,23 @@ app = Flask(__name__, template_folder=_template_dir)
|
||||
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1)
|
||||
_log = logging.getLogger(__name__)
|
||||
|
||||
# Cache: zuletzt gültige iCal-Bytes; Zeitpunkt der letzten Aktualisierung
|
||||
# Cache: zuletzt gültige iCal-Bytes; strukturierte Daten (Datum → Gerichte); Zeitpunkt der letzten Aktualisierung
|
||||
_ical_cache: bytes = empty_ical_bytes()
|
||||
_by_date_cache: dict[date, list[str]] | None = None
|
||||
_last_refresh_at: datetime | None = None
|
||||
_cache_lock = threading.Lock()
|
||||
_TIMEZONE = ZoneInfo("Europe/Berlin")
|
||||
_WEEKDAY_NAMES = ("Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag")
|
||||
|
||||
def _do_refresh() -> None:
|
||||
"""Refresh ausführen und bei Erfolg Cache aktualisieren."""
|
||||
global _ical_cache, _last_refresh_at
|
||||
global _ical_cache, _by_date_cache, _last_refresh_at
|
||||
result = refresh_speiseplan(KANTINE_BASE_URL)
|
||||
if result is not None:
|
||||
_, ical_bytes = result
|
||||
by_date, ical_bytes = result
|
||||
with _cache_lock:
|
||||
_ical_cache = ical_bytes
|
||||
_by_date_cache = by_date
|
||||
_last_refresh_at = datetime.now(_TIMEZONE)
|
||||
_log.info("Speiseplan-Refresh erfolgreich, Cache aktualisiert.")
|
||||
else:
|
||||
@@ -105,17 +108,34 @@ def _format_last_refresh() -> str | None:
|
||||
return t.strftime("%d.%m.%Y, %H:%M") + " Uhr"
|
||||
|
||||
|
||||
def _upcoming_days() -> list[tuple[str, list[str]]]:
|
||||
"""Heute und zukünftige Tage aus dem Cache, sortiert, mit formatiertem Datum (z. B. Montag, 03.02.2026)."""
|
||||
with _cache_lock:
|
||||
by_date = _by_date_cache
|
||||
if not by_date:
|
||||
return []
|
||||
today = datetime.now(_TIMEZONE).date()
|
||||
upcoming = [(d, dishes) for d, dishes in by_date.items() if d >= today]
|
||||
upcoming.sort(key=lambda x: x[0])
|
||||
return [
|
||||
(f"{_WEEKDAY_NAMES[d.weekday()]}, {d.strftime('%d.%m.%Y')}", dishes)
|
||||
for d, dishes in upcoming
|
||||
]
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def index():
|
||||
"""Startseite mit Anleitung zur iCal-Einbettung (Google und andere)."""
|
||||
"""Startseite mit Anleitung zur iCal-Einbettung (Google und andere) und Speiseplan-Kacheln."""
|
||||
base = PUBLIC_URL or request.url_root.rstrip("/")
|
||||
calendar_url = f"{base}/calendar.ics"
|
||||
last_refresh_str = _format_last_refresh()
|
||||
upcoming_days = _upcoming_days()
|
||||
try:
|
||||
return render_template(
|
||||
"index.html",
|
||||
calendar_url=calendar_url,
|
||||
last_refresh_str=last_refresh_str,
|
||||
upcoming_days=upcoming_days,
|
||||
)
|
||||
except Exception as e:
|
||||
_log.exception("Template index.html: %s", e)
|
||||
|
||||
Reference in New Issue
Block a user