Skip to main content

bpi_rs/bangumi/
timeline.rs

1//! 番剧或影视时间线
2//!
3//! [查看 API 文档](https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/bangumi/timeline.md)
4use crate::{ BilibiliRequest, BpiClient, BpiError, BpiResponse };
5use serde::{ Deserialize, Serialize };
6
7/// 番剧类型
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum BangumiTimelineType {
10    /// 番剧
11    Anime = 1,
12    /// 电影
13    Movie = 3,
14    /// 国创
15    ChineseAnimation = 4,
16}
17
18impl BangumiTimelineType {
19    pub fn as_i32(self) -> i32 {
20        self as i32
21    }
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct BangumiTimelineDay {
26    pub date: String,
27    pub date_ts: i64,
28    pub day_of_week: i32,
29    pub episodes: Vec<BangumiTimelineEpisode>,
30    pub is_today: i32,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct BangumiTimelineEpisode {
35    pub cover: String,
36    pub delay: i32,
37    pub delay_id: i64,
38    pub delay_index: String,
39    pub delay_reason: String,
40    pub ep_cover: String,
41    pub episode_id: i64,
42    pub pub_index: String,
43    pub pub_time: String,
44    pub pub_ts: i64,
45    pub published: i32,
46    pub follows: String,
47    pub plays: String,
48    pub season_id: i64,
49    pub square_cover: String,
50    pub title: String,
51}
52
53impl BpiClient {
54    /// 获取番剧或影视时间线
55    ///
56    /// # 参数
57    /// * `types` - 类别(1:番剧,3:电影,4:国创)
58    /// * `before` - 开始于前几日(0-7)
59    /// * `after` - 结束于后几日(0-7)
60    /// # 文档
61    /// [获取番剧或影视时间线](https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/bangumi/timeline.md#获取番剧或影视时间线)
62    pub async fn bangumi_timeline(
63        &self,
64        types: BangumiTimelineType,
65        before: i32,
66        after: i32
67    ) -> Result<BpiResponse<Vec<BangumiTimelineDay>>, BpiError> {
68        // 验证参数
69        if before < 0 || before > 7 {
70            return Err(BpiError::InvalidParameter {
71                field: "before",
72                message: "before参数必须在0-7之间",
73            });
74        }
75        if after < 0 || after > 7 {
76            return Err(BpiError::InvalidParameter {
77                field: "after",
78                message: "after参数必须在0-7之间",
79            });
80        }
81
82        self
83            .get("https://api.bilibili.com/pgc/web/timeline")
84            .query(
85                &[
86                    ("types", types.as_i32().to_string()),
87                    ("before", before.to_string()),
88                    ("after", after.to_string()),
89                ]
90            )
91            .send_bpi("获取番剧或影视时间线").await
92    }
93}
94
95#[cfg(test)]
96mod tests {
97    use super::*;
98
99    #[tokio::test]
100    async fn test_bangumi_timeline() {
101        let bpi = BpiClient::new();
102        let result = bpi.bangumi_timeline(BangumiTimelineType::Anime, 3, 7).await;
103        assert!(result.is_ok());
104        let response = result.unwrap();
105        assert_eq!(response.code, 0);
106        let data = response.data.unwrap();
107
108        assert!(!data.is_empty());
109        for day in &data {
110            assert!(!day.date.is_empty());
111            assert!(day.day_of_week >= 1 && day.day_of_week <= 7);
112            assert!(!day.episodes.is_empty());
113            for episode in &day.episodes {
114                assert!(!episode.title.is_empty());
115                assert!(episode.season_id > 0);
116            }
117        }
118    }
119
120    #[tokio::test]
121    async fn test_bangumi_timeline_invalid_before() {
122        let bpi = BpiClient::new();
123        let result = bpi.bangumi_timeline(BangumiTimelineType::Anime, 8, 7).await;
124        assert!(result.is_err());
125        let error = result.unwrap_err();
126        match error {
127            BpiError::InvalidParameter { field, message } => {
128                assert_eq!(field, "before");
129                assert_eq!(message, "before参数必须在0-7之间");
130            }
131            _ => panic!("Expected InvalidParameter error"),
132        }
133    }
134
135    #[tokio::test]
136    async fn test_bangumi_timeline_invalid_after() {
137        let bpi = BpiClient::new();
138        let result = bpi.bangumi_timeline(BangumiTimelineType::Anime, 3, 8).await;
139        assert!(result.is_err());
140        let error = result.unwrap_err();
141        match error {
142            BpiError::InvalidParameter { field, message } => {
143                assert_eq!(field, "after");
144                assert_eq!(message, "after参数必须在0-7之间");
145            }
146            _ => panic!("Expected InvalidParameter error"),
147        }
148    }
149
150    #[test]
151    fn test_bangumi_timeline_type() {
152        assert_eq!(BangumiTimelineType::Anime.as_i32(), 1);
153        assert_eq!(BangumiTimelineType::Movie.as_i32(), 3);
154        assert_eq!(BangumiTimelineType::ChineseAnimation.as_i32(), 4);
155    }
156}