Last active
November 29, 2023 12:11
-
-
Save DEVTomatoCake/e18d870381f22c17bf25d738510c8d1c to your computer and use it in GitHub Desktop.
(German) parser for the timetable API of the Deutsche Bahn. Still garbage, but displays most data from the API + json is better than xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { create } = require("xmlbuilder2") | |
const messageTypes = { | |
h: "HIM (generiert von Hafas Information Manager)", | |
q: "Qualitätsänderung", | |
f: "Freitext", | |
d: "Verspätung", | |
i: "IBIS (generiert durch IRIS-AP)", | |
u: "IBIS (generiert durch IRIS-AP), noch nicht mit Zug verbunden", | |
r: "Ausfall", | |
c: "Verbindung/Connection" | |
} | |
const priorityTypes = { | |
1: "HIGH", | |
2: "MEDIUM", | |
3: "LOW", | |
4: "DONE" | |
} | |
const eventStatusTypes = { | |
p: "Ereignis geplant", | |
a: "Ereignis als neuer Halt hinzugefügt", | |
c: "Ereignis abgebrochen" | |
} | |
const stats = { | |
MeldungenPrioritaet: {}, | |
AenderungsTyp: {} | |
} | |
const parseDate = (str, raw = false) => { | |
const date = str.substr(0, 6) | |
const time = str.substr(6, 4) | |
const d = new Date() | |
d.setFullYear(parseInt(date.substr(0, 2)) + 2000) | |
d.setMonth(parseInt(date.substr(2, 2)) - 1) | |
d.setDate(parseInt(date.substr(4, 2))) | |
d.setHours(parseInt(time.substr(0, 2))) | |
d.setMinutes(parseInt(time.substr(2, 2))) | |
d.setSeconds(0) | |
if (raw) return d.getTime() | |
return d.toLocaleString("de-DE", {timeFormat: "short"}) | |
} | |
async function main() { | |
const res = await fetch("https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/fchg/8002549", { | |
// (last number in path above) EVU number of a station, e.g. from | |
// https://data.deutschebahn.com/dataset/data-haltestellen/resource/21edf505-e97d-4c99-bcc9-a46e85f8620f.html | |
headers: { | |
"DB-Client-Id": "", // DB Client Id | |
"DB-Api-Key": "" // DB API key | |
} | |
}) | |
const xml = create(await res.text()).end({format: "object"}) | |
stats.MeldungenAnzahl = xml.timetable.s.length | |
const handleNachricht = (m, hideTime = false) => { | |
if (!Array.isArray(m)) m = [m] | |
return "Meldung: " + m.map(msg => { | |
if (msg["@pr"]) stats.MeldungenPrioritaet[priorityTypes[msg["@pr"]]] = (stats.MeldungenPrioritaet[priorityTypes[msg["@pr"]]] || 0) + 1 | |
return "ID: " + msg["@id"] + (!hideTime ? ", veröffentlicht: " + parseDate(msg["@ts"]) : "") + ", Typ: " + messageTypes[msg["@t"]] + | |
(msg["@from"] && !hideTime ? ", gültig ab: " + parseDate(msg["@from"]) : "") + | |
(msg["@to"] && !hideTime ? ", bis: " + parseDate(msg["@to"]) : "") + | |
(msg["@cat"] ? ", Kategorie: " + msg["@cat"] : "") + | |
(msg["@pr"] ? ", Priorität: " + priorityTypes[msg["@pr"]] : "") | |
}).join("; ") | |
} | |
console.log(xml.timetable.s.map(i => { | |
let temp = "ID: " + i["@id"] | |
const ardp = (j, typ) => { | |
if (typ == "Ankunft" && (j["@ct"] || j["@pt"])) stats.AnkunftszeitGeaendert = (stats.AnkunftszeitGeaendert || 0) + 1 | |
if (typ == "Abfahrt" && (j["@ct"] || j["@pt"])) stats.AbfahrtszeitGeaendert = (stats.AbfahrtszeitGeaendert || 0) + 1 | |
if (j["@cp"] || j["@pp"]) stats.BahnsteigGeaendert = (stats.BahnsteigGeaendert || 0) + 1 | |
if (j["@cpth"] || j["@ppth"]) stats.RouteGeaendert = (stats.RouteGeaendert || 0) + 1 | |
if (j["@clt"]) stats.HaltEntfernt = (stats.HaltEntfernt || 0) + 1 | |
if (j["@cs"]) stats.AenderungsTyp[eventStatusTypes[j["@cs"]]] = (stats.AenderungsTyp[eventStatusTypes[j["@cs"]]] || 0) + 1 | |
if (j["@ct"] && j["@pt"]) { | |
if (parseDate(j["@ct"], true) >= parseDate(j["@pt"], true)) { | |
stats.ZugSpaeter = (stats.ZugSpaeter || 0) + 1 | |
stats.ZugSpaeterUmMs = (stats.ZugSpaeterUmMs || 0) + parseDate(j["@ct"], true) - parseDate(j["@pt"], true) | |
stats.ZugSpaeterUmH = 0 | |
stats.ZugSpaeterDurchschnittH = 0 | |
} else { | |
stats.ZugFrueher = (stats.ZugFrueher || 0) + 1 | |
stats.ZugFrueherUmMs = (stats.ZugFrueherUmMs || 0) + parseDate(j["@pt"], true) - parseDate(j["@ct"], true) | |
stats.ZugFrueherUmH = 0 | |
stats.ZugFrueherDurchschnittH = 0 | |
} | |
} | |
return (j["@l"] ? "Linie: " + j["@l"] : "") + | |
(j["@ct"] ? (j["@l"] ? ", " : "") + "geänderte " + typ + "szeit: " + parseDate(j["@ct"]) : "") + | |
(j["@pt"] ? ", " + typ + "szeit geplant: " + parseDate(j["@pt"]) : "") + | |
(j["@cp"] ? ", geänderter Bahnsteig: " + j["@cp"] : "") + | |
(j["@pp"] ? ", Bahnsteig geplant: " + j["@pp"] : "") + | |
(j["@cpth"] ? ", geänderte Route: " + j["@cpth"] : "") + | |
(j["@ppth"] ? ", Route geplant: " + j["@ppth"] : "") + | |
(j["@cs"] ? ", Änderungsstatus: " + eventStatusTypes[j["@cs"]] : "") + | |
(j["@clt"] ? ", Halt entfernt um: " + parseDate(j["@clt"]) : "") + | |
(j.m ? ", " + handleNachricht(j.m) : "") | |
} | |
if (i.ar) temp += "; Ankunft: " + ardp(i.ar, "Ankunft") | |
if (i.dp) temp += "; Abfahrt: " + ardp(i.dp, "Abfahrt") | |
if (i.tl) temp += "; Zug: " + i.tl["@c"] + " " + i.tl["@n"] + ", Filter: " + i.tl["@f"] + ", Besitzer: " + i.tl["@o"] + ", Typ: " + i.tl["@t"] | |
if (i.m) temp += "; " + handleNachricht(i.m) | |
return temp | |
}).join("\n")) | |
if (stats.ZugFrueherUmMs > 5000000) { | |
stats.ZugFrueherUmH = stats.ZugFrueherUmMs / 1000 / 60 / 60 | |
stats.ZugFrueherDurchschnittH = stats.ZugFrueherUmH / stats.ZugFrueher | |
} else { | |
stats.ZugFrueherUmMin = stats.ZugFrueherUmMs / 1000 / 60 | |
stats.ZugFrueherDurchschnittMin = stats.ZugFrueherUmMin / stats.ZugFrueher | |
} | |
if (stats.ZugSpaeterUmMs > 5000000) { | |
stats.ZugSpaeterUmH = stats.ZugSpaeterUmMs / 1000 / 60 / 60 | |
stats.ZugSpaeterDurchschnittH = stats.ZugSpaeterUmH / stats.ZugSpaeter | |
} else { | |
stats.ZugSpaeterUmMin = stats.ZugSpaeterUmMs / 1000 / 60 / 60 | |
stats.ZugSpaeterDurchschnittMin = stats.ZugSpaeterUmMin / stats.ZugSpaeter | |
} | |
console.log("Bahnhof: " + xml.timetable["@station"] + " (" + xml.timetable["@eva"] + ")" + (xml.timetable.m ? ", " + handleNachricht(xml.timetable.m, true) : "")) | |
console.log(stats) | |
} | |
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "db-timetable", | |
"version": "1.0.0", | |
"description": "Displays timetable data from the Deutsche Bahn API", | |
"main": "index.js", | |
"keywords": [], | |
"author": "TomatoCake", | |
"license": "MIT", | |
"dependencies": { | |
"xmlbuilder2": "^3.0.2" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment