Trams und U-Bahnen (CH, DE, NL): eigener Filter, ab Stadtzoom im Ausschnitt; NL-Echtzeit auch für Tram/Metro; Vorausschau ohne 7-fache Neuberechnung; deutsche Steig-Zusätze aus Haltestellennamen

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X48pE4bzjHej8w9HyZXCjb
This commit is contained in:
Claude
2026-10-22 10:33:45 +02:00
parent 49860c50f5
commit d11cc109f6
9 changed files with 148 additions and 56 deletions
+8 -7
View File
@@ -23,13 +23,14 @@ import httpx
from . import border
from . import config as C
from .feed import route_mode
log = logging.getLogger("prepare")
def is_rail(route_type: str) -> bool:
t = int(route_type)
return t == 2 or 100 <= t <= 199 # GTFS + "extended route types" (Schweiz nutzt 100–117)
# Aufbereitungs-Version: ändert sich, was aus dem Fahrplan übernommen wird, rechnet der Updater
# alle Fahrpläne einmal neu, auch ohne neuen Fahrplan (2: mit Trams und U-Bahnen)
FORMAT = 2
def timetable_year(today: dt.date) -> int:
@@ -136,7 +137,7 @@ def filter_rail(zip_path: Path, out: Path, version: str | None = None) -> dict:
z = zipfile.ZipFile(zip_path)
h, rd = rows(z, "routes.txt")
routes = [r for r in rd if is_rail(r[h.index("route_type")])]
routes = [r for r in rd if route_mode(r[h.index("route_type")])]
write_csv(out / "routes.txt", h, routes)
route_ids = {r[h.index("route_id")] for r in routes}
@@ -226,7 +227,7 @@ def run_pfaedle(work: Path, rail: Path, source: str) -> Path | None:
"--overwrite"], check=True)
log.info("[%s] pfaedle rechnet Streckenverläufe …", source)
t = time.time()
res = subprocess.run([C.PFAEDLE, "-D", "-m", "rail", "-x", str(osm), str(rail)], cwd=work)
res = subprocess.run([C.PFAEDLE, "-D", "-m", "rail,tram,subway", "-x", str(osm), str(rail)], cwd=work)
osm.unlink()
out = work / "gtfs-out"
if res.returncode != 0 or not (out / "shapes.txt").exists():
@@ -313,7 +314,7 @@ def prepare(source: str, state: dict, zip_path: Path | None = None, force: bool
else:
url = gtfs_url(source)
name, version = remote_id(source, url)
if name == state.get(source) and not force:
if f"{name} #{FORMAT}" == state.get(source) and not force:
log.info("[%s] Kein neuer Fahrplan (%s)", source, name)
return
zip_path = work / "gtfs.zip"
@@ -334,7 +335,7 @@ def prepare(source: str, state: dict, zip_path: Path | None = None, force: bool
meta["prepared_at"] = int(time.time())
publish(source, shaped or work / "rail", meta)
shutil.rmtree(work, ignore_errors=True)
state[source] = name
state[source] = f"{name} #{FORMAT}"
log.info("[%s] Fahrplan %s bereit", source, meta["feed_version"])