vjav proxy
This commit is contained in:
@@ -8,6 +8,7 @@ use crate::proxies::pimpbunny::PimpbunnyProxy;
|
|||||||
use crate::proxies::porndish::PorndishProxy;
|
use crate::proxies::porndish::PorndishProxy;
|
||||||
use crate::proxies::shooshtime::ShooshtimeProxy;
|
use crate::proxies::shooshtime::ShooshtimeProxy;
|
||||||
use crate::proxies::spankbang::SpankbangProxy;
|
use crate::proxies::spankbang::SpankbangProxy;
|
||||||
|
use crate::proxies::vjav::VjavProxy;
|
||||||
use crate::{proxies::sxyprn::SxyprnProxy, util::requester::Requester};
|
use crate::{proxies::sxyprn::SxyprnProxy, util::requester::Requester};
|
||||||
|
|
||||||
pub mod doodstream;
|
pub mod doodstream;
|
||||||
@@ -26,6 +27,7 @@ pub mod pornhubthumb;
|
|||||||
pub mod shooshtime;
|
pub mod shooshtime;
|
||||||
pub mod spankbang;
|
pub mod spankbang;
|
||||||
pub mod sxyprn;
|
pub mod sxyprn;
|
||||||
|
pub mod vjav;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum AnyProxy {
|
pub enum AnyProxy {
|
||||||
@@ -39,6 +41,7 @@ pub enum AnyProxy {
|
|||||||
Shooshtime(ShooshtimeProxy),
|
Shooshtime(ShooshtimeProxy),
|
||||||
Hqporner(HqpornerProxy),
|
Hqporner(HqpornerProxy),
|
||||||
Heavyfetish(HeavyfetishProxy),
|
Heavyfetish(HeavyfetishProxy),
|
||||||
|
Vjav(VjavProxy),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Proxy {
|
pub trait Proxy {
|
||||||
@@ -58,6 +61,7 @@ impl Proxy for AnyProxy {
|
|||||||
AnyProxy::Shooshtime(p) => p.get_video_url(url, requester).await,
|
AnyProxy::Shooshtime(p) => p.get_video_url(url, requester).await,
|
||||||
AnyProxy::Hqporner(p) => p.get_video_url(url, requester).await,
|
AnyProxy::Hqporner(p) => p.get_video_url(url, requester).await,
|
||||||
AnyProxy::Heavyfetish(p) => p.get_video_url(url, requester).await,
|
AnyProxy::Heavyfetish(p) => p.get_video_url(url, requester).await,
|
||||||
|
AnyProxy::Vjav(p) => p.get_video_url(url, requester).await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
187
src/proxies/vjav.rs
Normal file
187
src/proxies/vjav.rs
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
use base64::{Engine as _, engine::general_purpose::STANDARD};
|
||||||
|
use ntex::web;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
use crate::util::requester::Requester;
|
||||||
|
|
||||||
|
const BASE_URL: &str = "https://vjav.com";
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct VjavProxy {}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Clone, Default)]
|
||||||
|
struct VideofileEntry {
|
||||||
|
#[serde(default)]
|
||||||
|
video_url: String,
|
||||||
|
#[serde(default)]
|
||||||
|
is_default: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VjavProxy {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normalize_detail_url(endpoint: &str) -> Option<String> {
|
||||||
|
let endpoint = endpoint.trim().trim_start_matches('/');
|
||||||
|
if endpoint.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let detail_url = if endpoint.starts_with("http://") || endpoint.starts_with("https://") {
|
||||||
|
endpoint.to_string()
|
||||||
|
} else {
|
||||||
|
format!("https://{}", endpoint.trim_start_matches('/'))
|
||||||
|
};
|
||||||
|
|
||||||
|
Self::is_allowed_detail_url(&detail_url).then_some(detail_url)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_allowed_detail_url(url: &str) -> bool {
|
||||||
|
let Some(parsed) = Url::parse(url).ok() else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
if parsed.scheme() != "https" {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(host) = parsed.host_str() else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
if host != "vjav.com" && host != "www.vjav.com" {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(video_id) = Self::extract_video_id(parsed.path()) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
!video_id.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_video_id(path: &str) -> Option<String> {
|
||||||
|
let mut segments = path.split('/').filter(|segment| !segment.is_empty());
|
||||||
|
let first = segments.next()?;
|
||||||
|
let second = segments.next()?;
|
||||||
|
|
||||||
|
if first != "videos" {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
second
|
||||||
|
.chars()
|
||||||
|
.all(|value| value.is_ascii_digit())
|
||||||
|
.then_some(second.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_obfuscated_base64(value: &str) -> String {
|
||||||
|
value
|
||||||
|
.chars()
|
||||||
|
.map(|character| match character {
|
||||||
|
'А' => 'A',
|
||||||
|
'В' => 'B',
|
||||||
|
'Е' => 'E',
|
||||||
|
'К' => 'K',
|
||||||
|
'М' => 'M',
|
||||||
|
'Н' => 'H',
|
||||||
|
'О' => 'O',
|
||||||
|
'Р' => 'P',
|
||||||
|
'С' => 'C',
|
||||||
|
'Т' => 'T',
|
||||||
|
'Х' => 'X',
|
||||||
|
'а' => 'a',
|
||||||
|
'е' => 'e',
|
||||||
|
'о' => 'o',
|
||||||
|
'р' => 'p',
|
||||||
|
'с' => 'c',
|
||||||
|
'у' => 'y',
|
||||||
|
'х' => 'x',
|
||||||
|
'к' => 'k',
|
||||||
|
'м' => 'm',
|
||||||
|
'і' => 'i',
|
||||||
|
'І' => 'I',
|
||||||
|
_ => character,
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_base64ish(value: &str) -> Option<String> {
|
||||||
|
let mut normalized = value.trim().replace('~', "=");
|
||||||
|
while normalized.len() % 4 != 0 {
|
||||||
|
normalized.push('=');
|
||||||
|
}
|
||||||
|
let bytes = STANDARD.decode(normalized).ok()?;
|
||||||
|
String::from_utf8(bytes).ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_video_url(value: &str) -> Option<String> {
|
||||||
|
let normalized = Self::decode_obfuscated_base64(value);
|
||||||
|
if normalized.contains(',') {
|
||||||
|
let mut parts = normalized.split(',');
|
||||||
|
let path_part = parts.next()?;
|
||||||
|
let query_part = parts.next()?;
|
||||||
|
|
||||||
|
let path = Self::decode_base64ish(path_part)?;
|
||||||
|
let query = Self::decode_base64ish(query_part)?;
|
||||||
|
let separator = if path.contains('?') { "&" } else { "?" };
|
||||||
|
return Some(format!("{BASE_URL}{path}{separator}{query}&f=video.m3u8"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let decoded = Self::decode_base64ish(&normalized)?;
|
||||||
|
if decoded.starts_with("http://") || decoded.starts_with("https://") {
|
||||||
|
return Some(decoded);
|
||||||
|
}
|
||||||
|
if decoded.starts_with('/') {
|
||||||
|
return Some(format!("{BASE_URL}{decoded}"));
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::proxies::Proxy for VjavProxy {
|
||||||
|
async fn get_video_url(&self, url: String, requester: web::types::State<Requester>) -> String {
|
||||||
|
let Some(detail_url) = Self::normalize_detail_url(&url) else {
|
||||||
|
return String::new();
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(video_id) = Url::parse(&detail_url)
|
||||||
|
.ok()
|
||||||
|
.and_then(|value| Self::extract_video_id(value.path()))
|
||||||
|
else {
|
||||||
|
return String::new();
|
||||||
|
};
|
||||||
|
|
||||||
|
let api_url = format!("{BASE_URL}/api/videofile.php?video_id={video_id}&lifetime=8640000");
|
||||||
|
|
||||||
|
let mut requester = requester.get_ref().clone();
|
||||||
|
let text = requester.get(&api_url, None).await.unwrap_or_default();
|
||||||
|
if text.is_empty() {
|
||||||
|
return String::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
let Ok(entries) = serde_json::from_str::<Vec<VideofileEntry>>(&text) else {
|
||||||
|
return String::new();
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut fallback = String::new();
|
||||||
|
for entry in entries {
|
||||||
|
if entry.video_url.trim().is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let Some(decoded) = Self::decode_video_url(&entry.video_url) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if entry.is_default == 1 {
|
||||||
|
return decoded;
|
||||||
|
}
|
||||||
|
if fallback.is_empty() {
|
||||||
|
fallback = decoded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fallback
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ use crate::proxies::pornhd3x::Pornhd3xProxy;
|
|||||||
use crate::proxies::shooshtime::ShooshtimeProxy;
|
use crate::proxies::shooshtime::ShooshtimeProxy;
|
||||||
use crate::proxies::spankbang::SpankbangProxy;
|
use crate::proxies::spankbang::SpankbangProxy;
|
||||||
use crate::proxies::sxyprn::SxyprnProxy;
|
use crate::proxies::sxyprn::SxyprnProxy;
|
||||||
|
use crate::proxies::vjav::VjavProxy;
|
||||||
use crate::proxies::*;
|
use crate::proxies::*;
|
||||||
use crate::util::requester::Requester;
|
use crate::util::requester::Requester;
|
||||||
|
|
||||||
@@ -49,6 +50,11 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
|||||||
.route(web::post().to(proxy2redirect))
|
.route(web::post().to(proxy2redirect))
|
||||||
.route(web::get().to(proxy2redirect)),
|
.route(web::get().to(proxy2redirect)),
|
||||||
)
|
)
|
||||||
|
.service(
|
||||||
|
web::resource("/vjav/{endpoint}*")
|
||||||
|
.route(web::post().to(proxy2redirect))
|
||||||
|
.route(web::get().to(proxy2redirect)),
|
||||||
|
)
|
||||||
.service(
|
.service(
|
||||||
web::resource("/pornhd3x/{endpoint}*")
|
web::resource("/pornhd3x/{endpoint}*")
|
||||||
.route(web::post().to(proxy2redirect))
|
.route(web::post().to(proxy2redirect))
|
||||||
@@ -128,6 +134,7 @@ fn get_proxy(proxy: &str) -> Option<AnyProxy> {
|
|||||||
"javtiful" => Some(AnyProxy::Javtiful(JavtifulProxy::new())),
|
"javtiful" => Some(AnyProxy::Javtiful(JavtifulProxy::new())),
|
||||||
"hqporner" => Some(AnyProxy::Hqporner(HqpornerProxy::new())),
|
"hqporner" => Some(AnyProxy::Hqporner(HqpornerProxy::new())),
|
||||||
"heavyfetish" => Some(AnyProxy::Heavyfetish(HeavyfetishProxy::new())),
|
"heavyfetish" => Some(AnyProxy::Heavyfetish(HeavyfetishProxy::new())),
|
||||||
|
"vjav" => Some(AnyProxy::Vjav(VjavProxy::new())),
|
||||||
"pornhd3x" => Some(AnyProxy::Pornhd3x(Pornhd3xProxy::new())),
|
"pornhd3x" => Some(AnyProxy::Pornhd3x(Pornhd3xProxy::new())),
|
||||||
"shooshtime" => Some(AnyProxy::Shooshtime(ShooshtimeProxy::new())),
|
"shooshtime" => Some(AnyProxy::Shooshtime(ShooshtimeProxy::new())),
|
||||||
"pimpbunny" => Some(AnyProxy::Pimpbunny(PimpbunnyProxy::new())),
|
"pimpbunny" => Some(AnyProxy::Pimpbunny(PimpbunnyProxy::new())),
|
||||||
|
|||||||
Reference in New Issue
Block a user