bpi_rs/fav/
info.rs

1use crate::{BilibiliRequest, BpiClient, BpiError, BpiResponse};
2use serde::{Deserialize, Serialize};
3
4// --- 获取收藏夹元数据 ---
5
6/// 收藏夹元数据的创建者信息
7#[derive(Debug, Clone, Deserialize, Serialize)]
8pub struct FavFolderUpper {
9    pub mid: u64,
10    pub name: String,
11    pub face: String,
12    pub followed: bool,
13    pub vip_type: u8,
14    /// 阿b拼写错误
15    #[serde(rename = "vip_statue")]
16    pub vip_status: u8,
17}
18
19/// 收藏夹元数据的状态数
20#[derive(Debug, Clone, Deserialize, Serialize)]
21pub struct FavFolderCntInfo {
22    pub collect: u64,
23    pub play: u64,
24    pub thumb_up: u64,
25    pub share: u64,
26}
27
28/// 收藏夹元数据
29#[derive(Debug, Clone, Deserialize, Serialize)]
30pub struct FavFolderInfo {
31    pub id: u64,
32    pub fid: u64,
33    pub mid: u64,
34    pub attr: u32,
35    pub title: String,
36    pub cover: String,
37    pub upper: FavFolderUpper,
38    pub cover_type: u8,
39    pub cnt_info: FavFolderCntInfo,
40    #[serde(rename = "type")]
41    pub type_name: u32,
42    pub intro: String,
43    pub ctime: u64,
44    pub mtime: u64,
45    pub state: u8,
46    pub fav_state: u8,
47    pub like_state: u8,
48    pub media_count: u32,
49}
50
51// --- 获取指定用户创建的所有收藏夹信息 ---
52
53/// 用户创建的收藏夹列表项
54#[derive(Debug, Clone, Deserialize, Serialize)]
55pub struct CreatedFolderItem {
56    pub id: u64,
57    pub fid: u64,
58    pub mid: u64,
59    pub attr: u32,
60    pub title: String,
61    pub fav_state: u8,
62    pub media_count: u32,
63}
64
65/// 用户创建的收藏夹信息数据
66#[derive(Debug, Clone, Deserialize, Serialize)]
67pub struct CreatedFolderListData {
68    pub count: u32,
69    pub list: Vec<CreatedFolderItem>,
70}
71
72// --- 查询用户收藏的视频收藏夹 ---
73
74/// 用户收藏的视频收藏夹列表项的创建人信息
75#[derive(Debug, Clone, Deserialize, Serialize)]
76pub struct CollectedFolderUpper {
77    pub mid: u64,
78    pub name: String,
79    pub face: String,
80}
81
82/// 用户收藏的视频收藏夹列表项
83#[derive(Debug, Clone, Deserialize, Serialize)]
84pub struct CollectedFolderItem {
85    pub id: u64,
86    pub fid: u64,
87    pub mid: u64,
88    pub attr: u32,
89    pub title: String,
90    pub cover: String,
91    pub upper: CollectedFolderUpper,
92    pub cover_type: u8,
93    pub intro: String,
94    pub ctime: u64,
95    pub mtime: u64,
96    pub state: u8,
97    pub fav_state: u8,
98    pub media_count: u32,
99}
100
101/// 用户收藏的视频收藏夹列表数据
102#[derive(Debug, Clone, Deserialize, Serialize)]
103pub struct CollectedFolderListData {
104    pub count: u32,
105    pub list: Vec<CollectedFolderItem>,
106}
107
108// --- 批量获取指定收藏id的内容 ---
109
110/// 内容信息列表中的UP主信息
111#[derive(Debug, Clone, Deserialize, Serialize)]
112pub struct ResourceInfoUpper {
113    pub mid: u64,
114    pub name: String,
115    pub face: String,
116}
117
118/// 内容信息列表中的状态数
119#[derive(Debug, Clone, Deserialize, Serialize)]
120pub struct ResourceInfoCntInfo {
121    pub collect: u64,
122    pub play: u64,
123    pub danmaku: u64,
124}
125
126/// 批量获取的内容信息列表项
127#[derive(Debug, Clone, Deserialize, Serialize)]
128pub struct ResourceInfoItem {
129    pub id: u64,
130    #[serde(rename = "type")]
131    pub type_name: u8,
132    pub title: String,
133    pub cover: String,
134    pub intro: String,
135    pub page: Option<u32>,
136    pub duration: u32,
137    pub upper: ResourceInfoUpper,
138    pub attr: u8,
139    pub cnt_info: ResourceInfoCntInfo,
140    pub link: String,
141    pub ctime: u64,
142    pub pubtime: u64,
143    pub fav_time: u64,
144    pub bv_id: Option<String>,
145    pub bvid: Option<String>,
146    pub season: Option<serde_json::Value>,
147}
148
149impl BpiClient {
150    /// 获取收藏夹元数据
151    ///
152    /// 文档: https://github.com/SocialSisterYi/bilibili-API-collect/tree/master/docs/fav
153    ///
154    /// 参数
155    ///
156    /// | 名称 | 类型 | 说明 |
157    /// | ---- | ---- | ---- |
158    /// | `media_id` | u64 | 收藏夹 media_id |
159    pub async fn fav_folder_info(
160        &self,
161        media_id: u64,
162    ) -> Result<BpiResponse<FavFolderInfo>, BpiError> {
163        self.get("https://api.bilibili.com/x/v3/fav/folder/info")
164            .query(&[("media_id", media_id)])
165            .send_bpi("获取收藏夹元数据")
166            .await
167    }
168
169    /// 获取指定用户创建的所有收藏夹信息
170    ///
171    /// 文档: https://github.com/SocialSisterYi/bilibili-API-collect/tree/master/docs/fav
172    ///
173    /// 参数
174    ///
175    /// | 名称 | 类型 | 说明 |
176    /// | ---- | ---- | ---- |
177    /// | `up_mid` | u64 | 用户 mid |
178    /// | `typ` | Option<u8> | 类型过滤 |
179    /// | `rid` | Option<u64> | 关联资源 id |
180    pub async fn fav_created_list(
181        &self,
182        up_mid: u64,
183        typ: Option<u8>,
184        rid: Option<u64>,
185    ) -> Result<BpiResponse<CreatedFolderListData>, BpiError> {
186        let mut request = self
187            .get("https://api.bilibili.com/x/v3/fav/folder/created/list-all")
188            .query(&[("up_mid", up_mid.to_string())]);
189
190        if let Some(t) = typ {
191            request = request.query(&[("type", t)]);
192        }
193        if let Some(r) = rid {
194            request = request.query(&[("rid", r)]);
195        }
196
197        request
198            .query(&[("web_location", "333.1387")])
199            .send_bpi("获取指定用户创建的所有收藏夹信息")
200            .await
201    }
202
203    /// 查询用户收藏的视频收藏夹
204    ///
205    /// 文档: https://github.com/SocialSisterYi/bilibili-API-collect/tree/master/docs/fav
206    ///
207    /// 参数
208    ///
209    /// | 名称 | 类型 | 说明 |
210    /// | ---- | ---- | ---- |
211    /// | `up_mid` | u64 | 用户 mid |
212    /// | `pn` | u32 | 页码 |
213    /// | `ps` | u32 | 页大小 |
214    pub async fn fav_collected_list(
215        &self,
216        up_mid: u64,
217        pn: u32,
218        ps: u32,
219    ) -> Result<BpiResponse<CollectedFolderListData>, BpiError> {
220        self.get("https://api.bilibili.com/x/v3/fav/folder/collected/list")
221            .query(&[
222                ("up_mid", up_mid.to_string()),
223                ("pn", pn.to_string()),
224                ("ps", ps.to_string()),
225                ("platform", "web".to_string()),
226            ])
227            .send_bpi("查询用户收藏的视频收藏夹")
228            .await
229    }
230
231    /// 批量获取指定收藏id的内容
232    /// `resources`: "{内容id}:{内容类型},..."
233    ///
234    /// 文档: https://github.com/SocialSisterYi/bilibili-API-collect/tree/master/docs/fav
235    ///
236    /// 参数
237    ///
238    /// | 名称 | 类型 | 说明 |
239    /// | ---- | ---- | ---- |
240    /// | `resources` | &str | 形如 "{内容id}:{内容类型},..." |
241    pub async fn fav_resource_infos(
242        &self,
243        resources: &str,
244    ) -> Result<BpiResponse<Vec<ResourceInfoItem>>, BpiError> {
245        self.get("https://api.bilibili.com/x/v3/fav/resource/infos")
246            .query(&[("resources", resources), ("platform", "web")])
247            .send_bpi("批量获取指定收藏id的内容")
248            .await
249    }
250}
251
252#[cfg(test)]
253mod tests {
254    use super::*;
255    use tracing::info;
256
257    #[tokio::test]
258    async fn test_get_fav_folder_info() {
259        let bpi = BpiClient::new();
260        // 替换为一个公开收藏夹的media_id
261        let media_id = 3717139570;
262        let resp = bpi.fav_folder_info(media_id).await;
263
264        info!("{:?}", resp);
265        assert!(resp.is_ok());
266
267        let resp_data = resp.unwrap();
268        info!("code: {}", resp_data.code);
269        if let Some(data) = resp_data.data {
270            info!("folder title: {}", data.title);
271            info!("folder media_count: {}", data.media_count);
272            info!("upper info: {:?}", data.upper);
273        }
274    }
275
276    #[tokio::test]
277    async fn test_get_fav_created_list() {
278        let bpi = BpiClient::new();
279
280        let up_mid = 4279370;
281        let resp = bpi.fav_created_list(up_mid, None, None).await;
282
283        info!("{:?}", resp);
284        assert!(resp.is_ok());
285
286        let resp_data = resp.unwrap();
287        info!("code: {}", resp_data.code);
288        if let Some(data) = resp_data.data {
289            info!("created folders count: {}", data.count);
290            info!("first folder info: {:?}", data.list.first());
291        }
292    }
293
294    #[tokio::test]
295    async fn test_get_fav_collected_list() {
296        let bpi = BpiClient::new();
297
298        let up_mid = 4279370;
299        let resp = bpi.fav_collected_list(up_mid, 1, 20).await;
300
301        info!("{:?}", resp);
302        assert!(resp.is_ok());
303
304        let resp_data = resp.unwrap();
305        info!("code: {}", resp_data.code);
306        if let Some(data) = resp_data.data {
307            info!("collected folders count: {}", data.count);
308            info!("first collected folder info: {:?}", data.list.first());
309        }
310    }
311
312    #[tokio::test]
313    async fn test_get_fav_resource_infos() {
314        let bpi = BpiClient::new();
315        let resources = "115087859779103:2";
316        let resp = bpi.fav_resource_infos(resources).await;
317
318        info!("{:?}", resp);
319        assert!(resp.is_ok());
320
321        let resp_data = resp.unwrap();
322        info!("code: {}", resp_data.code);
323        if let Some(data) = resp_data.data {
324            info!("retrieved {} resources", data.len());
325            info!("first resource info: {:?}", data.first());
326        }
327    }
328}