Skip to main content

bpi_rs/live/
report.rs

1use serde::{ Deserialize, Serialize };
2
3use crate::{ BilibiliRequest, BpiClient, BpiError, BpiResponse };
4use base64::{ Engine as _, engine::general_purpose };
5
6// ================= 数据结构 =================
7
8#[derive(Debug, Serialize, Clone, Deserialize)]
9pub struct HeartBeatData {
10    /// 下次心跳间隔
11    pub next_interval: i32,
12}
13
14pub type HeartBeatResponse = BpiResponse<HeartBeatData>;
15
16// ================= 实现 =================
17
18impl BpiClient {
19    /// 直播心跳 (Web端)
20    ///
21    /// # 文档
22    /// [查看API文档](https://github.com/SocialSisterYi/bilibili-API-collect/tree/master/docs/live)
23    pub async fn live_web_heart_beat(
24        &self,
25        room_id: i64,
26        next_interval: Option<i32>,
27        platform: Option<&str>
28    ) -> Result<HeartBeatResponse, BpiError> {
29        // 构建心跳数据
30        let interval = next_interval.unwrap_or(60);
31        let heart_beat_data = format!("{interval}|{room_id}|1|0");
32
33        // Base64编码
34        let encoded_hb = general_purpose::STANDARD.encode(heart_beat_data);
35
36        let mut params: Vec<(&str, String)> = vec![("hb", encoded_hb)];
37
38        if let Some(platform) = platform {
39            params.push(("pf", platform.to_string()));
40        } else {
41            params.push(("pf", "web".to_string()));
42        }
43
44        let resp: HeartBeatResponse = self
45            .get("https://live-trace.bilibili.com/xlive/rdata-interface/v1/heartbeat/webHeartBeat")
46            .query(&params)
47            .send_bpi("直播心跳上报").await?;
48
49        Ok(resp)
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    #[tokio::test]
58    async fn test_web_heart_beat() -> Result<(), Box<BpiError>> {
59        let bpi = BpiClient::new();
60        let resp = bpi.live_web_heart_beat(23174842, None, None).await?;
61
62        let data = resp.data.unwrap();
63
64        assert!(data.next_interval > 0);
65        Ok(())
66    }
67}