diff --git a/src/providers/clapdat.rs b/src/providers/clapdat.rs index c696fa1..87f166e 100644 --- a/src/providers/clapdat.rs +++ b/src/providers/clapdat.rs @@ -1,7 +1,8 @@ use crate::DbPool; use crate::api::ClientVersion; use crate::providers::{ - Provider, build_proxy_url, report_provider_error, requester_or_default, strip_url_scheme, + Provider, build_proxy_url, probe_first_archive, report_provider_error, requester_or_default, + slug_dashed, strip_url_scheme, }; use crate::status::*; use crate::util::time::parse_time_to_seconds; @@ -149,6 +150,29 @@ impl ClapdatProvider { } } + /// A free-form query that names a tag or a user goes to that archive + /// (probed on the site; unknown names 404), else keyword search. + async fn resolve_keyword(&self, query: &str, options: &ServerOptions) -> Option { + let slug = slug_dashed(query); + if slug.is_empty() { + return None; + } + let candidates = [ + Target::Tag { slug: slug.clone() }, + Target::User { username: slug }, + ]; + let urls: Vec = candidates + .iter() + .filter_map(|t| self.listing_url(t, 1)) + .collect(); + let mut requester = requester_or_default(options, CHANNEL_ID, "resolve_keyword"); + let (index, _) = probe_first_archive(&mut requester, &urls, &format!("{}/", self.url), |body| { + body.contains("/video/") + }) + .await?; + candidates.into_iter().nth(index) + } + fn listing_url(&self, target: &Target, page: u16) -> Option { let page = page.max(1); match target { @@ -491,7 +515,12 @@ impl Provider for ClapdatProvider { sort }; let query_value = query.unwrap_or_default(); - let target = self.resolve_target(&query_value, &sort_value); + let mut target = self.resolve_target(&query_value, &sort_value); + if let Target::Search { query } = &target { + if let Some(found) = self.resolve_keyword(query, &options).await { + target = found; + } + } let stubs = match &target { Target::Search { query } => match self