use std::path::{Path, PathBuf};
use bnto_core::BntoError;
use bnto_core::processor::{FileData, OutputFile};
use crate::validate;
pub(crate) fn collect_output_files(
dir: &Path,
max_output_mb: u64,
) -> Result<Vec<OutputFile>, BntoError> {
let mut files = Vec::new();
collect_output_files_recursive(dir, dir, max_output_mb, &mut files)?;
Ok(files)
}
fn collect_output_files_recursive(
root_dir: &Path,
dir: &Path,
max_output_mb: u64,
files: &mut Vec<OutputFile>,
) -> Result<(), BntoError> {
let entries = std::fs::read_dir(dir).map_err(|e| {
BntoError::ProcessingFailed(format!("Failed to read output directory: {e}"))
})?;
for entry in entries.flatten() {
let path = entry.path();
if path.is_dir() {
collect_output_files_recursive(root_dir, &path, max_output_mb, files)?;
} else if path.is_file() {
files.push(output_file(root_dir, path, max_output_mb)?);
}
}
Ok(())
}
fn output_file(
root_dir: &Path,
path: PathBuf,
max_output_mb: u64,
) -> Result<OutputFile, BntoError> {
let filename = relative_name(root_dir, &path);
check_file_size(&path, &filename, max_output_mb)?;
let mime = mime_from_extension(&filename);
Ok(OutputFile {
data: FileData::Path(path),
filename,
mime_type: mime,
metadata: serde_json::Map::new(),
})
}
fn relative_name(root_dir: &Path, path: &Path) -> String {
path.strip_prefix(root_dir)
.map(bnto_core::slash_path)
.unwrap_or_else(|_| {
path.file_name()
.map(|n| n.to_string_lossy().into_owned())
.unwrap_or_else(|| "output".to_string())
})
}
fn check_file_size(path: &Path, filename: &str, max_output_mb: u64) -> Result<(), BntoError> {
let file_size = std::fs::metadata(path).map(|m| m.len()).unwrap_or(0);
let limit = validate::max_output_bytes(max_output_mb) as u64;
if file_size > limit {
return Err(BntoError::ProcessingFailed(format!(
"Output file '{}' is {} MB, exceeding the {} MB limit",
filename,
file_size / (1024 * 1024),
max_output_mb
)));
}
Ok(())
}
pub(crate) fn mime_from_extension(filename: &str) -> String {
let ext = filename
.rsplit_once('.')
.map(|(_, e)| e.to_lowercase())
.unwrap_or_default();
match ext.as_str() {
"mp4" => "video/mp4",
"webm" => "video/webm",
"mkv" => "video/x-matroska",
"mp3" => "audio/mpeg",
"m4a" => "audio/mp4",
"ogg" | "opus" => "audio/ogg",
"wav" => "audio/wav",
"flac" => "audio/flac",
"json" => "application/json",
"txt" | "log" => "text/plain",
_ => "application/octet-stream",
}
.to_string()
}