feat(downloader): route terabox via local Playwright resolver
Deploy Scraper / build-and-deploy (push) Canceled after 0s
Deploy Scraper / build-and-deploy (push) Canceled after 0s
Replace dead tera2.sylyt93.workers.dev (NXDOMAIN) with a local terabox-resolver service (systemd, :4092) that uses Playwright + residential proxy + user cookies to resolve TeraBox share links end-to-end to real signed dlink. Proven path: navigate terabox.app directly, duplicate cookies across .terabox.app domains, call /share/list from browser context. Supports directories (child files).
This commit is contained in:
@@ -2804,33 +2804,54 @@ pub async fn fetch_terabox(url: &str) -> Result<DownloadResult, ScrapingError> {
|
|||||||
|
|
||||||
let surl = surl.ok_or_else(|| ScrapingError::Http("SURL not found.".to_string()))?;
|
let surl = surl.ok_or_else(|| ScrapingError::Http("SURL not found.".to_string()))?;
|
||||||
|
|
||||||
|
// Call local TeraBox resolver (Playwright + residential proxy + cookies)
|
||||||
|
let resolver_url = std::env::var("TERABOX_RESOLVER_URL")
|
||||||
|
.unwrap_or_else(|_| "http://127.0.0.1:4092".to_string());
|
||||||
|
let resolve_url = format!("{}/resolve?surl={}", resolver_url, surl);
|
||||||
|
|
||||||
let client = http_client();
|
let client = http_client();
|
||||||
let resp = client
|
let resp = client
|
||||||
.client()
|
.client()
|
||||||
.get("https://tera2.sylyt93.workers.dev/info")
|
.get(&resolve_url)
|
||||||
.query(&[("s", &surl)])
|
|
||||||
.header("origin", "https://www.kauruka.com")
|
|
||||||
.header("referer", "https://www.kauruka.com/")
|
|
||||||
.header(USER_AGENT, "Mozilla/5.0")
|
.header(USER_AGENT, "Mozilla/5.0")
|
||||||
.timeout(Duration::from_secs(15))
|
.timeout(Duration::from_secs(60))
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.map_err(|e| ScrapingError::Http(format!("TeraBox info fetch failed: {}", e)))?
|
.map_err(|e| ScrapingError::Http(format!("TeraBox resolver fetch failed: {}", e)))?;
|
||||||
.json::<serde_json::Value>()
|
|
||||||
.await
|
|
||||||
.map_err(|e| ScrapingError::Http(format!("TeraBox JSON parse failed: {}", e)))?;
|
|
||||||
|
|
||||||
if let Some(download_url) = resp.get("url").and_then(|v| v.as_str()) {
|
if !resp.status().is_success() {
|
||||||
let mut result = DownloadResult::success(
|
let status = resp.status();
|
||||||
resp.get("name")
|
let body = resp.text().await.unwrap_or_default();
|
||||||
.and_then(|v| v.as_str())
|
return Ok(DownloadResult::error(format!(
|
||||||
.map(|s| s.to_string()),
|
"TeraBox resolver returned HTTP {}: {}",
|
||||||
);
|
status, body
|
||||||
result.provider = Some("terabox".to_string());
|
)));
|
||||||
result.thumbnail = resp
|
}
|
||||||
.get("img")
|
|
||||||
.and_then(|v| v.as_str())
|
let data: serde_json::Value = resp
|
||||||
.map(|s| s.to_string());
|
.json()
|
||||||
|
.await
|
||||||
|
.map_err(|e| ScrapingError::Http(format!("TeraBox resolver JSON parse failed: {}", e)))?;
|
||||||
|
|
||||||
|
if let Some(error) = data.get("error").and_then(|v| v.as_str()) {
|
||||||
|
return Ok(DownloadResult::error(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
let file_name = data
|
||||||
|
.get("file_name")
|
||||||
|
.and_then(|v| v.as_str())
|
||||||
|
.map(|s| s.to_string());
|
||||||
|
|
||||||
|
let mut result = DownloadResult::success(file_name.clone());
|
||||||
|
result.provider = Some("terabox".to_string());
|
||||||
|
result.thumbnail = data
|
||||||
|
.get("thumbnail")
|
||||||
|
.and_then(|v| v.as_str())
|
||||||
|
.map(|s| s.to_string());
|
||||||
|
|
||||||
|
// Primary download link
|
||||||
|
if let Some(download_url) = data.get("download_link").and_then(|v| v.as_str()) {
|
||||||
|
let size_bytes = data.get("file_size").and_then(|v| v.as_u64()).unwrap_or(0);
|
||||||
|
|
||||||
result.media.push(MediaItem {
|
result.media.push(MediaItem {
|
||||||
url: download_url.to_string(),
|
url: download_url.to_string(),
|
||||||
@@ -2838,21 +2859,39 @@ pub async fn fetch_terabox(url: &str) -> Result<DownloadResult, ScrapingError> {
|
|||||||
file_type: Some(MediaType::File),
|
file_type: Some(MediaType::File),
|
||||||
extension: None,
|
extension: None,
|
||||||
thumbnail: None,
|
thumbnail: None,
|
||||||
file_size: None,
|
file_size: Some(format_filesize(size_bytes)),
|
||||||
size_bytes: None,
|
size_bytes: Some(size_bytes),
|
||||||
frame_width: None,
|
frame_width: None,
|
||||||
frame_height: None,
|
frame_height: None,
|
||||||
note: None,
|
note: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(result)
|
// Directory: add child file links
|
||||||
} else {
|
if let Some(files) = data.get("files").and_then(|v| v.as_array()) {
|
||||||
Ok(DownloadResult::error(
|
for f in files {
|
||||||
resp.get("error")
|
if let Some(furl) = f.get("download_link").and_then(|v| v.as_str()) {
|
||||||
.and_then(|v| v.as_str())
|
let fsize = f.get("file_size").and_then(|v| v.as_u64()).unwrap_or(0);
|
||||||
.unwrap_or("Failed to fetch TeraBox info"),
|
result.media.push(MediaItem {
|
||||||
))
|
url: furl.to_string(),
|
||||||
|
quality: None,
|
||||||
|
file_type: Some(MediaType::File),
|
||||||
|
extension: None,
|
||||||
|
thumbnail: None,
|
||||||
|
file_size: Some(format_filesize(fsize)),
|
||||||
|
size_bytes: Some(fsize),
|
||||||
|
frame_width: None,
|
||||||
|
frame_height: None,
|
||||||
|
note: f
|
||||||
|
.get("file_name")
|
||||||
|
.and_then(|v| v.as_str())
|
||||||
|
.map(|s| s.to_string()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn fetch_videy(url: &str) -> Result<DownloadResult, ScrapingError> {
|
pub async fn fetch_videy(url: &str) -> Result<DownloadResult, ScrapingError> {
|
||||||
|
|||||||
Reference in New Issue
Block a user