This commit is contained in:
Simon
2026-04-05 21:27:47 +00:00
parent 004399ecbe
commit 8d39b3a36f
6 changed files with 360 additions and 2 deletions

133
src/proxies/hqporner.rs Normal file
View File

@@ -0,0 +1,133 @@
use ntex::web;
use regex::Regex;
use url::Url;
use crate::util::requester::Requester;
#[derive(Debug, Clone)]
pub struct HqpornerProxy {}
impl HqpornerProxy {
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(url) = Url::parse(url).ok() else {
return false;
};
if url.scheme() != "https" {
return false;
}
let Some(host) = url.host_str() else {
return false;
};
(host == "hqporner.com" || host == "www.hqporner.com") && url.path().starts_with("/hdporn/")
}
fn normalize_url(raw: &str) -> String {
let value = raw.trim();
if value.is_empty() {
return String::new();
}
if value.starts_with("//") {
return format!("https:{value}");
}
if value.starts_with('/') {
return format!("https://www.hqporner.com{value}");
}
if value.starts_with("http://") {
return value.replacen("http://", "https://", 1);
}
value.to_string()
}
fn regex(value: &str) -> Option<Regex> {
Regex::new(value).ok()
}
fn extract_player_url(detail_html: &str) -> Option<String> {
let path = detail_html
.split("url: '/blocks/altplayer.php?i=")
.nth(1)
.and_then(|s| s.split('\'').next())?;
Some(Self::normalize_url(&format!(
"/blocks/altplayer.php?i={path}"
)))
}
fn extract_source_url(player_html: &str) -> Option<String> {
for source in player_html.split("<source ").skip(1) {
let src = source
.split("src=\\\"")
.nth(1)
.and_then(|s| s.split("\\\"").next())
.or_else(|| {
source
.split("src=\"")
.nth(1)
.and_then(|s| s.split('"').next())
})
.unwrap_or_default();
let url = Self::normalize_url(src);
if !url.is_empty() {
return Some(url);
}
}
let source_regex = Self::regex(r#"src=\\\"([^\\"]+)\\\""#)?;
source_regex
.captures(player_html)
.and_then(|caps| caps.get(1))
.map(|m| Self::normalize_url(m.as_str()))
.filter(|value| !value.is_empty())
}
}
impl crate::proxies::Proxy for HqpornerProxy {
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 mut requester = requester.get_ref().clone();
let headers = vec![("Referer".to_string(), "https://hqporner.com/".to_string())];
let detail_html = requester
.get_with_headers(&detail_url, headers.clone(), None)
.await
.unwrap_or_default();
if detail_html.is_empty() {
return String::new();
}
let Some(player_url) = Self::extract_player_url(&detail_html) else {
return String::new();
};
let player_html = requester
.get_with_headers(&player_url, headers, None)
.await
.unwrap_or_default();
if player_html.is_empty() {
return String::new();
}
Self::extract_source_url(&player_html).unwrap_or_default()
}
}