Skip to main content

bpi_rs/video_ranking/
popular.rs

1use crate::{ BilibiliRequest, BpiClient, BpiError, BpiResponse };
2use serde::{ Deserialize, Serialize };
3
4// --- 获取当前热门视频列表 ---
5
6/// 热门视频列表的页面信息
7#[derive(Debug, Clone, Deserialize, Serialize)]
8pub struct PopularListData {
9    /// 视频列表
10    pub list: Vec<serde_json::Value>, // 视频内容复杂,这里用Value代替
11    /// 是否有更多数据
12    pub no_more: bool,
13}
14
15// --- 每周必看全部列表 ---
16
17/// 每周必看列表中的单个必看
18#[derive(Debug, Clone, Deserialize, Serialize)]
19pub struct PopularSeriesItem {
20    /// 期数
21    pub number: u32,
22    /// 主题
23    pub subject: String,
24    /// 状态,2: 已结束
25    pub status: u8,
26    /// 名称,如 "yyyy第n期 MM.dd - MM.dd"
27    pub name: String,
28}
29
30/// 每周必看全部列表数据
31#[derive(Debug, Clone, Deserialize, Serialize)]
32pub struct PopularSeriesListData {
33    /// 全部信息列表
34    pub list: Vec<PopularSeriesItem>,
35}
36
37// --- 每周必看选期详细信息 ---
38
39/// 每周必看选期信息
40#[derive(Debug, Clone, Deserialize, Serialize)]
41pub struct PopularSeriesConfig {
42    /// 选期 ID
43    pub id: u64,
44    /// 选期类型
45    #[serde(rename = "type")]
46    pub type_name: String,
47    /// 期数
48    pub number: u32,
49    /// 主题
50    pub subject: String,
51    /// 开始时间
52    pub stime: u64,
53    /// 结束时间
54    pub etime: u64,
55    /// 状态,2: 已结束
56    pub status: u8,
57    /// 名称
58    pub name: String,
59    /// 标题
60    pub label: String,
61    /// 提示
62    pub hint: String,
63    /// 颜色
64    pub color: u32,
65    /// 封面
66    pub cover: String,
67    /// 分享标题
68    pub share_title: String,
69    /// 分享副标题
70    pub share_subtitle: String,
71    /// 媒体 ID
72    pub media_id: u64,
73}
74
75/// 每周必看选期详细信息数据
76#[derive(Debug, Clone, Deserialize, Serialize)]
77pub struct PopularSeriesOneData {
78    /// 选期信息
79    pub config: PopularSeriesConfig,
80    /// 提醒
81    pub reminder: Option<String>,
82    /// 选期视频列表
83    pub list: Vec<serde_json::Value>,
84}
85
86impl BpiClient {
87    /// 获取当前热门视频列表
88    ///
89    /// # 文档
90    /// [查看API文档](https://socialsisteryi.github.io/bilibili-API-collect/docs/video_ranking/popular.html#获取当前热门视频列表)
91    ///
92    /// # 参数
93    /// | 名称 | 类型         | 说明                 |
94    /// | ---- | ------------| -------------------- |
95    /// | `pn` | `Option<u32>` | 页码,可选           |
96    /// | `ps` | `Option<u32>` | 每页数量,可选       |
97    pub async fn video_popular_list(
98        &self,
99        pn: Option<u32>,
100        ps: Option<u32>
101    ) -> Result<BpiResponse<PopularListData>, BpiError> {
102        let mut request = self.get("https://api.bilibili.com/x/web-interface/popular");
103
104        if let Some(pn) = pn {
105            request = request.query(&[("pn", pn)]);
106        }
107        if let Some(ps) = ps {
108            request = request.query(&[("ps", ps)]);
109        }
110
111        request.send_bpi("获取当前热门视频列表").await
112    }
113
114    /// 获取每周必看全部列表
115    ///
116    /// # 文档
117    /// [查看API文档](https://socialsisteryi.github.io/bilibili-API-collect/docs/video_ranking/popular.html#获取每周必看全部列表)
118    ///
119    pub async fn video_popular_series_list(
120        &self
121    ) -> Result<BpiResponse<PopularSeriesListData>, BpiError> {
122        self
123            .get("https://api.bilibili.com/x/web-interface/popular/series/list")
124            .send_bpi("获取每周必看全部列表").await
125    }
126
127    /// 获取每周必看选期详细信息
128    ///
129    /// # 文档
130    /// [查看API文档](https://socialsisteryi.github.io/bilibili-API-collect/docs/video_ranking/popular.html#获取每周必看选期详细信息)
131    ///
132    /// # 参数
133    /// | 名称     | 类型     | 说明         |
134    /// | -------- | --------| ------------|
135    /// | `number` | u32     | 期数         |
136    pub async fn video_popular_series_one(
137        &self,
138        number: u32
139    ) -> Result<BpiResponse<PopularSeriesOneData>, BpiError> {
140        self
141            .get("https://api.bilibili.com/x/web-interface/popular/series/one")
142            .query(&[("number", number)])
143            .send_bpi("获取每周必看选期详细信息").await
144    }
145}
146
147#[cfg(test)]
148mod tests {
149    use super::*;
150    use tracing::info;
151
152    #[tokio::test]
153    async fn test_video_popular_list() {
154        let bpi = BpiClient::new();
155        let resp = bpi.video_popular_list(Some(1), Some(2)).await;
156
157        info!("{:?}", resp);
158        assert!(resp.is_ok());
159
160        let resp_data = resp.unwrap();
161        info!("code: {}", resp_data.code);
162        if let Some(data) = resp_data.data {
163            info!("no_more: {}", data.no_more);
164            info!("first item: {:?}", data.list.first());
165        }
166    }
167
168    #[tokio::test]
169    async fn test_video_popular_series_list() {
170        let bpi = BpiClient::new();
171        let resp = bpi.video_popular_series_list().await;
172
173        info!("{:?}", resp);
174        assert!(resp.is_ok());
175
176        let resp_data = resp.unwrap();
177        info!("code: {}", resp_data.code);
178        if let Some(data) = resp_data.data {
179            info!("first series: {:?}", data.list.first());
180        }
181    }
182
183    #[tokio::test]
184    async fn test_video_popular_series_one() {
185        let bpi = BpiClient::new();
186        let resp = bpi.video_popular_series_one(1).await;
187
188        info!("{:?}", resp);
189        assert!(resp.is_ok());
190
191        let resp_data = resp.unwrap();
192        info!("code: {}", resp_data.code);
193        if let Some(data) = resp_data.data {
194            info!("config: {:?}", data.config);
195            info!("first video: {:?}", data.list.first());
196        }
197    }
198}