summaryrefslogtreecommitdiff
path: root/src/generate_rss.rs
diff options
context:
space:
mode:
authorBen Bridle <ben@derelict.engineering>2026-02-22 10:15:06 +1300
committerBen Bridle <ben@derelict.engineering>2026-02-22 10:15:33 +1300
commit700c0ddd79fc6ca01d52250b69b02c1a13d4ddef (patch)
tree9c3c31e8d9cde40dbcc689c0abd876e57a10f028 /src/generate_rss.rs
parent8c2ac6d92f6a4579591f748eebcbca2b9913d92d (diff)
downloadtoaster-700c0ddd79fc6ca01d52250b69b02c1a13d4ddef.zip
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
Diffstat (limited to 'src/generate_rss.rs')
-rw-r--r--src/generate_rss.rs72
1 files changed, 72 insertions, 0 deletions
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(&timestamp) 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!("
+ <item>
+ <title>{entry_title}</title>
+ <link>{entry_link}</link>
+ <pubDate>{entry_time}</pubDate>
+ </item>
+");
+ all_entries.push_str(&entry_string);
+ } else {
+ warn!("Invalid line in RSS file {path:?}: {line:?}");
+ }
+ }
+
+ format!(
+r#"<?xml version="1.0" encoding="UTF-8" ?>
+<rss version="2.0">
+ <channel>
+ <title>{channel_title}</title>
+ <link>{base_url}</link>
+ <lastBuildDate>{last_build_date}</lastBuildDate>
+{all_entries}
+ </channel>
+</rss>"#)
+}