1use crate::{BilibiliRequest, BpiClient, BpiError, BpiResponse};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Deserialize, Serialize)]
8pub struct FavListUpper {
9 pub mid: u64,
10 pub name: String,
11 pub face: String,
12 pub followed: Option<bool>,
13 pub vip_type: Option<u8>,
14 pub vip_status: Option<u8>,
15}
16
17#[derive(Debug, Clone, Deserialize, Serialize)]
19pub struct FavListCntInfo {
20 pub collect: u64,
22 pub play: u64,
24
25 pub share: Option<u64>,
27 pub thumb_up: Option<u64>,
29 pub danmaku: Option<u64>,
31 pub view_text_1: Option<String>,
33}
34
35#[derive(Debug, Clone, Deserialize, Serialize)]
37pub struct FavListInfo {
38 pub id: u64,
39 pub fid: u64,
40 pub mid: u64,
41 pub attr: u32,
42 pub title: String,
43 pub cover: String,
44 pub upper: FavListUpper,
45 pub cover_type: u8,
46 pub cnt_info: FavListCntInfo,
47 #[serde(rename = "type")]
48 pub type_name: u32,
49 pub intro: String,
50 pub ctime: u64,
51 pub mtime: u64,
52 pub state: u8,
53 pub fav_state: u8,
54 pub like_state: u8,
55 pub media_count: u32,
56}
57
58#[derive(Debug, Clone, Deserialize, Serialize)]
60pub struct FavListMedia {
61 pub id: u64,
62 #[serde(rename = "type")]
63 pub type_name: u8,
64 pub title: String,
65 pub cover: String,
66 pub intro: String,
67 pub page: Option<u32>,
68 pub duration: u32,
69 pub upper: FavListUpper,
70 pub attr: u8,
71 pub cnt_info: FavListCntInfo,
72 pub link: String,
73 pub ctime: u64,
74 pub pubtime: u64,
75 pub fav_time: u64,
76 pub bv_id: Option<String>,
77 pub bvid: Option<String>,
78 pub season: Option<serde_json::Value>,
79}
80
81#[derive(Debug, Clone, Deserialize, Serialize)]
83pub struct FavListDetailData {
84 pub info: FavListInfo,
85 pub medias: Vec<FavListMedia>,
86 pub has_more: bool,
87 pub ttl: u64,
88}
89
90#[derive(Debug, Clone, Deserialize, Serialize)]
94pub struct FavResourceIdItem {
95 pub id: u64,
96 #[serde(rename = "type")]
97 pub type_name: u8,
98 pub bv_id: Option<String>,
99 pub bvid: Option<String>,
100}
101
102impl BpiClient {
103 pub async fn fav_list_detail(
119 &self,
120 media_id: u64,
121 tid: Option<u32>,
122 keyword: Option<&str>,
123 order: Option<&str>,
124 typ: Option<u8>,
125 ps: u32,
126 pn: Option<u32>,
127 ) -> Result<BpiResponse<FavListDetailData>, BpiError> {
128 let mut request = self
129 .get("https://api.bilibili.com/x/v3/fav/resource/list")
130 .query(&[
131 ("media_id", media_id.to_string()),
132 ("ps", ps.to_string()),
133 ("platform", "web".to_string()),
134 ]);
135
136 if let Some(tid) = tid {
137 request = request.query(&[("tid", tid)]);
138 }
139 if let Some(keyword) = keyword {
140 request = request.query(&[("keyword", keyword)]);
141 }
142 if let Some(order) = order {
143 request = request.query(&[("order", order)]);
144 }
145 if let Some(typ) = typ {
146 request = request.query(&[("type", typ)]);
147 }
148 if let Some(pn) = pn {
149 request = request.query(&[("pn", pn)]);
150 }
151
152 request.send_bpi("获取收藏夹内容明细列表").await
153 }
154
155 pub async fn fav_resource_ids(
165 &self,
166 media_id: u64,
167 ) -> Result<BpiResponse<Vec<FavResourceIdItem>>, BpiError> {
168 self.get("https://api.bilibili.com/x/v3/fav/resource/ids")
169 .query(&[
170 ("media_id", media_id.to_string()),
171 ("platform", "web".to_string()),
172 ])
173 .send_bpi("获取收藏夹全部内容id")
174 .await
175 }
176}
177
178#[cfg(test)]
179mod tests {
180 use super::*;
181 use tracing::info;
182
183 #[tokio::test]
184 async fn test_get_fav_list_detail() {
185 let bpi = BpiClient::new();
186 let media_id = 1572769770;
187 let resp = bpi
188 .fav_list_detail(media_id, None, None, Some("mtime"), Some(0), 5, Some(1))
189 .await;
190
191 info!("{:?}", resp);
192 assert!(resp.is_ok());
193
194 let resp_data = resp.unwrap();
195 info!("code: {}", resp_data.code);
196 if let Some(data) = resp_data.data {
197 info!("has_more: {}", data.has_more);
198 info!("total media count: {}", data.info.media_count);
199 info!("retrieved media count: {}", data.medias.len());
200 info!("first media item: {:?}", data.medias.first());
201 }
202 }
203
204 #[tokio::test]
205 async fn test_get_fav_resource_ids() {
206 let bpi = BpiClient::new();
207 let media_id = 1572769770;
208 let resp = bpi.fav_resource_ids(media_id).await;
209
210 info!("{:?}", resp);
211 assert!(resp.is_ok());
212
213 let resp_data = resp.unwrap();
214 info!("code: {}", resp_data.code);
215 if let Some(data) = resp_data.data {
216 info!("total IDs retrieved: {}", data.len());
217 info!("first ID item: {:?}", data.first());
218 }
219 }
220}