freejse searches

This commit is contained in:
Simon
2026-03-31 23:01:51 +00:00
parent 38acb2b5a5
commit e2796bfd71
2 changed files with 79 additions and 26 deletions

View File

@@ -9,10 +9,10 @@ use crate::videos::{ServerOptions, VideoFormat, VideoItem};
use async_trait::async_trait;
use error_chain::error_chain;
use htmlentity::entity::{ICodedDataTrait, decode};
use percent_encoding::{NON_ALPHANUMERIC, utf8_percent_encode};
use scraper::{Html, Selector};
use std::collections::HashSet;
use std::vec;
use url::form_urlencoded::Serializer;
pub const CHANNEL_METADATA: crate::providers::ProviderChannelMetadata =
crate::providers::ProviderChannelMetadata {
@@ -151,19 +151,22 @@ impl FreeusepornProvider {
}
}
fn build_list_url(
&self,
sort: &str,
page: u8,
query: Option<&str>,
category: Option<&str>,
) -> String {
let path = if let Some(query) = query.map(str::trim).filter(|value| !value.is_empty()) {
format!(
"/search/videos/{}",
utf8_percent_encode(query, NON_ALPHANUMERIC)
)
} else if let Some(category) = category
fn append_sort_and_page(&self, base_url: &str, sort: &str, page: u8) -> String {
let mut params = vec![format!("o={}", Self::sort_param(sort))];
if page > 1 {
params.push(format!("page={page}"));
}
if params.is_empty() {
return base_url.to_string();
}
let separator = if base_url.contains('?') { "&" } else { "?" };
format!("{base_url}{separator}{}", params.join("&"))
}
fn build_list_url(&self, sort: &str, page: u8, category: Option<&str>) -> String {
let path = if let Some(category) = category
.map(str::trim)
.filter(|value| !value.is_empty() && *value != "all")
{
@@ -172,12 +175,34 @@ impl FreeusepornProvider {
"/videos".to_string()
};
let mut params = vec![format!("o={}", Self::sort_param(sort))];
if page > 1 {
params.push(format!("page={page}"));
}
let base_url = format!("{}{}", self.url, path);
self.append_sort_and_page(&base_url, sort, page)
}
format!("{}{}?{}", self.url, path, params.join("&"))
fn build_search_request_body(query: &str) -> String {
let mut serializer = Serializer::new(String::new());
serializer.append_pair("search_query", query);
serializer.finish()
}
async fn resolve_search_url(&self, query: &str, options: &ServerOptions) -> Result<String> {
let search_url = format!("{}/search/videos", self.url);
let search_body = Self::build_search_request_body(query);
let referer = format!("{}/videos", self.url);
let mut requester = requester_or_default(options, module_path!(), "missing_requester");
let response = requester
.post(
&search_url,
&search_body,
vec![
("Content-Type", "application/x-www-form-urlencoded"),
("Referer", referer.as_str()),
],
)
.await
.map_err(|error| format!("search submit failed url={search_url}; error={error}"))?;
Ok(response.uri().to_string().trim_end_matches('/').to_string())
}
fn build_formats(&self, id: &str) -> Vec<VideoFormat> {
@@ -380,7 +405,7 @@ impl FreeusepornProvider {
sort: &str,
options: ServerOptions,
) -> Result<Vec<VideoItem>> {
let url = self.build_list_url(sort, page, None, options.category.as_deref());
let url = self.build_list_url(sort, page, options.category.as_deref());
self.fetch_listing(cache, url, options, "get.request").await
}
@@ -392,7 +417,19 @@ impl FreeusepornProvider {
sort: &str,
options: ServerOptions,
) -> Result<Vec<VideoItem>> {
let url = self.build_list_url(sort, page, Some(query), None);
let search_base = match self.resolve_search_url(query, &options).await {
Ok(url) => url,
Err(error) => {
report_provider_error(
"freeuseporn",
"query.search_submit",
&error.to_string(),
)
.await;
return Ok(vec![]);
}
};
let url = self.append_sort_and_page(&search_base, sort, page);
self.fetch_listing(cache, url, options, "query.request").await
}
}
@@ -464,16 +501,28 @@ mod tests {
let provider = provider();
assert_eq!(
provider.build_list_url("recent", 1, None, None),
provider.build_list_url("recent", 1, None),
"https://www.freeuseporn.com/videos?o=mr"
);
assert_eq!(
provider.build_list_url("viewed", 2, None, Some("mind-control")),
provider.build_list_url("viewed", 2, Some("mind-control")),
"https://www.freeuseporn.com/videos/mind-control?o=mv&page=2"
);
assert_eq!(
provider.build_list_url("favorites", 3, Some("mind control"), None),
"https://www.freeuseporn.com/search/videos/mind%20control?o=tf&page=3"
provider.append_sort_and_page(
"https://www.freeuseporn.com/search/videos/Nicole-Kitt",
"favorites",
3
),
"https://www.freeuseporn.com/search/videos/Nicole-Kitt?o=tf&page=3"
);
}
#[test]
fn builds_search_request_body_with_form_encoding() {
assert_eq!(
FreeusepornProvider::build_search_request_body("Nicole Kitt & Cory Chase"),
"search_query=Nicole+Kitt+%26+Cory+Chase"
);
}

View File

@@ -375,7 +375,11 @@ impl Requester {
Ok(response)
}
#[cfg(any(not(hottub_single_provider), hottub_provider = "hypnotube"))]
#[cfg(any(
not(hottub_single_provider),
hottub_provider = "hypnotube",
hottub_provider = "freeuseporn",
))]
pub async fn post(
&mut self,
url: &str,