bpi_rs/article/action.rs
1//! 专栏点赞&投币&收藏
2//!
3//! [查看 API 文档](https://github.com/Yuelioi/bilibili-API-collect/tree/cfc5fddcc8a94b74d91970bb5b4eaeb349addc47/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/Yuelioi/bilibili-API-collect/tree/cfc5fddcc8a94b74d91970bb5b4eaeb349addc47/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/Yuelioi/bilibili-API-collect/tree/cfc5fddcc8a94b74d91970bb5b4eaeb349addc47/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/Yuelioi/bilibili-API-collect/tree/cfc5fddcc8a94b74d91970bb5b4eaeb349addc47/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/Yuelioi/bilibili-API-collect/tree/cfc5fddcc8a94b74d91970bb5b4eaeb349addc47/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}