summaryrefslogtreecommitdiff
path: root/src/generate_rss.rs
blob: 48a6917f45d21516d7acdd345a6cb17a98a45e78 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
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>"#)
}