refactor: 引入 enum_dispatch 静态分发,提升性能 (#232)
This commit is contained in:
13
Cargo.lock
generated
13
Cargo.lock
generated
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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<dyn VideoListModel>,
|
||||
Pin<Box<dyn Stream<Item = Result<VideoInfo>> + 'a>>,
|
||||
)> {
|
||||
) -> Result<(VideoListModelEnum, Pin<Box<dyn Stream<Item = Result<VideoInfo>> + '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::<i32>::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::<i32>::into(collection_item.collection_type.clone()))),
|
||||
)
|
||||
.one(connection)
|
||||
.await?
|
||||
.context("collection not found")?
|
||||
.into(),
|
||||
Box::pin(collection.into_video_stream()),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -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<dyn VideoListModel>,
|
||||
Pin<Box<dyn Stream<Item = Result<VideoInfo>> + 'a>>,
|
||||
)> {
|
||||
) -> Result<(VideoListModelEnum, Pin<Box<dyn Stream<Item = Result<VideoInfo>> + '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()),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -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<dyn VideoListModel>,
|
||||
Pin<Box<dyn Stream<Item = Result<VideoInfo>> + 'a>>,
|
||||
)> {
|
||||
) -> Result<(VideoListModelEnum, Pin<Box<dyn Stream<Item = Result<VideoInfo>> + '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,
|
||||
|
||||
@@ -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<dyn VideoListModel>,
|
||||
Pin<Box<dyn Stream<Item = Result<VideoInfo>> + 'a>>,
|
||||
)> {
|
||||
) -> Result<(VideoListModelEnum, Pin<Box<dyn Stream<Item = Result<VideoInfo>> + '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()),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -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<dyn VideoListModel>,
|
||||
Pin<Box<dyn Stream<Item = Result<VideoInfo>> + 'a>>,
|
||||
)> {
|
||||
) -> Result<(VideoListModelEnum, Pin<Box<dyn Stream<Item = Result<VideoInfo>> + '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()),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -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<VideoInfo>,
|
||||
video_list_model: &dyn VideoListModel,
|
||||
video_list_model: &VideoListModelEnum,
|
||||
connection: &DatabaseConnection,
|
||||
) -> Result<()> {
|
||||
let video_models = videos_info
|
||||
|
||||
@@ -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<Box<dyn Stream<Item = Result<VideoInfo>> + '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<page::Model>,
|
||||
connection: &DatabaseConnection,
|
||||
|
||||
Reference in New Issue
Block a user