get authors also from feed data + some css
This commit is contained in:
parent
4a9f5201d1
commit
150314936c
5 changed files with 140 additions and 39 deletions
|
|
@ -4,6 +4,7 @@ use feed_rs::model::Entry;
|
|||
use feed_rs::model::Feed;
|
||||
use ron::ser::{to_string_pretty, PrettyConfig};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::convert::AsRef;
|
||||
use std::fs;
|
||||
use std::io::BufReader;
|
||||
|
|
@ -13,9 +14,6 @@ use ureq::http::Response;
|
|||
use ureq::Body;
|
||||
use url::Url;
|
||||
|
||||
/// How many feed entries should be included in the planet
|
||||
const ENTRIES_LEN: usize = 10;
|
||||
|
||||
#[derive(Deserialize, Serialize, Default)]
|
||||
pub struct FetchData {
|
||||
pub etag: String,
|
||||
|
|
@ -135,8 +133,12 @@ impl FeedStore {
|
|||
Ok(Some(parser.parse(BufReader::new(file))?))
|
||||
}
|
||||
|
||||
pub fn collect(&self, feed_configs: &Vec<super::FeedConfig>) -> (Vec<Feed>, Vec<Entry>) {
|
||||
let mut feeds = Vec::new();
|
||||
pub fn collect(
|
||||
&self,
|
||||
feed_configs: &Vec<super::FeedConfig>,
|
||||
max_entries: usize,
|
||||
) -> (HashMap<String, Feed>, Vec<Entry>) {
|
||||
let mut feeds = HashMap::new();
|
||||
let mut entries = Vec::new();
|
||||
|
||||
for feed_config in feed_configs {
|
||||
|
|
@ -154,21 +156,24 @@ impl FeedStore {
|
|||
Ok(None) => continue,
|
||||
Ok(Some(f)) => f,
|
||||
};
|
||||
for entry in &mut feed.entries {
|
||||
entry.source = Some(feed_config.url.clone());
|
||||
}
|
||||
|
||||
entries.append(&mut std::mem::take(&mut feed.entries));
|
||||
feeds.push(feed);
|
||||
feeds.insert(feed_config.url.clone(), feed);
|
||||
// optimization to reduce memory usage
|
||||
if entries.len() > 4 * ENTRIES_LEN {
|
||||
entries = trim_entries(entries);
|
||||
if entries.len() > 4 * max_entries {
|
||||
entries = trim_entries(entries, max_entries);
|
||||
}
|
||||
}
|
||||
(feeds, trim_entries(entries))
|
||||
(feeds, trim_entries(entries, max_entries))
|
||||
}
|
||||
}
|
||||
|
||||
fn trim_entries(mut entries: Vec<Entry>) -> Vec<Entry> {
|
||||
fn trim_entries(mut entries: Vec<Entry>, max_entries: usize) -> Vec<Entry> {
|
||||
entries.sort_by_key(|e| std::cmp::Reverse(e.updated.or(e.published).unwrap_or_default()));
|
||||
entries.truncate(ENTRIES_LEN);
|
||||
entries.truncate(max_entries);
|
||||
entries
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,8 @@ struct Config {
|
|||
out_dir: String,
|
||||
/// templates folder
|
||||
templates_dir: String,
|
||||
/// How many feed entries should be included in the planet
|
||||
max_entries: usize,
|
||||
}
|
||||
|
||||
pub fn to_checked_pathbuf(dir: &str) -> PathBuf {
|
||||
|
|
|
|||
|
|
@ -2,21 +2,25 @@ use crate::feed_store::FeedStore;
|
|||
use crate::to_checked_pathbuf;
|
||||
use crate::Config;
|
||||
use anyhow::Result;
|
||||
use feed_rs::model::Feed;
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use tera::Tera;
|
||||
use tera::{from_value, Tera};
|
||||
|
||||
pub fn build(config: &Config, feed_store: &FeedStore) -> Result<()> {
|
||||
let tera = create_tera(&config.templates_dir)?;
|
||||
let mut tera = create_tera(&config.templates_dir)?;
|
||||
let out_dir = to_checked_pathbuf(&config.out_dir);
|
||||
|
||||
let mut context = tera::Context::new();
|
||||
let (feeds, entries) = feed_store.collect(&config.feeds);
|
||||
let (feeds, entries): (HashMap<String, Feed>, _) =
|
||||
feed_store.collect(&config.feeds, config.max_entries);
|
||||
context.insert("feeds", &feeds);
|
||||
context.insert("entries", &entries);
|
||||
context.insert("PKG_AUTHORS", env!("CARGO_PKG_AUTHORS"));
|
||||
context.insert("PKG_HOMEPAGE", env!("CARGO_PKG_HOMEPAGE"));
|
||||
context.insert("PKG_NAME", env!("CARGO_PKG_NAME"));
|
||||
context.insert("PKG_VERSION", env!("CARGO_PKG_VERSION"));
|
||||
tera.register_function("get_author", GetAuthorFunction { feeds });
|
||||
|
||||
for name in tera.get_template_names() {
|
||||
debug!("Processing template {name}");
|
||||
|
|
@ -33,3 +37,54 @@ fn create_tera(templates_dir: &str) -> Result<Tera> {
|
|||
tera.autoescape_on(vec![]);
|
||||
Ok(tera)
|
||||
}
|
||||
|
||||
struct GetAuthorFunction {
|
||||
feeds: HashMap<String, Feed>,
|
||||
}
|
||||
|
||||
impl tera::Function for GetAuthorFunction {
|
||||
fn call(&self, args: &HashMap<String, tera::Value>) -> Result<tera::Value, tera::Error> {
|
||||
let entry_val: tera::Map<_, _> = match args.get("entry") {
|
||||
None => {
|
||||
return Err(tera::Error::msg(
|
||||
"No argument of name 'entry' given to function.",
|
||||
))
|
||||
}
|
||||
Some(val) => from_value(val.clone())?,
|
||||
};
|
||||
|
||||
let feed_url: String = from_value(entry_val.get("source").unwrap().clone())?;
|
||||
let authors_val: Vec<tera::Map<_, _>> =
|
||||
from_value(entry_val.get("authors").unwrap().clone())?;
|
||||
|
||||
let mut authors: Vec<String> = Vec::new();
|
||||
for author_val in authors_val {
|
||||
let name: String = from_value(author_val.get("name").unwrap().clone())?;
|
||||
if is_valid_name(&name) {
|
||||
authors.push(name.clone());
|
||||
}
|
||||
}
|
||||
|
||||
if authors.is_empty() {
|
||||
authors.append(&mut self.find_authors_from_feed(&feed_url));
|
||||
}
|
||||
Ok(tera::Value::String(authors.join(", ")))
|
||||
}
|
||||
}
|
||||
|
||||
impl GetAuthorFunction {
|
||||
fn find_authors_from_feed(&self, feed_url: &str) -> Vec<String> {
|
||||
let feed = self.feeds.get(feed_url).unwrap();
|
||||
|
||||
feed.authors
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|x| x.name)
|
||||
.filter(is_valid_name)
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
fn is_valid_name(n: &String) -> bool {
|
||||
!n.is_empty() && n != "unknown" && n != "author"
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue