cosmetic updates
This commit is contained in:
parent
7a2fba6804
commit
a4e4c89e15
2 changed files with 58 additions and 31 deletions
27
README.md
27
README.md
|
@ -1,21 +1,8 @@
|
||||||
Merges multiple ics files into one stream
|
todo
|
||||||
|
|
||||||
Try `cargo run -- ics-debug --tz America/New_York sample-data/nascar.ics sample-data/formula-1.ics`
|
- [ ] Rewrite README considering best practices
|
||||||
|
- [ ] Add dynamic OpenGraph meta tags
|
||||||
Expected output is the next month or so of NASCAR and Formula 1 racing:
|
- [ ] HTML templating for faster styling
|
||||||
|
- [ ] Maybe put descriptions behind `details` tag
|
||||||
```
|
- [ ] Publish ICS to subscribe to?
|
||||||
2025-08-03 00:00:00 EDT - NASCAR Cup - Iowa Corn 350
|
- [ ] systemd unit or something
|
||||||
2025-08-03 00:00:00 EDT - F1 - Lenovo Hungarian Grand Prix
|
|
||||||
2025-08-10 00:00:00 EDT - NASCAR Cup - Go Bowling At The Glen (Watkins Glen)
|
|
||||||
2025-08-16 00:00:00 EDT - NASCAR Cup - Cook Out 400 (Richmond)
|
|
||||||
2025-08-23 00:00:00 EDT - NASCAR Cup - Coke Zero Sugar 400 (Daytona)
|
|
||||||
2025-08-31 00:00:00 EDT - NASCAR Cup -Playoff- Southern 500 (Darlington)
|
|
||||||
2025-08-31 00:00:00 EDT - F1 - Heineken Dutch Grand Prix
|
|
||||||
2025-09-07 00:00:00 EDT - NASCAR Cup -Playoff- Enjoy Illinois 300 (Gateway)
|
|
||||||
2025-09-07 00:00:00 EDT - F1 - Gran Premio d'Italia
|
|
||||||
2025-09-13 00:00:00 EDT - NASCAR Cup -Playoff- Bass Pro Shops Night Race (Bristol)
|
|
||||||
2025-09-21 00:00:00 EDT - F1 - Qatar Airways Azerbaijan Grand Prix
|
|
||||||
```
|
|
||||||
|
|
||||||
If the sample data is old, try the iCal links from <https://toomuchracing.com/calendar/>, e.g. `curl https://calendar.google.com/calendar/ical/fa9bjl6tu13dd10b066stoo5do%40group.calendar.google.com/public/basic.ics > sample-data/formula-1.ics`
|
|
||||||
|
|
62
src/main.rs
62
src/main.rs
|
@ -15,7 +15,7 @@ struct ConfigIcal {
|
||||||
google_id: Option<String>,
|
google_id: Option<String>,
|
||||||
|
|
||||||
/// A canonical webpage we can direct users to
|
/// A canonical webpage we can direct users to
|
||||||
html_url: url::Url,
|
html_url: Option<url::Url>,
|
||||||
|
|
||||||
/// Very short name for putting on each event
|
/// Very short name for putting on each event
|
||||||
short_name: String,
|
short_name: String,
|
||||||
|
@ -26,10 +26,16 @@ struct ConfigIcal {
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct ConfigOutput {
|
struct ConfigOutput {
|
||||||
|
/// Used as the OpenGraph description in meta tags
|
||||||
|
description: String,
|
||||||
|
|
||||||
/// Timezone to use for output (e.g. "Antarctica/South_Pole")
|
/// Timezone to use for output (e.g. "Antarctica/South_Pole")
|
||||||
///
|
///
|
||||||
/// <https://en.wikipedia.org/wiki/List_of_tz_database_time_zones>
|
/// <https://en.wikipedia.org/wiki/List_of_tz_database_time_zones>
|
||||||
timezone: chrono_tz::Tz,
|
timezone: chrono_tz::Tz,
|
||||||
|
|
||||||
|
/// Used as the page title and OpenGraph title in meta tags
|
||||||
|
title: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
@ -359,7 +365,11 @@ fn process_data(data: &Data, now: DateTime<chrono_tz::Tz>) -> Result<Vec<EventWi
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Don't print to stdout / stderr
|
// FIXME: Don't print to stdout / stderr
|
||||||
fn output_html(instances: &[EventWithUrl], now: DateTime<chrono_tz::Tz>) -> Result<()> {
|
fn output_html(
|
||||||
|
config: &ConfigOutput,
|
||||||
|
instances: &[EventWithUrl],
|
||||||
|
now: DateTime<chrono_tz::Tz>,
|
||||||
|
) -> Result<()> {
|
||||||
let today = now.date_naive();
|
let today = now.date_naive();
|
||||||
let mut last_month_printed: Option<String> = None;
|
let mut last_month_printed: Option<String> = None;
|
||||||
let mut last_date_printed = None;
|
let mut last_date_printed = None;
|
||||||
|
@ -437,10 +447,16 @@ fn output_html(instances: &[EventWithUrl], now: DateTime<chrono_tz::Tz>) -> Resu
|
||||||
li class="past" { (time) " - " (summary) }
|
li class="past" { (time) " - " (summary) }
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
let calendar_link = if let Some(html_url) = &ei.calendar.html_url {
|
||||||
|
maud::html! { a href=(html_url) { (ei.calendar.short_name) } }
|
||||||
|
} else {
|
||||||
|
maud::html! { (ei.calendar.short_name)}
|
||||||
|
};
|
||||||
|
|
||||||
day_list.push(maud::html! {
|
day_list.push(maud::html! {
|
||||||
li { p { (time) " - " (summary) }
|
li { p { (time) " - " (summary) }
|
||||||
ul {
|
ul {
|
||||||
li { a href=(ei.calendar.html_url) { (ei.calendar.short_name) } }
|
li { (calendar_link) " calendar" }
|
||||||
@if let Some(location) = location {
|
@if let Some(location) = location {
|
||||||
li { "Location: " (location) }
|
li { "Location: " (location) }
|
||||||
}
|
}
|
||||||
|
@ -476,12 +492,33 @@ fn output_html(instances: &[EventWithUrl], now: DateTime<chrono_tz::Tz>) -> Resu
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
|
let description = &config.description;
|
||||||
|
let title = &config.title;
|
||||||
|
|
||||||
let s = maud::html! {
|
let s = maud::html! {
|
||||||
(maud::PreEscaped(css))
|
html lang="en" {
|
||||||
h1 { "Wide-Angle Calendar" }
|
head {
|
||||||
p { "Written at: " (now.to_rfc3339()) }
|
meta http-equiv="Content-Type" content="text/html; charset=utf-8" {}
|
||||||
@for entry in html_list {
|
meta name="viewport" content="width=device-width, initial-scale=1" {}
|
||||||
(entry)
|
(maud::PreEscaped(css))
|
||||||
|
|
||||||
|
meta property="og:locale" content="en" {}
|
||||||
|
meta property="og:type" content="website" {}
|
||||||
|
|
||||||
|
meta property="description" content=(description) {}
|
||||||
|
meta property="og:description" content=(description) {}
|
||||||
|
|
||||||
|
title { (title) }
|
||||||
|
met property="og:title" content=(title) {}
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
h1 { (title) }
|
||||||
|
p { "Written at: " (now.to_rfc3339()) }
|
||||||
|
@for entry in html_list {
|
||||||
|
(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.into_string();
|
.into_string();
|
||||||
|
@ -525,10 +562,13 @@ async fn do_everything(cli: &CliAuto) -> Result<()> {
|
||||||
let tz = &config.output.timezone;
|
let tz = &config.output.timezone;
|
||||||
let now = Utc::now().with_timezone(tz);
|
let now = Utc::now().with_timezone(tz);
|
||||||
let instances = process_data(&data, now)?;
|
let instances = process_data(&data, now)?;
|
||||||
output_html(&instances, now)?;
|
output_html(&config.output, &instances, now)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Seconds to sleep between auto cycles
|
||||||
|
const SLEEP_SECS: u64 = 9000;
|
||||||
|
|
||||||
fn main_auto(cli: CliAuto) -> Result<()> {
|
fn main_auto(cli: CliAuto) -> Result<()> {
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
loop {
|
loop {
|
||||||
|
@ -539,7 +579,7 @@ fn main_auto(cli: CliAuto) -> Result<()> {
|
||||||
})?;
|
})?;
|
||||||
rt.shutdown_timeout(Duration::from_secs(10));
|
rt.shutdown_timeout(Duration::from_secs(10));
|
||||||
tracing::info!("The service is eeping");
|
tracing::info!("The service is eeping");
|
||||||
std::thread::sleep(Duration::from_secs(5823));
|
std::thread::sleep(Duration::from_secs(SLEEP_SECS));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -552,7 +592,7 @@ fn main_ics_debug(cli: CliIcsDebug) -> Result<()> {
|
||||||
let tz = &config.output.timezone;
|
let tz = &config.output.timezone;
|
||||||
let now = Utc::now().with_timezone(tz);
|
let now = Utc::now().with_timezone(tz);
|
||||||
let instances = process_data(&data, now)?;
|
let instances = process_data(&data, now)?;
|
||||||
output_html(&instances, now)?;
|
output_html(&config.output, &instances, now)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue