From c6a3c5b3dfd6d81957d227177eae460cdaef4e6c Mon Sep 17 00:00:00 2001 From: Eduard Iten Date: Sat, 21 Feb 2026 15:16:27 +0100 Subject: [PATCH] Erster Wurf --- config.yaml | 4 +- core/data_processor.py | 93 ++++++++++++++++------------ main.py | 2 + requirements.txt | 3 +- routers/web_routes.py | 38 +++++++----- static/BrittanySignature.ttf | Bin 0 -> 27536 bytes static/BrittanySignature.woff2 | Bin 0 -> 16432 bytes templates/admin.html | 84 +++++++++++++++++++++++-- templates/index.html | 45 -------------- templates/zeiten.html | 108 +++++++++++++++++++++++++++++++++ 10 files changed, 270 insertions(+), 107 deletions(-) create mode 100644 static/BrittanySignature.ttf create mode 100644 static/BrittanySignature.woff2 delete mode 100644 templates/index.html create mode 100644 templates/zeiten.html diff --git a/config.yaml b/config.yaml index 2765f62..b7ee17c 100644 --- a/config.yaml +++ b/config.yaml @@ -1,7 +1,7 @@ google_sheet: sheet_id: "15_SuNjWruwHcX4_R5OZPYb8Zwa__DrQ56ZcAodPj7QQ" - gid_times: "0" # Meistens 0 für das erste Blatt - gid_remarks: "92621051" # Beispiel-ID deines Bemerkungen-Blatts + gid_times: "635683780" + gid_remarks: "1437056802" date_column: "Datum" processing: diff --git a/core/data_processor.py b/core/data_processor.py index 2eab065..02039ed 100644 --- a/core/data_processor.py +++ b/core/data_processor.py @@ -1,66 +1,83 @@ import pandas as pd import requests +import markdown from io import StringIO from datetime import datetime, timedelta from .config_loader import config -_cache = {"events": None, "remarks": None} +_cache = {"events": None, "remarks": None, "timestamp": None} HEADERS = {"User-Agent": "Mozilla/5.0"} def invalidate_cache(): global _cache - _cache = {"events": None, "remarks": None} - print("DEBUG: Cache wurde manuell geleert.") + _cache = {"events": None, "remarks": None, "timestamp": None} return "Cache gelöscht" -def get_upcoming_events(): - if _cache["events"] is not None: - return _cache["events"] - - url = config['links']['times_csv'] - print(f"DEBUG: Lade Zeiten von URL: {url}") - - response = requests.get(url, headers=HEADERS) - df = pd.read_csv(StringIO(response.text)) - - # Debug: Spaltennamen prüfen - print(f"DEBUG: Spalten in Zeiten-Sheet gefunden: {df.columns.tolist()}") +def _is_cache_valid(): + if _cache["timestamp"] is None: + return False + return (datetime.now() - _cache["timestamp"]) < timedelta(hours=1) + +def get_upcoming_events(days_to_show=None, limit=None): + # Sofort Standardwert aus Config setzen, falls None oder 0 + if not days_to_show: + days_to_show = config['processing']['days_to_show'] + + # 1. Daten laden (entweder aus Cache oder von Google) + if not _is_cache_valid() or _cache["events"] is None: + url = config['links']['times_csv'] + response = requests.get(url, headers=HEADERS) + response.raise_for_status() + response.encoding = 'utf-8' + + df = pd.read_csv(StringIO(response.text)) + + # Typografie: Bindestrich durch En-Dash (–) ersetzen + for col in ['Morgen', 'Nachmittag']: + df[col] = df[col].fillna('').astype(str).str.replace('-', '–', regex=False) + + date_col = config['google_sheet']['date_column'] + df = df.dropna(subset=[date_col]) + df[date_col] = pd.to_datetime(df[date_col], dayfirst=True, errors='coerce') + + wt_map = {0: 'Mo', 1: 'Di', 2: 'Mi', 3: 'Do', 4: 'Fr', 5: 'Sa', 6: 'So'} + df['Wochentag'] = df[date_col].dt.weekday.map(wt_map) + + _cache["events"] = df.sort_values(by=date_col).to_dict(orient='records') + _cache["timestamp"] = datetime.now() - date_col = config['google_sheet']['date_column'] - df = df.dropna(subset=[date_col]) - df[date_col] = pd.to_datetime(df[date_col], dayfirst=True, errors='coerce') - df = df.dropna(subset=[date_col]).fillna('') - heute = pd.Timestamp(datetime.now().date()) - ende = heute + timedelta(days=config['processing']['days_to_show']) + date_col = config['google_sheet']['date_column'] + + # PRIORITÄT 1: Zeilen-Limit (gewinnt immer) + if limit and limit > 0: + return [e for e in _cache["events"] if e[date_col] >= heute][:limit] - mask = (df[date_col] >= heute) & (df[date_col] <= ende) - gefilterte = df.loc[mask].sort_values(by=date_col).copy() - - wt_map = {0: 'Mo', 1: 'Di', 2: 'Mi', 3: 'Do', 4: 'Fr', 5: 'Sa', 6: 'So'} - gefilterte['Wochentag'] = gefilterte[date_col].dt.weekday.map(wt_map) - - _cache["events"] = gefilterte.to_dict(orient='records') - return _cache["events"] + # PRIORITÄT 2: Tage-Logik + ende = heute + timedelta(days=int(days_to_show)) + return [e for e in _cache["events"] if heute <= e[date_col] <= ende] def get_remarks(): - if _cache["remarks"] is not None: + if _is_cache_valid() and _cache["remarks"] is not None: return _cache["remarks"] url = config['links']['remarks_csv'] - print(f"DEBUG: Lade Bemerkungen von URL: {url}") - response = requests.get(url, headers=HEADERS) - - # Debug: Die ersten 100 Zeichen der Antwort sehen - print(f"DEBUG: Raw Data Bemerkungen (Anfang): {response.text[:100]}...") + response.raise_for_status() + response.encoding = 'utf-8' df = pd.read_csv(StringIO(response.text), skiprows=2, header=None) if not df.empty: - print(f"DEBUG: Bemerkungen-DF Head:\n{df.head(3)}") - remarks = df[0].dropna().astype(str).tolist() - _cache["remarks"] = [r.strip() for r in remarks if r.strip()] + raw_remarks = df[0].dropna().astype(str).tolist() + processed = [] + for r in raw_remarks: + html = markdown.markdown(r.strip()) + if html.startswith("

