Startseite mit Anleitung, letzte Aktualisierung, README ergänzt

This commit is contained in:
2026-01-29 13:30:42 +01:00
parent bb43f7c63a
commit abd64fd961
4 changed files with 344 additions and 10 deletions

49
app.py
View File

@@ -8,8 +8,10 @@ import logging
import os
import threading
import time
from datetime import datetime
from zoneinfo import ZoneInfo
from flask import Flask, Response
from flask import Flask, Response, render_template, request
from kantine2ical import BASE_URL, empty_ical_bytes, refresh_speiseplan
@@ -17,21 +19,26 @@ from kantine2ical import BASE_URL, empty_ical_bytes, refresh_speiseplan
KANTINE_BASE_URL = os.environ.get("KANTINE_BASE_URL", BASE_URL)
REFRESH_INTERVAL_SECONDS = int(os.environ.get("REFRESH_INTERVAL_SECONDS", "86400")) # 24h
app = Flask(__name__)
# Template-Ordner immer relativ zu dieser Datei (funktioniert mit Gunicorn/Docker)
_template_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "templates")
app = Flask(__name__, template_folder=_template_dir)
_log = logging.getLogger(__name__)
# Cache: zuletzt gültige iCal-Bytes; Lock für Zugriff
# Cache: zuletzt gültige iCal-Bytes; Zeitpunkt der letzten Aktualisierung
_ical_cache: bytes = empty_ical_bytes()
_last_refresh_at: datetime | None = None
_cache_lock = threading.Lock()
_TIMEZONE = ZoneInfo("Europe/Berlin")
def _do_refresh() -> None:
"""Refresh ausführen und bei Erfolg Cache aktualisieren."""
global _ical_cache
global _ical_cache, _last_refresh_at
result = refresh_speiseplan(KANTINE_BASE_URL)
if result is not None:
_, ical_bytes = result
with _cache_lock:
_ical_cache = ical_bytes
_last_refresh_at = datetime.now(_TIMEZONE)
_log.info("Speiseplan-Refresh erfolgreich, Cache aktualisiert.")
else:
_log.warning("Speiseplan-Refresh fehlgeschlagen oder keine Daten; Cache unverändert.")
@@ -68,10 +75,38 @@ def calendar_ics() -> Response:
)
def _format_last_refresh() -> str | None:
"""Zeitpunkt der letzten Aktualisierung formatiert (z. B. 29.01.2025, 14:32 Uhr)."""
with _cache_lock:
t = _last_refresh_at
if t is None:
return None
return t.strftime("%d.%m.%Y, %H:%M") + " Uhr"
@app.route("/")
def index() -> Response:
"""Redirect auf calendar.ics oder gleiche Antwort wie /calendar.ics."""
return calendar_ics()
def index():
"""Startseite mit Anleitung zur iCal-Einbettung (Google und andere)."""
base = request.url_root.rstrip("/")
calendar_url = f"{base}/calendar.ics"
last_refresh_str = _format_last_refresh()
try:
return render_template(
"index.html",
calendar_url=calendar_url,
last_refresh_str=last_refresh_str,
)
except Exception as e:
_log.exception("Template index.html: %s", e)
return (
f'<!DOCTYPE html><html lang="de"><head><meta charset="UTF-8"><title>Speiseplan iCal</title></head>'
f'<body><h1>Speiseplan Kantine BHZ Kiel-Wik</h1>'
f'<p>Zuletzt aktualisiert: {last_refresh_str or "noch nicht"}.</p>'
f'<p>Abo-URL: <a href="{calendar_url}">{calendar_url}</a></p>'
f'<p>In Google Kalender: Andere Kalender → Von URL → obige URL einfügen.</p></body></html>',
200,
{"Content-Type": "text/html; charset=utf-8"},
)
def main() -> None: