bpi_rs/user/
status_number.rs

1//! B站用户关系、UP主状态、导航栏等相关接口
2//!
3//! 文档: https://github.com/SocialSisterYi/bilibili-API-collect/tree/master/docs/user
4use crate::{BilibiliRequest, BpiClient, BpiError, BpiResponse};
5use serde::{Deserialize, Serialize};
6
7// --- 响应数据结构体 ---
8
9/// 用户关系状态数响应数据
10#[derive(Debug, Clone, Deserialize, Serialize)]
11pub struct RelationStatResponseData {
12    /// 目标用户 mid
13    pub mid: u64,
14    /// 关注数
15    pub following: u64,
16    /// 悄悄关注数
17    pub whisper: u64,
18    /// 黑名单数
19    pub black: u64,
20    /// 粉丝数
21    pub follower: u64,
22}
23
24/// UP主状态数中的视频播放量
25#[derive(Debug, Clone, Deserialize, Serialize)]
26pub struct UpstatArchive {
27    /// 视频播放量
28    pub view: u64,
29}
30
31/// UP主状态数中的专栏阅读量
32#[derive(Debug, Clone, Deserialize, Serialize)]
33pub struct UpstatArticle {
34    /// 专栏阅读量
35    pub view: u64,
36}
37
38/// UP主状态数响应数据
39#[derive(Debug, Clone, Deserialize, Serialize)]
40pub struct UpstatResponseData {
41    /// 视频播放量
42    pub archive: UpstatArchive,
43    /// 专栏阅读量
44    pub article: UpstatArticle,
45    /// 获赞次数
46    pub likes: u64,
47}
48
49/// 用户导航栏状态数中的视频列表数
50#[derive(Debug, Clone, Deserialize, Serialize)]
51pub struct NavnumChannel {
52    /// 视频列表数
53    pub master: u64,
54    /// 视频列表数
55    pub guest: u64,
56}
57
58/// 用户导航栏状态数中的收藏夹数
59#[derive(Debug, Clone, Deserialize, Serialize)]
60pub struct NavnumFavourite {
61    /// 全部收藏夹数
62    pub master: u64,
63    /// 公开收藏夹数
64    pub guest: u64,
65}
66
67/// 用户导航栏状态数响应数据
68#[derive(Debug, Clone, Deserialize, Serialize)]
69pub struct NavnumResponseData {
70    /// 投稿视频数
71    pub video: u64,
72    /// 追番数
73    pub bangumi: u64,
74    /// 追剧数
75    pub cinema: u64,
76    /// 视频列表数
77    pub channel: NavnumChannel,
78    /// 收藏夹数
79    pub favourite: NavnumFavourite,
80    /// 关注 TAG 数
81    pub tag: u64,
82    /// 投稿专栏数
83    pub article: u64,
84    pub playlist: u64,
85    /// 投稿图文数
86    pub album: u64,
87    /// 投稿音频数
88    pub audio: u64,
89    /// 投稿课程数
90    pub pugv: u64,
91    /// 动态数
92    pub opus: u64,
93    /// 视频合集数
94    #[serde(rename = "season_num")]
95    pub season_num: u64,
96}
97
98/// 相簿投稿数响应数据
99#[derive(Debug, Clone, Deserialize, Serialize)]
100pub struct AlbumCountResponseData {
101    /// 相簿总数
102    pub all_count: u64,
103    /// 发布绘画数
104    pub draw_count: u64,
105    /// 发布摄影数
106    pub photo_count: u64,
107    /// 发布日常(图片动态)数
108    pub daily_count: u64,
109}
110
111// --- API 实现 ---
112
113impl BpiClient {
114    /// 获取用户关系状态数
115    ///
116    /// 文档: https://github.com/SocialSisterYi/bilibili-API-collect/tree/master/docs/user
117    ///
118    /// # 参数
119    /// | 名称   | 类型   | 说明           |
120    /// | ------ | ------ | -------------- |
121    /// | `vmid` | u64    | 目标用户 mid   |
122    pub async fn user_relation_stat(
123        &self,
124        vmid: u64,
125    ) -> Result<BpiResponse<RelationStatResponseData>, BpiError> {
126        self.get("https://api.bilibili.com/x/relation/stat")
127            .query(&[("vmid", &vmid.to_string())])
128            .send_bpi("获取用户关系状态数")
129            .await
130    }
131
132    /// 获取UP主状态数
133    ///
134    /// 文档: https://github.com/SocialSisterYi/bilibili-API-collect/tree/master/docs/user
135    ///
136    /// # 参数
137    /// | 名称   | 类型   | 说明           |
138    /// | ------ | ------ | -------------- |
139    /// | `mid`  | u64    | 目标用户 mid   |
140    pub async fn user_up_stat(
141        &self,
142        mid: u64,
143    ) -> Result<BpiResponse<UpstatResponseData>, BpiError> {
144        self.get("https://api.bilibili.com/x/space/upstat")
145            .query(&[("mid", &mid.to_string())])
146            .send_bpi("获取 UP 主状态数")
147            .await
148    }
149
150    /// 获取用户导航栏状态数
151    ///
152    /// 文档: https://github.com/SocialSisterYi/bilibili-API-collect/tree/master/docs/user
153    ///
154    /// # 参数
155    /// | 名称   | 类型   | 说明           |
156    /// | ------ | ------ | -------------- |
157    /// | `mid`  | u64    | 目标用户 mid   |
158    pub async fn user_navnum(&self, mid: u64) -> Result<BpiResponse<NavnumResponseData>, BpiError> {
159        self.get("https://api.bilibili.com/x/space/navnum")
160            .query(&[("mid", &mid.to_string())])
161            .send_bpi("获取用户导航栏状态数")
162            .await
163    }
164
165    /// 获取相簿投稿数
166    ///
167    /// 文档: https://github.com/SocialSisterYi/bilibili-API-collect/tree/master/docs/user
168    ///
169    /// # 参数
170    /// | 名称   | 类型   | 说明           |
171    /// | ------ | ------ | -------------- |
172    /// | `uid`  | u64    | 目标用户 mid   |
173    pub async fn user_album_count(
174        &self,
175        uid: u64,
176    ) -> Result<BpiResponse<AlbumCountResponseData>, BpiError> {
177        self.get("https://api.vc.bilibili.com/link_draw/v1/doc/upload_count")
178            .query(&[("uid", &uid.to_string())])
179            .send_bpi("获取相簿投稿数")
180            .await
181    }
182}
183
184// --- 测试模块 ---
185
186#[cfg(test)]
187mod tests {
188    use super::*;
189    use tracing::info;
190
191    // 请在运行测试前设置环境变量 `BPI_COOKIE`,以包含 SESSDATA 等登录信息
192    // mid 根据实际情况修改
193    const TEST_MID: u64 = 332704117;
194    const TEST_UP_MID: u64 = 456664753;
195    const TEST_NAV_MID: u64 = 645769214;
196
197    #[tokio::test]
198
199    async fn test_get_relation_stat() -> Result<(), BpiError> {
200        let bpi = BpiClient::new();
201        let resp = bpi.user_relation_stat(TEST_MID).await?;
202        let data = resp.into_data()?;
203
204        info!("关系状态数: {:?}", data);
205        assert_eq!(data.mid, TEST_MID);
206
207        Ok(())
208    }
209
210    #[tokio::test]
211
212    async fn test_get_up_stat() -> Result<(), BpiError> {
213        let bpi = BpiClient::new();
214        let resp = bpi.user_up_stat(TEST_UP_MID).await?;
215        let data = resp.into_data()?;
216
217        info!("UP主状态数: {:?}", data);
218        assert!(data.likes > 0);
219
220        Ok(())
221    }
222
223    #[tokio::test]
224    async fn test_get_nav_num() -> Result<(), BpiError> {
225        let bpi = BpiClient::new();
226        let resp = bpi.user_navnum(TEST_NAV_MID).await?;
227        let data = resp.into_data()?;
228
229        info!("用户导航栏状态数: {:?}", data);
230        assert!(data.video > 0);
231
232        Ok(())
233    }
234
235    #[tokio::test]
236    async fn test_get_album_count() -> Result<(), BpiError> {
237        let bpi = BpiClient::new();
238        let resp = bpi.user_album_count(TEST_NAV_MID).await?;
239        let data = resp.into_data()?;
240
241        info!("相簿投稿数: {:?}", data);
242        assert!(data.all_count > 0);
243
244        Ok(())
245    }
246}