use crate::{ BilibiliRequest, BpiClient, BpiError, BpiResponse };
use serde::{ Deserialize, Serialize };
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NavData {
#[serde(rename = "isLogin")]
pub is_login: bool,
pub wbi_img: WbiImg,
pub email_verified: i32,
pub face: String,
pub face_nft: i32,
pub level_info: LevelInfo,
pub mid: u64,
pub mobile_verified: i32,
pub money: f64,
pub moral: i32,
pub official: Official,
#[serde(rename = "officialVerify")]
pub official_verify: OfficialVerify,
pub pendant: Pendant,
pub scores: i32,
pub uname: String,
#[serde(rename = "vipDueDate")]
pub vip_due_date: u64,
#[serde(rename = "vipStatus")]
pub vip_status: i32,
#[serde(rename = "vipType")]
pub vip_type: i32,
pub vip_pay_type: i32,
pub vip_theme_type: i32,
pub vip_label: VipLabel,
pub vip_avatar_subscript: i32,
pub vip_nickname_color: String,
pub vip: Vip,
pub wallet: Wallet,
pub has_shop: bool,
pub shop_url: String,
pub is_senior_member: i32,
pub is_jury: bool,
pub name_render: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Wallet {
pub mid: u64,
pub bcoin_balance: i64,
pub coupon_balance: i64,
pub coupon_due_time: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WbiImg {
pub img_url: String,
pub sub_url: String,
}
use crate::models::{ LevelInfo, Official, OfficialVerify, Pendant, Vip, VipLabel };
#[derive(Debug, Clone, Serialize)]
pub struct User {
is_login: bool, face: String, mid: u64, money: f64, uname: String, is_vip: bool, }
impl BpiClient {
pub async fn login_info_nav_info(&self) -> Result<BpiResponse<NavData>, BpiError> {
self
.get("https://api.bilibili.com/x/web-interface/nav")
.send_bpi("获取导航栏用户信息").await
}
pub async fn is_logged_in(&self) -> bool {
self.login_info_nav_info().await.is_ok()
}
pub async fn login_info_user_info(&self) -> Result<User, BpiError> {
let nav_response = self.login_info_nav_info().await;
match nav_response {
Ok(nav_response) =>
Ok(
if let Some(data) = nav_response.data {
User {
is_login: data.is_login,
face: data.face,
mid: data.mid,
money: data.money,
uname: data.uname,
is_vip: data.vip.vip_status == 1,
}
} else {
User {
is_login: false,
face: String::new(),
mid: 0,
money: 0.0,
uname: String::new(),
is_vip: false,
}
}
),
_ => Err(BpiError::auth("账号未登录".to_string())),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use tracing::info;
#[tokio::test]
async fn test_bilibili_uinfo() -> Result<(), Box<BpiError>> {
let bpi = BpiClient::new();
let resp = bpi.login_info_nav_info().await?;
if resp.code == 0 {
let data = resp.data.unwrap();
info!("登录成功!UID={} 昵称={} ", data.mid, data.uname);
}
Ok(())
}
#[tokio::test]
async fn test_user_info() -> Result<(), Box<BpiError>> {
let bpi = BpiClient::new();
let user_info = bpi.login_info_user_info().await?;
info!("用户信息:{:?}", user_info);
Ok(())
}
}