From 40cf22a7faa38788503f0bf4e88b1d920138fafe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=B4=80=E1=B4=8D=E1=B4=9B=E1=B4=8F=E1=B4=80=E1=B4=87?= =?UTF-8?q?=CA=80?= Date: Fri, 24 Jan 2025 13:44:27 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=BC=95=E5=85=A5=20enum=5Fdispatc?= =?UTF-8?q?h=20=E9=9D=99=E6=80=81=E5=88=86=E5=8F=91=EF=BC=8C=E6=8F=90?= =?UTF-8?q?=E5=8D=87=E6=80=A7=E8=83=BD=20(#232)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 13 +++++++++ Cargo.toml | 1 + crates/bili_sync/Cargo.toml | 1 + crates/bili_sync/src/adapter/collection.rs | 30 +++++++++------------ crates/bili_sync/src/adapter/favorite.rs | 20 ++++++-------- crates/bili_sync/src/adapter/mod.rs | 21 ++++++++++++--- crates/bili_sync/src/adapter/submission.rs | 20 ++++++-------- crates/bili_sync/src/adapter/watch_later.rs | 20 ++++++-------- crates/bili_sync/src/utils/model.rs | 4 +-- crates/bili_sync/src/workflow.rs | 16 +++++------ 10 files changed, 79 insertions(+), 67 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0809e73..c2bb9ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -392,6 +392,7 @@ dependencies = [ "cookie", "cow-utils", "dirs", + "enum_dispatch", "float-ord", "futures", "handlebars", @@ -889,6 +890,18 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enum_dispatch" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa18ce2bc66555b3218614519ac839ddb759a7d6720732f979ef8d13be147ecd" +dependencies = [ + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.96", +] + [[package]] name = "equivalent" version = "1.0.1" diff --git a/Cargo.toml b/Cargo.toml index e634f19..d835f1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ clap = { version = "4.5.26", features = ["env"] } cookie = "0.18.1" cow-utils = "0.1.3" dirs = "6.0.0" +enum_dispatch = "0.3.13" float-ord = "0.3.2" futures = "0.3.31" handlebars = "6.3.0" diff --git a/crates/bili_sync/Cargo.toml b/crates/bili_sync/Cargo.toml index be8f063..bc92d98 100644 --- a/crates/bili_sync/Cargo.toml +++ b/crates/bili_sync/Cargo.toml @@ -19,6 +19,7 @@ clap = { workspace = true } cookie = { workspace = true } cow-utils = { workspace = true } dirs = { workspace = true } +enum_dispatch = { workspace = true } float-ord = { workspace = true } futures = { workspace = true } handlebars = { workspace = true } diff --git a/crates/bili_sync/src/adapter/collection.rs b/crates/bili_sync/src/adapter/collection.rs index a5e29a2..88d514c 100644 --- a/crates/bili_sync/src/adapter/collection.rs +++ b/crates/bili_sync/src/adapter/collection.rs @@ -9,7 +9,7 @@ use sea_orm::sea_query::{OnConflict, SimpleExpr}; use sea_orm::ActiveValue::Set; use sea_orm::{DatabaseConnection, Unchanged}; -use crate::adapter::{VideoListModel, _ActiveModel}; +use crate::adapter::{VideoListModel, VideoListModelEnum, _ActiveModel}; use crate::bilibili::{BiliClient, Collection, CollectionItem, CollectionType, VideoInfo}; impl VideoListModel for collection::Model { @@ -98,10 +98,7 @@ pub(super) async fn collection_from<'a>( path: &Path, bili_client: &'a BiliClient, connection: &DatabaseConnection, -) -> Result<( - Box, - Pin> + 'a>>, -)> { +) -> Result<(VideoListModelEnum, Pin> + 'a>>)> { let collection = Collection::new(bili_client, collection_item); let collection_info = collection.get_info().await?; collection::Entity::insert(collection::ActiveModel { @@ -124,18 +121,17 @@ pub(super) async fn collection_from<'a>( .exec(connection) .await?; Ok(( - Box::new( - collection::Entity::find() - .filter( - collection::Column::SId - .eq(collection_item.sid.clone()) - .and(collection::Column::MId.eq(collection_item.mid.clone())) - .and(collection::Column::Type.eq(Into::::into(collection_item.collection_type.clone()))), - ) - .one(connection) - .await? - .context("collection not found")?, - ), + collection::Entity::find() + .filter( + collection::Column::SId + .eq(collection_item.sid.clone()) + .and(collection::Column::MId.eq(collection_item.mid.clone())) + .and(collection::Column::Type.eq(Into::::into(collection_item.collection_type.clone()))), + ) + .one(connection) + .await? + .context("collection not found")? + .into(), Box::pin(collection.into_video_stream()), )) } diff --git a/crates/bili_sync/src/adapter/favorite.rs b/crates/bili_sync/src/adapter/favorite.rs index 6a8fe4e..008a989 100644 --- a/crates/bili_sync/src/adapter/favorite.rs +++ b/crates/bili_sync/src/adapter/favorite.rs @@ -9,7 +9,7 @@ use sea_orm::sea_query::{OnConflict, SimpleExpr}; use sea_orm::ActiveValue::Set; use sea_orm::{DatabaseConnection, Unchanged}; -use crate::adapter::{VideoListModel, _ActiveModel}; +use crate::adapter::{VideoListModel, VideoListModelEnum, _ActiveModel}; use crate::bilibili::{BiliClient, FavoriteList, VideoInfo}; impl VideoListModel for favorite::Model { @@ -70,10 +70,7 @@ pub(super) async fn favorite_from<'a>( path: &Path, bili_client: &'a BiliClient, connection: &DatabaseConnection, -) -> Result<( - Box, - Pin> + 'a>>, -)> { +) -> Result<(VideoListModelEnum, Pin> + 'a>>)> { let favorite = FavoriteList::new(bili_client, fid.to_owned()); let favorite_info = favorite.get_info().await?; favorite::Entity::insert(favorite::ActiveModel { @@ -90,13 +87,12 @@ pub(super) async fn favorite_from<'a>( .exec(connection) .await?; Ok(( - Box::new( - favorite::Entity::find() - .filter(favorite::Column::FId.eq(favorite_info.id)) - .one(connection) - .await? - .context("favorite not found")?, - ), + favorite::Entity::find() + .filter(favorite::Column::FId.eq(favorite_info.id)) + .one(connection) + .await? + .context("favorite not found")? + .into(), Box::pin(favorite.into_video_stream()), )) } diff --git a/crates/bili_sync/src/adapter/mod.rs b/crates/bili_sync/src/adapter/mod.rs index 3e89a3e..aac112c 100644 --- a/crates/bili_sync/src/adapter/mod.rs +++ b/crates/bili_sync/src/adapter/mod.rs @@ -7,17 +7,33 @@ use std::path::Path; use std::pin::Pin; use anyhow::Result; +use enum_dispatch::enum_dispatch; use futures::Stream; use sea_orm::entity::prelude::*; use sea_orm::sea_query::SimpleExpr; use sea_orm::DatabaseConnection; +#[rustfmt::skip] +use bili_sync_entity::collection::Model as Collection; +use bili_sync_entity::favorite::Model as Favorite; +use bili_sync_entity::submission::Model as Submission; +use bili_sync_entity::watch_later::Model as WatchLater; + use crate::adapter::collection::collection_from; use crate::adapter::favorite::favorite_from; use crate::adapter::submission::submission_from; use crate::adapter::watch_later::watch_later_from; use crate::bilibili::{BiliClient, CollectionItem, VideoInfo}; +#[enum_dispatch] +pub enum VideoListModelEnum { + Favorite, + Collection, + Submission, + WatchLater, +} + +#[enum_dispatch(VideoListModelEnum)] pub trait VideoListModel { /// 获取特定视频列表的筛选条件 fn filter_expr(&self) -> SimpleExpr; @@ -67,10 +83,7 @@ pub async fn video_list_from<'a>( path: &Path, bili_client: &'a BiliClient, connection: &DatabaseConnection, -) -> Result<( - Box, - Pin> + 'a>>, -)> { +) -> Result<(VideoListModelEnum, Pin> + 'a>>)> { match args { Args::Favorite { fid } => favorite_from(fid, path, bili_client, connection).await, Args::Collection { collection_item } => collection_from(collection_item, path, bili_client, connection).await, diff --git a/crates/bili_sync/src/adapter/submission.rs b/crates/bili_sync/src/adapter/submission.rs index 18dffe3..aeb58fb 100644 --- a/crates/bili_sync/src/adapter/submission.rs +++ b/crates/bili_sync/src/adapter/submission.rs @@ -9,7 +9,7 @@ use sea_orm::sea_query::{OnConflict, SimpleExpr}; use sea_orm::ActiveValue::Set; use sea_orm::{DatabaseConnection, Unchanged}; -use crate::adapter::{VideoListModel, _ActiveModel}; +use crate::adapter::{VideoListModel, VideoListModelEnum, _ActiveModel}; use crate::bilibili::{BiliClient, Submission, VideoInfo}; impl VideoListModel for submission::Model { @@ -82,10 +82,7 @@ pub(super) async fn submission_from<'a>( path: &Path, bili_client: &'a BiliClient, connection: &DatabaseConnection, -) -> Result<( - Box, - Pin> + 'a>>, -)> { +) -> Result<(VideoListModelEnum, Pin> + 'a>>)> { let submission = Submission::new(bili_client, upper_id.to_owned()); let upper = submission.get_info().await?; submission::Entity::insert(submission::ActiveModel { @@ -102,13 +99,12 @@ pub(super) async fn submission_from<'a>( .exec(connection) .await?; Ok(( - Box::new( - submission::Entity::find() - .filter(submission::Column::UpperId.eq(upper.mid)) - .one(connection) - .await? - .context("submission not found")?, - ), + submission::Entity::find() + .filter(submission::Column::UpperId.eq(upper.mid)) + .one(connection) + .await? + .context("submission not found")? + .into(), Box::pin(submission.into_video_stream()), )) } diff --git a/crates/bili_sync/src/adapter/watch_later.rs b/crates/bili_sync/src/adapter/watch_later.rs index f65bb9c..de0ec38 100644 --- a/crates/bili_sync/src/adapter/watch_later.rs +++ b/crates/bili_sync/src/adapter/watch_later.rs @@ -9,7 +9,7 @@ use sea_orm::sea_query::{OnConflict, SimpleExpr}; use sea_orm::ActiveValue::Set; use sea_orm::{DatabaseConnection, Unchanged}; -use crate::adapter::{VideoListModel, _ActiveModel}; +use crate::adapter::{VideoListModel, VideoListModelEnum, _ActiveModel}; use crate::bilibili::{BiliClient, VideoInfo, WatchLater}; impl VideoListModel for watch_later::Model { @@ -66,10 +66,7 @@ pub(super) async fn watch_later_from<'a>( path: &Path, bili_client: &'a BiliClient, connection: &DatabaseConnection, -) -> Result<( - Box, - Pin> + 'a>>, -)> { +) -> Result<(VideoListModelEnum, Pin> + 'a>>)> { let watch_later = WatchLater::new(bili_client); watch_later::Entity::insert(watch_later::ActiveModel { id: Set(1), @@ -84,13 +81,12 @@ pub(super) async fn watch_later_from<'a>( .exec(connection) .await?; Ok(( - Box::new( - watch_later::Entity::find() - .filter(watch_later::Column::Id.eq(1)) - .one(connection) - .await? - .context("watch_later not found")?, - ), + watch_later::Entity::find() + .filter(watch_later::Column::Id.eq(1)) + .one(connection) + .await? + .context("watch_later not found")? + .into(), Box::pin(watch_later.into_video_stream()), )) } diff --git a/crates/bili_sync/src/utils/model.rs b/crates/bili_sync/src/utils/model.rs index ec0f95d..3379bb5 100644 --- a/crates/bili_sync/src/utils/model.rs +++ b/crates/bili_sync/src/utils/model.rs @@ -4,7 +4,7 @@ use sea_orm::entity::prelude::*; use sea_orm::sea_query::{OnConflict, SimpleExpr}; use sea_orm::DatabaseTransaction; -use crate::adapter::VideoListModel; +use crate::adapter::{VideoListModel, VideoListModelEnum}; use crate::bilibili::{PageInfo, VideoInfo}; use crate::utils::status::STATUS_COMPLETED; @@ -50,7 +50,7 @@ pub async fn filter_unhandled_video_pages( /// 尝试创建 Video Model,如果发生冲突则忽略 pub async fn create_videos( videos_info: Vec, - video_list_model: &dyn VideoListModel, + video_list_model: &VideoListModelEnum, connection: &DatabaseConnection, ) -> Result<()> { let video_models = videos_info diff --git a/crates/bili_sync/src/workflow.rs b/crates/bili_sync/src/workflow.rs index ef13f5b..f83eeb4 100644 --- a/crates/bili_sync/src/workflow.rs +++ b/crates/bili_sync/src/workflow.rs @@ -12,7 +12,7 @@ use sea_orm::TransactionTrait; use tokio::fs; use tokio::sync::{Mutex, Semaphore}; -use crate::adapter::{video_list_from, Args, VideoListModel}; +use crate::adapter::{video_list_from, Args, VideoListModel, VideoListModelEnum}; use crate::bilibili::{BestStream, BiliClient, BiliError, Dimension, PageInfo, Video, VideoInfo}; use crate::config::{PathSafeTemplate, ARGS, CONFIG, TEMPLATE}; use crate::downloader::Downloader; @@ -35,21 +35,21 @@ pub async fn process_video_list( // 从参数中获取视频列表的 Model 与视频流 let (video_list_model, video_streams) = video_list_from(args, path, bili_client, connection).await?; // 从视频流中获取新视频的简要信息,写入数据库 - refresh_video_list(video_list_model.as_ref(), video_streams, connection).await?; + refresh_video_list(&video_list_model, video_streams, connection).await?; // 单独请求视频详情接口,获取视频的详情信息与所有的分页,写入数据库 - fetch_video_details(bili_client, video_list_model.as_ref(), connection).await?; + fetch_video_details(bili_client, &video_list_model, connection).await?; if ARGS.scan_only { warn!("已开启仅扫描模式,跳过视频下载..."); } else { // 从数据库中查找所有未下载的视频与分页,下载并处理 - download_unprocessed_videos(bili_client, video_list_model.as_ref(), connection).await?; + download_unprocessed_videos(bili_client, &video_list_model, connection).await?; } Ok(()) } /// 请求接口,获取视频列表中所有新添加的视频信息,将其写入数据库 pub async fn refresh_video_list<'a>( - video_list_model: &dyn VideoListModel, + video_list_model: &VideoListModelEnum, video_streams: Pin> + 'a>>, connection: &DatabaseConnection, ) -> Result<()> { @@ -98,7 +98,7 @@ pub async fn refresh_video_list<'a>( /// 筛选出所有未获取到全部信息的视频,尝试补充其详细信息 pub async fn fetch_video_details( bili_client: &BiliClient, - video_list_model: &dyn VideoListModel, + video_list_model: &VideoListModelEnum, connection: &DatabaseConnection, ) -> Result<()> { video_list_model.log_fetch_video_start(); @@ -143,7 +143,7 @@ pub async fn fetch_video_details( /// 下载所有未处理成功的视频 pub async fn download_unprocessed_videos( bili_client: &BiliClient, - video_list_model: &dyn VideoListModel, + video_list_model: &VideoListModelEnum, connection: &DatabaseConnection, ) -> Result<()> { video_list_model.log_download_video_start(); @@ -201,7 +201,7 @@ pub async fn download_unprocessed_videos( #[allow(clippy::too_many_arguments)] pub async fn download_video_pages( bili_client: &BiliClient, - video_list_model: &dyn VideoListModel, + video_list_model: &VideoListModelEnum, video_model: video::Model, pages: Vec, connection: &DatabaseConnection,