xhamster: resolve pornstar/channel names without prefix

This commit is contained in:
Simon
2026-10-17 05:50:41 +00:00
parent 76b9d4e058
commit 981ec29ad8

View File

@@ -1,6 +1,8 @@
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::parse_abbreviated_number;
@@ -94,6 +96,7 @@ enum Target {
Search(String),
Category(String),
Channel(String),
Pornstar(String),
}
#[derive(Debug, Clone)]
@@ -208,6 +211,7 @@ impl XhamsterProvider {
}
Target::Category(slug) => format!("{BASE_URL}/categories/{slug}"),
Target::Channel(slug) => format!("{BASE_URL}/channels/{slug}"),
Target::Pornstar(slug) => format!("{BASE_URL}/pornstars/{slug}"),
};
if page <= 1 {
base
@@ -385,6 +389,7 @@ impl XhamsterProvider {
match kind.trim().to_ascii_lowercase().as_str() {
"cat" | "category" => return Target::Category(slug),
"channel" | "channels" => return Target::Channel(slug),
"pornstar" | "pornstars" | "star" | "model" => return Target::Pornstar(slug),
_ => {}
}
}
@@ -401,6 +406,23 @@ impl XhamsterProvider {
Target::Search(trimmed.to_string())
}
/// 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(query: &str, options: &ServerOptions) -> Option<Target> {
let slug = slug_dashed(query);
if slug.is_empty() {
return None;
}
let candidates = [Target::Pornstar(slug.clone()), Target::Channel(slug)];
let urls: Vec<String> = candidates.iter().map(|t| Self::target_url(t, 1)).collect();
let mut requester = requester_or_default(options, CHANNEL_ID, "resolve_keyword");
let (index, _) = probe_first_archive(&mut requester, &urls, &format!("{BASE_URL}/"), |body| {
body.contains("video-thumb-info__name")
})
.await?;
candidates.into_iter().nth(index)
}
fn resolve_sort_target(sort: &str) -> Target {
match sort.trim().to_ascii_lowercase().as_str() {
"popular" | "viewed" | "most_viewed" | "mostviewed" => Target::MostViewed,
@@ -472,10 +494,15 @@ impl Provider for XhamsterProvider {
let page = page.parse::<u16>().unwrap_or(1).max(1);
let per_page = per_page.parse::<usize>().unwrap_or(10).clamp(1, 60);
let target = match query {
let mut target = match query {
Some(q) if !q.trim().is_empty() => self.resolve_query_target(q.trim()),
_ => self.resolve_option_target(&options, &sort),
};
if let Target::Search(query) = &target {
if let Some(found) = Self::resolve_keyword(query, &options).await {
target = found;
}
}
match self
.fetch_target(cache, target, page, per_page, options)