bpi_rs/article/
action.rs

1//! 专栏点赞&投币&收藏
2//!
3//! https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/article/action.md
4
5use crate::{BilibiliRequest, BpiClient, BpiError, BpiResponse};
6
7/// 投币响应数据
8#[derive(Debug, Clone, serde::Deserialize)]
9pub struct CoinResponseData {
10    /// 是否点赞成功 true:成功 false:失败 已赞过则附加点赞失败
11    pub like: bool,
12}
13
14impl BpiClient {
15    /// 点赞文章
16    ///
17    /// # 参数
18    /// | 名称   | 类型  | 说明                     |
19    /// | ------ | ----- | ------------------------ |
20    /// | `id`   | u64   | 文章 cvid (必要)         |
21    /// | `like` | bool  | 是否点赞,`true` 点赞,`false` 取消点赞 |
22    ///
23    /// # 文档
24    /// [点赞文章](https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/article/action.md#点赞文章)
25    pub async fn article_like(
26        &self,
27        id: u64,
28        like: bool,
29    ) -> Result<BpiResponse<serde_json::Value>, BpiError> {
30        let csrf = self.csrf()?;
31        let r#type = if like { 1 } else { 2 };
32
33        let result = self
34            .post("https://api.bilibili.com/x/article/like")
35            .form(&[
36                ("id", id.to_string()),
37                ("type", r#type.to_string()),
38                ("csrf", csrf),
39            ])
40            .send_bpi("点赞文章")
41            .await?;
42
43        Ok(result)
44    }
45
46    /// 投币文章
47    ///
48    /// # 参数
49    /// | 名称       | 类型  | 说明                        |
50    /// | ---------- | ----- | --------------------------- |
51    /// | `aid`      | i64   | 文章 cvid (必要)            |
52    /// | `upid`     | i64   | 文章作者 mid (必要)         |
53    /// | `multiply` | u32   | 投币数量 (必要,上限为 2)   |
54    ///
55    /// # 文档
56    /// [投币文章](https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/article/action.md#投币文章)
57    pub async fn article_coin(
58        &self,
59        aid: u64,
60        upid: u64,
61        multiply: u32,
62    ) -> Result<BpiResponse<CoinResponseData>, BpiError> {
63        let multiply = multiply.min(2);
64        let csrf = self.csrf()?;
65
66        let result = self
67            .post("https://api.bilibili.com/x/web-interface/coin/add")
68            .form(&[
69                ("aid", aid.to_string()),
70                ("upid", upid.to_string()),
71                ("multiply", multiply.to_string()),
72                ("avtype", "2".to_string()),
73                ("csrf", csrf),
74            ])
75            .send_bpi("投币文章")
76            .await?;
77
78        Ok(result)
79    }
80
81    /// 收藏文章
82    ///
83    /// # 参数
84    /// | 名称   | 类型  | 说明             |
85    /// | ------ | ----- | ---------------- |
86    /// | `id`   | u64   | 文章 cvid (必要) |
87    ///
88    /// # 文档
89    /// [收藏文章](https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/article/action.md#收藏文章)
90    pub async fn article_favorite(
91        &self,
92        id: u64,
93    ) -> Result<BpiResponse<serde_json::Value>, BpiError> {
94        let csrf = self.csrf()?;
95
96        let result = self
97            .post("https://api.bilibili.com/x/article/favorites/add")
98            .form(&[("id", id.to_string()), ("csrf", csrf)])
99            .send_bpi("收藏文章")
100            .await?;
101
102        Ok(result)
103    }
104
105    /// 收藏文章
106    ///
107    /// # 参数
108    /// | 名称   | 类型  | 说明             |
109    /// | ------ | ----- | ---------------- |
110    /// | `id`   | i64   | 文章 cvid (必要) |
111    ///
112    /// # 文档
113    /// [收藏文章](https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/article/action.md#收藏文章)
114    pub async fn article_unfavorite(
115        &self,
116        id: i64,
117    ) -> Result<BpiResponse<serde_json::Value>, BpiError> {
118        let csrf = self.csrf()?;
119
120        let result = self
121            .post("https://api.bilibili.com/x/article/favorites/del")
122            .form(&[("id", id.to_string()), ("csrf", csrf)])
123            .send_bpi("收藏文章")
124            .await?;
125
126        Ok(result)
127    }
128}
129
130#[cfg(test)]
131mod tests {
132    use super::*;
133
134    const TEST_CVID: u64 = 1;
135    const TEST_UID: u64 = 91221505;
136    #[tokio::test]
137    async fn test_like_article() -> Result<(), Box<BpiError>> {
138        let bpi = BpiClient::new();
139        bpi.article_like(TEST_CVID, true)
140            .await
141            .map(|_| ())
142            .or_else(|e| {
143                if e.code() == Some(65006) {
144                    Ok(())
145                } else {
146                    Err(Box::new(e))
147                }
148            })
149    }
150
151    #[tokio::test]
152    async fn test_coin_article() -> Result<(), Box<BpiError>> {
153        let bpi = BpiClient::new();
154        let multiply = 1;
155
156        bpi.article_coin(TEST_CVID, TEST_UID, multiply)
157            .await
158            .map(|_| ())
159            .or_else(|e| {
160                if e.code() == Some(34005) {
161                    Ok(())
162                } else {
163                    Err(Box::new(e))
164                }
165            })
166    }
167
168    #[tokio::test]
169    async fn test_favorite_article() -> Result<(), Box<BpiError>> {
170        let bpi = BpiClient::new();
171
172        bpi.article_favorite(TEST_CVID).await?;
173        Ok(())
174    }
175}