119 lines
3.6 KiB
Rust
119 lines
3.6 KiB
Rust
use std::error::Error;
|
||
|
||
use reqwest::header;
|
||
|
||
use crate::{AudioError, DownloadedAudio, MAX_GENERATED_AUDIO_BYTES};
|
||
|
||
pub fn normalize_audio_mime_type(content_type: &str, audio_url: &str) -> String {
|
||
let mime_type = content_type
|
||
.split(';')
|
||
.next()
|
||
.map(str::trim)
|
||
.filter(|value| value.starts_with("audio/"))
|
||
.unwrap_or("");
|
||
match mime_type {
|
||
"audio/mpeg" | "audio/mp3" => "audio/mpeg".to_string(),
|
||
"audio/wav" | "audio/wave" | "audio/x-wav" => "audio/wav".to_string(),
|
||
"audio/ogg" => "audio/ogg".to_string(),
|
||
"audio/webm" => "audio/webm".to_string(),
|
||
"audio/aac" => "audio/aac".to_string(),
|
||
"audio/flac" => "audio/flac".to_string(),
|
||
"audio/mp4" | "audio/x-m4a" => "audio/mp4".to_string(),
|
||
_ => mime_type_from_audio_url(audio_url),
|
||
}
|
||
}
|
||
|
||
pub fn audio_mime_to_extension(mime_type: &str) -> &'static str {
|
||
match mime_type {
|
||
"audio/wav" => "wav",
|
||
"audio/ogg" => "ogg",
|
||
"audio/webm" => "webm",
|
||
"audio/aac" => "aac",
|
||
"audio/flac" => "flac",
|
||
"audio/mp4" => "m4a",
|
||
_ => "mp3",
|
||
}
|
||
}
|
||
|
||
pub async fn download_generated_audio(
|
||
http_client: &reqwest::Client,
|
||
audio_url: &str,
|
||
_provider: &str,
|
||
) -> Result<DownloadedAudio, AudioError> {
|
||
let response = http_client.get(audio_url).send().await.map_err(|error| {
|
||
AudioError::request(
|
||
format!("下载生成音频失败:{error}"),
|
||
Some(audio_url.to_string()),
|
||
error.is_timeout(),
|
||
error.is_connect(),
|
||
error.is_request(),
|
||
error.is_body(),
|
||
error.status().map(|status| status.as_u16()),
|
||
Error::source(&error).map(ToString::to_string),
|
||
)
|
||
})?;
|
||
let status = response.status();
|
||
let content_type = response
|
||
.headers()
|
||
.get(header::CONTENT_TYPE)
|
||
.and_then(|value| value.to_str().ok())
|
||
.unwrap_or("audio/mpeg")
|
||
.to_string();
|
||
let body = response.bytes().await.map_err(|error| {
|
||
AudioError::request(
|
||
format!("读取生成音频内容失败:{error}"),
|
||
Some(audio_url.to_string()),
|
||
false,
|
||
false,
|
||
false,
|
||
true,
|
||
None,
|
||
None,
|
||
)
|
||
})?;
|
||
if !status.is_success() {
|
||
return Err(AudioError::upstream(
|
||
format!("下载生成音频失败:HTTP {}", status.as_u16()),
|
||
status.as_u16(),
|
||
truncate_raw(""),
|
||
));
|
||
}
|
||
if body.is_empty() || body.len() > MAX_GENERATED_AUDIO_BYTES {
|
||
return Err(AudioError::missing_audio("生成音频内容为空或超过大小上限"));
|
||
}
|
||
|
||
let mime_type = normalize_audio_mime_type(&content_type, audio_url);
|
||
Ok(DownloadedAudio {
|
||
extension: audio_mime_to_extension(&mime_type).to_string(),
|
||
mime_type,
|
||
bytes: body.to_vec(),
|
||
})
|
||
}
|
||
|
||
fn mime_type_from_audio_url(audio_url: &str) -> String {
|
||
let path = audio_url
|
||
.split('?')
|
||
.next()
|
||
.unwrap_or_default()
|
||
.to_ascii_lowercase();
|
||
if path.ends_with(".wav") {
|
||
"audio/wav".to_string()
|
||
} else if path.ends_with(".ogg") {
|
||
"audio/ogg".to_string()
|
||
} else if path.ends_with(".webm") {
|
||
"audio/webm".to_string()
|
||
} else if path.ends_with(".aac") {
|
||
"audio/aac".to_string()
|
||
} else if path.ends_with(".flac") {
|
||
"audio/flac".to_string()
|
||
} else if path.ends_with(".m4a") {
|
||
"audio/mp4".to_string()
|
||
} else {
|
||
"audio/mpeg".to_string()
|
||
}
|
||
}
|
||
|
||
fn truncate_raw(raw_text: &str) -> String {
|
||
raw_text.chars().take(800).collect()
|
||
}
|