bpi_rs/manga/
point_shop.rs1use crate::{ BilibiliRequest, BpiClient, BpiError, BpiResponse };
6use serde::{ Deserialize, Serialize };
7
8#[derive(Debug, Serialize, Clone, Deserialize)]
11pub struct UserPointData {
12 pub point: String,
14}
15
16pub type UserPointResponse = BpiResponse<UserPointData>;
17
18#[derive(Debug, Serialize, Clone, Deserialize)]
19pub struct ProductLimit {
20 #[serde(rename = "type")]
22 pub limit_type: i32,
23 pub id: i64,
25 pub title: String,
27}
28
29#[derive(Debug, Serialize, Clone, Deserialize)]
30pub struct Product {
31 pub id: i64,
33 pub r#type: i32,
35 pub title: String,
37 pub image: String,
39 pub amount: i32,
41 pub cost: i32,
43 pub real_cost: i32,
45 pub remain_amount: i32,
47 pub comic_id: i64,
49 pub limits: Vec<ProductLimit>,
51 pub discount: i32,
53 pub product_type: i32,
55 pub pendant_url: String,
57 pub pendant_expire: i32,
59 pub exchange_limit: i32,
61 pub address_deadline: String,
63 pub act_type: i32,
65 pub has_exchanged: bool,
67 pub main_coupon_deadline: String,
69 pub deadline: String,
71 pub point: String,
73}
74
75pub type ProductListResponse = BpiResponse<Vec<Product>>;
76
77#[derive(Debug, Clone, Serialize)]
78pub struct ExchangeRequest {
79 pub product_id: String,
81 pub product_num: i32,
83 pub point: i32,
85}
86
87pub type ExchangeResponse = BpiResponse<serde_json::Value>;
88
89impl BpiClient {
92 pub async fn manga_user_point(&self) -> Result<UserPointResponse, BpiError> {
96 self
97 .post("https://manga.bilibili.com/twirp/pointshop.v1.Pointshop/GetUserPoint")
98 .send_bpi("获取当前持有点数").await
99 }
100
101 pub async fn manga_point_products(&self) -> Result<ProductListResponse, BpiError> {
105 self
106 .post("https://manga.bilibili.com/twirp/pointshop.v1.Pointshop/ListProduct")
107 .send_bpi("获取兑换奖品列表").await
108 }
109
110 pub async fn manga_point_exchange(
122 &self,
123 product_id: i64,
124 product_num: i32,
125 point: i32
126 ) -> Result<ExchangeResponse, BpiError> {
127 let req = ExchangeRequest {
128 product_id: product_id.to_string(),
129 product_num,
130 point,
131 };
132
133 self
134 .post("https://manga.bilibili.com/twirp/pointshop.v1.Pointshop/Exchange")
135 .form(&req)
136 .send_bpi("兑换物品").await
137 }
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143
144 #[tokio::test]
145 async fn test_list_product() -> Result<(), Box<BpiError>> {
146 let bpi = BpiClient::new();
147 let resp = bpi.manga_point_products().await?;
148
149 let data = resp.into_data()?;
150 assert!(!data.is_empty());
151 Ok(())
152 }
153
154 #[tokio::test]
155 async fn test_get_user_point() -> Result<(), Box<BpiError>> {
156 let bpi = BpiClient::new();
157
158 let resp = bpi.manga_user_point().await?;
159 let data = resp.into_data()?;
160
161 tracing::info!("User point: {}", data.point);
162 Ok(())
163 }
164}