use owo_colors::OwoColorize;
use ssrm::{Config, ConfigFile, confirm, find_files, format_bytes, parse_date, remove_files};
use std::{env, path::PathBuf};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let args: Vec<String> = env::args().collect();
if args.iter().any(|a| a == "-h" || a == "--help") {
print_help();
return Ok(());
}
let has = |short: &str, long: &str| args.iter().any(|a| a == short || a == long);
let get_opt = |name: &str| args.windows(2).find(|w| w[0] == name).map(|w| w[1].as_str());
let cfg = Config {
dry_run: has("-n", "--dry-run"),
use_trash: has("-t", "--move-to-trash"),
include_videos: has("-v", "--videos"),
skip_confirm: has("-f", "--force") || has("-y", "--yes"),
recursive: has("-r", "--recursive"),
quiet: has("-q", "--quiet"),
verbose: has("-V", "--verbose"),
before: get_opt("--before").and_then(parse_date),
after: get_opt("--after").and_then(parse_date),
default_dir: None,
}.with_file_defaults(ConfigFile::load());
let expand_path = |a: &str| if a.starts_with('~') {
dirs::home_dir().expect("No home").join(a.strip_prefix("~/").unwrap_or(""))
} else { PathBuf::from(a) };
let target = args.iter().skip(1)
.find(|a| !a.starts_with('-') && parse_date(a).is_none())
.map(|a| expand_path(a))
.or(cfg.default_dir.clone())
.unwrap_or_else(|| dirs::desktop_dir().expect("No desktop"));
let files = find_files(&target, &cfg)?;
if files.is_empty() {
if !cfg.quiet {
println!("No screenshots{} found in {}{}.",
if cfg.include_videos { "/recordings" } else { "" },
target.display(),
if cfg.recursive { " (recursive)" } else { "" });
}
return Ok(());
}
let label = if cfg.include_videos { "file" } else { "screenshot" };
let total_size: u64 = files.iter().filter_map(|p| p.metadata().ok()).map(|m| m.len()).sum();
if !cfg.quiet { println!("Found {} {}(s) ({}):", files.len(), label, format_bytes(total_size)); }
if cfg.dry_run {
if !cfg.quiet {
for path in &files {
println!(" {} {}", "[dry-run]".cyan(), path.file_name().unwrap().to_string_lossy());
}
println!("\nRun without -n to delete.");
}
} else if cfg.skip_confirm || confirm(&format!(
"{} {} {}(s){}? [y/N] ",
if cfg.use_trash { "Move" } else { "Permanently delete" },
files.len(), label,
if cfg.use_trash { " to trash" } else { "" }
)) {
let stats = remove_files(&files, &cfg);
if !cfg.quiet {
let action = if cfg.use_trash { "Trashed" } else { "Removed" };
println!("\n{} {} {}(s). Freed {}.", action, stats.removed, label, format_bytes(stats.bytes_freed));
}
} else if !cfg.quiet {
println!("Aborted.");
}
Ok(())
}
fn print_help() {
println!("ssrm - Remove macOS screenshots/recordings\n");
println!("Usage: ssrm [DIR] [OPTIONS]\n");
println!("Arguments:");
println!(" [DIR] Target directory (default: Desktop)\n");
println!("Options:");
println!(" -n, --dry-run Show what would be deleted without deleting");
println!(" -t, --move-to-trash Move to trash instead of permanent deletion");
println!(" -v, --videos Include screen recordings");
println!(" -f, --force Skip confirmation prompt");
println!(" -y, --yes Alias for --force");
println!(" -r, --recursive Search directories recursively");
println!(" -q, --quiet Suppress output (for scripting)");
println!(" -V, --verbose Show detailed debug output");
println!(" --before DATE Only files before DATE (YYYY-MM-DD)");
println!(" --after DATE Only files after DATE (YYYY-MM-DD)");
println!(" -h, --help Show this help\n");
println!("Config: ~/.config/ssrm.toml");
println!(" use_trash = true # Always use trash");
println!(" include_videos = true # Include recordings");
println!(" recursive = true # Search recursively");
println!(" default_dir = \"~/...\" # Default target directory");
}