219 lines
6.1 KiB
Python
219 lines
6.1 KiB
Python
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()
|