Skip to main content

bpi_rs/creativecenter/
params.rs

1use crate::ids::Aid;
2use crate::{BpiError, BpiResult};
3
4/// Parameters for `/x2/creative/web/archives/sp`.
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub struct UpArchivesListParams {
7    page: u32,
8    page_size: Option<u32>,
9}
10
11impl UpArchivesListParams {
12    pub fn new(page: u32) -> BpiResult<Self> {
13        Ok(Self {
14            page: validate_non_zero_u32("pn", page)?,
15            page_size: None,
16        })
17    }
18
19    pub fn with_page_size(mut self, page_size: u32) -> BpiResult<Self> {
20        self.page_size = Some(validate_non_zero_u32("ps", page_size)?);
21        Ok(self)
22    }
23
24    pub(crate) fn query_pairs(&self) -> Vec<(&'static str, String)> {
25        let mut query = vec![("pn", self.page.to_string())];
26
27        if let Some(page_size) = self.page_size {
28            query.push(("ps", page_size.to_string()));
29        }
30
31        query
32    }
33}
34
35/// Parameters for `/x/web/archive/videos`.
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub struct UpArchiveVideosParams {
38    aid: Aid,
39}
40
41impl UpArchiveVideosParams {
42    pub fn new(aid: Aid) -> Self {
43        Self { aid }
44    }
45
46    pub(crate) fn query_pairs(&self) -> [(&'static str, String); 1] {
47        [("aid", self.aid.to_string())]
48    }
49}
50
51/// Parameters for `/x/web/data/archive_diagnose/compare`.
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
53pub struct UpArchiveCompareParams {
54    timestamp: Option<u64>,
55    size: Option<u32>,
56}
57
58impl UpArchiveCompareParams {
59    pub fn new() -> Self {
60        Self::default()
61    }
62
63    pub fn with_timestamp(mut self, timestamp: u64) -> BpiResult<Self> {
64        self.timestamp = Some(validate_non_zero_u64("t", timestamp)?);
65        Ok(self)
66    }
67
68    pub fn with_size(mut self, size: u32) -> BpiResult<Self> {
69        self.size = Some(validate_non_zero_u32("size", size)?);
70        Ok(self)
71    }
72
73    pub(crate) fn query_pairs(&self) -> Vec<(&'static str, String)> {
74        let mut query = Vec::new();
75
76        if let Some(timestamp) = self.timestamp {
77            query.push(("t", timestamp.to_string()));
78        }
79
80        if let Some(size) = self.size {
81            query.push(("size", size.to_string()));
82        }
83
84        query
85    }
86}
87
88/// Metric for `/x/web/data/pandect` video trend queries.
89#[derive(Debug, Clone, Copy, PartialEq, Eq)]
90pub enum UpVideoTrendMetric {
91    Play,
92    Danmaku,
93    Reply,
94    Share,
95    Coin,
96    Favorite,
97    Charge,
98    Like,
99}
100
101impl UpVideoTrendMetric {
102    const fn code(self) -> u8 {
103        match self {
104            Self::Play => 1,
105            Self::Danmaku => 2,
106            Self::Reply => 3,
107            Self::Share => 4,
108            Self::Coin => 5,
109            Self::Favorite => 6,
110            Self::Charge => 7,
111            Self::Like => 8,
112        }
113    }
114}
115
116/// Parameters for `/x/web/data/pandect`.
117#[derive(Debug, Clone, Copy, PartialEq, Eq)]
118pub struct UpVideoTrendParams {
119    metric: UpVideoTrendMetric,
120}
121
122impl UpVideoTrendParams {
123    pub fn new(metric: UpVideoTrendMetric) -> Self {
124        Self { metric }
125    }
126
127    pub(crate) fn query_pairs(&self) -> [(&'static str, String); 1] {
128        [("type", self.metric.code().to_string())]
129    }
130}
131
132/// Metric for `/x/web/data/article/thirty` article trend queries.
133#[derive(Debug, Clone, Copy, PartialEq, Eq)]
134pub enum UpArticleTrendMetric {
135    Read,
136    Reply,
137    Share,
138    Coin,
139    Favorite,
140    Like,
141}
142
143impl UpArticleTrendMetric {
144    const fn code(self) -> u8 {
145        match self {
146            Self::Read => 1,
147            Self::Reply => 2,
148            Self::Share => 3,
149            Self::Coin => 4,
150            Self::Favorite => 5,
151            Self::Like => 6,
152        }
153    }
154}
155
156/// Parameters for `/x/web/data/article/thirty`.
157#[derive(Debug, Clone, Copy, PartialEq, Eq)]
158pub struct UpArticleTrendParams {
159    metric: UpArticleTrendMetric,
160}
161
162impl UpArticleTrendParams {
163    pub fn new(metric: UpArticleTrendMetric) -> Self {
164        Self { metric }
165    }
166
167    pub(crate) fn query_pairs(&self) -> [(&'static str, String); 1] {
168        [("type", self.metric.code().to_string())]
169    }
170}
171
172fn validate_non_zero_u32(field: &'static str, value: u32) -> BpiResult<u32> {
173    if value == 0 {
174        return Err(BpiError::invalid_parameter(field, "value must be non-zero"));
175    }
176
177    Ok(value)
178}
179
180fn validate_non_zero_u64(field: &'static str, value: u64) -> BpiResult<u64> {
181    if value == 0 {
182        return Err(BpiError::invalid_parameter(field, "value must be non-zero"));
183    }
184
185    Ok(value)
186}
187
188#[cfg(test)]
189mod tests {
190    use super::*;
191
192    #[test]
193    fn up_archives_list_params_serializes_required_page() -> BpiResult<()> {
194        let params = UpArchivesListParams::new(1)?;
195
196        assert_eq!(params.query_pairs(), vec![("pn", "1".to_string())]);
197        Ok(())
198    }
199
200    #[test]
201    fn up_archives_list_params_serializes_optional_page_size() -> BpiResult<()> {
202        let params = UpArchivesListParams::new(2)?.with_page_size(20)?;
203
204        assert_eq!(
205            params.query_pairs(),
206            vec![("pn", "2".to_string()), ("ps", "20".to_string())]
207        );
208        Ok(())
209    }
210
211    #[test]
212    fn up_archives_list_params_rejects_zero_page() {
213        let err = UpArchivesListParams::new(0).unwrap_err();
214
215        assert!(matches!(
216            err,
217            BpiError::InvalidParameter { field: "pn", .. }
218        ));
219    }
220
221    #[test]
222    fn up_archives_list_params_rejects_zero_page_size() -> BpiResult<()> {
223        let err = UpArchivesListParams::new(1)?.with_page_size(0).unwrap_err();
224
225        assert!(matches!(
226            err,
227            BpiError::InvalidParameter { field: "ps", .. }
228        ));
229        Ok(())
230    }
231
232    #[test]
233    fn up_archive_videos_params_serializes_aid_query() -> BpiResult<()> {
234        let params = UpArchiveVideosParams::new(Aid::new(113602455409683)?);
235
236        assert_eq!(
237            params.query_pairs(),
238            [("aid", "113602455409683".to_string())]
239        );
240        Ok(())
241    }
242
243    #[test]
244    fn up_archive_compare_params_serializes_empty_defaults() {
245        let params = UpArchiveCompareParams::new();
246
247        assert!(params.query_pairs().is_empty());
248    }
249
250    #[test]
251    fn up_archive_compare_params_serializes_optional_filters() -> BpiResult<()> {
252        let params = UpArchiveCompareParams::new()
253            .with_timestamp(1_720_000_000)?
254            .with_size(3)?;
255
256        assert_eq!(
257            params.query_pairs(),
258            vec![("t", "1720000000".to_string()), ("size", "3".to_string())]
259        );
260        Ok(())
261    }
262
263    #[test]
264    fn up_archive_compare_params_rejects_zero_size() {
265        let err = UpArchiveCompareParams::new().with_size(0).unwrap_err();
266
267        assert!(matches!(
268            err,
269            BpiError::InvalidParameter { field: "size", .. }
270        ));
271    }
272
273    #[test]
274    fn up_video_trend_params_serializes_metric_code() {
275        let params = UpVideoTrendParams::new(UpVideoTrendMetric::Play);
276
277        assert_eq!(params.query_pairs(), [("type", "1".to_string())]);
278    }
279
280    #[test]
281    fn up_video_trend_metric_maps_like_code() {
282        let params = UpVideoTrendParams::new(UpVideoTrendMetric::Like);
283
284        assert_eq!(params.query_pairs(), [("type", "8".to_string())]);
285    }
286
287    #[test]
288    fn up_article_trend_params_serializes_metric_code() {
289        let params = UpArticleTrendParams::new(UpArticleTrendMetric::Read);
290
291        assert_eq!(params.query_pairs(), [("type", "1".to_string())]);
292    }
293
294    #[test]
295    fn up_article_trend_metric_maps_like_code() {
296        let params = UpArticleTrendParams::new(UpArticleTrendMetric::Like);
297
298        assert_eq!(params.query_pairs(), [("type", "6".to_string())]);
299    }
300}