From 700c0ddd79fc6ca01d52250b69b02c1a13d4ddef Mon Sep 17 00:00:00 2001 From: Ben Bridle Date: Sun, 22 Feb 2026 10:15:06 +1300 Subject: Big rewrite A quick list of everything that's changed: - links to a duplicate heading beneath the same level 1 heading now work - rss feed generation using a .feed file - customisation of the html template using the html.template key - option to use symlinks instead of copying static files - fixed incorrect resolution of internal links - simplified different name forms with the Name type - allow linking to a redirect --- src/generate_rss.rs | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 src/generate_rss.rs (limited to 'src/generate_rss.rs') diff --git a/src/generate_rss.rs b/src/generate_rss.rs new file mode 100644 index 0000000..48a6917 --- /dev/null +++ b/src/generate_rss.rs @@ -0,0 +1,72 @@ +use crate::*; + +use std::collections::VecDeque; + +use chrono::{DateTime, Utc, Local}; + + +pub fn generate_rss(feed: &Feed, website: &Website) -> String { + let path = &feed.source_path; + let content = std::fs::read_to_string(path).unwrap(); + let mut lines: VecDeque<&str> = content.lines().collect(); + let base_url = website.config.get("rss.base_url"); + if base_url.is_empty() { + warn!("No value was given for 'rss.base_url' key in toaster.conf"); + } + let (parent_url, _) = feed.url.split_once('/').unwrap(); + + let channel_title = lines.pop_front().unwrap_or("No title"); + let last_build_date = match feed.last_modified { + Some(system_time) => system_time.into(), + None => Utc::now(), + }.to_rfc2822(); + let mut all_entries = String::new(); + + for line in &lines { + if line.is_empty() { continue } + if let Some((timestamp, name)) = line.split_once("::") { + let mut timestamp = timestamp.to_string(); + let entry_title = name; + if !timestamp.contains('T') { + timestamp.push_str("T00:00:00"); + } + if !timestamp.contains('Z') || timestamp.contains('+') { + let offset = Local::now().offset().to_string(); + timestamp.push_str(&offset); + } + let Ok(entry_time) = DateTime::parse_from_rfc3339(×tamp) else { + warn!("Invalid timestamp in RSS file {path:?}: {timestamp:?}"); + continue; + }; + let entry_link = format!("{base_url}/{parent_url}/{}.html", to_slug(name)); + + // Check that child page exists. + if let None = website.has_page(feed, name, "html") { + warn!("Feed {feed:?} contains link to nonexistent page {name:?}"); + } + + + let entry_string = format!(" + + {entry_title} + {entry_link} + {entry_time} + +"); + all_entries.push_str(&entry_string); + } else { + warn!("Invalid line in RSS file {path:?}: {line:?}"); + } + } + + format!( +r#" + + + {channel_title} + {base_url} + {last_build_date} +{all_entries} + +"#) +} -- cgit v1.2.3-70-g09d2