Skip to content

Commit

Permalink
Add RSS feeds
Browse files Browse the repository at this point in the history
  • Loading branch information
sigaloid committed Apr 9, 2024
1 parent 27f25e0 commit 3f534d3
Show file tree
Hide file tree
Showing 5 changed files with 208 additions and 2 deletions.
111 changes: 110 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ fastrand = "2.0.1"
log = "0.4.20"
pretty_env_logger = "0.5.0"
dotenvy = "0.15.7"
rss = "2.0.7"

[dev-dependencies]
lipsum = "0.9.0"
Expand Down
4 changes: 4 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ async fn main() {
app.at("/u/:name/comments/:id/:title/:comment_id").get(|r| post::item(r).boxed());

app.at("/user/[deleted]").get(|req| error(req, "User has deleted their account").boxed());
app.at("/user/:name.rss").get(|r| user::rss(r).boxed());
app.at("/user/:name").get(|r| user::profile(r).boxed());
app.at("/user/:name/:listing").get(|r| user::profile(r).boxed());
app.at("/user/:name/comments/:id").get(|r| post::item(r).boxed());
Expand All @@ -265,6 +266,9 @@ async fn main() {
app.at("/settings/restore").get(|r| settings::restore(r).boxed());
app.at("/settings/update").get(|r| settings::update(r).boxed());

// RSS Subscriptions
app.at("/r/:sub.rss").get(|r| subreddit::rss(r).boxed());

// Subreddit services
app
.at("/r/:sub")
Expand Down
46 changes: 46 additions & 0 deletions src/subreddit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::utils::{
use crate::{client::json, server::ResponseExt, RequestExt};
use askama::Template;
use cookie::Cookie;
use hyper::header::CONTENT_TYPE;
use hyper::{Body, Request, Response};

use time::{Duration, OffsetDateTime};
Expand Down Expand Up @@ -446,6 +447,51 @@ async fn subreddit(sub: &str, quarantined: bool) -> Result<Subreddit, String> {
})
}

use rss::{ChannelBuilder, Item};

pub async fn rss(req: Request<Body>) -> Result<Response<Body>, String> {
// Get subreddit
let sub = req.param("sub").unwrap_or_default();
let post_sort = req.cookie("post_sort").map_or_else(|| "hot".to_string(), |c| c.value().to_string());
let sort = req.param("sort").unwrap_or_else(|| req.param("id").unwrap_or(post_sort));

// Get path
let path = format!("/r/{sub}/{sort}.json?{}", req.uri().query().unwrap_or_default());

// Get subreddit data
let subreddit = subreddit(&sub, false).await?;

// Get posts
let (posts, _) = Post::fetch(&path, false).await?;

// Build the RSS feed
let channel = ChannelBuilder::default()
.title(&subreddit.title)
.description(&subreddit.description)
.items(
posts
.into_iter()
.map(|post| Item {
title: Some(post.title),
link: Some(post.permalink),
author: Some(post.author.name),
content: Some(rewrite_urls(&post.body)),
..Default::default()
})
.collect::<Vec<_>>(),
)
.build();

// Serialize the feed to RSS
let body = channel.to_string().into_bytes();

// Create the HTTP response
let mut res = Response::new(Body::from(body));
res.headers_mut().insert(CONTENT_TYPE, hyper::header::HeaderValue::from_static("application/rss+xml"));

Ok(res)
}

#[tokio::test(flavor = "multi_thread")]
async fn test_fetching_subreddit() {
let subreddit = subreddit("rust", false).await;
Expand Down
48 changes: 47 additions & 1 deletion src/user.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// CRATES
use crate::client::json;
use crate::server::RequestExt;
use crate::utils::{error, filter_posts, format_url, get_filters, nsfw_landing, param, setting, template, Post, Preferences, User};
use crate::utils::{error, filter_posts, format_url, get_filters, nsfw_landing, param, rewrite_urls, setting, template, Post, Preferences, User};
use askama::Template;
use hyper::header::CONTENT_TYPE;
use hyper::{Body, Request, Response};
use time::{macros::format_description, OffsetDateTime};

Expand Down Expand Up @@ -129,6 +130,51 @@ async fn user(name: &str) -> Result<User, String> {
})
}

use rss::{ChannelBuilder, Item};

pub async fn rss(req: Request<Body>) -> Result<Response<Body>, String> {
// Get user
let user_str = req.param("name").unwrap_or_default();

let listing = req.param("listing").unwrap_or_else(|| "overview".to_string());

// Get path
let path = format!("/user/{user_str}/{listing}.json?{}&raw_json=1", req.uri().query().unwrap_or_default(),);

// Get user
let user_obj = user(&user_str).await.unwrap_or_default();

// Get posts
let (posts, _) = Post::fetch(&path, false).await?;

// Build the RSS feed
let channel = ChannelBuilder::default()
.title(user_str)
.description(user_obj.description)
.items(
posts
.into_iter()
.map(|post| Item {
title: Some(post.title),
link: Some(post.permalink),
author: Some(post.author.name),
content: Some(rewrite_urls(&post.body)),
..Default::default()
})
.collect::<Vec<_>>(),
)
.build();

// Serialize the feed to RSS
let body = channel.to_string().into_bytes();

// Create the HTTP response
let mut res = Response::new(Body::from(body));
res.headers_mut().insert(CONTENT_TYPE, hyper::header::HeaderValue::from_static("application/rss+xml"));

Ok(res)
}

#[tokio::test(flavor = "multi_thread")]
async fn test_fetching_user() {
let user = user("spez").await;
Expand Down

0 comments on commit 3f534d3

Please sign in to comment.