Atom syndication
This commit is contained in:
parent
5f0c06b6cf
commit
f2da7f6e2d
16
Cargo.lock
generated
16
Cargo.lock
generated
|
@ -350,6 +350,15 @@ version = "0.14.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "html-escape"
|
||||||
|
version = "0.2.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6d1ad449764d627e22bfd7cd5e8868264fc9236e07c752972b4080cd351cb476"
|
||||||
|
dependencies = [
|
||||||
|
"utf8-width",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "html5ever"
|
name = "html5ever"
|
||||||
version = "0.26.0"
|
version = "0.26.0"
|
||||||
|
@ -512,6 +521,7 @@ version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
|
"html-escape",
|
||||||
"markdown",
|
"markdown",
|
||||||
"regex",
|
"regex",
|
||||||
"scraper",
|
"scraper",
|
||||||
|
@ -1194,6 +1204,12 @@ version = "0.7.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8-width"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
|
|
|
@ -16,3 +16,4 @@ derive_more = "0.99"
|
||||||
scraper = "0.19"
|
scraper = "0.19"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
xml-builder = "0.5"
|
xml-builder = "0.5"
|
||||||
|
html-escape = "0.2"
|
||||||
|
|
|
@ -13,6 +13,7 @@ pub struct Config {
|
||||||
pub struct Syndication {
|
pub struct Syndication {
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub link: String,
|
pub link: String,
|
||||||
|
pub blog_root: String,
|
||||||
pub icon: Option<String>,
|
pub icon: Option<String>,
|
||||||
pub subtitle: Option<String>,
|
pub subtitle: Option<String>,
|
||||||
pub atom: Option<AtomConfig>,
|
pub atom: Option<AtomConfig>,
|
||||||
|
|
|
@ -19,7 +19,7 @@ pub fn emoji_pass(markdown: &str, emoji_config: &Option<config::EmojiConfig>) ->
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let html_string = format!(
|
let html_string = format!(
|
||||||
"<img class=\"emoji\" src=\"{}/{}\"><img>",
|
"<img class=\"emoji\" src=\"{}/{}\"></img>",
|
||||||
emoji_config.as_ref().unwrap().emoji_web_directory,
|
emoji_config.as_ref().unwrap().emoji_web_directory,
|
||||||
emoji_file_name.unwrap().to_str().unwrap()
|
emoji_file_name.unwrap().to_str().unwrap()
|
||||||
);
|
);
|
||||||
|
|
|
@ -8,12 +8,14 @@ use tera::{Context, Tera};
|
||||||
pub struct BlogPost {
|
pub struct BlogPost {
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub human_date: String,
|
pub human_date: String,
|
||||||
pub sort_date: i64, // Sort date = unix timestamp
|
pub sort_date: i64, // Sort date = unix timestamp
|
||||||
pub content: String, // Unformatted Content of blog post can be used to display a preview or reading time estimate. Will be html when assigned but later turned into raw text
|
pub last_updated: i64,
|
||||||
|
pub content: String,
|
||||||
pub output_file_name: String,
|
pub output_file_name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate(mut blog_posts: Vec<BlogPost>, template_dir: &String) -> String {
|
pub fn generate(blog_posts: Vec<BlogPost>, template_dir: &String) -> String {
|
||||||
|
let mut blog_posts = blog_posts;
|
||||||
for post in &mut blog_posts {
|
for post in &mut blog_posts {
|
||||||
post.content = get_unformatted_text(post.content.clone());
|
post.content = get_unformatted_text(post.content.clone());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#![feature(str_split_remainder)]
|
#![feature(str_split_remainder)]
|
||||||
|
#![feature(ascii_char)]
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use derive_more::Constructor;
|
use derive_more::Constructor;
|
||||||
use markdown::{to_html_with_options, CompileOptions, Options};
|
use markdown::{to_html_with_options, CompileOptions, Options};
|
||||||
|
|
20
src/main.rs
20
src/main.rs
|
@ -39,15 +39,33 @@ fn generate() {
|
||||||
&file.file_name.clone().into_string().unwrap(),
|
&file.file_name.clone().into_string().unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let last_updated: Option<&String> = frontmatter.get("updated_at");
|
||||||
|
let updated = {
|
||||||
|
if last_updated.is_some() {
|
||||||
|
chrono::DateTime::parse_from_rfc3339(last_updated.unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.timestamp()
|
||||||
|
} else {
|
||||||
|
file.date.clone().timestamp()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
post_index.push(index::BlogPost::new(
|
post_index.push(index::BlogPost::new(
|
||||||
file.title,
|
file.title,
|
||||||
file.date.format("%Y-%m-%d").to_string(),
|
file.date.format("%Y-%m-%d").to_string(),
|
||||||
file.date.timestamp(),
|
file.date.timestamp(),
|
||||||
|
updated,
|
||||||
index_content,
|
index_content,
|
||||||
format!("{}.html", file.file_name.to_str().unwrap()),
|
format!("{}.html", file.file_name.to_str().unwrap()),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
if config.syndication.is_some() {
|
||||||
|
if config.syndication.as_ref().unwrap().atom.is_some() {
|
||||||
|
let atom = syndication::atom::generate(config.syndication.unwrap(), &post_index);
|
||||||
|
std::fs::write(format!("{}/atom.xml", config.output_dir), atom)
|
||||||
|
.unwrap_or_else(|_| panic!("Error writing atom feed"));
|
||||||
|
}
|
||||||
|
}
|
||||||
let index = index::generate(post_index, &config.templates_dir);
|
let index = index::generate(post_index, &config.templates_dir);
|
||||||
|
|
||||||
std::fs::write(format!("{}/index.html", config.output_dir), index)
|
std::fs::write(format!("{}/index.html", config.output_dir), index)
|
||||||
|
|
|
@ -1,40 +1,80 @@
|
||||||
use xml_builder::{XMLBuilder, XMLElement, XMLVersion};
|
use xml_builder::{XMLBuilder, XMLElement, XMLVersion};
|
||||||
|
|
||||||
|
use crate::{xml_tag_attribute, xml_tag_text};
|
||||||
|
|
||||||
pub fn generate(
|
pub fn generate(
|
||||||
config: crate::config::Syndication,
|
config: crate::config::Syndication,
|
||||||
post_index: &Vec<crate::index::BlogPost>,
|
post_index: &Vec<crate::index::BlogPost>,
|
||||||
) -> String {
|
) -> String {
|
||||||
let mut xml = XMLBuilder::new()
|
let mut xml = XMLBuilder::new()
|
||||||
.version(XMLVersion::XML1_1)
|
.version(XMLVersion::XML1_0)
|
||||||
.encoding("UTF-8".into())
|
.encoding("UTF-8".into())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let mut feed = XMLElement::new("feed");
|
let mut feed = XMLElement::new("feed");
|
||||||
feed.add_attribute("xmlns", "http://www.w3.org/2005/Atom");
|
feed.add_attribute("xmlns", "http://www.w3.org/2005/Atom");
|
||||||
|
|
||||||
let mut id = XMLElement::new("id");
|
xml_tag_text!("id", config.link.clone(), feed);
|
||||||
id.add_text(config.link).unwrap();
|
|
||||||
feed.add_child(id).unwrap();
|
|
||||||
|
|
||||||
let mut title = XMLElement::new("title");
|
xml_tag_text!("title", config.title, feed);
|
||||||
title.add_text(config.title).unwrap();
|
|
||||||
feed.add_child(title).unwrap();
|
xml_tag_attribute!("link", feed, ("href", &config.link));
|
||||||
|
|
||||||
|
let mut author = XMLElement::new("author");
|
||||||
|
let mut name = XMLElement::new("name");
|
||||||
|
name.add_text("kibty".to_string()).unwrap();
|
||||||
|
author.add_child(name).unwrap();
|
||||||
|
feed.add_child(author).unwrap();
|
||||||
|
|
||||||
let mut updated = XMLElement::new("updated");
|
|
||||||
let last_update = chrono::DateTime::from_timestamp(last_update(post_index), 0).unwrap();
|
let last_update = chrono::DateTime::from_timestamp(last_update(post_index), 0).unwrap();
|
||||||
updated.add_text(last_update.to_rfc3339()).unwrap();
|
xml_tag_text!("updated", last_update.to_rfc3339(), feed);
|
||||||
feed.add_child(updated).unwrap();
|
|
||||||
|
|
||||||
if config.subtitle.is_some() {
|
if config.subtitle.is_some() {
|
||||||
let mut subtitle = XMLElement::new("subtitle");
|
xml_tag_text!("subtitle", config.subtitle.unwrap(), feed);
|
||||||
subtitle.add_text(config.subtitle.unwrap()).unwrap();
|
|
||||||
feed.add_child(subtitle).unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.icon.is_some() {
|
if config.icon.is_some() {
|
||||||
let mut icon = XMLElement::new("icon");
|
xml_tag_text!("icon", config.icon.unwrap(), feed);
|
||||||
icon.add_text(config.icon.unwrap()).unwrap();
|
}
|
||||||
feed.add_child(icon).unwrap();
|
|
||||||
|
for post in post_index {
|
||||||
|
let mut entry = XMLElement::new("entry");
|
||||||
|
|
||||||
|
xml_tag_text!("title", post.title.clone(), entry);
|
||||||
|
|
||||||
|
xml_tag_attribute!(
|
||||||
|
"link",
|
||||||
|
entry,
|
||||||
|
(
|
||||||
|
"href",
|
||||||
|
&format!(
|
||||||
|
"{}{}/{}",
|
||||||
|
&config.link, &config.blog_root, &post.output_file_name
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
xml_tag_text!(
|
||||||
|
"id",
|
||||||
|
format!(
|
||||||
|
"{}{}/{}",
|
||||||
|
&config.link, &config.blog_root, &post.output_file_name
|
||||||
|
),
|
||||||
|
entry
|
||||||
|
);
|
||||||
|
let last_update = chrono::DateTime::from_timestamp(post.last_updated, 0)
|
||||||
|
.unwrap()
|
||||||
|
.to_rfc3339();
|
||||||
|
xml_tag_text!("updated", last_update, entry);
|
||||||
|
|
||||||
|
let mut content = XMLElement::new("content");
|
||||||
|
content.add_attribute("type", "html");
|
||||||
|
content
|
||||||
|
.add_text(crate::syndication::escape_html(post.content.clone()))
|
||||||
|
.unwrap();
|
||||||
|
entry.add_child(content).unwrap();
|
||||||
|
|
||||||
|
feed.add_child(entry).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
xml.set_root_element(feed);
|
xml.set_root_element(feed);
|
||||||
|
|
|
@ -1 +1,26 @@
|
||||||
pub mod atom;
|
pub mod atom;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! xml_tag_text {
|
||||||
|
($a: expr, $b: expr, $c: expr) => {
|
||||||
|
let mut tag = XMLElement::new($a);
|
||||||
|
tag.add_text($b).unwrap();
|
||||||
|
$c.add_child(tag).unwrap();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! xml_tag_attribute {
|
||||||
|
($a: expr, $b: expr, $( $c: expr),+ ) => {
|
||||||
|
let mut tag = XMLElement::new($a);
|
||||||
|
$(
|
||||||
|
tag.add_attribute($c.0,$c.1);
|
||||||
|
)+
|
||||||
|
$b.add_child(tag).unwrap();
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn escape_html(unescaped_html: String) -> String {
|
||||||
|
html_escape::encode_text(&unescaped_html).to_string()
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue