mirror of
https://github.com/amtoaer/bili-sync.git
synced 2026-08-28 03:28:05 +08:00
feat: sqlite 开启 Wal,移除不必要的 Arc,妥善释放数据库 (#421)
This commit is contained in:
@@ -22,7 +22,7 @@ pub async fn get_config() -> Result<ApiResponse<Arc<Config>>, ApiError> {
|
|||||||
|
|
||||||
/// 更新全局配置
|
/// 更新全局配置
|
||||||
pub async fn update_config(
|
pub async fn update_config(
|
||||||
Extension(db): Extension<Arc<DatabaseConnection>>,
|
Extension(db): Extension<DatabaseConnection>,
|
||||||
ValidatedJson(config): ValidatedJson<Config>,
|
ValidatedJson(config): ValidatedJson<Config>,
|
||||||
) -> Result<ApiResponse<Arc<Config>>, ApiError> {
|
) -> Result<ApiResponse<Arc<Config>>, ApiError> {
|
||||||
let Some(_lock) = TASK_STATUS_NOTIFIER.detect_running() else {
|
let Some(_lock) = TASK_STATUS_NOTIFIER.detect_running() else {
|
||||||
@@ -30,7 +30,7 @@ pub async fn update_config(
|
|||||||
return Err(InnerApiError::BadRequest("下载任务正在运行,无法修改配置".to_string()).into());
|
return Err(InnerApiError::BadRequest("下载任务正在运行,无法修改配置".to_string()).into());
|
||||||
};
|
};
|
||||||
config.check()?;
|
config.check()?;
|
||||||
let new_config = VersionedConfig::get().update(config, db.as_ref()).await?;
|
let new_config = VersionedConfig::get().update(config, &db).await?;
|
||||||
drop(_lock);
|
drop(_lock);
|
||||||
Ok(ApiResponse::ok(new_config))
|
Ok(ApiResponse::ok(new_config))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use axum::routing::get;
|
use axum::routing::get;
|
||||||
use axum::{Extension, Router};
|
use axum::{Extension, Router};
|
||||||
use bili_sync_entity::*;
|
use bili_sync_entity::*;
|
||||||
@@ -14,21 +12,21 @@ pub(super) fn router() -> Router {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn get_dashboard(
|
async fn get_dashboard(
|
||||||
Extension(db): Extension<Arc<DatabaseConnection>>,
|
Extension(db): Extension<DatabaseConnection>,
|
||||||
) -> Result<ApiResponse<DashBoardResponse>, ApiError> {
|
) -> Result<ApiResponse<DashBoardResponse>, ApiError> {
|
||||||
let (enabled_favorites, enabled_collections, enabled_submissions, enabled_watch_later, videos_by_day) = tokio::try_join!(
|
let (enabled_favorites, enabled_collections, enabled_submissions, enabled_watch_later, videos_by_day) = tokio::try_join!(
|
||||||
favorite::Entity::find()
|
favorite::Entity::find()
|
||||||
.filter(favorite::Column::Enabled.eq(true))
|
.filter(favorite::Column::Enabled.eq(true))
|
||||||
.count(db.as_ref()),
|
.count(&db),
|
||||||
collection::Entity::find()
|
collection::Entity::find()
|
||||||
.filter(collection::Column::Enabled.eq(true))
|
.filter(collection::Column::Enabled.eq(true))
|
||||||
.count(db.as_ref()),
|
.count(&db),
|
||||||
submission::Entity::find()
|
submission::Entity::find()
|
||||||
.filter(submission::Column::Enabled.eq(true))
|
.filter(submission::Column::Enabled.eq(true))
|
||||||
.count(db.as_ref()),
|
.count(&db),
|
||||||
watch_later::Entity::find()
|
watch_later::Entity::find()
|
||||||
.filter(watch_later::Column::Enabled.eq(true))
|
.filter(watch_later::Column::Enabled.eq(true))
|
||||||
.count(db.as_ref()),
|
.count(&db),
|
||||||
DayCountPair::find_by_statement(Statement::from_string(
|
DayCountPair::find_by_statement(Statement::from_string(
|
||||||
db.get_database_backend(),
|
db.get_database_backend(),
|
||||||
// 用 SeaORM 太复杂了,直接写个裸 SQL
|
// 用 SeaORM 太复杂了,直接写个裸 SQL
|
||||||
@@ -55,7 +53,7 @@ ORDER BY
|
|||||||
dates.day;
|
dates.day;
|
||||||
"
|
"
|
||||||
))
|
))
|
||||||
.all(db.as_ref()),
|
.all(&db),
|
||||||
)?;
|
)?;
|
||||||
return Ok(ApiResponse::ok(DashBoardResponse {
|
return Ok(ApiResponse::ok(DashBoardResponse {
|
||||||
enabled_favorites,
|
enabled_favorites,
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ pub(super) fn router() -> Router {
|
|||||||
|
|
||||||
/// 获取当前用户创建的收藏夹
|
/// 获取当前用户创建的收藏夹
|
||||||
pub async fn get_created_favorites(
|
pub async fn get_created_favorites(
|
||||||
Extension(db): Extension<Arc<DatabaseConnection>>,
|
Extension(db): Extension<DatabaseConnection>,
|
||||||
Extension(bili_client): Extension<Arc<BiliClient>>,
|
Extension(bili_client): Extension<Arc<BiliClient>>,
|
||||||
) -> Result<ApiResponse<FavoritesResponse>, ApiError> {
|
) -> Result<ApiResponse<FavoritesResponse>, ApiError> {
|
||||||
let me = Me::new(bili_client.as_ref());
|
let me = Me::new(bili_client.as_ref());
|
||||||
@@ -40,7 +40,7 @@ pub async fn get_created_favorites(
|
|||||||
.column(favorite::Column::FId)
|
.column(favorite::Column::FId)
|
||||||
.filter(favorite::Column::FId.is_in(bili_fids))
|
.filter(favorite::Column::FId.is_in(bili_fids))
|
||||||
.into_tuple()
|
.into_tuple()
|
||||||
.all(db.as_ref())
|
.all(&db)
|
||||||
.await?;
|
.await?;
|
||||||
let subscribed_set: HashSet<i64> = subscribed_fids.into_iter().collect();
|
let subscribed_set: HashSet<i64> = subscribed_fids.into_iter().collect();
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ pub async fn get_created_favorites(
|
|||||||
|
|
||||||
/// 获取当前用户收藏的合集
|
/// 获取当前用户收藏的合集
|
||||||
pub async fn get_followed_collections(
|
pub async fn get_followed_collections(
|
||||||
Extension(db): Extension<Arc<DatabaseConnection>>,
|
Extension(db): Extension<DatabaseConnection>,
|
||||||
Extension(bili_client): Extension<Arc<BiliClient>>,
|
Extension(bili_client): Extension<Arc<BiliClient>>,
|
||||||
Query(params): Query<FollowedCollectionsRequest>,
|
Query(params): Query<FollowedCollectionsRequest>,
|
||||||
) -> Result<ApiResponse<CollectionsResponse>, ApiError> {
|
) -> Result<ApiResponse<CollectionsResponse>, ApiError> {
|
||||||
@@ -80,7 +80,7 @@ pub async fn get_followed_collections(
|
|||||||
.column(collection::Column::SId)
|
.column(collection::Column::SId)
|
||||||
.filter(collection::Column::SId.is_in(bili_sids))
|
.filter(collection::Column::SId.is_in(bili_sids))
|
||||||
.into_tuple()
|
.into_tuple()
|
||||||
.all(db.as_ref())
|
.all(&db)
|
||||||
.await?;
|
.await?;
|
||||||
let subscribed_set: HashSet<i64> = subscribed_ids.into_iter().collect();
|
let subscribed_set: HashSet<i64> = subscribed_ids.into_iter().collect();
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ pub async fn get_followed_collections(
|
|||||||
|
|
||||||
/// 获取当前用户关注的 UP 主
|
/// 获取当前用户关注的 UP 主
|
||||||
pub async fn get_followed_uppers(
|
pub async fn get_followed_uppers(
|
||||||
Extension(db): Extension<Arc<DatabaseConnection>>,
|
Extension(db): Extension<DatabaseConnection>,
|
||||||
Extension(bili_client): Extension<Arc<BiliClient>>,
|
Extension(bili_client): Extension<Arc<BiliClient>>,
|
||||||
Query(params): Query<FollowedUppersRequest>,
|
Query(params): Query<FollowedUppersRequest>,
|
||||||
) -> Result<ApiResponse<UppersResponse>, ApiError> {
|
) -> Result<ApiResponse<UppersResponse>, ApiError> {
|
||||||
@@ -121,7 +121,7 @@ pub async fn get_followed_uppers(
|
|||||||
.column(submission::Column::UpperId)
|
.column(submission::Column::UpperId)
|
||||||
.filter(submission::Column::UpperId.is_in(bili_uid))
|
.filter(submission::Column::UpperId.is_in(bili_uid))
|
||||||
.into_tuple()
|
.into_tuple()
|
||||||
.all(db.as_ref())
|
.all(&db)
|
||||||
.await?;
|
.await?;
|
||||||
let subscribed_set: HashSet<i64> = subscribed_ids.into_iter().collect();
|
let subscribed_set: HashSet<i64> = subscribed_ids.into_iter().collect();
|
||||||
|
|
||||||
|
|||||||
@@ -30,31 +30,31 @@ pub(super) fn router() -> Router {
|
|||||||
|
|
||||||
/// 列出所有视频来源
|
/// 列出所有视频来源
|
||||||
pub async fn get_video_sources(
|
pub async fn get_video_sources(
|
||||||
Extension(db): Extension<Arc<DatabaseConnection>>,
|
Extension(db): Extension<DatabaseConnection>,
|
||||||
) -> Result<ApiResponse<VideoSourcesResponse>, ApiError> {
|
) -> Result<ApiResponse<VideoSourcesResponse>, ApiError> {
|
||||||
let (collection, favorite, submission, mut watch_later) = tokio::try_join!(
|
let (collection, favorite, submission, mut watch_later) = tokio::try_join!(
|
||||||
collection::Entity::find()
|
collection::Entity::find()
|
||||||
.select_only()
|
.select_only()
|
||||||
.columns([collection::Column::Id, collection::Column::Name])
|
.columns([collection::Column::Id, collection::Column::Name])
|
||||||
.into_model::<VideoSource>()
|
.into_model::<VideoSource>()
|
||||||
.all(db.as_ref()),
|
.all(&db),
|
||||||
favorite::Entity::find()
|
favorite::Entity::find()
|
||||||
.select_only()
|
.select_only()
|
||||||
.columns([favorite::Column::Id, favorite::Column::Name])
|
.columns([favorite::Column::Id, favorite::Column::Name])
|
||||||
.into_model::<VideoSource>()
|
.into_model::<VideoSource>()
|
||||||
.all(db.as_ref()),
|
.all(&db),
|
||||||
submission::Entity::find()
|
submission::Entity::find()
|
||||||
.select_only()
|
.select_only()
|
||||||
.column(submission::Column::Id)
|
.column(submission::Column::Id)
|
||||||
.column_as(submission::Column::UpperName, "name")
|
.column_as(submission::Column::UpperName, "name")
|
||||||
.into_model::<VideoSource>()
|
.into_model::<VideoSource>()
|
||||||
.all(db.as_ref()),
|
.all(&db),
|
||||||
watch_later::Entity::find()
|
watch_later::Entity::find()
|
||||||
.select_only()
|
.select_only()
|
||||||
.column(watch_later::Column::Id)
|
.column(watch_later::Column::Id)
|
||||||
.column_as(Expr::value("稍后再看"), "name")
|
.column_as(Expr::value("稍后再看"), "name")
|
||||||
.into_model::<VideoSource>()
|
.into_model::<VideoSource>()
|
||||||
.all(db.as_ref())
|
.all(&db)
|
||||||
)?;
|
)?;
|
||||||
// watch_later 是一个特殊的视频来源,如果不存在则添加一个默认项
|
// watch_later 是一个特殊的视频来源,如果不存在则添加一个默认项
|
||||||
if watch_later.is_empty() {
|
if watch_later.is_empty() {
|
||||||
@@ -73,7 +73,7 @@ pub async fn get_video_sources(
|
|||||||
|
|
||||||
/// 获取视频来源详情
|
/// 获取视频来源详情
|
||||||
pub async fn get_video_sources_details(
|
pub async fn get_video_sources_details(
|
||||||
Extension(db): Extension<Arc<DatabaseConnection>>,
|
Extension(db): Extension<DatabaseConnection>,
|
||||||
) -> Result<ApiResponse<VideoSourcesDetailsResponse>, ApiError> {
|
) -> Result<ApiResponse<VideoSourcesDetailsResponse>, ApiError> {
|
||||||
let (collections, favorites, submissions, mut watch_later) = tokio::try_join!(
|
let (collections, favorites, submissions, mut watch_later) = tokio::try_join!(
|
||||||
collection::Entity::find()
|
collection::Entity::find()
|
||||||
@@ -85,7 +85,7 @@ pub async fn get_video_sources_details(
|
|||||||
collection::Column::Enabled
|
collection::Column::Enabled
|
||||||
])
|
])
|
||||||
.into_model::<VideoSourceDetail>()
|
.into_model::<VideoSourceDetail>()
|
||||||
.all(db.as_ref()),
|
.all(&db),
|
||||||
favorite::Entity::find()
|
favorite::Entity::find()
|
||||||
.select_only()
|
.select_only()
|
||||||
.columns([
|
.columns([
|
||||||
@@ -95,21 +95,21 @@ pub async fn get_video_sources_details(
|
|||||||
favorite::Column::Enabled
|
favorite::Column::Enabled
|
||||||
])
|
])
|
||||||
.into_model::<VideoSourceDetail>()
|
.into_model::<VideoSourceDetail>()
|
||||||
.all(db.as_ref()),
|
.all(&db),
|
||||||
submission::Entity::find()
|
submission::Entity::find()
|
||||||
.select_only()
|
.select_only()
|
||||||
.column(submission::Column::Id)
|
.column(submission::Column::Id)
|
||||||
.column_as(submission::Column::UpperName, "name")
|
.column_as(submission::Column::UpperName, "name")
|
||||||
.columns([submission::Column::Path, submission::Column::Enabled])
|
.columns([submission::Column::Path, submission::Column::Enabled])
|
||||||
.into_model::<VideoSourceDetail>()
|
.into_model::<VideoSourceDetail>()
|
||||||
.all(db.as_ref()),
|
.all(&db),
|
||||||
watch_later::Entity::find()
|
watch_later::Entity::find()
|
||||||
.select_only()
|
.select_only()
|
||||||
.column(watch_later::Column::Id)
|
.column(watch_later::Column::Id)
|
||||||
.column_as(Expr::value("稍后再看"), "name")
|
.column_as(Expr::value("稍后再看"), "name")
|
||||||
.columns([watch_later::Column::Path, watch_later::Column::Enabled])
|
.columns([watch_later::Column::Path, watch_later::Column::Enabled])
|
||||||
.into_model::<VideoSourceDetail>()
|
.into_model::<VideoSourceDetail>()
|
||||||
.all(db.as_ref())
|
.all(&db)
|
||||||
)?;
|
)?;
|
||||||
if watch_later.is_empty() {
|
if watch_later.is_empty() {
|
||||||
watch_later.push(VideoSourceDetail {
|
watch_later.push(VideoSourceDetail {
|
||||||
@@ -130,29 +130,29 @@ pub async fn get_video_sources_details(
|
|||||||
/// 更新视频来源
|
/// 更新视频来源
|
||||||
pub async fn update_video_source(
|
pub async fn update_video_source(
|
||||||
Path((source_type, id)): Path<(String, i32)>,
|
Path((source_type, id)): Path<(String, i32)>,
|
||||||
Extension(db): Extension<Arc<DatabaseConnection>>,
|
Extension(db): Extension<DatabaseConnection>,
|
||||||
ValidatedJson(request): ValidatedJson<UpdateVideoSourceRequest>,
|
ValidatedJson(request): ValidatedJson<UpdateVideoSourceRequest>,
|
||||||
) -> Result<ApiResponse<bool>, ApiError> {
|
) -> Result<ApiResponse<bool>, ApiError> {
|
||||||
let active_model = match source_type.as_str() {
|
let active_model = match source_type.as_str() {
|
||||||
"collections" => collection::Entity::find_by_id(id).one(db.as_ref()).await?.map(|model| {
|
"collections" => collection::Entity::find_by_id(id).one(&db).await?.map(|model| {
|
||||||
let mut active_model: collection::ActiveModel = model.into();
|
let mut active_model: collection::ActiveModel = model.into();
|
||||||
active_model.path = Set(request.path);
|
active_model.path = Set(request.path);
|
||||||
active_model.enabled = Set(request.enabled);
|
active_model.enabled = Set(request.enabled);
|
||||||
_ActiveModel::Collection(active_model)
|
_ActiveModel::Collection(active_model)
|
||||||
}),
|
}),
|
||||||
"favorites" => favorite::Entity::find_by_id(id).one(db.as_ref()).await?.map(|model| {
|
"favorites" => favorite::Entity::find_by_id(id).one(&db).await?.map(|model| {
|
||||||
let mut active_model: favorite::ActiveModel = model.into();
|
let mut active_model: favorite::ActiveModel = model.into();
|
||||||
active_model.path = Set(request.path);
|
active_model.path = Set(request.path);
|
||||||
active_model.enabled = Set(request.enabled);
|
active_model.enabled = Set(request.enabled);
|
||||||
_ActiveModel::Favorite(active_model)
|
_ActiveModel::Favorite(active_model)
|
||||||
}),
|
}),
|
||||||
"submissions" => submission::Entity::find_by_id(id).one(db.as_ref()).await?.map(|model| {
|
"submissions" => submission::Entity::find_by_id(id).one(&db).await?.map(|model| {
|
||||||
let mut active_model: submission::ActiveModel = model.into();
|
let mut active_model: submission::ActiveModel = model.into();
|
||||||
active_model.path = Set(request.path);
|
active_model.path = Set(request.path);
|
||||||
active_model.enabled = Set(request.enabled);
|
active_model.enabled = Set(request.enabled);
|
||||||
_ActiveModel::Submission(active_model)
|
_ActiveModel::Submission(active_model)
|
||||||
}),
|
}),
|
||||||
"watch_later" => match watch_later::Entity::find_by_id(id).one(db.as_ref()).await? {
|
"watch_later" => match watch_later::Entity::find_by_id(id).one(&db).await? {
|
||||||
// 稍后再看需要做特殊处理,get 时如果稍后再看不存在返回的是 id 为 1 的假记录
|
// 稍后再看需要做特殊处理,get 时如果稍后再看不存在返回的是 id 为 1 的假记录
|
||||||
// 因此此处可能是更新也可能是插入,做个额外的处理
|
// 因此此处可能是更新也可能是插入,做个额外的处理
|
||||||
Some(model) => {
|
Some(model) => {
|
||||||
@@ -180,13 +180,13 @@ pub async fn update_video_source(
|
|||||||
let Some(active_model) = active_model else {
|
let Some(active_model) = active_model else {
|
||||||
return Err(InnerApiError::NotFound(id).into());
|
return Err(InnerApiError::NotFound(id).into());
|
||||||
};
|
};
|
||||||
active_model.save(db.as_ref()).await?;
|
active_model.save(&db).await?;
|
||||||
Ok(ApiResponse::ok(true))
|
Ok(ApiResponse::ok(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 新增收藏夹订阅
|
/// 新增收藏夹订阅
|
||||||
pub async fn insert_favorite(
|
pub async fn insert_favorite(
|
||||||
Extension(db): Extension<Arc<DatabaseConnection>>,
|
Extension(db): Extension<DatabaseConnection>,
|
||||||
Extension(bili_client): Extension<Arc<BiliClient>>,
|
Extension(bili_client): Extension<Arc<BiliClient>>,
|
||||||
ValidatedJson(request): ValidatedJson<InsertFavoriteRequest>,
|
ValidatedJson(request): ValidatedJson<InsertFavoriteRequest>,
|
||||||
) -> Result<ApiResponse<bool>, ApiError> {
|
) -> Result<ApiResponse<bool>, ApiError> {
|
||||||
@@ -199,14 +199,14 @@ pub async fn insert_favorite(
|
|||||||
enabled: Set(true),
|
enabled: Set(true),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.exec(db.as_ref())
|
.exec(&db)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(ApiResponse::ok(true))
|
Ok(ApiResponse::ok(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 新增合集/列表订阅
|
/// 新增合集/列表订阅
|
||||||
pub async fn insert_collection(
|
pub async fn insert_collection(
|
||||||
Extension(db): Extension<Arc<DatabaseConnection>>,
|
Extension(db): Extension<DatabaseConnection>,
|
||||||
Extension(bili_client): Extension<Arc<BiliClient>>,
|
Extension(bili_client): Extension<Arc<BiliClient>>,
|
||||||
ValidatedJson(request): ValidatedJson<InsertCollectionRequest>,
|
ValidatedJson(request): ValidatedJson<InsertCollectionRequest>,
|
||||||
) -> Result<ApiResponse<bool>, ApiError> {
|
) -> Result<ApiResponse<bool>, ApiError> {
|
||||||
@@ -228,7 +228,7 @@ pub async fn insert_collection(
|
|||||||
enabled: Set(true),
|
enabled: Set(true),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.exec(db.as_ref())
|
.exec(&db)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(ApiResponse::ok(true))
|
Ok(ApiResponse::ok(true))
|
||||||
@@ -236,7 +236,7 @@ pub async fn insert_collection(
|
|||||||
|
|
||||||
/// 新增投稿订阅
|
/// 新增投稿订阅
|
||||||
pub async fn insert_submission(
|
pub async fn insert_submission(
|
||||||
Extension(db): Extension<Arc<DatabaseConnection>>,
|
Extension(db): Extension<DatabaseConnection>,
|
||||||
Extension(bili_client): Extension<Arc<BiliClient>>,
|
Extension(bili_client): Extension<Arc<BiliClient>>,
|
||||||
ValidatedJson(request): ValidatedJson<InsertSubmissionRequest>,
|
ValidatedJson(request): ValidatedJson<InsertSubmissionRequest>,
|
||||||
) -> Result<ApiResponse<bool>, ApiError> {
|
) -> Result<ApiResponse<bool>, ApiError> {
|
||||||
@@ -249,7 +249,7 @@ pub async fn insert_submission(
|
|||||||
enabled: Set(true),
|
enabled: Set(true),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.exec(db.as_ref())
|
.exec(&db)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(ApiResponse::ok(true))
|
Ok(ApiResponse::ok(true))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use axum::extract::{Extension, Path, Query};
|
use axum::extract::{Extension, Path, Query};
|
||||||
@@ -31,7 +30,7 @@ pub(super) fn router() -> Router {
|
|||||||
|
|
||||||
/// 列出视频的基本信息,支持根据视频来源筛选、名称查找和分页
|
/// 列出视频的基本信息,支持根据视频来源筛选、名称查找和分页
|
||||||
pub async fn get_videos(
|
pub async fn get_videos(
|
||||||
Extension(db): Extension<Arc<DatabaseConnection>>,
|
Extension(db): Extension<DatabaseConnection>,
|
||||||
Query(params): Query<VideosRequest>,
|
Query(params): Query<VideosRequest>,
|
||||||
) -> Result<ApiResponse<VideosResponse>, ApiError> {
|
) -> Result<ApiResponse<VideosResponse>, ApiError> {
|
||||||
let mut query = video::Entity::find();
|
let mut query = video::Entity::find();
|
||||||
@@ -48,7 +47,7 @@ pub async fn get_videos(
|
|||||||
if let Some(query_word) = params.query {
|
if let Some(query_word) = params.query {
|
||||||
query = query.filter(video::Column::Name.contains(query_word));
|
query = query.filter(video::Column::Name.contains(query_word));
|
||||||
}
|
}
|
||||||
let total_count = query.clone().count(db.as_ref()).await?;
|
let total_count = query.clone().count(&db).await?;
|
||||||
let (page, page_size) = if let (Some(page), Some(page_size)) = (params.page, params.page_size) {
|
let (page, page_size) = if let (Some(page), Some(page_size)) = (params.page, params.page_size) {
|
||||||
(page, page_size)
|
(page, page_size)
|
||||||
} else {
|
} else {
|
||||||
@@ -58,7 +57,7 @@ pub async fn get_videos(
|
|||||||
videos: query
|
videos: query
|
||||||
.order_by_desc(video::Column::Id)
|
.order_by_desc(video::Column::Id)
|
||||||
.into_partial_model::<VideoInfo>()
|
.into_partial_model::<VideoInfo>()
|
||||||
.paginate(db.as_ref(), page_size)
|
.paginate(&db, page_size)
|
||||||
.fetch_page(page)
|
.fetch_page(page)
|
||||||
.await?,
|
.await?,
|
||||||
total_count,
|
total_count,
|
||||||
@@ -67,17 +66,15 @@ pub async fn get_videos(
|
|||||||
|
|
||||||
pub async fn get_video(
|
pub async fn get_video(
|
||||||
Path(id): Path<i32>,
|
Path(id): Path<i32>,
|
||||||
Extension(db): Extension<Arc<DatabaseConnection>>,
|
Extension(db): Extension<DatabaseConnection>,
|
||||||
) -> Result<ApiResponse<VideoResponse>, ApiError> {
|
) -> Result<ApiResponse<VideoResponse>, ApiError> {
|
||||||
let (video_info, pages_info) = tokio::try_join!(
|
let (video_info, pages_info) = tokio::try_join!(
|
||||||
video::Entity::find_by_id(id)
|
video::Entity::find_by_id(id).into_partial_model::<VideoInfo>().one(&db),
|
||||||
.into_partial_model::<VideoInfo>()
|
|
||||||
.one(db.as_ref()),
|
|
||||||
page::Entity::find()
|
page::Entity::find()
|
||||||
.filter(page::Column::VideoId.eq(id))
|
.filter(page::Column::VideoId.eq(id))
|
||||||
.order_by_asc(page::Column::Cid)
|
.order_by_asc(page::Column::Cid)
|
||||||
.into_partial_model::<PageInfo>()
|
.into_partial_model::<PageInfo>()
|
||||||
.all(db.as_ref())
|
.all(&db)
|
||||||
)?;
|
)?;
|
||||||
let Some(video_info) = video_info else {
|
let Some(video_info) = video_info else {
|
||||||
return Err(InnerApiError::NotFound(id).into());
|
return Err(InnerApiError::NotFound(id).into());
|
||||||
@@ -90,18 +87,16 @@ pub async fn get_video(
|
|||||||
|
|
||||||
pub async fn reset_video(
|
pub async fn reset_video(
|
||||||
Path(id): Path<i32>,
|
Path(id): Path<i32>,
|
||||||
Extension(db): Extension<Arc<DatabaseConnection>>,
|
Extension(db): Extension<DatabaseConnection>,
|
||||||
Json(request): Json<ResetRequest>,
|
Json(request): Json<ResetRequest>,
|
||||||
) -> Result<ApiResponse<ResetVideoResponse>, ApiError> {
|
) -> Result<ApiResponse<ResetVideoResponse>, ApiError> {
|
||||||
let (video_info, pages_info) = tokio::try_join!(
|
let (video_info, pages_info) = tokio::try_join!(
|
||||||
video::Entity::find_by_id(id)
|
video::Entity::find_by_id(id).into_partial_model::<VideoInfo>().one(&db),
|
||||||
.into_partial_model::<VideoInfo>()
|
|
||||||
.one(db.as_ref()),
|
|
||||||
page::Entity::find()
|
page::Entity::find()
|
||||||
.filter(page::Column::VideoId.eq(id))
|
.filter(page::Column::VideoId.eq(id))
|
||||||
.order_by_asc(page::Column::Cid)
|
.order_by_asc(page::Column::Cid)
|
||||||
.into_partial_model::<PageInfo>()
|
.into_partial_model::<PageInfo>()
|
||||||
.all(db.as_ref())
|
.all(&db)
|
||||||
)?;
|
)?;
|
||||||
let Some(mut video_info) = video_info else {
|
let Some(mut video_info) = video_info else {
|
||||||
return Err(InnerApiError::NotFound(id).into());
|
return Err(InnerApiError::NotFound(id).into());
|
||||||
@@ -150,13 +145,13 @@ pub async fn reset_video(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn reset_all_videos(
|
pub async fn reset_all_videos(
|
||||||
Extension(db): Extension<Arc<DatabaseConnection>>,
|
Extension(db): Extension<DatabaseConnection>,
|
||||||
Json(request): Json<ResetRequest>,
|
Json(request): Json<ResetRequest>,
|
||||||
) -> Result<ApiResponse<ResetAllVideosResponse>, ApiError> {
|
) -> Result<ApiResponse<ResetAllVideosResponse>, ApiError> {
|
||||||
// 先查询所有视频和页面数据
|
// 先查询所有视频和页面数据
|
||||||
let (all_videos, all_pages) = tokio::try_join!(
|
let (all_videos, all_pages) = tokio::try_join!(
|
||||||
video::Entity::find().into_partial_model::<VideoInfo>().all(db.as_ref()),
|
video::Entity::find().into_partial_model::<VideoInfo>().all(&db),
|
||||||
page::Entity::find().into_partial_model::<PageInfo>().all(db.as_ref())
|
page::Entity::find().into_partial_model::<PageInfo>().all(&db)
|
||||||
)?;
|
)?;
|
||||||
let resetted_pages_info = all_pages
|
let resetted_pages_info = all_pages
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -210,18 +205,16 @@ pub async fn reset_all_videos(
|
|||||||
|
|
||||||
pub async fn update_video_status(
|
pub async fn update_video_status(
|
||||||
Path(id): Path<i32>,
|
Path(id): Path<i32>,
|
||||||
Extension(db): Extension<Arc<DatabaseConnection>>,
|
Extension(db): Extension<DatabaseConnection>,
|
||||||
ValidatedJson(request): ValidatedJson<UpdateVideoStatusRequest>,
|
ValidatedJson(request): ValidatedJson<UpdateVideoStatusRequest>,
|
||||||
) -> Result<ApiResponse<UpdateVideoStatusResponse>, ApiError> {
|
) -> Result<ApiResponse<UpdateVideoStatusResponse>, ApiError> {
|
||||||
let (video_info, mut pages_info) = tokio::try_join!(
|
let (video_info, mut pages_info) = tokio::try_join!(
|
||||||
video::Entity::find_by_id(id)
|
video::Entity::find_by_id(id).into_partial_model::<VideoInfo>().one(&db),
|
||||||
.into_partial_model::<VideoInfo>()
|
|
||||||
.one(db.as_ref()),
|
|
||||||
page::Entity::find()
|
page::Entity::find()
|
||||||
.filter(page::Column::VideoId.eq(id))
|
.filter(page::Column::VideoId.eq(id))
|
||||||
.order_by_asc(page::Column::Cid)
|
.order_by_asc(page::Column::Cid)
|
||||||
.into_partial_model::<PageInfo>()
|
.into_partial_model::<PageInfo>()
|
||||||
.all(db.as_ref())
|
.all(&db)
|
||||||
)?;
|
)?;
|
||||||
let Some(mut video_info) = video_info else {
|
let Some(mut video_info) = video_info else {
|
||||||
return Err(InnerApiError::NotFound(id).into());
|
return Err(InnerApiError::NotFound(id).into());
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use std::time::Duration;
|
|||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use bili_sync_migration::{Migrator, MigratorTrait};
|
use bili_sync_migration::{Migrator, MigratorTrait};
|
||||||
use sea_orm::sqlx::sqlite::SqliteConnectOptions;
|
use sea_orm::sqlx::sqlite::{SqliteConnectOptions, SqliteJournalMode, SqliteSynchronous};
|
||||||
use sea_orm::sqlx::{ConnectOptions as SqlxConnectOptions, Sqlite};
|
use sea_orm::sqlx::{ConnectOptions as SqlxConnectOptions, Sqlite};
|
||||||
use sea_orm::{ConnectOptions, Database, DatabaseConnection, SqlxSqliteConnector};
|
use sea_orm::{ConnectOptions, Database, DatabaseConnection, SqlxSqliteConnector};
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ fn database_url() -> String {
|
|||||||
async fn database_connection() -> Result<DatabaseConnection> {
|
async fn database_connection() -> Result<DatabaseConnection> {
|
||||||
let mut option = ConnectOptions::new(database_url());
|
let mut option = ConnectOptions::new(database_url());
|
||||||
option
|
option
|
||||||
.max_connections(100)
|
.max_connections(50)
|
||||||
.min_connections(5)
|
.min_connections(5)
|
||||||
.acquire_timeout(Duration::from_secs(90));
|
.acquire_timeout(Duration::from_secs(90));
|
||||||
let connect_option = option
|
let connect_option = option
|
||||||
@@ -23,7 +23,10 @@ async fn database_connection() -> Result<DatabaseConnection> {
|
|||||||
.parse::<SqliteConnectOptions>()
|
.parse::<SqliteConnectOptions>()
|
||||||
.context("Failed to parse database URL")?
|
.context("Failed to parse database URL")?
|
||||||
.disable_statement_logging()
|
.disable_statement_logging()
|
||||||
.busy_timeout(Duration::from_secs(90));
|
.busy_timeout(Duration::from_secs(90))
|
||||||
|
.journal_mode(SqliteJournalMode::Wal)
|
||||||
|
.synchronous(SqliteSynchronous::Normal)
|
||||||
|
.optimize_on_close(true, None);
|
||||||
Ok(SqlxSqliteConnector::from_sqlx_sqlite_pool(
|
Ok(SqlxSqliteConnector::from_sqlx_sqlite_pool(
|
||||||
option
|
option
|
||||||
.sqlx_pool_options::<Sqlite>()
|
.sqlx_pool_options::<Sqlite>()
|
||||||
|
|||||||
@@ -47,14 +47,14 @@ async fn main() {
|
|||||||
if !cfg!(debug_assertions) {
|
if !cfg!(debug_assertions) {
|
||||||
spawn_task(
|
spawn_task(
|
||||||
"定时下载",
|
"定时下载",
|
||||||
video_downloader(connection, bili_client),
|
video_downloader(connection.clone(), bili_client),
|
||||||
&tracker,
|
&tracker,
|
||||||
token.clone(),
|
token.clone(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
tracker.close();
|
tracker.close();
|
||||||
handle_shutdown(tracker, token).await
|
handle_shutdown(connection, tracker, token).await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_task(
|
fn spawn_task(
|
||||||
@@ -77,7 +77,7 @@ fn spawn_task(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 初始化日志系统、打印欢迎信息,初始化数据库连接和全局配置
|
/// 初始化日志系统、打印欢迎信息,初始化数据库连接和全局配置
|
||||||
async fn init() -> (Arc<DatabaseConnection>, LogHelper) {
|
async fn init() -> (DatabaseConnection, LogHelper) {
|
||||||
let (tx, _rx) = tokio::sync::broadcast::channel(30);
|
let (tx, _rx) = tokio::sync::broadcast::channel(30);
|
||||||
let log_history = Arc::new(Mutex::new(VecDeque::with_capacity(MAX_HISTORY_LOGS + 1)));
|
let log_history = Arc::new(Mutex::new(VecDeque::with_capacity(MAX_HISTORY_LOGS + 1)));
|
||||||
let log_writer = LogHelper::new(tx, log_history.clone());
|
let log_writer = LogHelper::new(tx, log_history.clone());
|
||||||
@@ -85,7 +85,7 @@ async fn init() -> (Arc<DatabaseConnection>, LogHelper) {
|
|||||||
init_logger(&ARGS.log_level, Some(log_writer.clone()));
|
init_logger(&ARGS.log_level, Some(log_writer.clone()));
|
||||||
info!("欢迎使用 Bili-Sync,当前程序版本:{}", config::version());
|
info!("欢迎使用 Bili-Sync,当前程序版本:{}", config::version());
|
||||||
info!("项目地址:https://github.com/amtoaer/bili-sync");
|
info!("项目地址:https://github.com/amtoaer/bili-sync");
|
||||||
let connection = Arc::new(setup_database().await.expect("数据库初始化失败"));
|
let connection = setup_database().await.expect("数据库初始化失败");
|
||||||
info!("数据库初始化完成");
|
info!("数据库初始化完成");
|
||||||
VersionedConfig::init(&connection).await.expect("配置初始化失败");
|
VersionedConfig::init(&connection).await.expect("配置初始化失败");
|
||||||
info!("配置初始化完成");
|
info!("配置初始化完成");
|
||||||
@@ -93,16 +93,21 @@ async fn init() -> (Arc<DatabaseConnection>, LogHelper) {
|
|||||||
(connection, log_writer)
|
(connection, log_writer)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_shutdown(tracker: TaskTracker, token: CancellationToken) {
|
async fn handle_shutdown(connection: DatabaseConnection, tracker: TaskTracker, token: CancellationToken) {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
_ = tracker.wait() => {
|
_ = tracker.wait() => {
|
||||||
error!("所有任务均已终止,程序退出")
|
error!("所有任务均已终止..")
|
||||||
}
|
}
|
||||||
_ = terminate() => {
|
_ = terminate() => {
|
||||||
info!("接收到终止信号,正在终止任务..");
|
info!("接收到终止信号,开始终止任务..");
|
||||||
token.cancel();
|
token.cancel();
|
||||||
tracker.wait().await;
|
tracker.wait().await;
|
||||||
info!("所有任务均已终止,程序退出");
|
info!("所有任务均已终止..");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
info!("正在关闭数据库连接..");
|
||||||
|
match connection.close().await {
|
||||||
|
Ok(()) => info!("数据库连接已关闭,程序结束"),
|
||||||
|
Err(e) => error!("关闭数据库连接时遇到错误:{:#},程序异常结束", e),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ use crate::config::VersionedConfig;
|
|||||||
struct Asset;
|
struct Asset;
|
||||||
|
|
||||||
pub async fn http_server(
|
pub async fn http_server(
|
||||||
database_connection: Arc<DatabaseConnection>,
|
database_connection: DatabaseConnection,
|
||||||
bili_client: Arc<BiliClient>,
|
bili_client: Arc<BiliClient>,
|
||||||
log_writer: LogHelper,
|
log_writer: LogHelper,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use crate::utils::task_notifier::TASK_STATUS_NOTIFIER;
|
|||||||
use crate::workflow::process_video_source;
|
use crate::workflow::process_video_source;
|
||||||
|
|
||||||
/// 启动周期下载视频的任务
|
/// 启动周期下载视频的任务
|
||||||
pub async fn video_downloader(connection: Arc<DatabaseConnection>, bili_client: Arc<BiliClient>) {
|
pub async fn video_downloader(connection: DatabaseConnection, bili_client: Arc<BiliClient>) {
|
||||||
let mut anchor = chrono::Local::now().date_naive();
|
let mut anchor = chrono::Local::now().date_naive();
|
||||||
loop {
|
loop {
|
||||||
info!("开始执行本轮视频下载任务..");
|
info!("开始执行本轮视频下载任务..");
|
||||||
|
|||||||
Reference in New Issue
Block a user