Fix chaturbate search URL (swapped format args) and stale cache branch
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MUYdCh2nCVsQYgJAT7gwSi
This commit is contained in:
@@ -43,8 +43,8 @@ Status: `[ ]` open, `[~]` in progress, `[x]` fixed and verified, `[-]` not repro
|
|||||||
|
|
||||||
| | Channel | Symptom | Notes |
|
| | Channel | Symptom | Notes |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| [ ] | `fapello` | "girl" and "milf" both 0 | |
|
| [-] | `fapello` | "girl" and "milf" both 0 | by design, documented in the provider: the site's search returns photo models, not videos; no keyword video search exists, so queries are literal-filtered over the feed |
|
||||||
| [ ] | `chaturbate` | "girl" and "milf" both 0 | |
|
| [x] | `chaturbate` | "girl" and "milf" both 0 | format arguments swapped in the search URL (`girl/api/...?keywords=https://chaturbate.com`, a relative-URL builder error); fixed + unit test. Also stale-cache branch never refreshed. 90 results per query, yt-dlp resolves the live stream |
|
||||||
| [x] | `cumlouder` | unknown tag takes 146s before returning 0 | a real 404 went through the requester's Jina/FlareSolverr fallback chain; now the raw response is read, 404 returns empty immediately (0s), 5xx/429 still retried. check.py passes |
|
| [x] | `cumlouder` | unknown tag takes 146s before returning 0 | a real 404 went through the requester's Jina/FlareSolverr fallback chain; now the raw response is read, 404 returns empty immediately (0s), 5xx/429 still retried. check.py passes |
|
||||||
| [ ] | `vjav` | "girl" 0, "milf" 10 | may be term-specific |
|
| [ ] | `vjav` | "girl" 0, "milf" 10 | may be term-specific |
|
||||||
| [ ] | `xxxtik` | "girl" 0 (not re-run serially) | |
|
| [ ] | `xxxtik` | "girl" 0 (not re-run serially) | |
|
||||||
|
|||||||
@@ -138,6 +138,34 @@ impl ChaturbateProvider {
|
|||||||
Ok(video_items)
|
Ok(video_items)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `keywords=` search on the room list. (The base URL and query used to be
|
||||||
|
/// passed in swapped order, producing `milf/api/...?keywords=https://...`.)
|
||||||
|
fn build_search_url(base: &str, query: &str, page: u8) -> String {
|
||||||
|
let keywords = query
|
||||||
|
.trim()
|
||||||
|
.chars()
|
||||||
|
.map(|c| match c {
|
||||||
|
' ' => "+".to_string(),
|
||||||
|
c if c.is_ascii_alphanumeric() || matches!(c, '-' | '_' | '.' | '~') => {
|
||||||
|
c.to_string()
|
||||||
|
}
|
||||||
|
c => {
|
||||||
|
let mut buf = [0u8; 4];
|
||||||
|
c.encode_utf8(&mut buf)
|
||||||
|
.bytes()
|
||||||
|
.map(|b| format!("%{b:02X}"))
|
||||||
|
.collect::<String>()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<String>();
|
||||||
|
format!(
|
||||||
|
"{}/api/ts/roomlist/room-list/?keywords={}&limit=90&offset={}",
|
||||||
|
base,
|
||||||
|
keywords,
|
||||||
|
90 * (page.max(1) as u32 - 1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
async fn query(
|
async fn query(
|
||||||
&self,
|
&self,
|
||||||
cache: VideoCache,
|
cache: VideoCache,
|
||||||
@@ -145,22 +173,15 @@ impl ChaturbateProvider {
|
|||||||
query: &str,
|
query: &str,
|
||||||
options: ServerOptions,
|
options: ServerOptions,
|
||||||
) -> Result<Vec<VideoItem>> {
|
) -> Result<Vec<VideoItem>> {
|
||||||
let mut video_url = format!(
|
let video_url = Self::build_search_url(&self.url, query, page);
|
||||||
"{}/api/ts/roomlist/room-list/?keywords={}&limit=90&offset={}",
|
|
||||||
query,
|
|
||||||
self.url,
|
|
||||||
90 * (page - 1)
|
|
||||||
);
|
|
||||||
video_url = video_url.replace(" ", "+");
|
|
||||||
// Check our Video Cache. If the result is younger than 1 hour, we return it.
|
// Check our Video Cache. If the result is younger than 1 hour, we return it.
|
||||||
let old_items = match cache.get(&video_url) {
|
let old_items = match cache.get(&video_url) {
|
||||||
Some((time, items)) => {
|
Some((time, items)) => {
|
||||||
if time.elapsed().unwrap_or_default().as_secs() < 60 * 1 {
|
if time.elapsed().unwrap_or_default().as_secs() < 60 * 1 {
|
||||||
return Ok(items.clone());
|
return Ok(items.clone());
|
||||||
} else {
|
|
||||||
let _ = cache.check().await;
|
|
||||||
return Ok(items.clone());
|
|
||||||
}
|
}
|
||||||
|
// Expired: refetch, keeping the stale list as the fallback.
|
||||||
|
items.clone()
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
vec![]
|
vec![]
|
||||||
@@ -347,3 +368,18 @@ impl Provider for ChaturbateProvider {
|
|||||||
Some(self.build_channel(clientversion))
|
Some(self.build_channel(clientversion))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::ChaturbateProvider;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn builds_search_url_with_base_first() {
|
||||||
|
assert_eq!(
|
||||||
|
ChaturbateProvider::build_search_url("https://chaturbate.com", "big tits", 2),
|
||||||
|
"https://chaturbate.com/api/ts/roomlist/room-list/?keywords=big+tits&limit=90&offset=90"
|
||||||
|
);
|
||||||
|
assert!(ChaturbateProvider::build_search_url("https://chaturbate.com", "a&b", 1)
|
||||||
|
.contains("keywords=a%26b&"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user