#!/usr/bin/env python
# Ruokalistaparseri
# Copyright (c) 2016 Toni Fadjukoff
# Based on food.pl by
# Copyright (c) 2007-2010 Timo Sirainen
# 2011-2016 Toni Fadjukoff
# This is Public Domain
import sys
day_names = [ "Maanantai", "Tiistai", "Keskiviikko", "Torstai",
"Perjantai", "Lauantai", "Sunnuntai" ]
import amica
import sodexo
import juvenes
import campusravita
allergies = [ "M", "L", "VL", "G", "K", "Ve" ]
allergy_descriptions = {
"M": "Maidoton",
"L": "Laktoositon","VL": "Vähälaktoosinen",
"G": "Gluteiiniton",
"K": "Kasvis",
"Ve": "Vegaani"
}
import os
import time
import datetime
import re
global_prefix = "";
use_old = True; # 1 is good for testing, 0 for production system!
unordered = []
l = time.localtime()
this_week = datetime.datetime.now().isocalendar()[1]
unordered += amica.get_restaurants(use_old, this_week)
unordered += juvenes.get_restaurants(use_old, this_week)
unordered += sodexo.get_restaurants(use_old, this_week)
unordered += campusravita.get_restaurants(use_old, this_week)
max_week = 0;
for r in unordered:
week = r[2]
max_week = week if week > max_week or week == 1 else max_week
if l[6] != 0 and this_week != max_week:
# it's not sunday, don't force next week's menu yet
max_week = this_week
stamp = time.time() - 3600*24*7
max_week_daterange = ""
if max_week >= 1 and max_week <= 52:
# figure out the date range
while True:
stamp_week = int(time.strftime("%W", time.localtime(stamp)))
if stamp_week == max_week:
break
stamp += 3600*24
l1 = time.localtime(stamp)
l2 = time.localtime(stamp + 3600*24*6)
if l1[1] == l2[1]:
# same month
max_week_daterange = "{monday}-{sunday}.{month}.".format(monday=l1[2], sunday=l2[2], month=l1[1])
else:
# different months
max_week_daterange = "{monday}.{month}.-{sunday}.{next_month}.".format(monday=l1[2], month=l1[1],
sunday=l2[2], next_month=l2[1])
max_week_daterange = " (" + str(max_week_daterange) + ")"
file_header = '''
Ruokalistat
PNA.fi on kolmannen osapuolen tarjoama palvelu. En voi taata ruokalistojen oikeellisuutta. Virallisen ruokalistan saat näkyviin siirtymällä ravintolan omille sivuille painamalla sen nimestä. Jos huomaat ruokalistassa virheen, nopeiten virhe saadaan pois näkyvistä kun lähetät minulle siitä sähköpostia: lamperi+pna@gmail.com
""".format(stamp=time.strftime("%d.%m.%Y %H:%M:%S"))
def find_last_day_with_foods(restaurants):
last_day = 0
for r in restaurants:
for day in range(7):
if day in r[3]:
last_day = day if day > last_day else last_day
return last_day
def write_days_header(fout, day, last_day):
fout.write( " ")
for i in range(last_day):
if i == day:
fout.write("{0} ".format(day_names[i]))
else:
fout.write("{1} ".format(i+1, day_names[i]))
if day < 0:
fout.write("Taulukko")
else:
fout.write("Taulukko")
fout.write("\n")
def write_prefix_header(fout, prefix, day, resources_prefix):
day = "table" if day == 0 else day
fout.write("")
if prefix == "":
fout.write("Kaikki ")
else:
fout.write("Kaikki ".format(resources_prefix=resources_prefix, day=day))
if prefix == "tay/":
fout.write("TaY ")
else:
fout.write("TaY ".format(resources_prefix=resources_prefix, day=day))
if prefix == "tays/":
fout.write("TAYS ")
else:
fout.write("TAYS ".format(resources_prefix=resources_prefix, day=day))
if prefix == "tty/":
fout.write("TTY ")
else:
fout.write("TTY ".format(resources_prefix=resources_prefix, day=day))
fout.write("\n")
def write_day(day, header, outfname, last_day, restaurants, prefix, resources_prefix):
with open(outfname, "w", encoding="utf-8") as fout:
import types
def write(self, writable):
#print("Writing {}: {}".format(type(writable), writable))
self.write_orig(writable)
fout.write_orig = fout.write
fout.write = types.MethodType(write, fout)
fout.write(file_header.format(resources_prefix=resources_prefix))
fout.write("
\n")
write_days_header(fout, day, last_day)
fout.write(" Näytä: ")
for a in allergies:
fout.write("".format(a=a))
fout.write("{a}".format(allergy_description=allergy_descriptions[a], a=a))
fout.write("\n")
write_prefix_header(fout, prefix, day+1, resources_prefix);
fout.write("
\n")
# print foods
foodnum = 0
eatable_food_numbers = {}
maybe_eatable_food_numbers = {}
for a in allergies:
eatable_food_numbers[a] = []
maybe_eatable_food_numbers[a] = []
css_class = "left"
fout.write("
\n".format(css_class=css_class))
for r in restaurants:
title, open_hours, week, week_foods, info = r
title2, url, lazy_allergies, info_class = info[0:4]
if day in week_foods or day < 5:
if info_class != css_class:
css_class = info_class
fout.write("
\n".format(url=url, title=title))
if not day in week_foods:
fout.write("
Ruokalistaa ei saatavilla.
")
continue
if week != "" and week != max_week:
if week > max_week or (week == 1 and max_week == 52):
# early..
fout.write("
Viikon {week} ruokalista:
".format(week=week))
else:
fout.write("
Saatavilla vain viikon {week} ruokalista.
".format(week=week))
continue
if len(week_foods[day]) == 0:
fout.write("
Ei ruokatietoja päivälle.
")
continue
fout.write("
\n")
for food in week_foods[day]:
output = []
total_allergies = {}
maybe_allergies = {}
for a in allergies:
total_allergies[a] = 0
maybe_allergies[a] = 0
part_count = 0
for part in food.split("\n"):
# who cares?
if re.match("Peruna|Riisi", part):
continue
# fries: well, maybe we do care, but we don't care about allergy stuff
# and keep it in the same line as the previous food so as not to
# waste visible space
(part, fries) = re.subn("Tikkuperunat|Ranskalaiset perunat", "", part)
fries = fries > 0
part_count += 1
# add missing () around allergies
part = re.sub(" (([MLGKA]|VL|Ve|VE|Veg|Hot)(, *([MLGKA]|VL|Ve|VE|Veg|Hot|))+)$", " (\\1)", part)
match = re.match("^(.*) \\(([^\\)]+)\\)$", part)
if match:
# fix allergy issues
food = match.group(1)
allergy = match.group(2)
# standardization
allergy = re.sub("Kasvis", "K", allergy)
allergy = re.sub("([MLGK]|VL)([MLGK]|[VL])", "\\1,\\2", allergy)
# spaces to commas
allergy = re.sub("saatavana[: ]+(.*)$", "eriks: \\1", allergy)
allergy = re.sub(" +", ",", allergy)
# remove double commas
allergy = re.sub(",+", ",", allergy)
# eriks: standardization
allergy = re.sub(",?eriks:,?", ", eriks: ", allergy)
# remove extra commas/spaces from beginning/end
allergy = re.sub("^[, ]+", "", allergy)
allergy = re.sub("[, ]+$", "", allergy)
part = "{food} ({allergy})".format(food=food, allergy=allergy)
if output and not fries:
output.append(" \n")
match = re.search("Saatavana myös: (.*)", part)
if match:
alt = match.group(1)
alt = re.sub(r"^\((.*)\)$", r"\1", alt)
alt = re.sub("[, ]+", r",", alt)
alt = re.sub("^,+", "", alt)
alt = re.sub(",+$", "", alt)
part = re.sub(r"\)[- ]*Saatavana myös:.*", "eriks: {alt})".format(alt=alt), part)
part = re.sub(r"[- ]*Saatavana myös:.*", "(eriks: {alt})".format(alt=alt), part)
match = re.match(r"^(.*)(\([^\)]+\))$", part)
if match:
text = match.group(1)
allergy = match.group(2)
if fries:
output.append(", {text}".format(text=text))
else:
output.append("{text} {allergy}".format(text=text, allergy=allergy))
allergy = re.sub(r"^\((.*)\)$", r"\1", allergy)
allergy = re.sub(" *eriks: ", "", allergy)
this_allergies = set()
for a in re.split("[, ]", allergy):
for al in allergies:
if a == al:
this_allergies.add(a)
break
if "L" in this_allergies:
this_allergies.add("VL")
for a in this_allergies:
if a in total_allergies:
total_allergies[a] += 1
if a in maybe_allergies:
maybe_allergies[a] += 1
match = re.search("M", lazy_allergies)
if match:
if "L" in this_allergies and not "M" in this_allergies:
maybe_allergies["M"] += 1
else:
if lazy_allergies == "all":
for a in allergies:
maybe_allergies[a] += 1
output.append(part)
allergy_output = ""
for a in allergies:
if total_allergies[a] == part_count:
eatable_food_numbers[a].append(foodnum)
elif maybe_allergies[a]== part_count:
maybe_eatable_food_numbers[a].append(foodnum)
fout.write("
\n".format(day_name=day_names[day]))
for r in restaurants:
(title, open_hours, week, week_foods, info) = r
if day in week_foods and (week == "" or week == max_week):
fout.write("
\n")
for food in week_foods[day]:
fout.write("
{food}
".format(food=food))
fout.write("
\n")
else:
fout.write("
\n")
fout.write("
{file_footer}".format(file_footer=file_footer.format(resources_prefix=resources_prefix)))
def get_restaurants_sorted(restaurants):
# consider writing comparator
out = []
for r in restaurants:
if r[4][3] == "left":
out.append(r)
for r in restaurants:
if r[4][3] == "right":
out.append(r)
for r in restaurants:
if r[4][3] == "middle" and not re.search("TAMK", r[4][0]):
out.append(r)
for r in restaurants:
if r[4][3] == "middle" and re.search("TAMK", r[4][0]):
out.append(r)
return out
def get_restaurants_with_prefix(prefix, restaurants):
out = []
for r in restaurants:
if re.search(prefix, r[4][0]):
out.append(r)
return get_restaurants_sorted(out)
tty_title = "TTY:n ruokalistat"
tty = get_restaurants_with_prefix("TTY", unordered)
write_all_days(tty, "tty/", tty_title, "../")
write_table(tty, "tty/", tty_title, "../")
tay_title = "Tampereen yliopiston ruokalistat"
tay = get_restaurants_with_prefix("TaY", unordered)
write_all_days(tay, "tay/", tay_title, "../")
write_table(tay, "tay/", tay_title, "../")
tays_title = "TAYS:n ruokalistat"
tays = get_restaurants_with_prefix("TAYS", unordered)
write_all_days(tays, "tays/", tays_title, "../")
write_table(tays, "tays/", tays_title, "../")
for r in unordered:
if re.search(r"^\(TaY\)", r[0]):
r[4][3] = "left"
if re.search(r"^\(TTY\)", r[0]):
r[4][3] = "right"
if re.search(r"^\(TAYS\)", r[0]):
r[4][3] = "middle"
all_title = "Tampereen yliopistojen ruokalistat";
all_restaurants = get_restaurants_sorted(unordered);
# move fusion kitchen last
#fusion = splice(@all_restaurants, 1, 1);
#splice(@all_restaurants, 4, 0, @fusion);
write_all_days(all_restaurants, "", all_title, "");
write_table(all_restaurants, "", all_title, "");