From c1f80f9abe870a221ef34182716403b40056d598 Mon Sep 17 00:00:00 2001 From: Vladimir Rubin Date: Mon, 30 Dec 2024 01:26:58 +0200 Subject: [PATCH] feat: add actually working sorting --- Cargo.lock | 1 + Cargo.toml | 12 +++- src/lib.rs | 10 ++-- src/main.rs | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 171 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6e9ed43..dc7e58b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -101,6 +101,7 @@ version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ + "indexmap", "serde", "serde_spanned", "toml_datetime", diff --git a/Cargo.toml b/Cargo.toml index 75f0da3..1cbfd5b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,4 +4,14 @@ version = "0.1.0" edition = "2021" [dependencies] -toml = "0.8.19" +toml = {version="0.8.19", default-features = false, features = ["parse", "preserve_order"]} + +[profile.release.package."*"] +opt-level = "z" + +[profile.release] +strip = true +codegen-units = 1 +opt-level = "s" +lto = "thin" +panic = "abort" diff --git a/src/lib.rs b/src/lib.rs index 2814359..9890683 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,17 +13,17 @@ pub struct Config { } pub const PICTURE_EXTENTIONS: [&str; 17] = [ - ".jpg", ".jpeg", ".png", ".gif", ".webp", ".jfif", ".bmp", ".apng", ".avif", ".tif", ".tga", - ".psd", ".eps", ".ai", ".indd", ".raw", ".ico", + "jpg", "jpeg", "png", "gif", "webp", "jfif", "bmp", "apng", "avif", "tif", "tga", + "psd", "eps", "ai", "indd", "raw", "ico", ]; pub const SOUND_EXTENTIONS: [&str; 10] = [ - ".mp3", ".wav", ".flac", ".ogg", ".aac", ".m4a", ".wma", ".aiff", ".au", ".opus", + "mp3", "wav", "flac", "ogg", "aac", "m4a", "wma", "aiff", "au", "opus", ]; pub const BOOK_EXTENTIONS: [&str; 11] = [ - ".pdf", ".epub", ".mobi", ".cbz", ".cbr", ".chm", ".djvu", ".fb2", ".lit", ".prc", ".xps", + "pdf", "epub", "mobi", "cbz", "cbr", "chm", "djvu", "fb2", "lit", "prc", "xps", ]; pub const VIDEO_EXTENTIONS: [&str; 11] = [ - ".mp4", ".mkv", ".avi", ".flv", ".webm", ".wmv", ".mov", ".m4v", ".3gp", ".3g2", ".swf", + "mp4", "mkv", "avi", "flv", "webm", "wmv", "mov", "m4v", "3gp", "3g2", "swf", ]; impl Config { diff --git a/src/main.rs b/src/main.rs index a9dcfc6..0024eb1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,23 +1,171 @@ -use std::{env, path::PathBuf}; +use std::{ + env, fs, + io::{self, Write}, + path::PathBuf, + process, + sync::OnceLock, + thread, +}; + +use filesorters::Config; + +static CONFIG: OnceLock = OnceLock::new(); fn main() { let config_path = get_config_path(); - println!("Using config file: {}", config_path.display()); - if !config_path.exists() { println!("Config file does not exist, creating..."); filesorters::Config::create(&config_path).unwrap(); } match filesorters::Config::parse(config_path) { - Ok(config) => { - println!("{:#?}", config); + Ok(parsed_config) => { + CONFIG.set(parsed_config).unwrap(); + println!("Config file loaded successfully"); } Err(err) => { - println!("Error: {}", err); + eprintln!("Error: {}", err); + process::exit(1); } } + { + let mut counter = 1; + for alias in CONFIG.get().unwrap().sources.keys() { + println!("{}: {}", counter, alias); + counter += 1; + } + } + + let mut actual_selection: Vec = Vec::new(); + + loop { + print!("Enter: "); + io::stdout().flush().unwrap(); + let mut selected = String::new(); + io::stdin() + .read_line(&mut selected) + .expect("Failed to read line"); + + let parsed_selection: Vec = selected + .split(" ") + .filter(|y| !y.is_empty()) + .map(|y| y.replace("\n", "")) + .flat_map(|x| x.parse::()) + .collect(); + + if parsed_selection.is_empty() { + println!("Invalid selection"); + continue; + } + if parsed_selection.len() > CONFIG.get().unwrap().sources.keys().len() { + println!("Too many selections made"); + continue; + } + if parsed_selection + .iter() + .any(|x| *x > CONFIG.get().unwrap().sources.keys().len()) + { + println!("Invalid selection"); + continue; + } + + for selection in parsed_selection { + actual_selection.push( + CONFIG + .get() + .unwrap() + .sources + .keys() + .nth(selection - 1) + .unwrap() + .to_string(), + ); + } + + break; + } + + println!("Selected: {}", actual_selection.join(", ")); + + let mut thread_pool: Vec> = Vec::new(); + + for selection in actual_selection { + let thread = thread::spawn(move || { + let _ = sort_files(selection, false); // TODO: handle errors + }); + + thread_pool.push(thread); + } + + for thread in thread_pool { + thread.join().unwrap(); + } +} + +fn sort_files(selection: String, _recursive: bool) -> Result<(), Box> { + println!("Sorting {}", selection); + + let search_path = CONFIG + .get() + .and_then(|config| config.sources.get(&selection)) + .cloned() + .unwrap(); + + println!("Searching in {}", search_path.display()); + + let dir = fs::read_dir(search_path)?; + + + // TODO: Simplyfy by using an array of tulpes instead of a bucket of ifs + for entry in dir.flatten().filter(|e| e.metadata().unwrap().is_file()) { + if let Some(extension) = entry.path().extension().and_then(|e| e.to_str()) { + let config = CONFIG.get().unwrap(); + let path = entry.path(); + + // Book files + if config.books_dir.is_some() && filesorters::BOOK_EXTENTIONS.contains(&extension) { + println!("Moved to Books: {}", path.display()); + if let Some(books_dir) = &config.books_dir { + move_file_to_directory(&path, books_dir); + } + } + + // Picture files + if config.pictures_dir.is_some() && filesorters::PICTURE_EXTENTIONS.contains(&extension) + { + println!("Moved to Pictures: {}", path.display()); + if let Some(pictures_dir) = &config.pictures_dir { + move_file_to_directory(&path, pictures_dir); + } + } + + // Video files + if config.videos_dir.is_some() && filesorters::VIDEO_EXTENTIONS.contains(&extension) { + println!("Moved to Videos: {}", path.display()); + if let Some(videos_dir) = &config.videos_dir { + move_file_to_directory(&path, videos_dir); + } + } + + // Music files + if config.music_dir.is_some() && filesorters::SOUND_EXTENTIONS.contains(&extension) { + println!("Moved to Music: {}", path.display()); + if let Some(music_dir) = &config.music_dir { + move_file_to_directory(&path, music_dir); + } + } + } + } + + Ok(()) +} + +fn move_file_to_directory(path: &std::path::Path, dir: &std::path::Path) { + let _ = fs::rename( + path, + dir.join(path.file_name().unwrap()) + ); } fn get_config_path() -> PathBuf {