253 lines
9.2 KiB
Python
Executable File
253 lines
9.2 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import datetime
|
|
from typing import List
|
|
from bs4 import BeautifulSoup
|
|
import tempfile
|
|
import sys
|
|
import os
|
|
import urllib.request
|
|
from datetime import date, timedelta
|
|
|
|
URL_SLADOVNICKA = "https://sladovnicka.unasplzenchutna.cz/cz/denni-nabidka"
|
|
URL_MOTLICI = "https://www.umotliku.cz"
|
|
URL_TECHTOWER = "https://www.equifarm.cz/restaurace-techtower"
|
|
|
|
DAY_NAMES = ['pondělí', 'úterý', 'středa',
|
|
'čtvrtek', 'pátek', 'sobota', 'neděle']
|
|
|
|
# Fráze v názvech jídel, které naznačují že se jedná o polévku
|
|
SOUP_NAMES = ['polévka', 'česnečka', 'česnekový krém', 'cibulačka', 'vývar']
|
|
|
|
|
|
class bcolors:
|
|
HEADER = '\033[95m'
|
|
OKBLUE = '\033[94m'
|
|
OKCYAN = '\033[96m'
|
|
OKGREEN = '\033[92m'
|
|
WARNING = '\033[93m'
|
|
FAIL = '\033[91m'
|
|
ENDC = '\033[0m'
|
|
BOLD = '\033[1m'
|
|
UNDERLINE = '\033[4m'
|
|
|
|
|
|
class Food:
|
|
name = None
|
|
amount = None
|
|
price = None
|
|
is_soup = False
|
|
|
|
def __init__(self, name, amount, price, is_soup=False) -> None:
|
|
self.name = name
|
|
self.amount = amount
|
|
self.price = price
|
|
self.is_soup = is_soup
|
|
|
|
|
|
def getOrDownloadHtml(prefix: str, url: str):
|
|
'''Vrátí HTML pro daný prefix pro aktuální den.
|
|
Pokud v tempu neexistuje, provede jeho stažení z předané URL a uložení.'''
|
|
filename = prefix + "_" + date.today().strftime("%Y_%m_%d") + ".html"
|
|
filepath = os.path.join(tempfile.gettempdir(), filename)
|
|
if not os.path.isfile(filepath):
|
|
urllib.request.urlretrieve(url, filepath)
|
|
file = open(filepath, "r")
|
|
contents = file.read()
|
|
file.close()
|
|
return contents
|
|
|
|
|
|
def isNameOfDay(text: str):
|
|
'''Vrátí True, pokud předaný text představuje název dne v týdnu (např. "pondělí")'''
|
|
return text.strip().lower() in DAY_NAMES
|
|
|
|
|
|
def getDayNameOfDate(date: datetime.datetime):
|
|
'''Vrátí název dne v týdnu - např. pondělí, úterý, ...'''
|
|
return DAY_NAMES[date.weekday()]
|
|
|
|
|
|
def getStartOfWeekDate():
|
|
'''Vrátí datetime představující pondělí v aktuálním týdnu.'''
|
|
today = datetime.datetime.now()
|
|
return today - timedelta(days=today.weekday())
|
|
|
|
|
|
def isTextSoupName(text: str):
|
|
'''Vrátí True, pokud se předaný text jeví jako název polévky.
|
|
Používá se tam, kde nemáme lepší způsob detekce (TechTower).'''
|
|
for name in SOUP_NAMES:
|
|
if name in text.lower():
|
|
return True
|
|
return False
|
|
|
|
|
|
def printMenu(name: str, foodList: List[Food]):
|
|
'''Vytiskne jídelní lístek na obrazovku.'''
|
|
print(f"{bcolors.OKGREEN}{name}{bcolors.ENDC}\n---------------------------------------------------------------------------------")
|
|
maxLength = 0
|
|
for jidlo in foodList:
|
|
if len(jidlo.name) > maxLength:
|
|
maxLength = len(jidlo.name)
|
|
for jidlo in foodList:
|
|
barva = bcolors.HEADER if jidlo.is_soup else bcolors.WARNING
|
|
print(f"{barva}{jidlo.amount}\t{jidlo.name.ljust(maxLength)}\t{bcolors.ENDC}{bcolors.OKCYAN}{jidlo.price}{bcolors.ENDC}")
|
|
print('\n')
|
|
|
|
|
|
def getMenuSladovnicka() -> List[Food]:
|
|
html = getOrDownloadHtml('sladovnicka', URL_SLADOVNICKA)
|
|
soup = BeautifulSoup(html, "html.parser")
|
|
div = soup.select_one("div.tab-pane.fade.in.active")
|
|
datumDen = div.find("h2").text
|
|
split = datumDen.split(".")
|
|
denMesic = split[0] + "." + split[1] + "."
|
|
# nazevDen = split[2]
|
|
dnesniDatum = date.today().strftime("%-d.%-m.")
|
|
if denMesic != dnesniDatum:
|
|
print('Chyba: neočekávané datum na stránce Sladovnické (' +
|
|
denMesic + '), očekáváno ' + dnesniDatum, file=sys.stderr)
|
|
sys.exit(1)
|
|
tables = div.find_all("table", {"class": "simple"})
|
|
if len(tables) != 2:
|
|
print('Chyba: neočekávaný počet tabulek na stránce Sladovnické (' +
|
|
str(len(tables)) + '), očekávány 2', file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
foodList: List[Food] = []
|
|
|
|
polevkaValues = tables[0].find_all("td")
|
|
amount = polevkaValues[0].text.strip()
|
|
name = polevkaValues[1].text.strip()
|
|
price = polevkaValues[2].text.strip()
|
|
foodList.append(Food(name, amount, price, True))
|
|
|
|
foodTables = tables[1].find_all("tr")
|
|
for food in foodTables:
|
|
rows = food.find_all("td")
|
|
if (len(rows) != 3):
|
|
print("Neočekávaný počet řádek hlavního jídla Sladovnické (" +
|
|
str(len(rows)) + ", očekávány 3, přeskakuji...")
|
|
continue
|
|
amount = rows[0].text.strip()
|
|
name = rows[1].text.strip()
|
|
price = rows[2].text.strip()
|
|
foodList.append(Food(name, amount, price))
|
|
return foodList
|
|
|
|
|
|
def getMenuUMotliku() -> List[Food]:
|
|
html = getOrDownloadHtml('u_motliku', URL_MOTLICI)
|
|
soup = BeautifulSoup(html, "html.parser")
|
|
table = soup.find("table", {"class": "Xtable-striped"})
|
|
rows = table.find_all("tr")
|
|
if len(rows) < 4:
|
|
print('Chyba: neočekávaný celkový počet řádek tabulky (' +
|
|
str(len(rows)) + '), očekáváno 4 a více', file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
foodList: List[Food] = []
|
|
|
|
if rows[0].td.text.strip() == 'Polévka':
|
|
tds = rows[1].find_all("td")
|
|
if len(tds) != 3:
|
|
print('Chyba: neočekávaný počet <td> elementů v řádce polévky (' +
|
|
str(len(tds)) + '), očekáváno 3', file=sys.stderr)
|
|
sys.exit(1)
|
|
amount = tds[0].text.strip()
|
|
name = tds[1].text.strip()
|
|
price = tds[2].text.strip().replace(',-', '')
|
|
foodList.append(Food(name, amount, price, True))
|
|
rows = rows[2:]
|
|
|
|
if rows[0].td.text.strip() == 'Hlavní jídlo':
|
|
for i in range(1, len(rows)):
|
|
tds = rows[i].find_all("td")
|
|
if len(tds) != 3:
|
|
print("Neočekávaný počet <td> elementů (" + str(len(tds)
|
|
) + ") pro hlavní jídlo " + str(i) + ", přeskakuji")
|
|
continue
|
|
amount = tds[0].text.strip()
|
|
name = tds[1].text.strip()
|
|
price = tds[2].text.strip().replace(',-', '')
|
|
foodList.append(Food(name, amount, price))
|
|
return foodList
|
|
|
|
|
|
def getMenuTechTower() -> List[Food]:
|
|
html = getOrDownloadHtml('techtower', URL_TECHTOWER)
|
|
soup = BeautifulSoup(html, "html.parser")
|
|
fonts = soup.find_all("font", {"class": ["wsw-41"]})
|
|
font = None
|
|
for f in fonts:
|
|
if (f.text.strip().startswith("Obědy")):
|
|
font = f
|
|
if font is None:
|
|
print('Chyba: nenalezen <font> pro obědy v HTML Techtower.', file=sys.stderr)
|
|
sys.exit(1)
|
|
siblings = font.parent.parent.find_next_siblings("p")
|
|
# dayNumber = date.today().strftime("%w")
|
|
currentDayName = getDayNameOfDate(datetime.datetime.now())
|
|
foodList = []
|
|
doParse = False
|
|
for i in range(0, len(siblings)):
|
|
text = siblings[i].text.strip().replace('\t', '').replace('\n', ' ')
|
|
if isNameOfDay(text):
|
|
if text == currentDayName:
|
|
# Našli jsme dnešní den, odtud začínáme parsovat jídla
|
|
doParse = True
|
|
elif doParse == True:
|
|
# Už parsujeme jídla, ale narazili jsme na následující den - končíme
|
|
break
|
|
elif doParse:
|
|
if len(text.strip()) == 0:
|
|
# Prázdná řádka - končíme (je za pátečním menu TechTower)
|
|
break
|
|
price = '? Kč'
|
|
if text.endswith('Kč'):
|
|
split = text.rsplit(' ', 2)
|
|
price = " ".join(split[1:])
|
|
text = split[0]
|
|
foodList.append(Food(text, '-', price, isTextSoupName(text)))
|
|
return foodList
|
|
|
|
|
|
if __name__ == "__main__":
|
|
if len(sys.argv) > 1:
|
|
input = sys.argv[1].lower()
|
|
selectedDate = None
|
|
if input[0].isalpha():
|
|
matches = []
|
|
for day in DAY_NAMES:
|
|
if day.startswith(input):
|
|
matches.append(day)
|
|
if len(matches) == 1:
|
|
print("Match - den v týdnu - " + matches[0])
|
|
selectedDate = getStartOfWeekDate(
|
|
) + timedelta(DAY_NAMES.index(matches[0]))
|
|
elif len(matches) == 0:
|
|
# TODO zkusit v, z (včera, zítra)
|
|
if 'zítra'.startswith(input):
|
|
print("Match - zítra")
|
|
selectedDate = datetime.datetime.now() + timedelta(days=1)
|
|
elif 'včera'.startswith(input):
|
|
print("Match - včera")
|
|
selectedDate = datetime.datetime.now() + timedelta(days=-1)
|
|
elif 'dneska'.startswith(input):
|
|
print("Match - dnes")
|
|
selectedDate = datetime.datetime.now()
|
|
else:
|
|
print('Nejasný parametr "' + input +
|
|
'" - může znamenat jednu z možností: ' + ', '.join(matches), file=sys.stderr)
|
|
sys.exit(1)
|
|
else:
|
|
# TODO implementovat zadání datem
|
|
print('Zadání datem není aktuálně implementováno', file=sys.stderr)
|
|
sys.exit(1)
|
|
print("Datum: " + selectedDate.strftime('%d.%m.%Y'))
|
|
print("Den: " + getDayNameOfDate(selectedDate))
|
|
# printMenu('Sladovnická', getMenuSladovnicka())
|
|
# printMenu('U Motlíků', getMenuUMotliku())
|
|
# printMenu('TechTower', getMenuTechTower())
|