mirror of
https://github.com/amtoaer/bili-sync.git
synced 2026-09-05 23:49:53 +08:00
fix: 修复某些视频下载提示 404 not found 的问题 (#579)
This commit is contained in:
@@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use crate::bilibili::error::BiliError;
|
use crate::bilibili::error::BiliError;
|
||||||
|
|
||||||
pub struct PageAnalyzer {
|
pub struct PageAnalyzer {
|
||||||
info: serde_json::Value,
|
pub(crate) info: serde_json::Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, strum::FromRepr, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Clone)]
|
#[derive(Debug, strum::FromRepr, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Clone)]
|
||||||
|
|||||||
@@ -169,9 +169,11 @@ impl Downloader {
|
|||||||
concurrent_download: &ConcurrentDownloadLimit,
|
concurrent_download: &ConcurrentDownloadLimit,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let (concurrency, threshold) = (concurrent_download.concurrency, concurrent_download.threshold);
|
let (concurrency, threshold) = (concurrent_download.concurrency, concurrent_download.threshold);
|
||||||
|
// 有些 B 站视频 url GET 有内容但 HEAD 会返回 404,此处使用 bytes=0-0 的 GET 代替 HEAD 以获取文件大小
|
||||||
let resp = self
|
let resp = self
|
||||||
.client
|
.client
|
||||||
.request(Method::HEAD, url, None)
|
.request(Method::GET, url, None)
|
||||||
|
.header(header::RANGE, "bytes=0-0")
|
||||||
.send()
|
.send()
|
||||||
.await?
|
.await?
|
||||||
.error_for_status()?;
|
.error_for_status()?;
|
||||||
@@ -247,3 +249,55 @@ impl ResponseExt for reqwest::Response {
|
|||||||
.and_then(|s| s.parse::<u64>().ok())
|
.and_then(|s| s.parse::<u64>().ok())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
use crate::bilibili::{BestStream, BiliClient, Video};
|
||||||
|
use crate::config::VersionedConfig;
|
||||||
|
use crate::database::setup_database;
|
||||||
|
use crate::downloader::Downloader;
|
||||||
|
|
||||||
|
#[ignore = "only for manual test"]
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_parse_and_download_video() -> Result<()> {
|
||||||
|
VersionedConfig::init_for_test(&setup_database(Path::new("./test.sqlite")).await?).await?;
|
||||||
|
let config = VersionedConfig::get().read();
|
||||||
|
let client = BiliClient::new();
|
||||||
|
let video = Video::new(&client, "BV14oCrBqEd2".to_owned(), &config.credential);
|
||||||
|
let pages = video.get_pages().await.expect("failed to get pages");
|
||||||
|
let first_page = pages.into_iter().next().expect("no page found");
|
||||||
|
let mut page_analyzer = video
|
||||||
|
.get_page_analyzer(&first_page)
|
||||||
|
.await
|
||||||
|
.expect("failed to get page analyzer");
|
||||||
|
let json_info = serde_json::to_string_pretty(&page_analyzer.info)?;
|
||||||
|
tokio::fs::write("./debug_playurl.json", json_info).await?;
|
||||||
|
let best_stream = page_analyzer
|
||||||
|
.best_stream(&config.filter_option)
|
||||||
|
.expect("failed to get best stream");
|
||||||
|
let BestStream::VideoAudio {
|
||||||
|
video,
|
||||||
|
audio: Some(audio),
|
||||||
|
} = best_stream
|
||||||
|
else {
|
||||||
|
panic!("best stream is not video & audio");
|
||||||
|
};
|
||||||
|
dbg!(&video);
|
||||||
|
dbg!(&audio);
|
||||||
|
let downloader = Downloader::new(client.client);
|
||||||
|
downloader
|
||||||
|
.multi_fetch_and_merge(
|
||||||
|
&video.urls(true),
|
||||||
|
&audio.urls(true),
|
||||||
|
Path::new("./output.mp4"),
|
||||||
|
&config.concurrent_limit.download,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.expect("failed to download video");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user