1use crate::{BilibiliRequest, BpiClient, BpiError, BpiResponse};
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Deserialize, Serialize)]
11pub struct OnlineTotalShowSwitch {
12 pub total: bool,
14 pub count: bool,
16}
17
18#[derive(Debug, Clone, Deserialize, Serialize)]
20pub struct OnlineTotalResponseData {
21 pub total: String,
23 pub count: String,
25 pub show_switch: OnlineTotalShowSwitch,
27}
28
29impl BpiClient {
30 pub async fn video_online_total(
43 &self,
44 aid: Option<u64>,
45 bvid: Option<&str>,
46 cid: u64,
47 ) -> Result<BpiResponse<OnlineTotalResponseData>, BpiError> {
48 if aid.is_none() && bvid.is_none() {
49 return Err(BpiError::parse("必须提供 aid 或 bvid"));
50 }
51
52 let mut req = self
53 .get("https://api.bilibili.com/x/player/online/total")
54 .query(&[("cid", &cid.to_string())]);
55
56 if let Some(a) = aid {
57 req = req.query(&[("aid", &a.to_string())]);
58 }
59 if let Some(b) = bvid {
60 req = req.query(&[("bvid", b)]);
61 }
62
63 req.send_bpi("获取视频在线人数").await
64 }
65}
66
67#[cfg(test)]
70mod tests {
71 use super::*;
72 use tracing::info;
73
74 const TEST_AID: u64 = 759949922;
76 const TEST_CID: u64 = 392402545;
77 const TEST_BVID: &str = "BV1y64y1q757";
78
79 #[tokio::test]
80 async fn test_video_online_total_by_aid() -> Result<(), BpiError> {
81 let bpi = BpiClient::new();
82 let resp = bpi
83 .video_online_total(Some(TEST_AID), None, TEST_CID)
84 .await?;
85
86 let data = resp.into_data()?;
87
88 info!("视频在线人数: {:?}", data);
89 assert!(!data.count.is_empty());
90 assert!(!data.total.is_empty());
91
92 Ok(())
93 }
94
95 #[tokio::test]
96 async fn test_video_online_total_by_bvid() -> Result<(), BpiError> {
97 let bpi = BpiClient::new();
98 let resp = bpi
99 .video_online_total(None, Some(TEST_BVID), TEST_CID)
100 .await?;
101
102 let data = resp.into_data()?;
103
104 info!("视频在线人数: {:?}", data);
105
106 assert!(!data.count.is_empty());
107 assert!(!data.total.is_empty());
108
109 Ok(())
110 }
111}