about summary refs log tree commit diff
diff options
context:
space:
mode:
authorgennyble <gen@nyble.dev>2024-04-13 05:39:43 -0500
committergennyble <gen@nyble.dev>2024-04-13 05:39:43 -0500
commit1b93aecbdc261ca2f7932db2754c6e33487dd9c8 (patch)
tree3b10f26a63098e8a169de63359881792fc234d5b
parenteafb6a862e5a525e615148dc0f297f1792d6ab89 (diff)
downloadawake-1b93aecbdc261ca2f7932db2754c6e33487dd9c8.tar.gz
awake-1b93aecbdc261ca2f7932db2754c6e33487dd9c8.zip
Atomizer: generate atom feeds
-rw-r--r--src/atomizer.rs163
1 files changed, 163 insertions, 0 deletions
diff --git a/src/atomizer.rs b/src/atomizer.rs
new file mode 100644
index 0000000..e6a147b
--- /dev/null
+++ b/src/atomizer.rs
@@ -0,0 +1,163 @@
+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("&lt;"),
+			'>' => ret.push_str("&gt;"),
+			'&' => ret.push_str("&amp;"),
+			'\'' => ret.push_str("&apos;"),
+			'"' => ret.push_str("&quot;"),
+			c => ret.push(c),
+		}
+	}
+
+	ret
+}
+
+fn cdataify(raw: &str) -> String {
+	format!("<![CDATA[{raw}]]>")
+}
+
+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!()
+			}
+		}
+	}
+}