bpi_rs/user/relation/
group.rs1use crate::{ BilibiliRequest, BpiClient, BpiError, BpiResponse };
5use serde::{ Deserialize, Serialize };
6
7#[derive(Debug, Clone, Deserialize, Serialize)]
11pub struct CreateTagResponseData {
12 pub tagid: i64,
14}
15
16impl BpiClient {
19 pub async fn user_group_create_tag(
28 &self,
29 group_name: &str
30 ) -> Result<BpiResponse<CreateTagResponseData>, BpiError> {
31 let csrf = self.csrf()?;
32 let form = reqwest::multipart::Form
33 ::new()
34 .text("tag", group_name.to_string())
35 .text("csrf", csrf.to_string());
36
37 self
38 .post("https://api.bilibili.com/x/relation/tag/create")
39 .multipart(form)
40 .send_bpi("创建分组").await
41 }
42
43 pub async fn user_group_update_tag(
53 &self,
54 tag_id: i64,
55 new_name: &str
56 ) -> Result<BpiResponse<serde_json::Value>, BpiError> {
57 let csrf = self.csrf()?;
58 let form = reqwest::multipart::Form
59 ::new()
60 .text("tagid", tag_id.to_string())
61 .text("name", new_name.to_string())
62 .text("csrf", csrf.to_string());
63
64 self
65 .post("https://api.bilibili.com/x/relation/tag/update")
66 .multipart(form)
67 .send_bpi("重命名分组").await
68 }
69
70 pub async fn user_group_delete_tag(
79 &self,
80 tag_id: i64
81 ) -> Result<BpiResponse<serde_json::Value>, BpiError> {
82 let csrf = self.csrf()?;
83 let form = reqwest::multipart::Form
84 ::new()
85 .text("tagid", tag_id.to_string())
86 .text("csrf", csrf.to_string());
87
88 self
89 .post("https://api.bilibili.com/x/relation/tag/del")
90 .multipart(form)
91 .send_bpi("删除分组").await
92 }
93
94 pub async fn user_group_add_users_to_tags(
104 &self,
105 fids: &[u64],
106 tagids: &[i64]
107 ) -> Result<BpiResponse<serde_json::Value>, BpiError> {
108 let csrf = self.csrf()?;
109 let fids_str = fids
110 .iter()
111 .map(|id| id.to_string())
112 .collect::<Vec<_>>()
113 .join(",");
114 let tagids_str = tagids
115 .iter()
116 .map(|id| id.to_string())
117 .collect::<Vec<_>>()
118 .join(",");
119
120 let form = reqwest::multipart::Form
121 ::new()
122 .text("fids", fids_str)
123 .text("tagids", tagids_str)
124 .text("csrf", csrf.to_string());
125
126 self
127 .post("https://api.bilibili.com/x/relation/tags/addUsers")
128 .multipart(form)
129 .send_bpi("修改分组成员").await
130 }
131
132 pub async fn user_group_remove_users_(
141 &self,
142 fids: &[u64]
143 ) -> Result<BpiResponse<serde_json::Value>, BpiError> {
144 let csrf = self.csrf()?;
145 let fids_str = fids
146 .iter()
147 .map(|id| id.to_string())
148 .collect::<Vec<_>>()
149 .join(",");
150
151 let form = reqwest::multipart::Form
152 ::new()
153 .text("fids", fids_str)
154 .text("tagids", "0".to_string())
155 .text("csrf", csrf.to_string());
156
157 self
158 .post("https://api.bilibili.com/x/relation/tags/addUsers")
159 .multipart(form)
160 .send_bpi("修改分组成员").await
161 }
162
163 pub async fn user_group_copy_users_to_tags(
173 &self,
174 fids: &[u64],
175 tagids: &[i64]
176 ) -> Result<BpiResponse<serde_json::Value>, BpiError> {
177 let csrf = self.csrf()?;
178 let fids_str = fids
179 .iter()
180 .map(|id| id.to_string())
181 .collect::<Vec<_>>()
182 .join(",");
183 let tagids_str = tagids
184 .iter()
185 .map(|id| id.to_string())
186 .collect::<Vec<_>>()
187 .join(",");
188
189 let form = reqwest::multipart::Form
190 ::new()
191 .text("fids", fids_str)
192 .text("tagids", tagids_str)
193 .text("csrf", csrf.to_string());
194
195 self
196 .post("https://api.bilibili.com/x/relation/tags/copyUsers")
197 .multipart(form)
198 .send_bpi("复制关注到分组").await
199 }
200
201 pub async fn user_group_move_users_to_tags(
212 &self,
213 fids: &[u64],
214 before_tag_ids: &[i64],
215 after_tag_ids: &[i64]
216 ) -> Result<BpiResponse<serde_json::Value>, BpiError> {
217 let csrf = self.csrf()?;
218 let fids_str = fids
219 .iter()
220 .map(|id| id.to_string())
221 .collect::<Vec<_>>()
222 .join(",");
223 let before_tag_ids_str = before_tag_ids
224 .iter()
225 .map(|id| id.to_string())
226 .collect::<Vec<_>>()
227 .join(",");
228 let after_tag_ids_str = after_tag_ids
229 .iter()
230 .map(|id| id.to_string())
231 .collect::<Vec<_>>()
232 .join(",");
233
234 let form = reqwest::multipart::Form
235 ::new()
236 .text("fids", fids_str)
237 .text("beforeTagids", before_tag_ids_str)
238 .text("afterTagids", after_tag_ids_str)
239 .text("csrf", csrf.to_string());
240
241 self
242 .post("https://api.bilibili.com/x/relation/tags/moveUsers")
243 .multipart(form)
244 .send_bpi("移动关注到分组").await
245 }
246}
247
248#[cfg(test)]
251mod tests {
252 use super::*;
253 use tracing::info;
254
255 const TEST_FID: u64 = 107997089;
256
257 const DEFAULT_GROUP_FID: u64 = 3493257409464519;
258
259 #[tokio::test]
260 async fn test_tag_operations() -> Result<(), BpiError> {
261 let bpi = BpiClient::new();
262 let test_tag_name = "测试分组1";
263 let new_tag_name = "新测试分组2";
264
265 info!("正在创建分组...");
267 let create_resp = bpi.user_group_create_tag(&test_tag_name).await?;
268 let tag_id = create_resp.into_data()?.tagid;
269 info!("创建分组成功,ID: {}", tag_id);
270
271 info!("正在重命名分组...");
273 let update_resp = bpi.user_group_update_tag(tag_id, &new_tag_name).await?;
274 info!("重命名分组成功");
275 assert_eq!(update_resp.code, 0);
276
277 info!("正在将用户添加到默认分组...");
279 let add_resp = bpi.user_group_add_users_to_tags(&[TEST_FID], &[-10]).await?;
280 info!("添加用户到默认分组成功");
281 assert_eq!(add_resp.code, 0);
282
283 info!("正在将用户从默认分组移动到新分组...");
286 let move_resp = bpi.user_group_move_users_to_tags(
287 &[DEFAULT_GROUP_FID],
288 &[-10],
289 &[tag_id]
290 ).await?;
291 info!("移动用户到分组成功");
292 assert_eq!(move_resp.code, 0);
293
294 info!("正在将用户复制到分组...");
296 let copy_resp = bpi.user_group_copy_users_to_tags(&[TEST_FID], &[tag_id]).await?;
297 info!("复制用户到分组成功");
298 assert_eq!(copy_resp.code, 0);
299
300 info!("正在删除分组...");
302 let delete_resp = bpi.user_group_delete_tag(tag_id).await?;
303 info!("删除分组成功");
304 assert_eq!(delete_resp.code, 0);
305
306 Ok(())
307 }
308}