add upstream calendars page
This commit is contained in:
parent
830f45423f
commit
ef0d32f0b7
4 changed files with 103 additions and 33 deletions
25
src/main.rs
25
src/main.rs
|
@ -51,6 +51,26 @@ impl Config {
|
||||||
)
|
)
|
||||||
.chain(self.icals.iter().map(|ical| ical.dl.clone()))
|
.chain(self.icals.iter().map(|ical| ical.dl.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn upstreams(&self) -> Vec<CalendarUi> {
|
||||||
|
let Self {
|
||||||
|
campfires,
|
||||||
|
common_ninjas,
|
||||||
|
icals,
|
||||||
|
output: _,
|
||||||
|
} = self;
|
||||||
|
|
||||||
|
let mut upstreams: Vec<_> = campfires
|
||||||
|
.iter()
|
||||||
|
.map(|cfg| &cfg.ui)
|
||||||
|
.cloned()
|
||||||
|
.chain(common_ninjas.iter().map(|cfg| &cfg.ui).cloned())
|
||||||
|
.chain(icals.iter().map(|cfg| &cfg.ui).cloned())
|
||||||
|
.collect();
|
||||||
|
upstreams.sort_by_key(|ui| ui.short_name.clone());
|
||||||
|
|
||||||
|
upstreams
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(clap::Parser)]
|
#[derive(clap::Parser)]
|
||||||
|
@ -238,7 +258,7 @@ async fn do_everything(cli: &CliAuto) -> Result<()> {
|
||||||
|
|
||||||
let data = read_data_from_disk(&config)?;
|
let data = read_data_from_disk(&config)?;
|
||||||
let instances = process_data(&data, &config.output, now)?;
|
let instances = process_data(&data, &config.output, now)?;
|
||||||
output::write_html(&config.output, &instances, now)?;
|
output::write_html(&config.output, &config.upstreams(), &instances, now)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,7 +296,8 @@ fn main_debug_output(cli: CliDebugOutput) -> 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, &config.output, now).context("Failed to process data")?;
|
let instances = process_data(&data, &config.output, now).context("Failed to process data")?;
|
||||||
output::write_html(&config.output, &instances, now).context("Failed to output HTML")?;
|
output::write_html(&config.output, &config.upstreams(), &instances, now)
|
||||||
|
.context("Failed to output HTML")?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,24 @@ use std::{collections::BTreeSet, io::Write as _};
|
||||||
|
|
||||||
use crate::{EventInstance, prelude::*};
|
use crate::{EventInstance, prelude::*};
|
||||||
|
|
||||||
|
const CSS: &str = r#"
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: 14pt;
|
||||||
|
line-height: 1.6;
|
||||||
|
max-width: 700px;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
.past {
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
"#;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub(crate) struct Config {
|
pub(crate) struct Config {
|
||||||
/// Used as the OpenGraph description in meta tags
|
/// Used as the OpenGraph description in meta tags
|
||||||
|
@ -40,8 +58,17 @@ impl Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn calendar_link(calendar_ui: &crate::CalendarUi) -> maud::PreEscaped<String> {
|
||||||
|
if let Some(html_url) = &calendar_ui.html_url {
|
||||||
|
maud::html! { a href=(html_url) { (calendar_ui.short_name) } }
|
||||||
|
} else {
|
||||||
|
maud::html! { (calendar_ui.short_name)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn write_html(
|
pub(crate) fn write_html(
|
||||||
config: &Config,
|
config: &Config,
|
||||||
|
upstreams: &[crate::CalendarUi],
|
||||||
instances: &[EventInstance],
|
instances: &[EventInstance],
|
||||||
now: DateTime<chrono_tz::Tz>,
|
now: DateTime<chrono_tz::Tz>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
@ -118,12 +145,6 @@ pub(crate) fn write_html(
|
||||||
li class="past" { (time) " - " (summary) }
|
li class="past" { (time) " - " (summary) }
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
let calendar_link = if let Some(html_url) = &ei.calendar_ui.html_url {
|
|
||||||
maud::html! { a href=(html_url) { (ei.calendar_ui.short_name) } }
|
|
||||||
} else {
|
|
||||||
maud::html! { (ei.calendar_ui.short_name)}
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is where the main stuff happens
|
// This is where the main stuff happens
|
||||||
|
|
||||||
tracing::debug!(uid = ei.uid, summary = ei.summary);
|
tracing::debug!(uid = ei.uid, summary = ei.summary);
|
||||||
|
@ -131,7 +152,7 @@ pub(crate) fn write_html(
|
||||||
li { details {
|
li { details {
|
||||||
summary { (time) " - " (summary) }
|
summary { (time) " - " (summary) }
|
||||||
ul {
|
ul {
|
||||||
li { (calendar_link) " calendar" }
|
li { (calendar_link(&ei.calendar_ui)) " calendar" }
|
||||||
@if let Some(location) = &ei.location {
|
@if let Some(location) = &ei.location {
|
||||||
li { "Location: " (location) }
|
li { "Location: " (location) }
|
||||||
}
|
}
|
||||||
|
@ -155,7 +176,49 @@ pub(crate) fn write_html(
|
||||||
let final_path = "output/calendars.html";
|
let final_path = "output/calendars.html";
|
||||||
let mut f = std::fs::File::create(temp_path)?;
|
let mut f = std::fs::File::create(temp_path)?;
|
||||||
|
|
||||||
f.write_all("".as_bytes())?;
|
let description = "A list of upstream calendars used by this Wide-Angle Calendar instance";
|
||||||
|
let title = "Upstream calendars";
|
||||||
|
|
||||||
|
let s = maud::html! {
|
||||||
|
(maud::PreEscaped("<!DOCTYPE html>"))
|
||||||
|
html lang="en" {
|
||||||
|
head {
|
||||||
|
meta http-equiv="Content-Type" content="text/html; charset=utf-8" {}
|
||||||
|
meta name="viewport" content="width=device-width, initial-scale=1" {}
|
||||||
|
(maud::PreEscaped(CSS))
|
||||||
|
|
||||||
|
meta property="og:locale" content="en" {}
|
||||||
|
meta property="og:type" content="website" {}
|
||||||
|
|
||||||
|
meta name="description" content=(description) {}
|
||||||
|
meta property="description" content=(description) {}
|
||||||
|
meta property="og:description" content=(description) {}
|
||||||
|
|
||||||
|
title { (title) }
|
||||||
|
met property="og:title" content=(title) {}
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
h1 { (title) }
|
||||||
|
p {
|
||||||
|
a href="index.html" { "Wide-Angle Calendar" }
|
||||||
|
" / "
|
||||||
|
a href="calendars.html" { (title) }
|
||||||
|
}
|
||||||
|
|
||||||
|
p { "Written at: " (now.format("%F %T")) }
|
||||||
|
p { "These are the calendars that Wide-Angle Calendar pulls from." }
|
||||||
|
|
||||||
|
ol {
|
||||||
|
@for upstream in upstreams {
|
||||||
|
li { (calendar_link(upstream)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.into_string();
|
||||||
|
|
||||||
|
f.write_all(s.as_bytes())?;
|
||||||
std::fs::rename(temp_path, final_path)?;
|
std::fs::rename(temp_path, final_path)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,23 +226,6 @@ pub(crate) fn write_html(
|
||||||
let temp_path = "output/index.html.tmp";
|
let temp_path = "output/index.html.tmp";
|
||||||
let final_path = "output/index.html";
|
let final_path = "output/index.html";
|
||||||
let mut f = std::fs::File::create(temp_path)?;
|
let mut f = std::fs::File::create(temp_path)?;
|
||||||
let css = r#"
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
font-family: sans-serif;
|
|
||||||
font-size: 14pt;
|
|
||||||
line-height: 1.6;
|
|
||||||
max-width: 700px;
|
|
||||||
}
|
|
||||||
img {
|
|
||||||
max-width: 100%;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
.past {
|
|
||||||
color: #888;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
"#;
|
|
||||||
|
|
||||||
let description = &config.description;
|
let description = &config.description;
|
||||||
let title = &config.title;
|
let title = &config.title;
|
||||||
|
@ -190,7 +236,7 @@ pub(crate) fn write_html(
|
||||||
head {
|
head {
|
||||||
meta http-equiv="Content-Type" content="text/html; charset=utf-8" {}
|
meta http-equiv="Content-Type" content="text/html; charset=utf-8" {}
|
||||||
meta name="viewport" content="width=device-width, initial-scale=1" {}
|
meta name="viewport" content="width=device-width, initial-scale=1" {}
|
||||||
(maud::PreEscaped(css))
|
(maud::PreEscaped(CSS))
|
||||||
|
|
||||||
meta property="og:locale" content="en" {}
|
meta property="og:locale" content="en" {}
|
||||||
meta property="og:type" content="website" {}
|
meta property="og:type" content="website" {}
|
||||||
|
@ -206,6 +252,7 @@ pub(crate) fn write_html(
|
||||||
h1 { (title) }
|
h1 { (title) }
|
||||||
img src="hero.webp" width="700" height="233" {}
|
img src="hero.webp" width="700" height="233" {}
|
||||||
p { "Written at: " (now.format("%F %T")) }
|
p { "Written at: " (now.format("%F %T")) }
|
||||||
|
p { a href = "calendars.html" { "Upstream calendars" } }
|
||||||
@for entry in html_list {
|
@for entry in html_list {
|
||||||
(entry)
|
(entry)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,11 +19,12 @@ pub(crate) struct Config {
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct Event {
|
struct Event {
|
||||||
description: String,
|
#[serde(alias = "description")]
|
||||||
|
_description: String,
|
||||||
#[serde(alias = "endDate")]
|
#[serde(alias = "endDate")]
|
||||||
end_date: Option<String>,
|
_end_date: Option<String>,
|
||||||
#[serde(alias = "endTime")]
|
#[serde(alias = "endTime")]
|
||||||
end_time: Option<String>,
|
_end_time: Option<String>,
|
||||||
#[serde(alias = "eventName")]
|
#[serde(alias = "eventName")]
|
||||||
event_name: String,
|
event_name: String,
|
||||||
location: String,
|
location: String,
|
||||||
|
|
|
@ -36,10 +36,11 @@ impl Config {
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct Event {
|
struct Event {
|
||||||
#[serde(alias = "durationInMinutes")]
|
#[serde(alias = "durationInMinutes")]
|
||||||
duration_in_minutes: u32,
|
_duration_in_minutes: u32,
|
||||||
timestamp: i64,
|
timestamp: i64,
|
||||||
title: String,
|
title: String,
|
||||||
description: String,
|
#[serde(alias = "description")]
|
||||||
|
_description: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue