HSMensaW/HSMensaW_bot.py

203 lines
7.1 KiB
Python

#!/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)