upgrades
This commit is contained in:
345
src/api.rs
345
src/api.rs
@@ -83,6 +83,40 @@ impl Ord for ClientVersion {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn client_version_from_request(req: &HttpRequest) -> ClientVersion {
|
||||||
|
match req.headers().get("User-Agent") {
|
||||||
|
Some(v) => match v.to_str() {
|
||||||
|
Ok(useragent) => ClientVersion::parse(useragent)
|
||||||
|
.unwrap_or_else(|| ClientVersion::new(999, 0, "Hot%20Tub".to_string())),
|
||||||
|
Err(_) => ClientVersion::new(999, 0, "Hot%20Tub".to_string()),
|
||||||
|
},
|
||||||
|
_ => ClientVersion::new(999, 0, "Hot%20Tub".to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn ensure_videos_table(pool: &DbPool) {
|
||||||
|
match pool.get() {
|
||||||
|
Ok(mut conn) => match db::has_table(&mut conn, "videos") {
|
||||||
|
Ok(false) => {
|
||||||
|
if let Err(e) = db::create_table(
|
||||||
|
&mut conn,
|
||||||
|
"CREATE TABLE videos (id TEXT NOT NULL, url TEXT NOT NULL);",
|
||||||
|
) {
|
||||||
|
report_provider_error("db", "ensure_videos_table.create_table", &e.to_string())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(true) => {}
|
||||||
|
Err(e) => {
|
||||||
|
report_provider_error("db", "ensure_videos_table.has_table", &e.to_string()).await;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
report_provider_error("db", "ensure_videos_table.pool_get", &e.to_string()).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn normalize_query(raw_query: Option<&str>) -> (Option<String>, Option<String>) {
|
fn normalize_query(raw_query: Option<&str>) -> (Option<String>, Option<String>) {
|
||||||
let Some(raw_query) = raw_query else {
|
let Some(raw_query) = raw_query else {
|
||||||
return (None, None);
|
return (None, None);
|
||||||
@@ -130,6 +164,55 @@ fn video_matches_literal_query(video: &VideoItem, literal_query: &str) -> bool {
|
|||||||
.is_some_and(|tags| tags.iter().any(|tag| contains_literal(tag)))
|
.is_some_and(|tags| tags.iter().any(|tag| contains_literal(tag)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn normalize_uploader_name(value: &str) -> String {
|
||||||
|
value
|
||||||
|
.trim()
|
||||||
|
.trim_start_matches('#')
|
||||||
|
.split_whitespace()
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(" ")
|
||||||
|
.to_ascii_lowercase()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn video_matches_normalized_uploader(video: &VideoItem, normalized_uploader: &str) -> bool {
|
||||||
|
video
|
||||||
|
.uploader
|
||||||
|
.as_deref()
|
||||||
|
.map(normalize_uploader_name)
|
||||||
|
.is_some_and(|value| value == normalized_uploader)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_inline_previews(video_items: &mut [VideoItem]) {
|
||||||
|
for video in video_items.iter_mut() {
|
||||||
|
if video.duration <= 120 {
|
||||||
|
let mut preview_url = video.url.clone();
|
||||||
|
if let Some(x) = &video.formats {
|
||||||
|
if let Some(first) = x.first() {
|
||||||
|
preview_url = first.url.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
video.preview = Some(preview_url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn slugify(value: &str) -> String {
|
||||||
|
let mut slug = String::new();
|
||||||
|
let mut prev_dash = false;
|
||||||
|
|
||||||
|
for ch in normalize_uploader_name(value).chars() {
|
||||||
|
if ch.is_ascii_alphanumeric() {
|
||||||
|
slug.push(ch);
|
||||||
|
prev_dash = false;
|
||||||
|
} else if !prev_dash {
|
||||||
|
slug.push('-');
|
||||||
|
prev_dash = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
slug.trim_matches('-').to_string()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||||
cfg.service(
|
cfg.service(
|
||||||
web::resource("/status")
|
web::resource("/status")
|
||||||
@@ -141,19 +224,14 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
|||||||
// .route(web::get().to(videos_get))
|
// .route(web::get().to(videos_get))
|
||||||
.route(web::post().to(videos_post)),
|
.route(web::post().to(videos_post)),
|
||||||
)
|
)
|
||||||
|
.service(web::resource("/uploader").route(web::post().to(uploader_post)))
|
||||||
|
.service(web::resource("/uploaders").route(web::post().to(uploader_post)))
|
||||||
.service(web::resource("/test").route(web::get().to(test)))
|
.service(web::resource("/test").route(web::get().to(test)))
|
||||||
.service(web::resource("/proxies").route(web::get().to(proxies)));
|
.service(web::resource("/proxies").route(web::get().to(proxies)));
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn status(req: HttpRequest) -> Result<impl web::Responder, web::Error> {
|
async fn status(req: HttpRequest) -> Result<impl web::Responder, web::Error> {
|
||||||
let clientversion: ClientVersion = match req.headers().get("User-Agent") {
|
let clientversion = client_version_from_request(&req);
|
||||||
Some(v) => match v.to_str() {
|
|
||||||
Ok(useragent) => ClientVersion::parse(useragent)
|
|
||||||
.unwrap_or_else(|| ClientVersion::new(999, 0, "Hot%20Tub".to_string())),
|
|
||||||
Err(_) => ClientVersion::new(999, 0, "Hot%20Tub".to_string()),
|
|
||||||
},
|
|
||||||
_ => ClientVersion::new(999, 0, "Hot%20Tub".to_string()),
|
|
||||||
};
|
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"Received status request with client version: {:?}",
|
"Received status request with client version: {:?}",
|
||||||
@@ -198,35 +276,9 @@ async fn videos_post(
|
|||||||
requester: web::types::State<Requester>,
|
requester: web::types::State<Requester>,
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
) -> Result<impl web::Responder, web::Error> {
|
) -> Result<impl web::Responder, web::Error> {
|
||||||
let clientversion: ClientVersion = match req.headers().get("User-Agent") {
|
let clientversion = client_version_from_request(&req);
|
||||||
Some(v) => match v.to_str() {
|
|
||||||
Ok(useragent) => ClientVersion::parse(useragent)
|
|
||||||
.unwrap_or_else(|| ClientVersion::new(999, 0, "Hot%20Tub".to_string())),
|
|
||||||
Err(_) => ClientVersion::new(999, 0, "Hot%20Tub".to_string()),
|
|
||||||
},
|
|
||||||
_ => ClientVersion::new(999, 0, "Hot%20Tub".to_string()),
|
|
||||||
};
|
|
||||||
let requester = requester.get_ref().clone();
|
let requester = requester.get_ref().clone();
|
||||||
// Ensure "videos" table exists with two string columns.
|
ensure_videos_table(pool.get_ref()).await;
|
||||||
match pool.get() {
|
|
||||||
Ok(mut conn) => match db::has_table(&mut conn, "videos") {
|
|
||||||
Ok(false) => {
|
|
||||||
if let Err(e) = db::create_table(
|
|
||||||
&mut conn,
|
|
||||||
"CREATE TABLE videos (id TEXT NOT NULL, url TEXT NOT NULL);",
|
|
||||||
) {
|
|
||||||
report_provider_error("db", "videos_post.create_table", &e.to_string()).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(true) => {}
|
|
||||||
Err(e) => {
|
|
||||||
report_provider_error("db", "videos_post.has_table", &e.to_string()).await;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
report_provider_error("db", "videos_post.pool_get", &e.to_string()).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut videos = Videos {
|
let mut videos = Videos {
|
||||||
pageInfo: PageInfo {
|
pageInfo: PageInfo {
|
||||||
@@ -387,21 +439,182 @@ async fn videos_post(
|
|||||||
});
|
});
|
||||||
//###
|
//###
|
||||||
|
|
||||||
for video in videos.items.iter_mut() {
|
add_inline_previews(&mut videos.items);
|
||||||
if video.duration <= 120 {
|
|
||||||
let mut preview_url = video.url.clone();
|
|
||||||
if let Some(x) = &video.formats {
|
|
||||||
if let Some(first) = x.first() {
|
|
||||||
preview_url = first.url.clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
video.preview = Some(preview_url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(web::HttpResponse::Ok().json(&videos))
|
Ok(web::HttpResponse::Ok().json(&videos))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn uploader_post(
|
||||||
|
uploader_request: web::types::Json<UploaderRequest>,
|
||||||
|
cache: web::types::State<VideoCache>,
|
||||||
|
pool: web::types::State<DbPool>,
|
||||||
|
requester: web::types::State<Requester>,
|
||||||
|
req: HttpRequest,
|
||||||
|
) -> Result<impl web::Responder, web::Error> {
|
||||||
|
let clientversion = client_version_from_request(&req);
|
||||||
|
let requester = requester.get_ref().clone();
|
||||||
|
ensure_videos_table(pool.get_ref()).await;
|
||||||
|
|
||||||
|
let uploader_name = uploader_request
|
||||||
|
.uploader
|
||||||
|
.as_deref()
|
||||||
|
.or(uploader_request.title.as_deref())
|
||||||
|
.or(uploader_request.query.as_deref())
|
||||||
|
.map(str::trim)
|
||||||
|
.filter(|value| !value.is_empty())
|
||||||
|
.ok_or_else(|| web::error::ErrorBadRequest("Missing uploader".to_string()))?;
|
||||||
|
let normalized_uploader = normalize_uploader_name(uploader_name);
|
||||||
|
if normalized_uploader.is_empty() {
|
||||||
|
return Err(web::error::ErrorBadRequest("Missing uploader".to_string()).into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let page: u8 = uploader_request
|
||||||
|
.page
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|value| value.to_u8())
|
||||||
|
.unwrap_or(1);
|
||||||
|
let per_page: u8 = uploader_request
|
||||||
|
.perPage
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|value| value.to_u8())
|
||||||
|
.unwrap_or(10);
|
||||||
|
let sort = uploader_request
|
||||||
|
.sort
|
||||||
|
.as_deref()
|
||||||
|
.unwrap_or("date")
|
||||||
|
.to_string();
|
||||||
|
let featured = uploader_request
|
||||||
|
.featured
|
||||||
|
.as_deref()
|
||||||
|
.unwrap_or("all")
|
||||||
|
.to_string();
|
||||||
|
let category = uploader_request
|
||||||
|
.category
|
||||||
|
.as_deref()
|
||||||
|
.unwrap_or("all")
|
||||||
|
.to_string();
|
||||||
|
let sites = uploader_request
|
||||||
|
.all_provider_sites
|
||||||
|
.as_deref()
|
||||||
|
.or(uploader_request.sites.as_deref())
|
||||||
|
.unwrap_or("")
|
||||||
|
.to_string();
|
||||||
|
let filter = uploader_request
|
||||||
|
.filter
|
||||||
|
.as_deref()
|
||||||
|
.unwrap_or("new")
|
||||||
|
.to_string();
|
||||||
|
let language = uploader_request
|
||||||
|
.language
|
||||||
|
.as_deref()
|
||||||
|
.unwrap_or("en")
|
||||||
|
.to_string();
|
||||||
|
let networks = uploader_request
|
||||||
|
.networks
|
||||||
|
.as_deref()
|
||||||
|
.unwrap_or("")
|
||||||
|
.to_string();
|
||||||
|
let stars = uploader_request.stars.as_deref().unwrap_or("").to_string();
|
||||||
|
let categories = uploader_request
|
||||||
|
.categories
|
||||||
|
.as_deref()
|
||||||
|
.unwrap_or("")
|
||||||
|
.to_string();
|
||||||
|
let duration = uploader_request
|
||||||
|
.duration
|
||||||
|
.as_deref()
|
||||||
|
.unwrap_or("")
|
||||||
|
.to_string();
|
||||||
|
let sexuality = uploader_request
|
||||||
|
.sexuality
|
||||||
|
.as_deref()
|
||||||
|
.unwrap_or("")
|
||||||
|
.to_string();
|
||||||
|
let public_url_base = format!(
|
||||||
|
"{}://{}",
|
||||||
|
req.connection_info().scheme(),
|
||||||
|
req.connection_info().host()
|
||||||
|
);
|
||||||
|
let options = ServerOptions {
|
||||||
|
featured: Some(featured),
|
||||||
|
category: Some(category),
|
||||||
|
sites: Some(sites),
|
||||||
|
filter: Some(filter),
|
||||||
|
language: Some(language),
|
||||||
|
public_url_base: Some(public_url_base),
|
||||||
|
requester: Some(requester),
|
||||||
|
network: Some(networks),
|
||||||
|
stars: Some(stars),
|
||||||
|
categories: Some(categories),
|
||||||
|
duration: Some(duration),
|
||||||
|
sort: Some(sort.clone()),
|
||||||
|
sexuality: Some(sexuality),
|
||||||
|
};
|
||||||
|
|
||||||
|
let provider = get_provider("all")
|
||||||
|
.ok_or_else(|| web::error::ErrorBadRequest("Invalid channel".to_string()))?;
|
||||||
|
let mut video_items = run_provider_guarded(
|
||||||
|
"all",
|
||||||
|
"uploader_post.get_videos",
|
||||||
|
provider.get_videos(
|
||||||
|
cache.get_ref().clone(),
|
||||||
|
pool.get_ref().clone(),
|
||||||
|
sort,
|
||||||
|
Some(uploader_name.to_string()),
|
||||||
|
page.to_string(),
|
||||||
|
per_page.to_string(),
|
||||||
|
options,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
if clientversion == ClientVersion::new(38, 0, "Hot%20Tub".to_string()) {
|
||||||
|
video_items = video_items
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|video| {
|
||||||
|
let last_url = video
|
||||||
|
.formats
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|formats| formats.last().map(|f| f.url.clone()));
|
||||||
|
if let Some(url) = last_url {
|
||||||
|
let mut v = video;
|
||||||
|
v.url = url;
|
||||||
|
return Some(v);
|
||||||
|
}
|
||||||
|
Some(video)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
video_items.retain(|video| video_matches_normalized_uploader(video, &normalized_uploader));
|
||||||
|
add_inline_previews(&mut video_items);
|
||||||
|
|
||||||
|
let display_name = video_items
|
||||||
|
.iter()
|
||||||
|
.find_map(|video| video.uploader.as_ref())
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_else(|| uploader_name.to_string());
|
||||||
|
let row = LayoutRow {
|
||||||
|
id: "videos".to_string(),
|
||||||
|
row_type: "videos".to_string(),
|
||||||
|
title: "Videos".to_string(),
|
||||||
|
subtitle: Some(format!("Results for {display_name}")),
|
||||||
|
pageInfo: PageInfo {
|
||||||
|
hasNextPage: !video_items.is_empty(),
|
||||||
|
resultsPerPage: u32::from(per_page),
|
||||||
|
},
|
||||||
|
items: video_items,
|
||||||
|
};
|
||||||
|
let response = UploaderResponse {
|
||||||
|
id: slugify(&display_name),
|
||||||
|
title: display_name.clone(),
|
||||||
|
uploader: display_name,
|
||||||
|
rows: vec![row],
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(web::HttpResponse::Ok().json(&response))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_provider(channel: &str) -> Option<DynProvider> {
|
pub fn get_provider(channel: &str) -> Option<DynProvider> {
|
||||||
ALL_PROVIDERS.get(channel).cloned()
|
ALL_PROVIDERS.get(channel).cloned()
|
||||||
}
|
}
|
||||||
@@ -443,3 +656,41 @@ pub async fn proxies() -> Result<impl web::Responder, web::Error> {
|
|||||||
}
|
}
|
||||||
Ok(web::HttpResponse::Ok().json(&by_protocol))
|
Ok(web::HttpResponse::Ok().json(&by_protocol))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::{normalize_uploader_name, slugify, video_matches_normalized_uploader};
|
||||||
|
use crate::videos::VideoItem;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn normalize_uploader_name_collapses_spacing_and_case() {
|
||||||
|
assert_eq!(
|
||||||
|
normalize_uploader_name(" #The Pet Collective "),
|
||||||
|
"the pet collective"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn uploader_match_uses_normalized_equality() {
|
||||||
|
let video = VideoItem::new(
|
||||||
|
"id".to_string(),
|
||||||
|
"title".to_string(),
|
||||||
|
"https://example.com/video".to_string(),
|
||||||
|
"all".to_string(),
|
||||||
|
"https://example.com/thumb.jpg".to_string(),
|
||||||
|
90,
|
||||||
|
)
|
||||||
|
.uploader("The Pet Collective".to_string());
|
||||||
|
|
||||||
|
assert!(video_matches_normalized_uploader(
|
||||||
|
&video,
|
||||||
|
"the pet collective"
|
||||||
|
));
|
||||||
|
assert!(!video_matches_normalized_uploader(&video, "pet collective"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn slugify_uses_normalized_name() {
|
||||||
|
assert_eq!(slugify(" #The Pet Collective "), "the-pet-collective");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ pub mod pmvhaven;
|
|||||||
pub mod pornhat;
|
pub mod pornhat;
|
||||||
pub mod pornhub;
|
pub mod pornhub;
|
||||||
pub mod redtube;
|
pub mod redtube;
|
||||||
pub mod rule34video;
|
|
||||||
pub mod spankbang;
|
pub mod spankbang;
|
||||||
// pub mod hentaimoon;
|
// pub mod hentaimoon;
|
||||||
pub mod beeg;
|
pub mod beeg;
|
||||||
@@ -34,6 +33,7 @@ pub mod omgxxx;
|
|||||||
pub mod paradisehill;
|
pub mod paradisehill;
|
||||||
pub mod porn00;
|
pub mod porn00;
|
||||||
pub mod porn4fans;
|
pub mod porn4fans;
|
||||||
|
pub mod porndish;
|
||||||
pub mod pornzog;
|
pub mod pornzog;
|
||||||
pub mod shooshtime;
|
pub mod shooshtime;
|
||||||
pub mod sxyprn;
|
pub mod sxyprn;
|
||||||
@@ -53,6 +53,7 @@ pub mod javtiful;
|
|||||||
pub mod noodlemagazine;
|
pub mod noodlemagazine;
|
||||||
pub mod pimpbunny;
|
pub mod pimpbunny;
|
||||||
pub mod rule34gen;
|
pub mod rule34gen;
|
||||||
|
pub mod rule34video;
|
||||||
pub mod xxdbx;
|
pub mod xxdbx;
|
||||||
// pub mod tube8;
|
// pub mod tube8;
|
||||||
|
|
||||||
@@ -78,10 +79,6 @@ pub static ALL_PROVIDERS: Lazy<HashMap<&'static str, DynProvider>> = Lazy::new(|
|
|||||||
"spankbang",
|
"spankbang",
|
||||||
Arc::new(spankbang::SpankbangProvider::new()) as DynProvider,
|
Arc::new(spankbang::SpankbangProvider::new()) as DynProvider,
|
||||||
);
|
);
|
||||||
m.insert(
|
|
||||||
"rule34video",
|
|
||||||
Arc::new(rule34video::Rule34videoProvider::new()) as DynProvider,
|
|
||||||
);
|
|
||||||
m.insert(
|
m.insert(
|
||||||
"redtube",
|
"redtube",
|
||||||
Arc::new(redtube::RedtubeProvider::new()) as DynProvider,
|
Arc::new(redtube::RedtubeProvider::new()) as DynProvider,
|
||||||
@@ -134,6 +131,10 @@ pub static ALL_PROVIDERS: Lazy<HashMap<&'static str, DynProvider>> = Lazy::new(|
|
|||||||
"porn4fans",
|
"porn4fans",
|
||||||
Arc::new(porn4fans::Porn4fansProvider::new()) as DynProvider,
|
Arc::new(porn4fans::Porn4fansProvider::new()) as DynProvider,
|
||||||
);
|
);
|
||||||
|
m.insert(
|
||||||
|
"porndish",
|
||||||
|
Arc::new(porndish::PorndishProvider::new()) as DynProvider,
|
||||||
|
);
|
||||||
m.insert(
|
m.insert(
|
||||||
"shooshtime",
|
"shooshtime",
|
||||||
Arc::new(shooshtime::ShooshtimeProvider::new()) as DynProvider,
|
Arc::new(shooshtime::ShooshtimeProvider::new()) as DynProvider,
|
||||||
@@ -160,6 +161,10 @@ pub static ALL_PROVIDERS: Lazy<HashMap<&'static str, DynProvider>> = Lazy::new(|
|
|||||||
Arc::new(viralxxxporn::ViralxxxpornProvider::new()) as DynProvider,
|
Arc::new(viralxxxporn::ViralxxxpornProvider::new()) as DynProvider,
|
||||||
);
|
);
|
||||||
// m.insert("pornxp", Arc::new(pornxp::PornxpProvider::new()) as DynProvider);
|
// m.insert("pornxp", Arc::new(pornxp::PornxpProvider::new()) as DynProvider);
|
||||||
|
m.insert(
|
||||||
|
"rule34video",
|
||||||
|
Arc::new(rule34video::Rule34videoProvider::new()) as DynProvider,
|
||||||
|
);
|
||||||
m.insert(
|
m.insert(
|
||||||
"rule34gen",
|
"rule34gen",
|
||||||
Arc::new(rule34gen::Rule34genProvider::new()) as DynProvider,
|
Arc::new(rule34gen::Rule34genProvider::new()) as DynProvider,
|
||||||
|
|||||||
1066
src/providers/porndish.rs
Normal file
1066
src/providers/porndish.rs
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -7,6 +7,7 @@ pub mod hanimecdn;
|
|||||||
pub mod hqpornerthumb;
|
pub mod hqpornerthumb;
|
||||||
pub mod javtiful;
|
pub mod javtiful;
|
||||||
pub mod noodlemagazine;
|
pub mod noodlemagazine;
|
||||||
|
pub mod porndishthumb;
|
||||||
pub mod spankbang;
|
pub mod spankbang;
|
||||||
pub mod sxyprn;
|
pub mod sxyprn;
|
||||||
|
|
||||||
|
|||||||
62
src/proxies/porndishthumb.rs
Normal file
62
src/proxies/porndishthumb.rs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
use ntex::http::header::CONTENT_TYPE;
|
||||||
|
use ntex::{
|
||||||
|
http::Response,
|
||||||
|
web::{self, HttpRequest, error},
|
||||||
|
};
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
use crate::util::requester::Requester;
|
||||||
|
|
||||||
|
pub async fn get_image(
|
||||||
|
req: HttpRequest,
|
||||||
|
_requester: web::types::State<Requester>,
|
||||||
|
) -> Result<impl web::Responder, web::Error> {
|
||||||
|
let endpoint = req.match_info().query("endpoint").to_string();
|
||||||
|
let image_url = if endpoint.starts_with("http://") || endpoint.starts_with("https://") {
|
||||||
|
endpoint
|
||||||
|
} else {
|
||||||
|
format!("https://{}", endpoint.trim_start_matches('/'))
|
||||||
|
};
|
||||||
|
|
||||||
|
let output = tokio::task::spawn_blocking(move || {
|
||||||
|
Command::new("python3")
|
||||||
|
.arg("-c")
|
||||||
|
.arg(
|
||||||
|
r#"
|
||||||
|
import sys
|
||||||
|
from curl_cffi import requests
|
||||||
|
|
||||||
|
url = sys.argv[1]
|
||||||
|
response = requests.get(
|
||||||
|
url,
|
||||||
|
impersonate="chrome",
|
||||||
|
timeout=30,
|
||||||
|
allow_redirects=True,
|
||||||
|
headers={"Referer": "https://www.porndish.com/"},
|
||||||
|
)
|
||||||
|
if response.status_code >= 400:
|
||||||
|
sys.stderr.write(f"status={response.status_code}\n")
|
||||||
|
sys.exit(1)
|
||||||
|
sys.stderr.write(response.headers.get("content-type", "application/octet-stream"))
|
||||||
|
sys.stdout.buffer.write(response.content)
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.arg(image_url)
|
||||||
|
.output()
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.map_err(error::ErrorBadGateway)?
|
||||||
|
.map_err(error::ErrorBadGateway)?;
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
return Ok(web::HttpResponse::NotFound().finish());
|
||||||
|
}
|
||||||
|
|
||||||
|
let content_type = String::from_utf8_lossy(&output.stderr).trim().to_string();
|
||||||
|
let mut resp = Response::build(ntex::http::StatusCode::OK);
|
||||||
|
if !content_type.is_empty() {
|
||||||
|
resp.set_header(CONTENT_TYPE, content_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(resp.body(output.stdout))
|
||||||
|
}
|
||||||
@@ -36,6 +36,11 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
|||||||
web::resource("/hqporner-thumb/{endpoint}*")
|
web::resource("/hqporner-thumb/{endpoint}*")
|
||||||
.route(web::post().to(crate::proxies::hqpornerthumb::get_image))
|
.route(web::post().to(crate::proxies::hqpornerthumb::get_image))
|
||||||
.route(web::get().to(crate::proxies::hqpornerthumb::get_image)),
|
.route(web::get().to(crate::proxies::hqpornerthumb::get_image)),
|
||||||
|
)
|
||||||
|
.service(
|
||||||
|
web::resource("/porndish-thumb/{endpoint}*")
|
||||||
|
.route(web::post().to(crate::proxies::porndishthumb::get_image))
|
||||||
|
.route(web::get().to(crate::proxies::porndishthumb::get_image)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,30 @@ pub struct VideosRequest {
|
|||||||
pub duration: Option<String>,
|
pub duration: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize, Debug)]
|
||||||
|
pub struct UploaderRequest {
|
||||||
|
pub uploader: Option<String>,
|
||||||
|
pub title: Option<String>,
|
||||||
|
pub uploaderUrl: Option<String>,
|
||||||
|
pub uploaderId: Option<String>,
|
||||||
|
pub channel: Option<String>,
|
||||||
|
pub sort: Option<String>,
|
||||||
|
pub query: Option<String>,
|
||||||
|
pub page: Option<FlexibleNumber>,
|
||||||
|
pub perPage: Option<FlexibleNumber>,
|
||||||
|
pub featured: Option<String>,
|
||||||
|
pub category: Option<String>,
|
||||||
|
pub sites: Option<String>,
|
||||||
|
pub all_provider_sites: Option<String>,
|
||||||
|
pub filter: Option<String>,
|
||||||
|
pub language: Option<String>,
|
||||||
|
pub networks: Option<String>,
|
||||||
|
pub stars: Option<String>,
|
||||||
|
pub categories: Option<String>,
|
||||||
|
pub duration: Option<String>,
|
||||||
|
pub sexuality: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
|
||||||
pub struct ServerOptions {
|
pub struct ServerOptions {
|
||||||
pub featured: Option<String>, // "featured",
|
pub featured: Option<String>, // "featured",
|
||||||
@@ -405,3 +429,23 @@ pub struct Videos {
|
|||||||
pub pageInfo: PageInfo,
|
pub pageInfo: PageInfo,
|
||||||
pub items: Vec<VideoItem>,
|
pub items: Vec<VideoItem>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, Debug)]
|
||||||
|
pub struct LayoutRow {
|
||||||
|
pub id: String,
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
pub row_type: String,
|
||||||
|
pub title: String,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub subtitle: Option<String>,
|
||||||
|
pub pageInfo: PageInfo,
|
||||||
|
pub items: Vec<VideoItem>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, Debug)]
|
||||||
|
pub struct UploaderResponse {
|
||||||
|
pub id: String,
|
||||||
|
pub title: String,
|
||||||
|
pub uploader: String,
|
||||||
|
pub rows: Vec<LayoutRow>,
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user