mirror of
https://github.com/lanyeeee/bilibili-video-downloader.git
synced 2026-09-09 01:27:27 +08:00
feat: 后端支持获取课程视频url
This commit is contained in:
@@ -16,10 +16,10 @@ use crate::{
|
||||
extensions::AppHandleExt,
|
||||
types::{
|
||||
bangumi_info::BangumiInfo, bangumi_media_url::BangumiMediaUrl, cheese_info::CheeseInfo,
|
||||
get_bangumi_info_params::GetBangumiInfoParams, get_cheese_info_params::GetCheeseInfoParams,
|
||||
get_normal_info_params::GetNormalInfoParams, normal_info::NormalInfo,
|
||||
normal_media_url::NormalMediaUrl, qrcode_data::QrcodeData, qrcode_status::QrcodeStatus,
|
||||
user_info::UserInfo,
|
||||
cheese_media_url::CheeseMediaUrl, get_bangumi_info_params::GetBangumiInfoParams,
|
||||
get_cheese_info_params::GetCheeseInfoParams, get_normal_info_params::GetNormalInfoParams,
|
||||
normal_info::NormalInfo, normal_media_url::NormalMediaUrl, qrcode_data::QrcodeData,
|
||||
qrcode_status::QrcodeStatus, user_info::UserInfo,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -345,6 +345,47 @@ impl BiliClient {
|
||||
Ok(media_url)
|
||||
}
|
||||
|
||||
pub async fn get_cheese_url(&self, ep_id: i64) -> anyhow::Result<CheeseMediaUrl> {
|
||||
let params = json!({
|
||||
"ep_id": ep_id,
|
||||
"qn": 127,
|
||||
"fnval": 4048,
|
||||
});
|
||||
// 发送获取课程url的请求
|
||||
let request = self
|
||||
.api_client
|
||||
.read()
|
||||
.get("https://api.bilibili.com/pugv/player/web/playurl")
|
||||
.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 == -403 {
|
||||
return Err(anyhow!("没有观看权限,请先购买: {bili_resp:?}"));
|
||||
} else 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解析为CheeseMediaUrl
|
||||
let data_str = data.to_string();
|
||||
let media_url: CheeseMediaUrl = serde_json::from_str(&data_str)
|
||||
.context(format!("将data解析为CheeseMediaUrl失败: {data_str}"))?;
|
||||
|
||||
Ok(media_url)
|
||||
}
|
||||
|
||||
fn get_cookie(&self) -> String {
|
||||
let sessdata = self.app.get_config().read().sessdata.clone();
|
||||
format!("SESSDATA={sessdata}")
|
||||
|
||||
@@ -7,11 +7,7 @@ use crate::{
|
||||
extensions::AppHandleExt,
|
||||
logger,
|
||||
types::{
|
||||
bangumi_info::BangumiInfo, bangumi_media_url::BangumiMediaUrl, cheese_info::CheeseInfo,
|
||||
get_bangumi_info_params::GetBangumiInfoParams, get_cheese_info_params::GetCheeseInfoParams,
|
||||
get_normal_info_params::GetNormalInfoParams, normal_info::NormalInfo,
|
||||
normal_media_url::NormalMediaUrl, qrcode_data::QrcodeData, qrcode_status::QrcodeStatus,
|
||||
user_info::UserInfo,
|
||||
bangumi_info::BangumiInfo, bangumi_media_url::BangumiMediaUrl, cheese_info::CheeseInfo, cheese_media_url::CheeseMediaUrl, get_bangumi_info_params::GetBangumiInfoParams, get_cheese_info_params::GetCheeseInfoParams, get_normal_info_params::GetNormalInfoParams, normal_info::NormalInfo, normal_media_url::NormalMediaUrl, qrcode_data::QrcodeData, qrcode_status::QrcodeStatus, user_info::UserInfo
|
||||
},
|
||||
};
|
||||
|
||||
@@ -165,3 +161,14 @@ pub async fn get_bangumi_url(app: AppHandle, cid: i64) -> CommandResult<BangumiM
|
||||
.map_err(|err| CommandError::from("获取番剧视频url失败", err))?;
|
||||
Ok(media_url)
|
||||
}
|
||||
|
||||
#[tauri::command(async)]
|
||||
#[specta::specta]
|
||||
pub async fn get_cheese_url(app: AppHandle, ep_id: i64) -> CommandResult<CheeseMediaUrl> {
|
||||
let bili_client = app.get_bili_client();
|
||||
let media_url = bili_client
|
||||
.get_cheese_url(ep_id)
|
||||
.await
|
||||
.map_err(|err| CommandError::from("获取课程视频url失败", err))?;
|
||||
Ok(media_url)
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ pub fn run() {
|
||||
get_cheese_info,
|
||||
get_normal_url,
|
||||
get_bangumi_url,
|
||||
get_cheese_url,
|
||||
])
|
||||
.events(tauri_specta::collect_events![LogEvent]);
|
||||
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specta::Type;
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct CheeseMediaUrl {
|
||||
pub accept_format: String,
|
||||
pub code: i64,
|
||||
pub seek_param: String,
|
||||
pub is_preview: i64,
|
||||
pub fnval: i64,
|
||||
pub video_project: bool,
|
||||
pub play_view_business_info: Option<PlayViewBusinessInfo>,
|
||||
pub fnver: i64,
|
||||
#[serde(rename = "type")]
|
||||
pub type_field: String,
|
||||
pub result: String,
|
||||
pub seek_type: String,
|
||||
pub from: String,
|
||||
pub video_codecid: i64,
|
||||
pub no_rexcode: i64,
|
||||
pub format: String,
|
||||
pub support_formats: Vec<SupportFormatInCheese>,
|
||||
pub message: String,
|
||||
pub accept_quality: Vec<i64>,
|
||||
pub quality: i64,
|
||||
pub timelength: i64,
|
||||
pub durls: Vec<DurlInCheese>,
|
||||
pub has_paid: bool,
|
||||
pub dash: Option<DashInCheese>,
|
||||
pub accept_description: Vec<String>,
|
||||
pub status: i64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct PlayViewBusinessInfo {
|
||||
pub user_status: UserStatusInCheeseUrl,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct UserStatusInCheeseUrl {
|
||||
pub watch_progress: WatchProgress,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
#[allow(clippy::struct_field_names)]
|
||||
pub struct WatchProgress {
|
||||
pub current_watch_progress: i64,
|
||||
pub last_ep_id: i64,
|
||||
pub last_ep_index: String,
|
||||
pub last_time: i64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct SupportFormatInCheese {
|
||||
pub display_desc: String,
|
||||
pub superscript: String,
|
||||
pub need_login: bool,
|
||||
pub codecs: Vec<String>,
|
||||
pub format: String,
|
||||
pub description: String,
|
||||
pub quality: i64,
|
||||
pub new_description: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct DashInCheese {
|
||||
pub duration: u64,
|
||||
pub min_buffer_time: f64,
|
||||
pub video: Vec<MediaInCheese>,
|
||||
pub audio: Option<Vec<MediaInCheese>>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct MediaInCheese {
|
||||
pub start_with_sap: i64,
|
||||
pub bandwidth: i64,
|
||||
pub sar: String,
|
||||
pub codecs: String,
|
||||
pub base_url: String,
|
||||
pub backup_url: Vec<String>,
|
||||
pub segment_base: SegmentBaseInCheese,
|
||||
pub frame_rate: String,
|
||||
pub codecid: i64,
|
||||
pub size: i64,
|
||||
pub mime_type: String,
|
||||
pub width: i64,
|
||||
pub id: i64,
|
||||
pub height: i64,
|
||||
pub md5: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct SegmentBaseInCheese {
|
||||
pub initialization: String,
|
||||
pub index_range: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct DurlInCheese {
|
||||
pub durl: Vec<DurlDetailInCheese>,
|
||||
pub quality: i64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||
pub struct DurlDetailInCheese {
|
||||
pub size: i64,
|
||||
pub ahead: String,
|
||||
pub length: i64,
|
||||
pub vhead: String,
|
||||
pub backup_url: Vec<String>,
|
||||
pub url: String,
|
||||
pub order: i64,
|
||||
pub md5: String,
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
pub mod bangumi_info;
|
||||
pub mod bangumi_media_url;
|
||||
pub mod cheese_info;
|
||||
pub mod cheese_media_url;
|
||||
pub mod get_bangumi_info_params;
|
||||
pub mod get_cheese_info_params;
|
||||
pub mod get_normal_info_params;
|
||||
|
||||
Reference in New Issue
Block a user