147 lines
4.9 KiB
Rust
147 lines
4.9 KiB
Rust
use crate::cohost_account::CohostAccount;
|
|
use crate::cohost_posts::*;
|
|
use crate::ARGS;
|
|
use atom_syndication::LinkBuilder;
|
|
use rss::extension::atom::{AtomExtensionBuilder, Link};
|
|
use rss::Channel;
|
|
|
|
fn rel_link_for(rel: &str, project_name: &str, page_number: u64) -> Link {
|
|
LinkBuilder::default()
|
|
.rel(rel)
|
|
.href(format!(
|
|
"https://{}{}{}/feed.rss?page={}",
|
|
&ARGS.domain,
|
|
&ARGS.base_url,
|
|
project_name.clone(),
|
|
page_number
|
|
))
|
|
.build()
|
|
}
|
|
|
|
pub fn channel_for_posts_page(
|
|
project_name: impl AsRef<str>,
|
|
project: CohostAccount,
|
|
mut page: CohostPostsPage,
|
|
originals_only: bool,
|
|
) -> Channel {
|
|
let project_name = project_name.as_ref().clone();
|
|
let mut builder = rss::ChannelBuilder::default();
|
|
builder
|
|
.title(format!(
|
|
"{} Cohost Posts{}",
|
|
project.display_name,
|
|
if originals_only { "" } else { " and Shares" }
|
|
))
|
|
.description(project.description)
|
|
.generator(Some(format!(
|
|
"{} {}",
|
|
env!("CARGO_CRATE_NAME"),
|
|
env!("CARGO_PKG_VERSION")
|
|
)))
|
|
.link(format!("https://cohost.org/{}", project_name,));
|
|
|
|
let mut atom = AtomExtensionBuilder::default();
|
|
let links = vec![
|
|
rel_link_for("self", project_name, 0),
|
|
rel_link_for("first", project_name, 0),
|
|
];
|
|
atom.links(links);
|
|
|
|
builder.atom_ext(Some(atom.build()));
|
|
|
|
page.items.sort_by_key(|item| item.published_at);
|
|
let mut items = Vec::with_capacity(page.number_items);
|
|
for item in page.items {
|
|
let mut item_builder = rss::ItemBuilder::default();
|
|
let mut categories: Vec<rss::Category> = Vec::with_capacity(item.tags.len());
|
|
for tag in item.tags.iter().cloned() {
|
|
categories.push(rss::Category {
|
|
name: tag,
|
|
domain: Some("https://cohost.org".into()),
|
|
});
|
|
}
|
|
item_builder
|
|
.link(item.url.clone())
|
|
.title(item.headline)
|
|
.author(item.poster.handle)
|
|
.guid(Some(rss::Guid {
|
|
value: item.url.clone(),
|
|
permalink: true,
|
|
}))
|
|
.categories(categories)
|
|
.pub_date(item.published_at.to_rfc2822())
|
|
.source(Some(rss::Source {
|
|
title: Some(format!("{} Cohost Posts", project.display_name)),
|
|
url: format!("https://{}/feed/{}.rss", ARGS.domain, project_name),
|
|
}));
|
|
|
|
let mut body_text = String::new();
|
|
|
|
if let Some(shared_post_id) = item.transparent_share_of_post_id {
|
|
if originals_only {
|
|
continue;
|
|
}
|
|
body_text.push_str(&format!(
|
|
"(share of post {} without any commentary)\n\n---\n\n",
|
|
shared_post_id
|
|
));
|
|
} else if item.share_tree.len() == 1 {
|
|
body_text.push_str("(in reply to another post)\n\n---\n\n")
|
|
} else if item.share_tree.len() > 1 {
|
|
body_text.push_str(&format!(
|
|
"(in reply to {} other posts)\n\n---\n\n",
|
|
item.share_tree.len()
|
|
));
|
|
}
|
|
|
|
if item.cws.is_empty() {
|
|
body_text.push_str(&item.plain_body);
|
|
} else {
|
|
body_text.push_str("Sensitive post, body text omitted. Content warnings:");
|
|
for cw in item.cws {
|
|
body_text.push_str(&format!(" {},", cw));
|
|
}
|
|
body_text.pop(); // Remove trailing comma
|
|
body_text.push_str("\n\n---\n\n")
|
|
};
|
|
|
|
if !item.tags.is_empty() {
|
|
body_text.push_str("\n\n Post tagged:");
|
|
for tag in item.tags {
|
|
body_text.push_str(&format!(" #{},", tag));
|
|
}
|
|
body_text.pop(); // Remove trailing comma
|
|
}
|
|
|
|
use pulldown_cmark::Options;
|
|
let options = Options::ENABLE_FOOTNOTES
|
|
& Options::ENABLE_STRIKETHROUGH
|
|
& Options::ENABLE_TABLES
|
|
& Options::ENABLE_TASKLISTS;
|
|
let parser = pulldown_cmark::Parser::new_ext(&body_text, options);
|
|
let mut html_output = String::new();
|
|
pulldown_cmark::html::push_html(&mut html_output, parser);
|
|
item_builder.content(html_output);
|
|
|
|
for attachment in item.blocks.into_iter().filter_map(|block| block.attachment) {
|
|
use mime_guess::from_path as guess_mime_from_path;
|
|
use rss::EnclosureBuilder;
|
|
let enclosure = EnclosureBuilder::default()
|
|
.mime_type(
|
|
guess_mime_from_path(&attachment.file_url)
|
|
.first_or_octet_stream()
|
|
.to_string(),
|
|
)
|
|
.url(attachment.file_url)
|
|
.build();
|
|
item_builder.enclosure(enclosure);
|
|
}
|
|
|
|
items.push(item_builder.build());
|
|
}
|
|
|
|
builder.items(items);
|
|
|
|
builder.build()
|
|
}
|