mirror of
https://gitlab.com/Anson-Projects/zine.git
synced 2025-06-15 05:06:39 +00:00
Add RSS feed
This commit is contained in:
parent
0924e73b95
commit
e5ff6551e3
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
/target
|
||||
/output/index.html
|
||||
/output/index.html
|
||||
/output/feed.xml
|
131
Cargo.lock
generated
131
Cargo.lock
generated
@ -28,6 +28,7 @@ dependencies = [
|
||||
"maud",
|
||||
"rayon",
|
||||
"reqwest",
|
||||
"rss",
|
||||
"scraper",
|
||||
"simple_logger",
|
||||
]
|
||||
@ -81,6 +82,19 @@ version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
||||
|
||||
[[package]]
|
||||
name = "atom_syndication"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "571832dcff775e26562e8e6930cd483de5587301d40d3a3b85d532b6383e15a7"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"derive_builder",
|
||||
"diligent-date-parser",
|
||||
"never",
|
||||
"quick-xml 0.30.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.2.0"
|
||||
@ -270,6 +284,41 @@ dependencies = [
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.14.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.14.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.14.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.3.11"
|
||||
@ -279,6 +328,37 @@ dependencies = [
|
||||
"powerfmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_builder"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8"
|
||||
dependencies = [
|
||||
"derive_builder_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_builder_core"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_builder_macro"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e"
|
||||
dependencies = [
|
||||
"derive_builder_core",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
version = "0.99.17"
|
||||
@ -290,6 +370,15 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diligent-date-parser"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6cf7fe294274a222363f84bcb63cdea762979a0443b4cf1f4f8fd17c86b1182"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "1.0.5"
|
||||
@ -368,7 +457,7 @@ dependencies = [
|
||||
"chrono",
|
||||
"lazy_static",
|
||||
"mime",
|
||||
"quick-xml",
|
||||
"quick-xml 0.31.0",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -677,6 +766,12 @@ dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.5.0"
|
||||
@ -844,6 +939,12 @@ dependencies = [
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "never"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c96aba5aa877601bb3f6dd6a63a969e1f82e60646e81e71b14496995e9853c91"
|
||||
|
||||
[[package]]
|
||||
name = "new_debug_unreachable"
|
||||
version = "1.0.6"
|
||||
@ -1140,6 +1241,16 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.30.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956"
|
||||
dependencies = [
|
||||
"encoding_rs",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.31.0"
|
||||
@ -1307,6 +1418,18 @@ dependencies = [
|
||||
"winreg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rss"
|
||||
version = "2.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7b2c77eb4450d7d5f98df52c381cd6c4e19b75dad9209a9530b85a44510219a"
|
||||
dependencies = [
|
||||
"atom_syndication",
|
||||
"derive_builder",
|
||||
"never",
|
||||
"quick-xml 0.30.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-argon2"
|
||||
version = "0.8.3"
|
||||
@ -1559,6 +1682,12 @@ dependencies = [
|
||||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
|
@ -7,8 +7,6 @@ authors = ["Anson Biggs"]
|
||||
homepage = "https://zine.ansonbiggs.com"
|
||||
license = "MIT"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
feed-rs = "1.4"
|
||||
reqwest = { version = "0.12", features = ["blocking"] }
|
||||
@ -18,6 +16,7 @@ scraper = "0.19"
|
||||
rayon = "1.8"
|
||||
simple_logger = "4.3"
|
||||
log = "0.4"
|
||||
rss = "2.0"
|
||||
|
||||
[dev-dependencies]
|
||||
clippy = "0.0.302"
|
||||
|
14
README.md
14
README.md
@ -2,6 +2,18 @@
|
||||
|
||||
Anson's Aggregated Feed is a Rust application designed to aggregate content from multiple RSS feeds, creating a personalized news page. It fetches articles from specified RSS feed URLs, generates HTML cards for each entry, and outputs a single, styled HTML page. This project showcases the use of Rust for web content aggregation and manipulation, leveraging several powerful crates for parsing RSS feeds, handling dates and times, making HTTP requests, and rendering HTML.
|
||||
|
||||
## Algorithm
|
||||
|
||||
Long term I would like some sort of algorithm that is a small improvement over just sorting the feed by posting date. Right now the only aspects taken into account are:
|
||||
|
||||
- Whether the feed is in the featured list
|
||||
- Publish date of the post
|
||||
- Bonus points if the feed includes an image, negative points if there isn't even a social image.
|
||||
|
||||
## Featured Feeds
|
||||
|
||||
These are feeds that are extremely high quality and don't post on a regular schedule. There are blogs (factorio for example) that I think are consistently high quality but I want to save this space for very special posts.
|
||||
These are feeds that are extremely high quality and don't post on a regular schedule. There are blogs (factorio for example) that I think are consistently high quality but I want to save this space for very special posts.
|
||||
|
||||
## RSS Feed
|
||||
|
||||
The site also aggregates everything that is on the homepage into an rss feed. Available at https://zine.ansonbiggs.com/feed.xml
|
||||
|
25
src/main.rs
25
src/main.rs
@ -50,17 +50,28 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
entries.retain(|entry| entry.score.is_positive());
|
||||
entries.sort();
|
||||
|
||||
let index = site_generator::generate_index(entries);
|
||||
|
||||
let output_path = Path::new("output/index.html");
|
||||
let index = site_generator::generate_index(entries.clone());
|
||||
let index_path = Path::new("output/index.html");
|
||||
DirBuilder::new()
|
||||
.recursive(true)
|
||||
.create(output_path.parent().unwrap())
|
||||
.create(index_path.parent().unwrap())
|
||||
.unwrap();
|
||||
|
||||
match write(output_path, index.into_string()) {
|
||||
Ok(_) => log::info!("Successfully wrote to {}", output_path.display()),
|
||||
Err(e) => log::error!("Failed to write to {}: {}", output_path.display(), e),
|
||||
match write(index_path, index.into_string()) {
|
||||
Ok(_) => log::info!("Successfully wrote to {}", index_path.display()),
|
||||
Err(e) => log::error!("Failed to write to {}: {}", index_path.display(), e),
|
||||
}
|
||||
|
||||
let feed = site_generator::generate_rss(entries.clone());
|
||||
let feed_path = Path::new("output/feed.xml");
|
||||
DirBuilder::new()
|
||||
.recursive(true)
|
||||
.create(feed_path.parent().unwrap())
|
||||
.unwrap();
|
||||
|
||||
match write(feed_path, feed) {
|
||||
Ok(_) => log::info!("Successfully wrote to {}", feed_path.display()),
|
||||
Err(e) => log::error!("Failed to write to {}: {}", feed_path.display(), e),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -7,6 +7,7 @@ use chrono::DateTime;
|
||||
use chrono::Utc;
|
||||
|
||||
use maud::{html, Markup};
|
||||
use rss::{ChannelBuilder, Item, ItemBuilder};
|
||||
|
||||
use crate::utilities;
|
||||
|
||||
@ -69,14 +70,17 @@ fn generate_footer() -> Markup {
|
||||
p {
|
||||
a href="https://ansonbiggs.com" { "Anson Biggs" }
|
||||
" - "
|
||||
a href=("/feed.xml") target="_blank" rel="noopener noreferrer" { "RSS Feed" }
|
||||
" - "
|
||||
a href="https://gitlab.com/MisterBiggs/zine" { "Source Code" }
|
||||
" - "
|
||||
"Page generated at: " em data-tooltip="Usually daily 8AM Mountain Time" { (formatted_utc) " UTC" }
|
||||
"Page generated at: " em data-tooltip="Automatic builds daily 8AM Mountain Time" { (formatted_utc) " UTC" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_header() -> Markup {
|
||||
html! {
|
||||
header {
|
||||
@ -86,6 +90,9 @@ fn generate_header() -> Markup {
|
||||
}
|
||||
ul {
|
||||
li { button data-target="about" onclick="toggleModal(event)" { "About" } }
|
||||
li {
|
||||
|
||||
}
|
||||
li {
|
||||
details class="dropdown" {
|
||||
summary role="button" class="outline secondary" { "Theme" }
|
||||
@ -191,3 +198,26 @@ pub fn generate_index(mut entries: Vec<utilities::Post>) -> Markup {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_rss(posts: Vec<utilities::Post>) -> String {
|
||||
let items: Vec<Item> = posts
|
||||
.iter()
|
||||
.map(|post| {
|
||||
ItemBuilder::default()
|
||||
.title(post.title.clone())
|
||||
.link(post.link.clone())
|
||||
.pub_date(post.date.to_rfc2822())
|
||||
.description(post.truncated_description.clone())
|
||||
.build()
|
||||
})
|
||||
.collect();
|
||||
|
||||
let channel = ChannelBuilder::default()
|
||||
.title("Anson's Aggregate RSS Feed")
|
||||
.link("https://zine.ansonbiggs.com/feed")
|
||||
.description("All the feeds I like, aggregated into one place.")
|
||||
.items(items)
|
||||
.build();
|
||||
|
||||
channel.to_string()
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user