349 lines
11 KiB
Python
349 lines
11 KiB
Python
#! /usr/bin/env python3
|
||
from calendar import monthrange
|
||
from fpdf import FPDF
|
||
import datetime
|
||
from datetime import datetime as datelul
|
||
from bs4 import BeautifulSoup
|
||
import requests
|
||
import os
|
||
|
||
|
||
def is_invalid_date(date_str):
|
||
try:
|
||
datelul.strptime(date_str, "%Y-%m-%d")
|
||
return False
|
||
except ValueError:
|
||
return True
|
||
|
||
|
||
def pdf_safe(text):
|
||
if text is None:
|
||
return ""
|
||
|
||
text = str(text)
|
||
|
||
replacements = {
|
||
"„": '"',
|
||
"“": '"',
|
||
"‚": "'",
|
||
"‘": "'",
|
||
"’": "'",
|
||
"–": "-",
|
||
"—": "-",
|
||
"…": "...",
|
||
"\xa0": " ",
|
||
}
|
||
|
||
for old, new in replacements.items():
|
||
text = text.replace(old, new)
|
||
|
||
# Alles, was nicht latin-1-kompatibel ist, verwerfen
|
||
return text.encode("latin-1", "replace").decode("latin-1")
|
||
|
||
|
||
#### GENERAL DATE CONFIGURATION ####
|
||
months_numeric = ["JANUAR", "FEBRUAR", "MÄRZ", "APRIL", "MAI", "JUNI", "JULI", "AUGUST", "SEPTEMBER", "OKTOBER", "NOVEMBER", "DEZEMBER"]
|
||
months_numeric_lower = ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"]
|
||
date = datetime.datetime.now()
|
||
month_range = monthrange(date.year, date.month)
|
||
month = months_numeric[date.month - 1]
|
||
weekdays_list = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
|
||
counter = 2
|
||
actual_day = datetime.date.today()
|
||
first_day = actual_day.replace(day=1)
|
||
weekday = first_day.weekday()
|
||
|
||
#### URL HTML PARSING ####
|
||
url = os.environ.get("CKAL_CALENDAR_URL")
|
||
if not url:
|
||
raise RuntimeError("CKAL_CALENDAR_URL ist nicht gesetzt.")
|
||
result = requests.get(url, timeout=30)
|
||
result.raise_for_status()
|
||
|
||
doc = BeautifulSoup(result.text, "html.parser")
|
||
table = doc.find_all("tbody")[0]
|
||
tablerows = table.find_all("tr")
|
||
|
||
#### PDF GENERATING PROGRESS ####
|
||
pdf = FPDF("P", "mm", "A4")
|
||
pdf.set_auto_page_break(auto=True, margin=15)
|
||
pdf.add_page()
|
||
|
||
# Header
|
||
pdf.set_font("helvetica", "B", 16)
|
||
pdf.cell(160, 7, pdf_safe("Terminübersicht: " + str(month) + " " + str(date.year)), 0, 1)
|
||
|
||
path = os.path.join(os.path.dirname(__file__), "nak_logo.png")
|
||
assert os.path.isfile(path)
|
||
pdf.image(path, 188, 9.5, 11)
|
||
|
||
pdf.set_font("helvetica", "", 10)
|
||
pdf.cell(160, 5, pdf_safe("der Gemeinde Berlin-Reinickendorf"), 0, 1)
|
||
pdf.cell(0, 2, " ", 0, 1)
|
||
|
||
# Tablehead
|
||
pdf.set_font("helvetica", "B", 10)
|
||
pdf.cell(20, 5, "Datum", 1, 0, "C")
|
||
pdf.cell(15, 5, "Tag", 1, 0, "C")
|
||
pdf.cell(20, 5, "Uhrzeit", 1, 0, "C")
|
||
pdf.cell(75, 5, "Veranstaltung", 1, 0)
|
||
pdf.cell(60, 5, "Ort", 1, 1, "C")
|
||
|
||
pdf.set_font("helvetica", "", 8)
|
||
|
||
# Startposition (heutiges Datum) suchen
|
||
iStart = None
|
||
jStart = None
|
||
|
||
for i in range(len(tablerows)):
|
||
table_cells = tablerows[i].find_all("td")
|
||
for j in range(len(table_cells)):
|
||
table_dates = table_cells[j].get("data-date", "")
|
||
date_for_table = str(table_dates).split("-")
|
||
if len(date_for_table) == 3:
|
||
if (
|
||
date_for_table[0] == str(date.strftime("%Y"))
|
||
and date_for_table[1] == str(date.strftime("%m"))
|
||
and date_for_table[2] == str(date.strftime("%d"))
|
||
):
|
||
iStart = i
|
||
jStart = j
|
||
break
|
||
if jStart is not None:
|
||
break
|
||
|
||
if jStart is None:
|
||
raise RuntimeError("Heutiges Datum wurde im Kalender nicht gefunden.")
|
||
|
||
j = jStart
|
||
|
||
for i in range(len(tablerows)):
|
||
table_cells = tablerows[i].find_all("td")
|
||
table_dates = table_cells[j].get("data-date", "")
|
||
date_for_table = str(table_dates).split("-")
|
||
|
||
if len(date_for_table) != 3:
|
||
break
|
||
|
||
if is_invalid_date(date_for_table[0] + "-" + date_for_table[1] + "-" + date_for_table[2]):
|
||
break
|
||
|
||
# Trennlinie
|
||
pdf.set_fill_color(130)
|
||
pdf.cell(0, 0.3, " ", 0, 1, fill=True)
|
||
|
||
# Wochentag korrigieren
|
||
if weekday == 7:
|
||
weekday = 0
|
||
|
||
# Zeilenfarbe
|
||
if counter % 2 == 0:
|
||
pdf.set_fill_color(255, 255, 255)
|
||
else:
|
||
pdf.set_fill_color(220)
|
||
|
||
# Samstag/Sonntag hervorheben
|
||
pdf.set_font("helvetica", "", 8)
|
||
if weekday == 2 or weekday == 6:
|
||
pdf.set_font("helvetica", "B", 8)
|
||
if weekday == 6:
|
||
pdf.set_fill_color(170, 210, 255)
|
||
|
||
# Heutigen Tag gelb markieren
|
||
if (
|
||
date_for_table[0] == str(date.strftime("%Y"))
|
||
and date_for_table[1] == str(date.strftime("%m"))
|
||
and date_for_table[2] == str(date.strftime("%d"))
|
||
):
|
||
pdf.set_fill_color(255, 255, 0)
|
||
|
||
pdf.cell(20, 4, pdf_safe(date_for_table[2] + "." + date_for_table[1] + "." + date_for_table[0]), 0, 0, "C", fill=True)
|
||
|
||
event_full_block = table_cells[j].find_all("div", class_="calEventBox")
|
||
events = table_cells[j].find_all(
|
||
style=lambda style: style
|
||
and "margin-right:.2em" in style.replace(" ", "")
|
||
)
|
||
|
||
pdf.cell(15, 4, pdf_safe(weekdays_list[weekday]), 0, 0, "C", fill=True)
|
||
|
||
if len(events) == 0:
|
||
pdf.cell(0, 4, " ", 0, 1, fill=True)
|
||
|
||
for k in range(len(events)):
|
||
if k > 0:
|
||
pdf.cell(35, 4, " ", 0, 0, fill=True)
|
||
|
||
event_place = "--"
|
||
pdf.cell(20, 4, " ", 0, 0, "C", fill=True)
|
||
|
||
if k < len(event_full_block):
|
||
event_time = event_full_block[k].find_all(style="font-weight:normal")
|
||
else:
|
||
event_time = []
|
||
|
||
if len(event_time) > 0:
|
||
try:
|
||
elements = str(event_time[0]).split("<")
|
||
except Exception:
|
||
print("error1")
|
||
else:
|
||
if len(elements) > 1 and ">" in elements[1]:
|
||
time_text = elements[1].split(">")[1]
|
||
if ":" in str(time_text):
|
||
pdf.set_x(pdf.get_x() - 20)
|
||
pdf.cell(20, 4, pdf_safe(time_text), 0, 0, "C", fill=True)
|
||
|
||
if len(elements) > 2 and ">" in elements[2]:
|
||
place_text = elements[2].split(">")[1]
|
||
if place_text == "":
|
||
event_place = "--"
|
||
else:
|
||
if str(place_text).startswith(","):
|
||
event_place = str(place_text)[2:]
|
||
else:
|
||
event_place = str(place_text)
|
||
|
||
event_name = events[k].get_text(strip=True) if len(events) > 0 else ""
|
||
pdf.cell(75, 4, pdf_safe(event_name), 0, 0, fill=True)
|
||
pdf.cell(60, 4, pdf_safe(event_place), 0, 1, "C", fill=True)
|
||
|
||
counter += 1
|
||
weekday += 1
|
||
|
||
# Fußzeile
|
||
pdf.set_font("helvetica", "", 8)
|
||
pdf.cell(0, 1, " ", 0, 1)
|
||
pdf.cell(0, 0.1, " ", 1, 1)
|
||
pdf.cell(0, 1, " ", 0, 1)
|
||
pdf.cell(153, 3, pdf_safe("gemeindeleitung@nak-reinickendorf.de"), 0, 0)
|
||
pdf.cell(30, 3, pdf_safe("Klixstraße 17, 13403 Berlin"), 0, 1)
|
||
pdf.set_font("helvetica", "I", 8)
|
||
pdf.cell(153, 3, pdf_safe("Berlin, " + str(date.strftime("%d.%m.%Y %H:%M"))), 0, 0)
|
||
pdf.set_font("helvetica", "", 8)
|
||
pdf.cell(30, 3, pdf_safe("nak-reinickendorf.de"), 0, 1)
|
||
|
||
# Zweite Monats-Spalte / Folgemonat
|
||
if jStart + 1 < 12:
|
||
pdf.cell(0, 4, " ", 0, 1)
|
||
pdf.cell(0, 2, " ", 0, 1)
|
||
|
||
pdf.set_font("helvetica", "B", 16)
|
||
pdf.cell(160, 7, pdf_safe("Terminübersicht: " + str(months_numeric[date.month] + " " + str(date.year))), 0, 1)
|
||
|
||
pdf.set_font("helvetica", "", 10)
|
||
pdf.cell(
|
||
160,
|
||
5,
|
||
pdf_safe("Die Termine für " + str(months_numeric_lower[date.month]) + " befinden sich noch in Planung und können sich ändern."),
|
||
0,
|
||
1,
|
||
)
|
||
pdf.cell(0, 2, " ", 0, 1)
|
||
|
||
# Tablehead
|
||
pdf.set_font("helvetica", "B", 10)
|
||
pdf.cell(20, 5, "Datum", 1, 0, "C")
|
||
pdf.cell(15, 5, "Tag", 1, 0, "C")
|
||
pdf.cell(20, 5, "Uhrzeit", 1, 0, "C")
|
||
pdf.cell(75, 5, "Veranstaltung", 1, 0)
|
||
pdf.cell(60, 5, "Ort", 1, 1, "C")
|
||
|
||
j = jStart + 1
|
||
|
||
for i in range(len(tablerows)):
|
||
table_cells = tablerows[i].find_all("td")
|
||
table_dates = table_cells[j].get("data-date", "")
|
||
date_for_table = str(table_dates).split("-")
|
||
|
||
if len(date_for_table) != 3:
|
||
break
|
||
|
||
if is_invalid_date(date_for_table[0] + "-" + date_for_table[1] + "-" + date_for_table[2]):
|
||
break
|
||
|
||
pdf.set_fill_color(130)
|
||
pdf.cell(0, 0.3, " ", 0, 1, fill=True)
|
||
|
||
if weekday == 7:
|
||
weekday = 0
|
||
|
||
if counter % 2 == 0:
|
||
pdf.set_fill_color(255, 255, 255)
|
||
else:
|
||
pdf.set_fill_color(220)
|
||
|
||
pdf.set_font("helvetica", "", 8)
|
||
if weekday == 2 or weekday == 6:
|
||
pdf.set_font("helvetica", "B", 8)
|
||
if weekday == 6:
|
||
pdf.set_fill_color(170, 210, 255)
|
||
|
||
pdf.cell(20, 4, pdf_safe(date_for_table[2] + "." + date_for_table[1] + "." + date_for_table[0]), 0, 0, "C", fill=True)
|
||
|
||
event_full_block = table_cells[j].find_all("div", class_="calEventBox")
|
||
events = table_cells[j].find_all(style="margin-right:.2em")
|
||
|
||
pdf.cell(15, 4, pdf_safe(weekdays_list[weekday]), 0, 0, "C", fill=True)
|
||
|
||
if len(events) == 0:
|
||
pdf.cell(0, 4, " ", 0, 1, fill=True)
|
||
|
||
for k in range(len(events)):
|
||
if k > 0:
|
||
pdf.cell(35, 4, " ", 0, 0, fill=True)
|
||
|
||
event_place = "--"
|
||
pdf.cell(20, 4, " ", 0, 0, "C", fill=True)
|
||
|
||
if k < len(event_full_block):
|
||
event_time = event_full_block[k].find_all(style="font-weight:normal")
|
||
else:
|
||
event_time = []
|
||
|
||
if len(event_time) > 0:
|
||
try:
|
||
elements = str(event_time[0]).split("<")
|
||
except Exception:
|
||
print("error3")
|
||
else:
|
||
if len(elements) > 1 and ">" in elements[1]:
|
||
time_text = elements[1].split(">")[1]
|
||
if ":" in str(time_text):
|
||
pdf.set_x(pdf.get_x() - 20)
|
||
pdf.cell(20, 4, pdf_safe(time_text), 0, 0, "C", fill=True)
|
||
|
||
if len(elements) > 2 and ">" in elements[2]:
|
||
place_text = elements[2].split(">")[1]
|
||
if place_text == "":
|
||
event_place = "--"
|
||
else:
|
||
if str(place_text).startswith(","):
|
||
event_place = str(place_text)[2:]
|
||
else:
|
||
event_place = str(place_text)
|
||
|
||
event_name = events[k].get_text(strip=True) if len(events) > 0 else ""
|
||
pdf.cell(75, 4, pdf_safe(event_name), 0, 0, fill=True)
|
||
pdf.cell(60, 4, pdf_safe(event_place), 0, 1, "C", fill=True)
|
||
|
||
counter += 1
|
||
weekday += 1
|
||
|
||
# Fußzeile
|
||
pdf.set_font("helvetica", "", 8)
|
||
pdf.cell(0, 1, " ", 0, 1)
|
||
pdf.cell(0, 0.1, " ", 1, 1)
|
||
pdf.cell(0, 1, " ", 0, 1)
|
||
pdf.cell(153, 3, pdf_safe("gemeindeleitung@nak-reinickendorf.de"), 0, 0)
|
||
pdf.cell(30, 3, pdf_safe("Klixstraße 17, 13403 Berlin"), 0, 1)
|
||
pdf.set_font("helvetica", "I", 8)
|
||
pdf.cell(153, 3, pdf_safe("Berlin, " + str(date.strftime("%d.%m.%Y %H:%M"))), 0, 0)
|
||
pdf.set_font("helvetica", "", 8)
|
||
pdf.cell(30, 3, pdf_safe("nak-reinickendorf.de"), 0, 1)
|
||
|
||
#### PDF ERZEUGEN ####
|
||
output_path = os.environ.get("PDF_OUTPUT", "/data/pdf/terminuebersicht.pdf")
|
||
os.makedirs(os.path.dirname(output_path), exist_ok=True)
|
||
pdf.output(output_path)
|