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

View File

@@ -41,6 +41,7 @@ pub struct VideoInfo {
pub struct Upper {
pub mid: i32,
pub name: String,
pub face: String,
}
impl FavoriteList {
pub fn new(client: Arc<BiliClient>, fid: String) -> Self {

View File

@@ -1,43 +1,60 @@
use std::sync::Arc;
use entity::video;
use futures_util::{pin_mut, StreamExt};
use log::info;
use sea_orm::entity::prelude::*;
use sea_orm::ActiveValue::Set;
use crate::bilibili::{BiliClient, FavoriteList, Video};
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;
pub async fn process_favorite(
bili_client: Arc<BiliClient>,
fid: i32,
fid: &str,
connection: Arc<DatabaseConnection>,
) -> 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);
refresh_favorite(bili_client.clone(), fid, connection.clone()).await?;
download_favorite(bili_client.clone(), fid, connection.clone()).await?;
Ok(())
}
pub async fn refresh_favorite(
bili_client: Arc<BiliClient>,
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);
while let Some(videos_info) = video_stream.next().await {
let exist_bvids_pubtimes =
exists_bvids_favtime(&videos_info, favorite_obj.id, connection.as_ref()).await?;
let exist_labels = exist_labels(&videos_info, &favorite_model, connection.as_ref()).await?;
let should_break = videos_info
.iter()
// 出现 bvid 和 fav_time 都相同的记录,说明已经到达了上次处理到的位置
.any(|v| exist_bvids_pubtimes.contains(&(v.bvid.clone(), v.fav_time.naive_utc())));
create_videos(&videos_info, &favorite_obj, connection.as_ref()).await?;
let all_unprocessed_videos =
filter_videos(&videos_info, &favorite_obj, true, true, connection.as_ref()).await?;
if !all_unprocessed_videos.is_empty() {
for video in all_unprocessed_videos {
let bili_video = Video::new(bili_client.clone(), video.bvid.clone());
let pages = bili_video.get_pages().await?;
create_video_pages(&pages, &video, connection.as_ref()).await?;
.any(|v| exist_labels.contains(&(v.bvid.clone(), v.fav_time.naive_utc())));
create_videos(&videos_info, &favorite_model, connection.as_ref()).await?;
let unrefreshed_video_models = filter_videos(
&videos_info,
&favorite_model,
true,
true,
connection.as_ref(),
)
.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 {
@@ -46,3 +63,12 @@ pub async fn process_favorite(
}
Ok(())
}
#[allow(unused_variables)]
pub async fn download_favorite(
bili_client: Arc<BiliClient>,
fid: &str,
connection: Arc<DatabaseConnection>,
) -> Result<()> {
todo!();
}

View File

@@ -10,7 +10,7 @@ use sea_orm::QuerySelect;
use crate::bilibili::{FavoriteListInfo, PageInfo, VideoInfo};
use crate::Result;
// 根据获得的收藏夹信息,插入或更新数据库中的收藏夹,并返回收藏夹对象
/// 根据获得的收藏夹信息,插入或更新数据库中的收藏夹,并返回收藏夹对象
pub async fn handle_favorite_info(
info: &FavoriteListInfo,
connection: &DatabaseConnection,
@@ -40,20 +40,21 @@ pub async fn handle_favorite_info(
.unwrap())
}
// 获取数据库中存在的与该视频 favorite_id 和 bvid 重合的视频
pub async fn exists_bvids_favtime(
/// 获取数据库中存在的与该视频 favorite_id 和 bvid 重合的视频中的 bvid 和 favtime
/// 如果 bvidfavtime 均相同,说明到达了上次处理到的位置
pub async fn exist_labels(
videos_info: &[VideoInfo],
fid: i32,
favorite_model: &favorite::Model,
connection: &DatabaseConnection,
) -> Result<HashSet<(String, DateTime)>> {
let bvids = videos_info
.iter()
.map(|v| v.bvid.clone())
.collect::<Vec<String>>();
let exist_bvid_favtime = video::Entity::find()
let exist_labels = video::Entity::find()
.filter(
video::Column::FavoriteId
.eq(fid)
.eq(favorite_model.id)
.and(video::Column::Bvid.is_in(bvids)),
)
.select_only()
@@ -63,21 +64,21 @@ pub async fn exists_bvids_favtime(
.await?
.into_iter()
.collect::<HashSet<(String, DateTime)>>();
Ok(exist_bvid_favtime)
Ok(exist_labels)
}
// 尝试创建 Video Model如果发生冲突则忽略
/// 尝试创建 Video Model如果发生冲突则忽略
pub async fn create_videos(
videos_info: &[VideoInfo],
favorite_obj: &favorite::Model,
favorite: &favorite::Model,
connection: &DatabaseConnection,
) -> Result<()> {
let video_models = videos_info
.iter()
.map(move |v| video::ActiveModel {
favorite_id: Set(favorite_obj.id),
favorite_id: Set(favorite.id),
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)
.to_str()
.unwrap()
@@ -95,6 +96,7 @@ pub async fn create_videos(
single_page: Set(None),
upper_id: Set(v.upper.mid),
upper_name: Set(v.upper.name.clone()),
upper_face: Set(v.upper.face.clone()),
..Default::default()
})
.collect::<Vec<video::ActiveModel>>();
@@ -110,10 +112,10 @@ pub async fn create_videos(
Ok(())
}
// 筛选所有符合条件的视频
/// 筛选所有符合条件的视频
pub async fn filter_videos(
videos_info: &[VideoInfo],
favorite_obj: &favorite::Model,
favorite_model: &favorite::Model,
only_unhandled: bool,
only_no_page: bool,
connection: &DatabaseConnection,
@@ -123,7 +125,7 @@ pub async fn filter_videos(
.map(|v| v.bvid.clone())
.collect::<Vec<String>>();
let mut condition = video::Column::FavoriteId
.eq(favorite_obj.id)
.eq(favorite_model.id)
.and(video::Column::Bvid.is_in(bvids))
.and(video::Column::Valid.eq(true));
if only_unhandled {
@@ -137,26 +139,26 @@ pub async fn filter_videos(
.all(connection)
.await?)
}
/// 创建视频的所有分 P
pub async fn create_video_pages(
pages: &[PageInfo],
video_obj: &video::Model,
pages_info: &[PageInfo],
video_model: &video::Model,
connection: &DatabaseConnection,
) -> Result<()> {
let page_models = pages
let page_models = pages_info
.iter()
.map(move |p| page::ActiveModel {
video_id: Set(video_obj.id),
video_id: Set(video_model.id),
cid: Set(p.cid),
pid: Set(p.page),
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)
.to_str()
.unwrap()
.to_string()),
image: Set(p.first_frame.clone()),
valid: Set(video_obj.valid),
valid: Set(video_model.valid),
download_status: Set(0),
..Default::default()
})
@@ -172,3 +174,19 @@ pub async fn create_video_pages(
.await?;
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?)
}

View File

@@ -3,16 +3,18 @@ use std::sync::Arc;
use bili_sync::bilibili::BiliClient;
use bili_sync::core::command::process_favorite;
use bili_sync::database::database_connection;
use log::error;
#[tokio::main]
async fn main() -> ! {
env_logger::init();
let connection = Arc::new(database_connection().await.unwrap());
let bili_client = Arc::new(BiliClient::new(None));
loop {
for fid in [52642258] {
for fid in ["52642258"] {
let res = process_favorite(bili_client.clone(), fid, connection.clone()).await;
if let Err(e) = res {
eprintln!("Error: {:?}", e);
error!("Error: {e}");
}
}
tokio::time::sleep(std::time::Duration::from_secs(600)).await;