pretty up the page and allow for local calendars
This commit is contained in:
parent
5310f19383
commit
1717b3ab70
2 changed files with 68 additions and 10 deletions
29
src/main.rs
29
src/main.rs
|
@ -26,7 +26,7 @@ struct ConfigIcal {
|
||||||
short_name: String,
|
short_name: String,
|
||||||
|
|
||||||
/// URL to scrape to download the ics file
|
/// URL to scrape to download the ics file
|
||||||
ics_url: url::Url,
|
ics_url: Option<url::Url>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
@ -371,13 +371,10 @@ impl ICal {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let uid = ev
|
let Some(uid) = ev.ev.get_uid() else {
|
||||||
.ev
|
// If there's no UID, we can't apply recurrence exceptions
|
||||||
.get_uid()
|
return true;
|
||||||
.context(
|
};
|
||||||
"Every recurring event should have a UID so we can apply recurrence exceptions",
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let key = RecurrenceKey {
|
let key = RecurrenceKey {
|
||||||
recurrence_id: ev.dtstart,
|
recurrence_id: ev.dtstart,
|
||||||
uid,
|
uid,
|
||||||
|
@ -542,6 +539,10 @@ fn output_html(
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
max-width: 700px;
|
max-width: 700px;
|
||||||
}
|
}
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
.past {
|
.past {
|
||||||
color: #888;
|
color: #888;
|
||||||
}
|
}
|
||||||
|
@ -552,6 +553,7 @@ fn output_html(
|
||||||
let title = &config.title;
|
let title = &config.title;
|
||||||
|
|
||||||
let s = maud::html! {
|
let s = maud::html! {
|
||||||
|
(maud::PreEscaped("<!DOCTYPE html>"))
|
||||||
html lang="en" {
|
html lang="en" {
|
||||||
head {
|
head {
|
||||||
meta http-equiv="Content-Type" content="text/html; charset=utf-8" {}
|
meta http-equiv="Content-Type" content="text/html; charset=utf-8" {}
|
||||||
|
@ -561,6 +563,7 @@ fn output_html(
|
||||||
meta property="og:locale" content="en" {}
|
meta property="og:locale" content="en" {}
|
||||||
meta property="og:type" content="website" {}
|
meta property="og:type" content="website" {}
|
||||||
|
|
||||||
|
meta name="description" content=(description) {}
|
||||||
meta property="description" content=(description) {}
|
meta property="description" content=(description) {}
|
||||||
meta property="og:description" content=(description) {}
|
meta property="og:description" content=(description) {}
|
||||||
|
|
||||||
|
@ -569,6 +572,7 @@ fn output_html(
|
||||||
}
|
}
|
||||||
body {
|
body {
|
||||||
h1 { (title) }
|
h1 { (title) }
|
||||||
|
img src="hero.webp" width="700" height="233" {}
|
||||||
p { "Written at: " (now.to_rfc3339()) }
|
p { "Written at: " (now.to_rfc3339()) }
|
||||||
@for entry in html_list {
|
@for entry in html_list {
|
||||||
(entry)
|
(entry)
|
||||||
|
@ -600,8 +604,11 @@ async fn do_everything(cli: &CliAuto) -> Result<()> {
|
||||||
.user_agent(APP_USER_AGENT)
|
.user_agent(APP_USER_AGENT)
|
||||||
.build()?;
|
.build()?;
|
||||||
for ical in &config.icals {
|
for ical in &config.icals {
|
||||||
tracing::info!(url = ical.ics_url.to_string(), "requesting...");
|
let Some(ics_url) = &ical.ics_url else {
|
||||||
let resp = client.get(ical.ics_url.clone()).send().await?;
|
continue;
|
||||||
|
};
|
||||||
|
tracing::info!(url = ics_url.to_string(), "requesting...");
|
||||||
|
let resp = client.get(ics_url.clone()).send().await?;
|
||||||
if resp.status() != 200 {
|
if resp.status() != 200 {
|
||||||
bail!("Bad status {}", resp.status());
|
bail!("Bad status {}", resp.status());
|
||||||
}
|
}
|
||||||
|
@ -639,6 +646,8 @@ fn main_auto(cli: CliAuto) -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main_ics_debug(cli: CliIcsDebug) -> Result<()> {
|
fn main_ics_debug(cli: CliIcsDebug) -> Result<()> {
|
||||||
|
tracing_subscriber::fmt::init();
|
||||||
|
tracing::info!("Started tracing");
|
||||||
let config = std::fs::read_to_string(&cli.config)?;
|
let config = std::fs::read_to_string(&cli.config)?;
|
||||||
let config: Config = toml::from_str(&config)?;
|
let config: Config = toml::from_str(&config)?;
|
||||||
|
|
||||||
|
|
49
src/tests.rs
49
src/tests.rs
|
@ -80,6 +80,55 @@ END:VCALENDAR
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hand_written() -> Result<()> {
|
||||||
|
let s = r#"
|
||||||
|
BEGIN:VCALENDAR
|
||||||
|
|
||||||
|
COMMENT:August
|
||||||
|
|
||||||
|
BEGIN:VEVENT
|
||||||
|
DTSTART;TZID=America/Chicago:20250819T210000
|
||||||
|
DTEND;TZID=America/Chicago:20250819T223000
|
||||||
|
SUMMARY:Redacted
|
||||||
|
END:VEVENT
|
||||||
|
|
||||||
|
BEGIN:VEVENT
|
||||||
|
DTSTART;TZID=America/Chicago:20250823T170000
|
||||||
|
SUMMARY:Redacted
|
||||||
|
URL:https://www.example.com
|
||||||
|
END:VEVENT
|
||||||
|
|
||||||
|
END:VCALENDAR
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let ical = ICal::read_from_str(s)?;
|
||||||
|
let params = Parameters {
|
||||||
|
ignore_before: chicago_time(2025, 1, 1, 0, 0, 0),
|
||||||
|
output_start: chicago_time(2025, 7, 1, 0, 0, 0),
|
||||||
|
output_stop: chicago_time(2025, 10, 1, 0, 0, 0),
|
||||||
|
tz: chrono_tz::America::Chicago,
|
||||||
|
};
|
||||||
|
let instances = ical.event_instances(¶ms)?;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
[instances[0].dtstart, instances[1].dtstart,],
|
||||||
|
[
|
||||||
|
DatePerhapsTime {
|
||||||
|
dt: chicago_time(2025, 8, 19, 21, 0, 0),
|
||||||
|
all_day: false,
|
||||||
|
},
|
||||||
|
DatePerhapsTime {
|
||||||
|
dt: chicago_time(2025, 8, 23, 17, 0, 0),
|
||||||
|
all_day: false,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
assert_eq!(instances.len(), 2);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Expect that recurrent exceptions work correctly and don't duplicate events
|
/// Expect that recurrent exceptions work correctly and don't duplicate events
|
||||||
#[test]
|
#[test]
|
||||||
fn recurrence_exceptions() -> Result<()> {
|
fn recurrence_exceptions() -> Result<()> {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue