hanime updates
This commit is contained in:
@@ -126,13 +126,13 @@ impl HanimeProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_video_item(&self, hit: HanimeSearchResult, pool: DbPool) -> Result<VideoItem> {
|
async fn get_video_item(&self, hit: HanimeSearchResult, pool: DbPool, options: ServerOptions) -> Result<VideoItem> {
|
||||||
let mut conn = pool.get().expect("couldn't get db connection from pool");
|
let mut conn = pool.get().expect("couldn't get db connection from pool");
|
||||||
let db_result = db::get_video(&mut conn,format!("https://h.freeanimehentai.net/api/v8/video?id={}&", hit.slug.clone()));
|
let db_result = db::get_video(&mut conn,format!("https://h.freeanimehentai.net/api/v8/video?id={}&", hit.slug.clone()));
|
||||||
drop(conn);
|
drop(conn);
|
||||||
let id = hit.id.to_string();
|
let id = hit.id.to_string();
|
||||||
let title = hit.name;
|
let title = hit.name;
|
||||||
let thumb = hit.poster_url;
|
let thumb = hit.cover_url.replace("hanime-cdn.com", "hottub.spacemoehre.de");
|
||||||
let duration = (hit.duration_in_ms / 1000) as u32; // Convert ms to seconds
|
let duration = (hit.duration_in_ms / 1000) as u32; // Convert ms to seconds
|
||||||
let channel = "hanime".to_string(); // Placeholder, adjust as needed
|
let channel = "hanime".to_string(); // Placeholder, adjust as needed
|
||||||
match db_result {
|
match db_result {
|
||||||
@@ -142,6 +142,7 @@ impl HanimeProvider {
|
|||||||
.uploader(hit.brand)
|
.uploader(hit.brand)
|
||||||
.views(hit.views as u32)
|
.views(hit.views as u32)
|
||||||
.rating((hit.likes as f32 / (hit.likes + hit.dislikes)as f32) * 100 as f32)
|
.rating((hit.likes as f32 / (hit.likes + hit.dislikes)as f32) * 100 as f32)
|
||||||
|
.aspect_ratio(0.68)
|
||||||
.formats(vec![videos::VideoFormat::new(video_url.clone(), "1080".to_string(), "m3u8".to_string())]));
|
.formats(vec![videos::VideoFormat::new(video_url.clone(), "1080".to_string(), "m3u8".to_string())]));
|
||||||
}
|
}
|
||||||
Ok(None) => (),
|
Ok(None) => (),
|
||||||
@@ -150,22 +151,10 @@ impl HanimeProvider {
|
|||||||
// return Err(format!("Error fetching video from database: {}", e).into());
|
// return Err(format!("Error fetching video from database: {}", e).into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let client = Client::builder()
|
|
||||||
.emulation(Emulation::Firefox136)
|
|
||||||
.build()?;
|
|
||||||
let url = format!("https://h.freeanimehentai.net/api/v8/video?id={}&", hit.slug);
|
let url = format!("https://h.freeanimehentai.net/api/v8/video?id={}&", hit.slug);
|
||||||
let response = client.get(url).send().await?;
|
|
||||||
|
|
||||||
let text = match response.status().is_success() {
|
let mut requester = options.requester.clone().unwrap();
|
||||||
true => {
|
let text = requester.get(&url).await.unwrap();
|
||||||
response.text().await?
|
|
||||||
},
|
|
||||||
false => {
|
|
||||||
print!("Failed to fetch video item: {}\n\n", response.status());
|
|
||||||
return Err(format!("Failed to fetch video item: {}", response.status()).into());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let urls = text.split("\"servers\"").collect::<Vec<&str>>()[1];
|
let urls = text.split("\"servers\"").collect::<Vec<&str>>()[1];
|
||||||
let mut url_vec = vec![];
|
let mut url_vec = vec![];
|
||||||
@@ -188,7 +177,7 @@ impl HanimeProvider {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get(&self, cache: VideoCache, pool: DbPool, page: u8, query: String, sort:String) -> Result<Vec<VideoItem>> {
|
async fn get(&self, cache: VideoCache, pool: DbPool, page: u8, query: String, sort:String, options: ServerOptions) -> Result<Vec<VideoItem>> {
|
||||||
let index = format!("hanime:{}:{}:{}", query, page, sort);
|
let index = format!("hanime:{}:{}:{}", query, page, sort);
|
||||||
let order_by = match sort.contains("."){
|
let order_by = match sort.contains("."){
|
||||||
true => sort.split(".").collect::<Vec<&str>>()[0].to_string(),
|
true => sort.split(".").collect::<Vec<&str>>()[0].to_string(),
|
||||||
@@ -218,12 +207,9 @@ impl HanimeProvider {
|
|||||||
.search_text(query.clone())
|
.search_text(query.clone())
|
||||||
.order_by(order_by)
|
.order_by(order_by)
|
||||||
.ordering(ordering);
|
.ordering(ordering);
|
||||||
let client = Client::builder()
|
|
||||||
.emulation(Emulation::Firefox136)
|
let mut requester = options.requester.clone().unwrap();
|
||||||
.build()?;
|
let response = requester.post("https://search.htv-services.com/search", &search, vec![]).await.unwrap();
|
||||||
let response = client.post("https://search.htv-services.com/search")
|
|
||||||
.json(&search)
|
|
||||||
.send().await?;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -237,7 +223,7 @@ impl HanimeProvider {
|
|||||||
let hits_json: Vec<HanimeSearchResult> = serde_json::from_str(hits.as_str())
|
let hits_json: Vec<HanimeSearchResult> = serde_json::from_str(hits.as_str())
|
||||||
.map_err(|e| format!("Failed to parse hits JSON: {}", e))?;
|
.map_err(|e| format!("Failed to parse hits JSON: {}", e))?;
|
||||||
// let timeout_duration = Duration::from_secs(120);
|
// let timeout_duration = Duration::from_secs(120);
|
||||||
let futures = hits_json.into_iter().map(|el| self.get_video_item(el.clone(), pool.clone()));
|
let futures = hits_json.into_iter().map(|el| self.get_video_item(el.clone(), pool.clone(), options.clone()));
|
||||||
let results: Vec<Result<VideoItem>> = join_all(futures).await;
|
let results: Vec<Result<VideoItem>> = join_all(futures).await;
|
||||||
let video_items: Vec<VideoItem> = results
|
let video_items: Vec<VideoItem> = results
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -270,8 +256,8 @@ impl Provider for HanimeProvider {
|
|||||||
let _ = per_page;
|
let _ = per_page;
|
||||||
let _ = sort;
|
let _ = sort;
|
||||||
let videos: std::result::Result<Vec<VideoItem>, Error> = match query {
|
let videos: std::result::Result<Vec<VideoItem>, Error> = match query {
|
||||||
Some(q) => self.get(cache, pool, page.parse::<u8>().unwrap_or(1), q, sort).await,
|
Some(q) => self.get(cache, pool, page.parse::<u8>().unwrap_or(1), q, sort, options).await,
|
||||||
None => self.get(cache, pool, page.parse::<u8>().unwrap_or(1), "".to_string(), sort).await,
|
None => self.get(cache, pool, page.parse::<u8>().unwrap_or(1), "".to_string(), sort, options).await,
|
||||||
};
|
};
|
||||||
match videos {
|
match videos {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
|
|||||||
54
src/proxies/hanimecdn.rs
Normal file
54
src/proxies/hanimecdn.rs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
use ntex::{
|
||||||
|
http::Response,
|
||||||
|
web::{self, HttpRequest, error},
|
||||||
|
};
|
||||||
|
use ntex::http::header::{CONTENT_LENGTH, CONTENT_TYPE};
|
||||||
|
|
||||||
|
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 = format!("https://hanime-cdn.com/{}", endpoint);
|
||||||
|
|
||||||
|
let upstream = match requester
|
||||||
|
.get_ref()
|
||||||
|
.clone()
|
||||||
|
.get_raw_with_headers(
|
||||||
|
image_url.as_str(),
|
||||||
|
vec![("Referer".to_string(), "https://hanime.tv/".to_string())],
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(response) => response,
|
||||||
|
Err(_) => return Ok(web::HttpResponse::NotFound().finish()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let status = upstream.status();
|
||||||
|
let headers = upstream.headers().clone();
|
||||||
|
|
||||||
|
// Read body from upstream
|
||||||
|
let bytes = upstream.bytes().await.map_err(error::ErrorBadGateway)?;
|
||||||
|
|
||||||
|
// Build response and forward headers
|
||||||
|
let mut resp = Response::build(status);
|
||||||
|
|
||||||
|
if let Some(ct) = headers.get(CONTENT_TYPE) {
|
||||||
|
if let Ok(ct_str) = ct.to_str() {
|
||||||
|
resp.set_header(CONTENT_TYPE, ct_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(cl) = headers.get(CONTENT_LENGTH) {
|
||||||
|
if let Ok(cl_str) = cl.to_str() {
|
||||||
|
resp.set_header(CONTENT_LENGTH, cl_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Either zero-copy to ntex Bytes...
|
||||||
|
// Ok(resp.body(NtexBytes::from(bytes)))
|
||||||
|
|
||||||
|
// ...or simple & compatible:
|
||||||
|
Ok(resp.body(bytes.to_vec()))
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ use ntex::web;
|
|||||||
use crate::{proxies::sxyprn::SxyprnProxy, util::requester::Requester};
|
use crate::{proxies::sxyprn::SxyprnProxy, util::requester::Requester};
|
||||||
|
|
||||||
pub mod sxyprn;
|
pub mod sxyprn;
|
||||||
|
pub mod hanimecdn;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum AnyProxy {
|
pub enum AnyProxy {
|
||||||
@@ -19,7 +20,6 @@ pub trait Proxy {
|
|||||||
|
|
||||||
|
|
||||||
impl Proxy for AnyProxy {
|
impl Proxy for AnyProxy {
|
||||||
|
|
||||||
async fn get_video_url(
|
async fn get_video_url(
|
||||||
&self,
|
&self,
|
||||||
url: String,
|
url: String,
|
||||||
|
|||||||
@@ -10,6 +10,11 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
|||||||
.route(web::post().to(sxyprn))
|
.route(web::post().to(sxyprn))
|
||||||
.route(web::get().to(sxyprn)),
|
.route(web::get().to(sxyprn)),
|
||||||
)
|
)
|
||||||
|
.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(
|
// .service(
|
||||||
// web::resource("/videos")
|
// web::resource("/videos")
|
||||||
// // .route(web::get().to(videos_get))
|
// // .route(web::get().to(videos_get))
|
||||||
@@ -23,7 +28,6 @@ async fn sxyprn(req: HttpRequest,
|
|||||||
requester: web::types::State<Requester>,) -> Result<impl web::Responder, web::Error> {
|
requester: web::types::State<Requester>,) -> Result<impl web::Responder, web::Error> {
|
||||||
let proxy = get_proxy(req.uri().to_string().split("/").collect::<Vec<&str>>()[2]).unwrap();
|
let proxy = get_proxy(req.uri().to_string().split("/").collect::<Vec<&str>>()[2]).unwrap();
|
||||||
let endpoint = req.match_info().query("endpoint").to_string();
|
let endpoint = req.match_info().query("endpoint").to_string();
|
||||||
println!("/proxy/sxyprn: endpoint={:?}", endpoint);
|
|
||||||
let video_url = match proxy.get_video_url(endpoint, requester).await{
|
let video_url = match proxy.get_video_url(endpoint, requester).await{
|
||||||
url if url != "" => url,
|
url if url != "" => url,
|
||||||
_ => "Error".to_string(),
|
_ => "Error".to_string(),
|
||||||
|
|||||||
@@ -83,6 +83,29 @@ impl Requester {
|
|||||||
request.send().await
|
request.send().await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_raw_with_headers(&mut self, url: &str, headers: Vec<(String, String)>) -> Result<Response, wreq::Error> {
|
||||||
|
let client = Client::builder()
|
||||||
|
.cert_verification(false)
|
||||||
|
.emulation(Emulation::Firefox136)
|
||||||
|
.cookie_store(true)
|
||||||
|
.build()
|
||||||
|
.expect("Failed to create HTTP client");
|
||||||
|
|
||||||
|
let mut request = client.get(url).version(Version::HTTP_11);
|
||||||
|
|
||||||
|
if self.proxy {
|
||||||
|
if let Ok(proxy_url) = env::var("BURP_URL") {
|
||||||
|
let proxy = Proxy::all(&proxy_url).unwrap();
|
||||||
|
request = request.proxy(proxy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Set custom headers
|
||||||
|
for (key, value) in headers.iter() {
|
||||||
|
request = request.header(key, value);
|
||||||
|
}
|
||||||
|
request.send().await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn post<S>(&mut self, url: &str, data: &S, headers: Vec<(String, String)>) -> Result<Response, wreq::Error>
|
pub async fn post<S>(&mut self, url: &str, data: &S, headers: Vec<(String, String)>) -> Result<Response, wreq::Error>
|
||||||
where
|
where
|
||||||
S: Serialize + ?Sized,
|
S: Serialize + ?Sized,
|
||||||
|
|||||||
Reference in New Issue
Block a user