use ntex::web::{self, HttpRequest}; use crate::proxies::archivebate::ArchivebateProxy; use crate::proxies::clapdat::ClapdatProxy; use crate::proxies::doodstream::DoodstreamProxy; use crate::proxies::heavyfetish::HeavyfetishProxy; use crate::proxies::hqporner::HqpornerProxy; use crate::proxies::javtiful::JavtifulProxy; use crate::proxies::pimpbunny::PimpbunnyProxy; use crate::proxies::porndish::PorndishProxy; use crate::proxies::pornhd3x::Pornhd3xProxy; use crate::proxies::spankbang::SpankbangProxy; use crate::proxies::supjav::SupjavProxy; use crate::proxies::sxyprn::SxyprnProxy; use crate::proxies::tube8::Tube8Proxy; use crate::proxies::vjav::VjavProxy; use crate::proxies::vidara::VidaraProxy; use crate::proxies::lulustream::LulustreamProxy; use crate::proxies::thaiporntv::ThaipornTvProxy; use crate::proxies::*; use crate::util::requester::Requester; /// Proxies that answer with a `302` to the real media instead of streaming it. /// The Hot Tub app cannot follow a redirect inside `formats[].url`, so for app /// clients a format pointing at one of these is moved to `video.url` (see /// `move_redirect_formats_to_url`). Keep in sync with the `proxy2redirect` /// routes below; `redirect_proxy_list_matches_routes` enforces it. pub const REDIRECT_PROXIES: &[&str] = &[ "archivebate", "clapdat", "doodstream", "lulustream", "sxyprn", "javtiful", "spankbang", "porndish", "hqporner", "heavyfetish", "vjav", "pornhd3x", "vidara", "pimpbunny", "thaiporntv", "tube8", "supjav", ]; /// True for a `/proxy//...` URL (absolute or host-relative). pub fn is_redirect_proxy_url(url: &str) -> bool { let Some(rest) = url.split_once("/proxy/").map(|(_, rest)| rest) else { return false; }; let name = rest.split('/').next().unwrap_or_default(); REDIRECT_PROXIES.contains(&name) } pub fn config(cfg: &mut web::ServiceConfig) { cfg.service( web::resource("/archivebate/{endpoint}*") .route(web::post().to(proxy2redirect)) .route(web::get().to(proxy2redirect)), ) .service( web::resource("/clapdat/{endpoint}*") .route(web::post().to(proxy2redirect)) .route(web::get().to(proxy2redirect)), ) .service( web::resource("/doodstream/{endpoint}*") .route(web::post().to(proxy2redirect)) .route(web::get().to(proxy2redirect)), ) .service( web::resource("/lulustream/{endpoint}*") .route(web::post().to(proxy2redirect)) .route(web::get().to(proxy2redirect)), ) .service( web::resource("/sxyprn/{endpoint}*") .route(web::post().to(proxy2redirect)) .route(web::get().to(proxy2redirect)), ) .service( web::resource("/javtiful/{endpoint}*") .route(web::post().to(proxy2redirect)) .route(web::get().to(proxy2redirect)), ) .service( web::resource("/spankbang/{endpoint}*") .route(web::post().to(proxy2redirect)) .route(web::get().to(proxy2redirect)), ) .service( web::resource("/porndish/{endpoint}*") .route(web::post().to(proxy2redirect)) .route(web::get().to(proxy2redirect)), ) .service( web::resource("/hqporner/{endpoint}*") .route(web::post().to(proxy2redirect)) .route(web::get().to(proxy2redirect)), ) .service( web::resource("/heavyfetish/{endpoint}*") .route(web::post().to(proxy2redirect)) .route(web::get().to(proxy2redirect)), ) .service( web::resource("/vjav/{endpoint}*") .route(web::post().to(proxy2redirect)) .route(web::get().to(proxy2redirect)), ) .service( web::resource("/pornhd3x/{endpoint}*") .route(web::post().to(proxy2redirect)) .route(web::get().to(proxy2redirect)), ) .service( web::resource("/vidara/{endpoint}*") .route(web::post().to(proxy2redirect)) .route(web::get().to(proxy2redirect)), ) .service( web::resource("/shooshtime-media/{endpoint}*") .route(web::post().to(crate::proxies::shooshtime::serve_media)) .route(web::get().to(crate::proxies::shooshtime::serve_media)), ) .service( web::resource("/pimpbunny/{endpoint}*") .route(web::post().to(proxy2redirect)) .route(web::get().to(proxy2redirect)), ) .service( web::resource("/noodlemagazine/{endpoint}*") .route(web::post().to(crate::proxies::noodlemagazine::serve_media)) .route(web::get().to(crate::proxies::noodlemagazine::serve_media)), ) .service( web::resource("/animeidhentai/{endpoint}*") .route(web::get().to(crate::proxies::animeidhentai::serve_media)) .route(web::post().to(crate::proxies::animeidhentai::serve_media)) .route(web::head().to(crate::proxies::animeidhentai::serve_media)), ) .service( web::resource("/hentaitv/{endpoint}*") .route(web::get().to(crate::proxies::hentaitv::serve_media)) .route(web::post().to(crate::proxies::hentaitv::serve_media)) .route(web::head().to(crate::proxies::hentaitv::serve_media)), ) .service( web::resource("/noodlemagazine-thumb/{endpoint}*") .route(web::post().to(crate::proxies::noodlemagazine::get_image)) .route(web::get().to(crate::proxies::noodlemagazine::get_image)), ) .service( web::resource("/fikfap-thumb/{endpoint}*") .route(web::post().to(crate::proxies::fikfapthumb::get_image)) .route(web::get().to(crate::proxies::fikfapthumb::get_image)), ) .service( web::resource("/hanime-cdn/{endpoint}*") .route(web::post().to(crate::proxies::hanimecdn::get_image)) .route(web::get().to(crate::proxies::hanimecdn::get_image)), ) .service( web::resource("/hanime-thumb/{endpoint}*") .route(web::post().to(crate::proxies::hanimethumb::get_image)) .route(web::get().to(crate::proxies::hanimethumb::get_image)), ) .service( web::resource("/hqporner-thumb/{endpoint}*") .route(web::post().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)), ) .service( web::resource("/hotbunny-thumb/{endpoint}*") .route(web::post().to(crate::proxies::hotbunnythumb::get_image)) .route(web::get().to(crate::proxies::hotbunnythumb::get_image)), ); cfg.service( web::resource("/aylo-thumb/{endpoint}*") .route(web::post().to(crate::proxies::aylothumb::get_image)) .route(web::get().to(crate::proxies::aylothumb::get_image)), ); cfg.service( web::resource("/pornhub-thumb/{endpoint}*") .route(web::post().to(crate::proxies::pornhubthumb::get_image)) .route(web::get().to(crate::proxies::pornhubthumb::get_image)), ); cfg.service( web::resource("/thaiporntv/{endpoint}*") .route(web::post().to(proxy2redirect)) .route(web::get().to(proxy2redirect)), ); cfg.service( web::resource("/tube8/{endpoint}*") .route(web::post().to(proxy2redirect)) .route(web::get().to(proxy2redirect)), ); cfg.service( web::resource("/supjav/{endpoint}*") .route(web::post().to(proxy2redirect)) .route(web::get().to(proxy2redirect)) .route(web::head().to(proxy2redirect)), ); cfg.service( web::resource("/jable/{slug}*") .route(web::get().to(crate::proxies::jable::redirect_to_page)) .route(web::head().to(crate::proxies::jable::redirect_to_page)), ); cfg.service( web::resource("/thepornbunny/{slug}*") .route(web::get().to(crate::proxies::thepornbunny::redirect_to_media)) .route(web::head().to(crate::proxies::thepornbunny::redirect_to_media)), ); cfg.service( web::resource("/aps/{endpoint}*") .route(web::post().to(crate::proxies::allpornstream::serve)) .route(web::get().to(crate::proxies::allpornstream::serve)), ); cfg.service( web::resource("/melonstube/{endpoint}*") .route(web::post().to(crate::proxies::melonstube::serve)) .route(web::get().to(crate::proxies::melonstube::serve)), ); cfg.service( web::resource("/xiaoshenke/{endpoint}*") .route(web::post().to(crate::proxies::xiaoshenke::serve_media)) .route(web::get().to(crate::proxies::xiaoshenke::serve_media)) .route(web::head().to(crate::proxies::xiaoshenke::serve_media)), ); } async fn proxy2redirect( req: HttpRequest, requester: web::types::State, ) -> Result { let proxy = get_proxy(req.uri().to_string().split("/").collect::>()[2]).unwrap(); let endpoint = req.match_info().query("endpoint").to_string(); let video_url = proxy.get_video_url(endpoint, requester).await; if video_url.is_empty() { return Ok(web::HttpResponse::BadGateway().finish()); } Ok(web::HttpResponse::Found() .header("Location", video_url) .finish()) } fn get_proxy(proxy: &str) -> Option { match proxy { "archivebate" => Some(AnyProxy::Archivebate(ArchivebateProxy::new())), "clapdat" => Some(AnyProxy::Clapdat(ClapdatProxy::new())), "doodstream" => Some(AnyProxy::Doodstream(DoodstreamProxy::new())), "sxyprn" => Some(AnyProxy::Sxyprn(SxyprnProxy::new())), "javtiful" => Some(AnyProxy::Javtiful(JavtifulProxy::new())), "hqporner" => Some(AnyProxy::Hqporner(HqpornerProxy::new())), "heavyfetish" => Some(AnyProxy::Heavyfetish(HeavyfetishProxy::new())), "vjav" => Some(AnyProxy::Vjav(VjavProxy::new())), "pornhd3x" => Some(AnyProxy::Pornhd3x(Pornhd3xProxy::new())), "vidara" => Some(AnyProxy::Vidara(VidaraProxy::new())), "pimpbunny" => Some(AnyProxy::Pimpbunny(PimpbunnyProxy::new())), "porndish" => Some(AnyProxy::Porndish(PorndishProxy::new())), "spankbang" => Some(AnyProxy::Spankbang(SpankbangProxy::new())), "lulustream" => Some(AnyProxy::Lulustream(LulustreamProxy::new())), "thaiporntv" => Some(AnyProxy::ThaipornTv(ThaipornTvProxy::new())), "tube8" => Some(AnyProxy::Tube8(Tube8Proxy::new())), "supjav" => Some(AnyProxy::Supjav(SupjavProxy::new())), _ => None, } } #[cfg(test)] mod redirect_proxy_tests { use super::*; #[test] fn recognises_redirect_proxy_urls() { assert!(is_redirect_proxy_url("http://h/proxy/archivebate/archivebate.com/watch/1")); assert!(is_redirect_proxy_url("/proxy/hqporner/x")); assert!(!is_redirect_proxy_url("http://h/proxy/noodlemagazine/x")); assert!(!is_redirect_proxy_url("https://cdn.example/video.mp4")); } #[test] fn redirect_proxy_list_matches_routes() { let source = include_str!("proxy.rs"); let config_body = source .split("pub fn config(") .nth(1) .and_then(|rest| rest.split("async fn proxy2redirect(").next()) .expect("config body"); let mut from_routes: Vec = Vec::new(); for block in config_body.split("web::resource(\"/").skip(1) { let name = block.split("/{endpoint}").next().unwrap_or_default(); let until_next = block.split("web::resource(").next().unwrap_or(block); if until_next.contains("proxy2redirect") { from_routes.push(name.to_string()); } } let mut listed: Vec = REDIRECT_PROXIES.iter().map(|s| s.to_string()).collect(); from_routes.sort(); from_routes.dedup(); listed.sort(); assert_eq!(listed, from_routes); } }