use crate::article::models::ArticleStats;
use crate::{ BilibiliRequest, BpiClient, BpiError, BpiResponse };
use serde::{ Deserialize, Serialize };
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ArticleInfoData {
pub like: i32,
pub attention: bool,
pub favorite: bool,
pub coin: i32,
pub stats: ArticleStats,
pub title: String,
pub banner_url: String,
pub mid: i64,
pub author_name: String,
pub is_author: bool,
pub image_urls: Vec<String>,
pub origin_image_urls: Vec<String>,
pub shareable: bool,
pub show_later_watch: bool,
pub show_small_window: bool,
pub in_list: bool,
pub pre: i64,
pub next: i64,
pub share_channels: Vec<ShareChannel>,
pub r#type: i32,
#[serde(default)]
pub video_url: String,
#[serde(default)]
pub location: String,
#[serde(default)]
pub disable_share: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ShareChannel {
pub name: String,
pub picture: String,
pub share_channel: String,
}
impl BpiClient {
pub async fn article_info(&self, id: i64) -> Result<BpiResponse<ArticleInfoData>, BpiError> {
self
.get("https://api.bilibili.com/x/article/viewinfo")
.query(&[("id", id.to_string())])
.send_bpi("获取专栏文章基本信息").await
}
}
#[cfg(test)]
mod tests {
use super::*;
const TEST_CVID: i64 = 2;
#[tokio::test]
async fn test_article_info() -> Result<(), Box<BpiError>> {
let bpi = BpiClient::new();
let cvid = TEST_CVID;
let result = bpi.article_info(cvid).await?;
let data = result.data.unwrap();
assert!(!data.title.is_empty());
assert!(!data.author_name.is_empty());
assert!(data.mid > 0);
Ok(())
}
#[tokio::test]
async fn test_article_stats() -> Result<(), Box<BpiError>> {
let bpi = BpiClient::new();
let result = bpi.article_info(TEST_CVID).await?;
let data = result.data.unwrap();
let stats = &data.stats;
assert!(stats.view >= 0);
assert!(stats.favorite >= 0);
assert!(stats.like >= 0);
assert!(stats.reply >= 0);
Ok(())
}
}