feat: 后端支持获取追番信息

This commit is contained in:
lanyeeee
2025-08-21 04:49:57 +08:00
parent 703723dfaa
commit e1088cb8f5
8 changed files with 335 additions and 20 deletions
+47 -1
View File
@@ -21,8 +21,10 @@ use crate::{
extensions::{AnyhowErrorToStringChain, AppHandleExt},
protobuf::DmSegMobileReply,
types::{
bangumi_info::BangumiInfo, bangumi_media_url::BangumiMediaUrl, cheese_info::CheeseInfo,
bangumi_follow_info::BangumiFollowInfo, bangumi_info::BangumiInfo,
bangumi_media_url::BangumiMediaUrl, cheese_info::CheeseInfo,
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,
@@ -626,6 +628,50 @@ impl BiliClient {
Ok(watch_later_info)
}
pub async fn get_bangumi_follow_info(
&self,
params: GetBangumiFollowInfoParams,
) -> anyhow::Result<BangumiFollowInfo> {
// 发送获取番剧追踪信息的请求
let params = json!({
"vmid": params.vmid,
"type": params.type_field,
"pn": params.pn,
"ps": 24,
"follow_status": params.follow_status,
});
let request = self
.api_client
.read()
.get("https://api.bilibili.com/x/space/bangumi/follow/list")
.query(&params)
.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解析为BangumiFollowInfo
let data_str = data.to_string();
let bangumi_follow_info: BangumiFollowInfo = serde_json::from_str(&data_str)
.context(format!("将data解析为BangumiFollowInfo失败: {data_str}"))?;
Ok(bangumi_follow_info)
}
pub async fn get_media_chunk(
&self,
media_url: &str,
+16
View File
@@ -9,10 +9,12 @@ use crate::{
extensions::AppHandleExt,
logger,
types::{
bangumi_follow_info::BangumiFollowInfo,
bangumi_info::EpInBangumi,
create_download_task_params::CreateDownloadTaskParams,
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,
@@ -179,6 +181,20 @@ pub async fn get_watch_later_info(app: AppHandle, page: i32) -> CommandResult<Wa
Ok(watch_later_info)
}
#[tauri::command(async)]
#[specta::specta]
pub async fn get_bangumi_follow_info(
app: AppHandle,
params: GetBangumiFollowInfoParams,
) -> CommandResult<BangumiFollowInfo> {
let bili_client = app.get_bili_client();
let bangumi_follow_info = bili_client
.get_bangumi_follow_info(params)
.await
.map_err(|err| CommandError::from("获取追番信息失败", err))?;
Ok(bangumi_follow_info)
}
#[allow(clippy::needless_pass_by_value)]
#[tauri::command(async)]
#[specta::specta]
+1
View File
@@ -44,6 +44,7 @@ pub fn run() {
get_fav_folders,
get_fav_info,
get_watch_later_info,
get_bangumi_follow_info,
create_download_tasks,
pause_download_tasks,
resume_download_tasks,
+207
View File
@@ -0,0 +1,207 @@
use serde::{Deserialize, Serialize};
use specta::Type;
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
pub struct BangumiFollowInfo {
pub list: Vec<EpInBangumiFollow>,
pub pn: i64,
pub ps: i64,
pub total: i64,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
pub struct EpInBangumiFollow {
pub season_id: i64,
pub media_id: i64,
pub season_type: i64,
pub season_type_name: String,
pub title: String,
pub cover: String,
pub total_count: i64,
pub is_finish: i64,
pub is_started: i64,
pub is_play: i64,
pub badge: String,
pub badge_type: i64,
pub rights: RightsInBangumiFollow,
pub stat: StatInBangumiFollow,
pub new_ep: NewEpInBangumiFollow,
pub rating: Option<RatingInBangumiFollow>,
pub square_cover: String,
pub season_status: i64,
pub season_title: String,
pub badge_ep: String,
pub media_attr: i64,
pub season_attr: i64,
pub evaluate: String,
pub areas: Vec<AreaInBangumiFollow>,
pub subtitle: String,
pub first_ep: i64,
pub can_watch: i64,
pub release_date_show: Option<String>,
pub series: SeriesInBangumiFollow,
pub publish: PublishInBangumiFollow,
pub mode: i64,
pub section: Vec<SectionInBangumiFollow>,
pub url: String,
pub badge_info: BadgeInfoInBangumiFollow,
pub renewal_time: Option<String>,
pub first_ep_info: FirstEpInfo,
pub formal_ep_count: Option<i64>,
pub short_url: String,
pub badge_infos: Option<BadgeInfos>,
pub season_version: Option<String>,
pub horizontal_cover_16_9: Option<String>,
pub horizontal_cover_16_10: Option<String>,
pub subtitle_14: Option<String>,
pub viewable_crowd_type: i64,
#[serde(default)]
pub producers: Vec<Producer>,
pub summary: String,
#[serde(default)]
pub styles: Vec<String>,
pub follow_status: i64,
pub is_new: i64,
pub progress: String,
pub both_follow: bool,
pub subtitle_25: Option<String>,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
pub struct RightsInBangumiFollow {
pub allow_review: Option<i64>,
pub allow_preview: Option<i64>,
pub is_selection: i64,
pub selection_style: i64,
pub is_rcmd: Option<i64>,
pub allow_bp_rank: Option<i64>,
pub allow_bp: Option<i64>,
pub allow_download: Option<i64>,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
pub struct StatInBangumiFollow {
pub follow: i64,
pub view: i64,
pub danmaku: i64,
pub reply: i64,
pub coin: i64,
pub series_follow: Option<i64>,
pub series_view: Option<i64>,
pub likes: i64,
pub favorite: i64,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
pub struct NewEpInBangumiFollow {
pub id: Option<i64>,
pub index_show: Option<String>,
pub cover: Option<String>,
pub title: Option<String>,
pub long_title: Option<String>,
pub pub_time: Option<String>,
pub duration: Option<i64>,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
pub struct RatingInBangumiFollow {
pub score: f64,
pub count: i64,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
pub struct AreaInBangumiFollow {
pub id: i64,
pub name: String,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
pub struct SeriesInBangumiFollow {
pub series_id: Option<i64>,
pub title: Option<String>,
pub season_count: Option<i64>,
pub new_season_id: Option<i64>,
pub series_ord: Option<i64>,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
pub struct PublishInBangumiFollow {
pub pub_time: String,
pub pub_time_show: String,
pub release_date: String,
pub release_date_show: String,
pub pub_time_show_db: Option<String>,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
pub struct SectionInBangumiFollow {
pub section_id: i64,
pub season_id: i64,
pub limit_group: i64,
pub watch_platform: i64,
pub copyright: String,
pub ban_area_show: i64,
pub episode_ids: Vec<i64>,
#[serde(rename = "type")]
pub type_field: Option<i64>,
pub title: Option<String>,
pub attr: Option<i64>,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
pub struct BadgeInfoInBangumiFollow {
pub text: Option<String>,
pub bg_color: String,
pub bg_color_night: String,
pub img: Option<String>,
pub multi_img: MultiImg,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
pub struct MultiImg {
pub color: String,
pub medium_remind: String,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
pub struct FirstEpInfo {
pub id: i64,
pub cover: String,
pub title: String,
pub long_title: Option<String>,
pub pub_time: String,
pub duration: i64,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
pub struct BadgeInfos {
pub vip_or_pay: Option<VipOrPay>,
pub content_attr: Option<ContentAttr>,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
pub struct VipOrPay {
pub text: String,
pub bg_color: String,
pub bg_color_night: String,
pub img: String,
pub multi_img: MultiImg,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
pub struct ContentAttr {
pub text: String,
pub bg_color: String,
pub bg_color_night: String,
pub img: String,
pub multi_img: MultiImg,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
pub struct Producer {
pub mid: i64,
#[serde(rename = "type")]
pub type_field: i64,
pub is_contribute: Option<i64>,
pub title: String,
}
+11 -11
View File
@@ -7,7 +7,7 @@ pub struct BangumiInfo {
pub activity: Activity,
pub actors: String,
pub alias: String,
pub areas: Vec<Area>,
pub areas: Vec<AreaInBangumi>,
pub bkg_cover: String,
pub cover: String,
pub delivery_fragment_video: bool,
@@ -24,15 +24,15 @@ pub struct BangumiInfo {
pub payment: Option<PaymentInBangumi>,
pub play_strategy: Option<PlayStrategy>,
pub positive: Positive,
pub publish: Publish,
pub rating: Option<Rating>,
pub publish: PublishInBangumi,
pub rating: Option<RatingInBangumi>,
pub record: String,
pub rights: RightsInBangumi,
pub season_id: i64,
pub season_title: String,
pub seasons: Vec<Season>,
pub section: Option<Vec<SectionInBangumi>>,
pub series: Series,
pub series: SeriesInBangumi,
pub share_copy: String,
pub share_sub_title: String,
pub share_url: String,
@@ -95,7 +95,7 @@ pub struct Activity {
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
pub struct Area {
pub struct AreaInBangumi {
pub id: i64,
pub name: String,
}
@@ -105,7 +105,7 @@ pub struct Area {
pub struct EpInBangumi {
pub aid: i64,
pub badge: String,
pub badge_info: BadgeInfo,
pub badge_info: BadgeInfoInBangumi,
pub badge_type: Option<i64>,
pub bvid: Option<String>,
pub cid: i64,
@@ -140,7 +140,7 @@ pub struct EpInBangumi {
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
pub struct BadgeInfo {
pub struct BadgeInfoInBangumi {
pub bg_color: String,
pub bg_color_night: String,
pub text: String,
@@ -228,7 +228,7 @@ pub struct Positive {
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
pub struct Publish {
pub struct PublishInBangumi {
pub is_finish: i64,
pub is_started: i64,
pub pub_time: String,
@@ -238,7 +238,7 @@ pub struct Publish {
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
pub struct Rating {
pub struct RatingInBangumi {
pub count: i64,
pub score: f64,
}
@@ -266,7 +266,7 @@ pub struct RightsInBangumi {
#[allow(clippy::struct_field_names)]
pub struct Season {
pub badge: String,
pub badge_info: BadgeInfo,
pub badge_info: BadgeInfoInBangumi,
pub badge_type: i64,
pub cover: String,
pub enable_vt: bool,
@@ -298,7 +298,7 @@ pub struct StatInSeason {
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
#[allow(clippy::struct_field_names)]
pub struct Series {
pub struct SeriesInBangumi {
pub display_type: i64,
pub series_id: i64,
pub series_title: String,
@@ -0,0 +1,13 @@
use serde::{Deserialize, Serialize};
use specta::Type;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
pub struct GetBangumiFollowInfoParams {
pub vmid: i64,
/// 1: 番剧 2: 电视剧或电影
#[serde(rename = "type")]
pub type_field: i64,
pub pn: i64,
// 0: 全部 1: 想看 2: 在看 3: 看过
pub follow_status: i64,
}
+2
View File
@@ -1,4 +1,5 @@
pub mod audio_quality;
pub mod bangumi_follow_info;
pub mod bangumi_info;
pub mod bangumi_media_url;
pub mod cheese_info;
@@ -7,6 +8,7 @@ pub mod codec_type;
pub mod create_download_task_params;
pub mod fav_folders;
pub mod fav_info;
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;