archivebate: app clients get resolved media URLs with headers, resolved concurrently

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUYdCh2nCVsQYgJAT7gwSi
This commit is contained in:
Simon
2026-10-18 19:30:55 +00:00
parent a4364e5be3
commit 30271b9b7c
2 changed files with 128 additions and 46 deletions

View File

@@ -815,6 +815,53 @@ impl ArchivebateProvider {
item
}
/// For Hot Tub app clients: resolve every item's real media URL at the same
/// time (one task per item, no concurrency cap) and hand the app that URL
/// with the headers the CDN is played with, instead of the lazy
/// `/proxy/archivebate` redirect. Items that fail or time out keep the
/// proxied format, which re-resolves at playback time.
async fn resolve_direct_formats(
videos: Vec<VideoItem>,
options: &ServerOptions,
) -> Vec<VideoItem> {
let tasks: Vec<_> = videos
.iter()
.map(|video| {
let detail_url = video.url.clone();
let mut requester =
requester_or_default(options, CHANNEL_ID, "archivebate.resolve_direct");
tokio::spawn(async move {
timeout(
StdDuration::from_secs(25),
crate::proxies::archivebate::resolve_media(&mut requester, &detail_url),
)
.await
.ok()
.flatten()
})
})
.collect();
let resolved = futures::future::join_all(tasks).await;
videos
.into_iter()
.zip(resolved)
.map(|(mut video, resolved)| match resolved.ok().flatten() {
Some(media) => {
video.formats = Some(vec![Self::video_format_with_headers(
VideoFormat::new(media.media_url, "source".to_string(), "mp4".to_string()),
vec![
("Referer".to_string(), media.embed_url),
("User-Agent".to_string(), FIREFOX_UA.to_string()),
],
)]);
video
}
None => Self::with_default_format(video, options),
})
.collect()
}
async fn enrich_video(&self, item: VideoItem, options: &ServerOptions) -> VideoItem {
let page_url = item.url.clone();
let format_url = Self::proxied_video(options, &page_url);
@@ -1208,6 +1255,14 @@ impl Provider for ArchivebateProvider {
if videos.is_empty() {
return videos;
}
let is_app_client = options
.client_version
.as_ref()
.map(ClientVersion::is_verified_hottub)
.unwrap_or(false);
if is_app_client {
return Self::resolve_direct_formats(videos, &options).await;
}
stream::iter(videos.into_iter().map(|video| {
let provider = self.clone();
let options = options.clone();