refactor: extract platform media crates

This commit is contained in:
kdletters
2026-05-26 13:18:13 +08:00
parent 50f44489cd
commit 44c65df5c9
92 changed files with 7381 additions and 5848 deletions

View File

@@ -0,0 +1,159 @@
use serde_json::Value;
pub(crate) fn parse_api_error_message(raw_text: &str, fallback_message: &str) -> String {
if let Ok(parsed) = serde_json::from_str::<Value>(raw_text) {
for key in ["message", "detail", "error"] {
if let Some(message) = find_first_string_by_key(&parsed, key)
&& !message.trim().is_empty()
{
return message;
}
}
}
raw_text
.trim()
.chars()
.take(240)
.collect::<String>()
.trim()
.to_string()
.chars()
.next()
.map(|_| raw_text.trim().chars().take(240).collect())
.unwrap_or_else(|| fallback_message.to_string())
}
pub(crate) fn find_first_array_by_keys<'a>(
value: &'a Value,
keys: &[&str],
) -> Option<&'a Vec<Value>> {
match value {
Value::Object(object) => {
for (key, value) in object {
if keys.iter().any(|target| key.eq_ignore_ascii_case(target))
&& let Some(array) = value.as_array()
{
return Some(array);
}
if let Some(found) = find_first_array_by_keys(value, keys) {
return Some(found);
}
}
None
}
Value::Array(items) => items
.iter()
.find_map(|item| find_first_array_by_keys(item, keys)),
_ => None,
}
}
pub(crate) fn find_first_string_by_keys(value: &Value, keys: &[&str]) -> Option<String> {
keys.iter()
.find_map(|key| find_first_string_by_key(value, key))
}
pub(crate) fn find_first_f64_by_keys(value: &Value, keys: &[&str]) -> Option<f64> {
match value {
Value::Object(object) => {
for (key, value) in object {
if keys.iter().any(|target| key.eq_ignore_ascii_case(target))
&& let Some(number) = value.as_f64()
{
return Some(number);
}
if let Some(found) = find_first_f64_by_keys(value, keys) {
return Some(found);
}
}
None
}
Value::Array(items) => items
.iter()
.find_map(|item| find_first_f64_by_keys(item, keys)),
_ => None,
}
}
pub(crate) fn find_first_string_by_key(value: &Value, target_key: &str) -> Option<String> {
match value {
Value::Object(object) => {
for (key, value) in object {
if key.eq_ignore_ascii_case(target_key)
&& let Some(text) = value.as_str()
{
return Some(text.trim().to_string());
}
if let Some(found) = find_first_string_by_key(value, target_key) {
return Some(found);
}
}
None
}
Value::Array(items) => items
.iter()
.find_map(|item| find_first_string_by_key(item, target_key)),
_ => None,
}
}
pub(crate) fn find_root_string_by_keys(value: &Value, keys: &[&str]) -> Option<String> {
let object = value.as_object()?;
for key in keys {
if let Some(text) = object
.iter()
.find(|(candidate, _)| candidate.eq_ignore_ascii_case(key))
.and_then(|(_, value)| value.as_str())
.map(str::trim)
.filter(|value| !value.is_empty())
{
return Some(text.to_string());
}
}
None
}
pub(crate) fn collect_strings_by_keys(value: &Value, keys: &[&str]) -> Vec<String> {
let mut results = Vec::new();
collect_strings(value, keys, &mut results);
let mut deduped = Vec::new();
for result in results {
if !deduped.contains(&result) {
deduped.push(result);
}
}
deduped
}
fn collect_strings(value: &Value, keys: &[&str], output: &mut Vec<String>) {
match value {
Value::Object(object) => {
for (key, value) in object {
if keys.iter().any(|target| key.eq_ignore_ascii_case(target)) {
match value {
Value::String(text) if !text.trim().is_empty() => {
output.push(text.trim().to_string());
}
Value::Array(items) => {
for item in items {
if let Some(text) = item.as_str().map(str::trim)
&& !text.is_empty()
{
output.push(text.to_string());
}
}
}
_ => {}
}
}
collect_strings(value, keys, output);
}
}
Value::Array(items) => {
for item in items {
collect_strings(item, keys, output);
}
}
_ => {}
}
}