pimpbunny fix
This commit is contained in:
@@ -28,7 +28,6 @@ error_chain! {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[allow(dead_code)]
|
||||
pub struct AllProvider {}
|
||||
|
||||
impl AllProvider {
|
||||
|
||||
@@ -37,7 +37,6 @@ struct HanimeSearchRequest {
|
||||
page: u8,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl HanimeSearchRequest {
|
||||
pub fn new() -> Self {
|
||||
HanimeSearchRequest {
|
||||
@@ -51,26 +50,10 @@ impl HanimeSearchRequest {
|
||||
page: 0,
|
||||
}
|
||||
}
|
||||
pub fn tags(mut self, tags: Vec<String>) -> Self {
|
||||
self.tags = tags;
|
||||
self
|
||||
}
|
||||
pub fn search_text(mut self, search_text: String) -> Self {
|
||||
self.search_text = search_text;
|
||||
self
|
||||
}
|
||||
pub fn tags_mode(mut self, tags_mode: String) -> Self {
|
||||
self.tags_mode = tags_mode;
|
||||
self
|
||||
}
|
||||
pub fn brands(mut self, brands: Vec<String>) -> Self {
|
||||
self.brands = brands;
|
||||
self
|
||||
}
|
||||
pub fn blacklist(mut self, blacklist: Vec<String>) -> Self {
|
||||
self.blacklist = blacklist;
|
||||
self
|
||||
}
|
||||
pub fn order_by(mut self, order_by: String) -> Self {
|
||||
self.order_by = order_by;
|
||||
self
|
||||
@@ -120,16 +103,11 @@ struct HanimeSearchResult {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[allow(dead_code)]
|
||||
pub struct HanimeProvider {
|
||||
url: String,
|
||||
}
|
||||
pub struct HanimeProvider;
|
||||
|
||||
impl HanimeProvider {
|
||||
pub fn new() -> Self {
|
||||
HanimeProvider {
|
||||
url: "https://hanime.tv/".to_string(),
|
||||
}
|
||||
HanimeProvider
|
||||
}
|
||||
|
||||
fn build_channel(&self, _clientversion: ClientVersion) -> Channel {
|
||||
|
||||
@@ -230,6 +230,10 @@ fn channel_group_order(group_id: &str) -> usize {
|
||||
|
||||
pub fn decorate_channel(channel: Channel) -> ChannelView {
|
||||
let metadata = channel_metadata_for(&channel.id);
|
||||
let ytdlp_command = match channel.id.as_str() {
|
||||
"pimpbunny" => Some("yt-dlp --compat-options allow-unsafe-ext".to_string()),
|
||||
_ => None,
|
||||
};
|
||||
ChannelView {
|
||||
id: channel.id,
|
||||
name: channel.name,
|
||||
@@ -250,6 +254,7 @@ pub fn decorate_channel(channel: Channel) -> ChannelView {
|
||||
.map(|tag| (*tag).to_string())
|
||||
.collect()
|
||||
}),
|
||||
ytdlpCommand: ytdlp_command,
|
||||
cacheDuration: channel.cacheDuration,
|
||||
}
|
||||
}
|
||||
@@ -413,6 +418,7 @@ mod tests {
|
||||
let channel = decorate_channel(base_channel("hsex"));
|
||||
assert_eq!(channel.groupKey.as_deref(), Some("chinese"));
|
||||
assert_eq!(channel.sortOrder, None);
|
||||
assert_eq!(channel.ytdlpCommand, None);
|
||||
assert_eq!(
|
||||
channel.tags.as_deref(),
|
||||
Some(
|
||||
@@ -438,6 +444,15 @@ mod tests {
|
||||
assert_eq!(groups[2].id, "jav");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decorates_pimpbunny_with_ytdlp_command() {
|
||||
let channel = decorate_channel(base_channel("pimpbunny"));
|
||||
assert_eq!(
|
||||
channel.ytdlpCommand.as_deref(),
|
||||
Some("yt-dlp --compat-options allow-unsafe-ext")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reflects_updated_group_moves() {
|
||||
assert_eq!(
|
||||
@@ -461,6 +476,7 @@ mod tests {
|
||||
base_channel("missav"),
|
||||
base_channel("hsex"),
|
||||
base_channel("all"),
|
||||
base_channel("pimpbunny"),
|
||||
];
|
||||
|
||||
let json = serde_json::to_value(build_status_response(status)).expect("valid status json");
|
||||
@@ -487,5 +503,14 @@ mod tests {
|
||||
.find(|group| group["id"] == "chinese")
|
||||
.expect("chinese group present");
|
||||
assert_eq!(chinese_group["systemImage"], "globe");
|
||||
|
||||
let pimpbunny_channel = channels
|
||||
.iter()
|
||||
.find(|channel| channel["id"] == "pimpbunny")
|
||||
.expect("pimpbunny channel present");
|
||||
assert_eq!(
|
||||
pimpbunny_channel["ytdlpCommand"],
|
||||
"yt-dlp --compat-options allow-unsafe-ext"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,8 +49,7 @@ impl PimpbunnyProvider {
|
||||
const FIREFOX_USER_AGENT: &'static str =
|
||||
"Mozilla/5.0 (X11; Linux x86_64; rv:147.0) Gecko/20100101 Firefox/147.0";
|
||||
const HTML_ACCEPT: &'static str =
|
||||
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8";
|
||||
|
||||
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
|
||||
pub fn new() -> Self {
|
||||
let provider = Self {
|
||||
url: "https://pimpbunny.com".to_string(),
|
||||
@@ -235,39 +234,218 @@ impl PimpbunnyProvider {
|
||||
format!("{}/", self.url.trim_end_matches('/'))
|
||||
}
|
||||
|
||||
fn root_headers(&self) -> Vec<(String, String)> {
|
||||
Self::html_headers_with_referer(&self.root_referer())
|
||||
fn sort_by(sort: &str) -> &'static str {
|
||||
match sort {
|
||||
"best rated" => "rating",
|
||||
"most viewed" => "video_viewed",
|
||||
_ => "post_date",
|
||||
}
|
||||
}
|
||||
|
||||
fn html_headers_with_referer(referer: &str) -> Vec<(String, String)> {
|
||||
vec![
|
||||
("Referer".to_string(), referer.to_string()),
|
||||
fn build_search_path_query(query: &str, separator: &str) -> String {
|
||||
query.split_whitespace().collect::<Vec<_>>().join(separator)
|
||||
}
|
||||
|
||||
fn append_archive_query(url: String, sort: &str) -> String {
|
||||
let separator = if url.contains('?') { '&' } else { '?' };
|
||||
format!("{url}{separator}sort_by={}", Self::sort_by(sort))
|
||||
}
|
||||
|
||||
fn page_family_referer(&self, request_url: &str) -> String {
|
||||
let Some(url) = Url::parse(request_url).ok() else {
|
||||
return self.root_referer();
|
||||
};
|
||||
|
||||
let path = url.path();
|
||||
let referer_path = if path.starts_with("/videos/") {
|
||||
"/videos/".to_string()
|
||||
} else if path.starts_with("/search/") {
|
||||
let parts: Vec<_> = path.trim_matches('/').split('/').collect();
|
||||
if parts.len() >= 2 {
|
||||
format!("/search/{}/", parts[1])
|
||||
} else {
|
||||
"/search/".to_string()
|
||||
}
|
||||
} else if path.starts_with("/categories/") {
|
||||
let parts: Vec<_> = path.trim_matches('/').split('/').collect();
|
||||
if parts.len() >= 2 {
|
||||
format!("/categories/{}/", parts[1])
|
||||
} else {
|
||||
"/categories/".to_string()
|
||||
}
|
||||
} else if path.starts_with("/onlyfans-models/") {
|
||||
let parts: Vec<_> = path.trim_matches('/').split('/').collect();
|
||||
if parts.len() >= 2 {
|
||||
format!("/onlyfans-models/{}/", parts[1])
|
||||
} else {
|
||||
"/onlyfans-models/".to_string()
|
||||
}
|
||||
} else {
|
||||
"/".to_string()
|
||||
};
|
||||
|
||||
format!("{}{}", self.url.trim_end_matches('/'), referer_path)
|
||||
}
|
||||
|
||||
fn build_browse_url(&self, page: u8, sort: &str) -> String {
|
||||
let base = if page <= 1 {
|
||||
format!("{}/videos/", self.url)
|
||||
} else {
|
||||
format!("{}/videos/{page}/", self.url)
|
||||
};
|
||||
Self::append_archive_query(base, sort)
|
||||
}
|
||||
|
||||
fn build_search_url(&self, query: &str, page: u8, sort: &str) -> String {
|
||||
let path_query = Self::build_search_path_query(query, "-");
|
||||
let base = if page <= 1 {
|
||||
format!("{}/search/{path_query}/", self.url)
|
||||
} else {
|
||||
format!("{}/search/{path_query}/{page}/", self.url)
|
||||
};
|
||||
Self::append_archive_query(base, sort)
|
||||
}
|
||||
|
||||
fn build_common_archive_url(&self, archive_path: &str, page: u8, sort: &str) -> String {
|
||||
let canonical = format!(
|
||||
"{}/{}",
|
||||
self.url.trim_end_matches('/'),
|
||||
archive_path.trim_start_matches('/')
|
||||
);
|
||||
let base = if page <= 1 {
|
||||
canonical
|
||||
} else {
|
||||
format!("{}/{}", canonical.trim_end_matches('/'), page)
|
||||
};
|
||||
let base = if base.ends_with('/') {
|
||||
base
|
||||
} else {
|
||||
format!("{base}/")
|
||||
};
|
||||
Self::append_archive_query(base, sort)
|
||||
}
|
||||
|
||||
fn navigation_headers(
|
||||
referer: Option<&str>,
|
||||
sec_fetch_site: &'static str,
|
||||
) -> Vec<(String, String)> {
|
||||
let mut headers = vec![
|
||||
(
|
||||
"User-Agent".to_string(),
|
||||
Self::FIREFOX_USER_AGENT.to_string(),
|
||||
),
|
||||
("Accept".to_string(), Self::HTML_ACCEPT.to_string()),
|
||||
("Accept-Language".to_string(), "en-US,en;q=0.9".to_string()),
|
||||
]
|
||||
("Cache-Control".to_string(), "no-cache".to_string()),
|
||||
("Pragma".to_string(), "no-cache".to_string()),
|
||||
("Priority".to_string(), "u=0, i".to_string()),
|
||||
("Connection".to_string(), "keep-alive".to_string()),
|
||||
("TE".to_string(), "trailers".to_string()),
|
||||
("Sec-Fetch-Dest".to_string(), "document".to_string()),
|
||||
("Sec-Fetch-Mode".to_string(), "navigate".to_string()),
|
||||
("Sec-Fetch-Site".to_string(), sec_fetch_site.to_string()),
|
||||
("Sec-Fetch-User".to_string(), "?1".to_string()),
|
||||
("Upgrade-Insecure-Requests".to_string(), "1".to_string()),
|
||||
];
|
||||
if let Some(referer) = referer {
|
||||
headers.push(("Referer".to_string(), referer.to_string()));
|
||||
}
|
||||
headers
|
||||
}
|
||||
|
||||
fn headers_with_cookies(
|
||||
&self,
|
||||
requester: &Requester,
|
||||
request_url: &str,
|
||||
referer: &str,
|
||||
referer: Option<&str>,
|
||||
sec_fetch_site: &'static str,
|
||||
) -> Vec<(String, String)> {
|
||||
let mut headers = Self::html_headers_with_referer(referer);
|
||||
let mut headers = Self::navigation_headers(referer, sec_fetch_site);
|
||||
if let Some(cookie) = requester.cookie_header_for_url(request_url) {
|
||||
headers.push(("Cookie".to_string(), cookie));
|
||||
}
|
||||
headers
|
||||
}
|
||||
|
||||
fn is_cloudflare_challenge(html: &str) -> bool {
|
||||
html.contains("cf-turnstile-response")
|
||||
|| html.contains("Performing security verification")
|
||||
|| html.contains("__cf_chl_rt_tk")
|
||||
|| html.contains("cUPMDTk:\"")
|
||||
|| html.contains("Just a moment...")
|
||||
}
|
||||
|
||||
fn extract_challenge_path(html: &str) -> Option<String> {
|
||||
html.split("cUPMDTk:\"")
|
||||
.nth(1)
|
||||
.and_then(|s| s.split('"').next())
|
||||
.map(str::to_string)
|
||||
.or_else(|| {
|
||||
html.split("__cf_chl_rt_tk=")
|
||||
.nth(1)
|
||||
.and_then(|s| s.split('"').next())
|
||||
.map(|token| format!("/?__cf_chl_rt_tk={token}"))
|
||||
})
|
||||
}
|
||||
|
||||
fn absolute_site_url(&self, path_or_url: &str) -> String {
|
||||
if path_or_url.starts_with("http://") || path_or_url.starts_with("https://") {
|
||||
path_or_url.to_string()
|
||||
} else {
|
||||
format!(
|
||||
"{}/{}",
|
||||
self.url.trim_end_matches('/'),
|
||||
path_or_url.trim_start_matches('/')
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async fn fetch_html(
|
||||
&self,
|
||||
requester: &mut Requester,
|
||||
request_url: &str,
|
||||
referer: Option<&str>,
|
||||
sec_fetch_site: &'static str,
|
||||
) -> Result<String> {
|
||||
let headers = self.headers_with_cookies(requester, request_url, referer, sec_fetch_site);
|
||||
let response = requester
|
||||
.get_raw_with_headers(request_url, headers.clone())
|
||||
.await
|
||||
.map_err(Error::from)?;
|
||||
let status = response.status();
|
||||
let body = response.text().await.map_err(Error::from)?;
|
||||
|
||||
if status.is_success() || status.as_u16() == 404 {
|
||||
return Ok(body);
|
||||
}
|
||||
|
||||
if status.as_u16() == 403 && Self::is_cloudflare_challenge(&body) {
|
||||
if let Some(challenge_path) = Self::extract_challenge_path(&body) {
|
||||
let challenge_url = self.absolute_site_url(&challenge_path);
|
||||
let challenge_headers = self.headers_with_cookies(
|
||||
requester,
|
||||
&challenge_url,
|
||||
Some(request_url),
|
||||
"same-origin",
|
||||
);
|
||||
let _ = requester
|
||||
.get_raw_with_headers(&challenge_url, challenge_headers)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
let retry_headers =
|
||||
self.headers_with_cookies(requester, request_url, referer, sec_fetch_site);
|
||||
requester
|
||||
.get_with_headers(request_url, retry_headers, Some(Version::HTTP_11))
|
||||
.await
|
||||
.map_err(|e| Error::from(format!("{e}")))
|
||||
}
|
||||
|
||||
async fn warm_root_session(&self, requester: &mut Requester) {
|
||||
let root_url = self.root_referer();
|
||||
let _ = requester
|
||||
.get_with_headers(&root_url, self.root_headers(), Some(Version::HTTP_11))
|
||||
let _ = self
|
||||
.fetch_html(requester, &root_url, None, "none")
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -276,7 +454,7 @@ impl PimpbunnyProvider {
|
||||
let _ = requester
|
||||
.get_with_headers(
|
||||
&root_url,
|
||||
Self::html_headers_with_referer(&root_url),
|
||||
Self::navigation_headers(None, "none"),
|
||||
Some(Version::HTTP_11),
|
||||
)
|
||||
.await;
|
||||
@@ -288,7 +466,7 @@ impl PimpbunnyProvider {
|
||||
let request_url = format!("{base}/onlyfans-models/?models_per_page=20");
|
||||
let headers = {
|
||||
let root_url = format!("{}/", base.trim_end_matches('/'));
|
||||
let mut headers = Self::html_headers_with_referer(&root_url);
|
||||
let mut headers = Self::navigation_headers(Some(&root_url), "same-origin");
|
||||
if let Some(cookie) = requester.cookie_header_for_url(&request_url) {
|
||||
headers.push(("Cookie".to_string(), cookie));
|
||||
}
|
||||
@@ -343,7 +521,7 @@ impl PimpbunnyProvider {
|
||||
let request_url = format!("{base}/categories/?items_per_page=120");
|
||||
let headers = {
|
||||
let root_url = format!("{}/", base.trim_end_matches('/'));
|
||||
let mut headers = Self::html_headers_with_referer(&root_url);
|
||||
let mut headers = Self::navigation_headers(Some(&root_url), "same-origin");
|
||||
if let Some(cookie) = requester.cookie_header_for_url(&request_url) {
|
||||
headers.push(("Cookie".to_string(), cookie));
|
||||
}
|
||||
@@ -393,15 +571,7 @@ impl PimpbunnyProvider {
|
||||
sort: &str,
|
||||
options: ServerOptions,
|
||||
) -> Result<Vec<VideoItem>> {
|
||||
let sort_string = match sort {
|
||||
"best rated" => "&sort_by=rating",
|
||||
"most viewed" => "&sort_by=video_viewed",
|
||||
_ => "&sort_by=post_date",
|
||||
};
|
||||
let video_url = format!(
|
||||
"{}/videos/{}/?videos_per_page=32{}",
|
||||
self.url, page, sort_string
|
||||
);
|
||||
let video_url = self.build_browse_url(page, sort);
|
||||
let old_items = match cache.get(&video_url) {
|
||||
Some((time, items)) => {
|
||||
if time.elapsed().unwrap_or_default().as_secs() < 60 * 5 {
|
||||
@@ -417,9 +587,14 @@ impl PimpbunnyProvider {
|
||||
let mut requester =
|
||||
crate::providers::requester_or_default(&options, module_path!(), "missing_requester");
|
||||
self.warm_root_session(&mut requester).await;
|
||||
let headers = self.headers_with_cookies(&requester, &video_url, &self.root_referer());
|
||||
let text = match requester
|
||||
.get_with_headers(&video_url, headers, Some(Version::HTTP_11))
|
||||
let referer = self.page_family_referer(&video_url);
|
||||
let text = match self
|
||||
.fetch_html(
|
||||
&mut requester,
|
||||
&video_url,
|
||||
Some(&referer),
|
||||
"same-origin",
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(text) => text,
|
||||
@@ -451,27 +626,17 @@ impl PimpbunnyProvider {
|
||||
options: ServerOptions,
|
||||
) -> Result<Vec<VideoItem>> {
|
||||
let search_string = query.trim().to_string();
|
||||
|
||||
let mut video_url = format!(
|
||||
"{}/search/{}/?mode=async&function=get_block&block_id=list_videos_videos_list_search_result&videos_per_page=32&from_videos={}",
|
||||
self.url,
|
||||
search_string.replace(" ", "-"),
|
||||
page
|
||||
);
|
||||
|
||||
let sort_string = match options.sort.as_deref().unwrap_or("") {
|
||||
"best rated" => "&sort_by=rating",
|
||||
"most viewed" => "&sort_by=video_viewed",
|
||||
_ => "&sort_by=post_date",
|
||||
};
|
||||
let sort = options.sort.as_deref().unwrap_or("");
|
||||
let mut video_url = self.build_search_url(&search_string, page, sort);
|
||||
if let Ok(stars) = self.stars.read() {
|
||||
if let Some(star) = stars
|
||||
.iter()
|
||||
.find(|s| s.title.to_ascii_lowercase() == search_string.to_ascii_lowercase())
|
||||
{
|
||||
video_url = format!(
|
||||
"{}/onlyfans-models/{}/{}/?videos_per_page=20{}",
|
||||
self.url, star.id, page, sort_string
|
||||
video_url = self.build_common_archive_url(
|
||||
&format!("/onlyfans-models/{}/", star.id),
|
||||
page,
|
||||
sort,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
@@ -486,10 +651,8 @@ impl PimpbunnyProvider {
|
||||
.iter()
|
||||
.find(|c| c.title.to_ascii_lowercase() == search_string.to_ascii_lowercase())
|
||||
{
|
||||
video_url = format!(
|
||||
"{}/categories/{}/{}/?videos_per_page=20{}",
|
||||
self.url, cat.id, page, sort_string
|
||||
);
|
||||
video_url =
|
||||
self.build_common_archive_url(&format!("/categories/{}/", cat.id), page, sort);
|
||||
}
|
||||
} else {
|
||||
crate::providers::report_provider_error_background(
|
||||
@@ -516,10 +679,14 @@ impl PimpbunnyProvider {
|
||||
let mut requester =
|
||||
crate::providers::requester_or_default(&options, module_path!(), "missing_requester");
|
||||
self.warm_root_session(&mut requester).await;
|
||||
println!("Fetching URL: {}", video_url);
|
||||
let headers = self.headers_with_cookies(&requester, &video_url, &self.root_referer());
|
||||
let text = match requester
|
||||
.get_with_headers(&video_url, headers, Some(Version::HTTP_2))
|
||||
let referer = self.page_family_referer(&video_url);
|
||||
let text = match self
|
||||
.fetch_html(
|
||||
&mut requester,
|
||||
&video_url,
|
||||
Some(&referer),
|
||||
"same-origin",
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(text) => text,
|
||||
@@ -710,9 +877,17 @@ mod tests {
|
||||
use crate::videos::ServerOptions;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
fn test_provider() -> PimpbunnyProvider {
|
||||
PimpbunnyProvider {
|
||||
url: "https://pimpbunny.com".to_string(),
|
||||
stars: Arc::new(RwLock::new(vec![])),
|
||||
categories: Arc::new(RwLock::new(vec![])),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rewrites_allowed_thumbs_to_proxy_urls() {
|
||||
let provider = PimpbunnyProvider::new();
|
||||
let provider = test_provider();
|
||||
let options = ServerOptions {
|
||||
featured: None,
|
||||
category: None,
|
||||
@@ -742,7 +917,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn rewrites_video_pages_to_redirect_proxy() {
|
||||
let provider = PimpbunnyProvider::new();
|
||||
let provider = test_provider();
|
||||
let options = ServerOptions {
|
||||
featured: None,
|
||||
category: None,
|
||||
@@ -772,11 +947,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn parses_listing_without_detail_requests() {
|
||||
let provider = PimpbunnyProvider {
|
||||
url: "https://pimpbunny.com".to_string(),
|
||||
stars: Arc::new(RwLock::new(vec![])),
|
||||
categories: Arc::new(RwLock::new(vec![])),
|
||||
};
|
||||
let provider = test_provider();
|
||||
let options = ServerOptions {
|
||||
featured: None,
|
||||
category: None,
|
||||
@@ -820,4 +991,91 @@ mod tests {
|
||||
assert_eq!(items[0].views, Some(1200));
|
||||
assert_eq!(items[0].formats.as_ref().map(|f| f.len()), Some(1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extracts_cloudflare_challenge_path() {
|
||||
let html = r#"
|
||||
<script type="text/javascript">
|
||||
(function(){
|
||||
window._cf_chl_opt = {
|
||||
cUPMDTk:"/?mode=async&function=get_block&block_id=videos_videos_list&videos_per_page=8&sort_by=post_date&from=1&__cf_chl_tk=test-token"
|
||||
};
|
||||
}());
|
||||
</script>
|
||||
"#;
|
||||
|
||||
assert!(PimpbunnyProvider::is_cloudflare_challenge(html));
|
||||
assert_eq!(
|
||||
PimpbunnyProvider::extract_challenge_path(html).as_deref(),
|
||||
Some(
|
||||
"/?mode=async&function=get_block&block_id=videos_videos_list&videos_per_page=8&sort_by=post_date&from=1&__cf_chl_tk=test-token"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn builds_async_browse_url_instead_of_numbered_videos_path() {
|
||||
let provider = test_provider();
|
||||
assert_eq!(
|
||||
provider.build_browse_url(1, "most recent"),
|
||||
"https://pimpbunny.com/videos/?sort_by=post_date"
|
||||
);
|
||||
assert_eq!(
|
||||
provider.build_browse_url(2, "most recent"),
|
||||
"https://pimpbunny.com/videos/2/?sort_by=post_date"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn builds_search_url_with_query_and_pagination() {
|
||||
let provider = test_provider();
|
||||
assert_eq!(
|
||||
provider.build_search_url("adriana chechik", 1, "most viewed"),
|
||||
"https://pimpbunny.com/search/adriana-chechik/?sort_by=video_viewed"
|
||||
);
|
||||
assert_eq!(
|
||||
provider.build_search_url("adriana chechik", 3, "most viewed"),
|
||||
"https://pimpbunny.com/search/adriana-chechik/3/?sort_by=video_viewed"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn builds_common_archive_url_with_async_block() {
|
||||
let provider = test_provider();
|
||||
assert_eq!(
|
||||
provider.build_common_archive_url("/categories/amateur/", 1, "best rated"),
|
||||
"https://pimpbunny.com/categories/amateur/?sort_by=rating"
|
||||
);
|
||||
assert_eq!(
|
||||
provider.build_common_archive_url("/categories/amateur/", 4, "best rated"),
|
||||
"https://pimpbunny.com/categories/amateur/4/?sort_by=rating"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn derives_page_family_referer() {
|
||||
let provider = test_provider();
|
||||
assert_eq!(
|
||||
provider.page_family_referer("https://pimpbunny.com/videos/2/?sort_by=post_date"),
|
||||
"https://pimpbunny.com/videos/"
|
||||
);
|
||||
assert_eq!(
|
||||
provider.page_family_referer(
|
||||
"https://pimpbunny.com/categories/blowjob/2/?sort_by=post_date"
|
||||
),
|
||||
"https://pimpbunny.com/categories/blowjob/"
|
||||
);
|
||||
assert_eq!(
|
||||
provider.page_family_referer(
|
||||
"https://pimpbunny.com/search/adriana-chechik/3/?sort_by=video_viewed"
|
||||
),
|
||||
"https://pimpbunny.com/search/adriana-chechik/"
|
||||
);
|
||||
assert_eq!(
|
||||
provider.page_family_referer(
|
||||
"https://pimpbunny.com/onlyfans-models/momoitenshi/3/?sort_by=post_date"
|
||||
),
|
||||
"https://pimpbunny.com/onlyfans-models/momoitenshi/"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user