bpi_rs/activity/
list.rs

1//! 活动列表
2//!
3//! https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/activity/list.md
4
5use crate::{BilibiliRequest, BpiClient, BpiError, BpiResponse};
6use serde::{Deserialize, Serialize};
7
8/// 活动列表数据
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct ActivityListData {
11    /// 活动列表
12    pub list: Vec<ActivityItem>,
13    /// 当前页码
14    pub num: i32,
15    /// 每页条数
16    pub size: i32,
17    /// 总条数
18    pub total: i32,
19}
20
21/// 活动项目
22#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct ActivityItem {
24    /// 活动 ID
25    pub id: i32,
26    /// 固定值 1
27    pub state: i32,
28    /// 开始时间 UNIX 秒级时间戳
29    pub stime: i64,
30    /// 结束时间 UNIX 秒级时间戳
31    pub etime: i64,
32    /// 创建时间? UNIX 秒级时间戳, 可能为 0
33    pub ctime: i64,
34    /// 修改时间? UNIX 秒级时间戳, 可能为 0
35    pub mtime: i64,
36    /// 活动名称
37    pub name: String,
38    /// 活动链接
39    pub h5_url: String,
40    /// 活动封面
41    pub h5_cover: String,
42    /// 页面名称
43    pub page_name: String,
44    /// 活动平台类型? 即 URL 中 `plat` 参数
45    pub plat: i32,
46    /// 活动描述
47    pub desc: String,
48}
49
50#[derive(Debug, Clone, Serialize)]
51pub struct ActivityListParams {
52    /// 活动平台类型,可选范围 [1, 3],以半角逗号分隔
53    #[serde(skip_serializing_if = "Option::is_none")]
54    pub plat: Option<String>,
55
56    /// 固定值 0
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub mold: Option<i32>,
59
60    /// 固定值 3
61    #[serde(skip_serializing_if = "Option::is_none")]
62    pub http: Option<i32>,
63
64    /// 目标页码
65    #[serde(skip_serializing_if = "Option::is_none")]
66    pub pn: Option<i32>,
67
68    /// 每页条数
69    #[serde(skip_serializing_if = "Option::is_none")]
70    pub ps: Option<i32>,
71}
72
73impl Default for ActivityListParams {
74    fn default() -> Self {
75        Self {
76            plat: Some("1,3".to_string()),
77            mold: Some(0),
78            http: Some(3),
79            pn: Some(1),
80            ps: Some(15),
81        }
82    }
83}
84
85impl BpiClient {
86    /// 获取活动列表
87    ///
88    /// # 参数
89    /// | 名称    | 类型   | 说明                                               |
90    /// | ------- | ------ | -------------------------------------------------- |
91    /// | `plat`  | u32    | 活动平台类型,可选范围 `[1,3]`,以半角逗号分隔,默认 `1,3` |
92    /// | `mold`  | u32    | 固定值 `0` (可选)                                  |
93    /// | `http`  | u32    | 固定值 `3` (可选)                                  |
94    /// | `pn`    | u32    | 目标页码 (可选,默认为 `1`)                        |
95    /// | `ps`    | u32    | 每页条数 (可选,默认为 `15`)                       |
96    ///
97    /// # 文档
98    /// [获取活动列表](https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/activity/list.md#获取活动列表)
99
100    pub async fn activity_list(
101        &self,
102        plat: Option<&str>,
103        mold: Option<i32>,
104        http: Option<i32>,
105        pn: Option<i32>,
106        ps: Option<i32>,
107    ) -> Result<BpiResponse<ActivityListData>, BpiError> {
108        let params = ActivityListParams {
109            plat: plat
110                .map(|s| s.to_string())
111                .or_else(|| Some("1,3".to_string())),
112            mold: mold.or(Some(0)),
113            http: http.or(Some(3)),
114            pn: pn.or(Some(1)),
115            ps: ps.or(Some(15)),
116        };
117
118        let result = self
119            .get("https://api.bilibili.com/x/activity/page/list")
120            .query(&params)
121            .send_bpi("获取活动列表")
122            .await?;
123
124        Ok(result)
125    }
126
127    /// 获取活动列表(简化版本,使用默认参数)
128    ///
129    /// # 文档
130    /// [获取活动列表](https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/activity/list.md#获取活动列表)
131    pub async fn activity_list_default(&self) -> Result<BpiResponse<ActivityListData>, BpiError> {
132        self.activity_list(Some("1,3"), None, None, Some(1), Some(15))
133            .await
134    }
135}
136
137#[cfg(test)]
138mod tests {
139    use super::*;
140
141    #[tokio::test]
142    async fn test_get_activity_list() -> Result<(), Box<BpiError>> {
143        let bpi = BpiClient::new();
144
145        // 测试获取活动列表
146        let result = bpi
147            .activity_list(Some("1,3"), None, None, Some(1), Some(4))
148            .await?;
149        let data = result.into_data()?;
150        tracing::info!("{:#?}", data);
151
152        assert!(!data.list.is_empty());
153        assert_eq!(data.num, 1);
154        assert_eq!(data.size, 4);
155        assert!(data.total > 0);
156
157        Ok(())
158    }
159
160    #[tokio::test]
161    async fn test_get_activity_list_simple() -> Result<(), Box<BpiError>> {
162        let bpi = BpiClient::new();
163
164        // 测试简化版本获取活动列表
165        let result = bpi.activity_list_default().await?;
166        let data = result.into_data()?;
167        tracing::info!("{:#?}", data);
168
169        assert!(!data.list.is_empty());
170        assert_eq!(data.num, 1);
171        assert_eq!(data.size, 15);
172
173        Ok(())
174    }
175
176    #[tokio::test]
177    async fn test_activity_item_fields() -> Result<(), Box<BpiError>> {
178        let bpi = BpiClient::new();
179
180        let result = bpi
181            .activity_list(Some("1,3"), None, None, Some(1), Some(1))
182            .await?;
183        let data = result.into_data()?;
184        tracing::info!("{:#?}", data);
185
186        if let Some(activity) = data.list.first() {
187            assert!(activity.id > 0);
188            assert_eq!(activity.state, 1);
189            assert!(!activity.name.is_empty());
190            assert!(!activity.page_name.is_empty());
191        }
192
193        Ok(())
194    }
195}