Skip to main content

bpi_rs/user/relation/
action.rs

1// B站用户关系操作相关接口
2//
3// [查看 API 文档](https://github.com/SocialSisterYi/bilibili-API-collect/tree/master/docs/user)
4
5// --- 响应数据结构体 ---
6
7use crate::BilibiliRequest;
8use crate::BpiError;
9use crate::BpiResult;
10use crate::user::UserClient;
11use serde::{Deserialize, Serialize};
12
13/// 操作用户关系响应数据
14///
15/// 该接口的响应 `data` 字段为 `null`,因此我们使用空元组 `()` 来表示。
16
17#[derive(Debug, Clone, Deserialize, Serialize)]
18pub struct ModifyRelationResponseData;
19
20// --- API 实现 ---
21
22/// 操作代码
23///
24/// 用于 `act` 参数,定义了要执行的关系操作类型。
25#[repr(u8)]
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
27pub enum RelationAction {
28    /// 关注
29    Follow = 1,
30    /// 取关
31    Unfollow = 2,
32    /// 悄悄关注(已下线)
33    Whisper = 3,
34    /// 取消悄悄关注
35    Unwhisper = 4,
36    /// 拉黑
37    Blacklist = 5,
38    /// 取消拉黑
39    Unblacklist = 6,
40    /// 踢出粉丝
41    KickFan = 7,
42}
43
44/// 关注来源代码
45///
46/// 用于 `re_src` 参数,表示关注操作的来源。
47#[repr(u32)]
48#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
49pub enum RelationSource {
50    /// 包月充电
51    MonthlyCharge = 1,
52    /// 个人空间
53    Space = 11,
54    /// 视频
55    Video = 14,
56    /// 评论区
57    Comment = 15,
58    /// 视频播放器结束页面
59    VideoEndPage = 17,
60    /// H5推荐关注
61    H5Recommend = 58,
62    /// H5关注列表
63    H5FollowingList = 106,
64    /// H5粉丝列表
65    H5FanList = 107,
66    /// 专栏
67    Article = 115,
68    /// 私信
69    Message = 118,
70    /// 搜索
71    Search = 120,
72    /// 视频播放器左上角关注按钮
73    VideoPlayerButton = 164,
74    /// H5共同关注
75    H5CommonFollow = 167,
76    /// 创作激励计划
77    CreativeIncentive = 192,
78    /// 活动页面
79    ActivityPage = 222,
80    /// 联合投稿视频
81    JointVideo = 229,
82    /// 消息中心点赞详情
83    MessageCenterLike = 235,
84    /// 视频播放器关注弹幕
85    VideoPlayerDanmaku = 245,
86}
87
88/// Parameters for modifying a user relation.
89#[derive(Debug, Clone, Copy, PartialEq, Eq)]
90pub struct UserModifyRelationParams {
91    fid: u64,
92    action: RelationAction,
93    source: Option<RelationSource>,
94}
95
96impl UserModifyRelationParams {
97    pub fn new(fid: u64, action: RelationAction) -> BpiResult<Self> {
98        if fid == 0 {
99            return Err(BpiError::invalid_parameter("fid", "id must be non-zero"));
100        }
101
102        Ok(Self {
103            fid,
104            action,
105            source: None,
106        })
107    }
108
109    pub fn source(mut self, source: RelationSource) -> Self {
110        self.source = Some(source);
111        self
112    }
113
114    fn into_multipart(self, csrf: &str) -> reqwest::multipart::Form {
115        let mut form = reqwest::multipart::Form::new()
116            .text("fid", self.fid.to_string())
117            .text("act", (self.action as u8).to_string())
118            .text("csrf", csrf.to_string());
119
120        if let Some(source) = self.source {
121            form = form.text("re_src", (source as u32).to_string());
122        }
123
124        form
125    }
126}
127
128// --- 测试模块 ---
129
130impl<'a> UserClient<'a> {
131    /// Modifies a user relation and returns the canonical payload result.
132    pub async fn modify_relation(&self, params: UserModifyRelationParams) -> BpiResult<Option<()>> {
133        let csrf = self.client.csrf()?;
134        let form = params.into_multipart(&csrf);
135
136        self.client
137            .post("https://api.bilibili.com/x/relation/modify")
138            .multipart(form)
139            .send_bpi_optional_payload("user.relation.modify")
140            .await
141    }
142}
143
144#[cfg(test)]
145mod tests {}