You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

119 lines
4.0 KiB

import configparser
import icalendar
import datetime
import requests
import urllib
import glob
import pytz
import json
import os
def read_config():
config = configparser.ConfigParser()'config.ini')
return config
config = read_config()
current_year =
# request locations supportet by the endpoint
# Returns:
# [{"id":2049161,"name":"Nürnberg"}]
req = requests.get("")
locations = req.json()
for location in locations:
if location.get("name") == config["address"]["city"]:
nbg_id = location.get("id")
# request all known streets for a given location id (can be obtained by previous request)
req = requests.get("{location_id}/strassen".format(location_id=nbg_id))
streets = req.json()
for street in streets:
if street.get("name") == config["address"]["street"]:
street_id = street.get("id")
# request all known house numbers for a given street id (can be obtained by previous request)
req = requests.get("{street_id}".format(street_id=street_id))
housenumbers = req.json().get("hausNrList", [])
for number in housenumbers:
if number.get("nr") == config["address"]["house_number"]:
housenumber_id = number.get("id")
# request trash types picked up at that location
req = requests.get("{housenumber_id}/fraktionen".format(housenumber_id=housenumber_id))
trash_types = req.json()
for trash_type in trash_types:
#requested_trash_types = list(map(lambda x: str(x.get("id")), trash_types))
query = {
"format": ["ics"],
"jahr": [current_year],
"ort": ["Nürnberg"],
"strasse": [street_id],
"hnr": [housenumber_id],
"fraktion": []
radicale_props = {
"C:supported-calendar-component-set": "VEVENT",
"D:displayname": None,
"ICAL:calendar-color": "#000000ff",
"tag": "VCALENDAR"
target_path = config.get("calendar", "target", fallback=os.path.join(".", "calendars"))
if not os.path.exists(target_path):
for trash_type in trash_types:
radicale_props["D:displayname"] = trash_type.get("name")
radicale_props["ICAL:calendar-color"] = "#{}ff".format(trash_type.get("farbeRgb", "000000"))
folder_name = trash_type.get("name").replace("/", "_")
trash_type_folder = os.path.join(target_path, folder_name)
if not os.path.exists(trash_type_folder):
for f in os.listdir(trash_type_folder):
ical_path = os.path.join(trash_type_folder, f)
if os.path.isfile(ical_path):
with open(ical_path, "rb") as fh:
cal = icalendar.Calendar.from_ical(
except ValueError:
print("{} is not an parsable ical file".format(ical_path))
if cal.walk()[1]["DTSTART"].dt >
radicale_prop_file = os.path.join(trash_type_folder, ".Radicale.props")
with open(radicale_prop_file, "w") as f:
query["fraktion"] = [str(trash_type["id"])]
query_string = urllib.parse.urlencode(query, doseq=True)
query_url = urllib.parse.urlunparse(("https", "", "/kalender-nuernberg/downloadfile.jsp", "", query_string, ""))
req = requests.get(query_url)
ical = req.text
cal = icalendar.Calendar.from_ical(ical)
for event in cal.walk():
if isinstance(event,
uid = event.get("UID")
new_cal = icalendar.Calendar()
new_cal.add('prodid', 'Trash dates')
new_cal.add('version', '2.0')
ical_name = "{}_{}.ical".format(current_year, uid)
ical_path = os.path.join(trash_type_folder, ical_name)
with open(ical_path, "wb") as single_file: