1
0
Fork 0
mirror of synced 2024-04-28 01:22:53 +12:00

Things dedup (#1183)

* Deduplicate cli settings

* Save

* Nice

* TODO even bigger generalization

* Simplification

* Bad
This commit is contained in:
Rafał Mikrut 2024-01-14 14:38:55 +01:00 committed by GitHub
parent 0defcbd253
commit 6cde5ab7a0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 497 additions and 890 deletions

57
Cargo.lock generated
View file

@ -953,6 +953,19 @@ dependencies = [
"crossbeam-utils",
]
[[package]]
name = "console"
version = "0.15.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb"
dependencies = [
"encode_unicode",
"lazy_static",
"libc",
"unicode-width",
"windows-sys 0.52.0",
]
[[package]]
name = "const-field-offset"
version = "0.1.3"
@ -1179,6 +1192,16 @@ dependencies = [
"syn 2.0.48",
]
[[package]]
name = "ctrlc"
version = "3.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b467862cc8610ca6fc9a1532d7777cee0804e678ab45410897b9396495994a0b"
dependencies = [
"nix 0.27.1",
"windows-sys 0.52.0",
]
[[package]]
name = "cursor-icon"
version = "1.1.0"
@ -1190,10 +1213,13 @@ name = "czkawka_cli"
version = "6.1.0"
dependencies = [
"clap",
"crossbeam-channel",
"ctrlc",
"czkawka_core",
"fun_time",
"handsome_logger",
"image_hasher",
"indicatif",
"log",
]
@ -1574,6 +1600,12 @@ version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]]
name = "encode_unicode"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
[[package]]
name = "encoding_rs"
version = "0.8.33"
@ -3081,6 +3113,19 @@ dependencies = [
"hashbrown 0.14.3",
]
[[package]]
name = "indicatif"
version = "0.17.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25"
dependencies = [
"console",
"instant",
"number_prefix",
"portable-atomic",
"unicode-width",
]
[[package]]
name = "infer"
version = "0.15.0"
@ -3898,6 +3943,12 @@ dependencies = [
"libc",
]
[[package]]
name = "number_prefix"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]]
name = "objc"
version = "0.2.7"
@ -6102,6 +6153,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94"
[[package]]
name = "unicode-width"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
[[package]]
name = "untrusted"
version = "0.9.0"

View file

