diff --git a/crates/bili_sync/src/config/current.rs b/crates/bili_sync/src/config/current.rs index c682c16..7dc8016 100644 --- a/crates/bili_sync/src/config/current.rs +++ b/crates/bili_sync/src/config/current.rs @@ -9,7 +9,7 @@ use validator::Validate; use crate::bilibili::{Credential, DanmakuOption, FilterOption}; use crate::config::LegacyConfig; use crate::config::default::{default_auth_token, default_bind_address, default_time_format}; -use crate::config::item::{ConcurrentLimit, NFOTimeType}; +use crate::config::item::{ConcurrentLimit, NFOTimeType, SkipOption}; use crate::utils::model::{load_db_config, save_db_config}; pub static CONFIG_DIR: LazyLock = @@ -22,6 +22,8 @@ pub struct Config { pub credential: Credential, pub filter_option: FilterOption, pub danmaku_option: DanmakuOption, + #[serde(default)] + pub skip_option: SkipOption, pub video_name: String, pub page_name: String, pub interval: u64, @@ -94,6 +96,7 @@ impl Default for Config { credential: Credential::default(), filter_option: FilterOption::default(), danmaku_option: DanmakuOption::default(), + skip_option: SkipOption::default(), video_name: "{{title}}".to_owned(), page_name: "{{bvid}}".to_owned(), interval: 1200, @@ -115,6 +118,7 @@ impl From for Config { credential: legacy.credential, filter_option: legacy.filter_option, danmaku_option: legacy.danmaku_option, + skip_option: SkipOption::default(), video_name: legacy.video_name, page_name: legacy.page_name, interval: legacy.interval, diff --git a/crates/bili_sync/src/config/item.rs b/crates/bili_sync/src/config/item.rs index 46ebfd0..df25533 100644 --- a/crates/bili_sync/src/config/item.rs +++ b/crates/bili_sync/src/config/item.rs @@ -69,6 +69,15 @@ impl Default for ConcurrentLimit { } } +#[derive(Serialize, Deserialize, Clone, Default)] +pub struct SkipOption { + pub no_poster: bool, + pub no_video_nfo: bool, + pub no_upper: bool, + pub no_danmaku: bool, + pub no_subtitle: bool, +} + pub trait PathSafeTemplate { fn path_safe_register(&mut self, name: &'static str, template: impl Into) -> Result<()>; fn path_safe_render(&self, name: &'static str, data: &serde_json::Value) -> Result; diff --git a/crates/bili_sync/src/config/mod.rs b/crates/bili_sync/src/config/mod.rs index 40da1de..dc7b9fc 100644 --- a/crates/bili_sync/src/config/mod.rs +++ b/crates/bili_sync/src/config/mod.rs @@ -10,7 +10,7 @@ mod versioned_config; pub use crate::config::args::{ARGS, version}; pub use crate::config::current::{CONFIG_DIR, Config}; pub use crate::config::handlebar::TEMPLATE; -pub use crate::config::item::{NFOTimeType, PathSafeTemplate, RateLimit}; +pub use crate::config::item::{NFOTimeType, PathSafeTemplate, RateLimit, SkipOption}; pub use crate::config::legacy::LegacyConfig; pub use crate::config::versioned_cache::VersionedCache; pub use crate::config::versioned_config::VersionedConfig; diff --git a/crates/bili_sync/src/workflow.rs b/crates/bili_sync/src/workflow.rs index ee53b71..3aac61a 100644 --- a/crates/bili_sync/src/workflow.rs +++ b/crates/bili_sync/src/workflow.rs @@ -14,7 +14,7 @@ use tokio::sync::Semaphore; use crate::adapter::{VideoSource, VideoSourceEnum}; use crate::bilibili::{BestStream, BiliClient, BiliError, Dimension, PageInfo, Video, VideoInfo}; -use crate::config::{ARGS, PathSafeTemplate, TEMPLATE, VersionedConfig}; +use crate::config::{ARGS, PathSafeTemplate, SkipOption, TEMPLATE, VersionedConfig}; use crate::downloader::Downloader; use crate::error::{DownloadAbortError, ExecutionStatus, ProcessPageError}; use crate::utils::format_arg::{page_format_args, video_format_args}; @@ -163,6 +163,8 @@ pub async fn download_unprocessed_videos( video_source.log_download_video_start(); let semaphore = Semaphore::new(VersionedConfig::get().load().concurrent_limit.video); let downloader = Downloader::new(bili_client.client.clone()); + // 提前获取 skip_option,保证单个视频源在整个下载过程中配置不变 + let skip_option = &VersionedConfig::get().load().skip_option; let unhandled_videos_pages = filter_unhandled_video_pages(video_source.filter_expr(), connection).await?; let mut assigned_upper = HashSet::new(); let tasks = unhandled_videos_pages @@ -179,6 +181,7 @@ pub async fn download_unprocessed_videos( &semaphore, &downloader, should_download_upper, + skip_option, ) }) .collect::>(); @@ -218,6 +221,7 @@ pub async fn download_video_pages( semaphore: &Semaphore, downloader: &Downloader, should_download_upper: bool, + skip_option: &SkipOption, ) -> Result { let _permit = semaphore.acquire().await.context("acquire semaphore failed")?; let mut status = VideoStatus::from(video_model.download_status); @@ -239,7 +243,7 @@ pub async fn download_video_pages( let (res_1, res_2, res_3, res_4, res_5) = tokio::join!( // 下载视频封面 fetch_video_poster( - separate_status[0] && !is_single_page, + separate_status[0] && !is_single_page && !skip_option.no_poster, &video_model, downloader, base_path.join("poster.jpg"), @@ -247,20 +251,20 @@ pub async fn download_video_pages( ), // 生成视频信息的 nfo generate_video_nfo( - separate_status[1] && !is_single_page, + separate_status[1] && !is_single_page && !skip_option.no_video_nfo, &video_model, base_path.join("tvshow.nfo"), ), // 下载 Up 主头像 fetch_upper_face( - separate_status[2] && should_download_upper, + separate_status[2] && should_download_upper && !skip_option.no_upper, &video_model, downloader, base_upper_path.join("folder.jpg"), ), // 生成 Up 主信息的 nfo generate_upper_nfo( - separate_status[3] && should_download_upper, + separate_status[3] && should_download_upper && !skip_option.no_upper, &video_model, base_upper_path.join("person.nfo"), ), @@ -272,7 +276,8 @@ pub async fn download_video_pages( pages, connection, downloader, - &base_path + &base_path, + skip_option, ) ); let results = [res_1, res_2, res_3, res_4, res_5] @@ -309,6 +314,7 @@ pub async fn download_video_pages( } /// 分发并执行分页下载任务,当且仅当所有分页成功下载或达到最大重试次数时返回 Ok,否则根据失败原因返回对应的错误 +#[allow(clippy::too_many_arguments)] pub async fn dispatch_download_page( should_run: bool, bili_client: &BiliClient, @@ -317,6 +323,7 @@ pub async fn dispatch_download_page( connection: &DatabaseConnection, downloader: &Downloader, base_path: &Path, + skip_option: &SkipOption, ) -> Result { if !should_run { return Ok(ExecutionStatus::Skipped); @@ -332,6 +339,7 @@ pub async fn dispatch_download_page( &child_semaphore, downloader, base_path, + skip_option, ) }) .collect::>(); @@ -382,6 +390,7 @@ pub async fn download_page( semaphore: &Semaphore, downloader: &Downloader, base_path: &Path, + skip_option: &SkipOption, ) -> Result { let _permit = semaphore.acquire().await.context("acquire semaphore failed")?; let mut status = PageStatus::from(page_model.download_status); @@ -437,7 +446,7 @@ pub async fn download_page( let (res_1, res_2, res_3, res_4, res_5) = tokio::join!( // 下载分页封面 fetch_page_poster( - separate_status[0], + separate_status[0] && !skip_option.no_poster, video_model, &page_model, downloader, @@ -454,11 +463,28 @@ pub async fn download_page( &video_path ), // 生成分页视频信息的 nfo - generate_page_nfo(separate_status[2], video_model, &page_model, nfo_path), + generate_page_nfo( + separate_status[2] && !skip_option.no_video_nfo, + video_model, + &page_model, + nfo_path + ), // 下载分页弹幕 - fetch_page_danmaku(separate_status[3], bili_client, video_model, &page_info, danmaku_path), + fetch_page_danmaku( + separate_status[3] && !skip_option.no_danmaku, + bili_client, + video_model, + &page_info, + danmaku_path + ), // 下载分页字幕 - fetch_page_subtitle(separate_status[4], bili_client, video_model, &page_info, &subtitle_path) + fetch_page_subtitle( + separate_status[4] && !skip_option.no_subtitle, + bili_client, + video_model, + &page_info, + &subtitle_path + ) ); let results = [res_1, res_2, res_3, res_4, res_5] .into_iter() diff --git a/web/src/lib/types.ts b/web/src/lib/types.ts index 2513ecd..057dfe3 100644 --- a/web/src/lib/types.ts +++ b/web/src/lib/types.ts @@ -246,6 +246,14 @@ export interface DanmakuOption { time_offset: number; } +export interface SkipOption { + no_poster: boolean; + no_video_nfo: boolean; + no_upper: boolean; + no_danmaku: boolean; + no_subtitle: boolean; +} + export interface RateLimit { limit: number; duration: number; @@ -270,6 +278,7 @@ export interface Config { credential: Credential; filter_option: FilterOption; danmaku_option: DanmakuOption; + skip_option: SkipOption; video_name: string; page_name: string; interval: number; diff --git a/web/src/routes/settings/+page.svelte b/web/src/routes/settings/+page.svelte index ce291c8..f63ba73 100644 --- a/web/src/routes/settings/+page.svelte +++ b/web/src/routes/settings/+page.svelte @@ -145,7 +145,7 @@ 基本设置 B站认证 - 视频质量 + 视频处理 弹幕渲染 高级设置 @@ -431,6 +431,8 @@
+ +

排除某些类型的特殊流

@@ -448,6 +450,33 @@
+ + + +
+ +

在视频处理部分跳过某些执行环节

+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+