Skip to main content

bpi_rs/article/
action.rs

1//! 专栏点赞&投币&收藏
2//!
3//! [查看 API 文档](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                &[
37                    ("id", id.to_string()),
38                    ("type", r#type.to_string()),
39                    ("csrf", csrf),
40                ]
41            )
42            .send_bpi("点赞文章").await?;
43
44        Ok(result)
45    }
46
47    /// 投币文章
48    ///
49    /// # 参数
50    /// | 名称       | 类型  | 说明                        |
51    /// | ---------- | ----- | --------------------------- |
52    /// | `aid`      | i64   | 文章 cvid (必要)            |
53    /// | `upid`     | i64   | 文章作者 mid (必要)         |
54    /// | `multiply` | u32   | 投币数量 (必要,上限为 2)   |
55    ///
56    /// # 文档
57    /// [投币文章](https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/article/action.md#投币文章)
58    pub async fn article_coin(
59        &self,
60        aid: u64,
61        upid: u64,
62        multiply: u32
63    ) -> Result<BpiResponse<CoinResponseData>, BpiError> {
64        let multiply = multiply.min(2);
65        let csrf = self.csrf()?;
66
67        let result = self
68            .post("https://api.bilibili.com/x/web-interface/coin/add")
69            .form(
70                &[
71                    ("aid", aid.to_string()),
72                    ("upid", upid.to_string()),
73                    ("multiply", multiply.to_string()),
74                    ("avtype", "2".to_string()),
75                    ("csrf", csrf),
76                ]
77            )
78            .send_bpi("投币文章").await?;
79
80        Ok(result)
81    }
82
83    /// 收藏文章
84    ///
85    /// # 参数
86    /// | 名称   | 类型  | 说明             |
87    /// | ------ | ----- | ---------------- |
88    /// | `id`   | u64   | 文章 cvid (必要) |
89    ///
90    /// # 文档
91    /// [收藏文章](https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/article/action.md#收藏文章)
92    pub async fn article_favorite(
93        &self,
94        id: u64
95    ) -> Result<BpiResponse<serde_json::Value>, BpiError> {
96        let csrf = self.csrf()?;
97
98        let result = self
99            .post("https://api.bilibili.com/x/article/favorites/add")
100            .form(
101                &[
102                    ("id", id.to_string()),
103                    ("csrf", csrf),
104                ]
105            )
106            .send_bpi("收藏文章").await?;
107
108        Ok(result)
109    }
110
111    /// 收藏文章
112    ///
113    /// # 参数
114    /// | 名称   | 类型  | 说明             |
115    /// | ------ | ----- | ---------------- |
116    /// | `id`   | i64   | 文章 cvid (必要) |
117    ///
118    /// # 文档
119    /// [收藏文章](https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/article/action.md#收藏文章)
120    pub async fn article_unfavorite(
121        &self,
122        id: i64
123    ) -> Result<BpiResponse<serde_json::Value>, BpiError> {
124        let csrf = self.csrf()?;
125
126        let result = self
127            .post("https://api.bilibili.com/x/article/favorites/del")
128            .form(
129                &[
130                    ("id", id.to_string()),
131                    ("csrf", csrf),
132                ]
133            )
134            .send_bpi("收藏文章").await?;
135
136        Ok(result)
137    }
138}
139
140#[cfg(test)]
141mod tests {
142    use super::*;
143
144    const TEST_CVID: u64 = 1;
145    const TEST_UID: u64 = 91221505;
146    #[tokio::test]
147    async fn test_like_article() -> Result<(), Box<BpiError>> {
148        let bpi = BpiClient::new();
149        bpi.article_like(TEST_CVID, true).await
150            .map(|_| ())
151            .or_else(|e| {
152                if e.code() == Some(65006) { Ok(()) } else { Err(Box::new(e)) }
153            })
154    }
155
156    #[tokio::test]
157    async fn test_coin_article() -> Result<(), Box<BpiError>> {
158        let bpi = BpiClient::new();
159        let multiply = 1;
160
161        bpi.article_coin(TEST_CVID, TEST_UID, multiply).await
162            .map(|_| ())
163            .or_else(|e| {
164                if e.code() == Some(34005) { Ok(()) } else { Err(Box::new(e)) }
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}