mirror of
https://github.com/amtoaer/bili-sync.git
synced 2026-09-04 23:18:02 +08:00
feat: 写入 upper 头像,整理代码
This commit is contained in:
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user