Skip to main content

bpi_rs/live/
danmaku.rs

1use crate::{ BilibiliRequest, BpiClient, BpiError, BpiResponse };
2use chrono::Utc;
3use reqwest::multipart::Form;
4use serde::{ Deserialize, Serialize };
5
6// --- 弹幕发送响应数据结构体 ---
7
8/// 弹幕发送响应数据
9#[derive(Debug, Clone, Deserialize, Serialize)]
10pub struct SendDanmuData {
11    pub mode_info: Option<serde_json::Value>,
12    pub dm_v2: Option<serde_json::Value>,
13}
14
15impl BpiClient {
16    /// 发送直播间弹幕
17    ///
18    /// # 参数
19    /// * `room_id` - 直播间 ID
20    /// * `message` - 弹幕内容
21    /// * `color` - 十进制颜色值,默认 16777215 (白色)
22    /// * `font_size` - 字体大小,默认 25
23    pub async fn live_send_danmu(
24        &self,
25        room_id: u64,
26        message: &str,
27        color: Option<u32>,
28        font_size: Option<u32>
29    ) -> Result<BpiResponse<SendDanmuData>, BpiError> {
30        let csrf = self.csrf()?;
31        let now = Utc::now().timestamp();
32
33        // 使用 Form 构建 application/x-www-form-urlencoded 请求体
34        let mut form = Form::new()
35            .text("csrf", csrf.clone())
36            .text("roomid", room_id.to_string())
37            .text("msg", message.to_string())
38            .text("rnd", now.to_string())
39            .text("bubble", "0")
40            .text("mode", "1")
41            .text("statistics", r#"{"appId":100,"platform":5}"#)
42            .text("csrf_token", csrf); // 文档中提到 csrf_token 和 csrf 相同
43
44        if let Some(c) = color {
45            form = form.text("color", c.to_string());
46        } else {
47            form = form.text("color", "16777215"); // 默认白色
48        }
49
50        if let Some(s) = font_size {
51            form = form.text("fontsize", s.to_string());
52        } else {
53            form = form.text("fontsize", "25"); // 默认 25
54        }
55
56        self
57            .post("https://api.live.bilibili.com/msg/send")
58            .multipart(form)
59            .send_bpi("发送直播弹幕").await
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66    use tracing::info;
67
68    #[tokio::test]
69    async fn test_send_live_danmu() -> Result<(), BpiError> {
70        let bpi = BpiClient::new();
71        // 替换为实际的直播间 ID,这是一个公开的直播间 ID
72        let room_id = 21733448;
73        let message = "牛";
74
75        let resp = bpi.live_send_danmu(room_id, &message, None, None).await?;
76        assert_eq!(resp.code, 0);
77        let data = resp.into_data()?;
78
79        info!("弹幕发送成功!返回数据: {:?}", data);
80
81        Ok(())
82    }
83}