") and html.endswith("

"): + html = html[3:-4] + processed.append(html) + _cache["remarks"] = processed + _cache["timestamp"] = datetime.now() else: _cache["remarks"] = [] diff --git a/main.py b/main.py index 2c24f1c..cc9ec27 100644 --- a/main.py +++ b/main.py @@ -1,4 +1,5 @@ from fastapi import FastAPI +from fastapi.staticfiles import StaticFiles from routers.web_routes import router as web_router import uvicorn from core.config_loader import config @@ -7,6 +8,7 @@ app = FastAPI() # Router einbinden app.include_router(web_router) +app.mount("/static", StaticFiles(directory="static"), name="static") if __name__ == "__main__": uvicorn.run(app, host=config['server']['host'], port=config['server']['port']) diff --git a/requirements.txt b/requirements.txt index 39862c1..93f5e1c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,4 +4,5 @@ pyyaml fastapi uvicorn jinja2 -python-multipart \ No newline at end of file +python-multipart +markdown \ No newline at end of file diff --git a/routers/web_routes.py b/routers/web_routes.py index a889ce0..d72763f 100644 --- a/routers/web_routes.py +++ b/routers/web_routes.py @@ -2,31 +2,39 @@ from fastapi import APIRouter, Request from fastapi.responses import HTMLResponse, RedirectResponse from fastapi.templating import Jinja2Templates from core.data_processor import get_upcoming_events, get_remarks, invalidate_cache +from core.config_loader import config from pathlib import Path router = APIRouter() BASE_DIR = Path(__file__).parent.parent templates = Jinja2Templates(directory=str(BASE_DIR / "templates")) -# Admin auf Root -@router.get("/", response_class=HTMLResponse) -async def admin_page(request: Request): - from core.config_loader import config - return templates.TemplateResponse("admin.html", { - "request": request, "links": config['links'] +@router.get("/zeiten", response_class=HTMLResponse) +async def public_table(request: Request, days: int = None, lines: int = None, test: bool = False): + # Wenn nichts angegeben wurde, greift der Standard aus der Config + if not days and not lines: + days = config['processing']['days_to_show'] + + events = get_upcoming_events(days_to_show=days, limit=lines) + remarks = get_remarks() + + # Template 'zeiten.html' laden und 'test' Parameter durchreichen + return templates.TemplateResponse("zeiten.html", { + "request": request, + "events": events, + "remarks": remarks, + "test": test }) -# Tabelle unter /zeiten -@router.get("/zeiten", response_class=HTMLResponse) -async def times_table(request: Request): - events = get_upcoming_events() - remarks = get_remarks() - return templates.TemplateResponse("index.html", { - "request": request, "events": events, "remarks": remarks +@router.get("/", response_class=HTMLResponse) +async def admin_page(request: Request): + return templates.TemplateResponse("admin.html", { + "request": request, + "links": config['links'], + "config_days": config['processing']['days_to_show'] }) @router.get("/cache-clear") async def clear_cache(): invalidate_cache() - # Relativer Redirect zurück zum Admin-Interface - return RedirectResponse(url="./") \ No newline at end of file + return RedirectResponse(url="/") \ No newline at end of file diff --git a/static/BrittanySignature.ttf b/static/BrittanySignature.ttf new file mode 100644 index 0000000000000000000000000000000000000000..36a273de31b21764479a7f8a310684da9f5326c5 GIT binary patch literal 27536 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 literal 0 HcmV?d00001 diff --git a/static/BrittanySignature.woff2 b/static/BrittanySignature.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..21fcb645bee15975bc767198e647e61a5352d943 GIT binary patch literal 16432 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 KYHaC4*Z&2WckaXh literal 0 HcmV?d00001 diff --git a/templates/admin.html b/templates/admin.html index 396e1af..45d372f 100644 --- a/templates/admin.html +++ b/templates/admin.html @@ -1,11 +1,39 @@ - Admin - Öffnungszeiten + Administration - Öffnungszeiten @@ -15,14 +43,58 @@

