1
0
Fork 0
mirror of synced 2024-05-03 03:52:58 +12:00
This commit is contained in:
Rafał Mikrut 2024-02-17 13:11:07 +01:00
parent cd1c6e953d
commit e268afbc4b
12 changed files with 111 additions and 62 deletions

View file

@ -328,7 +328,7 @@ where
{
#[fun_time(message = "run(collecting files/dirs)", level = "debug")]
pub fn run(self) -> DirTraversalResult<T> {
assert!(self.tool_type != ToolType::None, "Tool type cannot be None");
assert_ne!(self.tool_type, ToolType::None, "Tool type cannot be None");
let mut all_warnings = vec![];
let mut grouped_file_entries: BTreeMap<T, Vec<FileEntry>> = BTreeMap::new();
@ -766,7 +766,6 @@ mod tests {
}
#[cfg(target_family = "unix")]
#[ignore] // Flaky test
#[test]
fn test_traversal_group_by_inode() -> io::Result<()> {
let dir = tempfile::Builder::new().tempdir()?;
@ -808,7 +807,6 @@ mod tests {
}
#[cfg(target_family = "windows")]
#[ignore] // Flaky test
#[test]
fn test_traversal_group_by_inode() -> io::Result<()> {
let dir = tempfile::Builder::new().tempdir()?;

View file

@ -1296,7 +1296,7 @@ where
fn vector_sort_simple_unstable_entry_by_path<T>(vector: &[T]) -> Vec<T>
where
T: ResultEntry + Clone,
T: std::marker::Send,
T: Send,
{
let mut vector = vector.to_vec();
vector.par_sort_unstable_by(|a, b| split_path_compare(a.get_path(), b.get_path()));

View file

@ -77,8 +77,8 @@ pub fn connect_button_search(gui_data: &GuiData, result_sender: Sender<Message>,
entry_info.set_text(&flg!("searching_for_data"));
// Resets progress bars
progress_bar_all_stages.set_fraction(0 as f64);
progress_bar_current_stage.set_fraction(0 as f64);
progress_bar_all_stages.set_fraction(0f64);
progress_bar_current_stage.set_fraction(0f64);
reset_text_view(&text_view_errors);
@ -162,7 +162,7 @@ impl LoadedCommonItems {
.as_str()
.to_string()
.split(',')
.map(std::string::ToString::to_string)
.map(ToString::to_string)
.collect::<Vec<String>>();
let allowed_extensions = entry_allowed_extensions.text().as_str().to_string();
let excluded_extensions = entry_excluded_extensions.text().as_str().to_string();

View file

@ -217,10 +217,10 @@ fn progress_default(gui_data: &GuiData, item: &ProgressData) {
fn common_set_data(item: &ProgressData, progress_bar_all_stages: &ProgressBar, progress_bar_current_stage: &ProgressBar, taskbar_state: &Rc<RefCell<TaskbarProgress>>) {
if item.entries_to_check != 0 {
let all_stages = (item.current_stage as f64 + (item.entries_checked) as f64 / item.entries_to_check as f64) / (item.max_stage + 1) as f64;
let all_stages = (item.current_stage as f64 + item.entries_checked as f64 / item.entries_to_check as f64) / (item.max_stage + 1) as f64;
let all_stages = if all_stages > 0.99 { 0.99 } else { all_stages };
progress_bar_all_stages.set_fraction(all_stages);
progress_bar_current_stage.set_fraction((item.entries_checked) as f64 / item.entries_to_check as f64);
progress_bar_current_stage.set_fraction(item.entries_checked as f64 / item.entries_to_check as f64);
taskbar_state.borrow().set_progress_value(
((item.current_stage as usize) * item.entries_to_check + item.entries_checked) as u64,
item.entries_to_check as u64 * (item.max_stage + 1) as u64,

View file

@ -212,7 +212,7 @@ fn add_manually_directories(window_main: &Window, tree_view: &TreeView, excluded
let list_store = get_list_store(&tree_view);
if excluded_items {
if !(check_if_value_is_in_list_store(&list_store, ColumnsExcludedDirectory::Path as i32, &text)) {
if !check_if_value_is_in_list_store(&list_store, ColumnsExcludedDirectory::Path as i32, &text) {
let values: [(u32, &dyn ToValue); 1] = [(ColumnsExcludedDirectory::Path as u32, &text)];
list_store.set(&list_store.append(), &values);
}

View file

@ -138,10 +138,10 @@ fn no_current_stage_get_data(item: &ProgressData) -> (i32, i32) {
// Used to calculate number of files to check and also to calculate current progress according to number of files to check and checked
fn common_get_data(item: &ProgressData) -> (i32, i32) {
if item.entries_to_check != 0 {
let all_stages = (item.current_stage as f64 + (item.entries_checked) as f64 / item.entries_to_check as f64) / (item.max_stage + 1) as f64;
let all_stages = (item.current_stage as f64 + item.entries_checked as f64 / item.entries_to_check as f64) / (item.max_stage + 1) as f64;
let all_stages = if all_stages > 0.99 { 0.99 } else { all_stages };
let current_stage = (item.entries_checked) as f64 / item.entries_to_check as f64;
let current_stage = item.entries_checked as f64 / item.entries_to_check as f64;
let current_stage = if current_stage > 0.99 { 0.99 } else { current_stage };
((all_stages * 100.0) as i32, (current_stage * 100.0) as i32)
} else {

View file

@ -105,7 +105,7 @@ fn scan_duplicates(a: Weak<MainWindow>, progress_sender: Sender<ProgressData>, s
// finder.set_ignore_hard_links(custom_settings.ignore); // TODO
finder.set_use_prehash_cache(custom_settings.duplicate_use_prehash);
finder.set_delete_outdated_cache(custom_settings.duplicate_delete_outdated_entries);
// finder.set_case_sensitive_name_comparison(custom_settings.); // TODO
finder.set_case_sensitive_name_comparison(custom_settings.duplicates_sub_name_case_sensitive);
finder.find_duplicates(Some(&stop_receiver), Some(&progress_sender));
let messages = finder.get_text_messages().create_messages_text();
@ -396,7 +396,7 @@ fn write_similar_images_results(app: &MainWindow, vector: Vec<(Option<ImagesEntr
}
}
app.set_similar_images_model(items.into());
app.invoke_scan_ended(format!("Found {items_found} similar images files").into());
app.invoke_scan_ended(format!("Found {items_found} similar image files").into());
app.global::<GuiState>().set_info_text(messages.into());
}
fn prepare_data_model_similar_images(fe: &ImagesEntry, hash_size: u8) -> (ModelRc<SharedString>, ModelRc<i32>) {
@ -470,7 +470,7 @@ fn write_similar_videos_results(app: &MainWindow, vector: Vec<(Option<VideosEntr
}
}
app.set_similar_videos_model(items.into());
app.invoke_scan_ended(format!("Found {items_found} similar videos files").into());
app.invoke_scan_ended(format!("Found {items_found} similar video files").into());
app.global::<GuiState>().set_info_text(messages.into());
}
fn prepare_data_model_similar_videos(fe: &VideosEntry) -> (ModelRc<SharedString>, ModelRc<i32>) {
@ -523,8 +523,8 @@ fn scan_similar_music(a: Weak<MainWindow>, progress_sender: Sender<ProgressData>
}
finder.set_music_similarity(music_similarity);
// finder.set_maximum_difference(custom_settings.mus); // TODO
// finder.set_minimum_segment_duration(minimum_segment_duration); // TODO
finder.set_maximum_difference(custom_settings.similar_music_sub_maximum_difference_value as f64);
finder.set_minimum_segment_duration(custom_settings.similar_music_sub_minimal_fragment_duration_value);
let audio_check_type = ALLOWED_AUDIO_CHECK_TYPE_VALUES[get_audio_check_type_idx(&custom_settings.similar_music_sub_audio_check_type).unwrap()].2;
finder.set_check_type(audio_check_type);
finder.set_approximate_comparison(custom_settings.similar_music_sub_approximate_comparison);
@ -549,7 +549,7 @@ fn scan_similar_music(a: Weak<MainWindow>, progress_sender: Sender<ProgressData>
}
a.upgrade_in_event_loop(move |app| {
crate::connect_scan::write_similar_music_results(&app, vector, messages);
write_similar_music_results(&app, vector, messages);
})
})
.unwrap();
@ -559,14 +559,14 @@ fn write_similar_music_results(app: &MainWindow, vector: Vec<(Option<MusicEntry>
let items = Rc::new(VecModel::default());
for (ref_fe, vec_fe) in vector {
if let Some(ref_fe) = ref_fe {
let (data_model_str, data_model_int) = crate::connect_scan::prepare_data_model_similar_music(&ref_fe);
let (data_model_str, data_model_int) = prepare_data_model_similar_music(&ref_fe);
insert_data_to_model(&items, data_model_str, data_model_int, Some(true));
} else {
insert_data_to_model(&items, ModelRc::new(VecModel::default()), ModelRc::new(VecModel::default()), Some(false));
}
for fe in vec_fe {
let (data_model_str, data_model_int) = crate::connect_scan::prepare_data_model_similar_music(&fe);
let (data_model_str, data_model_int) = prepare_data_model_similar_music(&fe);
insert_data_to_model(&items, data_model_str, data_model_int, None);
}
}
@ -618,7 +618,7 @@ fn write_invalid_symlinks_results(app: &MainWindow, vector: Vec<SymlinksFileEntr
let items_found = vector.len();
let items = Rc::new(VecModel::default());
for fe in vector {
let (data_model_str, data_model_int) = crate::connect_scan::prepare_data_model_invalid_symlinks(&fe);
let (data_model_str, data_model_int) = prepare_data_model_invalid_symlinks(&fe);
insert_data_to_model(&items, data_model_str, data_model_int, None);
}
app.set_invalid_symlinks_model(items.into());
@ -654,7 +654,7 @@ fn scan_temporary_files(a: Weak<MainWindow>, progress_sender: Sender<ProgressDat
vector.par_sort_unstable_by(|a, b| split_path_compare(a.path.as_path(), b.path.as_path()));
a.upgrade_in_event_loop(move |app| {
crate::connect_scan::write_temporary_files_results(&app, vector, messages);
write_temporary_files_results(&app, vector, messages);
})
})
.unwrap();
@ -663,7 +663,7 @@ fn write_temporary_files_results(app: &MainWindow, vector: Vec<TemporaryFileEntr
let items_found = vector.len();
let items = Rc::new(VecModel::default());
for fe in vector {
let (data_model_str, data_model_int) = crate::connect_scan::prepare_data_model_temporary_files(&fe);
let (data_model_str, data_model_int) = prepare_data_model_temporary_files(&fe);
insert_data_to_model(&items, data_model_str, data_model_int, None);
}
app.set_temporary_files_model(items.into());
@ -721,7 +721,7 @@ fn scan_broken_files(a: Weak<MainWindow>, progress_sender: Sender<ProgressData>,
vector.par_sort_unstable_by(|a, b| split_path_compare(a.path.as_path(), b.path.as_path()));
a.upgrade_in_event_loop(move |app| {
crate::connect_scan::write_broken_files_results(&app, vector, messages);
write_broken_files_results(&app, vector, messages);
})
})
.unwrap();
@ -730,7 +730,7 @@ fn write_broken_files_results(app: &MainWindow, vector: Vec<BrokenEntry>, messag
let items_found = vector.len();
let items = Rc::new(VecModel::default());
for fe in vector {
let (data_model_str, data_model_int) = crate::connect_scan::prepare_data_model_broken_files(&fe);
let (data_model_str, data_model_int) = prepare_data_model_broken_files(&fe);
insert_data_to_model(&items, data_model_str, data_model_int, None);
}
app.set_broken_files_model(items.into());
@ -767,7 +767,7 @@ fn scan_bad_extensions(a: Weak<MainWindow>, progress_sender: Sender<ProgressData
vector.par_sort_unstable_by(|a, b| split_path_compare(a.path.as_path(), b.path.as_path()));
a.upgrade_in_event_loop(move |app| {
crate::connect_scan::write_bad_extensions_results(&app, vector, messages);
write_bad_extensions_results(&app, vector, messages);
})
})
.unwrap();

View file

@ -226,6 +226,7 @@ mod tests {
model.push(MainListModel {
checked: item.0,
header_row: item.1,
full_header_row: false, // TODO - this needs to be calculated
selected_row: item.2,
val_str: ModelRc::new(all_items),
val_int: ModelRc::new(VecModel::default()),

View file

@ -1,6 +1,3 @@
use czkawka_core::big_file::SearchMode;
use image::imageops::FilterType;
use image_hasher::HashAlg;
use slint::{ComponentHandle, SharedString, VecModel};
use czkawka_core::common::get_all_available_threads;

View file

@ -26,6 +26,8 @@ pub const DEFAULT_BIGGEST_FILES: i32 = 50;
pub const DEFAULT_IMAGE_SIMILARITY: i32 = 10;
pub const DEFAULT_VIDEO_SIMILARITY: i32 = 15;
pub const DEFAULT_HASH_SIZE: u8 = 16;
pub const DEFAULT_MAXIMUM_DIFFERENCE_VALUE: f32 = 3.0;
pub const DEFAULT_MINIMAL_FRAGMENT_DURATION_VALUE: f32 = 5.0;
// (Hash size, Maximum difference) - Ehh... to simplify it, just use everywhere 40 as maximum similarity - for now I'm to lazy to change it, when hash size changes
// So if you want to change it, you need to change it in multiple places
@ -129,6 +131,8 @@ pub struct SettingsCustom {
pub duplicates_sub_check_method: String,
#[serde(default = "default_duplicates_hash_type")]
pub duplicates_sub_available_hash_type: String,
#[serde(default)]
pub duplicates_sub_name_case_sensitive: bool,
#[serde(default = "default_biggest_method")]
pub biggest_files_sub_method: String,
#[serde(default = "default_biggest_files")]
@ -153,6 +157,10 @@ pub struct SettingsCustom {
pub similar_music_sub_genre: bool,
#[serde(default)]
pub similar_music_sub_length: bool,
#[serde(default = "default_maximum_difference_value")]
pub similar_music_sub_maximum_difference_value: f32,
#[serde(default = "default_minimal_fragment_duration_value")]
pub similar_music_sub_minimal_fragment_duration_value: f32,
#[serde(default = "ttrue")]
pub broken_files_sub_audio: bool,
#[serde(default)]
@ -434,6 +442,7 @@ pub fn set_settings_to_gui(app: &MainWindow, custom_settings: &SettingsCustom) {
settings.set_duplicate_minimal_hash_cache_size(custom_settings.duplicate_minimal_hash_cache_size.to_string().into());
settings.set_duplicate_minimal_prehash_cache_size(custom_settings.duplicate_minimal_prehash_cache_size.to_string().into());
settings.set_duplicate_delete_outdated_entries(custom_settings.duplicate_delete_outdated_entries);
settings.set_duplicates_sub_name_case_sensitive(custom_settings.duplicates_sub_name_case_sensitive);
settings.set_similar_images_show_image_preview(custom_settings.similar_images_show_image_preview);
settings.set_similar_images_delete_outdated_entries(custom_settings.similar_images_delete_outdated_entries);
settings.set_similar_videos_delete_outdated_entries(custom_settings.similar_videos_delete_outdated_entries);
@ -449,7 +458,6 @@ pub fn set_settings_to_gui(app: &MainWindow, custom_settings: &SettingsCustom) {
settings.set_similar_images_sub_hash_size_index(similar_images_sub_hash_size_idx as i32);
settings.set_similar_images_sub_hash_size_value(ALLOWED_HASH_SIZE_VALUES[similar_images_sub_hash_size_idx].1.to_string().into());
// TODO all items with _value are not necessary, but due bug in slint are required, because combobox is not updated properly
let similar_images_sub_hash_alg_idx = get_image_hash_alg_idx(&custom_settings.similar_images_sub_hash_alg).unwrap_or_else(|| {
warn!(
"Value of hash type \"{}\" is invalid, setting it to default value",
@ -458,7 +466,6 @@ pub fn set_settings_to_gui(app: &MainWindow, custom_settings: &SettingsCustom) {
0
});
settings.set_similar_images_sub_hash_alg_index(similar_images_sub_hash_alg_idx as i32);
let similar_images_sub_resize_algorithm_idx = get_resize_algorithm_idx(&custom_settings.similar_images_sub_resize_algorithm).unwrap_or_else(|| {
warn!(
"Value of resize algorithm \"{}\" is invalid, setting it to default value",
@ -468,7 +475,6 @@ pub fn set_settings_to_gui(app: &MainWindow, custom_settings: &SettingsCustom) {
});
settings.set_similar_images_sub_resize_algorithm_index(similar_images_sub_resize_algorithm_idx as i32);
settings.set_similar_images_sub_resize_algorithm_value(ALLOWED_RESIZE_ALGORITHM_VALUES[similar_images_sub_resize_algorithm_idx].1.to_string().into());
settings.set_similar_images_sub_ignore_same_size(custom_settings.similar_images_sub_ignore_same_size);
settings.set_similar_images_sub_max_similarity(40.0);
settings.set_similar_images_sub_current_similarity(custom_settings.similar_images_sub_similarity as f32);
@ -525,6 +531,8 @@ pub fn set_settings_to_gui(app: &MainWindow, custom_settings: &SettingsCustom) {
settings.set_similar_music_sub_bitrate(custom_settings.similar_music_sub_bitrate);
settings.set_similar_music_sub_genre(custom_settings.similar_music_sub_genre);
settings.set_similar_music_sub_length(custom_settings.similar_music_sub_length);
settings.set_similar_music_sub_maximum_difference_value(custom_settings.similar_music_sub_maximum_difference_value);
settings.set_similar_music_sub_minimal_fragment_duration_value(custom_settings.similar_music_sub_minimal_fragment_duration_value);
settings.set_broken_files_sub_audio(custom_settings.broken_files_sub_audio);
settings.set_broken_files_sub_pdf(custom_settings.broken_files_sub_pdf);
@ -571,6 +579,7 @@ pub fn collect_settings(app: &MainWindow) -> SettingsCustom {
.parse::<i32>()
.unwrap_or(DEFAULT_MINIMUM_PREHASH_CACHE_SIZE);
let duplicate_delete_outdated_entries = settings.get_duplicate_delete_outdated_entries();
let duplicates_sub_name_case_sensitive = settings.get_duplicates_sub_name_case_sensitive();
let similar_images_show_image_preview = settings.get_similar_images_show_image_preview();
let similar_images_delete_outdated_entries = settings.get_similar_images_delete_outdated_entries();
@ -609,6 +618,8 @@ pub fn collect_settings(app: &MainWindow) -> SettingsCustom {
let similar_music_sub_bitrate = settings.get_similar_music_sub_bitrate();
let similar_music_sub_genre = settings.get_similar_music_sub_genre();
let similar_music_sub_length = settings.get_similar_music_sub_length();
let similar_music_sub_maximum_difference_value = settings.get_similar_music_sub_maximum_difference_value();
let similar_music_sub_minimal_fragment_duration_value = settings.get_similar_music_sub_minimal_fragment_duration_value();
let broken_files_sub_audio = settings.get_broken_files_sub_audio();
let broken_files_sub_pdf = settings.get_broken_files_sub_pdf();
@ -647,6 +658,7 @@ pub fn collect_settings(app: &MainWindow) -> SettingsCustom {
similar_images_sub_similarity,
duplicates_sub_check_method,
duplicates_sub_available_hash_type,
duplicates_sub_name_case_sensitive,
biggest_files_sub_method,
biggest_files_sub_number_of_files,
similar_videos_sub_ignore_same_size,
@ -659,6 +671,8 @@ pub fn collect_settings(app: &MainWindow) -> SettingsCustom {
similar_music_sub_bitrate,
similar_music_sub_genre,
similar_music_sub_length,
similar_music_sub_maximum_difference_value,
similar_music_sub_minimal_fragment_duration_value,
broken_files_sub_audio,
broken_files_sub_pdf,
broken_files_sub_archive,
@ -704,6 +718,12 @@ fn default_excluded_directories() -> Vec<PathBuf> {
fn default_duplicates_check_method() -> String {
ALLOWED_DUPLICATES_CHECK_METHOD_VALUES[0].0.to_string()
}
fn default_maximum_difference_value() -> f32 {
DEFAULT_MAXIMUM_DIFFERENCE_VALUE
}
fn default_minimal_fragment_duration_value() -> f32 {
DEFAULT_MINIMAL_FRAGMENT_DURATION_VALUE
}
fn default_duplicates_hash_type() -> String {
ALLOWED_DUPLICATES_HASH_TYPE_VALUES[0].0.to_string()
}

View file

@ -61,6 +61,8 @@ export global Settings {
in-out property <[string]> duplicates_sub_available_hash_type: ["Blake3", "CRC32", "XXH3"];
in-out property <int> duplicates_sub_available_hash_type_index: 0;
in-out property <string> duplicates_sub_available_hash_type_value: "Blake3";
in-out property <bool> duplicates_sub_name_case_sensitive: false;
// Big files
in-out property <[string]> biggest_files_sub_method: ["The Biggest", "The Smallest"];
@ -84,6 +86,10 @@ export global Settings {
in-out property <bool> similar_music_sub_bitrate: false;
in-out property <bool> similar_music_sub_genre: false;
in-out property <bool> similar_music_sub_length: false;
in-out property <float> similar_music_sub_minimal_fragment_duration_value: 5.0;
in-out property <float> similar_music_sub_minimal_fragment_duration_max: 180.0;
in-out property <float> similar_music_sub_maximum_difference_value: 3.0;
in-out property <float> similar_music_sub_maximum_difference_max: 10.0;
// Broken Files
in-out property <bool> broken_files_sub_audio: true;

View file

@ -118,6 +118,10 @@ export component ToolSettings {
current_index <=> Settings.duplicates_sub_available_hash_type_index;
current_value <=> Settings.duplicates_sub_available_hash_type_value;
}
CheckBoxWrapper {
text: "Case Sensitive(only name modes)";
checked <=> Settings.duplicates_sub_name_case_sensitive;
}
Rectangle {}
}
VerticalLayout {
@ -166,37 +170,60 @@ export component ToolSettings {
current_index <=> Settings.similar_music_sub_audio_check_type_index;
current_value <=> Settings.similar_music_sub_audio_check_type_value;
}
CheckBoxWrapper {
text: "Approximate Tag Comparison";
checked <=> Settings.similar_music_sub_approximate_comparison;
// A little bit of a hack
// Mode should be set with a enum, not index, but it's not possible in slint(maybe yet)
if Settings.similar_music_sub_audio_check_type_index == 0: VerticalLayout {
spacing: 5px;
CheckBoxWrapper {
text: "Approximate Tag Comparison";
checked <=> Settings.similar_music_sub_approximate_comparison;
}
Text {
text: "Compared tags";
font-size: 12px;
}
CheckBoxWrapper {
text: "Title";
checked <=> Settings.similar_music_sub_title;
}
CheckBoxWrapper {
text: "Artist";
checked <=> Settings.similar_music_sub_artist;
}
CheckBoxWrapper {
text: "Bitrate";
checked <=> Settings.similar_music_sub_bitrate;
}
CheckBoxWrapper {
text: "Genre";
checked <=> Settings.similar_music_sub_genre;
}
CheckBoxWrapper {
text: "Year";
checked <=> Settings.similar_music_sub_year;
}
CheckBoxWrapper {
text: "Length";
checked <=> Settings.similar_music_sub_length;
}
}
Text {
text: "Compared tags";
font-size: 12px;
}
CheckBoxWrapper {
text: "Title";
checked <=> Settings.similar_music_sub_title;
}
CheckBoxWrapper {
text: "Artist";
checked <=> Settings.similar_music_sub_artist;
}
CheckBoxWrapper {
text: "Bitrate";
checked <=> Settings.similar_music_sub_bitrate;
}
CheckBoxWrapper {
text: "Genre";
checked <=> Settings.similar_music_sub_genre;
}
CheckBoxWrapper {
text: "Year";
checked <=> Settings.similar_music_sub_year;
}
CheckBoxWrapper {
text: "Length";
checked <=> Settings.similar_music_sub_length;
if Settings.similar_music_sub_audio_check_type_index == 1: VerticalLayout {
spacing: 5px;
SliderWrapper {
text: "Max difference";
end_text: "(" + round(Settings.similar_music_sub_maximum_difference_value) + "/" + round(Settings.similar_music_sub_maximum_difference_max) + ")";
end_text_size: 40px;
maximum <=> Settings.similar_music_sub_maximum_difference_max;
value <=> Settings.similar_music_sub_maximum_difference_value;
}
SliderWrapper {
text: "Minimal fragment duration";
end_text: round(Settings.similar_music_sub_minimal_fragment_duration_value);
end_text_size: 40px;
maximum <=> Settings.similar_music_sub_minimal_fragment_duration_max;
value <=> Settings.similar_music_sub_minimal_fragment_duration_value;
}
}
Rectangle {}
}