#!/usr/bin/python3 # -*- coding: utf-8 -*- import datetime import json import signal import ssl import sys import urllib.request import xml.etree.ElementTree as ET from time import sleep from urllib.error import HTTPError import telepot from telepot.loop import MessageLoop class Essen: def __init__(self, name, preis, kategorie): self.name = name self.preis = preis self.kategorie = kategorie def __str__(self): return str("*%s*: %s (%.2f €)" % (self.kategorie, self.name, self.preis)) config_filename = "config.json" monate = ["Januar", "Februar", "März", "April", "Mai", "Juni", "August", "September", "Oktober", "November", "Dezember"] wochentage = ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"] status = "" def handle(msg): global essen, status content_type, chat_type, chat_id = telepot.glance(msg) if content_type == "text": text = str(msg["text"]).lower() if text.startswith("/start"): if chat_id not in ids: ids.append(chat_id) bot.sendMessage(chat_id, "Bot wurde aktiviert") chat = get_chat_name(msg) send_status("Bot aktiviert für Chat %s (ID: %i)" % (chat, chat_id)) with open(config_filename, 'w') as outfile: json.dump(config, outfile) else: bot.sendMessage(chat_id, "Bot war bereits aktiviert") elif text.startswith("/stop"): if chat_id in ids: ids.remove(chat_id) bot.sendMessage(chat_id, "Bot wurde deaktiviert") chat = get_chat_name(msg) send_status("Bot deaktiviert für Chat %s (ID: %i)" % (chat, chat_id)) with open(config_filename, 'w') as outfile: json.dump(config, outfile) else: bot.sendMessage(chat_id, "Bot war nicht aktiv") elif text.startswith("/essen") or text.startswith("/mensa") or text.startswith("/speiseplan"): chat = get_chat_name(msg) send_status("Essen angefordert für Chat %s (ID: %i)" % (chat, chat_id)) var = get_essen() if len(essen) == 0: if var: bot.sendMessage(chat_id, "Es ist ein Fehler aufgetreten. Bitte später erneut versuchen.") else: bot.sendMessage(chat_id, "Für heute ist leider kein Speiseplan verfügbar.") else: send_essen(chat_id) send_status("Essen versendet für Chat %s (ID: %i)" % (chat, chat_id)) elif text.startswith("/status") and chat_id in config_ids: bot.sendMessage(chat_id, status) elif content_type == "new_chat_member": if msg["new_chat_participant"]["id"] == bot.getMe()["id"]: bot.sendMessage(chat_id, "*Mensa-Bot der Hochschule Mittweida (beta)*\nDieser Bot versendet jeden Tag um " "8 Uhr den aktuellen Mensa-Speiseplan. Er wird über /start für den aktuellen Chat " "oder die aktuelle Gruppe gestartet, /stop beendet ihn wieder. Mit /essen, /mensa " "und /speiseplan kann der aktuelle Speiseplan manuell abgerufen werden.\n\n" "_Haftungsausschluss: Dieser Bot steht in keiner Verbindung mit der Hochschule " "Mittweida oder dem Studentenwerk Freiberg. Alle Angaben ohne Gewähr._", "markdown") elif content_type == "left_chat_member": if msg["left_chat_participant"]["id"] == bot.getMe()["id"]: if chat_id in ids: ids.remove(chat_id) with open(config_filename, 'w') as outfile: json.dump(config, outfile) def send_essen(chat_id): global datum, essen nachricht = "Speiseplan am WOCHENTAG, den %s:\n" % datum.strftime("%d. MONAT %Y") nachricht = nachricht.replace("MONAT", monate[(datum.month - 1) % 12]) nachricht = nachricht.replace("WOCHENTAG", wochentage[datum.weekday()]) for i in essen: nachricht += "- " + str(i).replace(".", ",") + "\n\n" bot.sendMessage(chat_id, nachricht, "markdown") def send_status(text): global config_ids for chat_id in config_ids: bot.sendMessage(chat_id, text) def get_essen(): global datum, essen, ctx essen = [] try: # response = urllib.request.urlopen(url, context=ctx) response = urllib.request.urlopen(url) except HTTPError: return False except Exception as expt: send_status("Es ist ein Fehler aufgetreten:\n%s" % str(expt)) print("Fehler:\n%s" % str(expt)) return True data = response.read() response.close() text = data.decode('utf-8') et = ET.fromstring(text) date = et.findall("./menus/day/date")[0].text datum = datetime.date(int(date[:4]), int(date[5:7]), int(date[8:10])) menus = et.findall("./menus/day/menu") for i in menus: kategorie = i.findall("type")[0].text name = i.findall("description")[0].text.strip("()1234567890, ") preis = float(i.findall("./prices/price[label='Studenten']/value")[0].text.replace(",", ".")) essen.append(Essen(name, preis, kategorie)) def get_chat_name(msg): if msg["chat"]["type"] == "group": chat = msg["chat"]["title"] + " (g)" elif msg["chat"]["type"] == "private": chat = msg["chat"]["first_name"] + " " + msg["chat"]["last_name"] + " (p)" else: chat = "null" return chat def shutdown(signum, frame): print('Signal handler called with signal', signum) sys.stdout.close() sys.stderr.close() sys.exit(-1) sys.stdout = open("out.log", "a") sys.stderr = open("err.log", "a") signal.signal(signal.SIGTERM, shutdown) try: with open(config_filename, 'r') as config_file: config = json.load(config_file) except FileNotFoundError as e: print('Error: config file "{}" not found: {}'.format(config_filename, e)) sys.exit(-1) except ValueError as e: print('Error: invalid config file "{}": {}'.format(config_filename, e)) sys.exit(-1) telegram_bot_token = config.get("telegram_bot_token") url = config.get("url") ids = config.get("ids") config_ids = config.get("config_ids") bot = telepot.Bot(telegram_bot_token) MessageLoop(bot, handle).run_as_thread() ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE while True: now = datetime.datetime.today() nextDay = datetime.datetime(now.year, now.month, now.day) + datetime.timedelta(1, 28800) send_status("Wartezeit: %i Sekunden" % (nextDay - now).seconds) status = "Warten bis %s" % nextDay sleep((nextDay - now).seconds) send_status("Aufwachen um 8 Uhr") status = "Essen abrufen" get_essen() send_status("%i Essen gefunden" % len(essen)) status = "Essen senden" if len(essen) > 0: send_status("Essen werden gesendet") for i in ids: send_essen(i) send_status("Abgeschlossen, warte 30 Sekunden") status = "Warte 30 Sekunden" sleep(30)