diff --git a/Cargo.lock b/Cargo.lock index 3d58dfe..8962da8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -504,6 +504,7 @@ dependencies = [ "rayon", "rodio", "serde", + "serde_json", "tempfile", "vid_dup_finder_lib", "xxhash-rust", @@ -1183,9 +1184,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.108" +version = "0.2.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119" +checksum = "f98a04dce437184842841303488f70d0188c5f51437d2a834dc097eafa909a01" [[package]] name = "libloading" @@ -1232,9 +1233,9 @@ checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "memoffset" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" dependencies = [ "autocfg", ] diff --git a/czkawka_core/Cargo.toml b/czkawka_core/Cargo.toml index e1411de..d9a067f 100644 --- a/czkawka_core/Cargo.toml +++ b/czkawka_core/Cargo.toml @@ -44,8 +44,11 @@ tempfile = "3.2.0" # Video Duplactes vid_dup_finder_lib = "0.1.0" ffmpeg_cmdline_utils = "0.1.0" + +# Saving/Loading Cache serde = "1.0.130" bincode = "1.3.3" +serde_json = "1.0.72" [features] diff --git a/czkawka_core/src/similar_videos.rs b/czkawka_core/src/similar_videos.rs index fc91580..5fd0f28 100644 --- a/czkawka_core/src/similar_videos.rs +++ b/czkawka_core/src/similar_videos.rs @@ -423,7 +423,7 @@ impl SimilarVideos { Ok(t) => t, Err(e) => { return { - file_entry.error = format!("Failed to hash file, {}", e); + file_entry.error = format!("Failed to hash file, reason {}", e); Some(file_entry) } } @@ -592,14 +592,6 @@ impl PrintResults for SimilarVideos { pub fn save_hashes_to_file(hashmap: &BTreeMap, text_messages: &mut Messages) { if let Some(proj_dirs) = ProjectDirs::from("pl", "Qarmin", "Czkawka") { - // Lin: /home/username/.cache/czkawka - // Win: C:\Users\Username\AppData\Local\Qarmin\Czkawka\cache - // Mac: /Users/Username/Library/Caches/pl.Qarmin.Czkawka - - // Saves data - // path//file_size//modified_date//num_frames//duration//hash1//hash2 etc. - // number of hashes is equal to HASH_QWORDS(19 at this moment) - let cache_dir = PathBuf::from(proj_dirs.cache_dir()); if cache_dir.exists() { if !cache_dir.is_dir() { @@ -610,7 +602,8 @@ pub fn save_hashes_to_file(hashmap: &BTreeMap, text_messages: text_messages.messages.push(format!("Cannot create config dir {}, reason {}", cache_dir.display(), e)); return; } - let cache_file = cache_dir.join("cache_similar_videos.bin"); + + let cache_file = cache_dir.join(cache_dir.join(get_cache_file())); let file_handler = match OpenOptions::new().truncate(true).write(true).create(true).open(&cache_file) { Ok(t) => t, Err(e) => { @@ -620,25 +613,43 @@ pub fn save_hashes_to_file(hashmap: &BTreeMap, text_messages: }; let writer = BufWriter::new(file_handler); + #[cfg(not(debug_assertions))] if let Err(e) = bincode::serialize_into(writer, hashmap) { - text_messages.messages.push(format!("cannot write data to cache file {}, reason {}", cache_file.display(), e)); + text_messages.messages.push(format!("Cannot write data to cache file {}, reason {}", cache_file.display(), e)); + return; } + #[cfg(debug_assertions)] + if let Err(e) = serde_json::to_writer(writer, hashmap) { + text_messages.messages.push(format!("Cannot write data to cache file {}, reason {}", cache_file.display(), e)); + return; + } + + text_messages.messages.push(format!("Properly saved to file {} cache entries.", hashmap.len())); } } pub fn load_hashes_from_file(text_messages: &mut Messages, delete_outdated_cache: bool) -> Option> { if let Some(proj_dirs) = ProjectDirs::from("pl", "Qarmin", "Czkawka") { let cache_dir = PathBuf::from(proj_dirs.cache_dir()); - let cache_file = cache_dir.join("cache_similar_videos.bin"); + let cache_file = cache_dir.join(get_cache_file()); let file_handler = match OpenOptions::new().read(true).open(&cache_file) { Ok(t) => t, Err(_inspected) => { - // text_messages.messages.push(format!("Cannot find or open cache file {}", cache_file.display())); // This shouldn't be write to output + // text_messages.messages.push(format!("Cannot find or open cache file {}", cache_file.display())); // No error warning return None; } }; let reader = BufReader::new(file_handler); + #[cfg(debug_assertions)] + let mut hashmap_loaded_entries: BTreeMap = match serde_json::from_reader(reader) { + Ok(t) => t, + Err(e) => { + text_messages.warnings.push(format!("Failed to load data from cache file {}, reason {}", cache_file.display(), e)); + return None; + } + }; + #[cfg(not(debug_assertions))] let mut hashmap_loaded_entries: BTreeMap = match bincode::deserialize_from(reader) { Ok(t) => t, Err(e) => { @@ -648,15 +659,33 @@ pub fn load_hashes_from_file(text_messages: &mut Messages, delete_outdated_cache }; // Don't load cache data if destination file not exists - hashmap_loaded_entries.retain(|src_path, _file_entry| Path::new(src_path).exists() && !delete_outdated_cache); + if delete_outdated_cache { + hashmap_loaded_entries.retain(|src_path, _file_entry| Path::new(src_path).exists()); + } + + text_messages.messages.push(format!("Properly loaded {} cache entries.", hashmap_loaded_entries.len())); return Some(hashmap_loaded_entries); } - text_messages.messages.push("Cannot find or open system config dir to save cache file".to_string()); + text_messages.messages.push("Cannot find or open system config dir to save cache file.".to_string()); None } +fn get_cache_file() -> String { + let extension; + #[cfg(debug_assertions)] + { + extension = "json"; + } + #[cfg(not(debug_assertions))] + { + extension = "bin"; + } + + format!("cache_similar_videos.{}", extension) +} + pub fn check_if_ffmpeg_is_installed() -> bool { let vid = "999999999999999999.txt"; if let Err(DetermineVideo { src_path: _a, error: FfmpegNotFound }) = VideoHash::from_path(&vid) { diff --git a/czkawka_gui/src/connect_button_hardlink.rs b/czkawka_gui/src/connect_button_hardlink.rs index 324a73f..0564e48 100644 --- a/czkawka_gui/src/connect_button_hardlink.rs +++ b/czkawka_gui/src/connect_button_hardlink.rs @@ -11,15 +11,18 @@ use crate::help_functions::*; use crate::notebook_enums::*; pub fn connect_button_hardlink_symlink(gui_data: &GuiData) { + // Hardlinking { let buttons_hardlink = gui_data.bottom_buttons.buttons_hardlink.clone(); let gui_data = gui_data.clone(); buttons_hardlink.connect_clicked(move |_| { - glib::MainContext::default().spawn_local(sym_hard_link_things(gui_data.clone(), false)); + glib::MainContext::default().spawn_local(sym_hard_link_things(gui_data.clone(), true)); }); } + + // Symlinking { let buttons_symlink = gui_data.bottom_buttons.buttons_symlink.clone(); @@ -46,7 +49,7 @@ pub async fn sym_hard_link_things(gui_data: GuiData, hardlinking: bool) { let tree_view = &main_tree_views[nb_number as usize]; let nb_object = &NOTEBOOKS_INFOS[nb_number as usize]; - let column_color = nb_object.column_color.expect("Symlinking can be only used for tree views with grouped results"); + let column_color = nb_object.column_color.expect("Linking can be only used for tree views with grouped results"); let check_button_settings_confirm_link = gui_data.settings.check_button_settings_confirm_link.clone(); @@ -57,6 +60,7 @@ pub async fn sym_hard_link_things(gui_data: GuiData, hardlinking: bool) { if !check_if_can_link_files(&check_button_settings_confirm_link, &window_main).await { return; } + if !check_if_changing_one_item_in_group_and_continue(tree_view, column_color, nb_object.column_selection, &window_main).await { return; } diff --git a/czkawka_gui/src/connect_button_select.rs b/czkawka_gui/src/connect_button_select.rs index 920c4ae..aba1b92 100644 --- a/czkawka_gui/src/connect_button_select.rs +++ b/czkawka_gui/src/connect_button_select.rs @@ -1,41 +1,23 @@ -use std::collections::HashMap; - use gtk::prelude::*; use crate::gui_data::GuiData; use crate::gui_popovers::GuiPopovers; -use crate::help_functions::PopoverTypes; +use crate::help_functions::{PopoverTypes, NOTEBOOKS_INFOS}; use crate::notebook_enums::*; pub fn connect_button_select(gui_data: &GuiData) { - let mut hashmap: HashMap> = Default::default(); - { - hashmap.insert(NotebookMainEnum::SimilarImages, vec![PopoverTypes::All, PopoverTypes::Size, PopoverTypes::Reverse, PopoverTypes::Custom, PopoverTypes::Date]); - hashmap.insert(NotebookMainEnum::SimilarVideos, vec![PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom, PopoverTypes::Date, PopoverTypes::Size]); - hashmap.insert(NotebookMainEnum::Duplicate, vec![PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom, PopoverTypes::Date]); - hashmap.insert(NotebookMainEnum::SameMusic, vec![PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom, PopoverTypes::Date, PopoverTypes::Size]); - - hashmap.insert(NotebookMainEnum::EmptyFiles, vec![PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom]); - hashmap.insert(NotebookMainEnum::EmptyDirectories, vec![PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom]); - hashmap.insert(NotebookMainEnum::BigFiles, vec![PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom]); - hashmap.insert(NotebookMainEnum::Symlinks, vec![PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom]); - hashmap.insert(NotebookMainEnum::Temporary, vec![PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom]); - hashmap.insert(NotebookMainEnum::BrokenFiles, vec![PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom]); - } - assert_eq!(hashmap.len(), NUMBER_OF_NOTEBOOK_MAIN_TABS); - let popovers = gui_data.popovers.clone(); let notebook_main = gui_data.main_notebook.notebook_main.clone(); let popover_select = gui_data.popovers.popover_select.clone(); let buttons_select = gui_data.bottom_buttons.buttons_select.clone(); buttons_select.connect_clicked(move |_| { - show_required_popovers(&popovers, &to_notebook_main_enum(notebook_main.current_page().unwrap()), &hashmap); + show_required_popovers(&popovers, &to_notebook_main_enum(notebook_main.current_page().unwrap())); popover_select.popup(); }); } -fn show_required_popovers(popovers: &GuiPopovers, current_mode: &NotebookMainEnum, hashmap: &HashMap>) { +fn show_required_popovers(popovers: &GuiPopovers, current_mode: &NotebookMainEnum) { let buttons_popover_select_all = popovers.buttons_popover_select_all.clone(); let buttons_popover_unselect_all = popovers.buttons_popover_unselect_all.clone(); let buttons_popover_reverse = popovers.buttons_popover_reverse.clone(); @@ -53,9 +35,9 @@ fn show_required_popovers(popovers: &GuiPopovers, current_mode: &NotebookMainEnu let separator_select_image_size = popovers.separator_select_image_size.clone(); let separator_select_reverse = popovers.separator_select_reverse.clone(); - let vec = hashmap.get(current_mode).unwrap(); + let arr = &NOTEBOOKS_INFOS[current_mode.clone() as usize].available_modes; - if vec.contains(&PopoverTypes::All) { + if arr.contains(&PopoverTypes::All) { buttons_popover_select_all.show(); buttons_popover_unselect_all.show(); } else { @@ -63,7 +45,7 @@ fn show_required_popovers(popovers: &GuiPopovers, current_mode: &NotebookMainEnu buttons_popover_unselect_all.hide(); } - if vec.contains(&PopoverTypes::Size) { + if arr.contains(&PopoverTypes::Size) { buttons_popover_select_all_images_except_biggest.show(); buttons_popover_select_all_images_except_smallest.show(); separator_select_image_size.show(); @@ -73,7 +55,7 @@ fn show_required_popovers(popovers: &GuiPopovers, current_mode: &NotebookMainEnu separator_select_image_size.hide(); } - if vec.contains(&PopoverTypes::Reverse) { + if arr.contains(&PopoverTypes::Reverse) { buttons_popover_reverse.show(); separator_select_reverse.show(); } else { @@ -81,7 +63,7 @@ fn show_required_popovers(popovers: &GuiPopovers, current_mode: &NotebookMainEnu separator_select_reverse.hide(); } - if vec.contains(&PopoverTypes::Custom) { + if arr.contains(&PopoverTypes::Custom) { buttons_popover_select_custom.show(); buttons_popover_unselect_custom.show(); separator_select_custom.show(); @@ -91,7 +73,7 @@ fn show_required_popovers(popovers: &GuiPopovers, current_mode: &NotebookMainEnu separator_select_custom.hide(); } - if vec.contains(&PopoverTypes::Date) { + if arr.contains(&PopoverTypes::Date) { buttons_popover_select_all_except_oldest.show(); buttons_popover_select_all_except_newest.show(); buttons_popover_select_one_oldest.show(); diff --git a/czkawka_gui/src/help_functions.rs b/czkawka_gui/src/help_functions.rs index 34a7a85..206d8b2 100644 --- a/czkawka_gui/src/help_functions.rs +++ b/czkawka_gui/src/help_functions.rs @@ -42,7 +42,7 @@ pub enum PopoverTypes { pub struct NotebookObject { pub notebook_type: NotebookMainEnum, - pub available_modes: [PopoverTypes; 4], + pub available_modes: [PopoverTypes; 5], pub column_activatable_button: Option, pub column_path: i32, pub column_name: i32, @@ -57,7 +57,7 @@ pub struct NotebookObject { pub static NOTEBOOKS_INFOS: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [ NotebookObject { notebook_type: NotebookMainEnum::Duplicate, - available_modes: [PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom, PopoverTypes::Date], + available_modes: [PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom, PopoverTypes::Date, PopoverTypes::None], column_activatable_button: Some(ColumnsDuplicates::ActivatableSelectButton as i32), column_path: ColumnsDuplicates::Path as i32, column_name: ColumnsDuplicates::Name as i32, @@ -70,7 +70,7 @@ pub static NOTEBOOKS_INFOS: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [ }, NotebookObject { notebook_type: NotebookMainEnum::EmptyDirectories, - available_modes: [PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom, PopoverTypes::None], + available_modes: [PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom, PopoverTypes::None, PopoverTypes::None], column_activatable_button: None, column_path: ColumnsEmptyFolders::Path as i32, column_name: ColumnsEmptyFolders::Name as i32, @@ -83,7 +83,7 @@ pub static NOTEBOOKS_INFOS: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [ }, NotebookObject { notebook_type: NotebookMainEnum::BigFiles, - available_modes: [PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom, PopoverTypes::None], + available_modes: [PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom, PopoverTypes::None, PopoverTypes::None], column_activatable_button: None, column_path: ColumnsBigFiles::Path as i32, column_name: ColumnsBigFiles::Name as i32, @@ -96,7 +96,7 @@ pub static NOTEBOOKS_INFOS: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [ }, NotebookObject { notebook_type: NotebookMainEnum::EmptyFiles, - available_modes: [PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom, PopoverTypes::None], + available_modes: [PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom, PopoverTypes::None, PopoverTypes::None], column_activatable_button: None, column_path: ColumnsEmptyFiles::Path as i32, column_name: ColumnsEmptyFiles::Name as i32, @@ -109,7 +109,7 @@ pub static NOTEBOOKS_INFOS: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [ }, NotebookObject { notebook_type: NotebookMainEnum::Temporary, - available_modes: [PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom, PopoverTypes::None], + available_modes: [PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom, PopoverTypes::None, PopoverTypes::None], column_activatable_button: None, column_path: ColumnsTemporaryFiles::Path as i32, column_name: ColumnsTemporaryFiles::Name as i32, @@ -122,7 +122,7 @@ pub static NOTEBOOKS_INFOS: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [ }, NotebookObject { notebook_type: NotebookMainEnum::SimilarImages, - available_modes: [PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom, PopoverTypes::Date], + available_modes: [PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom, PopoverTypes::Date, PopoverTypes::Size], column_activatable_button: Some(ColumnsSimilarImages::ActivatableSelectButton as i32), column_path: ColumnsSimilarImages::Path as i32, column_name: ColumnsSimilarImages::Name as i32, @@ -135,7 +135,7 @@ pub static NOTEBOOKS_INFOS: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [ }, NotebookObject { notebook_type: NotebookMainEnum::SimilarVideos, - available_modes: [PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom, PopoverTypes::Date], + available_modes: [PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom, PopoverTypes::Date, PopoverTypes::Size], column_activatable_button: Some(ColumnsSimilarVideos::ActivatableSelectButton as i32), column_path: ColumnsSimilarVideos::Path as i32, column_name: ColumnsSimilarVideos::Name as i32, @@ -148,7 +148,7 @@ pub static NOTEBOOKS_INFOS: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [ }, NotebookObject { notebook_type: NotebookMainEnum::SameMusic, - available_modes: [PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom, PopoverTypes::Date], + available_modes: [PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom, PopoverTypes::Date, PopoverTypes::Size], column_activatable_button: Some(ColumnsSameMusic::ActivatableSelectButton as i32), column_path: ColumnsSameMusic::Path as i32, column_name: ColumnsSameMusic::Name as i32, @@ -161,7 +161,7 @@ pub static NOTEBOOKS_INFOS: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [ }, NotebookObject { notebook_type: NotebookMainEnum::Symlinks, - available_modes: [PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom, PopoverTypes::None], + available_modes: [PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom, PopoverTypes::None, PopoverTypes::None], column_activatable_button: None, column_path: ColumnsInvalidSymlinks::Path as i32, column_name: ColumnsInvalidSymlinks::Name as i32, @@ -174,7 +174,7 @@ pub static NOTEBOOKS_INFOS: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [ }, NotebookObject { notebook_type: NotebookMainEnum::BrokenFiles, - available_modes: [PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom, PopoverTypes::None], + available_modes: [PopoverTypes::All, PopoverTypes::Reverse, PopoverTypes::Custom, PopoverTypes::None, PopoverTypes::None], column_activatable_button: None, column_path: ColumnsBrokenFiles::Path as i32, column_name: ColumnsBrokenFiles::Name as i32, @@ -357,33 +357,37 @@ pub fn split_path(path: &Path) -> (String, String) { pub fn print_text_messages_to_text_view(text_messages: &Messages, text_view: >k::TextView) { let mut messages: String = String::from(""); if !text_messages.messages.is_empty() { - messages += "############### MESSAGES ###############\n"; + messages += format!("############### MESSAGES({}) ###############\n", text_messages.messages.len()).as_str(); } for text in &text_messages.messages { messages += text.as_str(); messages += "\n"; } - if !text_messages.messages.is_empty() { - messages += "\n"; - } + // if !text_messages.messages.is_empty() { + // messages += "\n"; + // } if !text_messages.warnings.is_empty() { - messages += "############### WARNINGS ###############\n"; + messages += format!("############### WARNINGS({}) ###############\n", text_messages.warnings.len()).as_str(); } for text in &text_messages.warnings { messages += text.as_str(); messages += "\n"; } - if !text_messages.warnings.is_empty() { - messages += "\n"; - } + // if !text_messages.warnings.is_empty() { + // messages += "\n"; + // } if !text_messages.errors.is_empty() { - messages += "############### ERRORS ###############\n"; + messages += format!("############### ERRORS({}) ###############\n", text_messages.errors.len()).as_str(); } for text in &text_messages.errors { messages += text.as_str(); messages += "\n"; } - if !text_messages.errors.is_empty() { + // if !text_messages.errors.is_empty() { + // messages += "\n"; + // } + + if !text_messages.messages.is_empty() || !text_messages.warnings.is_empty() || !text_messages.errors.is_empty() { messages += "\n"; } diff --git a/instructions/Compilation.md b/instructions/Compilation.md index 25f3cf0..bfaf652 100644 --- a/instructions/Compilation.md +++ b/instructions/Compilation.md @@ -1,10 +1,10 @@ # Compiling Czkawka from sources ## Requirements -Program | Min | What for ----------|------|------------------------------------------------------------ -Rust | 1.53 | Czkawka, aims to support the latest available version of Rust on Ubuntu 20.04 -GTK | 3.22 | Only for the `GTK` backend +| Program | Min | What for | +|---------|------|-------------------------------------------------------------------------------| +| Rust | 1.53 | Czkawka, aims to support the latest available version of Rust on Ubuntu 20.04 | +| GTK | 3.24 | Only for the `GTK` backend | If you only want the terminal version without a GUI, just skip all the packages with `gtk` in their names. diff --git a/instructions/Installation.md b/instructions/Installation.md index c65e03a..0c59076 100644 --- a/instructions/Installation.md +++ b/instructions/Installation.md @@ -3,7 +3,7 @@ ### Linux If you use Snap, Flatpak or Appimage, you need to only install ffmpeg if you want to use Similar Videos tool. -For Czkawka GUI you are required to have at least `GTK 3.22` and also `Alsa` installed (for finding broken music files, but it is disabled by default). +For Czkawka GUI you are required to have at least `GTK 3.24` and also `Alsa` installed (for finding broken music files, but it is disabled by default). `FFmpeg` in Similar Videos is non required dependency - app will work, but this tool will throw errors, so I recommend to install it. It should be installed by default on all the most popular distros. #### Ubuntu/Debian/Linux Mint @@ -78,7 +78,7 @@ You can update the package with the same command. ``` sudo snap install czkawka ``` -By default, Snap can only access the files in your home directory. You have to allow czkawka access to all the drives: +By default, Snap can only access the files in your home directory. You have to allow Czkawka access to all the drives: ``` sudo snap connect czkawka:removable-media diff --git a/instructions/Instruction.md b/instructions/Instruction.md index 24ac191..b5ce785 100644 --- a/instructions/Instruction.md +++ b/instructions/Instruction.md @@ -70,6 +70,7 @@ Currently, Czkawka stores few config and cache files on disk: - `cache_similar_image_SIZE_HASH_FILTER.txt` - stores cache data and hashes which may be used later without needing to compute image hash again - editing this file manually is not recommended, but it is allowed. Each algorithms uses its own file, because hashes are completely different in each. - `cache_broken_files.txt` - stores cache data of broken files - `cache_duplicates_Blake3.txt` - stores cache data of duplicated files, to not suffer too big of a performance hit when saving/loading file, only already fully hashed files bigger than 5MB are stored. Similar files with replaced `Blake3` to e.g. `SHA256` may be shown, when support for new hashes will be introduced in Czkawka. +- `cache_similar_videos.bin/json` - stores cache data of video files. Depending on usage(debug/release build) it will produce bin file(fast, but unable to change) or json(slow, but well formatted). Config files are located in this path: @@ -203,7 +204,7 @@ It is a tool for finding similar images that differ e.g. in watermark, size etc. The tool first collects images with specific extensions that can be checked - `[".jpg", ".jpeg", ".png", ".bmp", ".tiff", ".tif", ".pnm", ".tga", ".ff", ".gif", ".jif", ".jfi", ".ico", ".webp", ".avif"]`. Next cached data is loaded from file to prevent hashing twice the same file. -The cache which points to non existing data is deleted automatically. +The cache which points to non existing data, by default is deleted automatically. Then a perceptual hash is created for each image which isn't available in cache. @@ -229,7 +230,7 @@ Before calculating hashes usually images are resized with specific algorithm(`La Each configuration saves results to different cache files to save users from invalid results. -Some images broke hash functions and create hashes full of `0` or `255`, so these images are silently excluded(probably proper error reporting should be provided). +Some images broke hash functions and create hashes full of `0` or `255`, so these images are silently excluded from end results(but still are saved to cache). You can test each algorithm with provided CLI tool, just put to folder `test.jpg` file and run inside this command `czkawka_cli tester -i`