From ab20b85b39fd2140a055acfcdf1e28dfd4a4e532 Mon Sep 17 00:00:00 2001 From: amtoaer Date: Sat, 23 Mar 2024 19:46:18 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=E7=95=A5=E5=BE=AE=E6=8E=A8=E8=BF=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/bilibili/mod.rs | 2 +- src/command.rs | 80 --------------------------- src/core/command.rs | 128 ++++++++++++++++++++++++++++++++++++++++++++ src/core/mod.rs | 1 + src/lib.rs | 2 +- src/main.rs | 4 +- 6 files changed, 133 insertions(+), 84 deletions(-) delete mode 100644 src/command.rs create mode 100644 src/core/command.rs create mode 100644 src/core/mod.rs diff --git a/src/bilibili/mod.rs b/src/bilibili/mod.rs index 542df59..d8717ea 100644 --- a/src/bilibili/mod.rs +++ b/src/bilibili/mod.rs @@ -9,5 +9,5 @@ pub use analyzer::{ }; pub use client::{BiliClient, Client}; pub use credential::Credential; -pub use favorite_list::FavoriteList; +pub use favorite_list::{FavoriteList, FavoriteListInfo, VideoInfo}; pub use video::Video; diff --git a/src/command.rs b/src/command.rs deleted file mode 100644 index 67e2c58..0000000 --- a/src/command.rs +++ /dev/null @@ -1,80 +0,0 @@ -use std::path::Path; -use std::sync::Arc; - -use entity::*; -use futures_util::{pin_mut, StreamExt}; -use migration::OnConflict; -use sea_orm::entity::prelude::*; -use sea_orm::ActiveValue::Set; - -use crate::bilibili::{BiliClient, FavoriteList}; -use crate::Result; - -pub async fn handle_favorite( - bili_client: Arc, - fid: i32, - connection: Arc, -) -> Result<()> { - let favorite_list = FavoriteList::new(bili_client.clone(), fid.to_string()); - let info = favorite_list.get_info().await?; - let favorite_obj = favorite::Entity::insert(favorite::ActiveModel { - f_id: Set(fid), - name: Set(info.title), - path: Set("/home/amtoaer/Documents/code/rust/bili-sync/video".to_string()), - enabled: Set(true), - ..Default::default() - }) - .on_conflict( - OnConflict::column(favorite::Column::FId) - .update_column(favorite::Column::Name) - .update_column(favorite::Column::Path) - .update_column(favorite::Column::Enabled) - .to_owned(), - ) - .exec_with_returning(connection.as_ref()) - .await?; - println!( - "Hi there! I'm going to scan this favorite: {:?}", - favorite_obj - ); - let video_stream = favorite_list.into_video_stream(); - pin_mut!(video_stream); - while let Some(v) = video_stream.next().await { - let not_exists = video::Entity::find() - .filter( - video::Column::Bvid - .eq(&v.bvid) - .and(video::Column::FavoriteId.eq(fid)), - ) - .count(connection.as_ref()) - .await - .is_ok_and(|x| x == 0); - if !not_exists { - break; - } - let _video_obj = video::Entity::insert(video::ActiveModel { - favorite_id: Set(fid), - bvid: Set(v.bvid), - path: Set(Path::new(favorite_obj.path.as_str()) - .join(&v.title) - .to_str() - .unwrap() - .to_string()), - name: Set(v.title), - category: Set(v.vtype.to_string()), - intro: Set(v.intro), - cover: Set(v.cover), - ctime: Set(v.ctime.to_string()), - pubtime: Set(v.pubtime.to_string()), - favtime: Set(v.fav_time.to_string()), - downloaded: Set(false), - valid: Set(true), - tags: Set("[]".to_string()), - single_page: Set(false), - ..Default::default() - }) - .exec_with_returning(connection.as_ref()) - .await?; - } - Ok(()) -} diff --git a/src/core/command.rs b/src/core/command.rs new file mode 100644 index 0000000..e13d2c9 --- /dev/null +++ b/src/core/command.rs @@ -0,0 +1,128 @@ +use std::collections::HashSet; +use std::path::Path; +use std::sync::Arc; + +use entity::*; +use futures_util::{pin_mut, StreamExt}; +use migration::OnConflict; +use sea_orm::entity::prelude::*; +use sea_orm::ActiveValue::Set; +use sea_orm::QuerySelect; + +use crate::bilibili::{BiliClient, FavoriteList, FavoriteListInfo, VideoInfo}; +use crate::Result; + +pub async fn process_favorite( + bili_client: Arc, + fid: i32, + connection: Arc, +) -> Result<()> { + let favorite_list = FavoriteList::new(bili_client.clone(), fid.to_string()); + let info = favorite_list.get_info().await?; + let favorite_obj = handle_favorite_info(&info, connection.as_ref()).await?; + println!( + "Hi there! I'm going to scan this favorite: {:?}", + favorite_obj + ); + let video_stream = favorite_list.into_video_stream().chunks(10); + pin_mut!(video_stream); + while let Some(videos_info) = video_stream.next().await { + let exist_bvids_pubtimes = + exists_bvids_favtime(&videos_info, fid, connection.as_ref()).await?; + let video_info_to_create = videos_info + .iter() + .filter(|v| !exist_bvids_pubtimes.contains(&(v.bvid.clone(), v.fav_time.to_string()))) + .collect::>(); + let len = video_info_to_create.len(); + if !video_info_to_create.is_empty() { + create_videos(video_info_to_create, &favorite_obj, connection.as_ref()).await?; + } + if videos_info.len() != len { + break; + } + } + Ok(()) +} + +// 根据获得的收藏夹信息,插入或更新数据库中的收藏夹,并返回收藏夹对象 +async fn handle_favorite_info( + info: &FavoriteListInfo, + connection: &DatabaseConnection, +) -> Result { + Ok(favorite::Entity::insert(favorite::ActiveModel { + f_id: Set(info.id as i32), + name: Set(info.title.to_string()), + path: Set("/home/amtoaer/Documents/code/rust/bili-sync/video".to_string()), + enabled: Set(true), + ..Default::default() + }) + .on_conflict( + OnConflict::column(favorite::Column::FId) + .update_column(favorite::Column::Name) + .update_column(favorite::Column::Path) + .update_column(favorite::Column::Enabled) + .to_owned(), + ) + .exec_with_returning(connection) + .await?) +} + +// 获取数据库中存在的与该视频 favorite_id 和 bvid 重合的视频 +async fn exists_bvids_favtime( + videos_info: &[VideoInfo], + fid: i32, + connection: &DatabaseConnection, +) -> Result> { + let bvids = videos_info + .iter() + .map(|v| v.bvid.clone()) + .collect::>(); + let exist_bvid_favtime = video::Entity::find() + .filter( + video::Column::FavoriteId + .eq(fid) + .and(video::Column::Bvid.is_in(bvids)), + ) + .select_only() + .columns([video::Column::Bvid, video::Column::Favtime]) + .all(connection) + .await? + .into_iter() + .map(|v| (v.bvid, v.favtime)) + .collect::>(); + Ok(exist_bvid_favtime) +} + +async fn create_videos( + videos_info: Vec<&VideoInfo>, + favorite_obj: &favorite::Model, + connection: &DatabaseConnection, +) -> Result { + let video_models = videos_info + .iter() + .map(move |v| video::ActiveModel { + favorite_id: Set(favorite_obj.id), + bvid: Set(v.bvid.clone()), + path: Set(Path::new(favorite_obj.path.as_str()) + .join(&v.title) + .to_str() + .unwrap() + .to_string()), + name: Set(v.title.clone()), + category: Set(v.vtype.to_string()), + intro: Set(v.intro.clone()), + cover: Set(v.cover.clone()), + ctime: Set(v.ctime.to_string()), + pubtime: Set(v.pubtime.to_string()), + favtime: Set(v.fav_time.to_string()), + downloaded: Set(false), + valid: Set(true), + tags: Set("[]".to_string()), + single_page: Set(false), + ..Default::default() + }) + .collect::>(); + Ok(video::Entity::insert_many(video_models) + .exec_without_returning(connection) + .await?) +} diff --git a/src/core/mod.rs b/src/core/mod.rs new file mode 100644 index 0000000..9fe7961 --- /dev/null +++ b/src/core/mod.rs @@ -0,0 +1 @@ +pub mod command; diff --git a/src/lib.rs b/src/lib.rs index 09d32cc..ccc2d9d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ use std::error; pub mod bilibili; -pub mod command; +pub mod core; pub mod database; pub mod downloader; diff --git a/src/main.rs b/src/main.rs index 9aa8ffd..7dc295b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use bili_sync::bilibili::BiliClient; -use bili_sync::command::handle_favorite; +use bili_sync::core::command::process_favorite; use bili_sync::database::database_connection; #[tokio::main] @@ -10,7 +10,7 @@ async fn main() -> ! { let bili_client = Arc::new(BiliClient::new(None)); loop { for fid in [52642258] { - let _ = handle_favorite(bili_client.clone(), fid, connection.clone()).await; + let _ = process_favorite(bili_client.clone(), fid, connection.clone()).await; } tokio::time::sleep(std::time::Duration::from_secs(60)).await; }