From 1f9554916768391597a82797a1ba10800d5eb55e Mon Sep 17 00:00:00 2001 From: Simon Date: Sat, 17 Oct 2026 05:38:47 +0000 Subject: [PATCH] youporn: resolve pornstar/channel/amateur names without prefix --- src/providers/youporn.rs | 41 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/src/providers/youporn.rs b/src/providers/youporn.rs index ceabd65..541ba8b 100644 --- a/src/providers/youporn.rs +++ b/src/providers/youporn.rs @@ -1,8 +1,11 @@ use crate::DbPool; use crate::api::ClientVersion; -use crate::providers::{Provider, report_provider_error, requester_or_default}; +use crate::providers::{ + Provider, probe_first_archive, 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, VideoItem}; @@ -248,6 +251,33 @@ impl YoupornProvider { } } + /// A free-form query that names a pornstar, channel or amateur goes to that + /// archive (probed on the site; unknown names 404), else keyword search. + async fn resolve_keyword( + &self, + requester: &mut Requester, + query: &str, + sort: &str, + ) -> Option { + let slug = slug_dashed(query); + if slug.is_empty() { + return None; + } + let sort = Self::normalized_sort(sort).to_string(); + let candidates = [ + Target::Pornstar { slug: slug.clone(), sort: sort.clone() }, + Target::Channel { slug: slug.clone(), sort: sort.clone() }, + Target::Amateur { slug, sort }, + ]; + let urls: Vec = candidates.iter().map(|t| self.build_url(t, 1)).collect(); + let referer = format!("{}/", self.url.trim_end_matches('/')); + let (index, _) = probe_first_archive(requester, &urls, &referer, |body| { + body.contains("js_video-box") + }) + .await?; + candidates.into_iter().nth(index) + } + fn build_url(&self, target: &Target, page: u8) -> String { match target { Target::Latest { sort } => format!( @@ -543,7 +573,13 @@ impl Provider for YoupornProvider { ) -> Vec { let query = query.unwrap_or_default(); let page = page.parse::().unwrap_or(1); - let target = self.target_from_query(&query, &sort); + let mut requester = requester_or_default(&options, CHANNEL_ID, "get_videos"); + let mut target = self.target_from_query(&query, &sort); + if let Target::Search { query } = &target { + if let Some(found) = self.resolve_keyword(&mut requester, query, &sort).await { + target = found; + } + } let video_url = self.build_url(&target, page); let old_items = match cache.get(&video_url) { @@ -554,7 +590,6 @@ impl Provider for YoupornProvider { None => vec![], }; - let mut requester = requester_or_default(&options, CHANNEL_ID, "get_videos"); let referer = format!("{}/", self.url.trim_end_matches('/')); let text = match requester .get_with_headers(&video_url, Self::html_headers(&referer), Some(Version::HTTP_11))