chore: 移除 utoipa (#375)

This commit is contained in:
ᴀᴍᴛᴏᴀᴇʀ
2025-07-07 01:01:15 +08:00
committed by GitHub
parent 7bb4e7bc44
commit 636a843bda
14 changed files with 41 additions and 374 deletions
Generated
-121
View File
@@ -136,15 +136,6 @@ dependencies = [
"backtrace", "backtrace",
] ]
[[package]]
name = "arbitrary"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223"
dependencies = [
"derive_arbitrary",
]
[[package]] [[package]]
name = "arc-swap" name = "arc-swap"
version = "1.7.1" version = "1.7.1"
@@ -520,8 +511,6 @@ dependencies = [
"tower", "tower",
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
"utoipa",
"utoipa-swagger-ui",
"validator", "validator",
] ]
@@ -951,17 +940,6 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "derive_arbitrary"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.96",
]
[[package]] [[package]]
name = "derive_builder" name = "derive_builder"
version = "0.20.2" version = "0.20.2"
@@ -1781,7 +1759,6 @@ checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
dependencies = [ dependencies = [
"equivalent", "equivalent",
"hashbrown 0.15.2", "hashbrown 0.15.2",
"serde",
] ]
[[package]] [[package]]
@@ -1943,12 +1920,6 @@ dependencies = [
"scopeguard", "scopeguard",
] ]
[[package]]
name = "lockfree-object-pool"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e"
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.22" version = "0.4.22"
@@ -2001,16 +1972,6 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "mime_guess"
version = "2.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
dependencies = [
"mime",
"unicase",
]
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.7.2" version = "0.7.2"
@@ -3252,12 +3213,6 @@ dependencies = [
"rand_core", "rand_core",
] ]
[[package]]
name = "simd-adler32"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
[[package]] [[package]]
name = "simdutf8" name = "simdutf8"
version = "0.1.4" version = "0.1.4"
@@ -4045,51 +4000,6 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "utoipa"
version = "5.3.1"
source = "git+https://github.com/amtoaer/utoipa.git?tag=v1.0.1#6d66603333218fe4d0f36e40fc662628c6682a79"
dependencies = [
"indexmap",
"serde",
"serde_json",
"utoipa-gen",
]
[[package]]
name = "utoipa-gen"
version = "5.3.1"
source = "git+https://github.com/amtoaer/utoipa.git?tag=v1.0.1#6d66603333218fe4d0f36e40fc662628c6682a79"
dependencies = [
"proc-macro2",
"quote",
"regex",
"syn 2.0.96",
]
[[package]]
name = "utoipa-swagger-ui"
version = "9.0.0"
source = "git+https://github.com/amtoaer/utoipa.git?tag=v1.0.1#6d66603333218fe4d0f36e40fc662628c6682a79"
dependencies = [
"axum",
"base64",
"mime_guess",
"regex",
"rust-embed-for-web",
"serde",
"serde_json",
"url",
"utoipa",
"utoipa-swagger-ui-vendored",
"zip",
]
[[package]]
name = "utoipa-swagger-ui-vendored"
version = "0.1.2"
source = "git+https://github.com/amtoaer/utoipa.git?tag=v1.0.1#6d66603333218fe4d0f36e40fc662628c6682a79"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.8.0" version = "1.8.0"
@@ -4705,34 +4615,3 @@ dependencies = [
"quote", "quote",
"syn 2.0.96", "syn 2.0.96",
] ]
[[package]]
name = "zip"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dd56a4d5921bc2f99947ac5b3abe5f510b1be7376fdc5e9fce4a23c6a93e87c"
dependencies = [
"arbitrary",
"crc32fast",
"crossbeam-utils",
"displaydoc",
"flate2",
"indexmap",
"memchr",
"thiserror 1.0.63",
"zopfli",
]
[[package]]
name = "zopfli"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946"
dependencies = [
"bumpalo",
"crc32fast",
"lockfree-object-pool",
"log",
"once_cell",
"simd-adler32",
]
-7
View File
@@ -71,13 +71,6 @@ toml = "0.8.22"
tower = "0.5.2" tower = "0.5.2"
tracing = "0.1.41" tracing = "0.1.41"
tracing-subscriber = { version = "0.3.19", features = ["chrono"] } tracing-subscriber = { version = "0.3.19", features = ["chrono"] }
utoipa = { git = "https://github.com/amtoaer/utoipa.git", tag = "v1.0.1", features = [
"axum_extras",
] }
utoipa-swagger-ui = { git = "https://github.com/amtoaer/utoipa.git", tag = "v1.0.1", features = [
"axum",
"vendored",
] }
validator = { version = "0.20.0", features = ["derive"] } validator = { version = "0.20.0", features = ["derive"] }
[workspace.metadata.release] [workspace.metadata.release]
-2
View File
@@ -50,8 +50,6 @@ toml = { workspace = true }
tower = { workspace = true } tower = { workspace = true }
tracing = { workspace = true } tracing = { workspace = true }
tracing-subscriber = { workspace = true } tracing-subscriber = { workspace = true }
utoipa = { workspace = true }
utoipa-swagger-ui = { workspace = true }
validator = { workspace = true } validator = { workspace = true }
[dev-dependencies] [dev-dependencies]
-18
View File
@@ -3,8 +3,6 @@ use axum::http::HeaderMap;
use axum::middleware::Next; use axum::middleware::Next;
use axum::response::{IntoResponse, Response}; use axum::response::{IntoResponse, Response};
use reqwest::StatusCode; use reqwest::StatusCode;
use utoipa::Modify;
use utoipa::openapi::security::{ApiKey, ApiKeyValue, SecurityScheme};
use crate::api::wrapper::ApiResponse; use crate::api::wrapper::ApiResponse;
use crate::config::VersionedConfig; use crate::config::VersionedConfig;
@@ -24,19 +22,3 @@ fn get_token(headers: &HeaderMap) -> Option<String> {
.and_then(|v| v.to_str().ok()) .and_then(|v| v.to_str().ok())
.map(Into::into) .map(Into::into)
} }
pub(super) struct OpenAPIAuth;
impl Modify for OpenAPIAuth {
fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) {
if let Some(schema) = openapi.components.as_mut() {
schema.add_security_scheme(
"Token",
SecurityScheme::ApiKey(ApiKey::Header(ApiKeyValue::with_description(
"Authorization",
"与配置文件中的 auth_token 相同",
))),
);
}
}
}
-152
View File
@@ -15,11 +15,9 @@ use sea_orm::{
ColumnTrait, DatabaseConnection, EntityTrait, PaginatorTrait, QueryFilter, QueryOrder, QuerySelect, ColumnTrait, DatabaseConnection, EntityTrait, PaginatorTrait, QueryFilter, QueryOrder, QuerySelect,
TransactionTrait, TransactionTrait,
}; };
use utoipa::OpenApi;
use super::request::ImageProxyParams; use super::request::ImageProxyParams;
use crate::adapter::_ActiveModel; use crate::adapter::_ActiveModel;
use crate::api::auth::OpenAPIAuth;
use crate::api::error::InnerApiError; use crate::api::error::InnerApiError;
use crate::api::helper::{update_page_download_status, update_video_download_status}; use crate::api::helper::{update_page_download_status, update_video_download_status};
use crate::api::request::{ use crate::api::request::{
@@ -38,20 +36,6 @@ use crate::config::{Config, VersionedConfig};
use crate::task::DOWNLOADER_TASK_RUNNING; use crate::task::DOWNLOADER_TASK_RUNNING;
use crate::utils::status::{PageStatus, VideoStatus}; use crate::utils::status::{PageStatus, VideoStatus};
#[derive(OpenApi)]
#[openapi(
paths(
get_video_sources, get_video_sources_details, update_video_source, get_videos, get_video, reset_video, reset_all_videos, update_video_status,
get_created_favorites, get_followed_collections, get_followed_uppers,
insert_favorite, insert_collection, insert_submission
),
modifiers(&OpenAPIAuth),
security(
("Token" = []),
)
)]
pub struct ApiDoc;
pub fn api_router() -> Router { pub fn api_router() -> Router {
Router::new() Router::new()
.route("/api/video-sources", get(get_video_sources)) .route("/api/video-sources", get(get_video_sources))
@@ -74,13 +58,6 @@ pub fn api_router() -> Router {
} }
/// 列出所有视频来源 /// 列出所有视频来源
#[utoipa::path(
get,
path = "/api/video-sources",
responses(
(status = 200, body = ApiResponse<VideoSourcesResponse>),
)
)]
pub async fn get_video_sources( pub async fn get_video_sources(
Extension(db): Extension<Arc<DatabaseConnection>>, Extension(db): Extension<Arc<DatabaseConnection>>,
) -> Result<ApiResponse<VideoSourcesResponse>, ApiError> { ) -> Result<ApiResponse<VideoSourcesResponse>, ApiError> {
@@ -124,16 +101,6 @@ pub async fn get_video_sources(
} }
/// 列出视频的基本信息,支持根据视频来源筛选、名称查找和分页 /// 列出视频的基本信息,支持根据视频来源筛选、名称查找和分页
#[utoipa::path(
get,
path = "/api/videos",
params(
VideosRequest,
),
responses(
(status = 200, body = ApiResponse<VideosResponse>),
)
)]
pub async fn get_videos( pub async fn get_videos(
Extension(db): Extension<Arc<DatabaseConnection>>, Extension(db): Extension<Arc<DatabaseConnection>>,
Query(params): Query<VideosRequest>, Query(params): Query<VideosRequest>,
@@ -169,14 +136,6 @@ pub async fn get_videos(
})) }))
} }
/// 获取视频详细信息,包括关联的所有 page
#[utoipa::path(
get,
path = "/api/videos/{id}",
responses(
(status = 200, body = ApiResponse<VideoResponse>),
)
)]
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<Arc<DatabaseConnection>>,
@@ -200,14 +159,6 @@ pub async fn get_video(
})) }))
} }
/// 将某个视频与其所有分页的失败状态清空为未下载状态,这样在下次下载任务中会触发重试
#[utoipa::path(
post,
path = "/api/videos/{id}/reset",
responses(
(status = 200, body = ApiResponse<ResetVideoResponse>),
)
)]
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<Arc<DatabaseConnection>>,
@@ -268,14 +219,6 @@ pub async fn reset_video(
})) }))
} }
/// 重置所有视频和页面的失败状态为未下载状态,这样在下次下载任务中会触发重试
#[utoipa::path(
post,
path = "/api/videos/reset-all",
responses(
(status = 200, body = ApiResponse<ResetAllVideosResponse>),
)
)]
pub async fn reset_all_videos( pub async fn reset_all_videos(
Extension(db): Extension<Arc<DatabaseConnection>>, Extension(db): Extension<Arc<DatabaseConnection>>,
) -> Result<ApiResponse<ResetAllVideosResponse>, ApiError> { ) -> Result<ApiResponse<ResetAllVideosResponse>, ApiError> {
@@ -333,15 +276,6 @@ pub async fn reset_all_videos(
})) }))
} }
/// 更新特定视频及其所含分页的状态位
#[utoipa::path(
post,
path = "/api/video/{id}/update-status",
request_body = UpdateVideoStatusRequest,
responses(
(status = 200, body = ApiResponse<UpdateVideoStatusResponse>),
)
)]
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<Arc<DatabaseConnection>>,
@@ -399,14 +333,6 @@ pub async fn update_video_status(
})) }))
} }
/// 获取当前用户创建的收藏夹列表,包含订阅状态
#[utoipa::path(
get,
path = "/api/me/favorites",
responses(
(status = 200, body = ApiResponse<FavoritesResponse>),
)
)]
pub async fn get_created_favorites( pub async fn get_created_favorites(
Extension(db): Extension<Arc<DatabaseConnection>>, Extension(db): Extension<Arc<DatabaseConnection>>,
Extension(bili_client): Extension<Arc<BiliClient>>, Extension(bili_client): Extension<Arc<BiliClient>>,
@@ -445,17 +371,6 @@ pub async fn get_created_favorites(
Ok(ApiResponse::ok(FavoritesResponse { favorites })) Ok(ApiResponse::ok(FavoritesResponse { favorites }))
} }
/// 获取当前用户关注的合集列表,包含订阅状态
#[utoipa::path(
get,
path = "/api/me/collections",
params(
FollowedCollectionsRequest,
),
responses(
(status = 200, body = ApiResponse<CollectionsResponse>),
)
)]
pub async fn get_followed_collections( pub async fn get_followed_collections(
Extension(db): Extension<Arc<DatabaseConnection>>, Extension(db): Extension<Arc<DatabaseConnection>>,
Extension(bili_client): Extension<Arc<BiliClient>>, Extension(bili_client): Extension<Arc<BiliClient>>,
@@ -497,16 +412,6 @@ pub async fn get_followed_collections(
})) }))
} }
#[utoipa::path(
get,
path = "/api/me/uppers",
params(
FollowedUppersRequest,
),
responses(
(status = 200, body = ApiResponse<UppersResponse>),
)
)]
pub async fn get_followed_uppers( pub async fn get_followed_uppers(
Extension(db): Extension<Arc<DatabaseConnection>>, Extension(db): Extension<Arc<DatabaseConnection>>,
Extension(bili_client): Extension<Arc<BiliClient>>, Extension(bili_client): Extension<Arc<BiliClient>>,
@@ -547,14 +452,6 @@ pub async fn get_followed_uppers(
})) }))
} }
#[utoipa::path(
post,
path = "/api/video-sources/favorites",
request_body = InsertFavoriteRequest,
responses(
(status = 200, body = ApiResponse<bool>),
)
)]
pub async fn insert_favorite( pub async fn insert_favorite(
Extension(db): Extension<Arc<DatabaseConnection>>, Extension(db): Extension<Arc<DatabaseConnection>>,
Extension(bili_client): Extension<Arc<BiliClient>>, Extension(bili_client): Extension<Arc<BiliClient>>,
@@ -574,14 +471,6 @@ pub async fn insert_favorite(
Ok(ApiResponse::ok(true)) Ok(ApiResponse::ok(true))
} }
#[utoipa::path(
post,
path = "/api/video-sources/collections",
request_body = InsertCollectionRequest,
responses(
(status = 200, body = ApiResponse<bool>),
)
)]
pub async fn insert_collection( pub async fn insert_collection(
Extension(db): Extension<Arc<DatabaseConnection>>, Extension(db): Extension<Arc<DatabaseConnection>>,
Extension(bili_client): Extension<Arc<BiliClient>>, Extension(bili_client): Extension<Arc<BiliClient>>,
@@ -611,15 +500,6 @@ pub async fn insert_collection(
Ok(ApiResponse::ok(true)) Ok(ApiResponse::ok(true))
} }
/// 订阅UP主投稿
#[utoipa::path(
post,
path = "/api/video-sources/submissions",
request_body = InsertSubmissionRequest,
responses(
(status = 200, body = ApiResponse<bool>),
)
)]
pub async fn insert_submission( pub async fn insert_submission(
Extension(db): Extension<Arc<DatabaseConnection>>, Extension(db): Extension<Arc<DatabaseConnection>>,
Extension(bili_client): Extension<Arc<BiliClient>>, Extension(bili_client): Extension<Arc<BiliClient>>,
@@ -640,14 +520,6 @@ pub async fn insert_submission(
Ok(ApiResponse::ok(true)) Ok(ApiResponse::ok(true))
} }
/// 获取所有视频源的详细信息,包括 path 和 enabled 状态
#[utoipa::path(
get,
path = "/api/video-sources/details",
responses(
(status = 200, body = ApiResponse<VideoSourcesDetailsResponse>),
)
)]
pub async fn get_video_sources_details( pub async fn get_video_sources_details(
Extension(db): Extension<Arc<DatabaseConnection>>, Extension(db): Extension<Arc<DatabaseConnection>>,
) -> Result<ApiResponse<VideoSourcesDetailsResponse>, ApiError> { ) -> Result<ApiResponse<VideoSourcesDetailsResponse>, ApiError> {
@@ -703,15 +575,6 @@ pub async fn get_video_sources_details(
})) }))
} }
/// 更新视频源的 path 和 enabled 状态
#[utoipa::path(
put,
path = "/api/video-sources/{type}/{id}",
request_body = UpdateVideoSourceRequest,
responses(
(status = 200, body = ApiResponse<bool>),
)
)]
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<Arc<DatabaseConnection>>,
@@ -769,25 +632,10 @@ pub async fn update_video_source(
Ok(ApiResponse::ok(true)) Ok(ApiResponse::ok(true))
} }
#[utoipa::path(
get,
path = "/api/config",
responses(
(status = 200, body = ApiResponse<Config>),
)
)]
pub async fn get_config() -> Result<ApiResponse<Arc<Config>>, ApiError> { pub async fn get_config() -> Result<ApiResponse<Arc<Config>>, ApiError> {
Ok(ApiResponse::ok(VersionedConfig::get().load_full())) Ok(ApiResponse::ok(VersionedConfig::get().load_full()))
} }
#[utoipa::path(
put,
path = "/api/config",
request_body = Config,
responses(
(status = 200, body = ApiResponse<Config>),
)
)]
pub async fn update_config( pub async fn update_config(
Extension(db): Extension<Arc<DatabaseConnection>>, Extension(db): Extension<Arc<DatabaseConnection>>,
ValidatedJson(config): ValidatedJson<Config>, ValidatedJson(config): ValidatedJson<Config>,
+11 -13
View File
@@ -1,9 +1,8 @@
use serde::Deserialize; use serde::Deserialize;
use utoipa::{IntoParams, ToSchema};
use validator::Validate; use validator::Validate;
use crate::bilibili::CollectionType; use crate::bilibili::CollectionType;
#[derive(Deserialize, IntoParams)] #[derive(Deserialize)]
pub struct VideosRequest { pub struct VideosRequest {
pub collection: Option<i32>, pub collection: Option<i32>,
pub favorite: Option<i32>, pub favorite: Option<i32>,
@@ -14,7 +13,7 @@ pub struct VideosRequest {
pub page_size: Option<u64>, pub page_size: Option<u64>,
} }
#[derive(Deserialize, Validate, ToSchema)] #[derive(Deserialize, Validate)]
pub struct StatusUpdate { pub struct StatusUpdate {
#[validate(range(min = 0, max = 4))] #[validate(range(min = 0, max = 4))]
pub status_index: usize, pub status_index: usize,
@@ -22,14 +21,14 @@ pub struct StatusUpdate {
pub status_value: u32, pub status_value: u32,
} }
#[derive(Deserialize, ToSchema, Validate)] #[derive(Deserialize, Validate)]
pub struct PageStatusUpdate { pub struct PageStatusUpdate {
pub page_id: i32, pub page_id: i32,
#[validate(nested)] #[validate(nested)]
pub updates: Vec<StatusUpdate>, pub updates: Vec<StatusUpdate>,
} }
#[derive(Deserialize, ToSchema, Validate)] #[derive(Deserialize, Validate)]
pub struct UpdateVideoStatusRequest { pub struct UpdateVideoStatusRequest {
#[serde(default)] #[serde(default)]
#[validate(nested)] #[validate(nested)]
@@ -39,49 +38,48 @@ pub struct UpdateVideoStatusRequest {
pub page_updates: Vec<PageStatusUpdate>, pub page_updates: Vec<PageStatusUpdate>,
} }
#[derive(Deserialize, IntoParams)] #[derive(Deserialize)]
pub struct FollowedCollectionsRequest { pub struct FollowedCollectionsRequest {
pub page_num: Option<i32>, pub page_num: Option<i32>,
pub page_size: Option<i32>, pub page_size: Option<i32>,
} }
#[derive(Deserialize, IntoParams)] #[derive(Deserialize)]
pub struct FollowedUppersRequest { pub struct FollowedUppersRequest {
pub page_num: Option<i32>, pub page_num: Option<i32>,
pub page_size: Option<i32>, pub page_size: Option<i32>,
} }
#[derive(Deserialize, ToSchema, Validate)] #[derive(Deserialize, Validate)]
pub struct InsertFavoriteRequest { pub struct InsertFavoriteRequest {
pub fid: i64, pub fid: i64,
#[validate(custom(function = "crate::utils::validation::validate_path"))] #[validate(custom(function = "crate::utils::validation::validate_path"))]
pub path: String, pub path: String,
} }
#[derive(Deserialize, ToSchema, Validate)] #[derive(Deserialize, Validate)]
pub struct InsertCollectionRequest { pub struct InsertCollectionRequest {
pub sid: i64, pub sid: i64,
pub mid: i64, pub mid: i64,
#[schema(value_type = i8)]
#[serde(default)] #[serde(default)]
pub collection_type: CollectionType, pub collection_type: CollectionType,
#[validate(custom(function = "crate::utils::validation::validate_path"))] #[validate(custom(function = "crate::utils::validation::validate_path"))]
pub path: String, pub path: String,
} }
#[derive(Deserialize, ToSchema, Validate)] #[derive(Deserialize, Validate)]
pub struct InsertSubmissionRequest { pub struct InsertSubmissionRequest {
pub upper_id: i64, pub upper_id: i64,
#[validate(custom(function = "crate::utils::validation::validate_path"))] #[validate(custom(function = "crate::utils::validation::validate_path"))]
pub path: String, pub path: String,
} }
#[derive(Deserialize, IntoParams)] #[derive(Deserialize)]
pub struct ImageProxyParams { pub struct ImageProxyParams {
pub url: String, pub url: String,
} }
#[derive(Deserialize, ToSchema, Validate)] #[derive(Deserialize, Validate)]
pub struct UpdateVideoSourceRequest { pub struct UpdateVideoSourceRequest {
#[validate(custom(function = "crate::utils::validation::validate_path"))] #[validate(custom(function = "crate::utils::validation::validate_path"))]
pub path: String, pub path: String,
+17 -20
View File
@@ -1,11 +1,10 @@
use bili_sync_entity::*; use bili_sync_entity::*;
use sea_orm::{DerivePartialModel, FromQueryResult}; use sea_orm::{DerivePartialModel, FromQueryResult};
use serde::Serialize; use serde::Serialize;
use utoipa::ToSchema;
use crate::utils::status::{PageStatus, VideoStatus}; use crate::utils::status::{PageStatus, VideoStatus};
#[derive(Serialize, ToSchema)] #[derive(Serialize)]
pub struct VideoSourcesResponse { pub struct VideoSourcesResponse {
pub collection: Vec<VideoSource>, pub collection: Vec<VideoSource>,
pub favorite: Vec<VideoSource>, pub favorite: Vec<VideoSource>,
@@ -13,64 +12,62 @@ pub struct VideoSourcesResponse {
pub watch_later: Vec<VideoSource>, pub watch_later: Vec<VideoSource>,
} }
#[derive(Serialize, ToSchema)] #[derive(Serialize)]
pub struct VideosResponse { pub struct VideosResponse {
pub videos: Vec<VideoInfo>, pub videos: Vec<VideoInfo>,
pub total_count: u64, pub total_count: u64,
} }
#[derive(Serialize, ToSchema)] #[derive(Serialize)]
pub struct VideoResponse { pub struct VideoResponse {
pub video: VideoInfo, pub video: VideoInfo,
pub pages: Vec<PageInfo>, pub pages: Vec<PageInfo>,
} }
#[derive(Serialize, ToSchema)] #[derive(Serialize)]
pub struct ResetVideoResponse { pub struct ResetVideoResponse {
pub resetted: bool, pub resetted: bool,
pub video: VideoInfo, pub video: VideoInfo,
pub pages: Vec<PageInfo>, pub pages: Vec<PageInfo>,
} }
#[derive(Serialize, ToSchema)] #[derive(Serialize)]
pub struct ResetAllVideosResponse { pub struct ResetAllVideosResponse {
pub resetted: bool, pub resetted: bool,
pub resetted_videos_count: usize, pub resetted_videos_count: usize,
pub resetted_pages_count: usize, pub resetted_pages_count: usize,
} }
#[derive(Serialize, ToSchema)] #[derive(Serialize)]
pub struct UpdateVideoStatusResponse { pub struct UpdateVideoStatusResponse {
pub success: bool, pub success: bool,
pub video: VideoInfo, pub video: VideoInfo,
pub pages: Vec<PageInfo>, pub pages: Vec<PageInfo>,
} }
#[derive(FromQueryResult, Serialize, ToSchema)] #[derive(FromQueryResult, Serialize)]
pub struct VideoSource { pub struct VideoSource {
pub id: i32, pub id: i32,
pub name: String, pub name: String,
} }
#[derive(Serialize, ToSchema, DerivePartialModel, FromQueryResult)] #[derive(Serialize, DerivePartialModel, FromQueryResult)]
#[sea_orm(entity = "video::Entity")] #[sea_orm(entity = "video::Entity")]
pub struct VideoInfo { pub struct VideoInfo {
pub id: i32, pub id: i32,
pub name: String, pub name: String,
pub upper_name: String, pub upper_name: String,
#[schema(value_type = [u32; 5])]
#[serde(serialize_with = "serde_video_download_status")] #[serde(serialize_with = "serde_video_download_status")]
pub download_status: u32, pub download_status: u32,
} }
#[derive(Serialize, ToSchema, DerivePartialModel, FromQueryResult)] #[derive(Serialize, DerivePartialModel, FromQueryResult)]
#[sea_orm(entity = "page::Entity")] #[sea_orm(entity = "page::Entity")]
pub struct PageInfo { pub struct PageInfo {
pub id: i32, pub id: i32,
pub video_id: i32, pub video_id: i32,
pub pid: i32, pub pid: i32,
pub name: String, pub name: String,
#[schema(value_type = [u32; 5])]
#[serde(serialize_with = "serde_page_download_status")] #[serde(serialize_with = "serde_page_download_status")]
pub download_status: u32, pub download_status: u32,
} }
@@ -91,7 +88,7 @@ where
status.serialize(serializer) status.serialize(serializer)
} }
#[derive(Serialize, ToSchema)] #[derive(Serialize)]
pub struct FavoriteWithSubscriptionStatus { pub struct FavoriteWithSubscriptionStatus {
pub title: String, pub title: String,
pub media_count: i64, pub media_count: i64,
@@ -100,7 +97,7 @@ pub struct FavoriteWithSubscriptionStatus {
pub subscribed: bool, pub subscribed: bool,
} }
#[derive(Serialize, ToSchema)] #[derive(Serialize)]
pub struct CollectionWithSubscriptionStatus { pub struct CollectionWithSubscriptionStatus {
pub title: String, pub title: String,
pub sid: i64, pub sid: i64,
@@ -109,7 +106,7 @@ pub struct CollectionWithSubscriptionStatus {
pub subscribed: bool, pub subscribed: bool,
} }
#[derive(Serialize, ToSchema)] #[derive(Serialize)]
pub struct UpperWithSubscriptionStatus { pub struct UpperWithSubscriptionStatus {
pub mid: i64, pub mid: i64,
pub uname: String, pub uname: String,
@@ -119,24 +116,24 @@ pub struct UpperWithSubscriptionStatus {
pub subscribed: bool, pub subscribed: bool,
} }
#[derive(Serialize, ToSchema)] #[derive(Serialize)]
pub struct FavoritesResponse { pub struct FavoritesResponse {
pub favorites: Vec<FavoriteWithSubscriptionStatus>, pub favorites: Vec<FavoriteWithSubscriptionStatus>,
} }
#[derive(Serialize, ToSchema)] #[derive(Serialize)]
pub struct CollectionsResponse { pub struct CollectionsResponse {
pub collections: Vec<CollectionWithSubscriptionStatus>, pub collections: Vec<CollectionWithSubscriptionStatus>,
pub total: i64, pub total: i64,
} }
#[derive(Serialize, ToSchema)] #[derive(Serialize)]
pub struct UppersResponse { pub struct UppersResponse {
pub uppers: Vec<UpperWithSubscriptionStatus>, pub uppers: Vec<UpperWithSubscriptionStatus>,
pub total: i64, pub total: i64,
} }
#[derive(Serialize, ToSchema)] #[derive(Serialize)]
pub struct VideoSourcesDetailsResponse { pub struct VideoSourcesDetailsResponse {
pub collections: Vec<VideoSourceDetail>, pub collections: Vec<VideoSourceDetail>,
pub favorites: Vec<VideoSourceDetail>, pub favorites: Vec<VideoSourceDetail>,
@@ -144,7 +141,7 @@ pub struct VideoSourcesDetailsResponse {
pub watch_later: Vec<VideoSourceDetail>, pub watch_later: Vec<VideoSourceDetail>,
} }
#[derive(Serialize, ToSchema, FromQueryResult)] #[derive(Serialize, FromQueryResult)]
pub struct VideoSourceDetail { pub struct VideoSourceDetail {
pub id: i32, pub id: i32,
pub name: String, pub name: String,
+1 -2
View File
@@ -8,12 +8,11 @@ use axum::response::IntoResponse;
use reqwest::StatusCode; use reqwest::StatusCode;
use serde::Serialize; use serde::Serialize;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use utoipa::ToSchema;
use validator::Validate; use validator::Validate;
use crate::api::error::InnerApiError; use crate::api::error::InnerApiError;
#[derive(ToSchema, Serialize)] #[derive(Serialize)]
pub struct ApiResponse<T: Serialize> { pub struct ApiResponse<T: Serialize> {
status_code: u16, status_code: u16,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
+4 -14
View File
@@ -1,6 +1,5 @@
use anyhow::{Context, Result, bail}; use anyhow::{Context, Result, bail};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
use crate::bilibili::error::BiliError; use crate::bilibili::error::BiliError;
use crate::config::VersionedConfig; use crate::config::VersionedConfig;
@@ -9,7 +8,7 @@ pub struct PageAnalyzer {
info: serde_json::Value, info: serde_json::Value,
} }
#[derive(Debug, strum::FromRepr, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, ToSchema, Clone)] #[derive(Debug, strum::FromRepr, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Clone)]
pub enum VideoQuality { pub enum VideoQuality {
Quality360p = 16, Quality360p = 16,
Quality480p = 32, Quality480p = 32,
@@ -23,7 +22,7 @@ pub enum VideoQuality {
Quality8k = 127, Quality8k = 127,
} }
#[derive(Debug, Clone, Copy, strum::FromRepr, PartialEq, Eq, Serialize, Deserialize, ToSchema)] #[derive(Debug, Clone, Copy, strum::FromRepr, PartialEq, Eq, Serialize, Deserialize)]
pub enum AudioQuality { pub enum AudioQuality {
Quality64k = 30216, Quality64k = 30216,
Quality132k = 30232, Quality132k = 30232,
@@ -56,16 +55,7 @@ impl AudioQuality {
#[allow(clippy::upper_case_acronyms)] #[allow(clippy::upper_case_acronyms)]
#[derive( #[derive(
Debug, Debug, strum::EnumString, strum::Display, strum::AsRefStr, PartialEq, PartialOrd, Serialize, Deserialize, Clone,
strum::EnumString,
strum::Display,
strum::AsRefStr,
PartialEq,
PartialOrd,
Serialize,
Deserialize,
ToSchema,
Clone,
)] )]
pub enum VideoCodecs { pub enum VideoCodecs {
#[strum(serialize = "hev")] #[strum(serialize = "hev")]
@@ -91,7 +81,7 @@ impl TryFrom<u64> for VideoCodecs {
} }
// 视频流的筛选偏好 // 视频流的筛选偏好
#[derive(Serialize, Deserialize, ToSchema, Clone)] #[derive(Serialize, Deserialize, Clone)]
pub struct FilterOption { pub struct FilterOption {
pub video_max_quality: VideoQuality, pub video_max_quality: VideoQuality,
pub video_min_quality: VideoQuality, pub video_min_quality: VideoQuality,
+1 -2
View File
@@ -10,7 +10,6 @@ use rsa::pkcs8::DecodePublicKey;
use rsa::sha2::Sha256; use rsa::sha2::Sha256;
use rsa::{Oaep, RsaPublicKey}; use rsa::{Oaep, RsaPublicKey};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
use crate::bilibili::{Client, Validate}; use crate::bilibili::{Client, Validate};
@@ -20,7 +19,7 @@ const MIXIN_KEY_ENC_TAB: [usize; 64] = [
20, 34, 44, 52, 20, 34, 44, 52,
]; ];
#[derive(Default, Debug, Clone, Serialize, Deserialize, ToSchema)] #[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct Credential { pub struct Credential {
pub sessdata: String, pub sessdata: String,
pub bili_jct: String, pub bili_jct: String,
@@ -4,14 +4,13 @@ mod lane;
use anyhow::Result; use anyhow::Result;
use float_ord::FloatOrd; use float_ord::FloatOrd;
use lane::Lane; use lane::Lane;
use utoipa::ToSchema;
use crate::bilibili::PageInfo; use crate::bilibili::PageInfo;
use crate::bilibili::danmaku::canvas::lane::Collision; use crate::bilibili::danmaku::canvas::lane::Collision;
use crate::bilibili::danmaku::danmu::DanmuType; use crate::bilibili::danmaku::danmu::DanmuType;
use crate::bilibili::danmaku::{Danmu, DrawEffect, Drawable}; use crate::bilibili::danmaku::{Danmu, DrawEffect, Drawable};
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema)] #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub struct DanmakuOption { pub struct DanmakuOption {
pub duration: f64, pub duration: f64,
pub font: String, pub font: String,
+1 -3
View File
@@ -4,7 +4,6 @@ use std::sync::LazyLock;
use anyhow::{Result, bail}; use anyhow::{Result, bail};
use sea_orm::DatabaseConnection; use sea_orm::DatabaseConnection;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
use validator::Validate; use validator::Validate;
use crate::bilibili::{Credential, DanmakuOption, FilterOption}; use crate::bilibili::{Credential, DanmakuOption, FilterOption};
@@ -16,7 +15,7 @@ use crate::utils::model::{load_db_config, save_db_config};
pub static CONFIG_DIR: LazyLock<PathBuf> = pub static CONFIG_DIR: LazyLock<PathBuf> =
LazyLock::new(|| dirs::config_dir().expect("No config path found").join("bili-sync")); LazyLock::new(|| dirs::config_dir().expect("No config path found").join("bili-sync"));
#[derive(Serialize, Deserialize, ToSchema, Validate, Clone)] #[derive(Serialize, Deserialize, Validate, Clone)]
pub struct Config { pub struct Config {
pub auth_token: String, pub auth_token: String,
pub bind_address: String, pub bind_address: String,
@@ -26,7 +25,6 @@ pub struct Config {
pub video_name: String, pub video_name: String,
pub page_name: String, pub page_name: String,
pub interval: u64, pub interval: u64,
#[schema(value_type = String)]
pub upper_path: PathBuf, pub upper_path: PathBuf,
pub nfo_time_type: NFOTimeType, pub nfo_time_type: NFOTimeType,
pub concurrent_limit: ConcurrentLimit, pub concurrent_limit: ConcurrentLimit,
+4 -5
View File
@@ -2,7 +2,6 @@ use std::path::PathBuf;
use anyhow::Result; use anyhow::Result;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
use crate::utils::filenamify::filenamify; use crate::utils::filenamify::filenamify;
@@ -14,7 +13,7 @@ pub struct WatchLaterConfig {
} }
/// NFO 文件使用的时间类型 /// NFO 文件使用的时间类型
#[derive(Serialize, Deserialize, Default, ToSchema, Clone)] #[derive(Serialize, Deserialize, Default, Clone)]
#[serde(rename_all = "lowercase")] #[serde(rename_all = "lowercase")]
pub enum NFOTimeType { pub enum NFOTimeType {
#[default] #[default]
@@ -23,7 +22,7 @@ pub enum NFOTimeType {
} }
/// 并发下载相关的配置 /// 并发下载相关的配置
#[derive(Serialize, Deserialize, ToSchema, Clone)] #[derive(Serialize, Deserialize, Clone)]
pub struct ConcurrentLimit { pub struct ConcurrentLimit {
pub video: usize, pub video: usize,
pub page: usize, pub page: usize,
@@ -32,7 +31,7 @@ pub struct ConcurrentLimit {
pub download: ConcurrentDownloadLimit, pub download: ConcurrentDownloadLimit,
} }
#[derive(Serialize, Deserialize, ToSchema, Clone)] #[derive(Serialize, Deserialize, Clone)]
pub struct ConcurrentDownloadLimit { pub struct ConcurrentDownloadLimit {
pub enable: bool, pub enable: bool,
pub concurrency: usize, pub concurrency: usize,
@@ -49,7 +48,7 @@ impl Default for ConcurrentDownloadLimit {
} }
} }
#[derive(Serialize, Deserialize, ToSchema, Clone)] #[derive(Serialize, Deserialize, Clone)]
pub struct RateLimit { pub struct RateLimit {
pub limit: usize, pub limit: usize,
pub duration: u64, pub duration: u64,
+1 -13
View File
@@ -9,11 +9,9 @@ use axum::{Extension, Router, ServiceExt, middleware};
use reqwest::StatusCode; use reqwest::StatusCode;
use rust_embed_for_web::{EmbedableFile, RustEmbed}; use rust_embed_for_web::{EmbedableFile, RustEmbed};
use sea_orm::DatabaseConnection; use sea_orm::DatabaseConnection;
use utoipa::OpenApi;
use utoipa_swagger_ui::{Config, SwaggerUi};
use crate::api::auth; use crate::api::auth;
use crate::api::handler::{ApiDoc, api_router}; use crate::api::handler::api_router;
use crate::bilibili::BiliClient; use crate::bilibili::BiliClient;
use crate::config::VersionedConfig; use crate::config::VersionedConfig;
@@ -26,16 +24,6 @@ struct Asset;
pub async fn http_server(database_connection: Arc<DatabaseConnection>, bili_client: Arc<BiliClient>) -> Result<()> { pub async fn http_server(database_connection: Arc<DatabaseConnection>, bili_client: Arc<BiliClient>) -> Result<()> {
let app = Router::new() let app = Router::new()
.merge(api_router()) .merge(api_router())
.merge(
SwaggerUi::new("/swagger-ui/")
.url("/api-docs/openapi.json", ApiDoc::openapi())
.config(
Config::default()
.try_it_out_enabled(true)
.persist_authorization(true)
.validator_url("none"),
),
)
.fallback_service(get(frontend_files)) .fallback_service(get(frontend_files))
.layer(Extension(database_connection)) .layer(Extension(database_connection))
.layer(Extension(bili_client)) .layer(Extension(bili_client))