add lots of custom translations for german sources

This commit is contained in:
5ila5
2024-07-22 21:18:59 +02:00
committed by 5ila5
parent 997fac17c2
commit c7bfad5761
63 changed files with 898 additions and 213 deletions

View File

@@ -26,6 +26,15 @@ TEST_CASES = {
},
}
PARAM_TRANSLATIONS = {
"de": {
"city": "Ort",
"street": "Straße",
"postcode": "PLZ",
"house_number": "Hausnummer",
}
}
class Source:
def __init__(self, city, postcode, street, house_number):

View File

@@ -56,6 +56,13 @@ SPECIAL_CHARS = str.maketrans(
)
LOGGER = logging.getLogger(__name__)
PARAM_TRANSLATIONS = {
"de": {
"zip_code": "PLZ",
"district": "Ort",
}
}
class Source:
def __init__(self, district: str, zip_code: str):

View File

@@ -1,16 +1,27 @@
import requests
from bs4 import BeautifulSoup
from waste_collection_schedule import Collection # type: ignore[attr-defined]
from waste_collection_schedule.service.ICS import ICS
from bs4 import BeautifulSoup
TITLE = "ASR Stadt Chemnitz"
DESCRIPTION = "Source for ASR Stadt Chemnitz."
URL = "https://www.asr-chemnitz.de"
TEST_CASES = {
"Hübschmannstr. 4": {"street": "Hübschmannstr.", "house_number": "4"},
"Carl-von-Ossietzky-Str 94": {"street": "Carl-von-Ossietzky-Str", "house_number": 94},
"Wasserscheide 5 (2204101)": {"street": "Wasserscheide", "house_number": "5", "object_number": "2204101"},
"Wasserscheide 5 (89251)": {"street": "Wasserscheide", "house_number": "5", "object_number": 89251},
"Carl-von-Ossietzky-Str 94": {
"street": "Carl-von-Ossietzky-Str",
"house_number": 94,
},
"Wasserscheide 5 (2204101)": {
"street": "Wasserscheide",
"house_number": "5",
"object_number": "2204101",
},
"Wasserscheide 5 (89251)": {
"street": "Wasserscheide",
"house_number": "5",
"object_number": 89251,
},
"Damaschkestraße 36": {"street": "Damaschkestr.", "house_number": "36"},
}
@@ -26,8 +37,19 @@ ICON_MAP = {
API_URL = "https://asc.hausmuell.info/ics/ics.php"
PARAM_TRANSLATIONS = {
"de": {
"street": "Straße",
"house_number": "Hausnummer",
"object_number": "Objektnummer",
}
}
class Source:
def __init__(self, street: str, house_number: str | int, object_number: str | int = ""):
def __init__(
self, street: str, house_number: str | int, object_number: str | int = ""
):
self._street: str = street
self._house_number: str = str(house_number)
self._object_number: str = str(object_number)
@@ -55,23 +77,21 @@ class Source:
r = requests.post("https://asc.hausmuell.info/proxy.php", data=args)
r.raise_for_status()
soup = BeautifulSoup(r.text, "html.parser")
street_id = soup.find("span").text.strip()
egebiet_id = soup.find_all("span")[1].text.strip()
if egebiet_id == "0":
if self._object_number == "":
raise Exception("No object number provided but needed")
args["input"] = self._object_number
args["url"] = 7
args["url"] = 7
r = requests.post("https://asc.hausmuell.info/proxy.php", data=args)
r.raise_for_status()
r.raise_for_status()
soup = BeautifulSoup(r.text, "html.parser")
egebiet_id = soup.find_all("span")[1].text.strip()
# get dates
args = {
"input_str": self._street,
@@ -104,7 +124,6 @@ class Source:
for d in dates:
bin_type = d[1].replace("Entsorgung:", "").strip()
entries.append(Collection(
d[0], bin_type, ICON_MAP.get(bin_type)))
entries.append(Collection(d[0], bin_type, ICON_MAP.get(bin_type)))
return entries

View File

@@ -54,6 +54,16 @@ class HiddenInputParser(HTMLParser):
self._args[d["name"]] = d["value"] if "value" in d else ""
PARAM_TRANSLATIONS = {
"de": {
"city": "Ort",
"street": "Straße",
"house_number": "Hausnummer",
"address_suffix": "Hausnummerzusatz",
}
}
class Source:
def __init__(
self, city: str, street: str, house_number: int, address_suffix: str = ""

View File

@@ -19,6 +19,14 @@ API_URL = "https://www.oldenburg.de/startseite/leben-umwelt/awb/awb-von-a-bis-z/
_LOGGER = logging.getLogger(__name__)
PARAM_TRANSLATIONS = {
"de": {
"street": "Straße",
"house_number": "Hausnummer",
}
}
class Source:
def __init__(self, street, house_number):
self._street = street

View File

@@ -10,6 +10,14 @@ URL = "https://www.awbkoeln.de"
TEST_CASES = {"Koeln": {"street_code": 2, "building_number": 50}}
PARAM_TRANSLATIONS = {
"de": {
"street_code": "Straßencode",
"building_number": "Hausnummer",
}
}
class Source:
def __init__(self, street_code, building_number):
self._street_code = street_code

View File

@@ -33,6 +33,15 @@ ICON_MAP = {
}
PARAM_TRANSLATIONS = {
"de": {
"building_number": "Hausnummer",
"street_name": "Straßenname",
"street_code": "Straßencode",
}
}
class Source:
def __init__(
self,

View File

@@ -1,7 +1,7 @@
import requests
import urllib3
from html.parser import HTMLParser
import requests
import urllib3
from waste_collection_schedule import Collection # type: ignore[attr-defined]
from waste_collection_schedule.service.ICS import ICS
@@ -39,6 +39,16 @@ SERVLET = (
"https://athos.awn-online.de/WasteManagementNeckarOdenwald/WasteManagementServlet"
)
PARAM_TRANSLATIONS = {
"de": {
"city": "Ort",
"street": "Straße",
"house_number": "Hausnummer",
"address_suffix": "Hausnummerzusatz",
}
}
# Parser for HTML input (hidden) text
class HiddenInputParser(HTMLParser):
def __init__(self):

View File

@@ -13,6 +13,13 @@ TEST_CASES = {
_LOGGER = logging.getLogger(__name__)
PARAM_TRANSLATIONS = {
"de": {
"city": "Ort",
"street": "Straße",
}
}
class Source:
def __init__(self, city, street):

View File

@@ -13,6 +13,13 @@ TEST_CASES = {
_LOGGER = logging.getLogger(__name__)
PARAM_TRANSLATIONS = {
"de": {
"city": "Ort",
"street": "Straße",
}
}
class Source:
def __init__(self, city, street):

View File

@@ -17,6 +17,14 @@ TEST_CASES = {
SERVICE_URL = "https://kundenportal.berlin-recycling.de/"
PARAM_TRANSLATIONS = {
"de": {
"username": "Benutzername",
"password": "Passwort",
}
}
class Source:
def __init__(self, username, password):
self._username = username
@@ -44,13 +52,13 @@ class Source:
serviceUrl = f"{SERVICE_URL}Default.aspx"
# get the default view (might not needed, but is a good check the login worked)
response = session.get('https://kundenportal.berlin-recycling.de/Default.aspx')
response = session.get("https://kundenportal.berlin-recycling.de/Default.aspx")
if response.history:
raise Exception ('The default view request was redirected to ' + response.url)
headers = {
'Content-Type': 'application/json'
}
raise Exception(
"The default view request was redirected to " + response.url
)
headers = {"Content-Type": "application/json"}
r = session.post(f"{serviceUrl}/GetDashboard", headers=headers)
r.raise_for_status()
@@ -63,9 +71,11 @@ class Source:
"ordername": "",
"orderdir": "",
"ClientParameters": "",
"headrecid": ""
"headrecid": "",
}
r = session.post(f"{serviceUrl}/GetDatasetTableHead", json=request_data, headers=headers)
r = session.post(
f"{serviceUrl}/GetDatasetTableHead", json=request_data, headers=headers
)
data = json.loads(r.text)
# load json again, because response is double coded
@@ -74,7 +84,7 @@ class Source:
entries = []
if "Object" not in data or "data" not in data["Object"]:
raise Exception("No data found", data)
for d in data["Object"]["data"]:
date = datetime.strptime(d["Task Date"], "%Y-%m-%d").date()
entries.append(Collection(date, d["Material Description"]))

View File

@@ -68,6 +68,15 @@ class HiddenInputParser(HTMLParser):
self._radio_args = new_radio
PARAM_TRANSLATIONS = {
"de": {
"street": "Straße",
"house_number": "Hausnummer",
"address_suffix": "Hausnummerzusatz",
}
}
class Source:
def __init__(self, street: str, house_number: int, address_suffix: str = ""):
self._street = street

View File

@@ -81,6 +81,14 @@ def downloadChristmastreeICS(s, abf_strasse, abf_hausnr):
return r.text
PARAM_TRANSLATIONS = {
"de": {
"abf_strasse": "Straße",
"abf_hausnr": "Hausnummer",
}
}
class Source:
def __init__(self, abf_strasse, abf_hausnr):
self._abf_strasse = abf_strasse

View File

@@ -92,6 +92,17 @@ SERVICE_MAP = [
},
]
PARAM_TRANSLATIONS = {
"de": {
"operator": "Betreiber",
"district": "Ort",
"street": "Straße",
"subdistrict": "Ortsteil",
"number": "Hausnummer",
"show_volume": "Große Container anzeigen",
}
}
# This datalcass is used for adding entries to a set and remove duplicate entries.
# The default `Collection` extends the standard dict and thus is not hashable.

View File

@@ -158,6 +158,18 @@ SERVICE_MAP = {
BASE_URL = "https://{subdomain}.c-trace.de"
PARAM_TRANSLATIONS = {
"en": {
"strasse": "Street",
"hausnummer": "House number",
"gemeinde": "Municipality",
"ort": "District",
"ortsteil": "Subdistrict",
"service": "Operator",
}
}
class Source:
def __init__(
self,

View File

@@ -20,6 +20,12 @@ ICON_MAP = {
"PAPER": "mdi:newspaper",
}
PARAM_TRANSLATIONS = {
"de": {
"street": "Straße",
}
}
class Source:
def __init__(self, street):

View File

@@ -33,6 +33,12 @@ ICON_MAP = {
"Gelbesäcke Abholung": "mdi:recycle",
}
PARAM_TRANSLATIONS = {
"de": {
"street": "Straße",
}
}
class Source:
def __init__(self, street: str):
@@ -40,7 +46,6 @@ class Source:
self._ics = ICS()
def fetch(self):
# the url contains the current year, but this doesn't really seems to matter at least for the ical, since the result is always the same
# still replace it for compatibility sake
now = datetime.now()

View File

@@ -25,6 +25,12 @@ ICON_MAP = { # Optional: Dict of waste types and suitable mdi icons
"PPK": "mdi:package-variant",
}
PARAM_TRANSLATIONS = {
"de": {
"street": "Straße",
}
}
class Source:
def __init__(

View File

@@ -39,6 +39,15 @@ ICON_MAP = {
"Braun": "mdi:leaf",
}
PARAM_TRANSLATIONS = {
"de": {
"city": "Ort",
"district": "Ortsteil",
"street": "Straße",
"housenumber": "Hausnummer",
}
}
class Source:
def __init__(self, city, district, street, housenumber):

View File

@@ -23,6 +23,12 @@ ICON_MAP = {
"Papiercontainer": "mdi:package-variant",
"Gelbe(r) Sack/Tonne": "mdi:recycle",
}
PARAM_TRANSLATIONS = {
"de": {
"city": "Ort",
"street": "Straße",
}
}
class Source:

View File

@@ -14,6 +14,14 @@ TEST_CASES = {
}
PARAM_TRANSLATIONS = {
"de": {
"city": "Ort",
"street": "Straße",
}
}
class Source:
def __init__(self, city, street):
self._city = city

View File

@@ -19,6 +19,13 @@ TEST_CASES = {
API_URL = "https://www.geoport-nwm.de/nwm-download/Abfuhrtermine/ICS/{year}/{arg}.ics"
PARAM_TRANSLATIONS = {
"de": {
"district": "Ortsteil",
}
}
class Source:
def __init__(self, district):
self._district = district

View File

@@ -191,6 +191,24 @@ def replace_special_chars_args(d: dict, replace_func=replace_special_chars) -> d
return to_return
PARAM_TRANSLATIONS = {
"de": {
"subdomain": "Subdomain",
"ort": "Ort",
"ortsteil": "Ortsteil",
"strasse": "Straße",
"hausnummer": "Hausnummer",
},
"en": {
"subdomain": "Subdomain",
"ort": "City",
"ortsteil": "District",
"strasse": "Street",
"hausnummer": "House number",
},
}
class Source:
def __init__(
self,

View File

@@ -49,6 +49,19 @@ ICON_MAP = {
"christmastree": "mdi:pine-tree",
}
PARAM_TRANSLATIONS = {
"de": {
"plz": "PLZ",
"strasse": "Straße",
"hausnr": "Hausnummer",
},
"en": {
"plz": "Zip Code",
"strasse": "Street",
"hausnr": "House number",
},
}
class Source:
def __init__(self, plz: int, strasse: str, hausnr: str | int | None = None):

View File

@@ -105,6 +105,24 @@ HEADERS = {"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
_LOGGER = logging.getLogger(__name__)
PARAM_TRANSLATIONS = {
"de": {
"url": "URL",
"file": "Datei",
"offset": "Offset",
"params": "Parameter",
"year_field": "Jahresfeld",
"method": "Methode",
"regex": "Regulärer Ausdruck",
"title_template": "Titelvorlage",
"split_at": "Trennen bei",
"version": "Version",
"verify_ssl": "SSL-Verifizierung aktivieren",
"headers": "Headers",
}
}
class Source:
def __init__(
self,

View File

@@ -46,6 +46,17 @@ TEST_CASES = {
}
PARAM_TRANSLATIONS = {
"de": {
"customer": "Kunde",
"zone": "Zone",
"city": "Ort",
"street": "Straße",
"housenumber": "Hausnummer",
}
}
class Source:
def __init__(self, customer, zone=None, city=None, street=None, housenumber=None):
self._customer = customer

View File

@@ -1,12 +1,10 @@
import json
import requests
from datetime import datetime
import requests
from waste_collection_schedule import Collection # type: ignore[attr-defined]
from waste_collection_schedule.service.InsertITDe import SERVICE_MAP
from waste_collection_schedule.service.ICS import ICS
from waste_collection_schedule.service.InsertITDe import SERVICE_MAP
TITLE = "Insert IT Apps"
DESCRIPTION = "Source for Apps by Insert IT"
@@ -17,25 +15,16 @@ COUNTRY = "de"
def EXTRA_INFO():
return [{"title": s["title"], "url": s["url"]} for s in SERVICE_MAP]
TEST_CASES = {
"Offenbach Address": {
"municipality": "Offenbach",
"street": "Kaiserstraße",
"hnr": 1
"hnr": 1,
},
"Offenbach Location ID": {
"municipality": "Offenbach",
"location_id": 7036
},
"Mannheim Address": {
"municipality": "Mannheim",
"street": "A 3",
"hnr": 1
},
"Mannheim Location ID": {
"municipality": "Mannheim",
"location_id": 430650
}
"Offenbach Location ID": {"municipality": "Offenbach", "location_id": 7036},
"Mannheim Address": {"municipality": "Mannheim", "street": "A 3", "hnr": 1},
"Mannheim Location ID": {"municipality": "Mannheim", "location_id": 430650},
}
@@ -62,7 +51,7 @@ ICON_MAP = {
"Bio": {"icon": "mdi:leaf", "name": "Biomüll"},
"Papier": {"icon": "mdi:package-variant", "name": "Altpapier"},
"Grünschnitt": {"icon": "mdi:leaf", "name": "Grünschnitt"},
}
},
}
REGEX_MAP = {
@@ -75,6 +64,15 @@ REGEX_MAP = {
"Offenbach": r"Leerung:\s+(.*)\s+\(.*\)",
}
PARAM_TRANSLATIONS = {
"de": {
"municipality": "Ort",
"street": "Straße",
"hnr": "Hausnummer",
"location_id": "Standort ID",
}
}
class Source:
def __init__(self, municipality, street=None, hnr=None, location_id=None):
@@ -87,17 +85,17 @@ class Source:
municipalities = MUNICIPALITIES
if municipality not in municipalities:
raise Exception(f"municipality '{municipality}' not found")
self._api_url = f"https://www.insert-it.de/{municipalities[municipality]}"
self._ics = ICS(regex=REGEX_MAP.get(municipality))
# Check if at least either location_id is set or both street and hnr are set
if not ((location_id is not None) or (street is not None and hnr is not None)):
raise Exception("At least either location_id should be set or both street and hnr should be set.")
self._uselocation = location_id is not None
raise Exception(
"At least either location_id should be set or both street and hnr should be set."
)
self._uselocation = location_id is not None
def get_street_id(self):
"""Return ID of matching street"""
@@ -117,9 +115,8 @@ class Source:
if element["Name"] == self._street:
street_id = element["ID"]
return street_id
raise Exception(f"Street {self._street} not found")
def get_location_id(self, street_id):
"""Return ID of first matching location"""
@@ -133,18 +130,20 @@ class Source:
result = json.loads(r.text)
if not result:
raise Exception(f"No locations found for Street ID {street_id} and House number {self._hnr}")
raise Exception(
f"No locations found for Street ID {street_id} and House number {self._hnr}"
)
for element in result:
if element["StreetId"] == street_id and element["Text"] == str(self._hnr):
location_id = element["ID"]
return location_id
raise Exception(f"Location for Street ID {street_id} with House number {self._hnr} not found")
raise Exception(
f"Location for Street ID {street_id} with House number {self._hnr} not found"
)
def fetch(self):
if not (self._uselocation):
street_id = self.get_street_id()
self._location = self.get_location_id(street_id)
@@ -156,7 +155,6 @@ class Source:
entries += self.fetch_year(now.year + 1)
return entries
def fetch_year(self, year):
s = requests.Session()
params = {"bmsLocationId": self._location, "year": year}
@@ -182,4 +180,4 @@ class Source:
else:
entries.append(Collection(d[0], d[1]))
return entries
return entries

View File

@@ -195,6 +195,17 @@ def EXTRA_INFO():
API_URL = "https://{provider}.jumomind.com/mmapp/api.php"
PARAM_TRANSLATIONS = {
"de": {
"service_id": "Service ID",
"city": "Ort",
"street": "Straße",
"city_id": "Ort ID",
"area_id": "Bereich ID",
"house_number": "Hausnummer",
}
}
LOGGER = logging.getLogger(__name__)

View File

@@ -48,6 +48,20 @@ ICON_MAP = {
API_URL = "https://web{i}.karlsruhe.de/service/abfall/akal/akal_{year}.php"
PARAM_TRANSLATIONS = {
"de": {
"street": "Straße",
"hnr": "Hausnummer",
"ladeort": "Ladeort",
},
"en": {
"street": "Street",
"hnr": "House number",
"ladeort": "Loading point",
},
}
class Source:
def __init__(self, street: str, hnr: str | int, ladeort: int | None = None):
self._street: str = street

View File

@@ -4,7 +4,8 @@ from urllib.parse import urljoin
import requests
from bs4 import BeautifulSoup
from waste_collection_schedule import Collection # type: ignore[attr-defined]
from waste_collection_schedule.service.ICS import ICS # type: ignore[attr-defined]
from waste_collection_schedule.service.ICS import \
ICS # type: ignore[attr-defined]
TITLE = "Stadtservice Korneuburg"
DESCRIPTION = "Source for Stadtservice Korneuburg"
@@ -28,6 +29,20 @@ WASTE_TYPE_URLS = {
}
PARAM_TRANSLATIONS = {
"de": {
"street_name": "Straßenname",
"street_number": "Hausnummer",
"teilgebiet": "Teilgebiet",
},
"en": {
"street_name": "Street Name",
"street_number": "Street Number",
"teilgebiet": "Subarea",
},
}
class Source:
def __init__(self, street_name, street_number, teilgebiet=-1):
self.street_name = street_name
@@ -43,7 +58,6 @@ class Source:
@staticmethod
def extract_street_numbers(soup):
scripts = soup.findAll("script", {"type": "text/javascript"})
street_number_idx = 0
@@ -190,7 +204,6 @@ class Source:
return entries
def fetch(self):
ical_urls = self.get_region_links()
all_entries = []

View File

@@ -17,7 +17,7 @@ TEST_CASES = {
"Grundschule": {
"village": "Bebertal (Eiche/Hüsig)",
"street": "Am Drei",
"house_number": "11",
"house_number": 11,
},
"KS Börde": {
"village": "Wolmirstedt",
@@ -37,8 +37,17 @@ ICON_MAP = {
}
PARAM_TRANSLATIONS = {
"de": {
"village": "Ort",
"street": "Straße",
"house_number": "Hausnummer",
}
}
class Source:
def __init__(self, village: str, street: str, house_number: str):
def __init__(self, village: str, street: str, house_number: str | int):
self._village = village
self._street = street
self._house_number = house_number
@@ -69,7 +78,7 @@ class Source:
# convert text into ICS object
return self._ics.convert(ics)
def get_from_proxy(self, village: int = 0, street: int = 0, input: str = ""):
def get_from_proxy(self, village: int = 0, street: int = 0, input: str | int = ""):
post_data = {
"input": input,
"ort_id": village,

View File

@@ -20,6 +20,16 @@ ICON_MAP = {
}
PARAM_TRANSLATIONS = {
"de": {
"pois": "POIS",
},
"en": {
"pois": "POIS",
},
}
class Source:
def __init__(self, pois):
self.ics = ICS()

View File

@@ -23,6 +23,15 @@ ICON_MAP = {
}
PARAM_TRANSLATIONS = {
"de": {
"city": "Ort",
"street": "Straße",
"number": "Hausnummer",
}
}
class Source:
def __init__(self, city, street, number):
self._city = city.strip().lower()

View File

@@ -11,34 +11,44 @@ TEST_CASES = {
"City only": {"city": "Ostheim"},
"City + District": {"city": "Ostheim", "district": "Oberwaldbehrungen"},
"District only": {"district": "Oberwaldbehrungen"},
"empty": {}
"empty": {},
}
API_URL = 'https://fs-api-rg.offizium.com/abfalltermine'
API_URL = "https://fs-api-rg.offizium.com/abfalltermine"
EVENT_BLACKLIST = ['Wertstoffhof Mellrichstadt',
'Wertstoffhof Bad Königshofen', 'Wertstoffzentrum Bad Neustadt',
'Wertstoffsammelstelle Ostheim',
'Wertstoffsammelstelle Bischofsheim']
EVENT_BLACKLIST = [
"Wertstoffhof Mellrichstadt",
"Wertstoffhof Bad Königshofen",
"Wertstoffzentrum Bad Neustadt",
"Wertstoffsammelstelle Ostheim",
"Wertstoffsammelstelle Bischofsheim",
]
ICON_MAP = {
"Restmüll/Biotonne": "mdi:trash-can",
"Gelbe Tonne": "mdi:recycle-variant",
"Papiersammlung": "mdi:package-variant",
"Problemmüllsammlung": "mdi:biohazard"
"Problemmüllsammlung": "mdi:biohazard",
}
PARAM_TRANSLATIONS = {
"de": {
"city": "Ort",
"district": "Ortsteil",
}
}
class Source:
def __init__(self, city: str = None, district: str = None):
def __init__(self, city: str | None = None, district: str | None = None):
self._city = city
self._district = district
def fetch(self):
r = requests.get(API_URL, params={
"stadt": self._city,
"ortsteil": self._district
})
r = requests.get(
API_URL, params={"stadt": self._city, "ortsteil": self._district}
)
r.raise_for_status()
@@ -48,11 +58,9 @@ class Source:
if event["muellart"] not in EVENT_BLACKLIST:
entries.append(
Collection(
date=datetime.datetime.fromisoformat(
event["termin"]).date(),
date=datetime.datetime.fromisoformat(event["termin"]).date(),
t=event["muellart"],
icon=ICON_MAP.get(
event["muellart"], "mdi:trash-can")
icon=ICON_MAP.get(event["muellart"], "mdi:trash-can"),
)
)

View File

@@ -1,8 +1,9 @@
import requests
import json
import requests
from bs4 import BeautifulSoup
from waste_collection_schedule import Collection # type: ignore[attr-defined]
from waste_collection_schedule.service.ICS import ICS
from bs4 import BeautifulSoup
TITLE = "Landkreis Wittmund"
DESCRIPTION = "Source for Landkreis Wittmund waste collection."
@@ -22,6 +23,14 @@ AUTOCOMPLETE_URL = "https://www.landkreis-wittmund.de/output/autocomplete.php?ou
DOWNLOAD_URL = "https://www.landkreis-wittmund.de/output/options.php?ModID=48&call=ical&ArtID%5B0%5D=3105.1&ArtID%5B1%5D=1.4&ArtID%5B2%5D=1.2&ArtID%5B3%5D=1.3&ArtID%5B4%5D=1.1&pois={}&alarm=0"
PARAM_TRANSLATIONS = {
"de": {
"city": "Ort",
"street": "Straße",
}
}
class Source:
def __init__(self, city, street=None):
self._city = city
@@ -35,39 +44,31 @@ class Source:
return self.fetch_ics(DOWNLOAD_URL.format(streetId))
def is_city_selection(self, tag, cityName):
return tag['value'] != "" and tag.string == self._city
return tag["value"] != "" and tag.string == self._city
def fetch_city_id(self, cityName):
r = requests.get(API_URL)
if not r.ok:
raise Exception(
"Error: failed to fetch url: {}".format(
API_URL
)
)
raise Exception(f"Error: failed to fetch url: {API_URL}")
soup = BeautifulSoup(r.text, 'html.parser')
citySelection = [ a for a in soup.select('#sf_locid > option[value]') if self.is_city_selection(a, cityName) ]
soup = BeautifulSoup(r.text, "html.parser")
citySelection = [
a
for a in soup.select("#sf_locid > option[value]")
if self.is_city_selection(a, cityName)
]
if len(citySelection) == 0:
raise Exception(
"Error: could not find id for city: '{}'".format(
cityName
)
)
raise Exception(f"Error: could not find id for city: '{cityName}'")
if len(citySelection) > 1:
raise Exception(
"Error: non-unique match for city: '{}'".format(
cityName
)
)
raise Exception(f"Error: non-unique match for city: '{cityName}'")
return citySelection[0]['value']
return citySelection[0]["value"]
def fetch_street_id(self, cityId, streetName):
r = requests.get(AUTOCOMPLETE_URL.format(cityId, streetName), headers={
"Referer": API_URL
})
r = requests.get(
AUTOCOMPLETE_URL.format(cityId, streetName), headers={"Referer": API_URL}
)
if not r.ok:
raise Exception(
@@ -78,39 +79,31 @@ class Source:
streets = json.loads(r.text)
if streetName != None:
streetId = [ item[0] for item in streets if streetName in item[1] ]
streetId = [item[0] for item in streets if streetName in item[1]]
else:
streetId = [ item[0] for item in streets ]
streetId = [item[0] for item in streets]
if len(streetId) == 0:
raise Exception(
"Error: could not find streets for city id / street: {}, '{}'".format(
cityId,
streetName
cityId, streetName
)
)
if len(streetId) > 1:
raise Exception(
"Error: non-unique match for city id / street: {}, '{}'".format(
cityId,
streetName
cityId, streetName
)
)
return streetId[0]
def fetch_ics(self, url):
r = requests.get(url, headers={
"Referer": API_URL
})
r = requests.get(url, headers={"Referer": API_URL})
if not r.ok:
raise Exception(
"Error: failed to fetch url: {}".format(
url
)
)
raise Exception(f"Error: failed to fetch url: {url}")
# parse ics file
r.encoding = "utf-8"

View File

@@ -22,6 +22,12 @@ ICON_MAP = {
"altmetalle": "mdi:nail",
}
PARAM_TRANSLATIONS = {
"de": {
"city": "Ort",
}
}
class Source:
def __init__(self, city):

View File

@@ -2,17 +2,20 @@ import requests
from waste_collection_schedule import Collection
from waste_collection_schedule.service.ICS import ICS
TITLE = "Landkreis Schwäbisch Hall"
DESCRIPTION = "Source for lrasha.de - Landkreis Schwäbisch Hall"
URL = "https://www.lrasha.de"
TEST_CASES = {
"Ilshofen": {"location": "68345"}
}
TEST_CASES = {"Ilshofen": {"location": "68345"}}
API_URL = "http://api.cross-7.de/public/calendar/396/events/ics?SecondCategoryIds="
HEADERS = {"user-agent": "Mozilla/5.0 (xxxx Windows NT 10.0; Win64; x64)"}
PARAM_TRANSLATIONS = {
"de": {
"location": "Gebiet",
}
}
class Source:
def __init__(self, location):

View File

@@ -1,7 +1,8 @@
from datetime import datetime
import requests
from waste_collection_schedule import Collection
from waste_collection_schedule.service.ICS import ICS
from datetime import datetime
TITLE = "mags Mönchengladbacher Abfall-, Grün- und Straßenbetriebe AöR"
DESCRIPTION = "Source for Stadt Mönchengladbach"
@@ -24,6 +25,14 @@ ICON_MAP = {
"Elektrokleingeräte-Sammlung": "mdi:radio",
}
PARAM_TRANSLATIONS = {
"de": {
"street": "Straße",
"number": "Hausnummer",
"turnus": "Turnus",
},
}
class Source:
def __init__(self, street, number, turnus=2):
@@ -35,17 +44,19 @@ class Source:
def fetch(self):
# fetch the ical
now = datetime.now()
r = requests.get(API_URL,
params={"building_number": self._number,
"building_number_addition": "",
"street_name": self._street,
"start_month": 1,
"end_month": 12,
"start_year": now.year,
"end_year": now.year,
"turnus": self._turnus
}
)
r = requests.get(
API_URL,
params={
"building_number": self._number,
"building_number_addition": "",
"street_name": self._street,
"start_month": 1,
"end_month": 12,
"start_year": now.year,
"end_year": now.year,
"turnus": self._turnus,
},
)
r.raise_for_status()
# replace non-ascii character in UID, otherwise ICS converter will fail
@@ -63,12 +74,6 @@ class Source:
entries = []
for d in dates:
entries.append(
Collection(
date=d[0],
t=d[1],
icon=ICON_MAP.get(d[1])
)
)
entries.append(Collection(date=d[0], t=d[1], icon=ICON_MAP.get(d[1])))
return entries

View File

@@ -53,6 +53,15 @@ TEST_CASES = {
},
}
PARAM_TRANSLATIONS = {
"de": {
"city": "Ort",
"street": "Strasse",
"house_number": "Hausnummer",
"address_suffix": "Hausnummerzusatz",
}
}
class Source:
def __init__(self, city, street, house_number, address_suffix=""):

View File

@@ -39,6 +39,18 @@ GERMAN_MONTHS = {
API_URL = "https://www.monaloga.de/mportal/awista-logistik/stadt-remscheid/index.php"
PARAM_TRANSLATIONS = {
"de": {
"plz": "PLZ",
"street": "Straße",
},
"en": {
"plz": "ZIP",
"street": "Street",
},
}
class Source:
def __init__(self, street: str, plz: str | int | None = None):
self._street: str = street

View File

@@ -31,6 +31,15 @@ ICON_MAP = {
"Biomüll": "mdi:leaf",
}
PARAM_TRANSLATIONS = {
"de": {
"client": "Client",
"city": "Ort",
"district": "Ortsteil",
"street": "Straße",
}
}
class Source:
def __init__(self, client, city, district=None, street=None):

View File

@@ -35,6 +35,15 @@ HEADERS = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3"
}
PARAM_TRANSLATIONS = {
"de": {
"service": "Service",
"mm_frm_ort_sel": "Ort",
"mm_frm_str_sel": "Straße",
"mm_frm_hnr_sel": "Hausnummer",
},
}
# Parser for HTML checkbox
class InputCheckboxParser(HTMLParser):

View File

@@ -25,6 +25,13 @@ ICON_MAP = {
}
PARAM_TRANSLATIONS = {
"de": {
"waste_district": "Abfuhrkreis",
},
}
class Source:
def __init__(self, waste_district):
self._waste_district = waste_district

View File

@@ -76,6 +76,13 @@ TEST_CASES = {
LOGGER = logging.getLogger(__name__)
PARAM_TRANSLATIONS = {
"de": {
"source": "Quelle",
"args": "Argumente",
},
}
def get_source(source: str, args: dict | list[dict]) -> list:
if isinstance(args, list):

View File

@@ -13,6 +13,12 @@ TEST_CASES = {
"offenbach": {"f_id_location": 7036}, # KaiserStraße 1
}
PARAM_TRANSLATIONS = {
"de": {
"f_id_location": "Standort ID",
},
}
class Source(InsertItSource):
def __init__(self, f_id_location):

View File

@@ -1,9 +1,9 @@
import json
from datetime import datetime, timedelta
import requests
from waste_collection_schedule import Collection # type: ignore[attr-defined]
from datetime import datetime, timedelta
import json
TITLE = "Potsdam"
DESCRIPTION = "Source for Potsdam."
URL = "https://www.potsdam.de"
@@ -28,7 +28,7 @@ TEST_CASES = {
"rest_rhythm": 4,
"papier_rhythm": 4,
"bio_rhythm": 2,
}
},
}
@@ -61,9 +61,36 @@ RHYTHM_MAP = {
API_URL = "https://www.geben-und-nehmen-markt.de/abfallkalender/potsdam/{year}/page-data/index/page-data.json"
PARAM_TRANSLATIONS = {
"de": {
"ortsteil": "Ortsteil",
"strasse": "Straße",
"rest_rhythm": "Restabfall Rhythmus",
"papier_rhythm": "Papier Rhythmus",
"bio_rhythm": "Bio Rhythmus",
"gelb_rhythm": "Gelb Rhythmus",
},
"en": {
"ortsteil": "District",
"strasse": "Street",
"rest_rhythm": "General waste rhythm",
"papier_rhythm": "Paper rhythm",
"bio_rhythm": "Organics rhythm",
"gelb_rhythm": "Recycling rhythm",
},
}
class Source:
def __init__(self, ortsteil: str, strasse: str, rest_rhythm: int = 0, papier_rhythm: int = 0, bio_rhythm: int = 0, gelb_rhythm: int = 3):
def __init__(
self,
ortsteil: str,
strasse: str,
rest_rhythm: int = 0,
papier_rhythm: int = 0,
bio_rhythm: int = 0,
gelb_rhythm: int = 3,
):
self._ortsteil: str = ortsteil
self._strasse: str = strasse
self._rhythms = {
@@ -73,7 +100,9 @@ class Source:
4: int(papier_rhythm),
}
def __get_entries_for_street(self, year: int, today: datetime) -> list[dict[str, str | int]] | None:
def __get_entries_for_street(
self, year: int, today: datetime
) -> list[dict[str, str | int]] | None:
try:
# get json file
r = requests.get(API_URL.format(year=year))
@@ -103,28 +132,54 @@ class Source:
start += timedelta(days=1)
def __typematch(self, partm, partd, bin_type, turnus, schwarz, gruen, blau):
startkombi = '0401'
endekombi = '1031'
startkombi = "0401"
endekombi = "1031"
return ((bin_type == 1) and (schwarz == turnus)) or \
((bin_type == 2) and ((gruen == turnus) or ((gruen == 5) and (((turnus == 2) and (partm + partd >= startkombi) and (partm + partd <= endekombi)) or ((turnus == 3) and ((partm + partd < startkombi) or (partm + partd > endekombi))))))) or \
((bin_type == 4) and (blau == turnus)) or \
(bin_type == 3)
return (
((bin_type == 1) and (schwarz == turnus))
or (
(bin_type == 2)
and (
(gruen == turnus)
or (
(gruen == 5)
and (
(
(turnus == 2)
and (partm + partd >= startkombi)
and (partm + partd <= endekombi)
)
or (
(turnus == 3)
and (
(partm + partd < startkombi)
or (partm + partd > endekombi)
)
)
)
)
)
)
or ((bin_type == 4) and (blau == turnus))
or (bin_type == 3)
)
def __date_is_collection(self, node, day: datetime, exceptions) -> bool:
return self.__date_is_collection_1_to_4(node, day, exceptions) or self.__date_is_collection5_6(node, day)
return self.__date_is_collection_1_to_4(
node, day, exceptions
) or self.__date_is_collection5_6(node, day)
def __date_is_collection5_6(self, node, day: datetime) -> bool:
if not node["typ"] in (5, 6):
return False
termin1 = datetime.fromisoformat(
node["termin1"].replace("Z", "+00:00")).date()
termin2 = datetime.fromisoformat(
node["termin2"].replace("Z", "+00:00")).date()
termin1 = datetime.fromisoformat(node["termin1"].replace("Z", "+00:00")).date()
termin2 = datetime.fromisoformat(node["termin2"].replace("Z", "+00:00")).date()
day = day.date()
return (termin1 == day) or (termin2 == day)
def __date_is_collection_1_to_4(self, node, day: datetime, exceptions, check_exception=True) -> bool:
def __date_is_collection_1_to_4(
self, node, day: datetime, exceptions, check_exception=True
) -> bool:
weekno = day.isocalendar()[1]
weekeven = weekno % 2 == 0
dow = day.weekday() + 1
@@ -134,13 +189,87 @@ class Source:
if day == e_from:
return False
if day == e_to:
return self.__date_is_collection_1_to_4(node, e_from, exceptions, check_exception=False)
return self.__date_is_collection_1_to_4(
node, e_from, exceptions, check_exception=False
)
return (((node["rhythmus"] == 1) and self.__typematch(day.strftime("%m"), day.strftime("%d"), node["typ"], 2, self._rhythms[1], self._rhythms[2], self._rhythms[4])) and (((node["tag1"] == dow) and (node["tag2"] == 0)) or (((node["tag1"] == dow) and not weekeven) or ((node["tag2"] == dow) and weekeven)))) or \
(((node["rhythmus"] == 2) and self.__typematch(day.strftime("%m"), day.strftime("%d"), node["typ"], 3, self._rhythms[1], self._rhythms[2], self._rhythms[4])) and (((node["woche"] == 2) and not weekeven) or ((node["woche"] == 3) and weekeven)) and (node["tag1"] == dow)) or \
(((node["rhythmus"] == 3) and self.__typematch(day.strftime("%m"), day.strftime("%d"), node["typ"], 4, self._rhythms[1], self._rhythms[2], self._rhythms[4])) and ((weekno - node["beginn"]) % 4 == 0) and (node["tag1"] == dow)) or \
(((node["rhythmus"] == 4) and self.__typematch(day.strftime("%m"), day.strftime("%d"), node["typ"], 1, self._rhythms[1], self._rhythms[2], self._rhythms[4])) and ((node["tag1"] == dow) or ((node["tag2"] > 0) and (node["tag2"] == dow)))) and \
(weekno >= node["beginn"])
return (
(
(
(node["rhythmus"] == 1)
and self.__typematch(
day.strftime("%m"),
day.strftime("%d"),
node["typ"],
2,
self._rhythms[1],
self._rhythms[2],
self._rhythms[4],
)
)
and (
((node["tag1"] == dow) and (node["tag2"] == 0))
or (
((node["tag1"] == dow) and not weekeven)
or ((node["tag2"] == dow) and weekeven)
)
)
)
or (
(
(node["rhythmus"] == 2)
and self.__typematch(
day.strftime("%m"),
day.strftime("%d"),
node["typ"],
3,
self._rhythms[1],
self._rhythms[2],
self._rhythms[4],
)
)
and (
((node["woche"] == 2) and not weekeven)
or ((node["woche"] == 3) and weekeven)
)
and (node["tag1"] == dow)
)
or (
(
(node["rhythmus"] == 3)
and self.__typematch(
day.strftime("%m"),
day.strftime("%d"),
node["typ"],
4,
self._rhythms[1],
self._rhythms[2],
self._rhythms[4],
)
)
and ((weekno - node["beginn"]) % 4 == 0)
and (node["tag1"] == dow)
)
or (
(
(node["rhythmus"] == 4)
and self.__typematch(
day.strftime("%m"),
day.strftime("%d"),
node["typ"],
1,
self._rhythms[1],
self._rhythms[2],
self._rhythms[4],
)
)
and (
(node["tag1"] == dow)
or ((node["tag2"] > 0) and (node["tag2"] == dow))
)
)
and (weekno >= node["beginn"])
)
def fetch(self):
today = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
@@ -159,19 +288,23 @@ class Source:
continue
for entry in entries:
exceptions = {datetime.strptime(d_from, "%d.%m.%Y"): datetime.strptime(d_to, "%d.%m.%Y") for d_from, d_to in json.loads(entry["ausnahmen"]).items()}
exceptions = {
datetime.strptime(d_from, "%d.%m.%Y"): datetime.strptime(
d_to, "%d.%m.%Y"
)
for d_from, d_to in json.loads(entry["ausnahmen"]).items()
}
icon = ICON_MAP.get(entry["typ"])
type = TYPE_MAP.get(entry["typ"])
rhythm_type = self._rhythms.get(entry["typ"])
if (rhythm_type in RHYTHM_MAP):
if rhythm_type in RHYTHM_MAP:
type += " (" + RHYTHM_MAP.get(rhythm_type) + ")"
for day in self.__generate_dates(today, datetime(year+1, 1, 1)):
for day in self.__generate_dates(today, datetime(year + 1, 1, 1)):
if not self.__date_is_collection(entry, day, exceptions):
continue
collections.append(Collection(
date=day.date(), t=type, icon=icon))
collections.append(Collection(date=day.date(), t=type, icon=icon))
collections.sort(key=lambda x: x.date)
return collections

View File

@@ -35,6 +35,14 @@ OLD_WASTE_NAME = (
API_URL = "https://www.real-luzern.ch/abfall/sammeldienst/abfallkalender/"
PARAM_TRANSLATIONS = {
"de": {
"municipality_id": "Orts ID",
"street_id": "Strassen ID",
},
}
class Source:
def __init__(self, municipality_id: str | int, street_id: str | int | None = None):
self._municipality_id = municipality_id

View File

@@ -18,6 +18,15 @@ HEADERS = {
}
PARAM_TRANSLATIONS = {
"de": {
"city": "Ort",
"street": "Straße",
"house_number": "Hausnummer",
},
}
class Source:
def __init__(self, city, street, house_number):
self.city = city

View File

@@ -1,4 +1,5 @@
from waste_collection_schedule.source.jumomind_de import Source as JumomindSource
from waste_collection_schedule.source.jumomind_de import \
Source as JumomindSource
TITLE = "Rhein-Hunsrück Entsorgung (RHE)"
DESCRIPTION = "Source for RHE (Rhein Hunsrück Entsorgung)."
@@ -18,6 +19,16 @@ TEST_CASES = {
}
PARAM_TRANSLATIONS = {
"de": {
"city": "Ort",
"street": "Straße",
"house_number": "Hausnummer",
"address_suffix": "Hausnummerzusatz",
},
}
class Source(JumomindSource):
def __init__(
self, city: str, street: str, house_number: int, address_suffix: str = ""

View File

@@ -24,6 +24,14 @@ ICON_MAP = {
# _LOGGER = logging.getLogger(__name__)
PARAM_TRANSLATIONS = {
"de": {
"city": "Ort",
"district": "Ortsteil",
"street": "Straße",
},
}
class Source:
def __init__(self, city, district, street=None):

View File

@@ -25,6 +25,13 @@ CITIES = {
HEADERS = {"user-agent": "Mozilla/5.0"}
PARAM_TRANSLATIONS = {
"de": {
"city": "Ort",
"street": "Straße",
},
}
class Source:
def __init__(self, city, street):

View File

@@ -10,6 +10,14 @@ URL = "https://service.stuttgart.de"
TEST_CASES = {"Im Steinengarten 7": {"street": "Im Steinengarten", "streetnr": 7}}
PARAM_TRANSLATIONS = {
"de": {
"street": "Straße",
"streetnr": "Hausnummer",
}
}
# Parser for HTML checkbox
class InputCheckboxParser(HTMLParser):
def __init__(self, name):

View File

@@ -24,6 +24,12 @@ ICON_MAP = {
_LOGGER = logging.getLogger(__name__)
PARAM_TRANSLATIONS = {
"de": {
"street": "Straße",
}
}
class Source:
def __init__(self, street):

View File

@@ -46,6 +46,12 @@ NAME_2_TYPE = {
"grau4Array": "grau4",
}
PARAM_TRANSLATIONS = {
"de": {
"url": "URL",
}
}
class Source:
def __init__(self, url: str):

View File

@@ -197,6 +197,16 @@ ICON_MAP = {
"Windeltonne": "mdi:baby",
}
PARAM_TRANSLATIONS = {
"de": {
"district": "Gebiet",
"municipal": "Gemeinde",
"calendar": "Kalender",
"calendar_title_separator": "Kalendertitel Seperator",
"calendar_splitter": "Kalendereintrag-Trenner",
}
}
class Source:
def __init__(

View File

@@ -19,6 +19,13 @@ ICON_MAP = {
"Altpapier": "mdi:file-document-outline",
}
PARAM_TRANSLATIONS = {
"de": {
"street": "Straße",
"city": "Ort",
}
}
class Source:
def __init__(self, street: str | None, city: str | None):

View File

@@ -46,6 +46,14 @@ ICON_MAP = {
}
PARAM_TRANSLATIONS = {
"de": {
"street": "Straße",
"house_number": "Hausnummer",
}
}
class Source:
def __init__(self, street, house_number):
self._street = street

View File

@@ -44,9 +44,24 @@ MUNICIPAL_CHOICES = {
"Techelsberg": "20435",
}
PARAM_TRANSLATIONS = {
"de": {
"address_id": "Adressen ID",
"municipal": "Gemeinde",
"address": "Adresse",
"street": "Straße",
}
}
class Source:
def __init__(self, address_id=None, municipal=None, address=None, street=None):
def __init__(
self,
address_id: int | None = None,
municipal: str | None = None,
address: str | None = None,
street: str | None = None,
):
if address_id is not None:
self._address_id = address_id
elif municipal is not None and address is not None and street is not None:
@@ -55,7 +70,7 @@ class Source:
)
else:
raise Exception(
"Invalid argument count, provide either address_id or all 3 address parts (municipal, address, street)"
"You must provide either an (address_id) or (municipal, address, street)"
)
def fetch(self):

View File

@@ -18,14 +18,22 @@ API_URL = "https://www.wuerzburg.de/themen/umwelt-klima/vorsorge-entsorgung/abfa
HEADERS = {"user-agent": "Mozilla/5.0 (xxxx Windows NT 10.0; Win64; x64)"}
PARAM_TRANSLATIONS = {
"de": {
"district": "Stadtteil",
"street": "Straße",
}
}
class Source:
def __init__(self, district: str = None, street: str = None):
def __init__(self, district: str | None = None, street: str | None = None):
self._district = district
self._street = street
self._district_id = None
@staticmethod
def map_district_id(district: str = None, street: str = None):
def map_district_id(district: str | None = None, street: str | None = None):
"""Map `street` or `district` to `district_id`, giving priority to `street`.
Parameters must exactly be the same as visible in dropdowns on `URL`.

View File

@@ -10,7 +10,7 @@ TEST_CASES = {
"ort": "Abtsteinach",
"strasse": "Am Hofböhl",
"hnr": "1",
"hnr_zusatz": ""
"hnr_zusatz": "",
},
"Gorxheimertal, Am Herrschaftswald 10": {
"ort": "Gorxheimertal",
@@ -21,13 +21,13 @@ TEST_CASES = {
"ort": "Rimbach",
"strasse": "Ahornweg",
"hnr": "1",
"hnr_zusatz": "B"
"hnr_zusatz": "B",
},
"Zwingenberg, Diefenbachstraße 57": {
"ort": "Zwingenberg",
"strasse": "Diefenbachstraße",
"hnr": 57,
"hnr_zusatz": ""
"hnr_zusatz": "",
},
}
@@ -46,6 +46,22 @@ ICON_MAP = {
API_URL = "https://www.zakb.de/online-service/abfallkalender/"
PARAM_TRANSLATIONS = {
"de": {
"ort": "Ort",
"strasse": "Straße",
"hnr": "Hausnummer",
"hnr_zusatz": "Hausnummerzusatz",
},
"en": {
"ort": "City",
"strasse": "Street",
"hnr": "House number",
"hnr_zusatz": "House number addition",
},
}
class Source:
def __init__(self, ort: str, strasse: str, hnr: str | int, hnr_zusatz: str = ""):
self._ort: str = ort.replace(" ", "+")
@@ -55,7 +71,6 @@ class Source:
self._ics = ICS()
def fetch(self):
# inizilize session
session = requests.Session()
@@ -91,7 +106,9 @@ class Source:
# make request to get ical file
r = session.post(
API_URL, data={"submitAction": "filedownload_ICAL", "pageName": "Terminliste"})
API_URL,
data={"submitAction": "filedownload_ICAL", "pageName": "Terminliste"},
)
r.raise_for_status()
dates = self._ics.convert(r.text)

View File

@@ -1,9 +1,8 @@
import re
import requests
from datetime import datetime
import requests
from bs4 import BeautifulSoup
from waste_collection_schedule import Collection # type: ignore[attr-defined]
from waste_collection_schedule.service.ICS import ICS
@@ -34,17 +33,27 @@ TEST_CASES = {
"ortsteil": "Guxhagen",
},
}
SERVLET = (
"https://www.zva-sek.de/module/abfallkalender/generate_ical.php"
)
SERVLET = "https://www.zva-sek.de/module/abfallkalender/generate_ical.php"
MAIN_URL = "https://www.zva-sek.de/online-dienste/abfallkalender-{year}/{file}"
API_URL = "https://www.zva-sek.de/module/abfallkalender/{file}"
PARAM_TRANSLATIONS = {
"de": {
"bezirk": "Abfuhrbezirk",
"strasse": "Straße",
"ortsteil": "Ortsteil",
},
"en": {
"bezirk": "City district",
"strasse": "Street",
"ortsteil": "District",
},
}
class Source:
def __init__(
self, bezirk: str, ortsteil: str, strasse: str = None
):
def __init__(self, bezirk: str, ortsteil: str, strasse: str | None = None):
self._bezirk = bezirk
self._ortsteil = ortsteil
self._street = strasse if strasse != "" else None
@@ -58,13 +67,13 @@ class Source:
ortsteil_id = None
# get bezirke id
r = session.get(MAIN_URL.format(
year=year, file=f"abfallkalender-{year}.html"))
if (r.status_code == 404): # try last year URL if this year is not available
r = session.get(MAIN_URL.format(
year=year, file=f"abfallkalender-{year-1}.html"))
r = session.get(MAIN_URL.format(year=year, file=f"abfallkalender-{year}.html"))
if r.status_code == 404: # try last year URL if this year is not available
r = session.get(
MAIN_URL.format(year=year, file=f"abfallkalender-{year-1}.html")
)
r.raise_for_status()
soup = BeautifulSoup(r.text, features="html.parser")
for option in soup.find("select", {"name": "ak_bezirk"}).find_all("option"):
if option.text.lower() == self._bezirk.lower():
@@ -77,13 +86,14 @@ class Source:
raise Exception("bezirk not found")
# get ortsteil id
r = session.get(API_URL.format(
file="get_ortsteile.php"), params={"bez_id": bezirk_id})
r = session.get(
API_URL.format(file="get_ortsteile.php"), params={"bez_id": bezirk_id}
)
r.raise_for_status()
last_orts_id = None
for part in r.text.split(";")[2:-1]:
# part is "f.ak_ortsteil.options[5].text = 'Alte Kasseler Straße'" or "ak_ortsteil.options[6].value = '2'"
if ("length" in part):
if "length" in part:
continue
if part.split(" = ")[1][1:-1].lower() == self._ortsteil.lower():
ortsteil_id = last_orts_id
@@ -97,13 +107,15 @@ class Source:
# get street id if steet given
if self._street is not None:
r = session.get(API_URL.format(
file="get_strassen.php"), params={"ot_id": ortsteil_id.split("-")[0]})
r = session.get(
API_URL.format(file="get_strassen.php"),
params={"ot_id": ortsteil_id.split("-")[0]},
)
r.raise_for_status()
last_street_id = None
for part in r.text.split(";")[2:-1]:
for part in r.text.split(";")[2:-1]:
# part is "f.ak_strasse.options[5].text = 'Alte Kasseler Straße'" or "ak_strasse.options[6].value = '2'"
if ("length" in part):
if "length" in part:
continue
if part.split(" = ")[1][1:-1].lower() == self._street.lower():
street_id = last_street_id
@@ -113,15 +125,19 @@ class Source:
if not street_id:
raise Exception("street not found")
entries = self.get_calendar_data(year, bezirk_id, ortsteil_id, street_id, session)
entries = self.get_calendar_data(
year, bezirk_id, ortsteil_id, street_id, session
)
if datetime.now().month >= 11:
try:
entries += self.get_calendar_data(year+1, bezirk_id, ortsteil_id, street_id, session)
entries += self.get_calendar_data(
year + 1, bezirk_id, ortsteil_id, street_id, session
)
except Exception:
pass
return entries
def get_calendar_data(self, year, bezirk_id, ortsteil_id,street_id, session):
def get_calendar_data(self, year, bezirk_id, ortsteil_id, street_id, session):
args = {
"year": str(year),
"ak_bezirk": bezirk_id,
@@ -143,6 +159,7 @@ class Source:
entries = []
for d in dates:
entries.append(Collection(d[0], re.sub(
"[ ]*am [0-9]+.[0-9]+.[0-9]+[ ]*", "", d[1])))
entries.append(
Collection(d[0], re.sub("[ ]*am [0-9]+.[0-9]+.[0-9]+[ ]*", "", d[1]))
)
return entries

View File

@@ -13,6 +13,13 @@ TEST_CASES = {
"Vockerode": {"city": "Meißner - Vockerode", "street": "Feuerwehr"},
}
PARAM_TRANSLATIONS = {
"de": {
"street": "Straße",
"city": "Ort",
}
}
class Source:
def __init__(self, city, street):

View File

@@ -123,6 +123,7 @@ def split_camel_and_snake_case(s):
s = re.sub("([a-z0-9])([A-Z])", r"\1 \2", s) # Split CamelCase
return s.replace("_", " ").split() # Split snake_case
def update_edpevent_se(modules: dict[str, ModuleType]):
module = modules.get("edpevent_se")
if not module:
@@ -136,6 +137,7 @@ def update_edpevent_se(modules: dict[str, ModuleType]):
_patch_file("doc/source/edpevent_se.md", "service", str)
def main() -> None:
sources: list[SourceInfo] = []
@@ -241,7 +243,7 @@ def browse_sources() -> list[SourceInfo]:
update_app_abfallplus_de(modules)
update_abfallnavi_de(modules)
update_edpevent_se(modules)
return sources
@@ -401,11 +403,20 @@ def update_json(
)
params.update(e.params)
for key, value in e.custom_param_translation.items():
if key in param_translations:
param_translations[key].update(value)
for lang, translations in e.custom_param_translation.items():
if lang in param_translations:
for key, value in translations.items():
if (
key in param_translations[lang]
and value != param_translations[lang][key]
):
print(
f'Conflicting translations for language {lang} "{key}" => "{value}" ({e.module}) AND "{param_translations[lang][key]}"'
)
param_translations[lang].update(translations)
else:
param_translations[key] = value.copy()
param_translations[lang] = translations.copy()
# output["Generic"] = [{"title": "ICS", "module": "ics", "default_params": {}}, {"title": "Static", "module": "static", "default_params": {}}]