1
0
Fork 0
mirror of synced 2024-05-17 19:03:08 +12:00
This commit is contained in:
Rafał Mikrut 2023-05-02 20:52:02 +02:00
parent b89d7ea00b
commit 3be13a914b
22 changed files with 311 additions and 488 deletions

View file

@ -10,6 +10,7 @@ use std::mem;
use std::time::SystemTime;
use crossbeam_channel::Receiver;
use futures::channel::mpsc::UnboundedSender;
use mime_guess::get_mime_extensions;
use rayon::prelude::*;
@ -208,7 +209,7 @@ impl BadExtensions {
}
}
pub fn find_bad_extensions_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) {
pub fn find_bad_extensions_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) {
self.directories.optimize_directories(self.recursive_search, &mut self.text_messages);
if !self.check_files(stop_receiver, progress_sender) {
self.stopped_search = true;
@ -283,7 +284,7 @@ impl BadExtensions {
self.excluded_items.set_excluded_items(excluded_items, &mut self.text_messages);
}
fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) -> bool {
let result = DirTraversalBuilder::new()
.root_dirs(self.directories.included_directories.clone())
.group_by(|_fe| ())
@ -317,14 +318,13 @@ impl BadExtensions {
}
}
fn look_for_bad_extensions_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
fn look_for_bad_extensions_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) -> bool {
let system_time = SystemTime::now();
let check_was_stopped = AtomicBool::new(false); // Used for breaking from GUI and ending check thread
let progress_thread_run = Arc::new(AtomicBool::new(true));
let atomic_counter = Arc::new(AtomicUsize::new(0));
let progress_thread_handle = prepare_thread_handler_common(
progress_sender,
&progress_thread_run,

View file

@ -2,33 +2,28 @@ use std::collections::BTreeMap;
use std::fs::{DirEntry, File, Metadata};
use std::io::{BufWriter, Write};
use std::path::{Path, PathBuf};
use std::sync::atomic::Ordering;
use std::sync::atomic::{AtomicBool, AtomicU64};
use std::sync::atomic::AtomicBool;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread::{sleep, JoinHandle};
use std::time::Duration;
use std::fs;
use std::time::SystemTime;
use std::{fs, thread};
use crossbeam_channel::Receiver;
use futures::channel::mpsc::UnboundedSender;
use humansize::format_size;
use humansize::BINARY;
use rayon::prelude::*;
use crate::common::{check_folder_children, send_info_and_wait_for_ending_all_threads, split_path};
use crate::common::{Common, LOOP_DURATION};
use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time};
use crate::common::Common;
use crate::common::{check_folder_children, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads, split_path};
use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData};
use crate::common_directory::Directories;
use crate::common_extensions::Extensions;
use crate::common_items::ExcludedItems;
use crate::common_messages::Messages;
use crate::common_traits::{DebugPrint, PrintResults, SaveResults};
#[derive(Debug)]
pub struct ProgressData {
pub files_checked: usize,
}
#[derive(Clone)]
pub struct FileEntry {
pub path: PathBuf,
@ -94,7 +89,7 @@ impl BigFile {
}
}
pub fn find_big_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) {
pub fn find_big_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) {
self.optimize_directories();
if !self.look_for_big_files(stop_receiver, progress_sender) {
self.stopped_search = true;
@ -147,33 +142,7 @@ impl BigFile {
self.allowed_extensions.set_allowed_extensions(allowed_extensions, &mut self.text_messages);
}
pub fn prepare_thread_handler(
&self,
progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>,
progress_thread_run: &Arc<AtomicBool>,
atomic_counter: &Arc<AtomicU64>,
) -> JoinHandle<()> {
if let Some(progress_sender) = progress_sender {
let progress_send = progress_sender.clone();
let progress_thread_run = progress_thread_run.clone();
let atomic_counter = atomic_counter.clone();
thread::spawn(move || loop {
progress_send
.unbounded_send(ProgressData {
files_checked: atomic_counter.load(Ordering::Relaxed) as usize,
})
.unwrap();
if !progress_thread_run.load(Ordering::Relaxed) {
break;
}
sleep(Duration::from_millis(LOOP_DURATION as u64));
})
} else {
thread::spawn(|| {})
}
}
fn look_for_big_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
fn look_for_big_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) -> bool {
let start_time: SystemTime = SystemTime::now();
let mut folders_to_check: Vec<PathBuf> = Vec::with_capacity(1024 * 2); // This should be small enough too not see to big difference and big enough to store most of paths without needing to resize vector
let mut old_map: BTreeMap<u64, Vec<FileEntry>> = Default::default();
@ -184,8 +153,8 @@ impl BigFile {
}
let progress_thread_run = Arc::new(AtomicBool::new(true));
let atomic_counter = Arc::new(AtomicU64::new(0));
let progress_thread_handle = self.prepare_thread_handler(progress_sender, &progress_thread_run, &atomic_counter);
let atomic_counter = Arc::new(AtomicUsize::new(0));
let progress_thread_handle = prepare_thread_handler_common(progress_sender, &progress_thread_run, &atomic_counter, 0, 0, 0, CheckingMethod::None);
while !folders_to_check.is_empty() {
if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() {
@ -251,7 +220,7 @@ impl BigFile {
pub fn collect_file_entry(
&self,
atomic_counter: &Arc<AtomicU64>,
atomic_counter: &Arc<AtomicUsize>,
metadata: &Metadata,
entry_data: &DirEntry,
fe_result: &mut Vec<(u64, FileEntry)>,

View file

@ -5,11 +5,12 @@ use std::io::{BufReader, BufWriter};
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread::{sleep, JoinHandle};
use std::time::{Duration, SystemTime};
use std::{fs, mem, panic, thread};
use std::time::SystemTime;
use std::{fs, mem, panic};
use crossbeam_channel::Receiver;
use futures::channel::mpsc::UnboundedSender;
use pdf::file::FileOptions;
use pdf::object::ParseOptions;
use pdf::PdfError;
@ -17,23 +18,17 @@ use pdf::PdfError::Try;
use rayon::prelude::*;
use serde::{Deserialize, Serialize};
use crate::common::{check_folder_children, create_crash_message, open_cache_folder, send_info_and_wait_for_ending_all_threads, Common, LOOP_DURATION, PDF_FILES_EXTENSIONS};
use crate::common::{
check_folder_children, create_crash_message, open_cache_folder, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads, Common, PDF_FILES_EXTENSIONS,
};
use crate::common::{AUDIO_FILES_EXTENSIONS, IMAGE_RS_BROKEN_FILES_EXTENSIONS, ZIP_FILES_EXTENSIONS};
use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time};
use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData};
use crate::common_directory::Directories;
use crate::common_extensions::Extensions;
use crate::common_items::ExcludedItems;
use crate::common_messages::Messages;
use crate::common_traits::*;
#[derive(Debug)]
pub struct ProgressData {
pub current_stage: u8,
pub max_stage: u8,
pub files_checked: usize,
pub files_to_check: usize,
}
#[derive(Eq, PartialEq, Clone, Debug, Copy)]
pub enum DeleteMethod {
None,
@ -121,7 +116,7 @@ impl BrokenFiles {
}
}
pub fn find_broken_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) {
pub fn find_broken_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) {
self.directories.optimize_directories(self.recursive_search, &mut self.text_messages);
if !self.check_files(stop_receiver, progress_sender) {
self.stopped_search = true;
@ -197,39 +192,7 @@ impl BrokenFiles {
self.excluded_items.set_excluded_items(excluded_items, &mut self.text_messages);
}
pub fn prepare_thread_handler_broken_files(
&self,
progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>,
progress_thread_run: &Arc<AtomicBool>,
atomic_counter: &Arc<AtomicUsize>,
current_stage: u8,
max_stage: u8,
max_value: usize,
) -> JoinHandle<()> {
if let Some(progress_sender) = progress_sender {
let progress_send = progress_sender.clone();
let progress_thread_run = progress_thread_run.clone();
let atomic_counter = atomic_counter.clone();
thread::spawn(move || loop {
progress_send
.unbounded_send(ProgressData {
current_stage,
max_stage,
files_checked: atomic_counter.load(Ordering::Relaxed),
files_to_check: max_value,
})
.unwrap();
if !progress_thread_run.load(Ordering::Relaxed) {
break;
}
sleep(Duration::from_millis(LOOP_DURATION as u64));
})
} else {
thread::spawn(|| {})
}
}
fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) -> bool {
let start_time: SystemTime = SystemTime::now();
let mut folders_to_check: Vec<PathBuf> = Vec::with_capacity(1024 * 2); // This should be small enough too not see to big difference and big enough to store most of paths without needing to resize vector
@ -240,7 +203,7 @@ impl BrokenFiles {
let progress_thread_run = Arc::new(AtomicBool::new(true));
let atomic_counter = Arc::new(AtomicUsize::new(0));
let progress_thread_handle = self.prepare_thread_handler_broken_files(progress_sender, &progress_thread_run, &atomic_counter, 0, 1, 0);
let progress_thread_handle = prepare_thread_handler_common(progress_sender, &progress_thread_run, &atomic_counter, 0, 1, 0, CheckingMethod::None);
while !folders_to_check.is_empty() {
if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() {
@ -441,7 +404,7 @@ impl BrokenFiles {
}
}
fn look_for_broken_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
fn look_for_broken_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) -> bool {
let system_time = SystemTime::now();
let loaded_hash_map;
@ -481,7 +444,15 @@ impl BrokenFiles {
let progress_thread_run = Arc::new(AtomicBool::new(true));
let atomic_counter = Arc::new(AtomicUsize::new(0));
let progress_thread_handle = self.prepare_thread_handler_broken_files(progress_sender, &progress_thread_run, &atomic_counter, 1, 1, non_cached_files_to_check.len());
let progress_thread_handle = prepare_thread_handler_common(
progress_sender,
&progress_thread_run,
&atomic_counter,
1,
1,
non_cached_files_to_check.len(),
CheckingMethod::None,
);
let mut vec_file_entry: Vec<FileEntry> = non_cached_files_to_check
.into_par_iter()

View file

@ -11,6 +11,7 @@ use std::{fs, thread};
#[cfg(feature = "heif")]
use anyhow::Result;
use directories_next::ProjectDirs;
use futures::channel::mpsc::UnboundedSender;
use image::{DynamicImage, ImageBuffer, Rgb};
use imagepipe::{ImageSource, Pipeline};
// #[cfg(feature = "heif")]
@ -360,7 +361,7 @@ pub fn check_folder_children(
}
pub fn prepare_thread_handler_common(
progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>,
progress_sender: Option<&UnboundedSender<ProgressData>>,
progress_thread_run: &Arc<AtomicBool>,
atomic_counter: &Arc<AtomicUsize>,
current_stage: u8,

View file

@ -7,6 +7,7 @@ use std::sync::Arc;
use std::time::{SystemTime, UNIX_EPOCH};
use crossbeam_channel::Receiver;
use futures::channel::mpsc::UnboundedSender;
use rayon::prelude::*;
use crate::common::{prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads};
@ -99,7 +100,7 @@ pub struct DirTraversalBuilder<'a, 'b, F> {
group_by: Option<F>,
root_dirs: Vec<PathBuf>,
stop_receiver: Option<&'a Receiver<()>>,
progress_sender: Option<&'b futures::channel::mpsc::UnboundedSender<ProgressData>>,
progress_sender: Option<&'b UnboundedSender<ProgressData>>,
minimal_file_size: Option<u64>,
maximal_file_size: Option<u64>,
checking_method: CheckingMethod,
@ -115,7 +116,7 @@ pub struct DirTraversal<'a, 'b, F> {
group_by: F,
root_dirs: Vec<PathBuf>,
stop_receiver: Option<&'a Receiver<()>>,
progress_sender: Option<&'b futures::channel::mpsc::UnboundedSender<ProgressData>>,
progress_sender: Option<&'b UnboundedSender<ProgressData>>,
recursive_search: bool,
directories: Directories,
excluded_items: ExcludedItems,
@ -168,7 +169,7 @@ impl<'a, 'b, F> DirTraversalBuilder<'a, 'b, F> {
}
#[must_use]
pub fn progress_sender(mut self, progress_sender: Option<&'b futures::channel::mpsc::UnboundedSender<ProgressData>>) -> Self {
pub fn progress_sender(mut self, progress_sender: Option<&'b UnboundedSender<ProgressData>>) -> Self {
self.progress_sender = progress_sender;
self
}
@ -333,16 +334,8 @@ where
folders_to_check.extend(self.root_dirs);
let progress_thread_run = Arc::new(AtomicBool::new(true));
let atomic_entry_counter = Arc::new(AtomicUsize::new(0));
let progress_thread_handle = prepare_thread_handler_common(
self.progress_sender,
&progress_thread_run,
&atomic_entry_counter,
0,
self.max_stage,
0,
self.checking_method,
);
let atomic_counter = Arc::new(AtomicUsize::new(0));
let progress_thread_handle = prepare_thread_handler_common(self.progress_sender, &progress_thread_run, &atomic_counter, 0, self.max_stage, 0, self.checking_method);
let DirTraversal {
collect,
@ -386,7 +379,7 @@ where
process_dir_in_file_symlink_mode(recursive_search, current_folder, entry_data, &directories, &mut dir_result, &mut warnings, &excluded_items);
}
(EntryType::Dir, Collect::EmptyFolders) => {
atomic_entry_counter.fetch_add(1, Ordering::Relaxed);
atomic_counter.fetch_add(1, Ordering::Relaxed);
process_dir_in_dir_mode(
&metadata,
current_folder,
@ -400,7 +393,7 @@ where
);
}
(EntryType::File, Collect::Files) => {
atomic_entry_counter.fetch_add(1, Ordering::Relaxed);
atomic_counter.fetch_add(1, Ordering::Relaxed);
process_file_in_file_mode(
&metadata,
entry_data,
@ -427,10 +420,10 @@ where
set_as_not_empty_folder_list.push(current_folder.clone());
}
(EntryType::File, Collect::InvalidSymlinks) => {
atomic_entry_counter.fetch_add(1, Ordering::Relaxed);
atomic_counter.fetch_add(1, Ordering::Relaxed);
}
(EntryType::Symlink, Collect::InvalidSymlinks) => {
atomic_entry_counter.fetch_add(1, Ordering::Relaxed);
atomic_counter.fetch_add(1, Ordering::Relaxed);
process_symlink_in_symlink_mode(
&metadata,
entry_data,

View file

@ -15,9 +15,11 @@ use std::time::SystemTime;
use std::{fs, mem};
use crossbeam_channel::Receiver;
use futures::channel::mpsc::UnboundedSender;
use humansize::format_size;
use humansize::BINARY;
use rayon::prelude::*;
use xxhash_rust::xxh3::Xxh3;
use crate::common::{open_cache_folder, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads, Common};
use crate::common_dir_traversal::{CheckingMethod, DirTraversalBuilder, DirTraversalResult, FileEntry, ProgressData};
@ -43,7 +45,7 @@ impl HashType {
match self {
HashType::Blake3 => Box::new(blake3::Hasher::new()),
HashType::Crc32 => Box::new(crc32fast::Hasher::new()),
HashType::Xxh3 => Box::new(xxhash_rust::xxh3::Xxh3::new()),
HashType::Xxh3 => Box::new(Xxh3::new()),
}
}
}
@ -147,7 +149,7 @@ impl DuplicateFinder {
}
}
pub fn find_duplicates(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) {
pub fn find_duplicates(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) {
self.directories.optimize_directories(self.recursive_search, &mut self.text_messages);
self.use_reference_folders = !self.directories.reference_directories.is_empty();
@ -340,7 +342,7 @@ impl DuplicateFinder {
&self.files_with_identical_size_names_referenced
}
fn check_files_name(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
fn check_files_name(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) -> bool {
let group_by_func = if self.case_sensitive_name_comparison {
|fe: &FileEntry| fe.path.file_name().unwrap().to_string_lossy().to_string()
} else {
@ -435,7 +437,7 @@ impl DuplicateFinder {
}
}
fn check_files_size_name(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
fn check_files_size_name(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) -> bool {
let group_by_func = if self.case_sensitive_name_comparison {
|fe: &FileEntry| (fe.size, fe.path.file_name().unwrap().to_string_lossy().to_string())
} else {
@ -535,7 +537,7 @@ impl DuplicateFinder {
/// Read file length and puts it to different boxes(each for different lengths)
/// If in box is only 1 result, then it is removed
fn check_files_size(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
fn check_files_size(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) -> bool {
let max_stage = match self.check_method {
CheckingMethod::Size => 0,
CheckingMethod::Hash => 2,
@ -718,7 +720,7 @@ impl DuplicateFinder {
fn prehashing(
&mut self,
stop_receiver: Option<&Receiver<()>>,
progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>,
progress_sender: Option<&UnboundedSender<ProgressData>>,
pre_checked_map: &mut BTreeMap<u64, Vec<FileEntry>>,
) -> Option<()> {
let start_time: SystemTime = SystemTime::now();
@ -886,7 +888,7 @@ impl DuplicateFinder {
fn full_hashing(
&mut self,
stop_receiver: Option<&Receiver<()>>,
progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>,
progress_sender: Option<&UnboundedSender<ProgressData>>,
pre_checked_map: BTreeMap<u64, Vec<FileEntry>>,
) -> Option<()> {
let check_was_stopped = AtomicBool::new(false); // Used for breaking from GUI and ending check thread
@ -1018,7 +1020,7 @@ impl DuplicateFinder {
}
/// The slowest checking type, which must be applied after checking for size
fn check_files_hash(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
fn check_files_hash(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) -> bool {
assert_eq!(self.check_method, CheckingMethod::Hash);
let mut pre_checked_map: BTreeMap<u64, Vec<FileEntry>> = Default::default();
@ -1617,7 +1619,7 @@ impl MyHasher for crc32fast::Hasher {
}
}
impl MyHasher for xxhash_rust::xxh3::Xxh3 {
impl MyHasher for Xxh3 {
fn update(&mut self, bytes: &[u8]) {
self.write(bytes);
}

View file

@ -6,6 +6,7 @@ use std::path::PathBuf;
use std::time::SystemTime;
use crossbeam_channel::Receiver;
use futures::channel::mpsc::UnboundedSender;
use crate::common::Common;
use crate::common_dir_traversal::{DirTraversalBuilder, DirTraversalResult, FileEntry, ProgressData};
@ -64,7 +65,7 @@ impl EmptyFiles {
}
/// Finding empty files, save results to internal struct variables
pub fn find_empty_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) {
pub fn find_empty_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) {
self.directories.optimize_directories(self.recursive_search, &mut self.text_messages);
if !self.check_files(stop_receiver, progress_sender) {
self.stopped_search = true;
@ -125,7 +126,7 @@ impl EmptyFiles {
}
/// Check files for any with size == 0
fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) -> bool {
let result = DirTraversalBuilder::new()
.root_dirs(self.directories.included_directories.clone())
.group_by(|_fe| ())

View file

@ -6,6 +6,7 @@ use std::path::PathBuf;
use std::time::SystemTime;
use crossbeam_channel::Receiver;
use futures::channel::mpsc::UnboundedSender;
use crate::common::Common;
use crate::common_dir_traversal::{Collect, DirTraversalBuilder, DirTraversalResult, FolderEmptiness, FolderEntry, ProgressData};
@ -88,7 +89,7 @@ impl EmptyFolder {
self.directories.set_excluded_directory(excluded_directory, &mut self.text_messages);
}
/// Public function used by CLI to search for empty folders
pub fn find_empty_folders(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) {
pub fn find_empty_folders(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) {
self.directories.optimize_directories(true, &mut self.text_messages);
if !self.check_for_empty_folders(stop_receiver, progress_sender) {
self.stopped_search = true;
@ -128,7 +129,7 @@ impl EmptyFolder {
/// Function to check if folder are empty.
/// Parameter `initial_checking` for second check before deleting to be sure that checked folder is still empty
fn check_for_empty_folders(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
fn check_for_empty_folders(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) -> bool {
let result = DirTraversalBuilder::new()
.root_dirs(self.directories.included_directories.clone())
.group_by(|_fe| ())

View file

@ -6,6 +6,7 @@ use std::path::PathBuf;
use std::time::SystemTime;
use crossbeam_channel::Receiver;
use futures::channel::mpsc::UnboundedSender;
use crate::common::Common;
use crate::common_dir_traversal::{Collect, DirTraversalBuilder, DirTraversalResult, ErrorType, FileEntry, ProgressData};
@ -63,7 +64,7 @@ impl InvalidSymlinks {
}
}
pub fn find_invalid_links(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) {
pub fn find_invalid_links(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) {
self.directories.optimize_directories(self.recursive_search, &mut self.text_messages);
if !self.check_files(stop_receiver, progress_sender) {
self.stopped_search = true;
@ -124,7 +125,7 @@ impl InvalidSymlinks {
}
/// Check files for any with size == 0
fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) -> bool {
let result = DirTraversalBuilder::new()
.root_dirs(self.directories.included_directories.clone())
.group_by(|_fe| ())

View file

@ -9,6 +9,7 @@ use std::time::SystemTime;
use std::{mem, panic};
use crossbeam_channel::Receiver;
use futures::channel::mpsc::UnboundedSender;
use lofty::TaggedFileExt;
use lofty::{read_from, AudioFile, ItemKey};
use rayon::prelude::*;
@ -148,7 +149,7 @@ impl SameMusic {
}
}
pub fn find_same_music(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) {
pub fn find_same_music(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) {
self.directories.optimize_directories(self.recursive_search, &mut self.text_messages);
self.use_reference_folders = !self.directories.reference_directories.is_empty();
if !self.check_files(stop_receiver, progress_sender) {
@ -276,7 +277,7 @@ impl SameMusic {
self.use_reference_folders
}
fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) -> bool {
if !self.allowed_extensions.using_custom_extensions() {
self.allowed_extensions.extend_allowed_extensions(AUDIO_FILES_EXTENSIONS);
} else {
@ -367,7 +368,7 @@ impl SameMusic {
save_cache_to_file(&all_results, &mut self.text_messages, self.save_also_as_json);
}
fn read_tags(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
fn read_tags(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) -> bool {
let start_time: SystemTime = SystemTime::now();
let (loaded_hash_map, records_already_cached, non_cached_files_to_check) = self.read_tags_load_cache();
@ -515,7 +516,7 @@ impl SameMusic {
Some(music_entry)
}
fn check_for_duplicate_tags(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
fn check_for_duplicate_tags(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) -> bool {
assert_ne!(MusicSimilarity::NONE, self.music_similarity, "This can't be none");
let start_time: SystemTime = SystemTime::now();

View file

@ -6,12 +6,13 @@ use std::panic;
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread::{sleep, JoinHandle};
use std::time::{Duration, SystemTime};
use std::{mem, thread};
use std::mem;
use std::time::SystemTime;
use bk_tree::BKTree;
use crossbeam_channel::Receiver;
use futures::channel::mpsc::UnboundedSender;
use humansize::format_size;
use humansize::BINARY;
use image::GenericImageView;
@ -22,10 +23,10 @@ use serde::{Deserialize, Serialize};
#[cfg(feature = "heif")]
use crate::common::get_dynamic_image_from_heic;
use crate::common::{
check_folder_children, create_crash_message, get_dynamic_image_from_raw_image, get_number_of_threads, open_cache_folder, send_info_and_wait_for_ending_all_threads, Common,
HEIC_EXTENSIONS, IMAGE_RS_SIMILAR_IMAGES_EXTENSIONS, LOOP_DURATION, RAW_IMAGE_EXTENSIONS,
check_folder_children, create_crash_message, get_dynamic_image_from_raw_image, get_number_of_threads, open_cache_folder, prepare_thread_handler_common,
send_info_and_wait_for_ending_all_threads, Common, HEIC_EXTENSIONS, IMAGE_RS_SIMILAR_IMAGES_EXTENSIONS, RAW_IMAGE_EXTENSIONS,
};
use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time};
use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData};
use crate::common_directory::Directories;
use crate::common_extensions::Extensions;
use crate::common_items::ExcludedItems;
@ -42,14 +43,6 @@ pub const SIMILAR_VALUES: [[u32; 6]; 4] = [
[6, 20, 40, 40, 40, 40], // 64
];
#[derive(Debug)]
pub struct ProgressData {
pub current_stage: u8,
pub max_stage: u8,
pub images_checked: usize,
pub images_to_check: usize,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct FileEntry {
pub path: PathBuf,
@ -254,7 +247,7 @@ impl SimilarImages {
}
/// Public function used by CLI to search for empty folders
pub fn find_similar_images(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) {
pub fn find_similar_images(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) {
self.directories.optimize_directories(true, &mut self.text_messages);
self.use_reference_folders = !self.directories.reference_directories.is_empty();
if !self.check_for_similar_images(stop_receiver, progress_sender) {
@ -279,41 +272,9 @@ impl SimilarImages {
// self.delete_folders = delete_folder;
// }
pub fn prepare_thread_handler_similar_images(
&self,
progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>,
progress_thread_run: &Arc<AtomicBool>,
atomic_counter: &Arc<AtomicUsize>,
current_stage: u8,
max_stage: u8,
max_value: usize,
) -> JoinHandle<()> {
if let Some(progress_sender) = progress_sender {
let progress_send = progress_sender.clone();
let progress_thread_run = progress_thread_run.clone();
let atomic_counter = atomic_counter.clone();
thread::spawn(move || loop {
progress_send
.unbounded_send(ProgressData {
current_stage,
max_stage,
images_checked: atomic_counter.load(Ordering::Relaxed),
images_to_check: max_value,
})
.unwrap();
if !progress_thread_run.load(Ordering::Relaxed) {
break;
}
sleep(Duration::from_millis(LOOP_DURATION as u64));
})
} else {
thread::spawn(|| {})
}
}
/// Function to check if folder are empty.
/// Parameter `initial_checking` for second check before deleting to be sure that checked folder is still empty
fn check_for_similar_images(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
fn check_for_similar_images(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) -> bool {
let start_time: SystemTime = SystemTime::now();
let mut folders_to_check: Vec<PathBuf> = Vec::with_capacity(1024 * 2); // This should be small enough too not see to big difference and big enough to store most of paths without needing to resize vector
@ -337,7 +298,7 @@ impl SimilarImages {
let progress_thread_run = Arc::new(AtomicBool::new(true));
let atomic_counter = Arc::new(AtomicUsize::new(0));
let progress_thread_handle = self.prepare_thread_handler_similar_images(progress_sender, &progress_thread_run, &atomic_counter, 0, 3, 0);
let progress_thread_handle = prepare_thread_handler_common(progress_sender, &progress_thread_run, &atomic_counter, 0, 2, 0, CheckingMethod::None);
while !folders_to_check.is_empty() {
if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() {
@ -466,7 +427,7 @@ impl SimilarImages {
// - Join already read hashes with hashes which were read from file
// - Join all hashes and save it to file
fn hash_images(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
fn hash_images(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) -> bool {
let hash_map_modification = SystemTime::now();
let (loaded_hash_map, records_already_cached, non_cached_files_to_check) = self.hash_images_load_cache();
@ -477,7 +438,15 @@ impl SimilarImages {
let check_was_stopped = AtomicBool::new(false); // Used for breaking from GUI and ending check thread
let progress_thread_run = Arc::new(AtomicBool::new(true));
let atomic_counter = Arc::new(AtomicUsize::new(0));
let progress_thread_handle = self.prepare_thread_handler_similar_images(progress_sender, &progress_thread_run, &atomic_counter, 1, 3, non_cached_files_to_check.len());
let progress_thread_handle = prepare_thread_handler_common(
progress_sender,
&progress_thread_run,
&atomic_counter,
1,
2,
non_cached_files_to_check.len(),
CheckingMethod::None,
);
let mut vec_file_entry: Vec<(FileEntry, ImHash)> = non_cached_files_to_check
.into_par_iter()
@ -610,7 +579,7 @@ impl SimilarImages {
fn compare_hashes(
&self,
hashes_to_check: &[ImHash],
atomic_mode_counter: &Arc<AtomicUsize>,
atomic_counter: &Arc<AtomicUsize>,
stop_receiver: Option<&Receiver<()>>,
check_was_stopped: &AtomicBool,
tolerance: u32,
@ -632,7 +601,7 @@ impl SimilarImages {
// Also don't add too often data to atomic variable
const CYCLES_COUNTER: usize = 0b11_1111;
if ((index & CYCLES_COUNTER) == CYCLES_COUNTER) && index != 0 {
atomic_mode_counter.fetch_add(CYCLES_COUNTER, Ordering::Relaxed);
atomic_counter.fetch_add(CYCLES_COUNTER, Ordering::Relaxed);
if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() {
check_was_stopped.store(true, Ordering::Relaxed);
return None;
@ -839,7 +808,7 @@ impl SimilarImages {
self.collect_hash_compare_result(hashes_parents, hashes_with_multiple_images, all_hashed_images, collected_similar_images, hashes_similarity);
}
fn find_similar_hashes(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
fn find_similar_hashes(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) -> bool {
if self.image_hashes.is_empty() {
return true;
}
@ -865,8 +834,8 @@ impl SimilarImages {
} else {
let check_was_stopped = AtomicBool::new(false); // Used for breaking from GUI and ending check thread
let progress_thread_run = Arc::new(AtomicBool::new(true));
let atomic_mode_counter = Arc::new(AtomicUsize::new(0));
let progress_thread_handle = self.prepare_thread_handler_similar_images(progress_sender, &progress_thread_run, &atomic_mode_counter, 2, 2, all_hashes.len());
let atomic_counter = Arc::new(AtomicUsize::new(0));
let progress_thread_handle = prepare_thread_handler_common(progress_sender, &progress_thread_run, &atomic_counter, 2, 2, all_hashes.len(), CheckingMethod::None);
// Don't use hashes with multiple images in bktree, because they will always be master of group and cannot be find by other hashes
@ -877,7 +846,7 @@ impl SimilarImages {
.map(|hashes_to_check| {
self.compare_hashes(
&hashes_to_check,
&atomic_mode_counter,
&atomic_counter,
stop_receiver,
&check_was_stopped,
tolerance,

View file

@ -5,12 +5,13 @@ use std::io::*;
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread::{sleep, JoinHandle};
use std::time::{Duration, SystemTime};
use std::{mem, thread};
use std::mem;
use std::time::SystemTime;
use crossbeam_channel::Receiver;
use ffmpeg_cmdline_utils::FfmpegErrorKind::FfmpegNotFound;
use futures::channel::mpsc::UnboundedSender;
use humansize::format_size;
use humansize::BINARY;
use rayon::prelude::*;
@ -18,9 +19,9 @@ use serde::{Deserialize, Serialize};
use vid_dup_finder_lib::HashCreationErrorKind::DetermineVideo;
use vid_dup_finder_lib::{NormalizedTolerance, VideoHash};
use crate::common::{check_folder_children, send_info_and_wait_for_ending_all_threads, VIDEO_FILES_EXTENSIONS};
use crate::common::{open_cache_folder, Common, LOOP_DURATION};
use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time};
use crate::common::{check_folder_children, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads, VIDEO_FILES_EXTENSIONS};
use crate::common::{open_cache_folder, Common};
use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData};
use crate::common_directory::Directories;
use crate::common_extensions::Extensions;
use crate::common_items::ExcludedItems;
@ -31,14 +32,6 @@ use crate::localizer_core::generate_translation_hashmap;
pub const MAX_TOLERANCE: i32 = 20;
#[derive(Debug)]
pub struct ProgressData {
pub current_stage: u8,
pub max_stage: u8,
pub videos_checked: usize,
pub videos_to_check: usize,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct FileEntry {
pub path: PathBuf,
@ -215,7 +208,7 @@ impl SimilarVideos {
}
/// Public function used by CLI to search for empty folders
pub fn find_similar_videos(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) {
pub fn find_similar_videos(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) {
if !check_if_ffmpeg_is_installed() {
self.text_messages.errors.push(flc!("core_ffmpeg_not_found"));
#[cfg(target_os = "windows")]
@ -247,41 +240,9 @@ impl SimilarVideos {
// self.delete_folders = delete_folder;
// }
pub fn prepare_thread_handler_similar_video(
&self,
progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>,
progress_thread_run: &Arc<AtomicBool>,
atomic_counter: &Arc<AtomicUsize>,
current_stage: u8,
max_stage: u8,
max_value: usize,
) -> JoinHandle<()> {
if let Some(progress_sender) = progress_sender {
let progress_send = progress_sender.clone();
let progress_thread_run = progress_thread_run.clone();
let atomic_counter = atomic_counter.clone();
thread::spawn(move || loop {
progress_send
.unbounded_send(ProgressData {
current_stage,
max_stage,
videos_checked: atomic_counter.load(Ordering::Relaxed),
videos_to_check: max_value,
})
.unwrap();
if !progress_thread_run.load(Ordering::Relaxed) {
break;
}
sleep(Duration::from_millis(LOOP_DURATION as u64));
})
} else {
thread::spawn(|| {})
}
}
/// Function to check if folder are empty.
/// Parameter `initial_checking` for second check before deleting to be sure that checked folder is still empty
fn check_for_similar_videos(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
fn check_for_similar_videos(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) -> bool {
let start_time: SystemTime = SystemTime::now();
let mut folders_to_check: Vec<PathBuf> = Vec::with_capacity(1024 * 2); // This should be small enough too not see to big difference and big enough to store most of paths without needing to resize vector
@ -301,7 +262,7 @@ impl SimilarVideos {
let progress_thread_run = Arc::new(AtomicBool::new(true));
let atomic_counter = Arc::new(AtomicUsize::new(0));
let progress_thread_handle = self.prepare_thread_handler_similar_video(progress_sender, &progress_thread_run, &atomic_counter, 0, 1, 0);
let progress_thread_handle = prepare_thread_handler_common(progress_sender, &progress_thread_run, &atomic_counter, 0, 1, 0, CheckingMethod::None);
while !folders_to_check.is_empty() {
if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() {
@ -424,7 +385,7 @@ impl SimilarVideos {
(loaded_hash_map, records_already_cached, non_cached_files_to_check)
}
fn sort_videos(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
fn sort_videos(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) -> bool {
let hash_map_modification = SystemTime::now();
let (loaded_hash_map, records_already_cached, non_cached_files_to_check) = self.load_cache_at_start();
@ -436,7 +397,15 @@ impl SimilarVideos {
let progress_thread_run = Arc::new(AtomicBool::new(true));
let atomic_counter = Arc::new(AtomicUsize::new(0));
let progress_thread_handle = self.prepare_thread_handler_similar_video(progress_sender, &progress_thread_run, &atomic_counter, 1, 1, non_cached_files_to_check.len());
let progress_thread_handle = prepare_thread_handler_common(
progress_sender,
&progress_thread_run,
&atomic_counter,
1,
1,
non_cached_files_to_check.len(),
CheckingMethod::None,
);
let mut vec_file_entry: Vec<FileEntry> = non_cached_files_to_check
.par_iter()

View file

@ -4,15 +4,16 @@ use std::io::BufWriter;
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread::{sleep, JoinHandle};
use std::time::{Duration, SystemTime};
use std::{fs, thread};
use std::fs;
use std::time::SystemTime;
use crossbeam_channel::Receiver;
use futures::channel::mpsc::UnboundedSender;
use rayon::prelude::*;
use crate::common::{check_folder_children, send_info_and_wait_for_ending_all_threads, Common, LOOP_DURATION};
use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time};
use crate::common::{check_folder_children, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads, Common};
use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData};
use crate::common_directory::Directories;
use crate::common_items::ExcludedItems;
use crate::common_messages::Messages;
@ -34,13 +35,6 @@ const TEMP_EXTENSIONS: &[&str] = &[
".partial",
];
#[derive(Debug)]
pub struct ProgressData {
pub current_stage: u8,
pub max_stage: u8,
pub files_checked: usize,
}
#[derive(Eq, PartialEq, Clone, Debug, Copy)]
pub enum DeleteMethod {
None,
@ -94,7 +88,7 @@ impl Temporary {
}
/// Finding temporary files, save results to internal struct variables
pub fn find_temporary_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) {
pub fn find_temporary_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) {
self.directories.optimize_directories(self.recursive_search, &mut self.text_messages);
if !self.check_files(stop_receiver, progress_sender) {
self.stopped_search = true;
@ -149,35 +143,7 @@ impl Temporary {
self.excluded_items.set_excluded_items(excluded_items, &mut self.text_messages);
}
fn prepare_thread_handler_temporary(
&self,
progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>,
progress_thread_run: &Arc<AtomicBool>,
atomic_counter: &Arc<AtomicUsize>,
) -> JoinHandle<()> {
if let Some(progress_sender) = progress_sender {
let progress_send = progress_sender.clone();
let progress_thread_run = progress_thread_run.clone();
let atomic_counter = atomic_counter.clone();
thread::spawn(move || loop {
progress_send
.unbounded_send(ProgressData {
current_stage: 0,
max_stage: 0,
files_checked: atomic_counter.load(Ordering::Relaxed),
})
.unwrap();
if !progress_thread_run.load(Ordering::Relaxed) {
break;
}
sleep(Duration::from_millis(LOOP_DURATION as u64));
})
} else {
thread::spawn(|| {})
}
}
fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender<ProgressData>>) -> bool {
let start_time: SystemTime = SystemTime::now();
let mut folders_to_check: Vec<PathBuf> = Vec::with_capacity(1024 * 2); // This should be small enough too not see to big difference and big enough to store most of paths without needing to resize vector
@ -188,7 +154,7 @@ impl Temporary {
let progress_thread_run = Arc::new(AtomicBool::new(true));
let atomic_counter = Arc::new(AtomicUsize::new(0));
let progress_thread_handle = self.prepare_thread_handler_temporary(progress_sender, &progress_thread_run, &atomic_counter);
let progress_thread_handle = prepare_thread_handler_common(progress_sender, &progress_thread_run, &atomic_counter, 0, 0, 0, CheckingMethod::None);
while !folders_to_check.is_empty() {
if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() {

View file

@ -1,3 +1,4 @@
use fs_extra::dir::CopyOptions;
use std::path::{Path, PathBuf};
use gtk4::prelude::*;
@ -199,7 +200,7 @@ fn move_files_common(
let thing = get_full_name_from_path_name(&path, &file_name);
let destination_file = destination_folder.join(file_name);
if Path::new(&thing).is_dir() {
if let Err(e) = fs_extra::dir::move_dir(&thing, &destination_file, &fs_extra::dir::CopyOptions::new()) {
if let Err(e) = fs_extra::dir::move_dir(&thing, &destination_file, &CopyOptions::new()) {
messages += flg!("move_folder_failed", generate_translation_hashmap(vec![("name", thing), ("reason", e.to_string())])).as_str();
messages += "\n";
continue 'next_result;

View file

@ -1,3 +1,4 @@
use futures::channel::mpsc::UnboundedSender;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
@ -8,7 +9,8 @@ use gtk4::prelude::*;
use czkawka_core::bad_extensions::BadExtensions;
use czkawka_core::big_file::BigFile;
use czkawka_core::broken_files::{BrokenFiles, CheckedTypes};
use czkawka_core::common_dir_traversal;
use czkawka_core::common_dir_traversal::ProgressData;
use czkawka_core::duplicate::DuplicateFinder;
use czkawka_core::empty_files::EmptyFiles;
use czkawka_core::empty_folder::EmptyFolder;
@ -17,7 +19,6 @@ use czkawka_core::same_music::{MusicSimilarity, SameMusic};
use czkawka_core::similar_images::SimilarImages;
use czkawka_core::similar_videos::SimilarVideos;
use czkawka_core::temporary::Temporary;
use czkawka_core::*;
use crate::gui_structs::gui_data::GuiData;
use crate::help_combo_box::{
@ -33,17 +34,17 @@ use crate::{flg, DEFAULT_MAXIMAL_FILE_SIZE, DEFAULT_MINIMAL_CACHE_SIZE, DEFAULT_
pub fn connect_button_search(
gui_data: &GuiData,
glib_stop_sender: Sender<Message>,
futures_sender_duplicate_files: futures::channel::mpsc::UnboundedSender<common_dir_traversal::ProgressData>,
futures_sender_empty_files: futures::channel::mpsc::UnboundedSender<common_dir_traversal::ProgressData>,
futures_sender_empty_folder: futures::channel::mpsc::UnboundedSender<common_dir_traversal::ProgressData>,
futures_sender_big_file: futures::channel::mpsc::UnboundedSender<big_file::ProgressData>,
futures_sender_same_music: futures::channel::mpsc::UnboundedSender<common_dir_traversal::ProgressData>,
futures_sender_similar_images: futures::channel::mpsc::UnboundedSender<similar_images::ProgressData>,
futures_sender_similar_videos: futures::channel::mpsc::UnboundedSender<similar_videos::ProgressData>,
futures_sender_temporary: futures::channel::mpsc::UnboundedSender<temporary::ProgressData>,
futures_sender_invalid_symlinks: futures::channel::mpsc::UnboundedSender<common_dir_traversal::ProgressData>,
futures_sender_broken_files: futures::channel::mpsc::UnboundedSender<broken_files::ProgressData>,
futures_sender_bad_extensions: futures::channel::mpsc::UnboundedSender<common_dir_traversal::ProgressData>,
futures_sender_duplicate_files: UnboundedSender<ProgressData>,
futures_sender_empty_files: UnboundedSender<ProgressData>,
futures_sender_empty_folder: UnboundedSender<ProgressData>,
futures_sender_big_file: UnboundedSender<ProgressData>,
futures_sender_same_music: UnboundedSender<ProgressData>,
futures_sender_similar_images: UnboundedSender<ProgressData>,
futures_sender_similar_videos: UnboundedSender<ProgressData>,
futures_sender_temporary: UnboundedSender<ProgressData>,
futures_sender_invalid_symlinks: UnboundedSender<ProgressData>,
futures_sender_broken_files: UnboundedSender<ProgressData>,
futures_sender_bad_extensions: UnboundedSender<ProgressData>,
) {
let check_button_settings_one_filesystem = gui_data.settings.check_button_settings_one_filesystem.clone();
let combo_box_image_hash_size = gui_data.main_notebook.combo_box_image_hash_size.clone();

View file

@ -119,6 +119,7 @@ pub fn connect_popover_sort(gui_data: &GuiData) {
#[cfg(test)]
mod test {
use glib::types::Type;
use gtk4::prelude::*;
use gtk4::{Popover, TreeView};
@ -126,7 +127,7 @@ mod test {
#[gtk4::test]
fn test_sort_iters() {
let columns_types: &[glib::types::Type] = &[glib::types::Type::U32, glib::types::Type::STRING];
let columns_types: &[Type] = &[Type::U32, Type::STRING];
let list_store = gtk4::ListStore::new(columns_types);
let values_to_add: &[&[(u32, &dyn ToValue)]] = &[&[(0, &2), (1, &"AAA")], &[(0, &3), (1, &"CCC")], &[(0, &1), (1, &"BBB")]];
@ -156,7 +157,7 @@ mod test {
#[gtk4::test]
pub fn test_popover_sort_general_simple() {
let columns_types: &[glib::types::Type] = &[glib::types::Type::BOOL, glib::types::Type::STRING];
let columns_types: &[Type] = &[Type::BOOL, Type::STRING];
let list_store = gtk4::ListStore::new(columns_types);
let tree_view = TreeView::builder().model(&list_store).build();
let popover = Popover::new();
@ -179,7 +180,7 @@ mod test {
#[gtk4::test]
pub fn test_popover_sort_general() {
let columns_types: &[glib::types::Type] = &[glib::types::Type::BOOL, glib::types::Type::STRING];
let columns_types: &[Type] = &[Type::BOOL, Type::STRING];
let list_store = gtk4::ListStore::new(columns_types);
let tree_view = TreeView::builder().model(&list_store).build();
let popover = Popover::new();

View file

@ -2,8 +2,8 @@ use futures::channel::mpsc::UnboundedReceiver;
use futures::StreamExt;
use gtk4::prelude::*;
use czkawka_core::common_dir_traversal;
use czkawka_core::common_dir_traversal::ProgressData;
use czkawka_core::{big_file, broken_files, common_dir_traversal, similar_images, similar_videos, temporary};
use crate::flg;
use crate::gui_structs::gui_data::GuiData;
@ -16,13 +16,13 @@ pub fn connect_progress_window(
mut futures_receiver_duplicate_files: UnboundedReceiver<ProgressData>,
mut futures_receiver_empty_files: UnboundedReceiver<ProgressData>,
mut futures_receiver_empty_folder: UnboundedReceiver<ProgressData>,
mut futures_receiver_big_files: UnboundedReceiver<big_file::ProgressData>,
mut futures_receiver_big_files: UnboundedReceiver<ProgressData>,
mut futures_receiver_same_music: UnboundedReceiver<ProgressData>,
mut futures_receiver_similar_images: UnboundedReceiver<similar_images::ProgressData>,
mut futures_receiver_similar_videos: UnboundedReceiver<similar_videos::ProgressData>,
mut futures_receiver_temporary: UnboundedReceiver<temporary::ProgressData>,
mut futures_receiver_similar_images: UnboundedReceiver<ProgressData>,
mut futures_receiver_similar_videos: UnboundedReceiver<ProgressData>,
mut futures_receiver_temporary: UnboundedReceiver<ProgressData>,
mut futures_receiver_invalid_symlinks: UnboundedReceiver<ProgressData>,
mut futures_receiver_broken_files: UnboundedReceiver<broken_files::ProgressData>,
mut futures_receiver_broken_files: UnboundedReceiver<ProgressData>,
mut futures_receiver_bad_extensions: UnboundedReceiver<ProgressData>,
) {
let main_context = glib::MainContext::default();
@ -175,7 +175,7 @@ pub fn connect_progress_window(
while let Some(item) = futures_receiver_big_files.next().await {
label_stage.set_text(&flg!(
"progress_scanning_general_file",
generate_translation_hashmap(vec![("file_number", item.files_checked.to_string())])
generate_translation_hashmap(vec![("file_number", item.entries_checked.to_string())])
));
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
@ -257,18 +257,18 @@ pub fn connect_progress_window(
progress_bar_current_stage.hide();
label_stage.set_text(&flg!(
"progress_scanning_general_file",
generate_translation_hashmap(vec![("file_number", item.images_checked.to_string())])
generate_translation_hashmap(vec![("file_number", item.entries_checked.to_string())])
));
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
1 => {
progress_bar_current_stage.show();
if item.images_to_check != 0 {
progress_bar_all_stages.set_fraction((1f64 + (item.images_checked) as f64 / item.images_to_check as f64) / (item.max_stage + 1) as f64);
progress_bar_current_stage.set_fraction((item.images_checked) as f64 / item.images_to_check as f64);
if item.entries_to_check != 0 {
progress_bar_all_stages.set_fraction((1f64 + (item.entries_checked) as f64 / item.entries_to_check as f64) / (item.max_stage + 1) 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.images_to_check + item.images_checked) as u64,
item.images_to_check as u64 * (item.max_stage + 1) as u64,
(item.entries_to_check + item.entries_checked) as u64,
item.entries_to_check as u64 * (item.max_stage + 1) as u64,
);
} else {
progress_bar_all_stages.set_fraction((item.current_stage as f64) / (item.max_stage + 1) as f64);
@ -277,17 +277,17 @@ pub fn connect_progress_window(
}
label_stage.set_text(&flg!(
"progress_scanning_image",
generate_translation_hashmap(vec![("file_checked", item.images_checked.to_string()), ("all_files", item.images_to_check.to_string())])
generate_translation_hashmap(vec![("file_checked", item.entries_checked.to_string()), ("all_files", item.entries_to_check.to_string())])
));
}
2 => {
progress_bar_current_stage.show();
if item.images_to_check != 0 {
progress_bar_all_stages.set_fraction((2f64 + (item.images_checked) as f64 / item.images_to_check as f64) / (item.max_stage + 1) as f64);
progress_bar_current_stage.set_fraction((item.images_checked) as f64 / item.images_to_check as f64);
if item.entries_to_check != 0 {
progress_bar_all_stages.set_fraction((2f64 + (item.entries_checked) as f64 / item.entries_to_check as f64) / (item.max_stage + 1) 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.images_to_check + item.images_checked) as u64,
item.images_to_check as u64 * (item.max_stage + 1) as u64,
(item.entries_to_check + item.entries_checked) as u64,
item.entries_to_check as u64 * (item.max_stage + 1) as u64,
);
} else {
progress_bar_all_stages.set_fraction((item.current_stage as f64) / (item.max_stage + 1) as f64);
@ -296,7 +296,7 @@ pub fn connect_progress_window(
}
label_stage.set_text(&flg!(
"progress_comparing_image_hashes",
generate_translation_hashmap(vec![("file_checked", item.images_checked.to_string()), ("all_files", item.images_to_check.to_string())])
generate_translation_hashmap(vec![("file_checked", item.entries_checked.to_string()), ("all_files", item.entries_to_check.to_string())])
));
}
_ => {
@ -320,18 +320,18 @@ pub fn connect_progress_window(
progress_bar_current_stage.hide();
label_stage.set_text(&flg!(
"progress_scanning_general_file",
generate_translation_hashmap(vec![("file_number", item.videos_checked.to_string())])
generate_translation_hashmap(vec![("file_number", item.entries_checked.to_string())])
));
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
1 => {
progress_bar_current_stage.show();
if item.videos_to_check != 0 {
progress_bar_all_stages.set_fraction((1f64 + (item.videos_checked) as f64 / item.videos_to_check as f64) / (item.max_stage + 1) as f64);
progress_bar_current_stage.set_fraction((item.videos_checked) as f64 / item.videos_to_check as f64);
if item.entries_to_check != 0 {
progress_bar_all_stages.set_fraction((1f64 + (item.entries_checked) as f64 / item.entries_to_check as f64) / (item.max_stage + 1) 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.videos_to_check + item.videos_checked) as u64,
item.videos_to_check as u64 * (item.max_stage + 1) as u64,
(item.entries_to_check + item.entries_checked) as u64,
item.entries_to_check as u64 * (item.max_stage + 1) as u64,
);
} else {
progress_bar_all_stages.set_fraction((1f64) / (item.max_stage + 1) as f64);
@ -340,7 +340,7 @@ pub fn connect_progress_window(
}
label_stage.set_text(&flg!(
"progress_scanning_video",
generate_translation_hashmap(vec![("file_checked", item.videos_checked.to_string()), ("all_files", item.videos_to_check.to_string())])
generate_translation_hashmap(vec![("file_checked", item.entries_checked.to_string()), ("all_files", item.entries_to_check.to_string())])
));
}
_ => {
@ -359,7 +359,7 @@ pub fn connect_progress_window(
while let Some(item) = futures_receiver_temporary.next().await {
label_stage.set_text(&flg!(
"progress_scanning_general_file",
generate_translation_hashmap(vec![("file_number", item.files_checked.to_string())])
generate_translation_hashmap(vec![("file_number", item.entries_checked.to_string())])
));
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
@ -394,18 +394,19 @@ pub fn connect_progress_window(
progress_bar_current_stage.hide();
label_stage.set_text(&flg!(
"progress_scanning_general_file",
generate_translation_hashmap(vec![("file_number", item.files_checked.to_string())])
generate_translation_hashmap(vec![("file_number", item.entries_checked.to_string())])
));
taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE);
}
1 => {
progress_bar_current_stage.show();
if item.files_to_check != 0 {
progress_bar_all_stages.set_fraction((1f64 + (item.files_checked) as f64 / item.files_to_check as f64) / (item.max_stage + 1) as f64);
progress_bar_current_stage.set_fraction((item.files_checked) as f64 / item.files_to_check as f64);
taskbar_state
.borrow()
.set_progress_value((item.files_to_check + item.files_checked) as u64, item.files_to_check as u64 * (item.max_stage + 1) as u64);
if item.entries_to_check != 0 {
progress_bar_all_stages.set_fraction((1f64 + (item.entries_checked) as f64 / item.entries_to_check as f64) / (item.max_stage + 1) 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.entries_to_check + item.entries_checked) as u64,
item.entries_to_check as u64 * (item.max_stage + 1) as u64,
);
} else {
progress_bar_all_stages.set_fraction((1f64) / (item.max_stage + 1) as f64);
progress_bar_current_stage.set_fraction(0f64);
@ -413,7 +414,7 @@ pub fn connect_progress_window(
}
label_stage.set_text(&flg!(
"progress_scanning_broken_files",
generate_translation_hashmap(vec![("file_checked", item.files_checked.to_string()), ("all_files", item.files_to_check.to_string())])
generate_translation_hashmap(vec![("file_checked", item.entries_checked.to_string()), ("all_files", item.entries_to_check.to_string())])
));
}
_ => {

View file

@ -1,5 +1,6 @@
use std::cell::RefCell;
use std::collections::HashMap;
use std::io::BufReader;
use std::rc::Rc;
use crossbeam_channel::bounded;
@ -122,7 +123,7 @@ impl GuiData {
window_main.set_title(Some(&flg!("window_main_title")));
window_main.show();
let pixbuf = Pixbuf::from_read(std::io::BufReader::new(ICON_ABOUT)).unwrap();
let pixbuf = Pixbuf::from_read(BufReader::new(ICON_ABOUT)).unwrap();
window_main.set_application(Some(application));

View file

@ -1,5 +1,6 @@
use std::cmp::Ordering;
use std::collections::HashMap;
use std::io::BufReader;
use std::path::PathBuf;
use gdk4::gdk_pixbuf::{InterpType, Pixbuf};
@ -714,7 +715,7 @@ const TYPE_OF_INTERPOLATION: InterpType = InterpType::Tiles;
pub fn set_icon_of_button<P: IsA<Widget>>(button: &P, data: &'static [u8]) {
let image = get_custom_image_from_widget(&button.clone());
let pixbuf = Pixbuf::from_read(std::io::BufReader::new(data)).unwrap();
let pixbuf = Pixbuf::from_read(BufReader::new(data)).unwrap();
let pixbuf = pixbuf.scale_simple(SIZE_OF_ICON, SIZE_OF_ICON, TYPE_OF_INTERPOLATION).unwrap();
image.set_from_pixbuf(Some(&pixbuf));
}
@ -778,6 +779,7 @@ pub fn scale_step_function(scale: &gtk4::Scale, _scroll_type: ScrollType, value:
#[cfg(test)]
mod test {
use glib::types::Type;
use gtk4::prelude::*;
use gtk4::Orientation;
use image::DynamicImage;
@ -789,7 +791,7 @@ mod test {
#[gtk4::test]
fn test_check_if_list_store_column_have_all_same_values() {
let columns_types: &[glib::types::Type] = &[glib::types::Type::BOOL];
let columns_types: &[Type] = &[Type::BOOL];
let list_store = gtk4::ListStore::new(columns_types);
list_store.clear();
@ -823,7 +825,7 @@ mod test {
#[gtk4::test]
fn test_check_if_value_is_in_list_store() {
let columns_types: &[glib::types::Type] = &[glib::types::Type::STRING];
let columns_types: &[Type] = &[Type::STRING];
let list_store = gtk4::ListStore::new(columns_types);
let values_to_add: &[(u32, &dyn ToValue)] = &[(0, &"Koczkodan"), (0, &"Kachir")];
for i in values_to_add {
@ -833,7 +835,7 @@ mod test {
assert!(check_if_value_is_in_list_store(&list_store, 0, "Kachir"));
assert!(!check_if_value_is_in_list_store(&list_store, 0, "Koczkodan2"));
let columns_types: &[glib::types::Type] = &[glib::types::Type::STRING, glib::types::Type::STRING];
let columns_types: &[Type] = &[Type::STRING, Type::STRING];
let list_store = gtk4::ListStore::new(columns_types);
let values_to_add: &[&[(u32, &dyn ToValue)]] = &[&[(0, &"Koczkodan"), (1, &"Krakus")], &[(0, &"Kachir"), (1, &"Wodnica")]];
for i in values_to_add {

View file

@ -3,6 +3,7 @@ use std::path::Path;
use std::rc::Rc;
use gdk4::gdk_pixbuf::Pixbuf;
use glib::types::Type;
use gtk4::gdk_pixbuf::InterpType;
use gtk4::prelude::*;
use gtk4::{CheckButton, Image, SelectionMode, TextView, TreeView};
@ -304,9 +305,9 @@ pub fn initialize_gui(gui_data: &mut GuiData) {
let evk = gui_data.upper_notebook.evk_tree_view_included_directories.clone();
let gc = gui_data.upper_notebook.gc_tree_view_included_directories.clone();
let col_types: [glib::types::Type; 2] = [
glib::types::Type::STRING, // Path
glib::types::Type::BOOL, // ReferenceButton
let col_types: [Type; 2] = [
Type::STRING, // Path
Type::BOOL, // ReferenceButton
];
let list_store: gtk4::ListStore = gtk4::ListStore::new(&col_types);
@ -341,7 +342,7 @@ pub fn initialize_gui(gui_data: &mut GuiData) {
let evk = gui_data.upper_notebook.evk_tree_view_excluded_directories.clone();
let gc = gui_data.upper_notebook.gc_tree_view_excluded_directories.clone();
let col_types: [glib::types::Type; 1] = [glib::types::Type::STRING];
let col_types: [Type; 1] = [Type::STRING];
let list_store: gtk4::ListStore = gtk4::ListStore::new(&col_types);
tree_view.set_model(Some(&list_store));

View file

@ -5,6 +5,8 @@
#![allow(clippy::type_complexity)]
#![allow(clippy::needless_late_init)]
use futures::channel::mpsc;
use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
use std::env;
use std::ffi::OsString;
@ -32,6 +34,7 @@ use connect_things::connect_settings::*;
use connect_things::connect_show_hide_ui::*;
use connect_things::connect_similar_image_size_change::*;
use czkawka_core::common::{get_number_of_threads, set_number_of_threads};
use czkawka_core::common_dir_traversal::ProgressData;
use czkawka_core::*;
use gui_structs::gui_data::*;
@ -80,50 +83,17 @@ fn build_ui(application: &Application, arguments: &[OsString]) {
let (glib_stop_sender, glib_stop_receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
// Futures progress report
let (futures_sender_duplicate_files, futures_receiver_duplicate_files): (
futures::channel::mpsc::UnboundedSender<common_dir_traversal::ProgressData>,
futures::channel::mpsc::UnboundedReceiver<common_dir_traversal::ProgressData>,
) = futures::channel::mpsc::unbounded();
let (futures_sender_empty_files, futures_receiver_empty_files): (
futures::channel::mpsc::UnboundedSender<common_dir_traversal::ProgressData>,
futures::channel::mpsc::UnboundedReceiver<common_dir_traversal::ProgressData>,
) = futures::channel::mpsc::unbounded();
let (futures_sender_empty_folder, futures_receiver_empty_folder): (
futures::channel::mpsc::UnboundedSender<common_dir_traversal::ProgressData>,
futures::channel::mpsc::UnboundedReceiver<common_dir_traversal::ProgressData>,
) = futures::channel::mpsc::unbounded();
let (futures_sender_big_file, futures_receiver_big_files): (
futures::channel::mpsc::UnboundedSender<big_file::ProgressData>,
futures::channel::mpsc::UnboundedReceiver<big_file::ProgressData>,
) = futures::channel::mpsc::unbounded();
let (futures_sender_same_music, futures_receiver_same_music): (
futures::channel::mpsc::UnboundedSender<common_dir_traversal::ProgressData>,
futures::channel::mpsc::UnboundedReceiver<common_dir_traversal::ProgressData>,
) = futures::channel::mpsc::unbounded();
let (futures_sender_similar_images, futures_receiver_similar_images): (
futures::channel::mpsc::UnboundedSender<similar_images::ProgressData>,
futures::channel::mpsc::UnboundedReceiver<similar_images::ProgressData>,
) = futures::channel::mpsc::unbounded();
let (futures_sender_similar_videos, futures_receiver_similar_videos): (
futures::channel::mpsc::UnboundedSender<similar_videos::ProgressData>,
futures::channel::mpsc::UnboundedReceiver<similar_videos::ProgressData>,
) = futures::channel::mpsc::unbounded();
let (futures_sender_temporary, futures_receiver_temporary): (
futures::channel::mpsc::UnboundedSender<temporary::ProgressData>,
futures::channel::mpsc::UnboundedReceiver<temporary::ProgressData>,
) = futures::channel::mpsc::unbounded();
let (futures_sender_invalid_symlinks, futures_receiver_invalid_symlinks): (
futures::channel::mpsc::UnboundedSender<common_dir_traversal::ProgressData>,
futures::channel::mpsc::UnboundedReceiver<common_dir_traversal::ProgressData>,
) = futures::channel::mpsc::unbounded();
let (futures_sender_broken_files, futures_receiver_broken_files): (
futures::channel::mpsc::UnboundedSender<broken_files::ProgressData>,
futures::channel::mpsc::UnboundedReceiver<broken_files::ProgressData>,
) = futures::channel::mpsc::unbounded();
let (futures_sender_bad_extensions, futures_receiver_bad_extensions): (
futures::channel::mpsc::UnboundedSender<common_dir_traversal::ProgressData>,
futures::channel::mpsc::UnboundedReceiver<common_dir_traversal::ProgressData>,
) = futures::channel::mpsc::unbounded();
let (futures_sender_duplicate_files, futures_receiver_duplicate_files): (UnboundedSender<ProgressData>, UnboundedReceiver<ProgressData>) = mpsc::unbounded();
let (futures_sender_empty_files, futures_receiver_empty_files): (UnboundedSender<ProgressData>, UnboundedReceiver<ProgressData>) = mpsc::unbounded();
let (futures_sender_empty_folder, futures_receiver_empty_folder): (UnboundedSender<ProgressData>, UnboundedReceiver<ProgressData>) = mpsc::unbounded();
let (futures_sender_big_file, futures_receiver_big_files): (UnboundedSender<ProgressData>, UnboundedReceiver<ProgressData>) = mpsc::unbounded();
let (futures_sender_same_music, futures_receiver_same_music): (UnboundedSender<ProgressData>, UnboundedReceiver<ProgressData>) = mpsc::unbounded();
let (futures_sender_similar_images, futures_receiver_similar_images): (UnboundedSender<ProgressData>, UnboundedReceiver<ProgressData>) = mpsc::unbounded();
let (futures_sender_similar_videos, futures_receiver_similar_videos): (UnboundedSender<ProgressData>, UnboundedReceiver<ProgressData>) = mpsc::unbounded();
let (futures_sender_temporary, futures_receiver_temporary): (UnboundedSender<ProgressData>, UnboundedReceiver<ProgressData>) = mpsc::unbounded();
let (futures_sender_invalid_symlinks, futures_receiver_invalid_symlinks): (UnboundedSender<ProgressData>, UnboundedReceiver<ProgressData>) = mpsc::unbounded();
let (futures_sender_broken_files, futures_receiver_broken_files): (UnboundedSender<ProgressData>, UnboundedReceiver<ProgressData>) = mpsc::unbounded();
let (futures_sender_bad_extensions, futures_receiver_bad_extensions): (UnboundedSender<ProgressData>, UnboundedReceiver<ProgressData>) = mpsc::unbounded();
initialize_gui(&mut gui_data);
validate_notebook_data(&gui_data); // Must be run after initialization of gui, to check if everything was properly setup

View file

@ -3,6 +3,7 @@ use crate::help_functions::{
ColumnsSameMusic, ColumnsSimilarImages, ColumnsSimilarVideos, ColumnsTemporaryFiles, PopoverTypes,
};
use crate::notebook_enums::{NotebookMainEnum, NUMBER_OF_NOTEBOOK_MAIN_TABS};
use glib::types::Type;
pub struct NotebookObject {
pub notebook_type: NotebookMainEnum,
@ -16,7 +17,7 @@ pub struct NotebookObject {
pub column_size: Option<i32>,
pub column_size_as_bytes: Option<i32>,
pub column_modification_as_secs: Option<i32>,
pub columns_types: &'static [glib::types::Type],
pub columns_types: &'static [Type],
pub bottom_buttons: &'static [BottomButtonsEnum],
}
@ -41,17 +42,17 @@ pub static NOTEBOOKS_INFO: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [
column_size_as_bytes: Some(ColumnsDuplicates::SizeAsBytes as i32),
column_modification_as_secs: Some(ColumnsDuplicates::ModificationAsSecs as i32),
columns_types: &[
glib::types::Type::BOOL, // ActivatableSelectButton
glib::types::Type::BOOL, // SelectionButton
glib::types::Type::STRING, // Size
glib::types::Type::U64, // SizeAsBytes
glib::types::Type::STRING, // Name
glib::types::Type::STRING, // Path
glib::types::Type::STRING, // Modification
glib::types::Type::U64, // ModificationAsSecs
glib::types::Type::STRING, // Color
glib::types::Type::BOOL, // IsHeader
glib::types::Type::STRING, // TextColor
Type::BOOL, // ActivatableSelectButton
Type::BOOL, // SelectionButton
Type::STRING, // Size
Type::U64, // SizeAsBytes
Type::STRING, // Name
Type::STRING, // Path
Type::STRING, // Modification
Type::U64, // ModificationAsSecs
Type::STRING, // Color
Type::BOOL, // IsHeader
Type::STRING, // TextColor
],
bottom_buttons: &[
BottomButtonsEnum::Save,
@ -76,11 +77,11 @@ pub static NOTEBOOKS_INFO: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [
column_size_as_bytes: None,
column_modification_as_secs: None,
columns_types: &[
glib::types::Type::BOOL, // SelectionButton
glib::types::Type::STRING, // Name
glib::types::Type::STRING, // Path
glib::types::Type::STRING, // Modification
glib::types::Type::U64, // ModificationAsSecs
Type::BOOL, // SelectionButton
Type::STRING, // Name
Type::STRING, // Path
Type::STRING, // Modification
Type::U64, // ModificationAsSecs
],
bottom_buttons: &[BottomButtonsEnum::Save, BottomButtonsEnum::Delete, BottomButtonsEnum::Select, BottomButtonsEnum::Move],
},
@ -97,13 +98,13 @@ pub static NOTEBOOKS_INFO: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [
column_size_as_bytes: None,
column_modification_as_secs: None,
columns_types: &[
glib::types::Type::BOOL, // SelectionButton
glib::types::Type::STRING, // Size
glib::types::Type::STRING, // Name
glib::types::Type::STRING, // Path
glib::types::Type::STRING, // Modification
glib::types::Type::U64, // SizeAsBytes
glib::types::Type::U64, // ModificationAsSecs
Type::BOOL, // SelectionButton
Type::STRING, // Size
Type::STRING, // Name
Type::STRING, // Path
Type::STRING, // Modification
Type::U64, // SizeAsBytes
Type::U64, // ModificationAsSecs
],
bottom_buttons: &[BottomButtonsEnum::Save, BottomButtonsEnum::Delete, BottomButtonsEnum::Select, BottomButtonsEnum::Move],
},
@ -120,11 +121,11 @@ pub static NOTEBOOKS_INFO: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [
column_size_as_bytes: None,
column_modification_as_secs: None,
columns_types: &[
glib::types::Type::BOOL, // SelectionButton
glib::types::Type::STRING, // Name
glib::types::Type::STRING, // Path
glib::types::Type::STRING, // Modification
glib::types::Type::U64, // ModificationAsSecs
Type::BOOL, // SelectionButton
Type::STRING, // Name
Type::STRING, // Path
Type::STRING, // Modification
Type::U64, // ModificationAsSecs
],
bottom_buttons: &[BottomButtonsEnum::Save, BottomButtonsEnum::Delete, BottomButtonsEnum::Select, BottomButtonsEnum::Move],
},
@ -141,11 +142,11 @@ pub static NOTEBOOKS_INFO: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [
column_size_as_bytes: None,
column_modification_as_secs: None,
columns_types: &[
glib::types::Type::BOOL, // SelectionButton
glib::types::Type::STRING, // Name
glib::types::Type::STRING, // Path
glib::types::Type::STRING, // Modification
glib::types::Type::U64, // ModificationAsSecs
Type::BOOL, // SelectionButton
Type::STRING, // Name
Type::STRING, // Path
Type::STRING, // Modification
Type::U64, // ModificationAsSecs
],
bottom_buttons: &[BottomButtonsEnum::Save, BottomButtonsEnum::Delete, BottomButtonsEnum::Select, BottomButtonsEnum::Move],
},
@ -162,19 +163,19 @@ pub static NOTEBOOKS_INFO: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [
column_size_as_bytes: Some(ColumnsSimilarImages::SizeAsBytes as i32),
column_modification_as_secs: Some(ColumnsSimilarImages::ModificationAsSecs as i32),
columns_types: &[
glib::types::Type::BOOL, // ActivatableSelectButton
glib::types::Type::BOOL, // SelectionButton
glib::types::Type::STRING, // Similarity
glib::types::Type::STRING, // Size
glib::types::Type::U64, // SizeAsBytes
glib::types::Type::STRING, // Dimensions
glib::types::Type::STRING, // Name
glib::types::Type::STRING, // Path
glib::types::Type::STRING, // Modification
glib::types::Type::U64, // ModificationAsSecs
glib::types::Type::STRING, // Color
glib::types::Type::BOOL, // IsHeader
glib::types::Type::STRING, // TextColor
Type::BOOL, // ActivatableSelectButton
Type::BOOL, // SelectionButton
Type::STRING, // Similarity
Type::STRING, // Size
Type::U64, // SizeAsBytes
Type::STRING, // Dimensions
Type::STRING, // Name
Type::STRING, // Path
Type::STRING, // Modification
Type::U64, // ModificationAsSecs
Type::STRING, // Color
Type::BOOL, // IsHeader
Type::STRING, // TextColor
],
bottom_buttons: &[
BottomButtonsEnum::Save,
@ -200,17 +201,17 @@ pub static NOTEBOOKS_INFO: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [
column_size_as_bytes: Some(ColumnsSimilarVideos::SizeAsBytes as i32),
column_modification_as_secs: Some(ColumnsSimilarVideos::ModificationAsSecs as i32),
columns_types: &[
glib::types::Type::BOOL, // ActivatableSelectButton
glib::types::Type::BOOL, // SelectionButton
glib::types::Type::STRING, // Size
glib::types::Type::U64, // SizeAsBytes
glib::types::Type::STRING, // Name
glib::types::Type::STRING, // Path
glib::types::Type::STRING, // Modification
glib::types::Type::U64, // ModificationAsSecs
glib::types::Type::STRING, // Color
glib::types::Type::BOOL, // IsHeader
glib::types::Type::STRING, // TextColor
Type::BOOL, // ActivatableSelectButton
Type::BOOL, // SelectionButton
Type::STRING, // Size
Type::U64, // SizeAsBytes
Type::STRING, // Name
Type::STRING, // Path
Type::STRING, // Modification
Type::U64, // ModificationAsSecs
Type::STRING, // Color
Type::BOOL, // IsHeader
Type::STRING, // TextColor
],
bottom_buttons: &[
BottomButtonsEnum::Save,
@ -235,24 +236,24 @@ pub static NOTEBOOKS_INFO: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [
column_size_as_bytes: Some(ColumnsSameMusic::SizeAsBytes as i32),
column_modification_as_secs: Some(ColumnsSameMusic::ModificationAsSecs as i32),
columns_types: &[
glib::types::Type::BOOL, // ActivatableSelectButton
glib::types::Type::BOOL, // SelectionButton
glib::types::Type::STRING, // Size
glib::types::Type::U64, // SizeAsBytes
glib::types::Type::STRING, // Name
glib::types::Type::STRING, // Path
glib::types::Type::STRING, // Title
glib::types::Type::STRING, // Artist
glib::types::Type::STRING, // Year
glib::types::Type::STRING, // Bitrate
glib::types::Type::U64, // BitrateAsNumber
glib::types::Type::STRING, // Length
glib::types::Type::STRING, // Genre
glib::types::Type::STRING, // Modification
glib::types::Type::U64, // ModificationAsSecs
glib::types::Type::STRING, // Color
glib::types::Type::BOOL, // IsHeader
glib::types::Type::STRING, // TextColor
Type::BOOL, // ActivatableSelectButton
Type::BOOL, // SelectionButton
Type::STRING, // Size
Type::U64, // SizeAsBytes
Type::STRING, // Name
Type::STRING, // Path
Type::STRING, // Title
Type::STRING, // Artist
Type::STRING, // Year
Type::STRING, // Bitrate
Type::U64, // BitrateAsNumber
Type::STRING, // Length
Type::STRING, // Genre
Type::STRING, // Modification
Type::U64, // ModificationAsSecs
Type::STRING, // Color
Type::BOOL, // IsHeader
Type::STRING, // TextColor
],
bottom_buttons: &[
BottomButtonsEnum::Save,
@ -277,13 +278,13 @@ pub static NOTEBOOKS_INFO: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [
column_size_as_bytes: None,
column_modification_as_secs: None,
columns_types: &[
glib::types::Type::BOOL, // SelectionButton
glib::types::Type::STRING, // Name
glib::types::Type::STRING, // Path
glib::types::Type::STRING, // DestinationPath
glib::types::Type::STRING, // TypeOfError
glib::types::Type::STRING, // Modification
glib::types::Type::U64, // ModificationAsSecs
Type::BOOL, // SelectionButton
Type::STRING, // Name
Type::STRING, // Path
Type::STRING, // DestinationPath
Type::STRING, // TypeOfError
Type::STRING, // Modification
Type::U64, // ModificationAsSecs
],
bottom_buttons: &[BottomButtonsEnum::Save, BottomButtonsEnum::Delete, BottomButtonsEnum::Select, BottomButtonsEnum::Move],
},
@ -300,12 +301,12 @@ pub static NOTEBOOKS_INFO: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [
column_size_as_bytes: None,
column_modification_as_secs: None,
columns_types: &[
glib::types::Type::BOOL, // SelectionButton
glib::types::Type::STRING, // Name
glib::types::Type::STRING, // Path
glib::types::Type::STRING, // ErrorType
glib::types::Type::STRING, // Modification
glib::types::Type::U64, // ModificationAsSecs
Type::BOOL, // SelectionButton
Type::STRING, // Name
Type::STRING, // Path
Type::STRING, // ErrorType
Type::STRING, // Modification
Type::U64, // ModificationAsSecs
],
bottom_buttons: &[BottomButtonsEnum::Save, BottomButtonsEnum::Delete, BottomButtonsEnum::Select, BottomButtonsEnum::Move],
},
@ -322,13 +323,13 @@ pub static NOTEBOOKS_INFO: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [
column_size_as_bytes: None,
column_modification_as_secs: None,
columns_types: &[
glib::types::Type::BOOL, // SelectionButton
glib::types::Type::STRING, // Name
glib::types::Type::STRING, // Path
glib::types::Type::STRING, // CurrentExtension
glib::types::Type::STRING, // ProperExtensions
glib::types::Type::STRING, // Modification
glib::types::Type::U64, // ModificationAsSecs
Type::BOOL, // SelectionButton
Type::STRING, // Name
Type::STRING, // Path
Type::STRING, // CurrentExtension
Type::STRING, // ProperExtensions
Type::STRING, // Modification
Type::U64, // ModificationAsSecs
],
bottom_buttons: &[BottomButtonsEnum::Save, BottomButtonsEnum::Delete, BottomButtonsEnum::Select, BottomButtonsEnum::Move],
},