feat: 写入 upper 头像,整理代码

This commit is contained in:
amtoaer
2024-03-27 23:26:22 +08:00
parent 986bb11a13
commit 29d893e3fc
4 changed files with 92 additions and 45 deletions
+1
View File
@@ -41,6 +41,7 @@ pub struct VideoInfo {
pub struct Upper { pub struct Upper {
pub mid: i32, pub mid: i32,
pub name: String, pub name: String,
pub face: String,
} }
impl FavoriteList { impl FavoriteList {
pub fn new(client: Arc<BiliClient>, fid: String) -> Self { pub fn new(client: Arc<BiliClient>, fid: String) -> Self {
+48 -22
View File
@@ -1,43 +1,60 @@
use std::sync::Arc; use std::sync::Arc;
use entity::video;
use futures_util::{pin_mut, StreamExt}; use futures_util::{pin_mut, StreamExt};
use log::info;
use sea_orm::entity::prelude::*; use sea_orm::entity::prelude::*;
use sea_orm::ActiveValue::Set;
use crate::bilibili::{BiliClient, FavoriteList, Video}; use crate::bilibili::{BiliClient, FavoriteList, Video};
use crate::core::utils::{ use crate::core::utils::{
create_video_pages, create_videos, exists_bvids_favtime, filter_videos, handle_favorite_info, create_video_pages, create_videos, exist_labels, filter_videos, handle_favorite_info,
}; };
use crate::Result; use crate::Result;
pub async fn process_favorite( pub async fn process_favorite(
bili_client: Arc<BiliClient>, bili_client: Arc<BiliClient>,
fid: i32, fid: &str,
connection: Arc<DatabaseConnection>, connection: Arc<DatabaseConnection>,
) -> Result<()> { ) -> Result<()> {
let favorite_list = FavoriteList::new(bili_client.clone(), fid.to_string()); refresh_favorite(bili_client.clone(), fid, connection.clone()).await?;
let info = favorite_list.get_info().await?; download_favorite(bili_client.clone(), fid, connection.clone()).await?;
let favorite_obj = handle_favorite_info(&info, connection.as_ref()).await?; Ok(())
println!( }
"Hi there! I'm going to scan this favorite: {:?}",
favorite_obj pub async fn refresh_favorite(
); bili_client: Arc<BiliClient>,
let video_stream = favorite_list.into_video_stream().chunks(10); fid: &str,
connection: Arc<DatabaseConnection>,
) -> Result<()> {
let bili_favorite_list = FavoriteList::new(bili_client.clone(), fid.to_owned());
let favorite_list_info = bili_favorite_list.get_info().await?;
let favorite_model = handle_favorite_info(&favorite_list_info, connection.as_ref()).await?;
info!("Scan the favorite: {fid}");
let video_stream = bili_favorite_list.into_video_stream().chunks(10);
pin_mut!(video_stream); pin_mut!(video_stream);
while let Some(videos_info) = video_stream.next().await { while let Some(videos_info) = video_stream.next().await {
let exist_bvids_pubtimes = let exist_labels = exist_labels(&videos_info, &favorite_model, connection.as_ref()).await?;
exists_bvids_favtime(&videos_info, favorite_obj.id, connection.as_ref()).await?;
let should_break = videos_info let should_break = videos_info
.iter() .iter()
// 出现 bvid 和 fav_time 都相同的记录,说明已经到达了上次处理到的位置 .any(|v| exist_labels.contains(&(v.bvid.clone(), v.fav_time.naive_utc())));
.any(|v| exist_bvids_pubtimes.contains(&(v.bvid.clone(), v.fav_time.naive_utc()))); create_videos(&videos_info, &favorite_model, connection.as_ref()).await?;
create_videos(&videos_info, &favorite_obj, connection.as_ref()).await?; let unrefreshed_video_models = filter_videos(
let all_unprocessed_videos = &videos_info,
filter_videos(&videos_info, &favorite_obj, true, true, connection.as_ref()).await?; &favorite_model,
if !all_unprocessed_videos.is_empty() { true,
for video in all_unprocessed_videos { true,
let bili_video = Video::new(bili_client.clone(), video.bvid.clone()); connection.as_ref(),
let pages = bili_video.get_pages().await?; )
create_video_pages(&pages, &video, connection.as_ref()).await?; .await?;
if !unrefreshed_video_models.is_empty() {
for video_model in unrefreshed_video_models {
let bili_video = Video::new(bili_client.clone(), video_model.bvid.clone());
let pages_info = bili_video.get_pages().await?;
create_video_pages(&pages_info, &video_model, connection.as_ref()).await?;
let mut video_active_model: video::ActiveModel = video_model.into();
video_active_model.single_page = Set(Some(pages_info.len() == 1));
video_active_model.save(connection.as_ref()).await?;
} }
} }
if should_break { if should_break {
@@ -46,3 +63,12 @@ pub async fn process_favorite(
} }
Ok(()) Ok(())
} }
#[allow(unused_variables)]
pub async fn download_favorite(
bili_client: Arc<BiliClient>,
fid: &str,
connection: Arc<DatabaseConnection>,
) -> Result<()> {
todo!();
}
+39 -21
View File
@@ -10,7 +10,7 @@ use sea_orm::QuerySelect;
use crate::bilibili::{FavoriteListInfo, PageInfo, VideoInfo}; use crate::bilibili::{FavoriteListInfo, PageInfo, VideoInfo};
use crate::Result; use crate::Result;
// 根据获得的收藏夹信息,插入或更新数据库中的收藏夹,并返回收藏夹对象 /// 根据获得的收藏夹信息,插入或更新数据库中的收藏夹,并返回收藏夹对象
pub async fn handle_favorite_info( pub async fn handle_favorite_info(
info: &FavoriteListInfo, info: &FavoriteListInfo,
connection: &DatabaseConnection, connection: &DatabaseConnection,
@@ -40,20 +40,21 @@ pub async fn handle_favorite_info(
.unwrap()) .unwrap())
} }
// 获取数据库中存在的与该视频 favorite_id 和 bvid 重合的视频 /// 获取数据库中存在的与该视频 favorite_id 和 bvid 重合的视频中的 bvid 和 favtime
pub async fn exists_bvids_favtime( /// 如果 bvid 和 favtime 均相同,说明到达了上次处理到的位置
pub async fn exist_labels(
videos_info: &[VideoInfo], videos_info: &[VideoInfo],
fid: i32, favorite_model: &favorite::Model,
connection: &DatabaseConnection, connection: &DatabaseConnection,
) -> Result<HashSet<(String, DateTime)>> { ) -> Result<HashSet<(String, DateTime)>> {
let bvids = videos_info let bvids = videos_info
.iter() .iter()
.map(|v| v.bvid.clone()) .map(|v| v.bvid.clone())
.collect::<Vec<String>>(); .collect::<Vec<String>>();
let exist_bvid_favtime = video::Entity::find() let exist_labels = video::Entity::find()
.filter( .filter(
video::Column::FavoriteId video::Column::FavoriteId
.eq(fid) .eq(favorite_model.id)
.and(video::Column::Bvid.is_in(bvids)), .and(video::Column::Bvid.is_in(bvids)),
) )
.select_only() .select_only()
@@ -63,21 +64,21 @@ pub async fn exists_bvids_favtime(
.await? .await?
.into_iter() .into_iter()
.collect::<HashSet<(String, DateTime)>>(); .collect::<HashSet<(String, DateTime)>>();
Ok(exist_bvid_favtime) Ok(exist_labels)
} }
// 尝试创建 Video Model,如果发生冲突则忽略 /// 尝试创建 Video Model,如果发生冲突则忽略
pub async fn create_videos( pub async fn create_videos(
videos_info: &[VideoInfo], videos_info: &[VideoInfo],
favorite_obj: &favorite::Model, favorite: &favorite::Model,
connection: &DatabaseConnection, connection: &DatabaseConnection,
) -> Result<()> { ) -> Result<()> {
let video_models = videos_info let video_models = videos_info
.iter() .iter()
.map(move |v| video::ActiveModel { .map(move |v| video::ActiveModel {
favorite_id: Set(favorite_obj.id), favorite_id: Set(favorite.id),
bvid: Set(v.bvid.clone()), bvid: Set(v.bvid.clone()),
path: Set(Path::new(favorite_obj.path.as_str()) path: Set(Path::new(favorite.path.as_str())
.join(&v.title) .join(&v.title)
.to_str() .to_str()
.unwrap() .unwrap()
@@ -95,6 +96,7 @@ pub async fn create_videos(
single_page: Set(None), single_page: Set(None),
upper_id: Set(v.upper.mid), upper_id: Set(v.upper.mid),
upper_name: Set(v.upper.name.clone()), upper_name: Set(v.upper.name.clone()),
upper_face: Set(v.upper.face.clone()),
..Default::default() ..Default::default()
}) })
.collect::<Vec<video::ActiveModel>>(); .collect::<Vec<video::ActiveModel>>();
@@ -110,10 +112,10 @@ pub async fn create_videos(
Ok(()) Ok(())
} }
// 筛选所有符合条件的视频 /// 筛选所有符合条件的视频
pub async fn filter_videos( pub async fn filter_videos(
videos_info: &[VideoInfo], videos_info: &[VideoInfo],
favorite_obj: &favorite::Model, favorite_model: &favorite::Model,
only_unhandled: bool, only_unhandled: bool,
only_no_page: bool, only_no_page: bool,
connection: &DatabaseConnection, connection: &DatabaseConnection,
@@ -123,7 +125,7 @@ pub async fn filter_videos(
.map(|v| v.bvid.clone()) .map(|v| v.bvid.clone())
.collect::<Vec<String>>(); .collect::<Vec<String>>();
let mut condition = video::Column::FavoriteId let mut condition = video::Column::FavoriteId
.eq(favorite_obj.id) .eq(favorite_model.id)
.and(video::Column::Bvid.is_in(bvids)) .and(video::Column::Bvid.is_in(bvids))
.and(video::Column::Valid.eq(true)); .and(video::Column::Valid.eq(true));
if only_unhandled { if only_unhandled {
@@ -137,26 +139,26 @@ pub async fn filter_videos(
.all(connection) .all(connection)
.await?) .await?)
} }
/// 创建视频的所有分 P
pub async fn create_video_pages( pub async fn create_video_pages(
pages: &[PageInfo], pages_info: &[PageInfo],
video_obj: &video::Model, video_model: &video::Model,
connection: &DatabaseConnection, connection: &DatabaseConnection,
) -> Result<()> { ) -> Result<()> {
let page_models = pages let page_models = pages_info
.iter() .iter()
.map(move |p| page::ActiveModel { .map(move |p| page::ActiveModel {
video_id: Set(video_obj.id), video_id: Set(video_model.id),
cid: Set(p.cid), cid: Set(p.cid),
pid: Set(p.page), pid: Set(p.page),
name: Set(p.name.clone()), name: Set(p.name.clone()),
path: Set(Path::new(video_obj.path.as_str()) path: Set(Path::new(video_model.path.as_str())
.join(&p.name) .join(&p.name)
.to_str() .to_str()
.unwrap() .unwrap()
.to_string()), .to_string()),
image: Set(p.first_frame.clone()), image: Set(p.first_frame.clone()),
valid: Set(video_obj.valid), valid: Set(video_model.valid),
download_status: Set(0), download_status: Set(0),
..Default::default() ..Default::default()
}) })
@@ -172,3 +174,19 @@ pub async fn create_video_pages(
.await?; .await?;
Ok(()) Ok(())
} }
/// 获取所有未处理的视频和页
pub async fn unhandled_videos_pages(
favorite_model: &favorite::Model,
connection: &DatabaseConnection,
) -> Result<Vec<video::Model>> {
Ok(video::Entity::find()
.filter(
video::Column::FavoriteId
.eq(favorite_model.id)
.and(video::Column::Valid.eq(true))
.and(video::Column::Handled.eq(false)),
)
.all(connection)
.await?)
}
+4 -2
View File
@@ -3,16 +3,18 @@ use std::sync::Arc;
use bili_sync::bilibili::BiliClient; use bili_sync::bilibili::BiliClient;
use bili_sync::core::command::process_favorite; use bili_sync::core::command::process_favorite;
use bili_sync::database::database_connection; use bili_sync::database::database_connection;
use log::error;
#[tokio::main] #[tokio::main]
async fn main() -> ! { async fn main() -> ! {
env_logger::init();
let connection = Arc::new(database_connection().await.unwrap()); let connection = Arc::new(database_connection().await.unwrap());
let bili_client = Arc::new(BiliClient::new(None)); let bili_client = Arc::new(BiliClient::new(None));
loop { loop {
for fid in [52642258] { for fid in ["52642258"] {
let res = process_favorite(bili_client.clone(), fid, connection.clone()).await; let res = process_favorite(bili_client.clone(), fid, connection.clone()).await;
if let Err(e) = res { if let Err(e) = res {
eprintln!("Error: {:?}", e); error!("Error: {e}");
} }
} }
tokio::time::sleep(std::time::Duration::from_secs(600)).await; tokio::time::sleep(std::time::Duration::from_secs(600)).await;