1use serde::{ Deserialize, Serialize };
2
3use crate::models::{ LevelInfo, Official, Pendant, Vip };
4use crate::{ BilibiliRequest, BpiClient, BpiError, BpiResponse };
5
6#[derive(Debug, Serialize, Clone, Deserialize)]
7pub struct DynamicCardData {
8 pub card: DynamicCard,
9}
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct DynamicCard {
13 pub desc: Desc,
14 pub card: String,
15 pub extend_json: String,
16 pub display: serde_json::Value,
17}
18
19#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct Desc {
21 pub uid: i64,
22 #[serde(rename = "type")]
23 pub type_field: i64,
24 pub rid: i64,
25 pub acl: i64,
26 pub view: i64,
27 pub repost: i64,
28 pub comment: i64,
29 pub like: i64,
30 pub is_liked: i64,
31 pub dynamic_id: i64,
32 pub timestamp: i64,
33 pub pre_dy_id: i64,
34 pub orig_dy_id: i64,
35 pub orig_type: i64,
36 pub user_profile: UserProfile,
37 pub spec_type: i64,
38 pub uid_type: i64,
39 pub stype: i64,
40 pub r_type: i64,
41 pub inner_id: i64,
42 pub status: i64,
43 pub dynamic_id_str: String,
44 pub pre_dy_id_str: String,
45 pub orig_dy_id_str: String,
46 pub rid_str: String,
47 pub bvid: String,
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, Serialize, Clone, Deserialize)]
80pub struct RecentUpData {
81 pub live_users: Option<serde_json::Value>,
83 pub my_info: Option<MyInfo>,
85 pub up_list: Vec<UpUser>,
87}
88
89#[derive(Debug, Serialize, Clone, Deserialize)]
91pub struct MyInfo {
92 pub dyns: i32,
94 pub face: String,
96 pub follower: String,
98 pub following: i32,
100 pub level_info: LevelInfo,
102 pub mid: i64,
104 pub name: String,
106 #[serde(rename = "official")]
108 pub official: Official,
109 pub space_bg: String,
111 pub vip: Vip,
113}
114
115#[derive(Debug, Serialize, Clone, Deserialize)]
117pub struct UpUser {
118 pub face: String,
120 pub has_update: bool,
122 pub is_reserve_recall: bool,
124 pub mid: i64,
126 pub uname: String,
128}
129
130impl BpiClient {
131 pub async fn dynamic_card_detail(
142 &self,
143 dynamic_id: &str
144 ) -> Result<BpiResponse<DynamicCardData>, BpiError> {
145 self
146 .get("https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/get_dynamic_detail")
147 .query(&[("dynamic_id", dynamic_id)])
148 .send_bpi("获取特定动态卡片信息").await
149 }
150
151 pub async fn dynamic_recent_up_list(&self) -> Result<BpiResponse<RecentUpData>, BpiError> {
156 self
157 .get("https://api.bilibili.com/x/polymer/web-dynamic/v1/portal")
158 .send_bpi("获取最近更新 UP 主列表").await
159 }
160}
161
162#[cfg(test)]
163mod tests {
164 use super::*;
165
166 #[tokio::test]
167 async fn test_dynamic_get_card_detail() {
168 let bpi = BpiClient::new();
169 let resp = bpi.dynamic_card_detail("1099138163191840776").await;
170 assert!(resp.is_ok());
171 }
172
173 #[tokio::test]
174 async fn test_dynamic_recent_up_list() {
175 let bpi = BpiClient::new();
176 let resp = bpi.dynamic_recent_up_list().await;
177 assert!(resp.is_ok());
178 if let Ok(res) = resp {
179 tracing::info!("{:#?}", res.data.unwrap().up_list.len());
180 }
181 }
182}