bpi_rs/audio/
musicstream_url.rs1use crate::{ BilibiliRequest, BpiClient, BpiError, BpiResponse };
5use serde::{ Deserialize, Serialize };
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum AudioQuality {
10 Smooth = 0,
12 Standard = 1,
14 HighQuality = 2,
16 Lossless = 3,
18}
19
20impl AudioQuality {
21 pub fn as_u32(self) -> u32 {
22 self as u32
23 }
24}
25
26#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct AudioStreamUrlWebData {
28 pub sid: u64,
29 pub r#type: u32,
30 pub info: String,
31 pub timeout: u64,
32 pub size: u64,
33 pub cdns: Vec<String>,
34 pub qualities: Option<serde_json::Value>,
35 pub title: String,
36 pub cover: String,
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct AudioStreamUrlData {
41 pub sid: u64,
42 pub r#type: u32,
43 pub info: String,
44 pub timeout: u64,
45 pub size: u64,
46 pub cdns: Vec<String>,
47 pub qualities: Vec<AudioQualityInfo>,
48 pub title: String,
49 pub cover: String,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
53pub struct AudioQualityInfo {
54 pub r#type: u32,
55 pub desc: String,
56 pub size: u64,
57 pub bps: String,
58 pub tag: String,
59 pub require: u32,
60 pub requiredesc: String,
61}
62
63impl BpiClient {
64 pub async fn audio_stream_url_web(
77 &self,
78 sid: u64
79 ) -> Result<BpiResponse<AudioStreamUrlWebData>, BpiError> {
80 let params = [
81 ("sid", sid.to_string()),
82 ("quality", "2".to_string()),
83 ("privilege", "2".to_string()),
84 ];
85
86 self
87 .get("https://www.bilibili.com/audio/music-service-c/web/url")
88 .query(¶ms)
89 .send_bpi("获取音频流URL(web端)").await
90 }
91
92 pub async fn audio_stream_url(
106 &self,
107 songid: u64,
108 quality: AudioQuality
109 ) -> Result<BpiResponse<AudioStreamUrlData>, BpiError> {
110 self
111 .get("https://api.bilibili.com/audio/music-service-c/url")
112 .with_bilibili_headers()
113 .query(
114 &[
115 ("songid", songid.to_string()),
116 ("quality", quality.as_u32().to_string()),
117 ("privilege", "2".to_string()),
118 ("mid", "2".to_string()),
119 ("platform", "android".to_string()),
120 ]
121 )
122 .send_bpi("获取音频流URL").await
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129
130 const TEST_SID: u64 = 13603;
131
132 #[tokio::test]
133 async fn test_audio_stream_url_web() {
134 let bpi = BpiClient::new();
135 let result = bpi.audio_stream_url_web(TEST_SID).await;
136 assert!(result.is_ok());
137 let response = result.unwrap();
138 assert_eq!(response.code, 0);
139 let data = response.data.unwrap();
140
141 assert_eq!(data.sid, TEST_SID);
142 assert!(data.timeout > 0);
143 assert!(!data.cdns.is_empty());
144 }
145
146 #[tokio::test]
147 async fn test_audio_stream_url() {
148 let bpi = BpiClient::new();
149 let result = bpi.audio_stream_url(15664, AudioQuality::HighQuality).await;
150 assert!(result.is_ok());
151 let response = result.unwrap();
152 assert_eq!(response.code, 0);
153 let data = response.data.unwrap();
154 assert_eq!(data.sid, 15664);
155 assert!(data.timeout > 0);
156 assert!(!data.cdns.is_empty());
157 assert!(!data.qualities.is_empty());
158 }
159}