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},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
use chrono::DateTime;
|
use chrono::{DateTime, NaiveDateTime};
|
||||||
use reqwest::get;
|
use reqwest::get;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
@ -157,38 +157,99 @@ impl ApiClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn bahnhof_get_departures() -> Result<String, String> {
|
pub async fn bahnhof_get_departures() -> Result<String, String> {
|
||||||
match get(
|
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"#;
|
||||||
"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",
|
match get(url).await {
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(response) => match response.text().await {
|
Ok(response) => match response.text().await {
|
||||||
Ok(response) => match serde_json::from_str::<BahnhofResDepartures>(&response) {
|
Ok(response) => match serde_json::from_str::<BahnhofResDepartures>(&response) {
|
||||||
Ok(response) => {
|
Ok(response) => {
|
||||||
let mut o = format!("<div class=\"dbflex\" style=\"display:flex;flex-wrap:wrap;padding:1%;\">\n");
|
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 {
|
if let Some(line_name) = &departure.line_name {
|
||||||
o.push_str(if departure.canceled {
|
if let Some(messages) =
|
||||||
r#"<div style="text-decoration: line-through wavy DarkRed; color:gray;">"#
|
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 {
|
} else {
|
||||||
r#"<div>"#
|
o.push_str("<div>");
|
||||||
});
|
}
|
||||||
o.push_str("<b>");
|
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>");
|
o.push_str("</b>");
|
||||||
if let Some(departure_time) =
|
if let Some(departure_time) =
|
||||||
departure.time_delayed.or(departure.time_schedule)
|
departure.time_delayed.or(departure.time_schedule)
|
||||||
{
|
{
|
||||||
o.push_str(" ");
|
o.push_str("<small> ");
|
||||||
o.push_str(
|
o.push_str(&departure_time.format("%H:%M").to_string());
|
||||||
&departure_time.naive_local().format("%H:%M").to_string(),
|
if let Some(platform) = departure
|
||||||
);
|
.platform
|
||||||
}
|
.as_ref()
|
||||||
if let Some(destination) =
|
.or(departure.platform_schedule.as_ref())
|
||||||
departure.destination.as_ref().and_then(|v| v.name.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);
|
html_escape::encode_safe_to_string(destination, &mut o);
|
||||||
|
o.push_str("</span>");
|
||||||
}
|
}
|
||||||
o.push_str("</div>\n");
|
o.push_str("</div>\n");
|
||||||
}
|
}
|
||||||
@ -333,25 +394,37 @@ pub struct JourneyData {
|
|||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct BahnhofResDepartures {
|
struct BahnhofResDepartures {
|
||||||
entries: Vec<Vec<BahnhofResDeparture>>,
|
#[serde(rename = "entries")]
|
||||||
|
pub entries: Vec<BahnhofResDeparture>,
|
||||||
}
|
}
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct BahnhofResDeparture {
|
struct BahnhofResDeparture {
|
||||||
#[serde(default, rename = "timeSchedule")]
|
#[serde(rename = "zeit")]
|
||||||
time_schedule: Option<DateTime<chrono::Local>>,
|
pub time_schedule: Option<NaiveDateTime>,
|
||||||
#[serde(default, rename = "timeDelayed")]
|
#[serde(rename = "ezZeit")]
|
||||||
time_delayed: Option<DateTime<chrono::Local>>,
|
pub time_delayed: Option<NaiveDateTime>,
|
||||||
#[serde(default, rename = "canceled")]
|
#[serde(rename = "ezGleis")]
|
||||||
canceled: bool,
|
pub platform: Option<String>,
|
||||||
// #[serde(default, rename = "platform")]
|
#[serde(rename = "gleis")]
|
||||||
// platform: Option<String>,
|
pub platform_schedule: Option<String>,
|
||||||
#[serde(default, rename = "lineName")]
|
#[serde(rename = "verkehrmittel")]
|
||||||
line_name: Option<String>,
|
pub line_name: Option<BahnhofResDepartureDestination>,
|
||||||
#[serde(default, rename = "destination")]
|
#[serde(rename = "terminus")]
|
||||||
destination: Option<BahnhofResDepartureDestination>,
|
pub destination: Option<String>,
|
||||||
|
#[serde(rename = "meldungen")]
|
||||||
|
pub messages: Option<Vec<BahnhofResDepartureMessage>>,
|
||||||
}
|
}
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct BahnhofResDepartureDestination {
|
pub struct BahnhofResDepartureDestination {
|
||||||
#[serde(default, rename = "name")]
|
#[serde(rename = "linienNummer")]
|
||||||
name: Option<String>,
|
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;
|
margin-right: 1em;
|
||||||
border-left: solid gray;
|
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>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user