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(
120 &self,
121 media_id: u64,
122 tid: Option<u32>,
123 keyword: Option<&str>,
124 order: Option<&str>,
125 typ: Option<u8>,
126 ps: u32,
127 pn: Option<u32>
128 ) -> Result<BpiResponse<FavListDetailData>, BpiError> {
129 let mut request = self.get("https://api.bilibili.com/x/v3/fav/resource/list").query(
130 &[
131 ("media_id", media_id.to_string()),
132 ("ps", ps.to_string()),
133 ("platform", "web".to_string()),
134 ]
135 );
136
137 if let Some(tid) = tid {
138 request = request.query(&[("tid", tid)]);
139 }
140 if let Some(keyword) = keyword {
141 request = request.query(&[("keyword", keyword)]);
142 }
143 if let Some(order) = order {
144 request = request.query(&[("order", order)]);
145 }
146 if let Some(typ) = typ {
147 request = request.query(&[("type", typ)]);
148 }
149 if let Some(pn) = pn {
150 request = request.query(&[("pn", pn)]);
151 }
152
153 request.send_bpi("获取收藏夹内容明细列表").await
154 }
155
156 pub async fn fav_resource_ids(
167 &self,
168 media_id: u64
169 ) -> Result<BpiResponse<Vec<FavResourceIdItem>>, BpiError> {
170 self
171 .get("https://api.bilibili.com/x/v3/fav/resource/ids")
172 .query(
173 &[
174 ("media_id", media_id.to_string()),
175 ("platform", "web".to_string()),
176 ]
177 )
178 .send_bpi("获取收藏夹全部内容id").await
179 }
180}
181
182#[cfg(test)]
183mod tests {
184 use super::*;
185 use tracing::info;
186
187 #[tokio::test]
188 async fn test_get_fav_list_detail() {
189 let bpi = BpiClient::new();
190 let media_id = 1572769770;
191 let resp = bpi.fav_list_detail(
192 media_id,
193 None,
194 None,
195 Some("mtime"),
196 Some(0),
197 5,
198 Some(1)
199 ).await;
200
201 info!("{:?}", resp);
202 assert!(resp.is_ok());
203
204 let resp_data = resp.unwrap();
205 info!("code: {}", resp_data.code);
206 if let Some(data) = resp_data.data {
207 info!("has_more: {}", data.has_more);
208 info!("total media count: {}", data.info.media_count);
209 info!("retrieved media count: {}", data.medias.len());
210 info!("first media item: {:?}", data.medias.first());
211 }
212 }
213
214 #[tokio::test]
215 async fn test_get_fav_resource_ids() {
216 let bpi = BpiClient::new();
217 let media_id = 1572769770;
218 let resp = bpi.fav_resource_ids(media_id).await;
219
220 info!("{:?}", resp);
221 assert!(resp.is_ok());
222
223 let resp_data = resp.unwrap();
224 info!("code: {}", resp_data.code);
225 if let Some(data) = resp_data.data {
226 info!("total IDs retrieved: {}", data.len());
227 info!("first ID item: {:?}", data.first());
228 }
229 }
230}