pinakes/crates/pinakes-core/src/export.rs
NotAShelf 185e3b562a
treewide: cleanup
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ia01590cdeed872cc8ebd16f6ca95f3cc6a6a6964
2026-03-12 19:41:15 +03:00

91 lines
2.6 KiB
Rust

use std::path::Path;
use serde::{Deserialize, Serialize};
/// Quote a string field for CSV output: wrap in double-quotes and escape
/// internal double-quotes by doubling them (RFC 4180).
fn csv_quote(s: &str) -> String {
if s.contains([',', '"', '\n', '\r']) {
format!("\"{}\"", s.replace('"', "\"\""))
} else {
s.to_string()
}
}
use crate::{error::Result, jobs::ExportFormat, storage::DynStorageBackend};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExportResult {
pub items_exported: usize,
pub output_path: String,
}
/// Export library data to the specified format.
///
/// # Errors
///
/// Returns an error if the storage query fails or if the output file cannot
/// be written.
pub async fn export_library(
storage: &DynStorageBackend,
format: &ExportFormat,
destination: &Path,
) -> Result<ExportResult> {
let pagination = crate::model::Pagination {
offset: 0,
limit: u64::MAX,
sort: None,
};
let items = storage.list_media(&pagination).await?;
let count = items.len();
match format {
ExportFormat::Json => {
let json = serde_json::to_string_pretty(&items).map_err(|e| {
crate::error::PinakesError::Serialization(format!(
"json serialize: {e}"
))
})?;
std::fs::write(destination, json)?;
},
ExportFormat::Csv => {
let mut csv = String::new();
csv.push_str(
"id,path,file_name,media_type,content_hash,file_size,title,artist,\
album,genre,year,duration_secs,description,created_at,updated_at\n",
);
for item in &items {
use std::fmt::Write as _;
writeln!(
csv,
"{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}",
item.id,
csv_quote(&item.path.display().to_string()),
csv_quote(&item.file_name),
csv_quote(&format!("{:?}", item.media_type)),
item.content_hash,
item.file_size,
csv_quote(item.title.as_deref().unwrap_or("")),
csv_quote(item.artist.as_deref().unwrap_or("")),
csv_quote(item.album.as_deref().unwrap_or("")),
csv_quote(item.genre.as_deref().unwrap_or("")),
item.year.map(|y| y.to_string()).unwrap_or_default(),
item
.duration_secs
.map(|d| d.to_string())
.unwrap_or_default(),
csv_quote(item.description.as_deref().unwrap_or("")),
item.created_at,
item.updated_at,
)
.unwrap_or_default();
}
std::fs::write(destination, csv)?;
},
}
Ok(ExportResult {
items_exported: count,
output_path: destination.to_string_lossy().to_string(),
})
}