bpi_rs/dynamic/
basic_info.rs

1use crate::models::Vip;
2use crate::{BilibiliRequest, BpiClient, BpiError, BpiResponse};
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5// 以下结构体为API文档中未完全列出的部分,根据描述进行了推断和简化。
6// 如果您有完整的文档,请替换这些结构体。
7
8/// 动态转发列表中的转发项
9#[derive(Debug, Clone, Deserialize, Serialize)]
10pub struct RepostItem {
11    pub desc: Desc,
12    pub card: String,
13    pub extend_json: String,
14    pub display: Display,
15}
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct Desc {
19    pub uid: i64,
20    #[serde(rename = "type")]
21    pub type_field: i64,
22    pub rid: i64,
23    pub acl: i64,
24    pub view: i64,
25    pub repost: i64,
26    pub comment: i64,
27    pub like: i64,
28    pub is_liked: i64,
29    pub dynamic_id: i64,
30    pub timestamp: i64,
31    pub pre_dy_id: i64,
32    pub orig_dy_id: i64,
33    pub orig_type: i64,
34    pub user_profile: UserProfile,
35    pub spec_type: i64,
36    pub uid_type: i64,
37    pub stype: i64,
38    pub r_type: i64,
39    pub inner_id: i64,
40    pub status: i64,
41    pub dynamic_id_str: String,
42    pub pre_dy_id_str: String,
43    pub orig_dy_id_str: String,
44    pub rid_str: String,
45    pub origin: Origin,
46    pub bvid: String,
47    pub previous: Value,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct UserProfile {
52    pub info: Info,
53    pub card: Card,
54    pub vip: Vip,
55    pub pendant: Pendant,
56    pub rank: String,
57    pub sign: String,
58    pub level_info: LevelInfo,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct Info {
63    pub uid: i64,
64    pub uname: String,
65    pub face: String,
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize)]
69pub struct Card {
70    pub official_verify: OfficialVerify,
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
74pub struct OfficialVerify {
75    #[serde(rename = "type")]
76    pub type_field: i64,
77}
78
79#[derive(Debug, Clone, Serialize, Deserialize)]
80pub struct Label {
81    pub path: String,
82    pub text: String,
83    pub label_theme: String,
84    pub text_color: String,
85    pub bg_style: i64,
86    pub bg_color: String,
87    pub border_color: String,
88}
89
90#[derive(Debug, Clone, Serialize, Deserialize)]
91pub struct Pendant {
92    pub pid: i64,
93    pub name: String,
94    pub image: String,
95    pub expire: i64,
96    pub image_enhance: String,
97    pub image_enhance_frame: String,
98}
99
100#[derive(Debug, Clone, Serialize, Deserialize)]
101pub struct LevelInfo {
102    pub current_level: i64,
103    pub current_min: i64,
104    pub current_exp: i64,
105    pub next_exp: String,
106}
107
108#[derive(Debug, Clone, Serialize, Deserialize)]
109pub struct Origin {
110    pub uid: i64,
111    #[serde(rename = "type")]
112    pub type_field: i64,
113    pub rid: i64,
114    pub acl: i64,
115    pub view: i64,
116    pub repost: i64,
117    pub comment: i64,
118    pub like: i64,
119    pub is_liked: i64,
120    pub dynamic_id: i64,
121    pub timestamp: i64,
122    pub pre_dy_id: i64,
123    pub orig_dy_id: i64,
124    pub orig_type: i64,
125    pub user_profile: Value,
126    pub spec_type: i64,
127    pub uid_type: i64,
128    pub stype: i64,
129    pub r_type: i64,
130    pub inner_id: i64,
131    pub status: i64,
132    pub dynamic_id_str: String,
133    pub pre_dy_id_str: String,
134    pub orig_dy_id_str: String,
135    pub rid_str: String,
136    pub origin: Value,
137    pub bvid: String,
138    pub previous: Value,
139}
140
141#[derive(Debug, Clone, Serialize, Deserialize)]
142pub struct Display {
143    pub origin: Origin2,
144    pub usr_action_txt: String,
145    pub relation: Relation2,
146    pub live_info: Value,
147    pub emoji_info: EmojiInfo2,
148    pub highlight: Value,
149}
150
151#[derive(Debug, Clone, Serialize, Deserialize)]
152pub struct Origin2 {
153    pub origin: Value,
154    pub usr_action_txt: String,
155    pub relation: Relation,
156    pub live_info: Value,
157    pub emoji_info: EmojiInfo,
158    pub highlight: Value,
159}
160
161#[derive(Debug, Clone, Serialize, Deserialize)]
162pub struct Relation {
163    pub status: i64,
164    pub is_follow: i64,
165    pub is_followed: i64,
166}
167
168#[derive(Debug, Clone, Serialize, Deserialize)]
169pub struct EmojiInfo {
170    pub emoji_details: Value,
171}
172
173#[derive(Debug, Clone, Serialize, Deserialize)]
174pub struct Relation2 {
175    pub status: i64,
176    pub is_follow: i64,
177    pub is_followed: i64,
178}
179
180#[derive(Debug, Clone, Serialize, Deserialize)]
181pub struct EmojiInfo2 {
182    pub emoji_details: Value,
183}
184
185/// 动态点赞列表中的点赞项
186#[derive(Debug, Clone, Deserialize, Serialize)]
187pub struct LikeItem {
188    // 由于API文档未详细列出字段,这里作为占位符。
189    // 请根据实际API响应填充此结构体。
190}
191
192/// 纯文本动态内容
193#[derive(Debug, Clone, Deserialize, Serialize)]
194pub struct PlainTextRequest {
195    // 假设纯文本动态内容有一个名为 `content` 的字段。
196    pub content: String,
197    // 其他字段...
198}
199
200/// 获取草稿列表中的单项
201#[derive(Debug, Clone, Deserialize, Serialize)]
202pub struct Draft {
203    /// 草稿id
204    pub draft_id: String,
205    /// 定时发送的秒级时间戳
206    pub publish_time: u64,
207    /// 动态类型
208    #[serde(rename = "type")]
209    pub type_num: u8,
210    /// 自己的mid
211    pub uid: u64,
212    /// 自己的用户信息
213    pub user_profile: UserProfile,
214    /// 动态内容
215    pub request: String,
216}
217
218/// 动态转发列表响应数据结构体
219#[derive(Debug, Clone, Deserialize, Serialize)]
220pub struct RepostDetailResponseData {
221    /// 是否还有下一页
222    pub has_more: Option<bool>,
223    /// 总计
224    pub total: u64,
225    /// 转发列表
226    pub items: Vec<RepostItem>,
227}
228
229/// 动态点赞列表响应数据结构体
230#[derive(Debug, Clone, Deserialize, Serialize)]
231pub struct SpecItemLikesResponseData {
232    /// 点赞信息列表主体
233    pub item_likes: Vec<LikeItem>,
234    /// 是否还有下一页
235    pub has_more: bool,
236    /// 总计点赞数
237    pub total_count: u64,
238    /// 作用尚不明确
239    pub gt: u64,
240}
241
242/// 获取草稿列表响应数据结构体
243#[derive(Debug, Clone, Deserialize, Serialize)]
244pub struct GetDraftsResponseData {
245    /// 草稿列表
246    pub drafts: Vec<Draft>,
247}
248
249impl BpiClient {
250    /// 动态转发列表
251    ///
252    /// 获取指定动态的转发列表。
253    ///
254    /// # 参数
255    /// * `dynamic_id` - 动态ID
256    /// * `offset` - 偏移量,非必要
257    /// 文档: https://github.com/SocialSisterYi/bilibili-API-collect/tree/master/docs/dynamic
258    ///
259    /// 参数
260    ///
261    /// | 名称 | 类型 | 说明 |
262    /// | ---- | ---- | ---- |
263    /// | `dynamic_id` | &str | 动态 ID |
264    /// | `offset` | Option<&str> | 偏移量 |
265    pub async fn dynamic_repost_detail(
266        &self,
267        dynamic_id: &str,
268        offset: Option<&str>,
269    ) -> Result<BpiResponse<RepostDetailResponseData>, BpiError> {
270        let mut req = self
271            .get("https://api.vc.bilibili.com/dynamic_repost/v1/dynamic_repost/repost_detail")
272            .query(&[("dynamic_id", dynamic_id)]);
273
274        if let Some(o) = offset {
275            req = req.query(&[("offset", o)]);
276        }
277
278        req.send_bpi("获取动态转发列表").await
279    }
280
281    /// 动态点赞列表
282    ///
283    /// 获取指定动态的点赞列表。赞列表总计超过25K部分继续获取可能被限制
284    ///
285    /// # 参数
286    /// * `dynamic_id` - 动态ID
287    /// * `pn` - 页码,非必要,默认1
288    /// * `ps` - 每页数量,非必要,默认20
289    /// 文档: https://github.com/SocialSisterYi/bilibili-API-collect/tree/master/docs/dynamic
290    ///
291    /// 参数
292    ///
293    /// | 名称 | 类型 | 说明 |
294    /// | ---- | ---- | ---- |
295    /// | `dynamic_id` | u64 | 动态 ID |
296    /// | `pn` | Option<u64> | 页码,默认 1 |
297    /// | `ps` | Option<u64> | 页大小,默认 20 |
298    pub async fn dynamic_spec_item_likes(
299        &self,
300        dynamic_id: u64,
301        pn: Option<u64>,
302        ps: Option<u64>,
303    ) -> Result<BpiResponse<SpecItemLikesResponseData>, BpiError> {
304        let pn_val = pn.unwrap_or(1);
305        let ps_val = ps.unwrap_or(20);
306
307        let req = self
308            .get("https://api.vc.bilibili.com/dynamic_like/v1/dynamic_like/spec_item_likes")
309            .query(&[
310                ("dynamic_id", &dynamic_id.to_string()),
311                ("pn", &pn_val.to_string()),
312                ("ps", &ps_val.to_string()),
313            ]);
314
315        req.send_bpi("获取动态点赞列表").await
316    }
317
318    /// 获取草稿列表 (已失效?)
319    ///
320    /// 获取用户已保存的动态草稿列表。需要登录认证。
321    #[allow(dead_code)]
322    async fn get_drafts(&self) -> Result<BpiResponse<GetDraftsResponseData>, BpiError> {
323        let req = self.get("https://api.vc.bilibili.com/dynamic_draft/v1/dynamic_draft/get_drafts");
324
325        req.send_bpi("获取草稿列表").await
326    }
327}
328
329#[cfg(test)]
330mod tests {
331    use super::*;
332    use tracing::info;
333
334    #[tokio::test]
335
336    async fn test_get_repost_detail() -> Result<(), BpiError> {
337        let bpi = BpiClient::new();
338        // 替换为有效的动态ID进行测试
339        let dynamic_id = "1099138163191840776";
340        let resp = bpi.dynamic_repost_detail(dynamic_id, None).await?;
341        let data = resp.into_data()?;
342
343        info!("动态转发列表测试结果: {:?}", data);
344        assert!(!data.items.iter().len() > 0);
345
346        Ok(())
347    }
348}