112 lines
3.9 KiB
Rust
112 lines
3.9 KiB
Rust
//! # RSS Generator
|
|
//!
|
|
//! A custom RSS generator. It crawls the template sub-directories containing
|
|
//! articles for syndication, extracts relevant information and writes the items
|
|
//! to `./static/feed.rss`.
|
|
//!
|
|
extern crate regex;
|
|
extern crate rss;
|
|
|
|
use regex::Regex;
|
|
use rss::{ChannelBuilder, Item};
|
|
use std::{error, fs, fs::File, io::prelude::*};
|
|
|
|
fn main() -> Result<(), Box<dyn error::Error>> {
|
|
// create rss channel for mycelial.technology
|
|
let mut channel = ChannelBuilder::default()
|
|
.title("mycelial technology")
|
|
.link("https://mycelial.technology")
|
|
.description(
|
|
"glyph's RSS feed. Biophilic musings on carbon-based and silicon-based technologies.",
|
|
)
|
|
.build()?;
|
|
|
|
// list template directories containing articles for syndication
|
|
let bacteria = "./site/bacteria";
|
|
let computers = "./site/computers";
|
|
let fungi = "./site/fungi";
|
|
let plants = "./site/plants";
|
|
|
|
// add directories to a vector
|
|
let dirs = vec![bacteria, computers, fungi, plants];
|
|
|
|
// create vectors for item fields
|
|
let mut titles = Vec::new();
|
|
let mut pub_dates = Vec::new();
|
|
let mut urls = Vec::new();
|
|
let mut articles = Vec::new();
|
|
|
|
// loop through template directories and extract item field values
|
|
for dir in dirs {
|
|
for entry in fs::read_dir(dir)? {
|
|
let entry = entry?;
|
|
let path = entry.path();
|
|
|
|
if !path.ends_with("index.html") {
|
|
// populate item url vector from article filenames
|
|
let re_url = Regex::new("./site/(.*).html")?;
|
|
let caps_url = re_url.captures(
|
|
path.to_str()
|
|
.expect("Failed to convert file path to string slice for regex capture"),
|
|
);
|
|
if let Some(url) = caps_url {
|
|
let article_url = url[1].replace("_", "-");
|
|
let full_url = format!("https://mycelial.technology/{}", article_url);
|
|
urls.push(full_url);
|
|
};
|
|
|
|
// open the file (article) and read it to a string
|
|
let mut file = File::open(path)?;
|
|
let mut contents = String::new();
|
|
file.read_to_string(&mut contents)?;
|
|
|
|
// populate item title vector from article heading
|
|
let re_h2 = Regex::new("<h2>(.*)</h2>")?;
|
|
let caps_h2 = re_h2.captures(&contents);
|
|
if let Some(title) = caps_h2 {
|
|
titles.push(title[1].to_string());
|
|
};
|
|
|
|
// populate pub_date vector from first italic element in article
|
|
let re_i = Regex::new("<i>(.*)</i>")?;
|
|
let caps_i = re_i.captures(&contents);
|
|
if let Some(date) = caps_i {
|
|
pub_dates.push(date[1].to_string());
|
|
};
|
|
|
|
// populate article content vector from article element
|
|
let re_article = Regex::new(r"<article>[\s\S]*</article>")?;
|
|
let caps_article = re_article.captures(&contents);
|
|
if let Some(content) = caps_article {
|
|
articles.push(content[0].to_string());
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
// get length of titles vector (serves as proxy for total number of articles)
|
|
let library = titles.len();
|
|
|
|
// create vector for channel items
|
|
let mut items = Vec::new();
|
|
|
|
// loop through vectors of item fields and create items accordingly
|
|
for x in 0..library {
|
|
let mut item = Item::default();
|
|
item.set_title(titles[x].to_string());
|
|
item.set_link(urls[x].to_string());
|
|
item.set_pub_date(pub_dates[x].to_string());
|
|
item.set_description(articles[x].to_string());
|
|
items.push(item)
|
|
}
|
|
|
|
// add the items to the channel
|
|
channel.set_items(items);
|
|
|
|
// write the channel to file
|
|
let rss_file = File::create("./static/feed.rss")?;
|
|
channel.write_to(rss_file)?;
|
|
|
|
Ok(())
|
|
}
|