use std::fs::create_dir_all;
use std::path::PathBuf;
use tauri::{AppHandle, Manager, Runtime};
use crate::error::Error;
const MEDIA_CACHE_SUBDIR: &str = "media-cache";
const MEDIA_OUTPUT_SUBDIR: &str = "media";
pub fn get_media_cache_dir<R: Runtime>(app: &AppHandle<R>) -> Result<PathBuf, Error> {
let base_path = app
.path()
.app_cache_dir()
.map_err(|e| Error::InvalidPath(format!("Could not determine app cache directory: {e}")))?;
let full_path = base_path.join(MEDIA_CACHE_SUBDIR);
create_dir_all(&full_path).map_err(|e| {
Error::InvalidPath(format!(
"Could not create cache directory {}: {}",
full_path.display(),
e
))
})?;
Ok(full_path)
}
pub fn get_media_output_dir<R: Runtime>(app: &AppHandle<R>) -> Result<PathBuf, Error> {
let base_path = app
.path()
.app_data_dir()
.map_err(|e| Error::InvalidPath(format!("Could not determine app data directory: {e}")))?;
let full_path = base_path.join(MEDIA_OUTPUT_SUBDIR);
create_dir_all(&full_path).map_err(|e| {
Error::InvalidPath(format!(
"Could not create output directory {}: {}",
full_path.display(),
e
))
})?;
Ok(full_path)
}
pub fn validate_path(path: &str) -> Result<(), Error> {
let path_buf = PathBuf::from(path);
for component in path_buf.components() {
if let std::path::Component::ParentDir = component {
return Err(Error::InvalidPath(
"Path traversal not allowed (contains '..')".to_string(),
));
}
}
Ok(())
}
pub fn cleanup_old_cache<R: Runtime>(app: &AppHandle<R>, max_age_hours: u64) -> Result<u64, Error> {
use std::time::{Duration, SystemTime};
let cache_dir = get_media_cache_dir(app)?;
let max_age = Duration::from_secs(max_age_hours * 3600);
let now = SystemTime::now();
let mut deleted_count = 0u64;
if let Ok(entries) = std::fs::read_dir(&cache_dir) {
for entry in entries.flatten() {
if let Ok(metadata) = entry.metadata() {
if let Ok(modified) = metadata.modified() {
if let Ok(age) = now.duration_since(modified) {
if age > max_age && metadata.is_file() {
if std::fs::remove_file(entry.path()).is_ok() {
deleted_count += 1;
}
}
}
}
}
}
}
Ok(deleted_count)
}