Skip to main content

bpi_rs/dynamic/
module.rs

1use crate::models::{Pendant, VipLabel};
2use serde::{Deserialize, Serialize};
3
4/// 作者模块 √
5#[derive(Default, Debug, Clone, Serialize, Deserialize)]
6pub struct ModuleAuthor {
7    /// 头像信息,主要用于网页渲染
8    pub avatar: Option<serde_json::Value>,
9    /// 装扮,仅当动态接口且无 decorationCard 时存在
10    pub decorate: Option<serde_json::Value>,
11    /// 装扮,仅当图文接口时存在
12    /// 头像 URL
13    pub face: String,
14    /// 是否为 NFT 头像
15    pub face_nft: bool,
16    /// 是否关注此 UP 主,自己的动态为 null
17    pub following: Option<bool>,
18    /// 跳转链接
19    pub jump_url: String,
20    /// 名称前标签,如 "合集", "电视剧", "番剧"
21    pub label: String,
22    /// UP 主 UID 或 剧集 SeasonId
23    pub mid: i64,
24    /// UP 主名称、剧集名称或合集名称
25    pub name: String,
26    /// UP 主认证信息,仅图文接口
27    pub official: Option<AuthorOfficial>,
28    /// UP 主认证信息,仅动态接口
29    #[serde(rename = "official_verify")]
30    pub official_verify: Option<AuthorOfficial>,
31    /// UP 主头像框
32    pub pendant: Option<Pendant>,
33    /// 更新动作描述,仅动态接口
34    pub pub_action: Option<String>,
35    /// 更新时间,如 "x分钟前", "x小时前", "昨天"
36    pub pub_time: String,
37    /// 更新时间戳,UNIX 秒级时间戳
38    pub pub_ts: i64,
39    pub views_text: String,
40    /// UP 主大会员信息
41    pub vip: Option<AuthorVip>,
42    /// 作者类型,仅动态接口
43    #[serde(rename = "type")]
44    pub type_field: Option<String>,
45}
46
47#[derive(Default, Debug, Clone, Serialize, Deserialize)]
48pub struct AuthorOfficial {
49    /// 认证说明
50    pub desc: String,
51    pub role: i64,
52    pub title: String,
53    /// 认证类型
54    #[serde(rename = "type")]
55    pub type_field: i64,
56}
57
58#[derive(Default, Debug, Clone, Serialize, Deserialize)]
59pub struct AuthorVip {
60    /// 大会员过期时间戳,UNIX 毫秒时间戳
61    pub due_date: i64,
62    /// 大会员标签
63    pub label: VipLabel,
64    /// 名字显示颜色,大会员:#FB7299
65    pub nickname_color: String,
66    /// 大会员状态,0:无,1:有,2:封禁?
67    pub status: i64,
68    /// 大会员类型?
69    pub r#type: i64,
70
71    /// 仅图文接口
72    pub role: Option<i64>,
73    /// 主题类型? 仅图文接口
74    pub theme_type: Option<i64>,
75    /// TV 端过期时间? 仅图文接口
76    pub tv_due_date: Option<i64>,
77    /// TV 端付费状态? 仅图文接口
78    pub tv_vip_pay_type: Option<i64>,
79    /// TV 端会员状态?
80    pub tv_vip_status: Option<i64>,
81    /// 大会员付费类型?
82    pub vip_pay_type: Option<i64>,
83}
84
85/// 更多模块 (三点菜单) √
86#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
87pub struct ModuleMore {
88    /// 右上角三点菜单
89    #[serde(rename = "three_point_items")]
90    pub three_point_items: Vec<ThreePointItem>,
91}
92
93#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
94pub struct ThreePointItem {
95    /// 显示文本
96    pub label: String,
97    /// 弹出框文本
98    pub modal: Option<Modal>,
99    /// # 参数信息
100    pub params: Option<Params>,
101    /// 三点操作类型,参见 右上角三点菜单
102    #[serde(rename = "type")]
103    pub type_field: String,
104}
105
106#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
107pub struct Modal {
108    /// 取消文本
109    pub cancel: String,
110    /// 确认文本
111    pub confirm: String,
112    /// 内容文本
113    pub content: String,
114    /// 标题文本
115    pub title: String,
116}
117
118#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
119pub struct Params {
120    /// 动态 id 字符串
121    #[serde(rename = "dyn_id_str")]
122    pub dyn_id_str: String,
123    /// 动态类型
124    #[serde(rename = "dyn_type")]
125    pub dyn_type: i64,
126    /// 动态 id 字符串
127    #[serde(rename = "rid_str")]
128    pub rid_str: String,
129}
130
131/// 统计模块 √
132#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
133pub struct ModuleStat {
134    /// 硬币数据,仅图文接口
135    pub coin: Option<StatData>,
136    /// 评论数据
137    pub comment: StatData,
138    /// 收藏数据,仅图文接口
139    pub favorite: Option<StatData>,
140    /// 转发数据
141    pub forward: StatData,
142    /// 点赞数据
143    pub like: StatData,
144}
145
146#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
147pub struct StatData {
148    /// 数量
149    pub count: i64,
150    /// 是否屏蔽
151    pub forbidden: bool,
152    /// 是否隐藏
153    pub hidden: Option<bool>,
154    /// 当前状态,是否已进行该操作
155    pub status: Option<bool>,
156}
157
158/// 内容模块
159#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
160pub struct ModuleContent {
161    /// 段落
162    pub paragraphs: Vec<Paragraph>,
163}
164
165#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
166pub struct Paragraph {
167    /// 对齐方式,0: 左对齐, 1: 居中, 2: 右对齐
168    pub align: i64,
169    /// 段落类型,1: 文本, 2: 图片, 3: 分割线, 4: 块引用, 5: 列表, 6: 链接卡片, 7: 代码
170    #[serde(rename = "para_type")]
171    pub para_type: i64,
172    /// 文本内容,仅 `para_type=1` 或 `para_type=4`
173    pub text: Option<Text>,
174    /// 图片内容,仅 `para_type=2`
175    pub pics: Option<ParagraphPics>,
176    /// 分割线,仅 `para_type=3`
177    pub line: Option<ParagraphLine>,
178    /// 列表,仅 `para_type=5`
179    pub list: Option<ParagraphList>,
180    /// 链接卡片,仅 `para_type=6`
181    #[serde(rename = "link_card")]
182    pub link_card: Option<LinkCard>,
183    /// 代码,仅 `para_type=7`
184    pub code: Option<ParagraphCode>,
185}
186
187#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
188pub struct Text {
189    /// 文本节点
190    pub nodes: Vec<TextNode>,
191}
192
193#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
194pub struct TextNode {
195    /// 文本节点类型,"TEXT_NODE_TYPE_WORD" 或 "TEXT_NODE_TYPE_RICH"
196    #[serde(rename = "type")]
197    pub type_field: String,
198    /// 纯文本,仅 `type='TEXT_NODE_TYPE_WORD'`
199    pub word: Option<TextNodeWord>,
200    /// 富文本,仅 `type='TEXT_NODE_TYPE_RICH'`
201    pub rich: Option<serde_json::Value>, // TODO: 详细的富文本节点结构未提供,用 Value 代替
202    /// 公式,仅 `type='TEXT_NODE_TYPE_FORMULA'`
203    pub formula: Option<TextNodeFormula>,
204}
205
206#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
207pub struct TextNodeWord {
208    /// 字体大小,用于控制文本所用标签名及行高
209    #[serde(rename = "font_size")]
210    pub font_size: i64,
211    /// 补充样式
212    pub style: serde_json::Value,
213    /// 文本内容
214    pub words: String,
215}
216
217#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
218pub struct TextNodeFormula {
219    /// 公式内容,LaTeX 格式
220    #[serde(rename = "latex_content")]
221    pub latex_content: String,
222}
223
224#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
225pub struct ParagraphLine {
226    /// 图片信息
227    pub pic: LinePic,
228}
229
230#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
231pub struct LinePic {
232    /// 高度
233    pub height: i64,
234    /// 图片 URL
235    pub url: String,
236}
237
238#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
239pub struct ParagraphList {
240    /// 样式,1: 有序列表, 2: 无序列表
241    pub style: i64,
242    /// 列表项
243    pub items: Vec<ListItem>,
244}
245
246#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
247pub struct ListItem {
248    /// 级别
249    pub level: i64,
250    /// 文本节点,同 `ModuleContent.paragraphs[].text.nodes[]`
251    pub nodes: Vec<TextNode>,
252    /// 序号
253    pub order: i64,
254}
255
256#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
257pub struct ParagraphPics {
258    /// 图片数组
259    pub pics: Vec<PicItem>,
260    /// 样式,1: isAlbum
261    pub style: i64,
262}
263
264#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
265pub struct PicItem {
266    /// 高度
267    pub height: i64,
268    /// 动图 URL?
269    #[serde(rename = "live_url")]
270    pub live_url: serde_json::Value,
271    /// 大小,单位: ki
272    pub size: Option<i64>,
273    /// 图片 URL
274    pub url: String,
275    /// 宽度
276    pub width: i64,
277}
278
279#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
280pub struct LinkCard {
281    /// 卡片内容
282    pub card: Card,
283}
284
285#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
286pub struct Card {
287    /// 关联 id,可能为 "undefined"
288    pub oid: String,
289    /// 卡片类型
290    #[serde(rename = "type")]
291    pub type_field: String,
292    // 以下字段根据 `type_field` 的值而存在,用 Option 包裹
293    /// 一般信息,仅 `type='LINK_CARD_TYPE_COMMON'`
294    pub common: Option<serde_json::Value>,
295    /// 商品信息,仅 `type='LINK_CARD_TYPE_GOODS'`
296    pub goods: Option<serde_json::Value>,
297    /// 比赛信息? 仅 `type='LINK_CARD_TYPE_MATCH'`
298    #[serde(rename = "match")]
299    pub match_field: Option<MatchCard>,
300    /// 投票信息,仅 `type='LINK_CARD_TYPE_VOTE'`
301    pub vote: Option<serde_json::Value>,
302    /// 视频信息,仅 `type='LINK_CARD_TYPE_UGC'`
303    pub ugc: Option<serde_json::Value>,
304    /// 预约信息,仅 `type='LINK_CARD_TYPE_RESERVE'`
305    pub reserve: Option<serde_json::Value>,
306    /// 充电专属抽奖信息,仅 `type='LINK_CARD_TYPE_UPOWER_LOTTERY'`
307    #[serde(rename = "upower_lottery")]
308    pub upower_lottery: Option<UpowerLottery>,
309    /// 图文信息,仅 `type='LINK_CARD_TYPE_OPUS'`
310    pub opus: Option<OpusCard>,
311    /// 音乐信息,仅 `type='LINK_CARD_TYPE_MUSIC'`
312    pub music: Option<serde_json::Value>,
313    /// 直播信息,仅 `type='LINK_CARD_TYPE_LIVE'`
314    pub live: Option<serde_json::Value>,
315    /// 提示信息,仅 `type='LINK_CARD_TYPE_ITEM_NULL'`
316    #[serde(rename = "item_null")]
317    pub item_null: Option<ItemNullCard>,
318}
319
320#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
321pub struct MatchCard {
322    /// 动态 ID
323    #[serde(rename = "id_str")]
324    pub id_str: String,
325    /// 跳转 URL
326    #[serde(rename = "jump_url")]
327    pub jump_url: String,
328    /// 比赛信息
329    #[serde(rename = "match_info")]
330    pub match_info: MatchInfo,
331}
332
333#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
334pub struct MatchInfo {
335    /// 中间区域底部的信息
336    #[serde(rename = "center_bottom")]
337    pub center_bottom: String,
338    /// 中间区域顶部的信息,会循环显示,可能用来显示比分或时间
339    #[serde(rename = "center_top")]
340    pub center_top: Vec<String>,
341    /// 右边队伍的信息
342    #[serde(rename = "left_team")]
343    pub left_team: TeamInfo,
344    /// 左边队伍的信息
345    #[serde(rename = "right_team")]
346    pub right_team: TeamInfo,
347    /// 比赛状态,2: 进行中 (文字高亮)
348    pub status: i64,
349    /// 副标题
350    #[serde(rename = "sub_title")]
351    pub sub_title: String,
352    /// 标题
353    pub title: String,
354}
355
356#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
357pub struct TeamInfo {
358    /// 队伍名字
359    pub name: String,
360    /// 图片 URL
361    pub pic: String,
362}
363
364#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
365pub struct UpowerLottery {
366    /// 按钮
367    pub button: UpowerLotteryButton,
368    /// 描述
369    pub desc: UpowerLotteryDesc,
370    /// 提示
371    pub hint: UpowerLotteryHint,
372    /// 跳转 URL
373    #[serde(rename = "jump_url")]
374    pub jump_url: String,
375    /// 关联 id
376    pub rid: i64,
377    /// 状态
378    pub state: i64,
379    /// 标题
380    pub title: String,
381    /// UP 主 mid (UID)
382    #[serde(rename = "up_mid")]
383    pub up_mid: i64,
384    /// 充电操作状态
385    #[serde(rename = "upower_action_state")]
386    pub upower_action_state: i64,
387    /// 充电级别
388    #[serde(rename = "upower_level")]
389    pub upower_level: i64,
390}
391
392#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
393pub struct UpowerLotteryButton {
394    /// 选中状态
395    pub check: UpowerLotteryButtonCheck,
396    /// 状态
397    pub status: i64,
398    /// 类型: 0, 1, 2
399    #[serde(rename = "type")]
400    pub type_field: i64,
401}
402
403#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
404pub struct UpowerLotteryButtonCheck {
405    /// 是否禁用,1: 禁用
406    pub disable: i64,
407    /// 图标 URL
408    #[serde(rename = "icon_url")]
409    pub icon_url: String,
410    /// 文字
411    pub text: String,
412    /// 提示
413    pub toast: String,
414}
415
416#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
417pub struct UpowerLotteryDesc {
418    /// 跳转 URL
419    #[serde(rename = "jump_url")]
420    pub jump_url: String,
421    /// 样式
422    pub style: i64,
423    /// 文字
424    pub text: String,
425}
426
427#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
428pub struct UpowerLotteryHint {
429    /// 样式
430    pub style: i64,
431    /// 文字
432    pub text: String,
433}
434
435#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
436pub struct OpusCard {
437    /// 作者信息
438    pub author: OpusAuthor,
439    /// 封面 URL
440    pub cover: String,
441    /// 跳转 URL
442    #[serde(rename = "jump_url")]
443    pub jump_url: String,
444    /// 状态信息
445    pub stat: OpusStat,
446    /// 标题
447    pub title: String,
448}
449
450#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
451pub struct OpusAuthor {
452    /// 作者名
453    pub name: String,
454}
455
456#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
457pub struct OpusStat {
458    /// 阅读数
459    pub view: i64,
460}
461
462#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
463pub struct ItemNullCard {
464    /// 文字
465    pub text: String,
466}
467
468#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
469pub struct ParagraphCode {
470    /// 内容
471    pub content: String,
472    /// 语言,如 "language-html"
473    pub lang: String,
474}
475
476/// 话题模块
477#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
478pub struct ModuleTopic {
479    /// 话题 id
480    pub id: i64,
481    /// 跳转 URL
482    #[serde(rename = "jump_url")]
483    pub jump_url: String,
484    /// 话题名称
485    pub name: String,
486}
487
488/// 文集模块
489#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
490pub struct ModuleCollection {
491    /// 文章数
492    pub count: String,
493    /// 文集 id
494    pub id: i64,
495    /// 文集名
496    pub name: String,
497    /// 标题,如 "收录于文集"
498    pub title: String,
499}
500
501/// 扩展模块
502#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
503pub struct ModuleExtend {
504    /// 项
505    pub items: Vec<ExtendItem>,
506}
507
508#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
509pub struct ExtendItem {
510    /// 图标
511    pub icon: Option<String>,
512    /// SVG 图版
513    #[serde(rename = "icon_svg")]
514    pub icon_svg: serde_json::Value,
515    /// 跳转 URL
516    #[serde(rename = "jump_url")]
517    pub jump_url: String,
518    /// 文本
519    pub text: String,
520}
521
522/// 底部模块
523#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
524pub struct ModuleBottom {
525    /// 分享信息
526    #[serde(rename = "share_info")]
527    pub share_info: ShareInfo,
528}
529
530#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
531pub struct ShareInfo {
532    /// 图片 URL
533    pub pic: String,
534    /// 总结
535    pub summary: String,
536    /// 标题
537    pub title: String,
538}
539
540/// 动态模块
541#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
542pub struct Root {
543    pub additional: Option<serde_json::Value>,
544    pub desc: Option<serde_json::Value>,
545    pub major: Major,
546    pub topic: Option<serde_json::Value>,
547}
548
549#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
550pub struct Major {
551    pub archive: Archive,
552    #[serde(rename = "type")]
553    pub type_field: String,
554}
555
556#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
557pub struct Archive {
558    pub aid: String,
559    pub badge: Badge,
560    pub bvid: String,
561    pub cover: String,
562    pub desc: String,
563    pub disable_preview: i64,
564    pub duration_text: String,
565    pub jump_url: String,
566    pub stat: Stat,
567    pub title: String,
568    #[serde(rename = "type")]
569    pub type_field: i64,
570}
571
572#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
573pub struct Badge {
574    pub bg_color: String,
575    pub color: String,
576    pub icon_url: serde_json::Value,
577    pub text: String,
578}
579
580#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
581pub struct Stat {
582    pub danmaku: String,
583    pub play: String,
584}