use bahn.de api
This commit is contained in:
parent
3d3754b116
commit
e2fcae8e8e
145
src/api.rs
145
src/api.rs
@ -3,7 +3,7 @@ use std::{
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use chrono::DateTime;
|
||||
use chrono::{DateTime, NaiveDateTime};
|
||||
use reqwest::get;
|
||||
use serde::Deserialize;
|
||||
|
||||
@ -157,38 +157,99 @@ impl ApiClient {
|
||||
}
|
||||
|
||||
pub async fn bahnhof_get_departures() -> Result<String, String> {
|
||||
match get(
|
||||
"https://www.bahnhof.de/api/boards/departures?evaNumbers=8000170&filterTransports=HIGH_SPEED_TRAIN&filterTransports=INTERCITY_TRAIN&filterTransports=INTER_REGIONAL_TRAIN&filterTransports=REGIONAL_TRAIN&filterTransports=CITY_TRAIN&filterTransports=UNKNOWN&duration=120&locale=de",
|
||||
)
|
||||
.await
|
||||
{
|
||||
let url = r#"https://www.bahn.de/web/api/reiseloesung/abfahrten?ortExtId=8000170&mitVias=true&maxVias=8&verkehrsmittel[]=ICE&verkehrsmittel[]=EC_IC&verkehrsmittel[]=IR&verkehrsmittel[]=REGIONAL&verkehrsmittel[]=SBAHN"#;
|
||||
match get(url).await {
|
||||
Ok(response) => match response.text().await {
|
||||
Ok(response) => match serde_json::from_str::<BahnhofResDepartures>(&response) {
|
||||
Ok(response) => {
|
||||
let mut o = format!("<div class=\"dbflex\" style=\"display:flex;flex-wrap:wrap;padding:1%;\">\n");
|
||||
for departure in response.entries.into_iter().flat_map(|v| v.into_iter()) {
|
||||
for departure in response.entries.into_iter() {
|
||||
if let Some(line_name) = &departure.line_name {
|
||||
o.push_str(if departure.canceled {
|
||||
r#"<div style="text-decoration: line-through wavy DarkRed; color:gray;">"#
|
||||
if let Some(messages) =
|
||||
departure.messages.as_ref().filter(|v| !v.is_empty())
|
||||
{
|
||||
if messages.iter().any(|msg| {
|
||||
msg.priority
|
||||
.as_ref()
|
||||
.is_some_and(|prio| ["HOCH"].contains(&prio.as_str()))
|
||||
}) {
|
||||
o.push_str(r#"<div class="affected_departure"><div class="affected_departure_messages">"#);
|
||||
} else {
|
||||
o.push_str(r#"<div class="affected_departure"><div class="affected_departure_messages">"#);
|
||||
}
|
||||
for message in messages.iter() {
|
||||
o.push_str(
|
||||
match message.priority.as_ref().map(|v| v.as_str()) {
|
||||
Some("HOCH") => r#"<p style="color:#ED153D;max-width:100%;text-wrap:wrap;font-size:large;">"#,
|
||||
Some("NORMAL") => r#"<p style="color:white;max-width:100%;text-wrap:wrap;font-size:large;">"#,
|
||||
Some("NIEDRIG") => r#"<p style="color:gray;max-width:100%;text-wrap:wrap;font-size:large;">"#,
|
||||
None | Some(_) => r#"<p style="color:#CA5CE1;max-width:100%;text-wrap:wrap;font-size:large;">"#,
|
||||
},
|
||||
);
|
||||
if let Some(text) = &message.text {
|
||||
html_escape::encode_safe_to_string(text, &mut o);
|
||||
}
|
||||
o.push_str("</p>");
|
||||
}
|
||||
o.push_str(r#"</div>"#);
|
||||
} else {
|
||||
r#"<div>"#
|
||||
});
|
||||
o.push_str("<div>");
|
||||
}
|
||||
o.push_str("<b>");
|
||||
html_escape::encode_safe_to_string(line_name, &mut o);
|
||||
let line_name = if let Some(p) = &line_name.product {
|
||||
if let Some(nr) = &line_name.line_number {
|
||||
format!("{p} {nr}")
|
||||
} else {
|
||||
format!("{p}")
|
||||
}
|
||||
} else {
|
||||
"[?]".to_owned()
|
||||
};
|
||||
html_escape::encode_safe_to_string(&line_name, &mut o);
|
||||
o.push_str("</b>");
|
||||
if let Some(departure_time) =
|
||||
departure.time_delayed.or(departure.time_schedule)
|
||||
{
|
||||
o.push_str(" ");
|
||||
o.push_str(
|
||||
&departure_time.naive_local().format("%H:%M").to_string(),
|
||||
);
|
||||
}
|
||||
if let Some(destination) =
|
||||
departure.destination.as_ref().and_then(|v| v.name.as_ref())
|
||||
o.push_str("<small> ");
|
||||
o.push_str(&departure_time.format("%H:%M").to_string());
|
||||
if let Some(platform) = departure
|
||||
.platform
|
||||
.as_ref()
|
||||
.or(departure.platform_schedule.as_ref())
|
||||
{
|
||||
o.push_str("<small>");
|
||||
o.push_str(&format!(" @ {platform}"));
|
||||
o.push_str("</small></small>");
|
||||
} else {
|
||||
o.push_str("</small>");
|
||||
}
|
||||
} else if let Some(platform) = departure
|
||||
.platform
|
||||
.as_ref()
|
||||
.or(departure.platform_schedule.as_ref())
|
||||
{
|
||||
o.push_str("<br>");
|
||||
o.push_str("<small><small>");
|
||||
o.push_str(&format!(" @ {platform}"));
|
||||
o.push_str("</small></small>");
|
||||
}
|
||||
if let Some(destination) = &departure.destination {
|
||||
if let Some(messages) =
|
||||
departure.messages.as_ref().filter(|v| !v.is_empty())
|
||||
{
|
||||
if messages.iter().any(|msg| {
|
||||
msg.priority
|
||||
.as_ref()
|
||||
.is_some_and(|prio| ["HOCH"].contains(&prio.as_str()))
|
||||
}) {
|
||||
o.push_str(r#"<br><span style="text-decoration: underline darkred;">"#);
|
||||
} else {
|
||||
o.push_str(r#"<br><span style="text-decoration: underline dotted #908070;">"#);
|
||||
}
|
||||
} else {
|
||||
o.push_str("<br><span>");
|
||||
}
|
||||
html_escape::encode_safe_to_string(destination, &mut o);
|
||||
o.push_str("</span>");
|
||||
}
|
||||
o.push_str("</div>\n");
|
||||
}
|
||||
@ -333,25 +394,37 @@ pub struct JourneyData {
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct BahnhofResDepartures {
|
||||
entries: Vec<Vec<BahnhofResDeparture>>,
|
||||
#[serde(rename = "entries")]
|
||||
pub entries: Vec<BahnhofResDeparture>,
|
||||
}
|
||||
#[derive(Deserialize)]
|
||||
struct BahnhofResDeparture {
|
||||
#[serde(default, rename = "timeSchedule")]
|
||||
time_schedule: Option<DateTime<chrono::Local>>,
|
||||
#[serde(default, rename = "timeDelayed")]
|
||||
time_delayed: Option<DateTime<chrono::Local>>,
|
||||
#[serde(default, rename = "canceled")]
|
||||
canceled: bool,
|
||||
// #[serde(default, rename = "platform")]
|
||||
// platform: Option<String>,
|
||||
#[serde(default, rename = "lineName")]
|
||||
line_name: Option<String>,
|
||||
#[serde(default, rename = "destination")]
|
||||
destination: Option<BahnhofResDepartureDestination>,
|
||||
#[serde(rename = "zeit")]
|
||||
pub time_schedule: Option<NaiveDateTime>,
|
||||
#[serde(rename = "ezZeit")]
|
||||
pub time_delayed: Option<NaiveDateTime>,
|
||||
#[serde(rename = "ezGleis")]
|
||||
pub platform: Option<String>,
|
||||
#[serde(rename = "gleis")]
|
||||
pub platform_schedule: Option<String>,
|
||||
#[serde(rename = "verkehrmittel")]
|
||||
pub line_name: Option<BahnhofResDepartureDestination>,
|
||||
#[serde(rename = "terminus")]
|
||||
pub destination: Option<String>,
|
||||
#[serde(rename = "meldungen")]
|
||||
pub messages: Option<Vec<BahnhofResDepartureMessage>>,
|
||||
}
|
||||
#[derive(Deserialize)]
|
||||
struct BahnhofResDepartureDestination {
|
||||
#[serde(default, rename = "name")]
|
||||
name: Option<String>,
|
||||
pub struct BahnhofResDepartureDestination {
|
||||
#[serde(rename = "linienNummer")]
|
||||
pub line_number: Option<String>,
|
||||
#[serde(rename = "kurzText")]
|
||||
pub product: Option<String>,
|
||||
}
|
||||
#[derive(Deserialize)]
|
||||
pub struct BahnhofResDepartureMessage {
|
||||
#[serde(rename = "text")]
|
||||
pub text: Option<String>,
|
||||
#[serde(rename = "prioritaet")]
|
||||
pub priority: Option<String>,
|
||||
}
|
||||
|
@ -20,6 +20,19 @@
|
||||
margin-right: 1em;
|
||||
border-left: solid gray;
|
||||
}
|
||||
.affected_departure > .affected_departure_messages {
|
||||
pointer-events: none;
|
||||
display: none;
|
||||
}
|
||||
.affected_departure:hover > .affected_departure_messages {
|
||||
pointer-events: none;
|
||||
display: block;
|
||||
position: fixed;
|
||||
inset: 5%;
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
background: #000C;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
Loading…
x
Reference in New Issue
Block a user