Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added support for multiple feeds
Browse files Browse the repository at this point in the history
LunarEclipse363 committed May 18, 2024
1 parent cebeb3a commit 0ca6468
Showing 19 changed files with 127 additions and 113 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -7,6 +7,9 @@
- Fix link check report inconsistency
- Fix resizing for images with EXIF orientation
- Add MIME type to get_image_metadata
- Added support for generating multiple kinds of feeds at once
- Changed config options named `generate_feed` to `generate_feeds`
- Changed config option `feed_filename: String` to `feed_filenames: Vec<String>`

## 0.18.0 (2023-12-18)

38 changes: 19 additions & 19 deletions components/config/src/config/languages.rs
Original file line number Diff line number Diff line change
@@ -14,11 +14,11 @@ pub struct LanguageOptions {
pub title: Option<String>,
/// Description of the site. Defaults to None
pub description: Option<String>,
/// Whether to generate a feed for that language, defaults to `false`
pub generate_feed: bool,
/// The filename to use for feeds. Used to find the template, too.
/// Defaults to "atom.xml", with "rss.xml" also having a template provided out of the box.
pub feed_filename: String,
/// Whether to generate feeds for that language, defaults to `false`
pub generate_feeds: bool,
/// The filenames to use for feeds. Used to find the templates, too.
/// Defaults to ["atom.xml"], with "rss.xml" also having a template provided out of the box.
pub feed_filenames: Vec<String>,
pub taxonomies: Vec<taxonomies::TaxonomyConfig>,
/// Whether to generate search index for that language, defaults to `false`
pub build_search_index: bool,
@@ -66,9 +66,9 @@ impl LanguageOptions {
merge_field!(self.title, other.title, "title");
merge_field!(self.description, other.description, "description");
merge_field!(
self.feed_filename == "atom.xml",
self.feed_filename,
other.feed_filename,
self.feed_filenames.is_empty(),
self.feed_filenames,
other.feed_filenames,
"feed_filename"
);
merge_field!(self.taxonomies.is_empty(), self.taxonomies, other.taxonomies, "taxonomies");
@@ -79,7 +79,7 @@ impl LanguageOptions {
"translations"
);

self.generate_feed = self.generate_feed || other.generate_feed;
self.generate_feeds = self.generate_feeds || other.generate_feeds;
self.build_search_index = self.build_search_index || other.build_search_index;

if self.search == search::Search::default() {
@@ -101,8 +101,8 @@ impl Default for LanguageOptions {
LanguageOptions {
title: None,
description: None,
generate_feed: false,
feed_filename: "atom.xml".to_string(),
generate_feeds: false,
feed_filenames: vec!["atom.xml".to_string()],
taxonomies: vec![],
build_search_index: false,
search: search::Search::default(),
@@ -129,8 +129,8 @@ mod tests {
let mut base_default_language_options = LanguageOptions {
title: Some("Site's title".to_string()),
description: None,
generate_feed: true,
feed_filename: "atom.xml".to_string(),
generate_feeds: true,
feed_filenames: vec!["atom.xml".to_string()],
taxonomies: vec![],
build_search_index: true,
search: search::Search::default(),
@@ -140,8 +140,8 @@ mod tests {
let section_default_language_options = LanguageOptions {
title: None,
description: Some("Site's description".to_string()),
generate_feed: false,
feed_filename: "rss.xml".to_string(),
generate_feeds: false,
feed_filenames: vec!["rss.xml".to_string()],
taxonomies: vec![],
build_search_index: true,
search: search::Search::default(),
@@ -156,8 +156,8 @@ mod tests {
let mut base_default_language_options = LanguageOptions {
title: Some("Site's title".to_string()),
description: Some("Duplicate site description".to_string()),
generate_feed: true,
feed_filename: "".to_string(),
generate_feeds: true,
feed_filenames: vec![],
taxonomies: vec![],
build_search_index: true,
search: search::Search::default(),
@@ -167,8 +167,8 @@ mod tests {
let section_default_language_options = LanguageOptions {
title: None,
description: Some("Site's description".to_string()),
generate_feed: false,
feed_filename: "Some feed_filename".to_string(),
generate_feeds: false,
feed_filenames: vec!["Some feed_filename".to_string()],
taxonomies: vec![],
build_search_index: true,
search: search::Search::default(),
46 changes: 24 additions & 22 deletions components/config/src/config/mod.rs
Original file line number Diff line number Diff line change
@@ -49,13 +49,13 @@ pub struct Config {
/// The translations strings for the default language
translations: HashMap<String, String>,

/// Whether to generate a feed. Defaults to false.
pub generate_feed: bool,
/// Whether to generate feeds. Defaults to false.
pub generate_feeds: bool,
/// The number of articles to include in the feed. Defaults to including all items.
pub feed_limit: Option<usize>,
/// The filename to use for feeds. Used to find the template, too.
/// Defaults to "atom.xml", with "rss.xml" also having a template provided out of the box.
pub feed_filename: String,
/// The filenames to use for feeds. Used to find the templates, too.
/// Defaults to ["atom.xml"], with "rss.xml" also having a template provided out of the box.
pub feed_filenames: Vec<String>,
/// If set, files from static/ will be hardlinked instead of copied to the output dir.
pub hard_link_static: bool,
pub taxonomies: Vec<taxonomies::TaxonomyConfig>,
@@ -109,7 +109,7 @@ pub struct SerializedConfig<'a> {
languages: HashMap<&'a String, &'a languages::LanguageOptions>,
default_language: &'a str,
generate_feed: bool,
feed_filename: &'a str,
feed_filenames: &'a [String],
taxonomies: &'a [taxonomies::TaxonomyConfig],
author: &'a Option<String>,
build_search_index: bool,
@@ -183,12 +183,14 @@ impl Config {

/// Makes a url, taking into account that the base url might have a trailing slash
pub fn make_permalink(&self, path: &str) -> String {
let trailing_bit =
if path.ends_with('/') || path.ends_with(&self.feed_filename) || path.is_empty() {
""
} else {
"/"
};
let trailing_bit = if path.ends_with('/')
|| self.feed_filenames.iter().any(|feed_filename| path.ends_with(feed_filename))
|| path.is_empty()
{
""
} else {
"/"
};

// Index section with a base url that has a trailing slash
if self.base_url.ends_with('/') && path == "/" {
@@ -212,8 +214,8 @@ impl Config {
let mut base_language_options = languages::LanguageOptions {
title: self.title.clone(),
description: self.description.clone(),
generate_feed: self.generate_feed,
feed_filename: self.feed_filename.clone(),
generate_feeds: self.generate_feeds,
feed_filenames: self.feed_filenames.clone(),
build_search_index: self.build_search_index,
taxonomies: self.taxonomies.clone(),
search: self.search.clone(),
@@ -320,8 +322,8 @@ impl Config {
description: &options.description,
languages: self.languages.iter().filter(|(k, _)| k.as_str() != lang).collect(),
default_language: &self.default_language,
generate_feed: options.generate_feed,
feed_filename: &options.feed_filename,
generate_feed: options.generate_feeds,
feed_filenames: &options.feed_filenames,
taxonomies: &options.taxonomies,
author: &self.author,
build_search_index: options.build_search_index,
@@ -369,9 +371,9 @@ impl Default for Config {
theme: None,
default_language: "en".to_string(),
languages: HashMap::new(),
generate_feed: false,
generate_feeds: false,
feed_limit: None,
feed_filename: "atom.xml".to_string(),
feed_filenames: vec!["atom.xml".to_string()],
hard_link_static: false,
taxonomies: Vec::new(),
author: None,
@@ -428,8 +430,8 @@ mod tests {
languages::LanguageOptions {
title: None,
description: description_lang_section.clone(),
generate_feed: true,
feed_filename: config.feed_filename.clone(),
generate_feeds: true,
feed_filenames: config.feed_filenames.clone(),
taxonomies: config.taxonomies.clone(),
build_search_index: false,
search: search::Search::default(),
@@ -456,8 +458,8 @@ mod tests {
languages::LanguageOptions {
title: title_lang_section.clone(),
description: None,
generate_feed: true,
feed_filename: config.feed_filename.clone(),
generate_feeds: true,
feed_filenames: config.feed_filenames.clone(),
taxonomies: config.taxonomies.clone(),
build_search_index: false,
search: search::Search::default(),
4 changes: 2 additions & 2 deletions components/content/src/front_matter/section.rs
Original file line number Diff line number Diff line change
@@ -69,7 +69,7 @@ pub struct SectionFrontMatter {
pub aliases: Vec<String>,
/// Whether to generate a feed for the current section
#[serde(skip_serializing)]
pub generate_feed: bool,
pub generate_feeds: bool,
/// Any extra parameter present in the front matter
pub extra: Map<String, Value>,
}
@@ -113,7 +113,7 @@ impl Default for SectionFrontMatter {
transparent: false,
page_template: None,
aliases: Vec::new(),
generate_feed: false,
generate_feeds: false,
extra: Map::new(),
draft: false,
}
4 changes: 2 additions & 2 deletions components/content/src/ser.rs
Original file line number Diff line number Diff line change
@@ -160,7 +160,7 @@ pub struct SerializingSection<'a> {
subsections: Vec<&'a str>,
translations: Vec<TranslatedContent<'a>>,
backlinks: Vec<BackLink<'a>>,
generate_feed: bool,
generate_feeds: bool,
transparent: bool,
}

@@ -220,7 +220,7 @@ impl<'a> SerializingSection<'a> {
reading_time: section.reading_time,
assets: &section.serialized_assets,
lang: &section.lang,
generate_feed: section.meta.generate_feed,
generate_feeds: section.meta.generate_feeds,
transparent: section.meta.transparent,
pages,
subsections,
2 changes: 1 addition & 1 deletion components/site/benches/site.rs
Original file line number Diff line number Diff line change
@@ -42,7 +42,7 @@ fn bench_render_feed(b: &mut test::Bencher) {
let public = &tmp_dir.path().join("public");
site.set_output_path(&public);
b.iter(|| {
site.render_feed(
site.render_feeds(
site.library.read().unwrap().pages.values().collect(),
None,
&site.config.default_language,
29 changes: 17 additions & 12 deletions components/site/src/feed.rs → components/site/src/feeds.rs
Original file line number Diff line number Diff line change
@@ -27,13 +27,13 @@ impl<'a> SerializedFeedTaxonomyItem<'a> {
}
}

pub fn render_feed(
pub fn render_feeds(
site: &Site,
all_pages: Vec<&Page>,
lang: &str,
base_path: Option<&PathBuf>,
additional_context_fn: impl Fn(Context) -> Context,
) -> Result<Option<String>> {
) -> Result<Option<Vec<String>>> {
let mut pages = all_pages.into_iter().filter(|p| p.meta.date.is_some()).collect::<Vec<_>>();

// Don't generate a feed if none of the pages has a date
@@ -73,18 +73,23 @@ pub fn render_feed(
context.insert("config", &site.config.serialize(lang));
context.insert("lang", lang);

let feed_filename = &site.config.feed_filename;
let feed_url = if let Some(base) = base_path {
site.config.make_permalink(&base.join(feed_filename).to_string_lossy().replace('\\', "/"))
} else {
site.config.make_permalink(feed_filename)
};
let mut feeds = Vec::new();
for feed_filename in &site.config.feed_filenames {
let mut context = context.clone();

context.insert("feed_url", &feed_url);
let feed_url = if let Some(base) = base_path {
site.config
.make_permalink(&base.join(feed_filename).to_string_lossy().replace('\\', "/"))
} else {
site.config.make_permalink(feed_filename)
};

context.insert("feed_url", &feed_url);

context = additional_context_fn(context);
context = additional_context_fn(context);

let feed = render_template(feed_filename, &site.tera, context, &site.config.theme)?;
feeds.push(render_template(feed_filename, &site.tera, context, &site.config.theme)?);
}

Ok(Some(feed))
Ok(Some(feeds))
}
Loading

0 comments on commit 0ca6468

Please sign in to comment.