diff --git a/src-tauri/src/bili_client.rs b/src-tauri/src/bili_client.rs index 1331f79..89f4c1d 100644 --- a/src-tauri/src/bili_client.rs +++ b/src-tauri/src/bili_client.rs @@ -29,8 +29,8 @@ use crate::{ 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, subtitle::Subtitle, tags::Tags, user_info::UserInfo, - user_video_info::UserVideoInfo, watch_later_info::WatchLaterInfo, + qrcode_status::QrcodeStatus, skip_segments::SkipSegments, subtitle::Subtitle, tags::Tags, + user_info::UserInfo, user_video_info::UserVideoInfo, watch_later_info::WatchLaterInfo, }, }; @@ -869,6 +869,41 @@ impl BiliClient { Ok(tags) } + pub async fn get_skip_segments( + &self, + bvid: &str, + cid: Option, + ) -> anyhow::Result { + // 发送获取跳过片段的请求 + let mut params = json!({ + "videoID": bvid, + "actionType": "skip", + }); + if let Some(cid) = cid { + params["cid"] = cid.into(); + } + + let request = self + .api_client + .read() + .get("https://bsbsb.top/api/skipSegments") + .query(¶ms); + let http_resp = request.send().await?; + // 检查http响应状态码 + let status = http_resp.status(); + let body = http_resp.text().await?; + if status == StatusCode::NOT_FOUND { + return Ok(SkipSegments(Vec::new())); + } else if status != StatusCode::OK { + return Err(anyhow!("预料之外的状态码({status}): {body}")); + } + // 尝试将body解析为SkipSegments + let skip_segments: SkipSegments = + serde_json::from_str(&body).context(format!("将body解析为SkipSegments失败: {body}"))?; + + Ok(skip_segments) + } + pub fn get_cookie(&self) -> String { let sessdata = self.app.get_config().read().sessdata.clone(); format!("SESSDATA={sessdata}") diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index e88bbb8..f19f14e 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -28,6 +28,7 @@ use crate::{ BangumiSearchResult, CheeseSearchResult, FavSearchResult, NormalSearchResult, SearchResult, UserVideoSearchResult, }, + skip_segments::SkipSegments, user_info::UserInfo, user_video_info::UserVideoInfo, watch_later_info::WatchLaterInfo, @@ -361,3 +362,18 @@ pub fn show_path_in_file_manager(app: AppHandle, path: &str) -> CommandResult<() .map_err(|err| CommandError::from("在文件管理器中打开失败", err))?; Ok(()) } + +#[tauri::command(async)] +#[specta::specta] +pub async fn get_skip_segments( + app: AppHandle, + bvid: String, + cid: Option, +) -> CommandResult { + let bili_client = app.get_bili_client(); + let skip_segments = bili_client + .get_skip_segments(&bvid, cid) + .await + .map_err(|err| CommandError::from("获取跳过片段失败", err))?; + Ok(skip_segments) +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 46dfb70..0862f71 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -55,6 +55,7 @@ pub fn run() { search, get_logs_dir_size, show_path_in_file_manager, + get_skip_segments, ]) .events(tauri_specta::collect_events![LogEvent, DownloadEvent]); diff --git a/src-tauri/src/types/mod.rs b/src-tauri/src/types/mod.rs index ad34195..cf5e5de 100644 --- a/src-tauri/src/types/mod.rs +++ b/src-tauri/src/types/mod.rs @@ -22,6 +22,7 @@ pub mod qrcode_data; pub mod qrcode_status; pub mod search_params; pub mod search_result; +pub mod skip_segments; pub mod subtitle; pub mod tags; pub mod user_info; diff --git a/src-tauri/src/types/skip_segments.rs b/src-tauri/src/types/skip_segments.rs new file mode 100644 index 0000000..df45b1d --- /dev/null +++ b/src-tauri/src/types/skip_segments.rs @@ -0,0 +1,21 @@ +use serde::{Deserialize, Serialize}; +use specta::Type; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)] +pub struct SkipSegments(pub Vec); + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)] +pub struct SkipSegment { + pub cid: String, + pub category: String, + #[serde(rename = "actionType")] + pub action_type: String, + pub segment: Vec, + #[serde(rename = "UUID")] + pub uuid: String, + #[serde(rename = "videoDuration")] + pub video_duration: i64, + pub locked: i64, + pub votes: i64, + pub description: String, +} diff --git a/src/bindings.ts b/src/bindings.ts index c2b48fd..d29bee7 100644 --- a/src/bindings.ts +++ b/src/bindings.ts @@ -142,6 +142,14 @@ async showPathInFileManager(path: string) : Promise> if(e instanceof Error) throw e; else return { status: "error", error: e as any }; } +}, +async getSkipSegments(bvid: string, cid: number | null) : Promise> { + try { + return { status: "ok", data: await TAURI_INVOKE("get_skip_segments", { bvid, cid }) }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} } } @@ -357,6 +365,8 @@ export type SeriesInBangumi = { display_type: number; series_id: number; series_ export type SeriesInBangumiFollow = { series_id: number | null; title: string | null; season_count: number | null; new_season_id: number | null; series_ord: number | null } export type Show = { wide_screen: number } export type Skip = { ed: Ed; op: Op } +export type SkipSegment = { cid: string; category: string; actionType: string; segment: number[]; UUID: string; videoDuration: number; locked: number; votes: number; description: string } +export type SkipSegments = SkipSegment[] export type Staff = { mid: number; title: string; name: string; face: string; follower: number; label_style: number } export type StatInBangumi = { coins: number; danmakus: number; favorite: number; favorites: number; follow_text: string; likes: number; reply: number; share: number; views: number; vt: number } export type StatInBangumiFollow = { follow: number; view: number; danmaku: number; reply: number; coin: number; series_follow: number | null; series_view: number | null; likes: number; favorite: number }