#!/usr/bin/env python3 """ Lokal Proxy-Server für Lara's Schachturnier Lädt die PGN-Datei und stellt sie mit CORS-Headern bereit. """ import http.server import socketserver import urllib.request import sys import os import threading import time import json from datetime import datetime PGN_URL = "https://www.deutsche-schachjugend.de/2026/odjm-d/partien/gesamt-utf8.pgn" PORT = 8111 CACHE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "cache") CACHE_FILE = os.path.join(CACHE_DIR, "gesamt-utf8.pgn") CACHE_TTL = 30 # Sekunden os.makedirs(CACHE_DIR, exist_ok=True) last_fetch_time = None def fetch_pgn(): """Lädt die PGN-Datei von der URL als Bytes.""" global last_fetch_time try: req = urllib.request.Request(PGN_URL, headers={"User-Agent": "Mozilla/5.0"}) with urllib.request.urlopen(req, timeout=30) as response: data = response.read() last_fetch_time = time.time() return data except Exception as e: print(f"[{datetime.now().strftime('%H:%M:%S')}] Fehler beim Laden: {e}") return None def get_pgn_content(): """Gibt PGN-Inhalt als Bytes zurück, nutzt Cache wenn möglich.""" now = time.time() # Prüfe Cache if os.path.exists(CACHE_FILE): age = now - os.path.getmtime(CACHE_FILE) if age < CACHE_TTL: with open(CACHE_FILE, "rb") as f: return f.read() # Cache verfallen oder nicht vorhanden -> neu laden content = fetch_pgn() if content: with open(CACHE_FILE, "wb") as f: f.write(content) print(f"[{datetime.now().strftime('%H:%M:%S')}] PGN aktualisiert ({len(content)} Bytes)") return content # Fallback: alter Cache if os.path.exists(CACHE_FILE): print(f"[{datetime.now().strftime('%H:%M:%S')}] Verwende alten Cache") with open(CACHE_FILE, "rb") as f: return f.read() return None class PGNHandler(http.server.BaseHTTPRequestHandler): def do_GET(self): if self.path == "/pgn": content = get_pgn_content() if content: self.send_response(200) self.send_header("Content-Type", "text/plain; charset=utf-8") self.send_header("Access-Control-Allow-Origin", "*") self.send_header("Cache-Control", "no-cache") self.end_headers() self.wfile.write(content) else: self.send_response(502) self.send_header("Content-Type", "application/json") self.send_header("Access-Control-Allow-Origin", "*") self.end_headers() self.wfile.write(b'{"error": "Konnte PGN nicht laden"}') elif self.path == "/status": self.send_response(200) self.send_header("Content-Type", "application/json") self.send_header("Access-Control-Allow-Origin", "*") self.send_header("Cache-Control", "no-cache") self.end_headers() status = { "status": "ok", "last_fetch": last_fetch_time, "cache_ttl": CACHE_TTL, "server_time": time.time() } self.wfile.write(json.dumps(status).encode()) else: # Statische Dateien aus dem Verzeichnis if self.path == "/": self.path = "/index.html" filepath = os.path.join(os.path.dirname(os.path.abspath(__file__)), self.path.lstrip("/")) if os.path.isfile(filepath): content_types = { ".html": "text/html", ".css": "text/css", ".js": "application/javascript", ".json": "application/json", ".png": "image/png", ".jpg": "image/jpeg", ".svg": "image/svg+xml", } ext = os.path.splitext(filepath)[1] content_type = content_types.get(ext, "application/octet-stream") with open(filepath, "rb") as f: content = f.read() self.send_response(200) self.send_header("Content-Type", f"{content_type}; charset=utf-8") self.send_header("Access-Control-Allow-Origin", "*") self.end_headers() self.wfile.write(content) else: self.send_response(404) self.end_headers() def log_message(self, format, *args): print(f"[{datetime.now().strftime('%H:%M:%S')}] {args[0]}") def background_refresh(): """Aktualisiert den Cache im Hintergrund.""" while True: time.sleep(CACHE_TTL) try: content = fetch_pgn() if content: with open(CACHE_FILE, "wb") as f: f.write(content) except Exception as e: print(f"[{datetime.now().strftime('%H:%M:%S')}] Hintergrund-Refresh Fehler: {e}") def main(): print("=" * 50) print(" [TROPHY] Lara Kiesewetter – Live Schachturnier") print("=" * 50) print(f" Server läuft auf: http://localhost:{PORT}") print(f" Drücke Ctrl+C zum Beenden") print("=" * 50) # Initialer Ladeversuch content = fetch_pgn() if content: with open(CACHE_FILE, "wb") as f: f.write(content) print(f"[OK] PGN geladen ({len(content)} Bytes)") else: print("[WARN] Initialer Ladeversuch fehlgeschlagen, wird wiederholt...") # Hintergrund-Refresh Thread starten refresh_thread = threading.Thread(target=background_refresh, daemon=True) refresh_thread.start() # Server starten with socketserver.TCPServer(("", PORT), PGNHandler) as httpd: print(f"\n[SERVER] Server gestartet: http://localhost:{PORT}\n") try: httpd.serve_forever() except KeyboardInterrupt: print("\n[BYE] Server gestoppt.") if __name__ == "__main__": main()