mirror of
https://github.com/lanyeeee/bilibili-video-downloader.git
synced 2026-09-08 17:16:52 +08:00
feat: 后端支持获取番剧视频信息
This commit is contained in:
@@ -15,6 +15,7 @@ use tauri::{
|
||||
use crate::{
|
||||
extensions::AppHandleExt,
|
||||
types::{
|
||||
bangumi_info::BangumiInfo, get_bangumi_info_params::GetBangumiInfoParams,
|
||||
get_normal_info_params::GetNormalInfoParams, normal_info::NormalInfo,
|
||||
qrcode_data::QrcodeData, qrcode_status::QrcodeStatus, user_info::UserInfo,
|
||||
},
|
||||
@@ -178,6 +179,48 @@ impl BiliClient {
|
||||
Ok(normal_info)
|
||||
}
|
||||
|
||||
pub async fn get_bangumi_info(
|
||||
&self,
|
||||
params: GetBangumiInfoParams,
|
||||
) -> anyhow::Result<BangumiInfo> {
|
||||
use GetBangumiInfoParams::{EpId, SeasonId};
|
||||
let params = match params {
|
||||
EpId(ep_id) => json!({"ep_id": ep_id}),
|
||||
SeasonId(season_id) => json!({"season_id": season_id}),
|
||||
};
|
||||
// 发送获取番剧视频信息的请求
|
||||
let request = self
|
||||
.api_client
|
||||
.read()
|
||||
.get("https://api.bilibili.com/pgc/view/web/season")
|
||||
.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解析为BangumiInfo
|
||||
let data_str = data.to_string();
|
||||
let bangumi_info: BangumiInfo = serde_json::from_str(&data_str)
|
||||
.context(format!("将data解析为BangumiInfo失败: {data_str}"))?;
|
||||
|
||||
Ok(bangumi_info)
|
||||
}
|
||||
|
||||
fn get_cookie(&self) -> String {
|
||||
let sessdata = self.app.get_config().read().sessdata.clone();
|
||||
format!("SESSDATA={sessdata}")
|
||||
|
||||
@@ -7,8 +7,7 @@ use crate::{
|
||||
extensions::AppHandleExt,
|
||||
logger,
|
||||
types::{
|
||||
get_normal_info_params::GetNormalInfoParams, normal_info::NormalInfo,
|
||||
qrcode_data::QrcodeData, qrcode_status::QrcodeStatus, user_info::UserInfo,
|
||||
bangumi_info::BangumiInfo, get_bangumi_info_params::GetBangumiInfoParams, get_normal_info_params::GetNormalInfoParams, normal_info::NormalInfo, qrcode_data::QrcodeData, qrcode_status::QrcodeStatus, user_info::UserInfo
|
||||
},
|
||||
};
|
||||
|
||||
@@ -108,3 +107,17 @@ pub async fn get_normal_info(
|
||||
.map_err(|err| CommandError::from("获取普通视频信息失败", err))?;
|
||||
Ok(normal_info)
|
||||
}
|
||||
|
||||
#[tauri::command(async)]
|
||||
#[specta::specta]
|
||||
pub async fn get_bangumi_info(
|
||||
app: AppHandle,
|
||||
params: GetBangumiInfoParams,
|
||||
) -> CommandResult<BangumiInfo> {
|
||||
let bili_client = app.get_bili_client();
|
||||
let bangumi_info = bili_client
|
||||
.get_bangumi_info(params)
|
||||
.await
|
||||
.map_err(|err| CommandError::from("获取番剧视频信息失败", err))?;
|
||||
Ok(bangumi_info)
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ pub fn run() {
|
||||
get_qrcode_status,
|
||||
get_user_info,
|
||||
get_normal_info,
|
||||
get_bangumi_info,
|
||||
])
|
||||
.events(tauri_specta::collect_events![LogEvent]);
|
||||
|
||||
|
||||
@@ -0,0 +1,354 @@
|
||||
use anyhow::{anyhow, Context};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specta::Type;
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct BangumiInfo {
|
||||
pub activity: Activity,
|
||||
pub actors: String,
|
||||
pub alias: String,
|
||||
pub areas: Vec<Area>,
|
||||
pub bkg_cover: String,
|
||||
pub cover: String,
|
||||
pub delivery_fragment_video: bool,
|
||||
pub enable_vt: bool,
|
||||
pub episodes: Vec<EpInBangumi>,
|
||||
pub evaluate: String,
|
||||
pub hide_ep_vv_vt_dm: i64,
|
||||
pub icon_font: IconFont,
|
||||
pub jp_title: String,
|
||||
pub link: String,
|
||||
pub media_id: i64,
|
||||
pub mode: i64,
|
||||
pub new_ep: NewEp,
|
||||
pub payment: Option<PaymentInBangumi>,
|
||||
pub play_strategy: Option<PlayStrategy>,
|
||||
pub positive: Positive,
|
||||
pub publish: Publish,
|
||||
pub rating: Option<Rating>,
|
||||
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 share_copy: String,
|
||||
pub share_sub_title: String,
|
||||
pub share_url: String,
|
||||
pub show: Show,
|
||||
pub show_season_type: i64,
|
||||
pub square_cover: String,
|
||||
pub staff: String,
|
||||
pub stat: StatInBangumi,
|
||||
pub status: i64,
|
||||
pub styles: Vec<String>,
|
||||
pub subtitle: String,
|
||||
pub title: String,
|
||||
pub total: i64,
|
||||
#[serde(rename = "type")]
|
||||
pub type_field: i64,
|
||||
pub up_info: Option<UpInfoInBangumi>,
|
||||
pub user_status: UserStatusInBangumi,
|
||||
}
|
||||
|
||||
impl BangumiInfo {
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
pub fn get_episode_with_order(&self, ep_id: i64) -> anyhow::Result<(&EpInBangumi, i64)> {
|
||||
let episode_with_order = self
|
||||
.episodes
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, ep)| (ep, i as i64 + 1))
|
||||
.find(|(ep, _)| ep.id == ep_id);
|
||||
|
||||
let episode_with_order = if let Some(episode_with_order) = episode_with_order {
|
||||
// 如果在正片中找到了对应的ep_id
|
||||
episode_with_order
|
||||
} else {
|
||||
// 如果在正片中没有找到对应的ep_id,则在section中查找
|
||||
let Some(sections) = &self.section else {
|
||||
return Err(anyhow!("找不到对应的ep_id为`{ep_id}`的番剧"));
|
||||
};
|
||||
let section_index = sections
|
||||
.iter()
|
||||
.position(|s| s.episodes.iter().any(|e| e.id == ep_id))
|
||||
.context(format!("找不到含有ep_id为`{ep_id}`的ep的section"))?;
|
||||
sections[section_index]
|
||||
.episodes
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, e)| (e, i as i64 + 1))
|
||||
.find(|(e, _)| e.id == ep_id)
|
||||
.context(format!("在section中找不到ep_id为`{ep_id}`的ep"))?
|
||||
};
|
||||
|
||||
Ok(episode_with_order)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct Activity {
|
||||
pub head_bg_url: String,
|
||||
pub id: i64,
|
||||
pub title: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct Area {
|
||||
pub id: i64,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
#[allow(clippy::struct_field_names)]
|
||||
pub struct EpInBangumi {
|
||||
pub aid: i64,
|
||||
pub badge: String,
|
||||
pub badge_info: BadgeInfo,
|
||||
pub badge_type: Option<i64>,
|
||||
pub bvid: Option<String>,
|
||||
pub cid: i64,
|
||||
pub cover: String,
|
||||
pub dimension: Option<DimensionInBangumi>,
|
||||
pub duration: Option<u64>,
|
||||
pub enable_vt: bool,
|
||||
pub ep_id: i64,
|
||||
pub from: Option<String>,
|
||||
pub id: i64,
|
||||
pub is_view_hide: bool,
|
||||
pub link: String,
|
||||
pub link_type: Option<String>,
|
||||
pub long_title: Option<String>,
|
||||
pub pub_time: i64,
|
||||
pub pv: i64,
|
||||
pub release_date: Option<String>,
|
||||
pub rights: Option<RightsInBangumiEp>,
|
||||
pub section_type: i64,
|
||||
pub share_copy: Option<String>,
|
||||
pub share_url: Option<String>,
|
||||
pub short_link: Option<String>,
|
||||
#[serde(rename = "showDrmLoginDialog")]
|
||||
pub show_drm_login_dialog: bool,
|
||||
pub show_title: Option<String>,
|
||||
pub skip: Option<Skip>,
|
||||
pub status: i64,
|
||||
pub subtitle: Option<String>,
|
||||
pub title: String,
|
||||
pub vid: Option<String>,
|
||||
pub icon_font: Option<IconFont>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct BadgeInfo {
|
||||
pub bg_color: String,
|
||||
pub bg_color_night: String,
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct DimensionInBangumi {
|
||||
pub height: i64,
|
||||
pub rotate: i64,
|
||||
pub width: i64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct RightsInBangumiEp {
|
||||
pub allow_dm: i64,
|
||||
pub allow_download: i64,
|
||||
pub area_limit: i64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct Skip {
|
||||
pub ed: Ed,
|
||||
pub op: Op,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct Ed {
|
||||
pub end: i64,
|
||||
pub start: i64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct Op {
|
||||
pub end: i64,
|
||||
pub start: i64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct IconFont {
|
||||
pub name: String,
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct NewEp {
|
||||
pub desc: String,
|
||||
pub id: i64,
|
||||
pub is_new: i64,
|
||||
pub title: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct PaymentInBangumi {
|
||||
pub discount: i64,
|
||||
pub pay_type: PayType,
|
||||
pub price: String,
|
||||
pub promotion: String,
|
||||
pub tip: String,
|
||||
pub view_start_time: i64,
|
||||
pub vip_discount: i64,
|
||||
pub vip_first_promotion: String,
|
||||
pub vip_price: String,
|
||||
pub vip_promotion: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct PayType {
|
||||
pub allow_discount: i64,
|
||||
pub allow_pack: i64,
|
||||
pub allow_ticket: i64,
|
||||
pub allow_time_limit: i64,
|
||||
pub allow_vip_discount: i64,
|
||||
pub forbid_bb: i64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct PlayStrategy {
|
||||
pub strategies: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct Positive {
|
||||
pub id: i64,
|
||||
pub title: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct Publish {
|
||||
pub is_finish: i64,
|
||||
pub is_started: i64,
|
||||
pub pub_time: String,
|
||||
pub pub_time_show: String,
|
||||
pub unknow_pub_date: i64,
|
||||
pub weekday: i64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct Rating {
|
||||
pub count: i64,
|
||||
pub score: f64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct RightsInBangumi {
|
||||
pub allow_bp: i64,
|
||||
pub allow_bp_rank: i64,
|
||||
pub allow_download: i64,
|
||||
pub allow_review: i64,
|
||||
pub area_limit: i64,
|
||||
pub ban_area_show: i64,
|
||||
pub can_watch: i64,
|
||||
pub copyright: String,
|
||||
pub forbid_pre: i64,
|
||||
pub freya_white: i64,
|
||||
pub is_cover_show: i64,
|
||||
pub is_preview: i64,
|
||||
pub only_vip_download: i64,
|
||||
pub resource: String,
|
||||
pub watch_platform: i64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
#[allow(clippy::struct_field_names)]
|
||||
pub struct Season {
|
||||
pub badge: String,
|
||||
pub badge_info: BadgeInfo,
|
||||
pub badge_type: i64,
|
||||
pub cover: String,
|
||||
pub enable_vt: bool,
|
||||
pub horizontal_cover_1610: String,
|
||||
pub horizontal_cover_169: String,
|
||||
pub icon_font: IconFont,
|
||||
pub media_id: i64,
|
||||
pub new_ep: NewEpInSeason,
|
||||
pub season_id: i64,
|
||||
pub season_title: String,
|
||||
pub season_type: i64,
|
||||
pub stat: StatInSeason,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct NewEpInSeason {
|
||||
pub cover: String,
|
||||
pub id: i64,
|
||||
pub index_show: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct StatInSeason {
|
||||
pub favorites: i64,
|
||||
pub series_follow: i64,
|
||||
pub views: i64,
|
||||
pub vt: i64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
#[allow(clippy::struct_field_names)]
|
||||
pub struct Series {
|
||||
pub display_type: i64,
|
||||
pub series_id: i64,
|
||||
pub series_title: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct Show {
|
||||
pub wide_screen: i64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct StatInBangumi {
|
||||
pub coins: i64,
|
||||
pub danmakus: i64,
|
||||
pub favorite: i64,
|
||||
pub favorites: i64,
|
||||
pub follow_text: String,
|
||||
pub likes: i64,
|
||||
pub reply: i64,
|
||||
pub share: i64,
|
||||
pub views: i64,
|
||||
pub vt: i64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct UpInfoInBangumi {
|
||||
pub avatar: String,
|
||||
pub mid: i64,
|
||||
pub uname: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct UserStatusInBangumi {
|
||||
pub area_limit: i64,
|
||||
pub ban_area_show: i64,
|
||||
pub follow: i64,
|
||||
pub follow_status: i64,
|
||||
pub login: i64,
|
||||
pub pay: i64,
|
||||
pub pay_pack_paid: i64,
|
||||
pub sponsor: i64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct SectionInBangumi {
|
||||
pub attr: i64,
|
||||
pub episodes: Vec<EpInBangumi>,
|
||||
pub id: i64,
|
||||
pub title: String,
|
||||
#[serde(rename = "type")]
|
||||
pub type_field: i64,
|
||||
pub type2: i64,
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specta::Type;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub enum GetBangumiInfoParams {
|
||||
EpId(i64),
|
||||
SeasonId(i64),
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
pub mod bangumi_info;
|
||||
pub mod get_bangumi_info_params;
|
||||
pub mod get_normal_info_params;
|
||||
pub mod log_level;
|
||||
pub mod normal_info;
|
||||
|
||||
Reference in New Issue
Block a user