mirror of
https://github.com/lanyeeee/bilibili-video-downloader.git
synced 2026-08-28 19:47:24 +08:00
feat: 后端支持配置代理
This commit is contained in:
@@ -16,7 +16,8 @@ use tauri::{
|
||||
use tokio::task::JoinSet;
|
||||
|
||||
use crate::{
|
||||
extensions::AppHandleExt,
|
||||
config::ProxyMode,
|
||||
extensions::{AnyhowErrorToStringChain, AppHandleExt},
|
||||
protobuf::DmSegMobileReply,
|
||||
types::{
|
||||
bangumi_info::BangumiInfo, bangumi_media_url::BangumiMediaUrl, cheese_info::CheeseInfo,
|
||||
@@ -59,6 +60,15 @@ impl BiliClient {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reload_client(&self) {
|
||||
let api_client = create_api_client(&self.app);
|
||||
*self.api_client.write() = api_client;
|
||||
let media_client = create_media_client(&self.app);
|
||||
*self.media_client.write() = media_client;
|
||||
let content_length_client = create_content_length_client(&self.app);
|
||||
*self.content_length_client.write() = content_length_client;
|
||||
}
|
||||
|
||||
pub async fn generate_qrcode(&self) -> anyhow::Result<QrcodeData> {
|
||||
// 发送生成二维码请求
|
||||
let request = self
|
||||
@@ -800,7 +810,7 @@ impl BiliClient {
|
||||
}
|
||||
}
|
||||
|
||||
fn create_api_client(_app: &AppHandle) -> ClientWithMiddleware {
|
||||
fn create_api_client(app: &AppHandle) -> ClientWithMiddleware {
|
||||
let retry_policy = ExponentialBackoff::builder()
|
||||
.base(1)
|
||||
.jitter(Jitter::Bounded)
|
||||
@@ -811,6 +821,7 @@ fn create_api_client(_app: &AppHandle) -> ClientWithMiddleware {
|
||||
headers.insert("referer", HeaderValue::from_static(REFERRER));
|
||||
|
||||
let client = reqwest::ClientBuilder::new()
|
||||
.set_proxy(app, "api_client")
|
||||
.timeout(Duration::from_secs(3))
|
||||
.default_headers(headers)
|
||||
.build()
|
||||
@@ -821,7 +832,7 @@ fn create_api_client(_app: &AppHandle) -> ClientWithMiddleware {
|
||||
.build()
|
||||
}
|
||||
|
||||
fn create_media_client(_app: &AppHandle) -> ClientWithMiddleware {
|
||||
fn create_media_client(app: &AppHandle) -> ClientWithMiddleware {
|
||||
let retry_policy = ExponentialBackoff::builder()
|
||||
.base(1)
|
||||
.jitter(Jitter::Bounded)
|
||||
@@ -832,6 +843,7 @@ fn create_media_client(_app: &AppHandle) -> ClientWithMiddleware {
|
||||
headers.insert("referer", HeaderValue::from_static(REFERRER));
|
||||
|
||||
let client = reqwest::ClientBuilder::new()
|
||||
.set_proxy(app, "media_client")
|
||||
.default_headers(headers)
|
||||
.build()
|
||||
.unwrap();
|
||||
@@ -841,18 +853,49 @@ fn create_media_client(_app: &AppHandle) -> ClientWithMiddleware {
|
||||
.build()
|
||||
}
|
||||
|
||||
fn create_content_length_client(_app: &AppHandle) -> Client {
|
||||
fn create_content_length_client(app: &AppHandle) -> Client {
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.insert("user-agent", HeaderValue::from_static(USER_AGENT));
|
||||
headers.insert("referer", HeaderValue::from_static(REFERRER));
|
||||
|
||||
reqwest::ClientBuilder::new()
|
||||
.set_proxy(app, "content_length_client")
|
||||
.timeout(Duration::from_secs(5))
|
||||
.default_headers(headers)
|
||||
.build()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
trait ClientBuilderExt {
|
||||
fn set_proxy(self, app: &AppHandle, client_name: &str) -> Self;
|
||||
}
|
||||
|
||||
impl ClientBuilderExt for reqwest::ClientBuilder {
|
||||
fn set_proxy(self, app: &AppHandle, client_name: &str) -> reqwest::ClientBuilder {
|
||||
let proxy_mode = app.get_config().read().proxy_mode;
|
||||
match proxy_mode {
|
||||
ProxyMode::NoProxy => self.no_proxy(),
|
||||
ProxyMode::System => self,
|
||||
ProxyMode::Custom => {
|
||||
let config = app.get_config().inner().read();
|
||||
let proxy_host = &config.proxy_host;
|
||||
let proxy_port = &config.proxy_port;
|
||||
let proxy_url = format!("http://{proxy_host}:{proxy_port}");
|
||||
|
||||
match reqwest::Proxy::all(&proxy_url).map_err(anyhow::Error::from) {
|
||||
Ok(proxy) => self.proxy(proxy),
|
||||
Err(err) => {
|
||||
let err_title = format!("{client_name}将`{proxy_url}`设为代理失败,将直连");
|
||||
let string_chain = err.to_string_chain();
|
||||
tracing::error!(err_title, message = string_chain);
|
||||
self.no_proxy()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct BiliResp {
|
||||
pub code: i64,
|
||||
|
||||
@@ -52,13 +52,18 @@ pub fn get_config(config: tauri::State<RwLock<Config>>) -> Config {
|
||||
#[specta::specta]
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
pub fn save_config(app: AppHandle, config: Config) -> CommandResult<()> {
|
||||
let bili_client = app.get_bili_client();
|
||||
let config_state = app.get_config();
|
||||
|
||||
let proxy_changed = {
|
||||
let config_state = config_state.read();
|
||||
config_state.proxy_mode != config.proxy_mode
|
||||
|| config_state.proxy_host != config.proxy_host
|
||||
|| config_state.proxy_port != config.proxy_port
|
||||
};
|
||||
|
||||
let enable_file_logger = config.enable_file_logger;
|
||||
let enable_file_logger_changed = config_state
|
||||
.read()
|
||||
.enable_file_logger
|
||||
.ne(&enable_file_logger);
|
||||
let file_logger_changed = config_state.read().enable_file_logger != enable_file_logger;
|
||||
|
||||
{
|
||||
// 包裹在大括号中,以便自动释放写锁
|
||||
@@ -70,7 +75,11 @@ pub fn save_config(app: AppHandle, config: Config) -> CommandResult<()> {
|
||||
tracing::debug!("保存配置成功");
|
||||
}
|
||||
|
||||
if enable_file_logger_changed {
|
||||
if proxy_changed {
|
||||
bili_client.reload_client();
|
||||
}
|
||||
|
||||
if file_logger_changed {
|
||||
if enable_file_logger {
|
||||
logger::reload_file_logger()
|
||||
.map_err(|err| CommandError::from("重新加载文件日志失败", err))?;
|
||||
|
||||
@@ -30,6 +30,9 @@ pub struct Config {
|
||||
pub dir_fmt: String,
|
||||
pub dir_fmt_for_part: String,
|
||||
pub time_fmt: String,
|
||||
pub proxy_mode: ProxyMode,
|
||||
pub proxy_host: String,
|
||||
pub proxy_port: u16,
|
||||
pub task_concurrency: usize,
|
||||
pub task_download_interval_sec: u64,
|
||||
pub chunk_concurrency: usize,
|
||||
@@ -111,6 +114,9 @@ impl Config {
|
||||
dir_fmt: "{collection_title}/{episode_title}".to_string(),
|
||||
dir_fmt_for_part: DEFAULT_FMT_FOR_PART.to_string(),
|
||||
time_fmt: "%Y-%m-%d_%H-%M-%S".to_string(),
|
||||
proxy_mode: ProxyMode::NoProxy,
|
||||
proxy_host: "127.0.0.1".to_string(),
|
||||
proxy_port: 7890,
|
||||
task_concurrency: 3,
|
||||
task_download_interval_sec: 0,
|
||||
chunk_concurrency: 16,
|
||||
@@ -215,3 +221,11 @@ pub enum PreferAudioQuality {
|
||||
#[serde(rename = "HiRes")]
|
||||
AudioHiRes = 30251,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub enum ProxyMode {
|
||||
#[default]
|
||||
NoProxy,
|
||||
System,
|
||||
Custom,
|
||||
}
|
||||
|
||||
+2
-1
@@ -258,7 +258,7 @@ export type CntInfo = { collect: number; play: number; thumb_up: number; share:
|
||||
export type CntInfoInMedia = { collect: number; play: number; danmaku: number; vt: number; play_switch: number; reply: number; view_text_1: string }
|
||||
export type CodecType = "Unknown" | "Audio" | "AVC" | "HEVC" | "AV1"
|
||||
export type CommandError = { err_title: string; err_message: string }
|
||||
export type Config = { download_dir: string; enable_file_logger: boolean; sessdata: string; prefer_video_quality: PreferVideoQuality; prefer_codec_type: PreferCodecType; prefer_audio_quality: PreferAudioQuality; download_video: boolean; download_audio: boolean; auto_merge: boolean; download_xml_danmaku: boolean; download_ass_danmaku: boolean; download_json_danmaku: boolean; download_subtitle: boolean; download_cover: boolean; download_nfo: boolean; download_json: boolean; dir_fmt: string; dir_fmt_for_part: string; time_fmt: string; task_concurrency: number; task_download_interval_sec: number; chunk_concurrency: number; chunk_download_interval_sec: number; danmaku_config: CanvasConfig }
|
||||
export type Config = { download_dir: string; enable_file_logger: boolean; sessdata: string; prefer_video_quality: PreferVideoQuality; prefer_codec_type: PreferCodecType; prefer_audio_quality: PreferAudioQuality; download_video: boolean; download_audio: boolean; auto_merge: boolean; download_xml_danmaku: boolean; download_ass_danmaku: boolean; download_json_danmaku: boolean; download_subtitle: boolean; download_cover: boolean; download_nfo: boolean; download_json: boolean; dir_fmt: string; dir_fmt_for_part: string; time_fmt: string; proxy_mode: ProxyMode; proxy_host: string; proxy_port: number; task_concurrency: number; task_download_interval_sec: number; chunk_concurrency: number; chunk_download_interval_sec: number; danmaku_config: CanvasConfig }
|
||||
export type Consulting = { consulting_flag: boolean; consulting_url: string }
|
||||
export type ContentList = { bold: boolean; content: string; number: string }
|
||||
export type Cooperation = { link: string }
|
||||
@@ -361,6 +361,7 @@ export type PreferAudioQuality = "Best" | "64K" | "132K" | "192K" | "Dolby" | "H
|
||||
export type PreferCodecType = "Unknown" | "AVC" | "HEVC" | "AV1"
|
||||
export type PreferVideoQuality = "Best" | "240P" | "360P" | "480P" | "720P" | "720P60" | "1080P" | "AiRepair" | "1080P+" | "1080P60" | "4K" | "HDR" | "Dolby" | "8K"
|
||||
export type PreviewedPurchaseNote = { long_watch_text: string; pay_text: string; price_format: string; watch_text: string; watching_text: string }
|
||||
export type ProxyMode = "NoProxy" | "System" | "Custom"
|
||||
export type Publish = { is_finish: number; is_started: number; pub_time: string; pub_time_show: string; unknow_pub_date: number; weekday: number }
|
||||
export type PurchaseFormatNote = { content_list: ContentList[]; link: string; title: string }
|
||||
export type PurchaseNote = { content: string; link: string; title: string }
|
||||
|
||||
Reference in New Issue
Block a user