refactor: extract platform media crates
This commit is contained in:
118
server-rs/crates/platform-audio/src/download.rs
Normal file
118
server-rs/crates/platform-audio/src/download.rs
Normal file
@@ -0,0 +1,118 @@
|
||||
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()
|
||||
}
|
||||
Reference in New Issue
Block a user