@ -10,6 +10,9 @@
### CLI
- Providing full static rust binary with [Eyra](https://github.com/sunfishcode/eyra) - [#1102](https://github.com/qarmin/czkawka/pull/1102)
- Fixed duplicated `-c` argument, now saving as compact json is handled via `-C` - [#1153](https://github.com/qarmin/czkawka/pull/1153)
- Added progress bar - [#TODO]()
- Clean and safe cancelling of scan - [#TODO]()
- Unification of CLI arguments - [#TODO]()
### Krokiet GUI
- Initial release of new gui - [#1102](https://github.com/qarmin/czkawka/pull/1102)

View file

@ -19,6 +19,9 @@ log = "0.4.20"
handsome_logger = "0.8"
fun_time = { version = "0.3", features = ["log"] }
czkawka_core = { path = "../czkawka_core", version = "6.1.0", features = [] }
indicatif = "0.17"
crossbeam-channel = { version = "0.5", features = [] }
ctrlc = { version = "3.4", features = ["termination"] }
[features]
default = []

View file

@ -87,13 +87,7 @@ pub enum Commands {
#[derive(Debug, clap::Args)]
pub struct DuplicatesArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)]
pub directories: Directories,
#[clap(flatten)]
pub excluded_directories: ExcludedDirectories,
#[clap(flatten)]
pub excluded_items: ExcludedItems,
pub common_cli_items: CommonCliItems,
#[clap(
short,
long,
@ -121,8 +115,6 @@ pub struct DuplicatesArgs {
long_help = "Minimum size of cached files in bytes, assigning bigger value may speed up the scan but loading the cache will be slower, assigning smaller value may slow down the scan and some files may need to be hashed again but loading the cache will be faster"
)]
pub minimal_cached_file_size: u64,
#[clap(flatten)]
pub allowed_extensions: AllowedExtensions,
#[clap(
short,
long,
@ -143,18 +135,7 @@ pub struct DuplicatesArgs {
)]
pub hash_type: HashType,
#[clap(flatten)]
pub file_to_save: FileToSave,
#[clap(flatten)]
pub json_compact_file_to_save: JsonCompactFileToSave,
#[clap(flatten)]
pub json_pretty_file_to_save: JsonPrettyFileToSave,
#[clap(flatten)]
pub not_recursive: NotRecursive,
#[clap(flatten)]
pub case_sensitive_name_comparison: CaseSensitiveNameComparison,
#[cfg(target_family = "unix")]
#[clap(flatten)]
pub exclude_other_filesystems: ExcludeOtherFilesystems,
#[clap(flatten)]
pub allow_hard_links: AllowHardLinks,
#[clap(flatten)]
@ -164,117 +145,43 @@ pub struct DuplicatesArgs {
#[derive(Debug, clap::Args)]
pub struct EmptyFoldersArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)]
pub directories: Directories,
#[clap(flatten)]
pub excluded_directories: ExcludedDirectories,
#[clap(flatten)]
pub excluded_items: ExcludedItems,
pub common_cli_items: CommonCliItems,
#[clap(short = 'D', long, help = "Delete found folders")]
pub delete_folders: bool,
#[clap(flatten)]
pub file_to_save: FileToSave,
#[clap(flatten)]
pub json_compact_file_to_save: JsonCompactFileToSave,
#[clap(flatten)]
pub json_pretty_file_to_save: JsonPrettyFileToSave,
#[cfg(target_family = "unix")]
#[clap(flatten)]
pub exclude_other_filesystems: ExcludeOtherFilesystems,
}
#[derive(Debug, clap::Args)]
pub struct BiggestFilesArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)]
pub directories: Directories,
#[clap(flatten)]
pub excluded_directories: ExcludedDirectories,
#[clap(flatten)]
pub excluded_items: ExcludedItems,
#[clap(flatten)]
pub allowed_extensions: AllowedExtensions,
pub common_cli_items: CommonCliItems,
#[clap(short, long, default_value = "50", help = "Number of files to be shown")]
pub number_of_files: usize,
#[clap(short = 'D', long, help = "Delete found files")]
pub delete_files: bool,
#[clap(flatten)]
pub file_to_save: FileToSave,
#[clap(flatten)]
pub json_compact_file_to_save: JsonCompactFileToSave,
#[clap(flatten)]
pub json_pretty_file_to_save: JsonPrettyFileToSave,
#[clap(flatten)]
pub not_recursive: NotRecursive,
#[clap(short = 'J', long, help = "Finds the smallest files instead the biggest")]
pub smallest_mode: bool,
#[cfg(target_family = "unix")]
#[clap(flatten)]
pub exclude_other_filesystems: ExcludeOtherFilesystems,
}
#[derive(Debug, clap::Args)]
pub struct EmptyFilesArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)]
pub directories: Directories,
#[clap(flatten)]
pub excluded_directories: ExcludedDirectories,
#[clap(flatten)]
pub excluded_items: ExcludedItems,
#[clap(flatten)]
pub allowed_extensions: AllowedExtensions,
pub common_cli_items: CommonCliItems,
#[clap(short = 'D', long, help = "Delete found files")]
pub delete_files: bool,
#[clap(flatten)]
pub file_to_save: FileToSave,
#[clap(flatten)]
pub json_compact_file_to_save: JsonCompactFileToSave,
#[clap(flatten)]
pub json_pretty_file_to_save: JsonPrettyFileToSave,
#[clap(flatten)]
pub not_recursive: NotRecursive,
#[cfg(target_family = "unix")]
#[clap(flatten)]
pub exclude_other_filesystems: ExcludeOtherFilesystems,
}
#[derive(Debug, clap::Args)]
pub struct TemporaryArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)]
pub directories: Directories,
#[clap(flatten)]
pub excluded_directories: ExcludedDirectories,
#[clap(flatten)]
pub excluded_items: ExcludedItems,
pub common_cli_items: CommonCliItems,
#[clap(short = 'D', long, help = "Delete found files")]
pub delete_files: bool,
#[clap(flatten)]
pub file_to_save: FileToSave,
#[clap(flatten)]
pub json_compact_file_to_save: JsonCompactFileToSave,
#[clap(flatten)]
pub json_pretty_file_to_save: JsonPrettyFileToSave,
#[clap(flatten)]
pub not_recursive: NotRecursive,
#[cfg(target_family = "unix")]
#[clap(flatten)]
pub exclude_other_filesystems: ExcludeOtherFilesystems,
}
#[derive(Debug, clap::Args)]
pub struct SimilarImagesArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)]
pub directories: Directories,
#[clap(flatten)]
pub excluded_directories: ExcludedDirectories,
pub common_cli_items: CommonCliItems,
#[clap(
short,
long,
@ -303,22 +210,9 @@ pub struct SimilarImagesArgs {
)]
pub similarity_preset: SimilarityPreset,
#[clap(flatten)]
pub excluded_items: ExcludedItems,
#[clap(flatten)]
pub file_to_save: FileToSave,
#[clap(flatten)]
pub delete_method: DMethod,
#[clap(flatten)]
pub dry_run: DryRun,
#[clap(flatten)]
pub json_compact_file_to_save: JsonCompactFileToSave,
#[clap(flatten)]
pub json_pretty_file_to_save: JsonPrettyFileToSave,
#[clap(flatten)]
pub not_recursive: NotRecursive,
#[cfg(target_family = "unix")]
#[clap(flatten)]
pub exclude_other_filesystems: ExcludeOtherFilesystems,
#[clap(
short = 'g',
long,
@ -348,13 +242,7 @@ pub struct SimilarImagesArgs {
#[derive(Debug, clap::Args)]
pub struct SameMusicArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)]
pub directories: Directories,
#[clap(flatten)]
pub excluded_directories: ExcludedDirectories,
#[clap(flatten)]
pub excluded_items: ExcludedItems,
pub common_cli_items: CommonCliItems,
#[clap(flatten)]
pub delete_method: DMethod,
#[clap(flatten)]
@ -377,17 +265,6 @@ pub struct SameMusicArgs {
long_help = "Methods to search files.\nCONTENT - finds similar audio files by content, TAGS - finds similar images by tags, needs to set"
)]
pub search_method: CheckingMethod,
#[clap(flatten)]
pub file_to_save: FileToSave,
#[clap(flatten)]
pub json_compact_file_to_save: JsonCompactFileToSave,
#[clap(flatten)]
pub json_pretty_file_to_save: JsonPrettyFileToSave,
#[clap(flatten)]
pub not_recursive: NotRecursive,
#[cfg(target_family = "unix")]
#[clap(flatten)]
pub exclude_other_filesystems: ExcludeOtherFilesystems,
#[clap(
short,
long,
@ -458,84 +335,27 @@ fn parse_minimum_segment_duration(src: &str) -> Result<f32, String> {
#[derive(Debug, clap::Args)]
pub struct InvalidSymlinksArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)]
pub directories: Directories,
#[clap(flatten)]
pub excluded_directories: ExcludedDirectories,
#[clap(flatten)]
pub excluded_items: ExcludedItems,
#[clap(flatten)]
pub allowed_extensions: AllowedExtensions,
pub common_cli_items: CommonCliItems,
#[clap(short = 'D', long, help = "Delete found files")]
pub delete_files: bool,
#[clap(flatten)]
pub file_to_save: FileToSave,
#[clap(flatten)]
pub json_compact_file_to_save: JsonCompactFileToSave,
#[clap(flatten)]
pub json_pretty_file_to_save: JsonPrettyFileToSave,
#[clap(flatten)]
pub not_recursive: NotRecursive,
#[cfg(target_family = "unix")]
#[clap(flatten)]
pub exclude_other_filesystems: ExcludeOtherFilesystems,
}
#[derive(Debug, clap::Args)]
pub struct BrokenFilesArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)]
pub directories: Directories,
#[clap(flatten)]
pub excluded_directories: ExcludedDirectories,
#[clap(flatten)]
pub excluded_items: ExcludedItems,
#[clap(flatten)]
pub allowed_extensions: AllowedExtensions,
pub common_cli_items: CommonCliItems,
#[clap(short = 'D', long, help = "Delete found files")]
pub delete_files: bool,
#[clap(flatten)]
pub file_to_save: FileToSave,
#[clap(flatten)]
pub json_compact_file_to_save: JsonCompactFileToSave,
#[clap(flatten)]
pub json_pretty_file_to_save: JsonPrettyFileToSave,
#[clap(flatten)]
pub not_recursive: NotRecursive,
#[cfg(target_family = "unix")]
#[clap(flatten)]
pub exclude_other_filesystems: ExcludeOtherFilesystems,
}
#[derive(Debug, clap::Args)]
pub struct SimilarVideosArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)]
pub directories: Directories,
#[clap(flatten)]
pub excluded_directories: ExcludedDirectories,
#[clap(flatten)]
pub excluded_items: ExcludedItems,
pub common_cli_items: CommonCliItems,
#[clap(flatten)]
pub delete_method: DMethod,
#[clap(flatten)]
pub dry_run: DryRun,
#[clap(flatten)]
pub file_to_save: FileToSave,
#[clap(flatten)]
pub json_compact_file_to_save: JsonCompactFileToSave,
#[clap(flatten)]
pub json_pretty_file_to_save: JsonPrettyFileToSave,
#[clap(flatten)]
pub allowed_extensions: AllowedExtensions,
#[clap(flatten)]
pub not_recursive: NotRecursive,
#[cfg(target_family = "unix")]
#[clap(flatten)]
pub exclude_other_filesystems: ExcludeOtherFilesystems,
#[clap(
short,
long,
@ -568,26 +388,53 @@ pub struct SimilarVideosArgs {
#[derive(Debug, clap::Args)]
pub struct BadExtensionsArgs {
#[clap(flatten)]
pub thread_number: ThreadNumber,
#[clap(flatten)]
pub directories: Directories,
#[clap(flatten)]
pub excluded_directories: ExcludedDirectories,
#[clap(flatten)]
pub excluded_items: ExcludedItems,
#[clap(flatten)]
pub allowed_extensions: AllowedExtensions,
pub common_cli_items: CommonCliItems,
}
#[derive(Debug, clap::Args)]
pub struct CommonCliItems {
#[clap(short = 'T', long, default_value = "0", help = "Limits thread number, 0(default) will use all available threads")]
pub thread_number: usize,
#[clap(
short,
long,
required = true,
help = "Directorie(s) to search",
long_help = "List of directorie(s) which will be searched(absolute path)"
)]
pub directories: Vec<PathBuf>,
#[clap(
short,
long,
help = "Excluded directorie(s)",
long_help = "List of directorie(s) which will be excluded from search(absolute path)"
)]
pub excluded_directories: Vec<PathBuf>,
#[clap(
short = 'E',
long,
help = "Excluded item(s)",
long_help = "List of excluded item(s) which contains * wildcard(may be slow, so use -e where possible)"
)]
pub excluded_items: Vec<String>,
#[clap(
short = 'x',
long,
help = "Allowed file extension(s)",
long_help = "List of checked files with provided extension(s). There are also helpful macros which allow to easy use a typical extensions like:\nIMAGE(\"jpg,kra,gif,png,bmp,tiff,hdr,svg\"),\nTEXT(\"txt,doc,docx,odt,rtf\"),\nVIDEO(\"mp4,flv,mkv,webm,vob,ogv,gifv,avi,mov,wmv,mpg,m4v,m4p,mpeg,3gp\") or\nMUSIC(\"mp3,flac,ogg,tta,wma,webm\")\n "
)]
pub allowed_extensions: Vec<String>,
#[clap(flatten)]
pub file_to_save: FileToSave,
#[clap(flatten)]
pub json_compact_file_to_save: JsonCompactFileToSave,
#[clap(flatten)]
pub json_pretty_file_to_save: JsonPrettyFileToSave,
#[clap(flatten)]
pub not_recursive: NotRecursive,
#[clap(short = 'R', long, help = "Prevents from recursive check of folders")]
pub not_recursive: bool,
#[cfg(target_family = "unix")]
#[clap(flatten)]
pub exclude_other_filesystems: ExcludeOtherFilesystems,
#[clap(short = 'X', long, help = "Exclude files on other filesystems")]
pub exclude_other_filesystems: bool,
}
#[derive(Debug, clap::Args)]
@ -603,70 +450,6 @@ pub struct DMethod {
pub delete_method: DeleteMethod,
}
#[derive(Debug, clap::Args)]
pub struct Directories {
#[clap(
short,
long,
required = true,
help = "Directorie(s) to search",
long_help = "List of directorie(s) which will be searched(absolute path)"
)]
pub directories: Vec<PathBuf>,
}
#[derive(Debug, clap::Args)]
pub struct ExcludedDirectories {
#[clap(
short,
long,
help = "Excluded directorie(s)",
long_help = "List of directorie(s) which will be excluded from search(absolute path)"
)]
pub excluded_directories: Vec<PathBuf>,
}
#[derive(Debug, clap::Args)]
pub struct ExcludedItems {
#[clap(
short = 'E',
long,
help = "Excluded item(s)",
long_help = "List of excluded item(s) which contains * wildcard(may be slow, so use -e where possible)"
)]
pub excluded_items: Vec<String>,
}
#[derive(Debug, clap::Args)]
pub struct AllowedExtensions {
#[clap(
short = 'x',
long,
help = "Allowed file extension(s)",
long_help = "List of checked files with provided extension(s). There are also helpful macros which allow to easy use a typical extensions like:\nIMAGE(\"jpg,kra,gif,png,bmp,tiff,hdr,svg\"),\nTEXT(\"txt,doc,docx,odt,rtf\"),\nVIDEO(\"mp4,flv,mkv,webm,vob,ogv,gifv,avi,mov,wmv,mpg,m4v,m4p,mpeg,3gp\") or\nMUSIC(\"mp3,flac,ogg,tta,wma,webm\")\n "
)]
pub allowed_extensions: Vec<String>,
}
#[derive(Debug, clap::Args)]
pub struct NotRecursive {
#[clap(short = 'R', long, help = "Prevents from recursive check of folders")]
pub not_recursive: bool,
}
#[derive(Debug, clap::Args)]
pub struct ThreadNumber {
#[clap(short = 'T', long, default_value = "0", help = "Limits thread number, 0(default) will use all available threads")]
pub thread_number: usize,
}
#[cfg(target_family = "unix")]
#[derive(Debug, clap::Args)]
pub struct ExcludeOtherFilesystems {
#[clap(short = 'X', long, help = "Exclude files on other filesystems")]
pub exclude_other_filesystems: bool,
}
#[derive(Debug, clap::Args)]
pub struct FileToSave {
#[clap(short, long, value_name = "file-name", help = "Saves the results into the formatted txt file")]

View file

@ -1,6 +1,9 @@
#![allow(clippy::needless_late_init)]
use std::thread;
use clap::Parser;
use crossbeam_channel::{bounded, unbounded, Receiver, Sender};
use log::error;
use commands::Commands;
@ -8,6 +11,7 @@ use czkawka_core::bad_extensions::BadExtensions;
use czkawka_core::big_file::{BigFile, SearchMode};
use czkawka_core::broken_files::BrokenFiles;
use czkawka_core::common::{print_version_mode, set_number_of_threads, setup_logger};
use czkawka_core::common_dir_traversal::ProgressData;
use czkawka_core::common_tool::{CommonData, DeleteMethod};
#[allow(unused_imports)] // It is used in release for print_results_to_output().
use czkawka_core::common_traits::*;
@ -21,11 +25,13 @@ use czkawka_core::similar_videos::SimilarVideos;
use czkawka_core::temporary::Temporary;
use crate::commands::{
Args, BadExtensionsArgs, BiggestFilesArgs, BrokenFilesArgs, DuplicatesArgs, EmptyFilesArgs, EmptyFoldersArgs, InvalidSymlinksArgs, SameMusicArgs, SimilarImagesArgs,
SimilarVideosArgs, TemporaryArgs,
Args, BadExtensionsArgs, BiggestFilesArgs, BrokenFilesArgs, CommonCliItems, DuplicatesArgs, EmptyFilesArgs, EmptyFoldersArgs, InvalidSymlinksArgs, SameMusicArgs,
SimilarImagesArgs, SimilarVideosArgs, TemporaryArgs,
};
use crate::progress::connect_progress;
mod commands;
mod progress;
fn main() {
let command = Args::parse().command;
@ -37,146 +43,95 @@ fn main() {
println!("{command:?}");
}
match command {
Commands::Duplicates(duplicates_args) => duplicates(duplicates_args),
Commands::EmptyFolders(empty_folders_args) => empty_folders(empty_folders_args),
Commands::BiggestFiles(biggest_files_args) => biggest_files(biggest_files_args),
Commands::EmptyFiles(empty_files_args) => empty_files(empty_files_args),
Commands::Temporary(temporary_args) => temporary(temporary_args),
Commands::SimilarImages(similar_images_args) => similar_images(similar_images_args),
Commands::SameMusic(same_music_args) => same_music(same_music_args),
Commands::InvalidSymlinks(invalid_symlinks_args) => invalid_symlinks(invalid_symlinks_args),
Commands::BrokenFiles(broken_files_args) => broken_files(broken_files_args),
Commands::SimilarVideos(similar_videos_args) => similar_videos(similar_videos_args),
Commands::BadExtensions(bad_extensions_args) => bad_extensions(bad_extensions_args),
let (progress_sender, progress_receiver): (Sender<ProgressData>, Receiver<ProgressData>) = unbounded();
let (stop_sender, stop_receiver): (Sender<()>, Receiver<()>) = bounded(1);
let calculate_thread = thread::spawn(move || match command {
Commands::Duplicates(duplicates_args) => duplicates(duplicates_args, &stop_receiver, &progress_sender),
Commands::EmptyFolders(empty_folders_args) => empty_folders(empty_folders_args, &stop_receiver, &progress_sender),
Commands::BiggestFiles(biggest_files_args) => biggest_files(biggest_files_args, &stop_receiver, &progress_sender),
Commands::EmptyFiles(empty_files_args) => empty_files(empty_files_args, &stop_receiver, &progress_sender),
Commands::Temporary(temporary_args) => temporary(temporary_args, &stop_receiver, &progress_sender),
Commands::SimilarImages(similar_images_args) => similar_images(similar_images_args, &stop_receiver, &progress_sender),
Commands::SameMusic(same_music_args) => same_music(same_music_args, &stop_receiver, &progress_sender),
Commands::InvalidSymlinks(invalid_symlinks_args) => invalid_symlinks(invalid_symlinks_args, &stop_receiver, &progress_sender),
Commands::BrokenFiles(broken_files_args) => broken_files(broken_files_args, &stop_receiver, &progress_sender),
Commands::SimilarVideos(similar_videos_args) => similar_videos(similar_videos_args, &stop_receiver, &progress_sender),
Commands::BadExtensions(bad_extensions_args) => bad_extensions(bad_extensions_args, &stop_receiver, &progress_sender),
Commands::Tester {} => {
test_image_conversion_speed();
}
}
});
ctrlc::set_handler(move || {
println!("Get Sender");
stop_sender.send(()).expect("Could not send signal on channel.");
})
.expect("Error setting Ctrl-C handler");
connect_progress(&progress_receiver);
calculate_thread.join().unwrap();
}
fn duplicates(duplicates: DuplicatesArgs) {
fn duplicates(duplicates: DuplicatesArgs, stop_receiver: &Receiver<()>, progress_sender: &Sender<ProgressData>) {
let DuplicatesArgs {
thread_number,
directories,
excluded_directories,
excluded_items,
common_cli_items,
minimal_file_size,
maximal_file_size,
minimal_cached_file_size,
allowed_extensions,
search_method,
delete_method,
hash_type,
file_to_save,
json_compact_file_to_save,
json_pretty_file_to_save,
not_recursive,
#[cfg(target_family = "unix")]
exclude_other_filesystems,
allow_hard_links,
dry_run,
case_sensitive_name_comparison,
} = duplicates;
set_number_of_threads(thread_number.thread_number);
let mut item = DuplicateFinder::new();
item.set_included_directory(directories.directories);
item.set_excluded_directory(excluded_directories.excluded_directories);
item.set_excluded_items(excluded_items.excluded_items);
set_common_settings(&mut item, &common_cli_items);
item.set_minimal_file_size(minimal_file_size);
item.set_maximal_file_size(maximal_file_size);
item.set_minimal_cache_file_size(minimal_cached_file_size);
item.set_allowed_extensions(allowed_extensions.allowed_extensions.join(","));
item.set_check_method(search_method);
item.set_delete_method(delete_method.delete_method);
item.set_hash_type(hash_type);
item.set_recursive_search(!not_recursive.not_recursive);
#[cfg(target_family = "unix")]
item.set_exclude_other_filesystems(exclude_other_filesystems.exclude_other_filesystems);
item.set_ignore_hard_links(!allow_hard_links.allow_hard_links);
item.set_dry_run(dry_run.dry_run);
item.set_case_sensitive_name_comparison(case_sensitive_name_comparison.case_sensitive_name_comparison);
item.find_duplicates(None, None);
item.find_duplicates(Some(stop_receiver), Some(progress_sender));
save_results_to_files(file_to_save.file_name(), json_compact_file_to_save.file_name(), json_pretty_file_to_save.file_name(), &item);
if !cfg!(debug_assertions) {
item.print_results_to_output();
}
item.get_text_messages().print_messages();
save_and_print_results(&mut item, &common_cli_items);
}
fn empty_folders(empty_folders: EmptyFoldersArgs) {
let EmptyFoldersArgs {
thread_number,
directories,
delete_folders,
file_to_save,
json_compact_file_to_save,
json_pretty_file_to_save,
excluded_directories,
excluded_items,
#[cfg(target_family = "unix")]
exclude_other_filesystems,
} = empty_folders;
set_number_of_threads(thread_number.thread_number);
fn empty_folders(empty_folders: EmptyFoldersArgs, stop_receiver: &Receiver<()>, progress_sender: &Sender<ProgressData>) {
let EmptyFoldersArgs { common_cli_items, delete_folders } = empty_folders;
let mut item = EmptyFolder::new();
item.set_included_directory(directories.directories);
item.set_excluded_directory(excluded_directories.excluded_directories);
item.set_excluded_items(excluded_items.excluded_items);
set_common_settings(&mut item, &common_cli_items);
if delete_folders {
item.set_delete_method(DeleteMethod::Delete);
}
#[cfg(target_family = "unix")]
item.set_exclude_other_filesystems(exclude_other_filesystems.exclude_other_filesystems);
item.find_empty_folders(None, None);
item.find_empty_folders(Some(stop_receiver), Some(progress_sender));
save_results_to_files(file_to_save.file_name(), json_compact_file_to_save.file_name(), json_pretty_file_to_save.file_name(), &item);
if !cfg!(debug_assertions) {
item.print_results_to_output();
}
item.get_text_messages().print_messages();
save_and_print_results(&mut item, &common_cli_items);
}
fn biggest_files(biggest_files: BiggestFilesArgs) {
fn biggest_files(biggest_files: BiggestFilesArgs, stop_receiver: &Receiver<()>, progress_sender: &Sender<ProgressData>) {
let BiggestFilesArgs {
thread_number,
directories,
excluded_directories,
excluded_items,
allowed_extensions,
common_cli_items,
number_of_files,
file_to_save,
json_compact_file_to_save,
json_pretty_file_to_save,
not_recursive,
#[cfg(target_family = "unix")]
exclude_other_filesystems,
delete_files,
smallest_mode,
} = biggest_files;
set_number_of_threads(thread_number.thread_number);
let mut item = BigFile::new();
item.set_included_directory(directories.directories);
item.set_excluded_directory(excluded_directories.excluded_directories);
item.set_excluded_items(excluded_items.excluded_items);
item.set_allowed_extensions(allowed_extensions.allowed_extensions.join(","));
set_common_settings(&mut item, &common_cli_items);
item.set_number_of_files_to_check(number_of_files);
item.set_recursive_search(!not_recursive.not_recursive);
#[cfg(target_family = "unix")]
item.set_exclude_other_filesystems(exclude_other_filesystems.exclude_other_filesystems);
if delete_files {
item.set_delete_method(DeleteMethod::Delete);
}
@ -184,113 +139,47 @@ fn biggest_files(biggest_files: BiggestFilesArgs) {
item.set_search_mode(SearchMode::SmallestFiles);
}
item.find_big_files(None, None);
item.find_big_files(Some(stop_receiver), Some(progress_sender));
save_results_to_files(file_to_save.file_name(), json_compact_file_to_save.file_name(), json_pretty_file_to_save.file_name(), &item);
if !cfg!(debug_assertions) {
item.print_results_to_output();
}
item.get_text_messages().print_messages();
save_and_print_results(&mut item, &common_cli_items);
}
fn empty_files(empty_files: EmptyFilesArgs) {
let EmptyFilesArgs {
thread_number,
directories,
excluded_directories,
excluded_items,
allowed_extensions,
delete_files,
file_to_save,
json_compact_file_to_save,
json_pretty_file_to_save,
not_recursive,
#[cfg(target_family = "unix")]
exclude_other_filesystems,
} = empty_files;
set_number_of_threads(thread_number.thread_number);
fn empty_files(empty_files: EmptyFilesArgs, stop_receiver: &Receiver<()>, progress_sender: &Sender<ProgressData>) {
let EmptyFilesArgs { common_cli_items, delete_files } = empty_files;
let mut item = EmptyFiles::new();
item.set_included_directory(directories.directories);
item.set_excluded_directory(excluded_directories.excluded_directories);
item.set_excluded_items(excluded_items.excluded_items);
item.set_allowed_extensions(allowed_extensions.allowed_extensions.join(","));
item.set_recursive_search(!not_recursive.not_recursive);
#[cfg(target_family = "unix")]
item.set_exclude_other_filesystems(exclude_other_filesystems.exclude_other_filesystems);
set_common_settings(&mut item, &common_cli_items);
if delete_files {
item.set_delete_method(DeleteMethod::Delete);
}
item.find_empty_files(None, None);
item.find_empty_files(Some(stop_receiver), Some(progress_sender));
save_results_to_files(file_to_save.file_name(), json_compact_file_to_save.file_name(), json_pretty_file_to_save.file_name(), &item);
if !cfg!(debug_assertions) {
item.print_results_to_output();
}
item.get_text_messages().print_messages();
save_and_print_results(&mut item, &common_cli_items);
}
fn temporary(temporary: TemporaryArgs) {
let TemporaryArgs {
thread_number,
directories,
excluded_directories,
excluded_items,
#[cfg(target_family = "unix")]
exclude_other_filesystems,
delete_files,
file_to_save,
json_compact_file_to_save,
json_pretty_file_to_save,
not_recursive,
} = temporary;
set_number_of_threads(thread_number.thread_number);
fn temporary(temporary: TemporaryArgs, stop_receiver: &Receiver<()>, progress_sender: &Sender<ProgressData>) {
let TemporaryArgs { common_cli_items, delete_files } = temporary;
let mut item = Temporary::new();
item.set_included_directory(directories.directories);
item.set_excluded_directory(excluded_directories.excluded_directories);
item.set_excluded_items(excluded_items.excluded_items);
item.set_recursive_search(!not_recursive.not_recursive);
#[cfg(target_family = "unix")]
item.set_exclude_other_filesystems(exclude_other_filesystems.exclude_other_filesystems);
set_common_settings(&mut item, &common_cli_items);
if delete_files {
item.set_delete_method(DeleteMethod::Delete);
}
item.find_temporary_files(None, None);
item.find_temporary_files(Some(stop_receiver), Some(progress_sender));
save_results_to_files(file_to_save.file_name(), json_compact_file_to_save.file_name(), json_pretty_file_to_save.file_name(), &item);
if !cfg!(debug_assertions) {
item.print_results_to_output();
}
item.get_text_messages().print_messages();
save_and_print_results(&mut item, &common_cli_items);
}
fn similar_images(similar_images: SimilarImagesArgs) {
fn similar_images(similar_images: SimilarImagesArgs, stop_receiver: &Receiver<()>, progress_sender: &Sender<ProgressData>) {
let SimilarImagesArgs {
thread_number,
directories,
excluded_directories,
excluded_items,
file_to_save,
json_compact_file_to_save,
json_pretty_file_to_save,
common_cli_items,
minimal_file_size,
maximal_file_size,
similarity_preset,
not_recursive,
#[cfg(target_family = "unix")]
exclude_other_filesystems,
hash_alg,
image_filter,
hash_size,
@ -298,49 +187,27 @@ fn similar_images(similar_images: SimilarImagesArgs) {
dry_run,
} = similar_images;
set_number_of_threads(thread_number.thread_number);
let mut item = SimilarImages::new();
item.set_included_directory(directories.directories);
item.set_excluded_directory(excluded_directories.excluded_directories);
item.set_excluded_items(excluded_items.excluded_items);
set_common_settings(&mut item, &common_cli_items);
item.set_minimal_file_size(minimal_file_size);
item.set_maximal_file_size(maximal_file_size);
item.set_recursive_search(!not_recursive.not_recursive);
#[cfg(target_family = "unix")]
item.set_exclude_other_filesystems(exclude_other_filesystems.exclude_other_filesystems);
item.set_image_filter(image_filter);
item.set_hash_alg(hash_alg);
item.set_hash_size(hash_size);
item.set_delete_method(delete_method.delete_method);
item.set_dry_run(dry_run.dry_run);
item.set_similarity(return_similarity_from_similarity_preset(&similarity_preset, hash_size));
item.find_similar_images(None, None);
item.find_similar_images(Some(stop_receiver), Some(progress_sender));
save_results_to_files(file_to_save.file_name(), json_compact_file_to_save.file_name(), json_pretty_file_to_save.file_name(), &item);
if !cfg!(debug_assertions) {
item.print_results_to_output();
}
item.get_text_messages().print_messages();
save_and_print_results(&mut item, &common_cli_items);
}
fn same_music(same_music: SameMusicArgs) {
fn same_music(same_music: SameMusicArgs, stop_receiver: &Receiver<()>, progress_sender: &Sender<ProgressData>) {
let SameMusicArgs {
thread_number,
directories,
excluded_directories,
excluded_items,
common_cli_items,
delete_method,
file_to_save,
json_compact_file_to_save,
json_pretty_file_to_save,
not_recursive,
#[cfg(target_family = "unix")]
exclude_other_filesystems,
minimal_file_size,
maximal_file_size,
music_similarity,
@ -350,18 +217,11 @@ fn same_music(same_music: SameMusicArgs) {
search_method,
} = same_music;
set_number_of_threads(thread_number.thread_number);
let mut item = SameMusic::new();
item.set_included_directory(directories.directories);
item.set_excluded_directory(excluded_directories.excluded_directories);
item.set_excluded_items(excluded_items.excluded_items);
set_common_settings(&mut item, &common_cli_items);
item.set_minimal_file_size(minimal_file_size);
item.set_maximal_file_size(maximal_file_size);
item.set_recursive_search(!not_recursive.not_recursive);
#[cfg(target_family = "unix")]
item.set_exclude_other_filesystems(exclude_other_filesystems.exclude_other_filesystems);
item.set_music_similarity(music_similarity);
item.set_delete_method(delete_method.delete_method);
item.set_dry_run(dry_run.dry_run);
@ -369,197 +229,111 @@ fn same_music(same_music: SameMusicArgs) {
item.set_maximum_difference(maximum_difference);
item.set_check_type(search_method);
item.find_same_music(None, None);
item.find_same_music(Some(stop_receiver), Some(progress_sender));
save_results_to_files(file_to_save.file_name(), json_compact_file_to_save.file_name(), json_pretty_file_to_save.file_name(), &item);
if !cfg!(debug_assertions) {
item.print_results_to_output();
}
item.get_text_messages().print_messages();
save_and_print_results(&mut item, &common_cli_items);
}
fn invalid_symlinks(invalid_symlinks: InvalidSymlinksArgs) {
let InvalidSymlinksArgs {
thread_number,
directories,
excluded_directories,
excluded_items,
allowed_extensions,
file_to_save,
json_compact_file_to_save,
json_pretty_file_to_save,
not_recursive,
#[cfg(target_family = "unix")]
exclude_other_filesystems,
delete_files,
} = invalid_symlinks;
set_number_of_threads(thread_number.thread_number);
fn invalid_symlinks(invalid_symlinks: InvalidSymlinksArgs, stop_receiver: &Receiver<()>, progress_sender: &Sender<ProgressData>) {
let InvalidSymlinksArgs { common_cli_items, delete_files } = invalid_symlinks;
let mut item = InvalidSymlinks::new();
item.set_included_directory(directories.directories);
item.set_excluded_directory(excluded_directories.excluded_directories);
item.set_excluded_items(excluded_items.excluded_items);
item.set_allowed_extensions(allowed_extensions.allowed_extensions.join(","));
item.set_recursive_search(!not_recursive.not_recursive);
#[cfg(target_family = "unix")]
item.set_exclude_other_filesystems(exclude_other_filesystems.exclude_other_filesystems);
set_common_settings(&mut item, &common_cli_items);
if delete_files {
item.set_delete_method(DeleteMethod::Delete);
}
item.find_invalid_links(None, None);
item.find_invalid_links(Some(stop_receiver), Some(progress_sender));
save_results_to_files(file_to_save.file_name(), json_compact_file_to_save.file_name(), json_pretty_file_to_save.file_name(), &item);
if !cfg!(debug_assertions) {
item.print_results_to_output();
}
item.get_text_messages().print_messages();
save_and_print_results(&mut item, &common_cli_items);
}
fn broken_files(broken_files: BrokenFilesArgs) {
let BrokenFilesArgs {
thread_number,
directories,
excluded_directories,
excluded_items,
allowed_extensions,
delete_files,
file_to_save,
json_compact_file_to_save,
json_pretty_file_to_save,
not_recursive,
#[cfg(target_family = "unix")]
exclude_other_filesystems,
} = broken_files;
set_number_of_threads(thread_number.thread_number);
fn broken_files(broken_files: BrokenFilesArgs, stop_receiver: &Receiver<()>, progress_sender: &Sender<ProgressData>) {
let BrokenFilesArgs { common_cli_items, delete_files } = broken_files;
let mut item = BrokenFiles::new();
item.set_included_directory(directories.directories);
item.set_excluded_directory(excluded_directories.excluded_directories);
item.set_excluded_items(excluded_items.excluded_items);
item.set_allowed_extensions(allowed_extensions.allowed_extensions.join(","));
item.set_recursive_search(!not_recursive.not_recursive);
#[cfg(target_family = "unix")]
item.set_exclude_other_filesystems(exclude_other_filesystems.exclude_other_filesystems);
set_common_settings(&mut item, &common_cli_items);
if delete_files {
item.set_delete_method(DeleteMethod::Delete);
}
item.find_broken_files(None, None);
item.find_broken_files(Some(stop_receiver), Some(progress_sender));
save_results_to_files(file_to_save.file_name(), json_compact_file_to_save.file_name(), json_pretty_file_to_save.file_name(), &item);
if !cfg!(debug_assertions) {
item.print_results_to_output();
}
item.get_text_messages().print_messages();
save_and_print_results(&mut item, &common_cli_items);
}
fn similar_videos(similar_videos: SimilarVideosArgs) {
fn similar_videos(similar_videos: SimilarVideosArgs, stop_receiver: &Receiver<()>, progress_sender: &Sender<ProgressData>) {
let SimilarVideosArgs {
thread_number,
directories,
excluded_directories,
excluded_items,
file_to_save,
json_compact_file_to_save,
json_pretty_file_to_save,
not_recursive,
#[cfg(target_family = "unix")]
exclude_other_filesystems,
common_cli_items,
tolerance,
minimal_file_size,
maximal_file_size,
allowed_extensions,
delete_method,
dry_run,
} = similar_videos;
set_number_of_threads(thread_number.thread_number);
let mut item = SimilarVideos::new();
item.set_included_directory(directories.directories);
item.set_excluded_directory(excluded_directories.excluded_directories);
item.set_excluded_items(excluded_items.excluded_items);
item.set_allowed_extensions(allowed_extensions.allowed_extensions.join(","));
item.set_recursive_search(!not_recursive.not_recursive);
#[cfg(target_family = "unix")]
item.set_exclude_other_filesystems(exclude_other_filesystems.exclude_other_filesystems);
set_common_settings(&mut item, &common_cli_items);
item.set_minimal_file_size(minimal_file_size);
item.set_maximal_file_size(maximal_file_size);
item.set_tolerance(tolerance);
item.set_delete_method(delete_method.delete_method);
item.set_dry_run(dry_run.dry_run);
item.find_similar_videos(None, None);
item.find_similar_videos(Some(stop_receiver), Some(progress_sender));
save_results_to_files(file_to_save.file_name(), json_compact_file_to_save.file_name(), json_pretty_file_to_save.file_name(), &item);
if !cfg!(debug_assertions) {
item.print_results_to_output();
}
item.get_text_messages().print_messages();
save_and_print_results(&mut item, &common_cli_items);
}
fn bad_extensions(bad_extensions: BadExtensionsArgs) {
let BadExtensionsArgs {
thread_number,
directories,
excluded_directories,
excluded_items,
file_to_save,
json_compact_file_to_save,
json_pretty_file_to_save,
not_recursive,
#[cfg(target_family = "unix")]
exclude_other_filesystems,
allowed_extensions,
} = bad_extensions;
set_number_of_threads(thread_number.thread_number);
fn bad_extensions(bad_extensions: BadExtensionsArgs, stop_receiver: &Receiver<()>, progress_sender: &Sender<ProgressData>) {
let BadExtensionsArgs { common_cli_items } = bad_extensions;
let mut item = BadExtensions::new();
item.set_included_directory(directories.directories);
item.set_excluded_directory(excluded_directories.excluded_directories);
item.set_excluded_items(excluded_items.excluded_items);
item.set_allowed_extensions(allowed_extensions.allowed_extensions.join(","));
item.set_recursive_search(!not_recursive.not_recursive);
#[cfg(target_family = "unix")]
item.set_exclude_other_filesystems(exclude_other_filesystems.exclude_other_filesystems);
set_common_settings(&mut item, &common_cli_items);
item.find_bad_extensions_files(None, None);
item.find_bad_extensions_files(Some(stop_receiver), Some(progress_sender));
save_results_to_files(file_to_save.file_name(), json_compact_file_to_save.file_name(), json_pretty_file_to_save.file_name(), &item);
if !cfg!(debug_assertions) {
item.print_results_to_output();
}
item.get_text_messages().print_messages();
save_and_print_results(&mut item, &common_cli_items);
}
fn save_results_to_files<T: PrintResults>(txt_file_name: Option<&str>, compact_json_file_name: Option<&str>, pretty_json_file_name: Option<&str>, item: &T) {
if let Some(file_name) = txt_file_name {
if let Err(e) = item.print_results_to_file(file_name) {
fn save_and_print_results<T: CommonData + PrintResults>(component: &mut T, common_cli_items: &CommonCliItems) {
if let Some(file_name) = common_cli_items.file_to_save.file_name() {
if let Err(e) = component.print_results_to_file(file_name) {
error!("Failed to save results to file {e}");
}
}
if let Some(file_name) = compact_json_file_name {
if let Err(e) = item.save_results_to_file_as_json(file_name, false) {
if let Some(file_name) = common_cli_items.json_compact_file_to_save.file_name() {
if let Err(e) = component.save_results_to_file_as_json(file_name, false) {
error!("Failed to save compact json results to file {e}");
}
}
if let Some(file_name) = pretty_json_file_name {
if let Err(e) = item.save_results_to_file_as_json(file_name, true) {
if let Some(file_name) = common_cli_items.json_pretty_file_to_save.file_name() {
if let Err(e) = component.save_results_to_file_as_json(file_name, true) {
error!("Failed to save pretty json results to file {e}");
}
}
if !cfg!(debug_assertions) {
component.print_results_to_output();
}
component.get_text_messages().print_messages();
}
fn set_common_settings<T>(component: &mut T, common_cli_items: &CommonCliItems)
where
T: CommonData + PrintResults,
{
set_number_of_threads(common_cli_items.thread_number);
component.set_included_directory(common_cli_items.directories.clone());
component.set_excluded_directory(common_cli_items.excluded_directories.clone());
component.set_excluded_items(common_cli_items.excluded_items.clone());
component.set_recursive_search(!common_cli_items.not_recursive);
#[cfg(target_family = "unix")]
component.set_exclude_other_filesystems(common_cli_items.exclude_other_filesystems);
component.set_allowed_extensions(common_cli_items.allowed_extensions.clone().join(","));
}

View file

@ -0,0 +1,93 @@
use std::time::Duration;
use crossbeam_channel::Receiver;
use indicatif::{ProgressBar, ProgressStyle};
use czkawka_core::common_dir_traversal::{CheckingMethod, ProgressData, ToolType};
pub fn connect_progress(progress_receiver: &Receiver<ProgressData>) {
let mut pb = ProgressBar::new(1);
let mut latest_id = None;
while let Ok(progress_data) = progress_receiver.recv() {
if latest_id != Some(progress_data.current_stage) {
pb.finish_and_clear();
if progress_data.current_stage == 0 {
pb = get_progress_bar_for_collect_files();
} else if check_if_saving_cache(&progress_data) || check_if_loading_cache(&progress_data) {
pb = get_progress_loading_saving_cache(check_if_loading_cache(&progress_data));
} else {
pb = get_progress_known_values(progress_data.entries_to_check, &get_progress_message(&progress_data));
}
latest_id = Some(progress_data.current_stage);
}
pb.set_position(progress_data.entries_checked as u64);
if progress_data.current_stage == 0 && progress_data.tool_type != ToolType::EmptyFolders {
pb.set_message(format!("Collecting files: {}", progress_data.entries_checked));
} else if progress_data.current_stage == 0 {
pb.set_message(format!("Collecting folders: {}", progress_data.entries_checked));
}
}
pb.finish();
}
pub fn get_progress_message(progress_data: &ProgressData) -> String {
match (progress_data.tool_type, progress_data.current_stage, progress_data.checking_method) {
(ToolType::SameMusic, 2, CheckingMethod::AudioTags) | (ToolType::SameMusic, 5, CheckingMethod::AudioContent) => "Reading tags",
(ToolType::SameMusic, 2, CheckingMethod::AudioContent) => "Calculating fingerprint",
(ToolType::SameMusic, 4, CheckingMethod::AudioTags) => "Comparing tags",
(ToolType::SameMusic, 4, CheckingMethod::AudioContent) => "Comparing fingerprint",
(ToolType::Duplicate, 2, CheckingMethod::Hash) => "Reading prehashes",
(ToolType::Duplicate, 5, CheckingMethod::Hash) => "Reading hashes",
(ToolType::SimilarImages, 1, _) => "Reading images",
(ToolType::SimilarImages, 2, _) => "Comparing image hashes",
(ToolType::SimilarVideos, 1, _) => "Reading similar values",
(ToolType::BrokenFiles, 1, _) => "Checking broken files",
(ToolType::BadExtensions, 1, _) => "Checking extensions of files",
_ => unreachable!(),
}
.to_string()
}
pub fn check_if_loading_cache(progress_data: &ProgressData) -> bool {
matches!(
(progress_data.tool_type, progress_data.current_stage),
(ToolType::SameMusic, 1) | (ToolType::Duplicate, 1 | 4)
)
}
pub fn check_if_saving_cache(progress_data: &ProgressData) -> bool {
matches!(
(progress_data.tool_type, progress_data.current_stage),
(ToolType::SameMusic, 3) | (ToolType::Duplicate, 3 | 6)
)
}
pub fn get_progress_bar_for_collect_files() -> ProgressBar {
let pb = ProgressBar::new_spinner();
pb.enable_steady_tick(Duration::from_millis(120));
pb.set_style(
ProgressStyle::with_template("{msg} {spinner:.blue}")
.unwrap()
.tick_strings(&["▹▹▹▹▹", "▸▹▹▹▹", "▹▸▹▹▹", "▹▹▸▹▹", "▹▹▹▸▹", "▹▹▹▹▸", "▪▪▪▪▪"]),
);
pb
}
pub fn get_progress_known_values(max_value: usize, msg: &str) -> ProgressBar {
let pb = ProgressBar::new(max_value as u64);
pb.set_style(ProgressStyle::with_template(&format!("{msg} [{{bar}}] {{pos}}/{{len}} ")).unwrap().progress_chars("=> "));
pb
}
pub fn get_progress_loading_saving_cache(loading: bool) -> ProgressBar {
let msg = if loading { "Loading cache" } else { "Saving cache" };
let pb = ProgressBar::new_spinner();
pb.enable_steady_tick(Duration::from_millis(120));
pb.set_style(
ProgressStyle::with_template(&format!("{msg} {{spinner:.blue}}"))
.unwrap()
.tick_strings(&["▹▹▹▹▹", "▸▹▹▹▹", "▹▸▹▹▹", "▹▹▸▹▹", "▹▹▹▸▹", "▹▹▹▹▸", "▪▪▪▪▪"]),
);
pb
}

View file

@ -156,17 +156,17 @@ impl BrokenFiles {
match result {
DirTraversalResult::SuccessFiles { grouped_file_entries, warnings } => {
self.broken_files = grouped_file_entries
self.files_to_check = grouped_file_entries
.into_values()
.flatten()
.map(|fe| {
let mut broken_entry = fe.into_broken_entry();
broken_entry.type_of_file = check_extension_availability(broken_entry.get_path(), &images_extensions, &zip_extensions, &audio_extensions, &pdf_extensions);
broken_entry
(broken_entry.path.to_string_lossy().to_string(), broken_entry)
})
.collect();
self.common_data.text_messages.warnings.extend(warnings);
debug!("check_files - Found {} image files.", self.broken_files.len());
debug!("check_files - Found {} files to check.", self.files_to_check.len());
true
}
@ -451,16 +451,18 @@ fn check_extension_availability(
debug_assert!(false, "Extension not really fully str");
return TypeOfFile::Unknown;
};
let extension_lowercase = extension_str.to_ascii_lowercase();
if images_extensions.contains(&extension_str) {
if images_extensions.contains(&extension_lowercase.as_str()) {
TypeOfFile::Image
} else if zip_extensions.contains(&extension_str) {
} else if zip_extensions.contains(&extension_lowercase.as_str()) {
TypeOfFile::ArchiveZip
} else if audio_extensions.contains(&extension_str) {
} else if audio_extensions.contains(&extension_lowercase.as_str()) {
TypeOfFile::Audio
} else if pdf_extensions.contains(&extension_str) {
} else if pdf_extensions.contains(&extension_lowercase.as_str()) {
TypeOfFile::PDF
} else {
eprintln!("File with unknown extension: {full_name:?} - {extension_lowercase}");
debug_assert!(false, "File with unknown extension");
TypeOfFile::Unknown
}

View file

@ -562,7 +562,8 @@ pub fn prepare_thread_handler_common(
let progress_thread_run = progress_thread_run.clone();
let atomic_counter = atomic_counter.clone();
thread::spawn(move || {
let mut time_since_last_send = SystemTime::now();
// Use earlier time, to send immediately first message
let mut time_since_last_send = SystemTime::now() - Duration::from_secs(10u64);
loop {
if time_since_last_send.elapsed().unwrap().as_millis() > SEND_PROGRESS_DATA_TIME_BETWEEN as u128 {

View file

@ -268,7 +268,7 @@ impl DuplicateFinder {
.group_by(group_by_func)
.stop_receiver(stop_receiver)
.progress_sender(progress_sender)
.checking_method(CheckingMethod::Name)
.checking_method(CheckingMethod::SizeName)
.build()
.run();

View file

@ -193,6 +193,7 @@ impl SameMusic {
.stop_receiver(stop_receiver)
.progress_sender(progress_sender)
.common_data(&self.common_data)
.checking_method(self.check_type)
.max_stage(max_stage)
.build()
.run();

View file

@ -19,6 +19,58 @@ use crate::localizer_core::generate_translation_hashmap;
use crate::taskbar_progress::tbp_flags::TBPF_INDETERMINATE;
use crate::taskbar_progress::TaskbarProgress;
// Empty files
// 0 - Collecting files
// Empty folders
// 0 - Collecting folders
// Big files
// 0 - Collecting files
// Same music
// 0 - Collecting files
// 1 - Loading cache
// 2 - Checking tags / content
// 3 - Saving cache
// 4 - Checking tags / content - progress
// 5 - Only content - ending
// Similar images
// 0 - Collecting files
// 1 - Scanning images
// 2 - Comparing hashes
// Similar videos
// 0 - Collecting files
// 1 - Scanning videos
// Temporary files
// 0 - Collecting files
// Invalid symlinks
// 0 - Collecting files
// Broken files
// 0 - Collecting files
// 1 - Scanning files
// Bad extensions
// 0 - Collecting files
// 1 - Scanning files
// Duplicates - Hash
// 0 - Collecting files
// 1 - Loading cache
// 2 - Hash - first 1KB file
// 3 - Saving cache
// 4 - Loading cache
// 5 - Hash - normal hash
// 6 - Saving cache
// Duplicates - Name or SizeName or Size
// 0 - Collecting files
#[allow(clippy::too_many_arguments)]
pub fn connect_progress_window(gui_data: &GuiData, progress_receiver: Receiver<ProgressData>) {
let main_context = MainContext::default();
@ -31,19 +83,12 @@ pub fn connect_progress_window(gui_data: &GuiData, progress_receiver: Receiver<P
loop {
let item = progress_receiver.try_recv();
if let Ok(item) = item {
match item.tool_type {
ToolType::Duplicate => process_bar_duplicates(&gui_data, &item),
ToolType::EmptyFiles => process_bar_empty_files(&gui_data, &item),
ToolType::EmptyFolders => process_bar_empty_folder(&gui_data, &item),
ToolType::BigFile => process_bar_big_files(&gui_data, &item),
ToolType::SameMusic => process_bar_same_music(&gui_data, &item),
ToolType::SimilarImages => process_bar_similar_images(&gui_data, &item),
ToolType::SimilarVideos => process_bar_similar_videos(&gui_data, &item),
ToolType::TemporaryFiles => process_bar_temporary(&gui_data, &item),
ToolType::InvalidSymlinks => process_bar_invalid_symlinks(&gui_data, &item),
ToolType::BrokenFiles => process_bar_broken_files(&gui_data, &item),
ToolType::BadExtensions => process_bar_bad_extensions(&gui_data, &item),
ToolType::None => panic!(),
if item.current_stage == 0 {
progress_collect_items(&gui_data, &item, item.tool_type != ToolType::EmptyFolders);
} else if check_if_loading_saving_cache(&item) {
progress_save_load_cache(&gui_data, &item);
} else {
progress_default(&gui_data, &item);
}
} else {
break;
@ -55,278 +100,123 @@ pub fn connect_progress_window(gui_data: &GuiData, progress_receiver: Receiver<P
main_context.spawn_local(future);
}
fn process_bar_empty_files(gui_data: &GuiData, item: &ProgressData) {
pub fn check_if_loading_saving_cache(progress_data: &ProgressData) -> bool {
matches!(
(progress_data.tool_type, progress_data.current_stage),
(ToolType::SameMusic, 1 | 3) | (ToolType::Duplicate, 1 | 3 | 4 | 6)
)
}
fn progress_save_load_cache(gui_data: &GuiData, item: &ProgressData) {
let label_stage = gui_data.progress_window.label_stage.clone();
let progress_bar_current_stage = gui_data.progress_window.progress_bar_current_stage.clone();
let taskbar_state = gui_data.taskbar_state.clone();
label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(item)));
progress_bar_current_stage.hide();
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
fn process_bar_empty_folder(gui_data: &GuiData, item: &ProgressData) {
let label_stage = gui_data.progress_window.label_stage.clone();
let taskbar_state = gui_data.taskbar_state.clone();
label_stage.set_text(&flg!(
"progress_scanning_empty_folders",
generate_translation_hashmap(vec![("folder_number", item.entries_checked.to_string())])
));
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
fn process_bar_big_files(gui_data: &GuiData, item: &ProgressData) {
let label_stage = gui_data.progress_window.label_stage.clone();
let taskbar_state = gui_data.taskbar_state.clone();
label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(item)));
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
fn process_bar_same_music(gui_data: &GuiData, item: &ProgressData) {
let label_stage = gui_data.progress_window.label_stage.clone();
let progress_bar_current_stage = gui_data.progress_window.progress_bar_current_stage.clone();
let progress_bar_all_stages = gui_data.progress_window.progress_bar_all_stages.clone();
let taskbar_state = gui_data.taskbar_state.clone();
match item.current_stage {
0 => {
progress_bar_current_stage.hide();
label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(item)));
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
let text = match (item.tool_type, item.checking_method, item.current_stage) {
(ToolType::SameMusic, CheckingMethod::AudioTags | CheckingMethod::AudioContent, 1) => {
flg!("progress_cache_loading")
}
// Loading cache
1 => {
progress_bar_current_stage.hide();
common_set_data(item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state);
label_stage.set_text(&flg!("progress_cache_loading"));
(ToolType::SameMusic, CheckingMethod::AudioTags | CheckingMethod::AudioContent, 3) => {
flg!("progress_cache_saving")
}
2 => {
progress_bar_current_stage.show();
common_set_data(item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state);
match item.checking_method {
CheckingMethod::AudioTags => label_stage.set_text(&flg!("progress_scanning_music_tags", progress_ratio_tm(item))),
CheckingMethod::AudioContent => label_stage.set_text(&flg!("progress_scanning_music_content", progress_ratio_tm(item))),
_ => panic!(),
}
(ToolType::Duplicate, CheckingMethod::Hash, 1) => {
flg!("progress_prehash_cache_loading")
}
// Saving cache
3 => {
progress_bar_current_stage.hide();
common_set_data(item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state);
label_stage.set_text(&flg!("progress_cache_saving"));
(ToolType::Duplicate, CheckingMethod::Hash, 3) => {
flg!("progress_prehash_cache_saving")
}
4 => {
progress_bar_current_stage.show();
common_set_data(item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state);
match item.checking_method {
CheckingMethod::AudioTags => label_stage.set_text(&flg!("progress_scanning_music_tags_end", progress_ratio_tm(item))),
CheckingMethod::AudioContent => label_stage.set_text(&flg!("progress_scanning_music_content_end", progress_ratio_tm(item))),
_ => panic!(),
}
(ToolType::Duplicate, CheckingMethod::Hash, 4) => {
flg!("progress_hash_cache_loading")
}
5 => {
progress_bar_current_stage.show();
common_set_data(item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state);
if item.checking_method == CheckingMethod::AudioContent {
label_stage.set_text(&flg!("progress_scanning_music_tags", progress_ratio_tm(item)));
} else {
panic!();
}
}
_ => panic!(),
}
}
fn process_bar_similar_images(gui_data: &GuiData, item: &ProgressData) {
let label_stage = gui_data.progress_window.label_stage.clone();
let progress_bar_current_stage = gui_data.progress_window.progress_bar_current_stage.clone();
let progress_bar_all_stages = gui_data.progress_window.progress_bar_all_stages.clone();
let taskbar_state = gui_data.taskbar_state.clone();
match item.current_stage {
0 => {
progress_bar_current_stage.hide();
label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(item)));
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
1 => {
progress_bar_current_stage.show();
common_set_data(item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state);
label_stage.set_text(&flg!("progress_scanning_image", progress_ratio_tm(item)));
}
2 => {
progress_bar_current_stage.show();
common_set_data(item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state);
label_stage.set_text(&flg!("progress_comparing_image_hashes", progress_ratio_tm(item)));
}
_ => panic!(),
}
}
fn process_bar_similar_videos(gui_data: &GuiData, item: &ProgressData) {
let label_stage = gui_data.progress_window.label_stage.clone();
let progress_bar_current_stage = gui_data.progress_window.progress_bar_current_stage.clone();
let progress_bar_all_stages = gui_data.progress_window.progress_bar_all_stages.clone();
let taskbar_state = gui_data.taskbar_state.clone();
match item.current_stage {
0 => {
progress_bar_current_stage.hide();
label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(item)));
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
1 => {
progress_bar_current_stage.show();
common_set_data(item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state);
label_stage.set_text(&flg!("progress_scanning_video", progress_ratio_tm(item)));
}
_ => panic!(),
}
}
fn process_bar_temporary(gui_data: &GuiData, item: &ProgressData) {
let label_stage = gui_data.progress_window.label_stage.clone();
let taskbar_state = gui_data.taskbar_state.clone();
label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(item)));
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
fn process_bar_invalid_symlinks(gui_data: &GuiData, item: &ProgressData) {
let label_stage = gui_data.progress_window.label_stage.clone();
let taskbar_state = gui_data.taskbar_state.clone();
label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(item)));
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
fn process_bar_broken_files(gui_data: &GuiData, item: &ProgressData) {
let label_stage = gui_data.progress_window.label_stage.clone();
let progress_bar_current_stage = gui_data.progress_window.progress_bar_current_stage.clone();
let progress_bar_all_stages = gui_data.progress_window.progress_bar_all_stages.clone();
let taskbar_state = gui_data.taskbar_state.clone();
match item.current_stage {
0 => {
progress_bar_current_stage.hide();
label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(item)));
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
1 => {
progress_bar_current_stage.show();
common_set_data(item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state);
label_stage.set_text(&flg!("progress_scanning_broken_files", progress_ratio_tm(item)));
}
_ => panic!(),
}
}
fn process_bar_bad_extensions(gui_data: &GuiData, item: &ProgressData) {
let label_stage = gui_data.progress_window.label_stage.clone();
let progress_bar_current_stage = gui_data.progress_window.progress_bar_current_stage.clone();
let progress_bar_all_stages = gui_data.progress_window.progress_bar_all_stages.clone();
let taskbar_state = gui_data.taskbar_state.clone();
match item.current_stage {
0 => {
progress_bar_current_stage.hide();
label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(item)));
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
1 => {
progress_bar_current_stage.show();
common_set_data(item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state);
label_stage.set_text(&flg!("progress_scanning_extension_of_files", progress_ratio_tm(item)));
}
_ => panic!(),
}
}
fn process_bar_duplicates(gui_data: &GuiData, item: &ProgressData) {
let label_stage = gui_data.progress_window.label_stage.clone();
let progress_bar_current_stage = gui_data.progress_window.progress_bar_current_stage.clone();
let progress_bar_all_stages = gui_data.progress_window.progress_bar_all_stages.clone();
let grid_progress_stages = gui_data.progress_window.grid_progress_stages.clone();
let taskbar_state = gui_data.taskbar_state.clone();
match item.checking_method {
CheckingMethod::Hash => {
label_stage.show();
match item.current_stage {
// Checking Size
0 => {
progress_bar_current_stage.hide();
progress_bar_all_stages.set_fraction(0f64);
label_stage.set_text(&flg!("progress_scanning_size", file_number_tm(item)));
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
// Loading cache
1 | 4 => {
progress_bar_current_stage.hide();
common_set_data(item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state);
if item.current_stage == 1 {
label_stage.set_text(&flg!("progress_prehash_cache_loading"));
} else {
label_stage.set_text(&flg!("progress_hash_cache_loading"));
}
}
// Saving cache
3 | 6 => {
progress_bar_current_stage.hide();
common_set_data(item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state);
if item.current_stage == 3 {
label_stage.set_text(&flg!("progress_prehash_cache_saving"));
} else {
label_stage.set_text(&flg!("progress_hash_cache_saving"));
}
}
// Hash - first 1KB file
2 => {
progress_bar_current_stage.show();
common_set_data(item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state);
label_stage.set_text(&flg!("progress_analyzed_partial_hash", progress_ratio_tm(item)));
}
// Hash - normal hash
5 => {
progress_bar_current_stage.show();
common_set_data(item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state);
label_stage.set_text(&flg!("progress_analyzed_full_hash", progress_ratio_tm(item)));
}
_ => {
panic!("Not available current_stage");
}
}
}
CheckingMethod::Name => {
label_stage.show();
grid_progress_stages.hide();
label_stage.set_text(&flg!("progress_scanning_name", file_number_tm(item)));
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
CheckingMethod::SizeName => {
label_stage.show();
grid_progress_stages.hide();
label_stage.set_text(&flg!("progress_scanning_size_name", file_number_tm(item)));
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
CheckingMethod::Size => {
label_stage.show();
grid_progress_stages.hide();
label_stage.set_text(&flg!("progress_scanning_size", file_number_tm(item)));
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
(ToolType::Duplicate, CheckingMethod::Hash, 6) => {
flg!("progress_hash_cache_saving")
}
_ => panic!(),
};
label_stage.set_text(&text);
}
fn progress_collect_items(gui_data: &GuiData, item: &ProgressData, files: bool) {
let label_stage = gui_data.progress_window.label_stage.clone();
let progress_bar_current_stage = gui_data.progress_window.progress_bar_current_stage.clone();
let taskbar_state = gui_data.taskbar_state.clone();
progress_bar_current_stage.hide();
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
match (item.tool_type, item.checking_method) {
(ToolType::Duplicate, CheckingMethod::Name) => {
label_stage.set_text(&flg!("progress_scanning_name", file_number_tm(item)));
return;
}
(ToolType::Duplicate, CheckingMethod::SizeName) => {
label_stage.set_text(&flg!("progress_scanning_size_name", file_number_tm(item)));
return;
}
(ToolType::Duplicate, CheckingMethod::Size | CheckingMethod::Hash) => {
label_stage.set_text(&flg!("progress_scanning_size", file_number_tm(item)));
return;
}
_ => {}
}
if files {
label_stage.set_text(&flg!("progress_scanning_general_file", file_number_tm(item)));
} else {
label_stage.set_text(&flg!(
"progress_scanning_empty_folders",
generate_translation_hashmap(vec![("folder_number", item.entries_checked.to_string())])
));
}
}
fn progress_default(gui_data: &GuiData, item: &ProgressData) {
let label_stage = gui_data.progress_window.label_stage.clone();
let progress_bar_current_stage = gui_data.progress_window.progress_bar_current_stage.clone();
let progress_bar_all_stages = gui_data.progress_window.progress_bar_all_stages.clone();
let taskbar_state = gui_data.taskbar_state.clone();
progress_bar_current_stage.show();
common_set_data(item, &progress_bar_all_stages, &progress_bar_current_stage, &taskbar_state);
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
match (item.tool_type, item.checking_method, item.current_stage) {
(ToolType::SameMusic, CheckingMethod::AudioTags, 2) | (ToolType::SameMusic, CheckingMethod::AudioContent, 5) => {
label_stage.set_text(&flg!("progress_scanning_music_tags", progress_ratio_tm(item)));
}
(ToolType::SameMusic, CheckingMethod::AudioContent, 2) => {
label_stage.set_text(&flg!("progress_scanning_music_content", progress_ratio_tm(item)));
}
(ToolType::SameMusic, CheckingMethod::AudioTags, 4) => {
label_stage.set_text(&flg!("progress_scanning_music_tags_end", progress_ratio_tm(item)));
}
(ToolType::SameMusic, CheckingMethod::AudioContent, 4) => {
label_stage.set_text(&flg!("progress_scanning_music_content_end", progress_ratio_tm(item)));
}
(ToolType::SimilarImages, _, 1) => {
label_stage.set_text(&flg!("progress_scanning_image", progress_ratio_tm(item)));
}
(ToolType::SimilarImages, _, 2) => {
label_stage.set_text(&flg!("progress_comparing_image_hashes", progress_ratio_tm(item)));
}
(ToolType::SimilarVideos, _, 1) => {
label_stage.set_text(&flg!("progress_scanning_video", progress_ratio_tm(item)));
}
(ToolType::BrokenFiles, _, 1) => {
label_stage.set_text(&flg!("progress_scanning_broken_files", progress_ratio_tm(item)));
}
(ToolType::BadExtensions, _, 1) => {
label_stage.set_text(&flg!("progress_scanning_extension_of_files", progress_ratio_tm(item)));
}
(ToolType::Duplicate, CheckingMethod::Hash, 2) => {
label_stage.set_text(&flg!("progress_analyzed_partial_hash", progress_ratio_tm(item)));
}
(ToolType::Duplicate, CheckingMethod::Hash, 5) => {
label_stage.set_text(&flg!("progress_analyzed_full_hash", progress_ratio_tm(item)));
}
_ => unreachable!(),
}
}
fn common_set_data(item: &ProgressData, progress_bar_all_stages: &ProgressBar, progress_bar_current_stage: &ProgressBar, taskbar_state: &Rc<RefCell<TaskbarProgress>>) {