Skip to main content

bpi_rs/fav/
list.rs

1use crate::{ BilibiliRequest, BpiClient, BpiError, BpiResponse };
2use serde::{ Deserialize, Serialize };
3
4// --- 获取收藏夹内容明细列表 ---
5
6/// 收藏夹内容明细列表中的 UP 主信息
7#[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/// 收藏夹内容明细列表中的状态数
18#[derive(Debug, Clone, Deserialize, Serialize)]
19pub struct FavListCntInfo {
20    /// 收藏
21    pub collect: u64,
22    /// 播放
23    pub play: u64,
24
25    /// 分享 (仅info)
26    pub share: Option<u64>,
27    /// 点赞 (仅info)
28    pub thumb_up: Option<u64>,
29    ///弹幕 (仅media)
30    pub danmaku: Option<u64>,
31    /// 播放文本 (仅media)
32    pub view_text_1: Option<String>,
33}
34
35/// 收藏夹元数据
36#[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/// 收藏夹中的单个内容
59#[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/// 收藏夹内容明细列表数据
82#[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// --- 获取收藏夹全部内容id ---
91
92/// 收藏夹全部内容ID列表中的单个ID
93#[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    /// 获取收藏夹内容明细列表
104    ///
105    /// # 文档
106    /// [查看API文档](https://github.com/SocialSisterYi/bilibili-API-collect/tree/master/docs/fav)
107    ///
108    /// # 参数
109    ///
110    /// | 名称 | 类型 | 说明 |
111    /// | ---- | ---- | ---- |
112    /// | `media_id` | u64 | 收藏夹 media_id |
113    /// | `tid` | `Option<u32>` | 分区 tid |
114    /// | `keyword` | `Option<&str>` | 关键词过滤 |
115    /// | `order` | `Option<&str>` | 排序,如 `mtime` |
116    /// | `typ` | `Option<u8>` | 内容类型 |
117    /// | `ps` | u32 | 每页条数 |
118    /// | `pn` | `Option<u32>` | 页码 |
119    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    /// 获取收藏夹全部内容id
157    ///
158    /// # 文档
159    /// [查看API文档](https://github.com/SocialSisterYi/bilibili-API-collect/tree/master/docs/fav)
160    ///
161    /// # 参数
162    ///
163    /// | 名称 | 类型 | 说明 |
164    /// | ---- | ---- | ---- |
165    /// | `media_id` | u64 | 收藏夹 media_id |
166    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}