Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,5 @@ REDLIB_DEFAULT_DISABLE_VISIT_REDDIT_CONFIRMATION=off
REDLIB_DEFAULT_HIDE_SCORE=off
# Enable fixed navbar by default
REDLIB_DEFAULT_FIXED_NAVBAR=on
# Set the default geo filter
REDLIB_DEFAULT_GEO_FILTER=GLOBAL
3 changes: 3 additions & 0 deletions app.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@
},
"REDLIB_DEFAULT_REMOVE_DEFAULT_FEEDS": {
"required": false
},
"REDLIB_DEFAULT_GEO_FILTER": {
"required": false
}
}
}
5 changes: 5 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ pub struct Config {

#[serde(rename = "REDLIB_DEFAULT_REMOVE_DEFAULT_FEEDS")]
pub(crate) default_remove_default_feeds: Option<String>,

#[serde(rename = "REDLIB_DEFAULT_GEO_FILTER")]
pub(crate) default_geo_filter: Option<String>,
}

impl Config {
Expand Down Expand Up @@ -156,6 +159,7 @@ impl Config {
enable_rss: parse("REDLIB_ENABLE_RSS"),
full_url: parse("REDLIB_FULL_URL"),
default_remove_default_feeds: parse("REDLIB_DEFAULT_REMOVE_DEFAULT_FEEDS"),
default_geo_filter: parse("REDLIB_DEFAULT_GEO_FILTER"),
}
}
}
Expand Down Expand Up @@ -186,6 +190,7 @@ fn get_setting_from_config(name: &str, config: &Config) -> Option<String> {
"REDLIB_ENABLE_RSS" => config.enable_rss.clone(),
"REDLIB_FULL_URL" => config.full_url.clone(),
"REDLIB_DEFAULT_REMOVE_DEFAULT_FEEDS" => config.default_remove_default_feeds.clone(),
"REDLIB_DEFAULT_GEO_FILTER" => config.default_geo_filter.clone(),
_ => None,
}
}
Expand Down
5 changes: 4 additions & 1 deletion src/instance_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ impl InstanceInfo {
["Hide HLS notification", &convert(&self.config.default_hide_hls_notification)],
["Subscriptions", &convert(&self.config.default_subscriptions)],
["Filters", &convert(&self.config.default_filters)],
["Geo filter", &convert(&self.config.default_geo_filter)],
])
.with_header_row(["Default preferences"]),
);
Expand Down Expand Up @@ -187,7 +188,8 @@ impl InstanceInfo {
Default use HLS: {:?}\n
Default hide HLS notification: {:?}\n
Default subscriptions: {:?}\n
Default filters: {:?}\n",
Default filters: {:?}\n,
Default geo filter: {:?}\n",
self.package_name,
self.crate_version,
self.git_commit,
Expand Down Expand Up @@ -215,6 +217,7 @@ impl InstanceInfo {
self.config.default_hide_hls_notification,
self.config.default_subscriptions,
self.config.default_filters,
self.config.default_geo_filter,
)
}
StringType::Html => self.to_table(),
Expand Down
15 changes: 14 additions & 1 deletion src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ struct SettingsTemplate {

// CONSTANTS

const PREFS: [&str; 19] = [
const PREFS: [&str; 20] = [
"theme",
"front_page",
"layout",
Expand All @@ -44,6 +44,19 @@ const PREFS: [&str; 19] = [
"disable_visit_reddit_confirmation",
"video_quality",
"remove_default_feeds",
"geo_filter",
];

pub static GEO_FILTERS: [&'static str; 250] = [
"GLOBAL", "AD", "AE", "AF", "AG", "AI", "AL", "AM", "AO", "AQ", "AR", "AS", "AT", "AU", "AW", "AX", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BL", "BM",
"BN", "BO", "BQ", "BR", "BS", "BT", "BV", "BW", "BY", "BZ", "CA", "CC", "CD", "CF", "CG", "CH", "CI", "CK", "CL", "CM", "CN", "CO", "CR", "CU", "CV", "CW", "CX", "CY",
"CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "EH", "ER", "ES", "ET", "FI", "FJ", "FK", "FM", "FO", "FR", "GA", "GB", "GD", "GE", "GF", "GG", "GH", "GI",
"GL", "GM", "GN", "GP", "GQ", "GR", "GS", "GT", "GU", "GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS", "IT", "JE",
"JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD",
"ME", "MF", "MG", "MH", "MK", "ML", "MM", "MN", "MO", "MP", "MQ", "MR", "MS", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NC", "NE", "NF", "NG", "NI", "NL", "NO",
"NP", "NR", "NU", "NZ", "OM", "PA", "PE", "PF", "PG", "PH", "PK", "PL", "PM", "PN", "PR", "PS", "PT", "PW", "PY", "QA", "RE", "RO", "RS", "RU", "RW", "SA", "SB", "SC",
"SD", "SE", "SG", "SH", "SI", "SJ", "SK", "SL", "SM", "SN", "SO", "SR", "SS", "ST", "SV", "SX", "SY", "SZ", "TC", "TD", "TF", "TG", "TH", "TJ", "TK", "TL", "TM", "TN",
"TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UM", "US", "UY", "UZ", "VA", "VC", "VE", "VG", "VI", "VN", "VU", "WF", "WS", "YE", "YT", "ZA", "ZM", "ZW",
];

// FUNCTIONS
Expand Down
67 changes: 23 additions & 44 deletions src/subreddit.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#![allow(clippy::cmp_owned)]

use crate::utils::{
Post, Preferences, Subreddit, catch_random, error, filter_posts, format_num, format_url, get_filters, info, nsfw_landing, param, redirect, rewrite_urls, setting, template, to_absolute_url, val
catch_random, error, filter_posts, format_num, format_url, get_filters, info, nsfw_landing, param, redirect, rewrite_urls, setting, template, to_absolute_url, val, Post,
Preferences, Subreddit,
};
use crate::{client::json, server::RequestExt, server::ResponseExt};
use crate::{config, utils};
Expand All @@ -11,9 +12,7 @@ use htmlescape::decode_html;
use hyper::{Body, Request, Response};

use chrono::DateTime;
use regex::Regex;
use rss::{ChannelBuilder, Item, Enclosure};
use std::sync::LazyLock;
use rss::{ChannelBuilder, Enclosure, Item};
use time::{Duration, OffsetDateTime};

// STRUCTS
Expand Down Expand Up @@ -57,13 +56,11 @@ struct WallTemplate {
url: String,
}

static GEO_FILTER_MATCH: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"geo_filter=(?<region>\w+)").unwrap());

// SERVICES
pub async fn community(req: Request<Body>) -> Result<Response<Body>, String> {
let prefs = Preferences::new(&req);
// Build Reddit API path
let root = req.uri().path() == "/";
let query = req.uri().query().unwrap_or_default().to_string();
let subscribed = setting(&req, "subscriptions");
let front_page = setting(&req, "front_page");
let remove_default_feeds = setting(&req, "remove_default_feeds") == "on";
Expand Down Expand Up @@ -133,11 +130,7 @@ pub async fn community(req: Request<Body>) -> Result<Response<Body>, String> {

let mut params = String::from("&raw_json=1");
if sub_name == "popular" {
let geo_filter = match GEO_FILTER_MATCH.captures(&query) {
Some(geo_filter) => geo_filter["region"].to_string(),
None => "GLOBAL".to_owned(),
};
params.push_str(&format!("&geo_filter={geo_filter}"));
params.push_str(&format!("&geo_filter={}", prefs.geo_filter));
}

let path = format!("/r/{}/{sort}.json?{}{params}", sub_name.replace('+', "%2B"), req.uri().query().unwrap_or_default());
Expand All @@ -152,7 +145,7 @@ pub async fn community(req: Request<Body>) -> Result<Response<Body>, String> {
posts: Vec::new(),
sort: (sort, param(&path, "t").unwrap_or_default()),
ends: (param(&path, "after").unwrap_or_default(), String::new()),
prefs: Preferences::new(&req),
prefs,
url,
redirect_url,
is_filtered: true,
Expand Down Expand Up @@ -655,23 +648,13 @@ fn apply_enclosure(item: &mut Item, post: &Post) {
// Embed the number of gallery images in description and content since
// only the first image in the gallery is used for the enclosure
if post.post_type == "gallery" && post.gallery.len() > 1 {
item.set_description(
format!("<a href='{}'>Gallery with {} images</a>",
to_absolute_url(&post.permalink),
post.gallery.len()
)
);
item.set_description(format!("<a href='{}'>Gallery with {} images</a>", to_absolute_url(&post.permalink), post.gallery.len()));

if let Some(content) = item.content() {
let new_content = format!(
"{}<br/>{}",
item.description().unwrap_or(""),
content,
);
let new_content = format!("{}<br/>{}", item.description().unwrap_or(""), content,);
item.set_content(new_content);
}
}

}

fn get_rss_image(post: &Post) -> Option<Enclosure> {
Expand All @@ -694,25 +677,21 @@ fn get_rss_image(post: &Post) -> Option<Enclosure> {
/// Determines the MIME type based on file extension in a URL.
/// Handles both absolute and relative URLs with query parameters.
fn get_mime_type(url: &str) -> &'static str {
// Extract the path component, removing query parameters
let path = url.split('?').next().unwrap_or(url);

// Get the file extension (everything after the last dot)
let extension = path
.rsplit('.')
.next()
.unwrap_or("")
.to_lowercase();

// Match common image extensions
match extension.as_str() {
"jpg" | "jpeg" => "image/jpeg",
"png" => "image/png",
"gif" => "image/gif",
"webp" => "image/webp",
"svg" => "image/svg+xml",
_ => "application/octet-stream",
}
// Extract the path component, removing query parameters
let path = url.split('?').next().unwrap_or(url);

// Get the file extension (everything after the last dot)
let extension = path.rsplit('.').next().unwrap_or("").to_lowercase();

// Match common image extensions
match extension.as_str() {
"jpg" | "jpeg" => "image/jpeg",
"png" => "image/png",
"gif" => "image/gif",
"webp" => "image/webp",
"svg" => "image/svg+xml",
_ => "application/octet-stream",
}
}

#[cfg(test)]
Expand Down
12 changes: 8 additions & 4 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,8 @@ pub struct Preferences {
pub hide_score: String,
#[revision(start = 1)]
pub remove_default_feeds: String,
#[revision(start = 1)]
pub geo_filter: String,
}

fn serialize_vec_with_plus<S>(vec: &[String], serializer: S) -> Result<S::Ok, S::Error>
Expand Down Expand Up @@ -725,6 +727,7 @@ impl Preferences {
hide_awards: setting(req, "hide_awards"),
hide_score: setting(req, "hide_score"),
remove_default_feeds: setting(req, "remove_default_feeds"),
geo_filter: setting_or_default(req, "geo_filter", "GLOBAL".to_string()),
}
}

Expand Down Expand Up @@ -1543,10 +1546,11 @@ mod tests {
hide_awards: "off".to_owned(),
hide_score: "off".to_owned(),
remove_default_feeds: "off".to_owned(),
geo_filter: "GLOBAL".to_owned(),
};
let urlencoded = serde_urlencoded::to_string(prefs).expect("Failed to serialize Prefs");

assert_eq!(urlencoded, "theme=laserwave&front_page=default&layout=compact&wide=on&blur_spoiler=on&show_nsfw=off&blur_nsfw=on&hide_hls_notification=off&video_quality=best&hide_sidebar_and_summary=off&use_hls=on&autoplay_videos=on&fixed_navbar=on&disable_visit_reddit_confirmation=on&comment_sort=confidence&post_sort=top&subscriptions=memes%2Bmildlyinteresting&filters=&hide_awards=off&hide_score=off&remove_default_feeds=off");
assert_eq!(urlencoded, "theme=laserwave&front_page=default&layout=compact&wide=on&blur_spoiler=on&show_nsfw=off&blur_nsfw=on&hide_hls_notification=off&video_quality=best&hide_sidebar_and_summary=off&use_hls=on&autoplay_videos=on&fixed_navbar=on&disable_visit_reddit_confirmation=on&comment_sort=confidence&post_sort=top&subscriptions=memes%2Bmildlyinteresting&filters=&hide_awards=off&hide_score=off&remove_default_feeds=off&geo_filter=GLOBAL");
}

#[test]
Expand Down Expand Up @@ -1655,9 +1659,9 @@ How`s your monitor by the way? Any IPS bleed whatsoever? I either got lucky or t
}

static KNOWN_GOOD_CONFIGS: &[&str] = &[
"ఴӅβØØҞÉဏႢձĬ༧ȒʯऌԔӵ୮༏",
"ਧՊΥÀÃǎƱГ۸ඣമĖฤ႙ʟาúໜϾௐɥঀĜໃહཞઠѫҲɂఙ࿔DzઉƲӟӻĻฅΜδ໖ԜǗဖငƦơ৶Ą௩ԹʛใЛʃශаΏ",
"ਧԩΥÀÃΊ౭൩ඔႠϼҭöҪƸռઇԾॐნɔາǒՍҰच௨ಖມŃЉŐདƦ๙ϩএఠȝഽйʮჯඒϰळՋ௮ສ৵ऎΦѧਹಧଟƙŃ३î༦ŌပղयƟแҜ།",
"ఴǐΪØÃҤÉఅഐႮვÆվƟ๑ഈ௲º",
"ਧճΥÀÃǙŨ౭ѰЉਠ༃ඍୟϊÓႼઞƶDzѾҠŶဿৠǡȈЧတĄঘशƕİԪӥОϥΪѼĔજɍႰůƅıęႵຈഛशખӺफƊўચபūগລનаΦǮʀԅཪ٦ಟซωॶԓԙµ",
"ਧՎΥºÃǖবб྾цҗҢจഘĦਝ೨ծമ۞তʦཤཎຟՐȸ൯ങஏ९ȹ૯нե࿑Ʋථఐ۳ԊຍखʟషၡŁलſԇચਆॹǕϻΪজԯǐĦЅթȣơϱǃඛϾຝϤ໐Քµ",
];

#[test]
Expand Down
6 changes: 6 additions & 0 deletions templates/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@
<input type="hidden" value="off" name="wide">
<input type="checkbox" name="wide" id="wide" {% if prefs.wide=="on" %}checked{% endif %}>
</div>
<div class="prefs-group">
<label for="geo_filter">Geo Filter:</label>
<select name="geo_filter" id="geo_filter">
{% call utils::options(prefs.geo_filter, self::GEO_FILTERS, prefs.geo_filter) %}
</select>
</div>
</fieldset>
<fieldset>
<legend>Content</legend>
Expand Down