feat: 支持下载SDR画质

This commit is contained in:
lanyeeee
2026-08-17 12:19:58 +08:00
parent e8f29aa371
commit 4aa8e7c032
6 changed files with 64 additions and 31 deletions
+2
View File
@@ -192,6 +192,8 @@ pub mod v1 {
Video1080P60 = 116, Video1080P60 = 116,
#[serde(rename = "4K")] #[serde(rename = "4K")]
Video4K = 120, Video4K = 120,
#[serde(rename = "SDR")]
VideoSDR = 122,
#[serde(rename = "HDR")] #[serde(rename = "HDR")]
VideoHDR = 125, VideoHDR = 125,
#[serde(rename = "Dolby")] #[serde(rename = "Dolby")]
+4 -4
View File
@@ -385,7 +385,7 @@ impl BiliClient {
"bvid": bvid, "bvid": bvid,
"cid": cid, "cid": cid,
"qn": 127, "qn": 127,
"fnval": 4048, "fnval": 139216,
}); });
// 发送获取普通url的请求 // 发送获取普通url的请求
let request = self let request = self
@@ -435,7 +435,7 @@ impl BiliClient {
let params = json!({ let params = json!({
"cid": cid, "cid": cid,
"qn": 127, "qn": 127,
"fnval": 4048, "fnval": 139216,
"drm_tech_type": 2, "drm_tech_type": 2,
}); });
// 发送获取番剧url的请求 // 发送获取番剧url的请求
@@ -478,7 +478,7 @@ impl BiliClient {
let params = json!({ let params = json!({
"cid": cid, "cid": cid,
"qn": 127, "qn": 127,
"fnval": 4048, "fnval": 139216,
"drm_tech_type": 2, "drm_tech_type": 2,
"from_client": "BROWSER", "from_client": "BROWSER",
}); });
@@ -522,7 +522,7 @@ impl BiliClient {
let params = json!({ let params = json!({
"ep_id": ep_id, "ep_id": ep_id,
"qn": 127, "qn": 127,
"fnval": 4048, "fnval": 139216,
"drm_tech_type": 2, "drm_tech_type": 2,
}); });
// 发送获取课程url的请求 // 发送获取课程url的请求
+54 -26
View File
@@ -53,7 +53,7 @@ impl Config {
let app_data_dir = app.path().app_data_dir()?; let app_data_dir = app.path().app_data_dir()?;
let config_path = app_data_dir.join("config.json"); let config_path = app_data_dir.join("config.json");
let config = if config_path.exists() { let mut config = if config_path.exists() {
let config_string = std::fs::read_to_string(config_path)?; let config_string = std::fs::read_to_string(config_path)?;
match serde_json::from_str(&config_string) { match serde_json::from_str(&config_string) {
// 如果能够直接解析为Config,则直接返回 // 如果能够直接解析为Config,则直接返回
@@ -65,6 +65,8 @@ impl Config {
} else { } else {
Config::default(&app_data_dir) Config::default(&app_data_dir)
}; };
config.reconcile_priority_lists();
config.save(app)?; config.save(app)?;
Ok(config) Ok(config)
} }
@@ -78,6 +80,18 @@ impl Config {
Ok(()) Ok(())
} }
fn reconcile_priority_lists(&mut self) {
reconcile(
&mut self.video_quality_priority,
DEFAULT_VIDEO_QUALITY_PRIORITY,
);
reconcile(
&mut self.audio_quality_priority,
DEFAULT_AUDIO_QUALITY_PRIORITY,
);
reconcile(&mut self.codec_type_priority, DEFAULT_CODEC_TYPE_PRIORITY);
}
fn merge_config(config_string: &str, app_data_dir: &Path) -> Config { fn merge_config(config_string: &str, app_data_dir: &Path) -> Config {
let Ok(mut json_value) = serde_json::from_str::<serde_json::Value>(config_string) else { let Ok(mut json_value) = serde_json::from_str::<serde_json::Value>(config_string) else {
return Config::default(app_data_dir); return Config::default(app_data_dir);
@@ -103,36 +117,14 @@ impl Config {
fn default(app_data_dir: &Path) -> Config { fn default(app_data_dir: &Path) -> Config {
const DEFAULT_FMT_FOR_PART: &str = const DEFAULT_FMT_FOR_PART: &str =
"{collection_title}/{episode_title}/{episode_title}-P{part_order} {part_title}"; "{collection_title}/{episode_title}/{episode_title}-P{part_order} {part_title}";
let default_video_quality_priority = vec![
VideoQuality::Video8K,
VideoQuality::VideoDolby,
VideoQuality::VideoHDR,
VideoQuality::Video4K,
VideoQuality::Video1080P60,
VideoQuality::Video1080PPlus,
VideoQuality::Video1080P,
VideoQuality::VideoAiRepair,
VideoQuality::Video720P60,
VideoQuality::Video720P,
VideoQuality::Video480P,
VideoQuality::Video360P,
VideoQuality::Video240P,
];
let default_audio_quality_priority = vec![
AudioQuality::AudioHiRes,
AudioQuality::AudioDolby,
AudioQuality::Audio192K,
AudioQuality::Audio132K,
AudioQuality::Audio64K,
];
Config { Config {
download_dir: app_data_dir.join("视频下载"), download_dir: app_data_dir.join("视频下载"),
enable_file_logger: true, enable_file_logger: true,
sessdata: String::new(), sessdata: String::new(),
video_quality_priority: default_video_quality_priority, video_quality_priority: DEFAULT_VIDEO_QUALITY_PRIORITY.to_vec(),
codec_type_priority: vec![CodecType::AVC, CodecType::HEVC, CodecType::AV1], codec_type_priority: DEFAULT_CODEC_TYPE_PRIORITY.to_vec(),
audio_quality_priority: default_audio_quality_priority, audio_quality_priority: DEFAULT_AUDIO_QUALITY_PRIORITY.to_vec(),
download_video: true, download_video: true,
download_audio: true, download_audio: true,
auto_merge: true, auto_merge: true,
@@ -162,6 +154,14 @@ impl Config {
} }
} }
fn reconcile<T: Copy + Eq>(priority: &mut Vec<T>, all: &[T]) {
for &item in all {
if !priority.contains(&item) {
priority.push(item);
}
}
}
#[derive(Default, Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Type)] #[derive(Default, Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Type)]
pub enum ProxyMode { pub enum ProxyMode {
#[default] #[default]
@@ -176,3 +176,31 @@ pub enum FileExistAction {
Overwrite, Overwrite,
Skip, Skip,
} }
const DEFAULT_VIDEO_QUALITY_PRIORITY: &[VideoQuality] = &[
VideoQuality::Video8K,
VideoQuality::VideoDolby,
VideoQuality::VideoHDR,
VideoQuality::VideoSDR,
VideoQuality::Video4K,
VideoQuality::Video1080P60,
VideoQuality::Video1080PPlus,
VideoQuality::Video1080P,
VideoQuality::VideoAiRepair,
VideoQuality::Video720P60,
VideoQuality::Video720P,
VideoQuality::Video480P,
VideoQuality::Video360P,
VideoQuality::Video240P,
];
const DEFAULT_AUDIO_QUALITY_PRIORITY: &[AudioQuality] = &[
AudioQuality::AudioHiRes,
AudioQuality::AudioDolby,
AudioQuality::Audio192K,
AudioQuality::Audio132K,
AudioQuality::Audio64K,
];
const DEFAULT_CODEC_TYPE_PRIORITY: &[CodecType] =
&[CodecType::AVC, CodecType::HEVC, CodecType::AV1];
+2
View File
@@ -41,6 +41,8 @@ pub enum VideoQuality {
Video1080P60 = 116, Video1080P60 = 116,
#[serde(rename = "4K")] #[serde(rename = "4K")]
Video4K = 120, Video4K = 120,
#[serde(rename = "SDR")]
VideoSDR = 122,
#[serde(rename = "HDR")] #[serde(rename = "HDR")]
VideoHDR = 125, VideoHDR = 125,
#[serde(rename = "Dolby")] #[serde(rename = "Dolby")]
+1 -1
View File
@@ -475,7 +475,7 @@ export type UserVideoInfo = { list: UserVideoList; page: PageInUserVideo }
export type UserVideoList = { vlist: EpInUserVideo[] } export type UserVideoList = { vlist: EpInUserVideo[] }
export type UserVideoSearchResult = UserVideoInfo export type UserVideoSearchResult = UserVideoInfo
export type VideoProcessTask = { merge_selected: boolean; embed_chapter_selected: boolean; embed_skip_selected: boolean; completed: boolean; skipped: boolean } export type VideoProcessTask = { merge_selected: boolean; embed_chapter_selected: boolean; embed_skip_selected: boolean; completed: boolean; skipped: boolean }
export type VideoQuality = "Unknown" | "240P" | "360P" | "480P" | "720P" | "720P60" | "1080P" | "AiRepair" | "1080P+" | "1080P60" | "4K" | "HDR" | "Dolby" | "8K" export type VideoQuality = "Unknown" | "240P" | "360P" | "480P" | "720P" | "720P60" | "1080P" | "AiRepair" | "1080P+" | "1080P60" | "4K" | "SDR" | "HDR" | "Dolby" | "8K"
export type VideoQualityAndCodecType = { video_quality: VideoQuality; codec_type: CodecType } export type VideoQualityAndCodecType = { video_quality: VideoQuality; codec_type: CodecType }
export type VideoTask = { selected: boolean; url: string; video_quality: VideoQuality; codec_type: CodecType; content_length: number; chunks: MediaChunk[]; completed: boolean; skipped: boolean } export type VideoTask = { selected: boolean; url: string; video_quality: VideoQuality; codec_type: CodecType; content_length: number; chunks: MediaChunk[]; completed: boolean; skipped: boolean }
export type VipInUserInfo = { type: number; status: number; due_date: number; vip_pay_type: number; theme_type: number; label: LabelInUserInfo; avatar_subscript: number; nickname_color: string; role: number; avatar_subscript_url: string; tv_vip_status: number; tv_vip_pay_type: number; tv_due_date: number } export type VipInUserInfo = { type: number; status: number; due_date: number; vip_pay_type: number; theme_type: number; label: LabelInUserInfo; avatar_subscript: number; nickname_color: string; role: number; avatar_subscript_url: string; tv_vip_status: number; tv_vip_pay_type: number; tv_due_date: number }
+1
View File
@@ -249,6 +249,7 @@ const videoQualityNameMap: Record<VideoQuality, string> = {
'1080P+': '1080P 高码率', '1080P+': '1080P 高码率',
'1080P60': '1080P 60帧', '1080P60': '1080P 60帧',
'4K': '4K 超高清', '4K': '4K 超高清',
SDR: '4K SDR增强',
HDR: 'HDR 真彩色', HDR: 'HDR 真彩色',
Dolby: '杜比视界', Dolby: '杜比视界',
'8K': '8K 超高清', '8K': '8K 超高清',