live_web_start/
live_web_start.rs1#[path = "common/account.rs"]
16mod account;
17
18use bpi_rs::BpiResult;
19
20const DEFAULT_ROOM_ID: i64 = 4354019;
21const DEFAULT_AREA_ID: u64 = 309;
22const MUTATING_ENV: &str = "BPI_MUTATING_TEST";
23
24fn mask(s: &str) -> String {
25 if s.len() <= 8 {
26 return "***".to_string();
27 }
28 format!("{}...{}", &s[..4], &s[s.len() - 4..])
29}
30
31fn mutating_enabled() -> bool {
32 std::env::var(MUTATING_ENV).ok().as_deref() == Some("1")
33}
34
35#[tokio::main]
36async fn main() -> BpiResult<()> {
37 let stop_if_live = std::env::args().any(|a| a == "--stop-if-live");
38 let stop_only = std::env::args().any(|a| a == "--stop-only");
39 let room_id: i64 = std::env::var("BILI_ROOM_ID")
40 .ok()
41 .and_then(|s| s.parse().ok())
42 .unwrap_or(DEFAULT_ROOM_ID);
43 let area_id: u64 = std::env::var("BILI_AREA_ID")
44 .ok()
45 .and_then(|s| s.parse().ok())
46 .unwrap_or(DEFAULT_AREA_ID);
47
48 let bpi = account::authenticated_client()?;
49
50 println!("=== Rust 网页自动开播验证 ===");
51 println!("room_id={room_id} area_v2={area_id}");
52
53 let live = bpi.live();
54 let info = live.room_info(room_id).await?;
55 println!(
56 "当前状态: live_status={} title={} area={}·{}",
57 info.live_status, info.title, info.parent_area_name, info.area_name
58 );
59
60 if !mutating_enabled() {
61 println!("{MUTATING_ENV}=1 未设置,只读取直播间状态,不执行开播、关播或获取推流码。");
62 return Ok(());
63 }
64
65 if stop_only {
66 if info.live_status == 1 {
67 println!("执行关播...");
68 let stop = live.live_stop(room_id as u64, "pc").await?;
69 println!("关播结果: status={}", stop.status);
70 tokio::time::sleep(std::time::Duration::from_secs(3)).await;
71 } else {
72 println!("当前未开播,跳过关播接口。");
73 }
74
75 let after = live.room_info(room_id).await?;
76 println!(
77 "验证: live_status={} ({})",
78 after.live_status,
79 if after.live_status == 0 {
80 "关播成功"
81 } else {
82 "仍在直播中"
83 }
84 );
85 return Ok(());
86 }
87
88 if info.live_status == 1 {
89 if stop_if_live {
90 println!("已在直播,--stop-if-live:先关播...");
91 let stop = live.live_stop(room_id as u64, "pc").await?;
92 println!("关播结果: status={}", stop.status);
93 tokio::time::sleep(std::time::Duration::from_secs(2)).await;
94 } else {
95 println!("已在直播中。若要完整验证开播链路,请加 --stop-if-live 或先手动关播。");
96 println!("仍尝试 FetchWebUpStreamAddr(只读)...");
97 let stream = live.live_fetch_web_up_stream_addr().await?;
98 println!("推流地址: {}{}", stream.addr.addr, mask(&stream.addr.code));
99 return Ok(());
100 }
101 }
102
103 println!("\n[1/2] FetchWebUpStreamAddr...");
104 let stream = live.live_fetch_web_up_stream_addr().await?;
105 println!(" rtmp: {}{}", stream.addr.addr, mask(&stream.addr.code));
106
107 println!("\n[2/2] WebLiveCenterStartLive (WBI)...");
108 let start = live.live_web_center_start(room_id as u64, area_id).await?;
109 println!(" status={} live_key={}", start.status, start.live_key);
110 if let Some(rtmp) = &start.rtmp {
111 println!(" rtmp(响应): {}{}", rtmp.addr, mask(&rtmp.code));
112 } else {
113 println!(" rtmp(响应): null(正常,推流码以 Fetch 为准)");
114 }
115
116 tokio::time::sleep(std::time::Duration::from_secs(2)).await;
117 let after = live.room_info(room_id).await?;
118 println!(
119 "\n验证: live_status={} ({})",
120 after.live_status,
121 if after.live_status == 1 {
122 "开播成功"
123 } else {
124 "未变为直播中(可能需 OBS 推流)"
125 }
126 );
127
128 Ok(())
129}