use crate::{ BilibiliRequest, BpiClient, BpiError, BpiResponse };
use serde::{ Deserialize, Serialize };
use std::collections::HashMap;
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct LoginNoticeData {
pub mid: u64,
pub device_name: String,
pub login_type: String,
pub login_time: String,
pub location: String,
pub ip: String,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct LoginLogData {
pub count: u32,
pub list: Vec<LoginLogEntry>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct LoginLogEntry {
pub ip: String,
pub time: u64,
pub time_at: String,
pub status: bool,
#[serde(rename = "type")]
pub login_type: u8,
#[serde(rename = "geo")]
pub location: String,
}
impl BpiClient {
pub async fn login_notice(
&self,
mid: u64,
buvid: Option<&str>
) -> Result<BpiResponse<LoginNoticeData>, BpiError> {
let mut params = HashMap::new();
params.insert("mid", mid.to_string());
if let Some(buvid_val) = buvid {
params.insert("buvid", buvid_val.to_string());
}
self
.get("https://api.bilibili.com/x/safecenter/login_notice")
.query(¶ms)
.send_bpi("查询登录记录").await
}
pub async fn login_log(&self) -> Result<BpiResponse<LoginLogData>, BpiError> {
self
.get("https://api.bilibili.com/x/member/web/login/log")
.query(
&[
("jsonp", "jsonp"),
("web_location", "333.33"),
]
)
.send_bpi("查询最近一周登录情况").await
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_get_login_notice() -> Result<(), BpiError> {
let bpi = BpiClient::new();
let mid = 4279370;
let resp = bpi.login_notice(mid, None).await?;
let data = resp.into_data()?;
println!("指定登录记录:");
println!(" 设备名: {}", data.device_name);
println!(" 登录方式: {}", data.login_type);
println!(" 登录时间: {}", data.login_time);
println!(" 登录位置: {}", data.location);
println!(" IP: {}", data.ip);
assert_eq!(data.mid, mid);
Ok(())
}
#[tokio::test]
async fn test_get_login_log() -> Result<(), BpiError> {
let bpi = BpiClient::new();
let resp = bpi.login_log().await?;
let data = resp.into_data()?;
println!("最近一周登录记录 (共 {} 条):", data.count);
for entry in data.list {
println!(" 时间: {} ({})", entry.time_at, entry.time);
println!(" IP: {}", entry.ip);
println!(" 位置: {}", entry.location);
println!(" 登录成功: {}", entry.status);
println!(" 登录类型: {}", entry.login_type);
}
Ok(())
}
}