use crate::{ BilibiliRequest, BpiClient, BpiError, BpiResponse };
use serde::{ Deserialize, Serialize };
#[derive(Debug, Serialize, Clone, Deserialize)]
pub struct UserPointData {
pub point: String,
}
pub type UserPointResponse = BpiResponse<UserPointData>;
#[derive(Debug, Serialize, Clone, Deserialize)]
pub struct ProductLimit {
#[serde(rename = "type")]
pub limit_type: i32,
pub id: i64,
pub title: String,
}
#[derive(Debug, Serialize, Clone, Deserialize)]
pub struct Product {
pub id: i64,
pub r#type: i32,
pub title: String,
pub image: String,
pub amount: i32,
pub cost: i32,
pub real_cost: i32,
pub remain_amount: i32,
pub comic_id: i64,
pub limits: Vec<ProductLimit>,
pub discount: i32,
pub product_type: i32,
pub pendant_url: String,
pub pendant_expire: i32,
pub exchange_limit: i32,
pub address_deadline: String,
pub act_type: i32,
pub has_exchanged: bool,
pub main_coupon_deadline: String,
pub deadline: String,
pub point: String,
}
pub type ProductListResponse = BpiResponse<Vec<Product>>;
#[derive(Debug, Clone, Serialize)]
pub struct ExchangeRequest {
pub product_id: String,
pub product_num: i32,
pub point: i32,
}
pub type ExchangeResponse = BpiResponse<serde_json::Value>;
impl BpiClient {
pub async fn manga_user_point(&self) -> Result<UserPointResponse, BpiError> {
self
.post("https://manga.bilibili.com/twirp/pointshop.v1.Pointshop/GetUserPoint")
.send_bpi("获取当前持有点数").await
}
pub async fn manga_point_products(&self) -> Result<ProductListResponse, BpiError> {
self
.post("https://manga.bilibili.com/twirp/pointshop.v1.Pointshop/ListProduct")
.send_bpi("获取兑换奖品列表").await
}
pub async fn manga_point_exchange(
&self,
product_id: i64,
product_num: i32,
point: i32
) -> Result<ExchangeResponse, BpiError> {
let req = ExchangeRequest {
product_id: product_id.to_string(),
product_num,
point,
};
self
.post("https://manga.bilibili.com/twirp/pointshop.v1.Pointshop/Exchange")
.form(&req)
.send_bpi("兑换物品").await
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_list_product() -> Result<(), Box<BpiError>> {
let bpi = BpiClient::new();
let resp = bpi.manga_point_products().await?;
let data = resp.into_data()?;
assert!(!data.is_empty());
Ok(())
}
#[tokio::test]
async fn test_get_user_point() -> Result<(), Box<BpiError>> {
let bpi = BpiClient::new();
let resp = bpi.manga_user_point().await?;
let data = resp.into_data()?;
tracing::info!("User point: {}", data.point);
Ok(())
}
}