feat: 写入 upper 头像,整理代码
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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!();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
/// 如果 bvid 和 favtime 均相同,说明到达了上次处理到的位置
|
||||
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?)
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user