From 1e56fe2da544c5b37b5ad5c9725dc9b10dc93345 Mon Sep 17 00:00:00 2001 From: Simon Date: Sat, 17 Oct 2026 05:37:07 +0000 Subject: [PATCH] tube8: resolve pornstar/channel names without prefix --- src/providers/tube8.rs | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/providers/tube8.rs b/src/providers/tube8.rs index 909ee89..735bf41 100644 --- a/src/providers/tube8.rs +++ b/src/providers/tube8.rs @@ -1,10 +1,12 @@ use crate::DbPool; use crate::api::ClientVersion; use crate::providers::{ - Provider, build_proxy_url, proxy_aylo_thumb, report_provider_error, requester_or_default, + Provider, build_proxy_url, probe_first_archive, proxy_aylo_thumb, report_provider_error, + requester_or_default, slug_dashed, }; use crate::status::*; use crate::util::cache::VideoCache; +use crate::util::requester::Requester; use crate::util::parse_abbreviated_number; use crate::util::time::parse_time_to_seconds; use crate::videos::{ServerOptions, VideoFormat, VideoItem}; @@ -136,6 +138,25 @@ impl Tube8Provider { ] } + /// A free-form query that names a pornstar or a channel goes to that + /// archive (probed on the site; unknown names 404), else keyword search. + async fn resolve_keyword(&self, requester: &mut Requester, query: &str) -> Option { + let slug = slug_dashed(query); + if slug.is_empty() { + return None; + } + let candidates = [ + Target::Pornstar { slug: slug.clone() }, + Target::Channel { slug }, + ]; + let urls: Vec = candidates.iter().map(|t| self.build_url(t, 1)).collect(); + let (index, _) = probe_first_archive(requester, &urls, &format!("{BASE_URL}/"), |body| { + body.contains("video-box") + }) + .await?; + candidates.into_iter().nth(index) + } + fn target_from_request(query: Option<&str>, sort: &str) -> Target { if let Some(q) = query.map(str::trim).filter(|v| !v.is_empty()) { let lower = q.to_ascii_lowercase(); @@ -439,7 +460,13 @@ impl Provider for Tube8Provider { options: ServerOptions, ) -> Vec { let page = page.parse::().unwrap_or(1).max(1); - let target = Self::target_from_request(query.as_deref(), &sort); + let mut requester = requester_or_default(&options, CHANNEL_ID, "get_videos"); + let mut target = Self::target_from_request(query.as_deref(), &sort); + if let Target::Search { query } = &target { + if let Some(found) = self.resolve_keyword(&mut requester, query).await { + target = found; + } + } let url = self.build_url(&target, page); let old_items = match cache.get(&url) { @@ -450,7 +477,6 @@ impl Provider for Tube8Provider { None => vec![], }; - let mut requester = requester_or_default(&options, CHANNEL_ID, "get_videos"); let text = match requester .get_with_headers(&url, Self::html_headers(), None) .await