use std::str::FromStr; use bempline::{variables, Document, Options}; use camino::{Utf8Path, Utf8PathBuf}; use confindent::{Confindent, Value}; use cutie::Html; use time::format_description::well_known; use crate::{markup, templated::Templated, timeparse}; pub fn main() -> ! { let awake_conf = Confindent::from_file(std::env::args().nth(2).unwrap()).unwrap(); let atom_conf_path = std::env::args().nth(3).unwrap_or(String::from("atom.conf")); let atom_conf = Confindent::from_file(atom_conf_path).unwrap(); let root: Utf8PathBuf = awake_conf.child_parse("Webroot").unwrap(); let atom = Document::from_file( root.clone() .join(atom_conf.child_value("Template").unwrap()) .canonicalize_utf8() .unwrap(), Options::default(), ) .unwrap(); let feeds = atom_conf.children("Feed"); for feed in feeds { make_feed(feed, &root, atom.clone()) } std::process::exit(0); } pub fn make_feed(feed: &Value, root: &Utf8Path, mut atom: Document) { let feed_relout: Utf8PathBuf = feed.child_parse("Output").unwrap(); let feed_link = feed.child_owned("Link").unwrap(); let feed_id = feed.child_owned("Id").unwrap(); let feed_title = feed.child_owned("Title").unwrap(); let feed_subtitle = feed.child_owned("Subtitle").unwrap(); let feed_updated = feed.child_owned("Updated").unwrap(); let feed_author_name = feed.get("Author/Name").unwrap(); let feed_author_email = feed.get("Author/Email").unwrap(); variables!( atom, feed_link, feed_id, feed_title, feed_subtitle, feed_updated, feed_author_email, feed_author_name ); let entries = feed.children("Entry"); let entry_pattern = atom.get_pattern("entry").unwrap(); for entry in entries { let entry_relpath: Utf8PathBuf = entry.parse().unwrap(); let entry_path = root.join(&entry_relpath); println!("entry {entry_relpath}"); let entry_content = match std::fs::read_to_string(&entry_path) { Ok(ok) => ok, Err(e) => { panic!("failed to get file at {entry_path}: {e}"); } }; let entry_templated = Templated::from_str(&entry_content).unwrap(); let entry_title = entry .child_value("Title") .unwrap_or_else(|| entry_templated.frontmatter.get("title").unwrap()); let entry_link = entry.child_value("Link").unwrap(); let entry_id = entry.child_value("Id").unwrap(); let entry_published_raw = entry .child_value("Published") .unwrap_or_else(|| entry_templated.frontmatter.get("published").unwrap()); let entry_updated = timeparse::parse(entry.child_value("Updated").unwrap_or_else(|| { entry_templated .frontmatter .get("updated") .unwrap_or(entry_published_raw) })) .unwrap() .format(&well_known::Rfc3339) .unwrap(); let entry_published = timeparse::parse(entry_published_raw) .unwrap() .format(&well_known::Rfc3339) .unwrap(); let mut entry_content = markup::process(&entry_templated.content); if let Some(part_id) = entry .child_value("Part") .map(|raw| raw.strip_prefix('#')) .flatten() { let cutie = cutie::Html::parse(entry_content); let found = cutie.get_by_id(part_id).unwrap(); entry_content = found.to_string(); } let mut pattern = entry_pattern.clone(); variables!( pattern, entry_title, entry_link, entry_id, entry_published, entry_updated ); pattern.set("entry_content", cdataify(&entry_content)); atom.set_pattern("entry", pattern); } let string = atom.compile(); let feed_out = root.join(feed_relout); std::fs::write(feed_out, string).unwrap(); } //FIXME: do NOT use this name fn htmlspecialchars(raw: &str) -> String { let mut ret = String::new(); for ch in raw.chars() { match ch { '<' => ret.push_str("<"), '>' => ret.push_str(">"), '&' => ret.push_str("&"), '\'' => ret.push_str("'"), '"' => ret.push_str("""), c => ret.push(c), } } ret } fn cdataify(raw: &str) -> String { format!("") } fn fix_links(html: &mut Html, path: Utf8PathBuf) { let root = match path.file_name() { Some(_) => path.parent().unwrap().to_owned(), None => path, }; for tag in html.child_tags_mut() { if let Some(src) = tag.get_attribute("src") { if !src.starts_with("http") { todo!() } } } }