freejse searches
This commit is contained in:
@@ -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"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user