diff --git a/src/api.rs b/src/api.rs index 0fc3b39..2be028f 100644 --- a/src/api.rs +++ b/src/api.rs @@ -119,6 +119,7 @@ async fn status(req: HttpRequest) -> Result { .and_then(|h| h.to_str().ok()) .unwrap_or_default() .to_string(); + let public_url_base = format!("{}://{}", req.connection_info().scheme(), host); let mut status = Status::new(); for (provider_name, provider) in ALL_PROVIDERS.iter() { @@ -126,7 +127,12 @@ async fn status(req: HttpRequest) -> Result { provider.get_channel(clientversion.clone()) })); match channel_result { - Ok(Some(channel)) => status.add_channel(channel), + Ok(Some(mut channel)) => { + if channel.favicon.starts_with('/') { + channel.favicon = format!("{}{}", public_url_base, channel.favicon); + } + status.add_channel(channel) + } Ok(None) => {} Err(payload) => { let panic_msg = panic_payload_to_string(payload); @@ -134,7 +140,7 @@ async fn status(req: HttpRequest) -> Result { } } } - status.iconUrl = format!("http://{}/favicon.ico", host).to_string(); + status.iconUrl = format!("{}/favicon.ico", public_url_base).to_string(); Ok(web::HttpResponse::Ok().json(&status)) } @@ -245,12 +251,18 @@ async fn videos_post( .to_string(); let duration = video_request.duration.as_deref().unwrap_or("").to_string(); let sexuality = video_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(network), stars: Some(stars), diff --git a/src/providers/all.rs b/src/providers/all.rs index 92c261e..68c13c3 100644 --- a/src/providers/all.rs +++ b/src/providers/all.rs @@ -158,7 +158,7 @@ impl Provider for AllProvider { name: "All".to_string(), description: "Query from all sites of this Server".to_string(), premium: false, - favicon: "https://hottub.spacemoehre.de/favicon.ico".to_string(), + favicon: "/favicon.ico".to_string(), status: "active".to_string(), categories: vec![], options: vec![ChannelOption { diff --git a/src/providers/hanime.rs b/src/providers/hanime.rs index 32e6e00..f352aff 100644 --- a/src/providers/hanime.rs +++ b/src/providers/hanime.rs @@ -213,9 +213,10 @@ impl HanimeProvider { drop(conn); let id = hit.id.to_string(); let title = hit.name; - let thumb = hit.cover_url.replace( - "https://hanime-cdn.com", - "https://hottub.spacemoehre.de/proxy/hanime-cdn", + let thumb = crate::providers::build_proxy_url( + &options, + "hanime-cdn", + &crate::providers::strip_url_scheme(&hit.cover_url), ); let duration = (hit.duration_in_ms / 1000) as u32; // Convert ms to seconds let channel = "hanime".to_string(); // Placeholder, adjust as needed diff --git a/src/providers/hqporner.rs b/src/providers/hqporner.rs index 71891b4..31d1238 100644 --- a/src/providers/hqporner.rs +++ b/src/providers/hqporner.rs @@ -188,7 +188,7 @@ impl HqpornerProvider { .await .map_err(|e| Error::from(format!("Request failed: {}", e)))?; - let video_items = self.get_video_items_from_html(text, &mut requester).await; + let video_items = self.get_video_items_from_html(text, &mut requester, &options).await; if !video_items.is_empty() { cache.insert(video_url, video_items.clone()); } @@ -234,7 +234,7 @@ impl HqpornerProvider { .await .map_err(|e| Error::from(format!("Request failed: {}", e)))?; - let video_items = self.get_video_items_from_html(text, &mut requester).await; + let video_items = self.get_video_items_from_html(text, &mut requester, &options).await; if !video_items.is_empty() { cache.insert(video_url, video_items.clone()); } @@ -245,6 +245,7 @@ impl HqpornerProvider { &self, html: String, requester: &mut Requester, + options: &ServerOptions, ) -> Vec { if html.is_empty() || html.contains("404 Not Found") { return vec![]; @@ -273,7 +274,7 @@ impl HqpornerProvider { let Some(seg) = iter.next() else { break; }; - in_flight.push(self.get_video_item(seg, requester.clone())); + in_flight.push(self.get_video_item(seg, requester.clone(), options)); } let Some(result) = in_flight.next().await else { @@ -312,7 +313,12 @@ impl HqpornerProvider { items } - async fn get_video_item(&self, seg: String, mut requester: Requester) -> Result { + async fn get_video_item( + &self, + seg: String, + mut requester: Requester, + options: &ServerOptions, + ) -> Result { let video_url = format!( "{}{}", self.url, @@ -351,7 +357,7 @@ impl HqpornerProvider { format!("https://{}", thumb_raw.trim_start_matches('/')) }; let thumb = match thumb_abs.strip_prefix("https://") { - Some(path) => format!("https://hottub.spacemoehre.de/proxy/hqporner-thumb/{path}"), + Some(path) => crate::providers::build_proxy_url(options, "hqporner-thumb", path), None => thumb_abs, }; let raw_duration = seg diff --git a/src/providers/javtiful.rs b/src/providers/javtiful.rs index 0451d78..07dbd5e 100644 --- a/src/providers/javtiful.rs +++ b/src/providers/javtiful.rs @@ -155,7 +155,7 @@ impl JavtifulProvider { return Ok(vec![]); } let video_items: Vec = self - .get_video_items_from_html(text.clone(), &mut requester) + .get_video_items_from_html(text.clone(), &mut requester, &options) .await; if !video_items.is_empty() { cache.remove(&video_url); @@ -223,7 +223,7 @@ impl JavtifulProvider { return Ok(vec![]); } let video_items: Vec = self - .get_video_items_from_html(text.clone(), &mut requester) + .get_video_items_from_html(text.clone(), &mut requester, &options) .await; if !video_items.is_empty() { cache.remove(&video_url); @@ -238,6 +238,7 @@ impl JavtifulProvider { &self, html: String, requester: &mut Requester, + options: &ServerOptions, ) -> Vec { if html.is_empty() || html.contains("404 Not Found") { return vec![]; @@ -269,7 +270,7 @@ impl JavtifulProvider { .split("card ") .skip(1) .filter(|seg| !seg.contains("SPONSOR")) - .map(|el| self.get_video_item(el.to_string(), requester.clone())); + .map(|el| self.get_video_item(el.to_string(), requester.clone(), options)); join_all(futures) .await @@ -300,7 +301,12 @@ impl JavtifulProvider { .collect() } - async fn get_video_item(&self, seg: String, mut requester: Requester) -> Result { + async fn get_video_item( + &self, + seg: String, + mut requester: Requester, + options: &ServerOptions, + ) -> Result { let video_url = seg .split(" href=\"") .nth(1) @@ -350,7 +356,7 @@ impl JavtifulProvider { .unwrap_or("") .to_string(); let duration = parse_time_to_seconds(&raw_duration).unwrap_or(0) as u32; - let (tags, formats, views) = self.extract_media(&video_url, &mut requester).await?; + let (tags, formats, views) = self.extract_media(&video_url, &mut requester, options).await?; if preview.len() == 0 { preview = format!("https://trailers.jav.si/preview/{id}.mp4"); @@ -367,6 +373,7 @@ impl JavtifulProvider { &self, url: &str, requester: &mut Requester, + options: &ServerOptions, ) -> Result<(Vec, Vec, u32)> { let text = requester .get(url, Some(Version::HTTP_2)) @@ -413,7 +420,11 @@ impl JavtifulProvider { .unwrap_or(0); let quality = "1080p".to_string(); - let video_url = url.replace("javtiful.com", "hottub.spacemoehre.de/proxy/javtiful"); + let video_url = crate::providers::build_proxy_url( + options, + "javtiful", + &crate::providers::strip_url_scheme(url), + ); Ok(( tags, vec![VideoFormat::new(video_url, quality, "video/mp4".into())], diff --git a/src/providers/mod.rs b/src/providers/mod.rs index 760c3bd..faa8121 100644 --- a/src/providers/mod.rs +++ b/src/providers/mod.rs @@ -286,6 +286,25 @@ pub fn requester_or_default( } } +pub fn strip_url_scheme(url: &str) -> String { + url.strip_prefix("https://") + .or_else(|| url.strip_prefix("http://")) + .unwrap_or(url) + .trim_start_matches('/') + .to_string() +} + +pub fn build_proxy_url(options: &ServerOptions, proxy: &str, target: &str) -> String { + let target = target.trim_start_matches('/'); + let base = options.public_url_base.as_deref().unwrap_or("").trim_end_matches('/'); + + if base.is_empty() { + format!("/proxy/{proxy}/{target}") + } else { + format!("{base}/proxy/{proxy}/{target}") + } +} + #[async_trait] pub trait Provider: Send + Sync { async fn get_videos( diff --git a/src/providers/noodlemagazine.rs b/src/providers/noodlemagazine.rs index 86c2738..26f789b 100644 --- a/src/providers/noodlemagazine.rs +++ b/src/providers/noodlemagazine.rs @@ -80,7 +80,8 @@ impl NoodlemagazineProvider { .await .unwrap_or_default(); - let items = self.get_video_items_from_html(text); + let proxy_base_url = options.public_url_base.as_deref().unwrap_or_default(); + let items = self.get_video_items_from_html(text, proxy_base_url); if items.is_empty() { Ok(old_items) @@ -117,7 +118,8 @@ impl NoodlemagazineProvider { .await .unwrap_or_default(); - let items = self.get_video_items_from_html(text); + let proxy_base_url = options.public_url_base.as_deref().unwrap_or_default(); + let items = self.get_video_items_from_html(text, proxy_base_url); if items.is_empty() { Ok(old_items) @@ -128,7 +130,7 @@ impl NoodlemagazineProvider { } } - fn get_video_items_from_html(&self, html: String) -> Vec { + fn get_video_items_from_html(&self, html: String, proxy_base_url: &str) -> Vec { if html.is_empty() || html.contains("404 Not Found") { return vec![]; } @@ -148,21 +150,29 @@ impl NoodlemagazineProvider { list.split("
") .skip(1) - .filter_map(|segment| self.get_video_item(segment.to_string()).ok()) + .filter_map(|segment| self.get_video_item(segment.to_string(), proxy_base_url).ok()) .collect() } - fn proxy_url(&self, video_url: &str) -> String { + fn proxy_url(&self, proxy_base_url: &str, video_url: &str) -> String { let target = video_url .strip_prefix("https://") .or_else(|| video_url.strip_prefix("http://")) .unwrap_or(video_url) .trim_start_matches('/'); - format!("https://hottub.spacemoehre.de/proxy/noodlemagazine/{target}") + if proxy_base_url.is_empty() { + return format!("/proxy/noodlemagazine/{target}"); + } + + format!( + "{}/proxy/noodlemagazine/{}", + proxy_base_url.trim_end_matches('/'), + target + ) } - fn get_video_item(&self, video_segment: String) -> Result { + fn get_video_item(&self, video_segment: String, proxy_base_url: &str) -> Result { let href = video_segment .split("Show more
"#; - let items = provider.get_video_items_from_html(html.to_string()); + let items = provider.get_video_items_from_html(html.to_string(), "https://example.com"); assert_eq!(items.len(), 1); assert_eq!( items[0].url, - "https://hottub.spacemoehre.de/proxy/noodlemagazine/noodlemagazine.com/watch/-123_456" + "https://example.com/proxy/noodlemagazine/noodlemagazine.com/watch/-123_456" ); assert_eq!(items[0].formats.as_ref().map(|f| f.len()), Some(1)); } diff --git a/src/providers/spankbang.rs b/src/providers/spankbang.rs index aac567b..1d210e8 100644 --- a/src/providers/spankbang.rs +++ b/src/providers/spankbang.rs @@ -172,12 +172,18 @@ impl SpankbangProvider { format!("{}/{}", self.url, url.trim_start_matches("./")) } - fn proxy_url(&self, url: &str) -> String { + fn proxy_url(&self, proxy_base_url: &str, url: &str) -> String { let path = url .strip_prefix(&self.url) .unwrap_or(url) .trim_start_matches('/'); - format!("https://hottub.spacemoehre.de/proxy/spankbang/{path}") + if proxy_base_url.is_empty() { + return format!("/proxy/spankbang/{path}"); + } + format!( + "{}/proxy/spankbang/{path}", + proxy_base_url.trim_end_matches('/') + ) } fn decode_html(text: &str) -> String { @@ -258,6 +264,7 @@ impl SpankbangProvider { views_selector: &Selector, rating_selector: &Selector, meta_link_selector: &Selector, + proxy_base_url: &str, ) -> Option { let card_html = card.html(); let card_text = Self::collapse_whitespace(&card.text().collect::>().join(" ")); @@ -312,7 +319,7 @@ impl SpankbangProvider { let mut item = VideoItem::new( id, title, - self.proxy_url(&href), + self.proxy_url(proxy_base_url, &href), "spankbang".to_string(), thumb, duration, @@ -344,7 +351,7 @@ impl SpankbangProvider { Some(item) } - fn get_video_items_from_html(&self, html: String) -> Vec { + fn get_video_items_from_html(&self, html: String, proxy_base_url: &str) -> Vec { let document = Html::parse_document(&html); let video_list_selector = Selector::parse(r#"[data-testid="video-list"]"#).unwrap(); let card_selector = Selector::parse(r#"[data-testid="video-item"]"#).unwrap(); @@ -378,6 +385,7 @@ impl SpankbangProvider { &views_selector, &rating_selector, &meta_link_selector, + proxy_base_url, ) { items.push(item); } @@ -432,7 +440,8 @@ impl SpankbangProvider { return Ok(old_items); } - let video_items = self.get_video_items_from_html(text); + let proxy_base_url = options.public_url_base.as_deref().unwrap_or_default(); + let video_items = self.get_video_items_from_html(text, proxy_base_url); if !video_items.is_empty() { cache.remove(&video_url); cache.insert(video_url.clone(), video_items.clone()); @@ -489,7 +498,8 @@ impl SpankbangProvider { return Ok(old_items); } - let video_items = self.get_video_items_from_html(text); + let proxy_base_url = options.public_url_base.as_deref().unwrap_or_default(); + let video_items = self.get_video_items_from_html(text, proxy_base_url); if !video_items.is_empty() { cache.remove(&video_url); cache.insert(video_url.clone(), video_items.clone()); @@ -634,13 +644,13 @@ mod tests { "#; - let items = provider.get_video_items_from_html(html.to_string()); + let items = provider.get_video_items_from_html(html.to_string(), "https://example.com"); assert_eq!(items.len(), 1); assert_eq!(items[0].id, "6597754"); assert_eq!(items[0].title, "Adriana's Fleshlight Insertion"); assert_eq!( items[0].url, - "https://hottub.spacemoehre.de/proxy/spankbang/3xeuy/video/adriana+s+fleshlight+insertion" + "https://example.com/proxy/spankbang/3xeuy/video/adriana+s+fleshlight+insertion" ); assert_eq!( items[0].thumb, @@ -691,7 +701,7 @@ mod tests { "#; - let items = provider.get_video_items_from_html(html.to_string()); + let items = provider.get_video_items_from_html(html.to_string(), "https://example.com"); assert_eq!(items.len(), 1); assert_eq!(items[0].id, "2"); assert_eq!(items[0].title, "Free video"); @@ -728,7 +738,7 @@ mod tests { "#; - let items = provider.get_video_items_from_html(html.to_string()); + let items = provider.get_video_items_from_html(html.to_string(), "https://example.com"); assert_eq!(items.len(), 1); assert_eq!(items[0].id, "222"); assert_eq!(items[0].title, "Right result"); diff --git a/src/providers/sxyprn.rs b/src/providers/sxyprn.rs index c8432ff..7cc1b56 100644 --- a/src/providers/sxyprn.rs +++ b/src/providers/sxyprn.rs @@ -162,7 +162,7 @@ impl SxyprnProvider { }; // Pass a reference to options if needed, or reconstruct as needed let video_items = match self - .get_video_items_from_html(text.clone(), pool, requester) + .get_video_items_from_html(text.clone(), pool, requester, &options) .await { Ok(items) => items, @@ -247,7 +247,7 @@ impl SxyprnProvider { }; let video_items = match self - .get_video_items_from_html(text.clone(), pool, requester) + .get_video_items_from_html(text.clone(), pool, requester, &options) .await { Ok(items) => items, @@ -284,6 +284,7 @@ impl SxyprnProvider { html: String, _pool: DbPool, _requester: Requester, + options: &ServerOptions, ) -> Result> { if html.is_empty() { return Ok(vec![]); @@ -313,7 +314,8 @@ impl SxyprnProvider { .ok_or_else(|| ErrorKind::Parse("failed to extract /post/ url".into()))? .to_string(); - let video_url = format!("https://hottub.spacemoehre.de/proxy/sxyprn/post/{}", url); + let video_url = + crate::providers::build_proxy_url(options, "sxyprn", &format!("post/{}", url)); // title parts let title_parts = video_segment @@ -421,7 +423,7 @@ impl SxyprnProvider { .collect::>(); let video_item_url = stream_urls.first().cloned().unwrap_or_else(|| { - format!("https://hottub.spacemoehre.de/proxy/sxyprn/post/{}", id) + crate::providers::build_proxy_url(options, "sxyprn", &format!("post/{}", id)) }); let mut video_item = VideoItem::new( diff --git a/src/videos.rs b/src/videos.rs index f471e81..56b122f 100644 --- a/src/videos.rs +++ b/src/videos.rs @@ -60,6 +60,7 @@ pub struct ServerOptions { pub sites: Option, // pub filter: Option, pub language: Option, // "en" + pub public_url_base: Option, pub requester: Option, pub network: Option, // pub stars: Option, //