import os import json import requests import hashlib import datetime import random # ------------------------- # KONFIG # ------------------------- WEBHOOK_URL = "Discord URL" BASE_URL = "https://das-schmeckt-mir.ruhr/images/pdf/speise_knapp/{kw:02d}_KW_Speiseplan{year}_Knapp.jpg" SAVE_DIR = "/opt/speiseplan-bot/plans" HASH_FILE = "/opt/speiseplan-bot/last_hashes.json" DELAY_FILE = "/opt/speiseplan-bot/delay.json" MESSAGES = [ "đŸœïž Herr B., ein weiterer Speiseplan fĂŒr die Woche {found_kw} ist in das Bominhaus eingeschlagen.", "đŸ„˜ Speiseplan fĂŒr Woche {found_kw}. Hoffentlich ist da kein Döner dabei.", "🍛 Boah, guck mal hier! Speiseplan fĂŒr {found_kw}!", "😋 Der {found_kw}. Speiseplan existiert und wir haben ihn.", "đŸČ Isch hab' gar nichts gemacht! Ich habe nur den {found_kw}. Speiseplan hochgeladen...", "💀 Wer diese Nachricht ĂŒber den {found_kw}. Speiseplan liest, der schuldet Kevin einen Döner.", "💕 Speiseplan gefunden und hochgeladen. Woche {found_kw}.", "đŸ€“ Wusstet ihr schon, dass das Essen in der KW {found_kw} schlechter ist als dieses Script?" ] # ------------------------- # LOGGING # ------------------------- def log_info(msg): print(f"\033[94m[{datetime.datetime.now().strftime('%H:%M:%S')}] {msg}\033[0m") def log_success(msg): print(f"\033[92m[{datetime.datetime.now().strftime('%H:%M:%S')}] {msg}\033[0m") def log_warn(msg): print(f"\033[93m[{datetime.datetime.now().strftime('%H:%M:%S')}] {msg}\033[0m") def log_error(msg): print(f"\033[91m[{datetime.datetime.now().strftime('%H:%M:%S')}] {msg}\033[0m") # ------------------------- # HILFSFUNKTIONEN # ------------------------- def load_json(path, default): if not os.path.exists(path): return default try: with open(path, "r") as f: return json.load(f) except: log_warn(f"JSON-Datei beschĂ€digt: {path}. Benutze Default.") return default def save_json(path, data): with open(path, "w") as f: json.dump(data, f, indent=2) def hash_bytes(data): return hashlib.sha256(data).hexdigest() def cleanup_old_plans(current_kw, current_year): log_info("AufrĂ€umen alter PlĂ€ne beginnt
") files = os.listdir(SAVE_DIR) cutoff = current_kw - 2 for file in files: if not file.startswith("Speiseplan_KW"): continue parts = file.replace("Speiseplan_KW", "").replace(".jpg", "").split("_") kw_old = int(parts[0]) year_old = int(parts[1]) if year_old < current_year or (year_old == current_year and kw_old <= cutoff): log_warn(f"Lösche alten Plan: {file}") os.remove(os.path.join(SAVE_DIR, file)) log_success("AufrĂ€umen abgeschlossen.") def fetch_plan(kw, year): url = BASE_URL.format(kw=kw, year=year) log_info(f"PrĂŒfe URL: {url}") try: r = requests.get(url) # Wenn kein Bild → direkt ignorieren content_type = r.headers.get("Content-Type", "") if r.status_code == 200 and content_type.startswith("image"): log_success(f"Echter Speiseplan gefunden → KW {kw}") return r.content # DEBUG: ausgeben, was der Server wirklich liefert log_warn(f"Kein gĂŒltiges Bild fĂŒr KW {kw} (Status={r.status_code}, Type={content_type})") return None except Exception as e: log_error(f"Fehler beim Abruf von KW {kw}: {e}") return None def record_delay(today, found_kw): delay = load_json(DELAY_FILE, {"active": False, "start": None, "days": 0}) current_kw = today.isocalendar().week if found_kw == current_kw: if delay["active"]: log_warn(f"Verzögerung beendet nach {delay['days']} Tagen.") delay = {"active": False, "start": None, "days": 0} save_json(DELAY_FILE, delay) return if found_kw < current_kw: if not delay["active"]: delay["active"] = True delay["start"] = today.isoformat() delay["days"] = 0 log_warn(f"Verzögerung gestartet! KW {found_kw} statt {current_kw}") else: start = datetime.date.fromisoformat(delay["start"]) delay["days"] = (today - start).days log_warn(f"Verzögerung lĂ€uft: {delay['days']} Tage") save_json(DELAY_FILE, delay) # ------------------------- # MAIN # ------------------------- def main(): os.makedirs(SAVE_DIR, exist_ok=True) today = datetime.date.today() year = today.year kw_current = today.isocalendar().week kw_next = kw_current + 1 year_next = year + 1 if kw_next > 52 else year if kw_next > 52: kw_next = 1 log_info(f"Starte Speiseplan-Check fĂŒr KW {kw_current} + KW {kw_next}
") hashes = load_json(HASH_FILE, {}) found_data = None found_kw = None found_year = None for kw_try, year_try in [(kw_current, year), (kw_next, year_next)]: data = fetch_plan(kw_try, year_try) if data: key = f"{kw_try}-{year_try}" new_hash = hash_bytes(data) if hashes.get(key) == new_hash: log_warn(f"Plan KW {kw_try} bereits bekannt – ĂŒberspringe.") continue found_data = data found_kw = kw_try found_year = year_try hashes[key] = new_hash break if not found_data: log_warn("Kein neuer Plan gefunden.") record_delay(today, -1) return record_delay(today, found_kw) filename = f"Speiseplan_KW{found_kw}_{found_year}.jpg" file_path = os.path.join(SAVE_DIR, filename) with open(file_path, "wb") as f: f.write(found_data) log_success(f"Plan gespeichert: {file_path}") # Nachricht formatieren message = random.choice(MESSAGES).format(found_kw=found_kw) with open(file_path, "rb") as f: requests.post( WEBHOOK_URL, data={"content": message}, files={"file": (filename, f, "image/jpeg")} ) log_success("Webhook erfolgreich gesendet!") save_json(HASH_FILE, hashes) cleanup_old_plans(kw_current, year) log_success("Speiseplan-Bot abgeschlossen.") if __name__ == "__main__": main()