mirror of
https://github.com/lanyeeee/bilibili-video-downloader.git
synced 2026-09-05 15:38:52 +08:00
feat: 后端支持获取历史记录
This commit is contained in:
Generated
+1
@@ -304,6 +304,7 @@ dependencies = [
|
||||
"reqwest-retry",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
"specta",
|
||||
"specta-typescript",
|
||||
"strfmt",
|
||||
|
||||
@@ -25,6 +25,7 @@ tauri-plugin-dialog = "2"
|
||||
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
serde_repr = "0.1"
|
||||
|
||||
specta = { version = "=2.0.0-rc.20", features = ["serde_json"] }
|
||||
tauri-specta = { version = "=2.0.0-rc.20", features = ["derive", "typescript"] }
|
||||
|
||||
@@ -26,11 +26,13 @@ use crate::{
|
||||
cheese_media_url::CheeseMediaUrl, fav_folders::FavFolders, fav_info::FavInfo,
|
||||
get_bangumi_follow_info_params::GetBangumiFollowInfoParams,
|
||||
get_bangumi_info_params::GetBangumiInfoParams, get_cheese_info_params::GetCheeseInfoParams,
|
||||
get_fav_info_params::GetFavInfoParams, get_normal_info_params::GetNormalInfoParams,
|
||||
get_user_video_info_params::GetUserVideoInfoParams, normal_info::NormalInfo,
|
||||
normal_media_url::NormalMediaUrl, player_info::PlayerInfo, qrcode_data::QrcodeData,
|
||||
qrcode_status::QrcodeStatus, skip_segments::SkipSegments, subtitle::Subtitle, tags::Tags,
|
||||
user_info::UserInfo, user_video_info::UserVideoInfo, watch_later_info::WatchLaterInfo,
|
||||
get_fav_info_params::GetFavInfoParams, get_history_info_params::GetHistoryInfoParams,
|
||||
get_normal_info_params::GetNormalInfoParams,
|
||||
get_user_video_info_params::GetUserVideoInfoParams, history_info::HistoryInfo,
|
||||
normal_info::NormalInfo, normal_media_url::NormalMediaUrl, player_info::PlayerInfo,
|
||||
qrcode_data::QrcodeData, qrcode_status::QrcodeStatus, skip_segments::SkipSegments,
|
||||
subtitle::Subtitle, tags::Tags, user_info::UserInfo, user_video_info::UserVideoInfo,
|
||||
watch_later_info::WatchLaterInfo,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -672,6 +674,53 @@ impl BiliClient {
|
||||
Ok(bangumi_follow_info)
|
||||
}
|
||||
|
||||
pub async fn get_history_info(
|
||||
&self,
|
||||
params: GetHistoryInfoParams,
|
||||
) -> anyhow::Result<HistoryInfo> {
|
||||
let device_type: i64 = params.device_type.into();
|
||||
let params = json!({
|
||||
"pn": params.pn,
|
||||
"keyword": params.keyword,
|
||||
"business": "archive",
|
||||
"add_time_start": params.add_time_start,
|
||||
"add_time_end": params.add_time_end,
|
||||
"arc_max_duration": params.arc_max_duration,
|
||||
"arc_min_duration": params.arc_min_duration,
|
||||
"device_type": device_type,
|
||||
});
|
||||
let request = self
|
||||
.api_client
|
||||
.read()
|
||||
.get("https://api.bilibili.com/x/web-interface/history/search")
|
||||
.query(¶ms)
|
||||
.header("cookie", self.get_cookie());
|
||||
let http_resp = request.send().await?;
|
||||
// 检查http响应状态码
|
||||
let status = http_resp.status();
|
||||
let body = http_resp.text().await?;
|
||||
if status != StatusCode::OK {
|
||||
return Err(anyhow!("预料之外的状态码({status}): {body}"));
|
||||
}
|
||||
// 尝试将body解析为BiliResp
|
||||
let bili_resp: BiliResp =
|
||||
serde_json::from_str(&body).context(format!("将body解析为BiliResp失败: {body}"))?;
|
||||
// 检查BiliResp的code字段
|
||||
if bili_resp.code != 0 {
|
||||
return Err(anyhow!("预料之外的code: {bili_resp:?}"));
|
||||
}
|
||||
// 检查BiliResp的data是否存在
|
||||
let Some(data) = bili_resp.data else {
|
||||
return Err(anyhow!("BiliResp中不存在data字段: {bili_resp:?}"));
|
||||
};
|
||||
// 尝试将data解析为HistoryInfo
|
||||
let data_str = data.to_string();
|
||||
let history_info: HistoryInfo = serde_json::from_str(&data_str)
|
||||
.context(format!("将data解析为HistoryInfo失败: {data_str}"))?;
|
||||
|
||||
Ok(history_info)
|
||||
}
|
||||
|
||||
pub async fn get_media_chunk(
|
||||
&self,
|
||||
media_url: &str,
|
||||
|
||||
@@ -18,8 +18,10 @@ use crate::{
|
||||
get_bangumi_info_params::GetBangumiInfoParams,
|
||||
get_cheese_info_params::GetCheeseInfoParams,
|
||||
get_fav_info_params::GetFavInfoParams,
|
||||
get_history_info_params::GetHistoryInfoParams,
|
||||
get_normal_info_params::GetNormalInfoParams,
|
||||
get_user_video_info_params::GetUserVideoInfoParams,
|
||||
history_info::HistoryInfo,
|
||||
normal_info::NormalInfo,
|
||||
qrcode_data::QrcodeData,
|
||||
qrcode_status::QrcodeStatus,
|
||||
@@ -210,6 +212,20 @@ pub async fn get_bangumi_follow_info(
|
||||
Ok(bangumi_follow_info)
|
||||
}
|
||||
|
||||
#[tauri::command(async)]
|
||||
#[specta::specta]
|
||||
pub async fn get_history_info(
|
||||
app: AppHandle,
|
||||
params: GetHistoryInfoParams,
|
||||
) -> CommandResult<HistoryInfo> {
|
||||
let bili_client = app.get_bili_client();
|
||||
let history_info = bili_client
|
||||
.get_history_info(params)
|
||||
.await
|
||||
.map_err(|err| CommandError::from("获取历史记录失败", err))?;
|
||||
Ok(history_info)
|
||||
}
|
||||
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
#[tauri::command(async)]
|
||||
#[specta::specta]
|
||||
|
||||
@@ -46,6 +46,7 @@ pub fn run() {
|
||||
get_fav_info,
|
||||
get_watch_later_info,
|
||||
get_bangumi_follow_info,
|
||||
get_history_info,
|
||||
create_download_tasks,
|
||||
pause_download_tasks,
|
||||
resume_download_tasks,
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
use num_enum::{FromPrimitive, IntoPrimitive};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specta::Type;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct GetHistoryInfoParams {
|
||||
pub pn: i64,
|
||||
pub keyword: String,
|
||||
pub add_time_start: i64,
|
||||
pub add_time_end: i64,
|
||||
pub arc_max_duration: i64,
|
||||
pub arc_min_duration: i64,
|
||||
pub device_type: DeviceType,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Default,
|
||||
Debug,
|
||||
Clone,
|
||||
Copy,
|
||||
Hash,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Type,
|
||||
IntoPrimitive,
|
||||
FromPrimitive,
|
||||
)]
|
||||
#[repr(i64)]
|
||||
pub enum DeviceType {
|
||||
#[default]
|
||||
All = 0,
|
||||
PC = 1,
|
||||
Mobile = 2,
|
||||
Pad = 3,
|
||||
TV = 4,
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specta::Type;
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct HistoryInfo {
|
||||
pub has_more: bool,
|
||||
pub page: PageInHistory,
|
||||
pub list: Option<Vec<HistoryDetail>>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct PageInHistory {
|
||||
pub pn: i64,
|
||||
pub total: i64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct HistoryDetail {
|
||||
pub title: String,
|
||||
pub long_title: String,
|
||||
pub cover: String,
|
||||
pub uri: String,
|
||||
pub history: History,
|
||||
pub videos: i64,
|
||||
pub author_name: String,
|
||||
pub author_face: String,
|
||||
pub author_mid: i64,
|
||||
pub view_at: i64,
|
||||
pub progress: i64,
|
||||
pub badge: String,
|
||||
pub show_title: String,
|
||||
pub duration: i64,
|
||||
pub total: i64,
|
||||
pub new_desc: String,
|
||||
pub is_finish: i64,
|
||||
pub is_fav: i64,
|
||||
pub kid: i64,
|
||||
pub tag_name: String,
|
||||
pub live_status: i64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct History {
|
||||
pub oid: i64,
|
||||
pub epid: i64,
|
||||
pub bvid: String,
|
||||
pub page: i64,
|
||||
pub cid: i64,
|
||||
pub part: String,
|
||||
pub business: String,
|
||||
pub dt: i64,
|
||||
}
|
||||
@@ -12,8 +12,10 @@ pub mod get_bangumi_follow_info_params;
|
||||
pub mod get_bangumi_info_params;
|
||||
pub mod get_cheese_info_params;
|
||||
pub mod get_fav_info_params;
|
||||
pub mod get_history_info_params;
|
||||
pub mod get_normal_info_params;
|
||||
pub mod get_user_video_info_params;
|
||||
pub mod history_info;
|
||||
pub mod log_level;
|
||||
pub mod normal_info;
|
||||
pub mod normal_media_url;
|
||||
|
||||
@@ -96,6 +96,14 @@ async getBangumiFollowInfo(params: GetBangumiFollowInfoParams) : Promise<Result<
|
||||
else return { status: "error", error: e as any };
|
||||
}
|
||||
},
|
||||
async getHistoryInfo(params: GetHistoryInfoParams) : Promise<Result<HistoryInfo, CommandError>> {
|
||||
try {
|
||||
return { status: "ok", data: await TAURI_INVOKE("get_history_info", { params }) };
|
||||
} catch (e) {
|
||||
if(e instanceof Error) throw e;
|
||||
else return { status: "error", error: e as any };
|
||||
}
|
||||
},
|
||||
async createDownloadTasks(params: CreateDownloadTaskParams) : Promise<void> {
|
||||
await TAURI_INVOKE("create_download_tasks", { params });
|
||||
},
|
||||
@@ -259,6 +267,7 @@ export type CreateDownloadTaskParams = { Normal: CreateNormalDownloadTaskParams
|
||||
export type CreateNormalDownloadTaskParams = { info: NormalInfo; aid_cid_pairs: ([number, number | null])[] }
|
||||
export type DanmakuTask = { xml_selected: boolean; ass_selected: boolean; json_selected: boolean; completed: boolean }
|
||||
export type DescV2 = { raw_text: string; type: number; biz_id: number }
|
||||
export type DeviceType = "All" | "PC" | "Mobile" | "Pad" | "TV"
|
||||
export type Dimension = { width: number; height: number; rotate: number }
|
||||
export type DimensionInBangumi = { height: number; rotate: number; width: number }
|
||||
export type DimensionInWatchLater = { width: number; height: number; rotate: number }
|
||||
@@ -290,8 +299,12 @@ type: number; pn: number; follow_status: number }
|
||||
export type GetBangumiInfoParams = { EpId: number } | { SeasonId: number }
|
||||
export type GetCheeseInfoParams = { EpId: number } | { SeasonId: number }
|
||||
export type GetFavInfoParams = { media_list_id: number; pn: number }
|
||||
export type GetHistoryInfoParams = { pn: number; keyword: string; add_time_start: number; add_time_end: number; arc_max_duration: number; arc_min_duration: number; device_type: DeviceType }
|
||||
export type GetNormalInfoParams = { Bvid: string } | { Aid: number }
|
||||
export type GetUserVideoInfoParams = { pn: number; mid: number }
|
||||
export type History = { oid: number; epid: number; bvid: string; page: number; cid: number; part: string; business: string; dt: number }
|
||||
export type HistoryDetail = { title: string; long_title: string; cover: string; uri: string; history: History; videos: number; author_name: string; author_face: string; author_mid: number; view_at: number; progress: number; badge: string; show_title: string; duration: number; total: number; new_desc: string; is_finish: number; is_fav: number; kid: number; tag_name: string; live_status: number }
|
||||
export type HistoryInfo = { has_more: boolean; page: PageInHistory; list: HistoryDetail[] | null }
|
||||
export type Honor = { aid: number; type: number; desc: string; weekly_recommend_num: number }
|
||||
export type HonorReply = { honor: Honor[] | null }
|
||||
export type IconFont = { name: string; text: string }
|
||||
@@ -319,6 +332,7 @@ export type OfficialVerify = { type: number; desc: string }
|
||||
export type Op = { end: number; start: number }
|
||||
export type OwnerInNormal = { mid: number; name: string; face: string }
|
||||
export type OwnerInWatchLater = { mid: number; name: string; face: string }
|
||||
export type PageInHistory = { pn: number; total: number }
|
||||
export type PageInNormal = { cid: number; page: number; from: string; part: string; duration: number; vid: string; weblink: string; dimension: Dimension; ctime: number }
|
||||
export type PageInNormalEp = { cid: number; page: number; from: string; part: string; duration: number; vid: string; weblink: string; dimension: Dimension }
|
||||
export type PageInUserVideo = { pn: number; ps: number; count: number }
|
||||
|
||||
Reference in New Issue
Block a user