Skip to main content

bpi_rs/user/relation/
following.rs

1//! B站用户关注列表相关接口
2//!
3//! [查看 API 文档](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 OfficialVerify {
12    /// 用户认证类型,-1: 无, 0: UP 主认证, 1: 机构认证
13    #[serde(rename = "type")]
14    pub verify_type: i8,
15    /// 用户认证信息,无则为空
16    pub desc: String,
17}
18
19/// 大会员标签
20#[derive(Debug, Clone, Deserialize, Serialize)]
21pub struct VipLabel {
22    pub path: String,
23}
24
25/// 会员信息
26#[derive(Debug, Clone, Deserialize, Serialize)]
27pub struct VipInfo {
28    /// 会员类型,0: 无, 1: 月度大会员, 2: 年度以上大会员
29    #[serde(rename = "vipType")]
30    pub vip_type: u8,
31    /// 会员到期时间,毫秒级时间戳
32    #[serde(rename = "vipDueDate")]
33    pub vip_due_date: u64,
34    #[serde(rename = "dueRemark")]
35    pub due_remark: String,
36    #[serde(rename = "accessStatus")]
37    pub access_status: u8,
38    /// 大会员状态,0: 无, 1: 有
39    #[serde(rename = "vipStatus")]
40    pub vip_status: u8,
41    #[serde(rename = "vipStatusWarn")]
42    pub vip_status_warn: String,
43    #[serde(rename = "themeType")]
44    pub theme_type: u8,
45    pub label: VipLabel,
46}
47
48/// 关系列表对象
49#[derive(Debug, Clone, Deserialize, Serialize)]
50pub struct RelationListItem {
51    /// 用户 mid
52    pub mid: u64,
53    /// 对方对于自己的关系属性,0: 未关注, 1: 悄悄关注, 2: 已关注, 6: 已互粉, 128: 已拉黑
54    pub attribute: u8,
55    /// 对方关注目标用户时间,秒级时间戳
56    pub mtime: u64,
57    /// 目标用户将对方分组到的 id
58    pub tag: Option<Vec<u64>>,
59    /// 目标用户特别关注对方标识,0: 否, 1: 是
60    pub special: u8,
61    pub contract_info: Option<serde_json::Value>,
62    /// 用户昵称
63    pub uname: String,
64    /// 用户头像 url
65    pub face: String,
66    /// 用户签名
67    pub sign: String,
68    /// 是否为 NFT 头像
69    pub face_nft: u8,
70    /// 认证信息
71    pub official_verify: OfficialVerify,
72    /// 会员信息
73    pub vip: VipInfo,
74    #[serde(rename = "name_render")]
75    pub name_render: Option<serde_json::Value>,
76    #[serde(rename = "nft_icon")]
77    pub nft_icon: Option<String>,
78    /// 推荐该用户的原因
79    pub rec_reason: Option<String>,
80    #[serde(rename = "track_id")]
81    pub track_id: Option<String>,
82    #[serde(rename = "follow_time")]
83    pub follow_time: Option<String>,
84}
85
86/// 用户关注明细响应数据
87#[derive(Debug, Clone, Deserialize, Serialize)]
88pub struct FollowingListResponseData {
89    /// 明细列表
90    pub list: Vec<RelationListItem>,
91    pub re_version: u32,
92    /// 关注总数
93    pub total: u64,
94}
95
96// --- API 实现 ---
97
98impl BpiClient {
99    /// 查询用户关注明细
100    ///
101    /// # 文档
102    /// [查看API文档](https://github.com/SocialSisterYi/bilibili-API-collect/tree/master/docs/user)
103    ///
104    /// # 参数
105    /// | 名称        | 类型           | 说明                                   |
106    /// | ----------- | --------------| -------------------------------------- |
107    /// | `vmid`      | u64           | 目标用户 mid                           |
108    /// | `order_type`| `Option<&str>`  | 排序方式,可选                         |
109    /// | `ps`        | `Option<u32>`   | 每页项数,默认50                       |
110    /// | `pn`        | `Option<u32>`   | 页码,默认1                            |
111    pub async fn user_followings(
112        &self,
113        vmid: u64,
114        order_type: Option<&str>,
115        ps: Option<u32>,
116        pn: Option<u32>
117    ) -> Result<BpiResponse<FollowingListResponseData>, BpiError> {
118        let mut req = self
119            .get("https://api.bilibili.com/x/relation/followings")
120            .with_bilibili_headers()
121            .query(&[("vmid", &vmid.to_string())]);
122
123        if let Some(o) = order_type {
124            req = req.query(&[("order_type", o)]);
125        }
126        if let Some(p) = ps {
127            req = req.query(&[("ps", &p.to_string())]);
128        }
129        if let Some(p) = pn {
130            req = req.query(&[("pn", &p.to_string())]);
131        }
132
133        req.send_bpi("查询用户关注明细").await
134    }
135}
136
137// --- 测试模块 ---
138
139#[cfg(test)]
140mod tests {
141    use super::*;
142    use tracing::info;
143
144    const TEST_VMID: u64 = 293793435;
145
146    #[tokio::test]
147    async fn test_user_followings() -> Result<(), BpiError> {
148        let bpi = BpiClient::new();
149        let resp = bpi.user_followings(TEST_VMID, None, Some(50), Some(1)).await?;
150        let data = resp.into_data()?;
151
152        info!("用户关注明细: {:?}", data);
153        assert!(!data.list.is_empty());
154        assert_eq!(data.list.len(), 50);
155
156        Ok(())
157    }
158}