Added Percent Encoding Support
This commit is contained in:
parent
8f157c0b40
commit
9a6430656d
3
Cargo.lock
generated
3
Cargo.lock
generated
@ -1394,11 +1394,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libreddit"
|
name = "libreddit"
|
||||||
version = "0.1.7"
|
version = "0.1.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-web",
|
"actix-web",
|
||||||
"askama",
|
"askama",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"percent-encoding",
|
||||||
"pulldown-cmark",
|
"pulldown-cmark",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
@ -3,15 +3,16 @@ name = "libreddit"
|
|||||||
description = " Alternative private front-end to Reddit"
|
description = " Alternative private front-end to Reddit"
|
||||||
license = "AGPL-3.0"
|
license = "AGPL-3.0"
|
||||||
repository = "https://github.com/spikecodes/libreddit"
|
repository = "https://github.com/spikecodes/libreddit"
|
||||||
version = "0.1.7"
|
version = "0.1.8"
|
||||||
authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"]
|
authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["proxy"]
|
default = ["proxy"]
|
||||||
proxy = ["actix-web/rustls"]
|
proxy = ["actix-web/rustls", "percent-encoding"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
percent-encoding = { version = "2.1.0", optional = true }
|
||||||
actix-web = "3.2.0"
|
actix-web = "3.2.0"
|
||||||
surf = "2.1.0"
|
surf = "2.1.0"
|
||||||
askama = "0.8.0"
|
askama = "0.8.0"
|
||||||
|
16534
cargo-timing.html
16534
cargo-timing.html
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
tab_spaces = 2
|
tab_spaces = 2
|
||||||
hard_tabs = true
|
hard_tabs = true
|
||||||
max_width = 200
|
max_width = 175
|
@ -4,9 +4,9 @@ use actix_web::{get, App, HttpResponse, HttpServer};
|
|||||||
// Reference local files
|
// Reference local files
|
||||||
mod popular;
|
mod popular;
|
||||||
mod post;
|
mod post;
|
||||||
|
mod proxy;
|
||||||
mod subreddit;
|
mod subreddit;
|
||||||
mod user;
|
mod user;
|
||||||
mod proxy;
|
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
// Create Services
|
// Create Services
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// CRATES
|
// CRATES
|
||||||
use actix_web::{get, web, HttpResponse, Result, http::StatusCode};
|
|
||||||
use askama::Template;
|
|
||||||
use crate::utils::{fetch_posts, ErrorTemplate, Params, Post};
|
use crate::utils::{fetch_posts, ErrorTemplate, Params, Post};
|
||||||
|
use actix_web::{get, http::StatusCode, web, HttpResponse, Result};
|
||||||
|
use askama::Template;
|
||||||
|
|
||||||
// STRUCTS
|
// STRUCTS
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
|
26
src/post.rs
26
src/post.rs
@ -1,9 +1,12 @@
|
|||||||
// CRATES
|
// CRATES
|
||||||
use actix_web::{get, web, HttpResponse, Result, http::StatusCode};
|
use crate::utils::{request, val, Comment, ErrorTemplate, Flair, Params, Post};
|
||||||
|
use actix_web::{get, http::StatusCode, web, HttpResponse, Result};
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
use chrono::{TimeZone, Utc};
|
use chrono::{TimeZone, Utc};
|
||||||
use pulldown_cmark::{html, Options, Parser};
|
use pulldown_cmark::{html, Options, Parser};
|
||||||
use crate::utils::{request, val, Comment, ErrorTemplate, Flair, Params, Post};
|
|
||||||
|
#[cfg(feature = "proxy")]
|
||||||
|
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
|
||||||
|
|
||||||
// STRUCTS
|
// STRUCTS
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
@ -66,6 +69,14 @@ async fn page(web::Path((_sub, id)): web::Path<(String, String)>, params: web::Q
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn format_url(url: &str) -> String {
|
||||||
|
#[cfg(feature = "proxy")]
|
||||||
|
return utf8_percent_encode(url, NON_ALPHANUMERIC).to_string();
|
||||||
|
|
||||||
|
#[cfg(not(feature = "proxy"))]
|
||||||
|
return url.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
// UTILITIES
|
// UTILITIES
|
||||||
async fn media(data: &serde_json::Value) -> String {
|
async fn media(data: &serde_json::Value) -> String {
|
||||||
let post_hint: &str = data["data"]["post_hint"].as_str().unwrap_or("");
|
let post_hint: &str = data["data"]["post_hint"].as_str().unwrap_or("");
|
||||||
@ -76,15 +87,20 @@ async fn media(data: &serde_json::Value) -> String {
|
|||||||
let media: String = if !has_media {
|
let media: String = if !has_media {
|
||||||
format!(r#"<h4 class="post_body"><a href="{u}">{u}</a></h4>"#, u = data["data"]["url"].as_str().unwrap())
|
format!(r#"<h4 class="post_body"><a href="{u}">{u}</a></h4>"#, u = data["data"]["url"].as_str().unwrap())
|
||||||
} else {
|
} else {
|
||||||
format!(r#"<img class="post_image" src="{}{}.png"/>"#, prefix, data["data"]["url"].as_str().unwrap())
|
format!(
|
||||||
|
r#"<img class="post_image" src="{}{}.png"/>"#,
|
||||||
|
prefix,
|
||||||
|
format_url(data["data"]["url"].as_str().unwrap()).await
|
||||||
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
match post_hint {
|
match post_hint {
|
||||||
"hosted:video" => format!(
|
"hosted:video" => format!(
|
||||||
r#"<video class="post_image" src="{}{}" controls/>"#,
|
r#"<video class="post_image" src="{}{}" controls/>"#,
|
||||||
prefix, data["data"]["media"]["reddit_video"]["fallback_url"].as_str().unwrap()
|
prefix,
|
||||||
|
format_url(data["data"]["media"]["reddit_video"]["fallback_url"].as_str().unwrap()).await
|
||||||
),
|
),
|
||||||
"image" => format!(r#"<img class="post_image" src="{}{}"/>"#, prefix, data["data"]["url"].as_str().unwrap()),
|
"image" => format!(r#"<img class="post_image" src="{}{}"/>"#, prefix, format_url(data["data"]["url"].as_str().unwrap()).await),
|
||||||
"self" => String::from(""),
|
"self" => String::from(""),
|
||||||
_ => media,
|
_ => media,
|
||||||
}
|
}
|
||||||
|
23
src/proxy.rs
23
src/proxy.rs
@ -1,18 +1,27 @@
|
|||||||
use actix_web::{get, web, HttpResponse, Result, client::Client, Error};
|
use actix_web::{client::Client, get, web, Error, HttpResponse, Result};
|
||||||
|
|
||||||
|
#[cfg(feature = "proxy")]
|
||||||
|
use percent_encoding::percent_decode_str;
|
||||||
|
|
||||||
#[get("/imageproxy/{url:.*}")]
|
#[get("/imageproxy/{url:.*}")]
|
||||||
async fn handler(web::Path(url): web::Path<String>) -> Result<HttpResponse> {
|
async fn handler(web::Path(url): web::Path<String>) -> Result<HttpResponse> {
|
||||||
if cfg!(feature = "proxy") {
|
if cfg!(feature = "proxy") {
|
||||||
dbg!(&url);
|
#[cfg(feature = "proxy")]
|
||||||
|
let media: String = percent_decode_str(url.as_str()).decode_utf8()?.to_string();
|
||||||
|
|
||||||
|
#[cfg(not(feature = "proxy"))]
|
||||||
|
let media: String = url;
|
||||||
|
|
||||||
|
dbg!(&media);
|
||||||
|
|
||||||
let client = Client::default();
|
let client = Client::default();
|
||||||
client.get(url)
|
client
|
||||||
|
.get(media)
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.map_err(Error::from)
|
.map_err(Error::from)
|
||||||
.and_then(|res| {
|
.and_then(|res| Ok(HttpResponse::build(res.status()).streaming(res)))
|
||||||
Ok(HttpResponse::build(res.status()).streaming(res))
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
Ok(HttpResponse::Ok().body(""))
|
Ok(HttpResponse::Ok().body(""))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// CRATES
|
// CRATES
|
||||||
use actix_web::{get, web, HttpResponse, Result, http::StatusCode};
|
use crate::utils::{fetch_posts, request, val, ErrorTemplate, Params, Post, Subreddit};
|
||||||
|
use actix_web::{get, http::StatusCode, web, HttpResponse, Result};
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
use crate::utils::{request, val, fetch_posts, ErrorTemplate, Params, Post, Subreddit};
|
|
||||||
|
|
||||||
// STRUCTS
|
// STRUCTS
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
@ -10,7 +10,7 @@ struct SubredditTemplate {
|
|||||||
sub: Subreddit,
|
sub: Subreddit,
|
||||||
posts: Vec<Post>,
|
posts: Vec<Post>,
|
||||||
sort: String,
|
sort: String,
|
||||||
ends: (String, String)
|
ends: (String, String),
|
||||||
}
|
}
|
||||||
|
|
||||||
// SERVICES
|
// SERVICES
|
||||||
@ -57,7 +57,7 @@ pub async fn render(sub_name: String, sort: Option<String>, ends: (Option<String
|
|||||||
sub: sub,
|
sub: sub,
|
||||||
posts: items.0,
|
posts: items.0,
|
||||||
sort: sorting,
|
sort: sorting,
|
||||||
ends: (before, items.1)
|
ends: (before, items.1),
|
||||||
}
|
}
|
||||||
.render()
|
.render()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -82,7 +82,7 @@ async fn subreddit(sub: &String) -> Result<Subreddit, &'static str> {
|
|||||||
let res = req.unwrap();
|
let res = req.unwrap();
|
||||||
|
|
||||||
let members = res["data"]["subscribers"].as_u64().unwrap_or(0);
|
let members = res["data"]["subscribers"].as_u64().unwrap_or(0);
|
||||||
let active = res["data"]["accounts_active"].as_u64().unwrap_or(0);
|
let active = res["data"]["accounts_active"].as_u64().unwrap_or(0);
|
||||||
|
|
||||||
let sub = Subreddit {
|
let sub = Subreddit {
|
||||||
name: val(&res, "display_name").await,
|
name: val(&res, "display_name").await,
|
||||||
@ -94,4 +94,4 @@ async fn subreddit(sub: &String) -> Result<Subreddit, &'static str> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Ok(sub)
|
Ok(sub)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// CRATES
|
// CRATES
|
||||||
use actix_web::{get, web, HttpResponse, Result, http::StatusCode};
|
use crate::utils::{fetch_posts, nested_val, request, ErrorTemplate, Params, Post, User};
|
||||||
|
use actix_web::{get, http::StatusCode, web, HttpResponse, Result};
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
use crate::utils::{nested_val, request, fetch_posts, ErrorTemplate, Params, Post, User};
|
|
||||||
|
|
||||||
// STRUCTS
|
// STRUCTS
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
@ -71,4 +71,4 @@ async fn user(name: &String) -> Result<User, &'static str> {
|
|||||||
banner: nested_val(&res, "subreddit", "banner_img").await,
|
banner: nested_val(&res, "subreddit", "banner_img").await,
|
||||||
description: nested_val(&res, "subreddit", "public_description").await,
|
description: nested_val(&res, "subreddit", "public_description").await,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
16
src/utils.rs
16
src/utils.rs
@ -2,8 +2,8 @@
|
|||||||
// CRATES
|
// CRATES
|
||||||
//
|
//
|
||||||
use chrono::{TimeZone, Utc};
|
use chrono::{TimeZone, Utc};
|
||||||
use surf::{get, client, middleware::Redirect};
|
use serde_json::{from_str, Value};
|
||||||
use serde_json::{Value, from_str};
|
use surf::{client, get, middleware::Redirect};
|
||||||
|
|
||||||
//
|
//
|
||||||
// STRUCTS
|
// STRUCTS
|
||||||
@ -23,7 +23,7 @@ pub struct Post {
|
|||||||
pub score: String,
|
pub score: String,
|
||||||
pub media: String,
|
pub media: String,
|
||||||
pub time: String,
|
pub time: String,
|
||||||
pub flair: Flair
|
pub flair: Flair,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -32,7 +32,7 @@ pub struct Comment {
|
|||||||
pub body: String,
|
pub body: String,
|
||||||
pub author: String,
|
pub author: String,
|
||||||
pub score: String,
|
pub score: String,
|
||||||
pub time: String
|
pub time: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -42,7 +42,7 @@ pub struct User {
|
|||||||
pub icon: String,
|
pub icon: String,
|
||||||
pub karma: i64,
|
pub karma: i64,
|
||||||
pub banner: String,
|
pub banner: String,
|
||||||
pub description: String
|
pub description: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -53,7 +53,7 @@ pub struct Subreddit {
|
|||||||
pub description: String,
|
pub description: String,
|
||||||
pub icon: String,
|
pub icon: String,
|
||||||
pub members: String,
|
pub members: String,
|
||||||
pub active: String
|
pub active: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parser for query params, used in sorting (eg. /r/rust/?sort=hot)
|
// Parser for query params, used in sorting (eg. /r/rust/?sort=hot)
|
||||||
@ -61,14 +61,14 @@ pub struct Subreddit {
|
|||||||
pub struct Params {
|
pub struct Params {
|
||||||
pub sort: Option<String>,
|
pub sort: Option<String>,
|
||||||
pub after: Option<String>,
|
pub after: Option<String>,
|
||||||
pub before: Option<String>
|
pub before: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error template
|
// Error template
|
||||||
#[derive(askama::Template)]
|
#[derive(askama::Template)]
|
||||||
#[template(path = "error.html", escape = "none")]
|
#[template(path = "error.html", escape = "none")]
|
||||||
pub struct ErrorTemplate {
|
pub struct ErrorTemplate {
|
||||||
pub message: String
|
pub message: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
Loading…
Reference in New Issue
Block a user