1use crate::{ BilibiliRequest, BpiClient, BpiError, BpiResponse };
6use serde::{ Deserialize, Serialize };
7
8#[derive(Debug, Clone, Serialize)]
12pub struct ClockInMakeupRequest {
13 pub r#type: i32,
15 pub date: String,
17}
18
19#[derive(Debug, Serialize, Clone, Deserialize)]
21pub struct PointInfo {
22 pub point: i32,
24 pub origin_point: i32,
26 pub is_activity: bool,
28 pub title: String,
30}
31
32#[derive(Debug, Serialize, Clone, Deserialize)]
34pub struct ClockInInfoData {
35 pub day_count: i32,
37 pub status: i32,
39 pub points: Vec<i32>,
41 pub credit_icon: String,
43 pub sign_before_icon: String,
45 pub sign_today_icon: String,
47 pub breathe_icon: String,
49 #[serde(default)]
51 pub new_credit_x_icon: String,
52 #[serde(default)]
54 pub coupon_pic: String,
55 pub point_infos: Vec<PointInfo>,
57}
58
59pub type ClockInInfoResponse = BpiResponse<ClockInInfoData>;
60
61impl BpiClient {
64 pub async fn manga_clock_in(&self) -> Result<BpiResponse<serde_json::Value>, BpiError> {
69 let params = [("platform", "android")];
70 self
71 .post("https://manga.bilibili.com/twirp/activity.v1.Activity/ClockIn")
72 .form(¶ms)
73 .send_bpi("漫画签到").await
74 }
75
76 pub async fn manga_clock_in_makeup(
87 &self,
88 date: &str
89 ) -> Result<BpiResponse<serde_json::Value>, BpiError> {
90 let params = ClockInMakeupRequest {
91 r#type: 0,
92 date: date.to_string(),
93 };
94 self
95 .post("https://manga.bilibili.com/twirp/activity.v1.Activity/ClockIn?platform=android")
96 .json(¶ms)
97 .send_bpi("漫画补签").await
98 }
99
100 pub async fn manga_clock_in_info(&self) -> Result<ClockInInfoResponse, BpiError> {
105 self
106 .post("https://manga.bilibili.com/twirp/activity.v1.Activity/GetClockInInfo")
107 .send_bpi("获取漫画签到信息").await
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114
115 #[tokio::test]
116 async fn test_manga_clock_in() -> Result<(), Box<BpiError>> {
117 let bpi = BpiClient::new();
118
119 let result = bpi.manga_clock_in().await;
120 match result {
121 Ok(_) => tracing::info!("签到成功"),
122 Err(error) => tracing::error!("{:#?}", error),
123 }
124
125 Ok(())
126 }
127
128 #[tokio::test]
129 async fn test_get_manga_clock_in_info() -> Result<(), Box<BpiError>> {
130 let bpi = BpiClient::new();
131
132 let result = bpi.manga_clock_in_info().await?;
133
134 let data = result.into_data()?;
135
136 assert!(data.day_count >= 0);
137 assert!(data.status == 0 || data.status == 1);
138 assert_eq!(data.points.len(), 7); assert!(!data.point_infos.is_empty());
140
141 Ok(())
142 }
143}