Google Sheets Links

➔ Tabelle: Bemerkungen bearbeiten

+ +
+
+ + +
+ +
+ + +
+
+ +

+ Zeilen hat Vorrang vor Tagen. Wenn beide Werte 0 sind, werden die Standard-Tage aus der Config genutzt (aktuell: {{ config_days }}). +

+ +

Cache Management

-

Nach Änderungen in Google Sheets muss der Cache gelöscht werden, damit die Website sofort aktualisiert wird.

- Invalidate Cache (Cache löschen) +

Der Cache wird automatisch alle 60 Minuten aktualisiert. Nach manuellen Änderungen in Google Sheets können Sie ihn hier sofort leeren.

+ Cache jetzt löschen
-

← Zurück zur Ansicht

+

← Zurück zur Ansicht

+ + - + \ No newline at end of file diff --git a/templates/index.html b/templates/index.html deleted file mode 100644 index f804998..0000000 --- a/templates/index.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - {% for event in events %} - - - - - {% if not event.Morgen and not event.Nachmittag %} - - {% else %} - - - {% endif %} - - {% endfor %} -
{{ event.Wochentag }}.{{ event.Datum.strftime('%d.%m.') }}geschlossen{{ event.Morgen }}{{ event.Nachmittag }}
- - {% if remarks %} -
- {% for r in remarks %} -
• {{ r }}
- {% endfor %} -
- {% endif %} - - \ No newline at end of file diff --git a/templates/zeiten.html b/templates/zeiten.html new file mode 100644 index 0000000..ce535f0 --- /dev/null +++ b/templates/zeiten.html @@ -0,0 +1,108 @@ + + + + + + + + {% if test %} +
+ {% endif %} + {% set monate = ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'] %} + {% set ns = namespace(last_month=none, last_week=none) %} + + {% for event in events %} + {% set current_month_name = monate[event.Datum.month - 1] %} + {% set current_week = event.Datum.isocalendar()[1] %} + + {# Monatstitel und Tabellen-Start/Ende Logik #} + {% if current_month_name != ns.last_month %} + {% if ns.last_month is not none %} {% endif %} + +
{{ current_month_name }}
+ + {% set ns.last_week = none %} {# Reset Wochendistanz bei neuem Monat #} + {% endif %} + + {# Wochen-Abstand innerhalb eines Monats #} + {% if ns.last_week is not none and current_week != ns.last_week %} + + {% endif %} + + + + + + {% if not event.Morgen and not event.Nachmittag %} + + {% else %} + + + {% endif %} + + + {% set ns.last_month = current_month_name %} + {% set ns.last_week = current_week %} + {% endfor %} +
{{ event.Wochentag }}.{{ event.Datum.strftime('%d.%m.') }}geschlossen{{ event.Morgen }}{{ event.Nachmittag }}
+ + {% if remarks %} +
+ {% for r in remarks %} +
{{ r | safe }}
+ {% endfor %} +
+ {% endif %} + {% if test %} +
+ {% endif %} + + + \ No newline at end of file

➔ Tabelle: Öffnungszeiten bearbeiten