Runde wird automatisch aus der Tabelle ermittelt

This commit is contained in:
2026-05-24 15:42:17 +02:00
parent 82e37fb9bf
commit 08ec14bd63

View File

@@ -17,19 +17,25 @@ import json
import re import re
from datetime import datetime from datetime import datetime
CURRENT_ROUND = int(os.environ.get("CURRENT_ROUND", 2))
PGN_URL = f"https://www.deutsche-schachjugend.de/2026/odjm-d/partien/{CURRENT_ROUND}.pgn"
STANDINGS_URL = "https://www.deutsche-schachjugend.de/2026/odjm-d/tabelle/" STANDINGS_URL = "https://www.deutsche-schachjugend.de/2026/odjm-d/tabelle/"
PORT = int(os.environ.get("PORT", 8111)) PORT = int(os.environ.get("PORT", 8111))
CACHE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "cache") CACHE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "cache")
CACHE_FILE = os.path.join(CACHE_DIR, f"runde-{CURRENT_ROUND}.pgn")
STANDINGS_CACHE_FILE = os.path.join(CACHE_DIR, "standings.json") STANDINGS_CACHE_FILE = os.path.join(CACHE_DIR, "standings.json")
CACHE_TTL = int(os.environ.get("CACHE_TTL", 31)) # Sekunden CACHE_TTL = int(os.environ.get("CACHE_TTL", 31))
os.makedirs(CACHE_DIR, exist_ok=True) os.makedirs(CACHE_DIR, exist_ok=True)
last_fetch_time = None last_fetch_time = None
last_standings_fetch_time = None last_standings_fetch_time = None
current_round = 0 # wird aus der Tabelle ermittelt
def get_pgn_url():
return f"https://www.deutsche-schachjugend.de/2026/odjm-d/partien/{current_round}.pgn"
def get_cache_file():
return os.path.join(CACHE_DIR, f"runde-{current_round}.pgn")
def fetch_pgn(): def fetch_pgn():
@@ -37,11 +43,14 @@ def fetch_pgn():
Nutzt If-Modified-Since gibt (data, changed) zurück. Nutzt If-Modified-Since gibt (data, changed) zurück.
changed=False bedeutet 304 Not Modified (keine neuen Daten).""" changed=False bedeutet 304 Not Modified (keine neuen Daten)."""
global last_fetch_time global last_fetch_time
if current_round == 0:
return None, False
url = get_pgn_url()
try: try:
headers = {"User-Agent": "Mozilla/5.0"} headers = {"User-Agent": "Mozilla/5.0"}
if last_fetch_time: if last_fetch_time:
headers["If-Modified-Since"] = datetime.utcfromtimestamp(last_fetch_time).strftime("%a, %d %b %Y %H:%M:%S GMT") headers["If-Modified-Since"] = datetime.utcfromtimestamp(last_fetch_time).strftime("%a, %d %b %Y %H:%M:%S GMT")
req = urllib.request.Request(PGN_URL, headers=headers) req = urllib.request.Request(url, headers=headers)
with urllib.request.urlopen(req, timeout=31) as response: with urllib.request.urlopen(req, timeout=31) as response:
data = response.read() data = response.read()
last_fetch_time = time.time() last_fetch_time = time.time()
@@ -60,33 +69,35 @@ def get_pgn_content_longpoll(since=0):
"""Long-Poll: Blockiert, bis sich die PGN-Datei tatsächlich ändert. """Long-Poll: Blockiert, bis sich die PGN-Datei tatsächlich ändert.
Antwortet nur bei neuen Daten, nie mit unverändertem Stand.""" Antwortet nur bei neuen Daten, nie mit unverändertem Stand."""
while True: while True:
if os.path.exists(CACHE_FILE): cache_file = get_cache_file()
mtime = os.path.getmtime(CACHE_FILE) if os.path.exists(cache_file):
mtime = os.path.getmtime(cache_file)
if mtime > since: if mtime > since:
with open(CACHE_FILE, "rb") as f: with open(cache_file, "rb") as f:
return f.read(), mtime return f.read(), mtime
age = time.time() - mtime age = time.time() - mtime
if age >= CACHE_TTL: if age >= CACHE_TTL:
content, changed = fetch_pgn() content, changed = fetch_pgn()
if changed and content is not None: if changed and content is not None:
with open(CACHE_FILE, "wb") as f: with open(cache_file, "wb") as f:
f.write(content) f.write(content)
new_mtime = os.path.getmtime(CACHE_FILE) new_mtime = os.path.getmtime(cache_file)
print(f"[{datetime.now().strftime('%H:%M:%S')}] PGN via Long-Poll aktualisiert ({len(content)} Bytes)") print(f"[{datetime.now().strftime('%H:%M:%S')}] PGN via Long-Poll aktualisiert ({len(content)} Bytes)")
return content, new_mtime return content, new_mtime
else: else:
content, changed = fetch_pgn() content, changed = fetch_pgn()
if changed and content is not None: if changed and content is not None:
with open(CACHE_FILE, "wb") as f: with open(cache_file, "wb") as f:
f.write(content) f.write(content)
return content, os.path.getmtime(CACHE_FILE) return content, os.path.getmtime(cache_file)
time.sleep(5) time.sleep(5)
def fetch_standings(): def fetch_standings():
"""Lädt die Tabellenseite und parst Laras Platzierung.""" """Lädt die Tabellenseite und parst Laras Platzierung.
global last_standings_fetch_time Ermittelt dabei auch die aktuelle Runde."""
global last_standings_fetch_time, current_round
try: try:
headers = {"User-Agent": "Mozilla/5.0"} headers = {"User-Agent": "Mozilla/5.0"}
if last_standings_fetch_time: if last_standings_fetch_time:
@@ -96,13 +107,16 @@ def fetch_standings():
html = response.read().decode("utf-8", errors="replace") html = response.read().decode("utf-8", errors="replace")
last_standings_fetch_time = time.time() last_standings_fetch_time = time.time()
# Rundeninfo extrahieren
round_info = "" round_info = ""
m = re.search(r"Tabellenstand\s+nach\s+der\s+(\d+)\.\s*Runde", html) m = re.search(r"Tabellenstand\s+nach\s+der\s+(\d+)\.\s*Runde", html)
if m: if m:
detected = int(m.group(1))
if detected != current_round:
old = current_round
current_round = detected
print(f"[{datetime.now().strftime('%H:%M:%S')}] Runde erkannt: {current_round} (war {old})")
round_info = f"nach der {m.group(1)}. Runde" round_info = f"nach der {m.group(1)}. Runde"
# Tabellenzeilen suchen
rows = re.findall(r"<tr[^>]*>(.*?)</tr>", html, re.DOTALL | re.IGNORECASE) rows = re.findall(r"<tr[^>]*>(.*?)</tr>", html, re.DOTALL | re.IGNORECASE)
for row in rows: for row in rows:
if "Lara Kiesewetter" not in row: if "Lara Kiesewetter" not in row:
@@ -238,9 +252,10 @@ def background_refresh():
while True: while True:
time.sleep(CACHE_TTL) time.sleep(CACHE_TTL)
try: try:
content = fetch_pgn() content, changed = fetch_pgn()
if content: if changed and content is not None:
with open(CACHE_FILE, "wb") as f: cache_file = get_cache_file()
with open(cache_file, "wb") as f:
f.write(content) f.write(content)
except Exception as e: except Exception as e:
print(f"[{datetime.now().strftime('%H:%M:%S')}] Hintergrund-Refresh Fehler: {e}") print(f"[{datetime.now().strftime('%H:%M:%S')}] Hintergrund-Refresh Fehler: {e}")
@@ -254,10 +269,18 @@ def main():
print(f" Drücke Ctrl+C zum Beenden") print(f" Drücke Ctrl+C zum Beenden")
print("=" * 50) print("=" * 50)
# Initialer Ladeversuch # Runde aus Tabelle ermitteln
content = fetch_pgn() standings = fetch_standings()
if content: if standings and current_round > 0:
with open(CACHE_FILE, "wb") as f: print(f"[OK] Aktuelle Runde: {current_round}")
else:
current_round = 1
print("[INFO] Starte mit Runde 1 (Tabelle noch nicht verfügbar)")
content, changed = fetch_pgn()
if changed and content is not None:
cache_file = get_cache_file()
with open(cache_file, "wb") as f:
f.write(content) f.write(content)
print(f"[OK] PGN geladen ({len(content)} Bytes)") print(f"[OK] PGN geladen ({len(content)} Bytes)")
else: else: