diff --git a/.gitignore b/.gitignore index 1dcc1b6..b8a2aef 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ results*.txt TestSuite* *.snap +flatpak/ diff --git a/Cargo.lock b/Cargo.lock index 22ef132..df1fd0a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -47,9 +47,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.45" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee10e43ae4a853c0a3591d4e2ada1719e553be18199d9da9d4a83f5927c2f5c7" +checksum = "62e1f47f7dc0422027a4e370dd4548d4d66b26782e513e98dca1e689e058a80e" [[package]] name = "arrayref" @@ -476,6 +476,7 @@ dependencies = [ "crc32fast", "crossbeam-channel", "directories-next", + "ffmpeg_cmdline_utils", "futures", "hamming", "humansize", @@ -484,6 +485,7 @@ dependencies = [ "rayon", "rodio", "tempfile", + "vid_dup_finder_lib", "xxhash-rust", "zip", ] @@ -601,6 +603,19 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +[[package]] +name = "ffmpeg_cmdline_utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f156b1f5ba5f16135ec1efd32d9f90d0dad3ef8f8b77ca9928d4d0e3b24dd41" +dependencies = [ + "image", + "rayon", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "field-offset" version = "0.3.4" @@ -1051,7 +1066,7 @@ checksum = "5ea4eac6fc4f64ed363d5c210732b747bfa5ddd8a25ac347d887f298c3a70b49" dependencies = [ "base64", "image", - "rustdct", + "rustdct 0.4.0", "serde", "transpose 0.2.1", ] @@ -1074,6 +1089,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + [[package]] name = "jni" version = "0.19.0" @@ -1146,15 +1167,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.107" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219" +checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119" [[package]] name = "libloading" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0cf036d15402bea3c5d4de17b3fce76b3e4a56ebc1f577be0e7a72f7c607cf0" +checksum = "afe203d669ec979b7128619bae5a63b7b42e9203c1b29146079ee05e2f604b52" dependencies = [ "cfg-if", "winapi", @@ -1336,9 +1357,9 @@ dependencies = [ [[package]] name = "ndk-sys" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c44922cb3dbb1c70b5e5f443d63b64363a898564d739ba5198e3a9138442868d" +checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121" [[package]] name = "nix" @@ -1372,6 +1393,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-complex" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5" +dependencies = [ + "num-traits", +] + [[package]] name = "num-derive" version = "0.3.3" @@ -1611,6 +1641,15 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" +[[package]] +name = "primal-check" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01419cee72c1a1ca944554e23d83e483e1bccf378753344e881de28b5487511d" +dependencies = [ + "num-integer", +] + [[package]] name = "proc-macro-crate" version = "0.1.5" @@ -1826,7 +1865,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef4d167674b4cf68c2114bdbcd34c95aa9071652b73b0f43b19298f1d2780b7d" dependencies = [ - "rustfft", + "rustfft 3.0.1", +] + +[[package]] +name = "rustdct" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fadcb505b98aa64da1dadb1498b912e3642aae4606623cb3ae952cd8da33f80d" +dependencies = [ + "rustfft 5.1.1", ] [[package]] @@ -1835,13 +1883,33 @@ version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77008ed59a8923c8b4ac2e5eaa6d28fbe893d3b9515098a4a5fc7767d6430fe5" dependencies = [ - "num-complex", + "num-complex 0.2.4", "num-integer", "num-traits", "strength_reduce", "transpose 0.1.0", ] +[[package]] +name = "rustfft" +version = "5.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1869bb2a6ff77380d52ff4bc631f165637035a55855c76aa462c85474dadc42f" +dependencies = [ + "num-complex 0.3.1", + "num-integer", + "num-traits", + "primal-check", + "strength_reduce", + "transpose 0.2.1", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + [[package]] name = "same-file" version = "1.0.6" @@ -1901,6 +1969,17 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063bf466a64011ac24040a49009724ee60a57da1b437617ceb32e53ad61bfb19" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "shlex" version = "0.1.1" @@ -2193,6 +2272,22 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +[[package]] +name = "vid_dup_finder_lib" +version = "0.1.0" +source = "git+https://github.com/qarmin/vid_dup_finder_lib#a4809772aea8f73c9a22da6fb43df50bfdd1b31d" +dependencies = [ + "ffmpeg_cmdline_utils", + "image", + "rand", + "rayon", + "rustdct 0.6.0", + "serde", + "serde_json", + "thiserror", + "transpose 0.2.1", +] + [[package]] name = "walkdir" version = "2.3.2" diff --git a/Changelog.md b/Changelog.md index da1bf45..b2e914d 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,6 @@ ## Version 3.3.1 - 22.11.2021r - +- Fix crash when moving buttons [#457](https://github.com/qarmin/czkawka/pull/457) +- Hide move button at start [c9ca230](https://github.com/qarmin/czkawka/commit/c9ca230dfd05e2166b2d68683b091cfd45037edd) ## Version 3.3.0 - 20.11.2021r - Select files by pressing space key [#415](https://github.com/qarmin/czkawka/pull/415) diff --git a/README.md b/README.md index 6e9da44..544b9e1 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ - Empty Files - Looks for empty files across the drive - Temporary Files - Finds temporary files - Similar Images - Finds images which are not exactly the same (different resolution, watermarks) + - Similar Videos - Looks for similar visually videos - Zeroed Files - Finds files which are filled with zeros (usually corrupted) - Same Music - Searches for music with the same artist, album etc. - Invalid Symbolic Links - Shows symbolic links which point to non-existent files/directories @@ -101,10 +102,11 @@ Bleachbit is a master at finding and removing temporary files, while Czkawka onl | Temporary files | • | • | | • | | Big files | • | | | | | Similar images | • | | • | | -| Zeroed Files | • | | | | +| Similar videos | • | | | | +| Zeroed files | • | | | | | Music duplicates(tags) | • | | • | | | Invalid symlinks | • | • | | | -| Broken Files | • | | | | +| Broken files | • | | | | | Names conflict | • | • | | | | Installed packages | | • | | | | Invalid names | | • | | | diff --git a/czkawka_cli/src/commands.rs b/czkawka_cli/src/commands.rs index 3378b18..3b111a9 100644 --- a/czkawka_cli/src/commands.rs +++ b/czkawka_cli/src/commands.rs @@ -123,7 +123,7 @@ pub enum Commands { not_recursive: NotRecursive, #[structopt(short = "g", long, default_value = "Gradient", parse(try_from_str = parse_similar_hash_algorithm), help="Hash algorithm (allowed: Mean, Gradient, Blockhash, VertGradient, DoubleGradient)")] hash_alg: HashAlg, - #[structopt(short = "f", long, default_value = "Lanczos3", parse(try_from_str = parse_similar_image_filter), help="Hash algorithm (allowed: Lanczos3, Nearest, Triangle, Faussian, Catmullrom)")] + #[structopt(short = "z", long, default_value = "Lanczos3", parse(try_from_str = parse_similar_image_filter), help="Hash algorithm (allowed: Lanczos3, Nearest, Triangle, Faussian, Catmullrom)")] image_filter: FilterType, #[structopt(short = "c", long, default_value = "8", parse(try_from_str = parse_image_hash_size), help="Hash size (allowed: 4, 8, 16)")] hash_size: u8, @@ -204,6 +204,29 @@ pub enum Commands { #[structopt(flatten)] not_recursive: NotRecursive, }, + #[structopt(name = "video", about = "Finds similar video files", help_message = HELP_MESSAGE, after_help = "EXAMPLE:\n czkawka videos -d /home/rafal -f results.txt")] + SimilarVideos { + #[structopt(flatten)] + directories: Directories, + #[structopt(flatten)] + excluded_directories: ExcludedDirectories, + #[structopt(flatten)] + excluded_items: ExcludedItems, + // #[structopt(short = "D", long, help = "Delete found files")] + // delete_files: bool, TODO + #[structopt(flatten)] + file_to_save: FileToSave, + #[structopt(flatten)] + allowed_extensions: AllowedExtensions, + #[structopt(flatten)] + not_recursive: NotRecursive, + #[structopt(short, long, parse(try_from_str = parse_minimal_file_size), default_value = "8192", help = "Minimum size in bytes", long_help = "Minimum size of checked files in bytes, assigning bigger value may speed up searching")] + minimal_file_size: u64, + #[structopt(short = "i", long, parse(try_from_str = parse_maximal_file_size), default_value = "18446744073709551615", help = "Maximum size in bytes", long_help = "Maximum size of checked files in bytes, assigning lower value may speed up searching")] + maximal_file_size: u64, + #[structopt(short = "t", long, parse(try_from_str = parse_tolerance), default_value = "10", help = "Video maximium difference (allowed values <0,20>)", long_help = "Maximum difference between video frames, bigger value means that videos can looks more and more different (allowed values <0,20>)")] + tolerance: i32, + }, #[structopt(name = "tester", about = "Contains various test", help_message = HELP_MESSAGE, after_help = "EXAMPLE:\n czkawka tests -i")] Tester { #[structopt(short = "i", long = "test_image", help = "Test speed of hashing provided test.jpg image with different filters and methods.")] @@ -283,6 +306,19 @@ fn parse_hash_type(src: &str) -> Result { } } +fn parse_tolerance(src: &str) -> Result { + match src.parse::() { + Ok(t) => { + if (0..=20).contains(&t) { + Ok(t) + } else { + Err("Tolerance should be in range <0,20>(Higher and lower similarity )") + } + } + _ => Err("Failed to parse tolerance as i32 value."), + } +} + fn parse_checking_method(src: &str) -> Result { match src.to_ascii_lowercase().as_str() { "name" => Ok(CheckingMethod::Name), diff --git a/czkawka_cli/src/main.rs b/czkawka_cli/src/main.rs index 7f81356..d4522d0 100644 --- a/czkawka_cli/src/main.rs +++ b/czkawka_cli/src/main.rs @@ -16,6 +16,7 @@ use czkawka_core::{ invalid_symlinks::InvalidSymlinks, same_music::SameMusic, similar_images::{return_similarity_from_similarity_preset, SimilarImages}, + similar_videos::SimilarVideos, temporary::{self, Temporary}, zeroed::{self, ZeroedFiles}, }; @@ -385,6 +386,41 @@ fn main() { br.print_results(); br.get_text_messages().print_messages(); } + Commands::SimilarVideos { + directories, + excluded_directories, + excluded_items, + file_to_save, + not_recursive, + tolerance, + minimal_file_size, + maximal_file_size, + allowed_extensions, + } => { + let mut vr = SimilarVideos::new(); + + vr.set_included_directory(directories.directories); + vr.set_excluded_directory(excluded_directories.excluded_directories); + vr.set_excluded_items(excluded_items.excluded_items); + vr.set_allowed_extensions(allowed_extensions.allowed_extensions.join(",")); + vr.set_recursive_search(!not_recursive.not_recursive); + vr.set_minimal_file_size(minimal_file_size); + vr.set_maximal_file_size(maximal_file_size); + vr.set_tolerance(tolerance); + + vr.find_similar_videos(None, None); + + if let Some(file_name) = file_to_save.file_name() { + if !vr.save_results_to_file(file_name) { + vr.get_text_messages().print_messages(); + process::exit(1); + } + } + + #[cfg(not(debug_assertions))] // This will show too much probably unnecessary data to debug, comment line only if needed + vr.print_results(); + vr.get_text_messages().print_messages(); + } Commands::Tester { test_image } => { if test_image { test_image_conversion_speed(); diff --git a/czkawka_core/Cargo.toml b/czkawka_core/Cargo.toml index 51df64c..fc11cd8 100644 --- a/czkawka_core/Cargo.toml +++ b/czkawka_core/Cargo.toml @@ -34,13 +34,17 @@ futures = "0.3.17" zip = "0.5.13" rodio = { version = "0.14.0", optional = true } -# Hashes +# Hashes for duplicate files blake3 = "1.2.0" crc32fast = "1.2.1" xxhash-rust = { version = "0.8.2", features = ["xxh3"] } tempfile = "3.2.0" +# Video Duplactes +vid_dup_finder_lib = { git = "https://github.com/qarmin/vid_dup_finder_lib"} +ffmpeg_cmdline_utils = "0.1.0" + [features] default = [] diff --git a/czkawka_core/src/big_file.rs b/czkawka_core/src/big_file.rs index 98e7cdc..5152ed8 100644 --- a/czkawka_core/src/big_file.rs +++ b/czkawka_core/src/big_file.rs @@ -346,7 +346,7 @@ impl DebugPrint for BigFile { println!("Excluded items - {:?}", self.excluded_items.items); println!("Included directories - {:?}", self.directories.included_directories); println!("Excluded directories - {:?}", self.directories.excluded_directories); - println!("Recursive search - {}", self.recursive_search.to_string()); + println!("Recursive search - {}", self.recursive_search); println!("Number of files to check - {:?}", self.number_of_files_to_check); println!("-----------------------------------------"); } diff --git a/czkawka_core/src/broken_files.rs b/czkawka_core/src/broken_files.rs index 113f299..87555c4 100644 --- a/czkawka_core/src/broken_files.rs +++ b/czkawka_core/src/broken_files.rs @@ -517,7 +517,7 @@ impl DebugPrint for BrokenFiles { println!("Excluded items - {:?}", self.excluded_items.items); println!("Included directories - {:?}", self.directories.included_directories); println!("Excluded directories - {:?}", self.directories.excluded_directories); - println!("Recursive search - {}", self.recursive_search.to_string()); + println!("Recursive search - {}", self.recursive_search); println!("Delete Method - {:?}", self.delete_method); println!("-----------------------------------------"); } diff --git a/czkawka_core/src/duplicate.rs b/czkawka_core/src/duplicate.rs index a6dbbfc..717d3f2 100644 --- a/czkawka_core/src/duplicate.rs +++ b/czkawka_core/src/duplicate.rs @@ -1073,7 +1073,7 @@ impl DebugPrint for DuplicateFinder { println!("Excluded items - {:?}", self.excluded_items.items); println!("Included directories - {:?}", self.directories.included_directories); println!("Excluded directories - {:?}", self.directories.excluded_directories); - println!("Recursive search - {}", self.recursive_search.to_string()); + println!("Recursive search - {}", self.recursive_search); println!("Minimum file size - {:?}", self.minimal_file_size); println!("Checking Method - {:?}", self.check_method); println!("Delete Method - {:?}", self.delete_method); diff --git a/czkawka_core/src/empty_files.rs b/czkawka_core/src/empty_files.rs index fec0af5..1d7488b 100644 --- a/czkawka_core/src/empty_files.rs +++ b/czkawka_core/src/empty_files.rs @@ -320,7 +320,7 @@ impl DebugPrint for EmptyFiles { println!("Excluded items - {:?}", self.excluded_items.items); println!("Included directories - {:?}", self.directories.included_directories); println!("Excluded directories - {:?}", self.directories.excluded_directories); - println!("Recursive search - {}", self.recursive_search.to_string()); + println!("Recursive search - {}", self.recursive_search); println!("Delete Method - {:?}", self.delete_method); println!("-----------------------------------------"); } diff --git a/czkawka_core/src/empty_folder.rs b/czkawka_core/src/empty_folder.rs index 431ba86..f66500a 100644 --- a/czkawka_core/src/empty_folder.rs +++ b/czkawka_core/src/empty_folder.rs @@ -359,7 +359,6 @@ impl SaveResults for EmptyFolder { } } impl PrintResults for EmptyFolder { - /// Prints basic info about empty folders // TODO print better fn print_results(&self) { if !self.empty_folder_list.is_empty() { println!("Found {} empty folders", self.empty_folder_list.len()); diff --git a/czkawka_core/src/invalid_symlinks.rs b/czkawka_core/src/invalid_symlinks.rs index f800e61..5e2727e 100644 --- a/czkawka_core/src/invalid_symlinks.rs +++ b/czkawka_core/src/invalid_symlinks.rs @@ -367,7 +367,7 @@ impl DebugPrint for InvalidSymlinks { println!("Excluded items - {:?}", self.excluded_items.items); println!("Included directories - {:?}", self.directories.included_directories); println!("Excluded directories - {:?}", self.directories.excluded_directories); - println!("Recursive search - {}", self.recursive_search.to_string()); + println!("Recursive search - {}", self.recursive_search); println!("Delete Method - {:?}", self.delete_method); println!("-----------------------------------------"); } diff --git a/czkawka_core/src/lib.rs b/czkawka_core/src/lib.rs index 17ae5f5..f52cf47 100644 --- a/czkawka_core/src/lib.rs +++ b/czkawka_core/src/lib.rs @@ -9,6 +9,7 @@ pub mod empty_folder; pub mod invalid_symlinks; pub mod same_music; pub mod similar_images; +pub mod similar_videos; pub mod temporary; pub mod zeroed; diff --git a/czkawka_core/src/same_music.rs b/czkawka_core/src/same_music.rs index 73bbd05..3b6532c 100644 --- a/czkawka_core/src/same_music.rs +++ b/czkawka_core/src/same_music.rs @@ -669,7 +669,7 @@ impl DebugPrint for SameMusic { println!("Found duplicated files music - {}", self.duplicated_music_entries.len()); println!("Included directories - {:?}", self.directories.included_directories); println!("Excluded directories - {:?}", self.directories.excluded_directories); - println!("Recursive search - {}", self.recursive_search.to_string()); + println!("Recursive search - {}", self.recursive_search); println!("Delete Method - {:?}", self.delete_method); println!("-----------------------------------------"); } diff --git a/czkawka_core/src/similar_images.rs b/czkawka_core/src/similar_images.rs index d85c75e..7906f8f 100644 --- a/czkawka_core/src/similar_images.rs +++ b/czkawka_core/src/similar_images.rs @@ -696,7 +696,6 @@ impl SaveResults for SimilarImages { } } impl PrintResults for SimilarImages { - /// Prints basic info about empty folders // TODO print better fn print_results(&self) { if !self.similar_vectors.is_empty() { println!("Found {} images which have similar friends", self.similar_vectors.len()); diff --git a/czkawka_core/src/similar_videos.rs b/czkawka_core/src/similar_videos.rs new file mode 100644 index 0000000..38fc507 --- /dev/null +++ b/czkawka_core/src/similar_videos.rs @@ -0,0 +1,720 @@ +use crate::common::Common; +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}; +use crossbeam_channel::Receiver; +use directories_next::ProjectDirs; +use ffmpeg_cmdline_utils::FfmpegErrorKind::FfmpegNotFound; +use humansize::{file_size_opts as options, FileSize}; +use rayon::prelude::*; +use std::collections::{BTreeMap, HashMap}; +use std::fs::OpenOptions; +use std::fs::{File, Metadata}; +use std::io::Write; +use std::io::*; +use std::path::{Path, PathBuf}; +use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; +use std::sync::Arc; +use std::thread::sleep; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; +use std::{fs, mem, thread}; +use vid_dup_finder_lib::HashCreationErrorKind::DetermineVideo; +use vid_dup_finder_lib::{NormalizedTolerance, VideoHash}; + +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)] +pub struct FileEntry { + pub path: PathBuf, + pub size: u64, + pub modified_date: u64, + pub vhash: VideoHash, +} + +/// Distance metric to use with the BK-tree. +struct Hamming; + +impl bk_tree::Metric> for Hamming { + fn distance(&self, a: &Vec, b: &Vec) -> u32 { + hamming::distance_fast(a, b).unwrap() as u32 + } + + fn threshold_distance(&self, a: &Vec, b: &Vec, _threshold: u32) -> Option { + Some(self.distance(a, b)) + } +} + +/// Struct to store most basics info about all folder +pub struct SimilarVideos { + information: Info, + text_messages: Messages, + directories: Directories, + excluded_items: ExcludedItems, + allowed_extensions: Extensions, + similar_vectors: Vec>, + recursive_search: bool, + minimal_file_size: u64, + maximal_file_size: u64, + videos_hashes: BTreeMap, Vec>, + stopped_search: bool, + videos_to_check: BTreeMap, + use_cache: bool, + tolerance: i32, +} + +/// Info struck with helpful information's about results +#[derive(Default)] +pub struct Info { + pub number_of_removed_files: usize, + pub number_of_failed_to_remove_files: usize, + pub gained_space: u64, +} +impl Info { + pub fn new() -> Self { + Default::default() + } +} + +/// Method implementation for EmptyFolder +impl SimilarVideos { + /// New function providing basics values + pub fn new() -> Self { + Self { + information: Default::default(), + text_messages: Messages::new(), + directories: Directories::new(), + excluded_items: Default::default(), + allowed_extensions: Extensions::new(), + similar_vectors: vec![], + recursive_search: true, + minimal_file_size: 1024 * 16, + maximal_file_size: u64::MAX, + videos_hashes: Default::default(), + stopped_search: false, + videos_to_check: Default::default(), + use_cache: true, + tolerance: 10, + } + } + + pub fn set_tolerance(&mut self, tolerance: i32) { + assert!((0..=MAX_TOLERANCE).contains(&tolerance)); + self.tolerance = tolerance + } + + pub fn get_stopped_search(&self) -> bool { + self.stopped_search + } + + pub const fn get_text_messages(&self) -> &Messages { + &self.text_messages + } + + pub fn set_allowed_extensions(&mut self, allowed_extensions: String) { + self.allowed_extensions.set_allowed_extensions(allowed_extensions, &mut self.text_messages); + } + + pub const fn get_similar_videos(&self) -> &Vec> { + &self.similar_vectors + } + + pub const fn get_information(&self) -> &Info { + &self.information + } + + pub fn set_use_cache(&mut self, use_cache: bool) { + self.use_cache = use_cache; + } + + pub fn set_recursive_search(&mut self, recursive_search: bool) { + self.recursive_search = recursive_search; + } + + pub fn set_minimal_file_size(&mut self, minimal_file_size: u64) { + self.minimal_file_size = match minimal_file_size { + 0 => 1, + t => t, + }; + } + pub fn set_maximal_file_size(&mut self, maximal_file_size: u64) { + self.maximal_file_size = match maximal_file_size { + 0 => 1, + t => t, + }; + } + + /// 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>) { + if !check_if_ffmpeg_is_installed() { + self.text_messages.errors.push("Cannot find proper installation of FFmpeg.".to_string()); + } else { + self.directories.optimize_directories(true, &mut self.text_messages); + if !self.check_for_similar_videos(stop_receiver, progress_sender) { + self.stopped_search = true; + return; + } + if !self.sort_videos(stop_receiver, progress_sender) { + self.stopped_search = true; + return; + } + // if self.delete_folders { + // self.delete_empty_folders(); + // } + } + self.debug_print(); + } + + // pub fn set_delete_folder(&mut self, delete_folder: bool) { + // self.delete_folders = delete_folder; + // } + + /// 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>) -> bool { + let start_time: SystemTime = SystemTime::now(); + let mut folders_to_check: Vec = 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 + + // Add root folders for finding + for id in &self.directories.included_directories { + folders_to_check.push(id.clone()); + } + + //// PROGRESS THREAD START + const LOOP_DURATION: u32 = 200; //in ms + let progress_thread_run = Arc::new(AtomicBool::new(true)); + + let atomic_file_counter = Arc::new(AtomicUsize::new(0)); + + let progress_thread_handle; + if let Some(progress_sender) = progress_sender { + let progress_send = progress_sender.clone(); + let progress_thread_run = progress_thread_run.clone(); + let atomic_file_counter = atomic_file_counter.clone(); + progress_thread_handle = thread::spawn(move || loop { + progress_send + .unbounded_send(ProgressData { + current_stage: 0, + max_stage: 1, + videos_checked: atomic_file_counter.load(Ordering::Relaxed) as usize, + videos_to_check: 0, + }) + .unwrap(); + if !progress_thread_run.load(Ordering::Relaxed) { + break; + } + sleep(Duration::from_millis(LOOP_DURATION as u64)); + }); + } else { + progress_thread_handle = thread::spawn(|| {}); + } + //// PROGRESS THREAD END + + while !folders_to_check.is_empty() { + if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() { + // End thread which send info to gui + progress_thread_run.store(false, Ordering::Relaxed); + progress_thread_handle.join().unwrap(); + return false; + } + let current_folder = folders_to_check.pop().unwrap(); + + // Read current dir, if permission are denied just go to next + let read_dir = match fs::read_dir(¤t_folder) { + Ok(t) => t, + Err(e) => { + self.text_messages.warnings.push(format!("Cannot open dir {}, reason {}", current_folder.display(), e)); + continue; + } // Permissions denied + }; + + // Check every sub folder/file/link etc. + 'dir: for entry in read_dir { + let entry_data = match entry { + Ok(t) => t, + Err(e) => { + self.text_messages.warnings.push(format!("Cannot read entry in dir {}, reason {}", current_folder.display(), e)); + continue; + } //Permissions denied + }; + let metadata: Metadata = match entry_data.metadata() { + Ok(t) => t, + Err(e) => { + self.text_messages.warnings.push(format!("Cannot read metadata in dir {}, reason {}", current_folder.display(), e)); + continue; + } //Permissions denied + }; + if metadata.is_dir() { + if !self.recursive_search { + continue; + } + + let next_folder = current_folder.join(entry_data.file_name()); + if self.directories.is_excluded(&next_folder) { + continue 'dir; + } + + if self.excluded_items.is_excluded(&next_folder) { + continue 'dir; + } + + folders_to_check.push(next_folder); + } else if metadata.is_file() { + atomic_file_counter.fetch_add(1, Ordering::Relaxed); + + let file_name_lowercase: String = match entry_data.file_name().into_string() { + Ok(t) => t, + Err(_inspected) => { + println!("File {:?} has not valid UTF-8 name", entry_data); + continue 'dir; + } + } + .to_lowercase(); + + if !self.allowed_extensions.file_extensions.is_empty() { + let allowed = self.allowed_extensions.file_extensions.iter().any(|e| file_name_lowercase.ends_with((".".to_string() + e.to_lowercase().as_str()).as_str())); + if !allowed { + // Not an allowed extension, ignore it. + continue 'dir; + } + } + + // Checking allowed video extensions + let allowed_video_extensions = [".mp4", ".mpv", ".flv", ".mp4a", ".webm", ".mpg", ".mp2", ".mpeg", ".m4p", ".m4v", ".avi", ".wmv", ".qt", ".mov", ".swf", ".mkv"]; + if !allowed_video_extensions.iter().any(|e| file_name_lowercase.ends_with(e)) { + continue 'dir; + } + + // Checking files + if (self.minimal_file_size..=self.maximal_file_size).contains(&metadata.len()) { + let current_file_name = current_folder.join(entry_data.file_name()); + if self.excluded_items.is_excluded(¤t_file_name) { + continue 'dir; + } + + let fe: FileEntry = FileEntry { + path: current_file_name.clone(), + size: metadata.len(), + modified_date: match metadata.modified() { + Ok(t) => match t.duration_since(UNIX_EPOCH) { + Ok(d) => d.as_secs(), + Err(_inspected) => { + self.text_messages.warnings.push(format!("File {} seems to be modified before Unix Epoch.", current_file_name.display())); + 0 + } + }, + Err(e) => { + self.text_messages.warnings.push(format!("Unable to get modification date from file {}, reason {}", current_file_name.display(), e)); + 0 + } // Permissions Denied + }, + vhash: Default::default(), + }; + + self.videos_to_check.insert(current_file_name.to_string_lossy().to_string(), fe); + } + } + } + } + // End thread which send info to gui + progress_thread_run.store(false, Ordering::Relaxed); + progress_thread_handle.join().unwrap(); + Common::print_time(start_time, SystemTime::now(), "check_for_similar_videos".to_string()); + true + } + + fn sort_videos(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) -> bool { + let hash_map_modification = SystemTime::now(); + + let loaded_hash_map; + + let mut records_already_cached: BTreeMap = Default::default(); + let mut non_cached_files_to_check: BTreeMap = Default::default(); + + if self.use_cache { + loaded_hash_map = match load_hashes_from_file(&mut self.text_messages) { + Some(t) => t, + None => Default::default(), + }; + + for (name, file_entry) in &self.videos_to_check { + #[allow(clippy::if_same_then_else)] + if !loaded_hash_map.contains_key(name) { + // If loaded data doesn't contains current videos info + non_cached_files_to_check.insert(name.clone(), file_entry.clone()); + } else if file_entry.size != loaded_hash_map.get(name).unwrap().size || file_entry.modified_date != loaded_hash_map.get(name).unwrap().modified_date { + // When size or modification date of video changed, then it is clear that is different video + non_cached_files_to_check.insert(name.clone(), file_entry.clone()); + } else { + // Checking may be omitted when already there is entry with same size and modification date + records_already_cached.insert(name.clone(), loaded_hash_map.get(name).unwrap().clone()); + } + } + } else { + loaded_hash_map = Default::default(); + mem::swap(&mut self.videos_to_check, &mut non_cached_files_to_check); + } + + Common::print_time(hash_map_modification, SystemTime::now(), "sort_videos - reading data from cache and preparing them".to_string()); + let hash_map_modification = SystemTime::now(); + + //// PROGRESS THREAD START + const LOOP_DURATION: u32 = 200; //in ms + let progress_thread_run = Arc::new(AtomicBool::new(true)); + + let atomic_file_counter = Arc::new(AtomicUsize::new(0)); + + let progress_thread_handle; + if let Some(progress_sender) = progress_sender { + let progress_send = progress_sender.clone(); + let progress_thread_run = progress_thread_run.clone(); + let atomic_file_counter = atomic_file_counter.clone(); + let videos_to_check = non_cached_files_to_check.len(); + progress_thread_handle = thread::spawn(move || loop { + progress_send + .unbounded_send(ProgressData { + current_stage: 1, + max_stage: 1, + videos_checked: atomic_file_counter.load(Ordering::Relaxed) as usize, + videos_to_check, + }) + .unwrap(); + if !progress_thread_run.load(Ordering::Relaxed) { + break; + } + sleep(Duration::from_millis(LOOP_DURATION as u64)); + }); + } else { + progress_thread_handle = thread::spawn(|| {}); + } + //// PROGRESS THREAD END + let old_vec_file_entry: Vec> = non_cached_files_to_check + .par_iter() + .map(|file_entry| { + atomic_file_counter.fetch_add(1, Ordering::Relaxed); + if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() { + // This will not break + return None; + } + let mut file_entry = file_entry.1.clone(); + + let vhash = match VideoHash::from_path(&file_entry.path) { + Ok(t) => t, + Err(e) => return Some(Err(format!("Failed to hash file, {}", e))), + }; + + file_entry.vhash = vhash; + + Some(Ok(file_entry)) + }) + .while_some() + .collect::>>(); + + // End thread which send info to gui + progress_thread_run.store(false, Ordering::Relaxed); + progress_thread_handle.join().unwrap(); + + let mut vec_file_entry = Vec::new(); + for result in old_vec_file_entry { + match result { + Ok(t) => vec_file_entry.push(t), + Err(e) => { + self.text_messages.errors.push(e); + } + } + } + + Common::print_time(hash_map_modification, SystemTime::now(), "sort_videos - reading data from files in parallel".to_string()); + let hash_map_modification = SystemTime::now(); + + // Just connect loaded results with already calculated hashes + for (_name, file_entry) in records_already_cached { + vec_file_entry.push(file_entry.clone()); + } + + let mut hashmap_with_file_entries: HashMap = Default::default(); + let mut vector_of_hashes: Vec = Vec::new(); + for i in &vec_file_entry { + hashmap_with_file_entries.insert(i.vhash.src_path().to_string_lossy().to_string(), i.clone()); + vector_of_hashes.push(i.vhash.clone()); + } + + if self.use_cache { + // Must save all results to file, old loaded from file with all currently counted results + let mut all_results: BTreeMap = loaded_hash_map; + for file_entry in vec_file_entry { + all_results.insert(file_entry.path.to_string_lossy().to_string(), file_entry); + } + save_hashes_to_file(&all_results, &mut self.text_messages); + } + + Common::print_time(hash_map_modification, SystemTime::now(), "sort_videos - saving data to files".to_string()); + let hash_map_modification = SystemTime::now(); + + let match_group = vid_dup_finder_lib::search(vector_of_hashes, NormalizedTolerance::new(self.tolerance as f64 / 100.0f64)); + + let mut collected_similar_videos: Vec> = Default::default(); + for i in match_group { + let mut temp_vector: Vec = Vec::new(); + for j in i.duplicates() { + temp_vector.push(hashmap_with_file_entries.get(&j.to_string_lossy().to_string()).unwrap().clone()); + } + assert!(temp_vector.len() > 1); + collected_similar_videos.push(temp_vector); + } + + self.similar_vectors = collected_similar_videos; + + Common::print_time(hash_map_modification, SystemTime::now(), "sort_videos - selecting data from BtreeMap".to_string()); + + // Clean unused data + self.videos_hashes = Default::default(); + self.videos_to_check = Default::default(); + + true + } + + /// Set included dir which needs to be relative, exists etc. + pub fn set_included_directory(&mut self, included_directory: Vec) { + self.directories.set_included_directory(included_directory, &mut self.text_messages); + } + + pub fn set_excluded_directory(&mut self, excluded_directory: Vec) { + self.directories.set_excluded_directory(excluded_directory, &mut self.text_messages); + } + + pub fn set_excluded_items(&mut self, excluded_items: Vec) { + self.excluded_items.set_excluded_items(excluded_items, &mut self.text_messages); + } +} +impl Default for SimilarVideos { + fn default() -> Self { + Self::new() + } +} + +impl DebugPrint for SimilarVideos { + #[allow(dead_code)] + #[allow(unreachable_code)] + fn debug_print(&self) { + #[cfg(not(debug_assertions))] + { + return; + } + + println!("---------------DEBUG PRINT---------------"); + println!("Included directories - {:?}", self.directories.included_directories); + println!("-----------------------------------------"); + } +} +impl SaveResults for SimilarVideos { + fn save_results_to_file(&mut self, file_name: &str) -> bool { + let start_time: SystemTime = SystemTime::now(); + let file_name: String = match file_name { + "" => "results.txt".to_string(), + k => k.to_string(), + }; + + let file_handler = match File::create(&file_name) { + Ok(t) => t, + Err(e) => { + self.text_messages.errors.push(format!("Failed to create file {}, reason {}", file_name, e)); + return false; + } + }; + let mut writer = BufWriter::new(file_handler); + + if let Err(e) = writeln!( + writer, + "Results of searching {:?} with excluded directories {:?} and excluded items {:?}", + self.directories.included_directories, self.directories.excluded_directories, self.excluded_items.items + ) { + self.text_messages.errors.push(format!("Failed to save results to file {}, reason {}", file_name, e)); + return false; + } + + if !self.similar_vectors.is_empty() { + write!(writer, "{} videos which have similar friends\n\n", self.similar_vectors.len()).unwrap(); + + for struct_similar in self.similar_vectors.iter() { + writeln!(writer, "Found {} videos which have similar friends", self.similar_vectors.len()).unwrap(); + for file_entry in struct_similar { + writeln!(writer, "{} - {}", file_entry.path.display(), file_entry.size.file_size(options::BINARY).unwrap(),).unwrap(); + } + writeln!(writer).unwrap(); + } + } else { + write!(writer, "Not found any similar videos.").unwrap(); + } + + Common::print_time(start_time, SystemTime::now(), "save_results_to_file".to_string()); + true + } +} +impl PrintResults for SimilarVideos { + fn print_results(&self) { + if !self.similar_vectors.is_empty() { + println!("Found {} videos which have similar friends", self.similar_vectors.len()); + + for vec_file_entry in &self.similar_vectors { + for file_entry in vec_file_entry { + println!("{} - {}", file_entry.path.display(), file_entry.size.file_size(options::BINARY).unwrap()); + } + println!(); + } + } + } +} + +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() { + text_messages.messages.push(format!("Config dir {} is a file!", cache_dir.display())); + return; + } + } else if let Err(e) = fs::create_dir_all(&cache_dir) { + text_messages.messages.push(format!("Cannot create config dir {}, reason {}", cache_dir.display(), e)); + return; + } + let cache_file = cache_dir.join("cache_similar_videos.txt"); + let file_handler = match OpenOptions::new().truncate(true).write(true).create(true).open(&cache_file) { + Ok(t) => t, + Err(e) => { + text_messages.messages.push(format!("Cannot create or open cache file {}, reason {}", cache_file.display(), e)); + return; + } + }; + let mut writer = BufWriter::new(file_handler); + + for file_entry in hashmap.values() { + let mut string: String = String::with_capacity(256); + + string += format!("{}//{}//{}//{}//{}", file_entry.path.display(), file_entry.size, file_entry.modified_date, file_entry.vhash.num_frames(), file_entry.vhash.duration()).as_str(); + + for i in file_entry.vhash.hash() { + string.push_str("//"); + string.push_str(i.to_string().as_str()); + } + + if let Err(e) = writeln!(writer, "{}", string) { + text_messages.messages.push(format!("Failed to save some data to cache file {}, reason {}", cache_file.display(), e)); + return; + }; + } + } +} +fn load_hashes_from_file(text_messages: &mut Messages) -> 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.txt"); + 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 + return None; + } + }; + + let reader = BufReader::new(file_handler); + + let mut hashmap_loaded_entries: BTreeMap = Default::default(); + + // Read the file line by line using the lines() iterator from std::io::BufRead. + for (index, line) in reader.lines().enumerate() { + let line = match line { + Ok(t) => t, + Err(e) => { + text_messages.warnings.push(format!("Failed to load line number {} from cache file {}, reason {}", index + 1, cache_file.display(), e)); + return None; + } + }; + let uuu = line.split("//").collect::>(); + let hash_size = 19; + // Hash size + other things + if uuu.len() != (hash_size + 5) { + text_messages.warnings.push(format!( + "Found invalid data in line {} - ({}) in cache file {}, expected {} values, found {}", + index + 1, + line, + cache_file.display(), + hash_size + 5, + uuu.len(), + )); + continue; + }; + // Don't load cache data if destination file not exists + if Path::new(uuu[0]).exists() { + let mut hash: [u64; 19] = [0; 19]; + for i in 0..hash_size { + hash[i] = match uuu[5 + i as usize].parse::() { + Ok(t) => t, + Err(e) => { + text_messages + .warnings + .push(format!("Found invalid hash value in line {} - ({}) in cache file {}, reason {}", index + 1, line, cache_file.display(), e)); + continue; + } + }; + } + + hashmap_loaded_entries.insert( + uuu[0].to_string(), + FileEntry { + path: PathBuf::from(uuu[0]), + size: match uuu[1].parse::() { + Ok(t) => t, + Err(e) => { + text_messages + .warnings + .push(format!("Found invalid size value in line {} - ({}) in cache file {}, reason {}", index + 1, line, cache_file.display(), e)); + continue; + } + }, + modified_date: match uuu[2].parse::() { + Ok(t) => t, + Err(e) => { + text_messages + .warnings + .push(format!("Found invalid modified date value in line {} - ({}) in cache file {}, reason {}", index + 1, line, cache_file.display(), e)); + continue; + } + }, + vhash: VideoHash::with_start_data(uuu[4].parse::().unwrap_or(0), uuu[0], hash, uuu[3].parse::().unwrap_or(10)), + }, + ); + } + } + + return Some(hashmap_loaded_entries); + } + + text_messages.messages.push("Cannot find or open system config dir to save cache file".to_string()); + None +} + +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) { + return false; + } + true +} diff --git a/czkawka_core/src/temporary.rs b/czkawka_core/src/temporary.rs index bc36178..b9cf0d1 100644 --- a/czkawka_core/src/temporary.rs +++ b/czkawka_core/src/temporary.rs @@ -305,7 +305,7 @@ impl DebugPrint for Temporary { println!("Excluded items - {:?}", self.excluded_items.items); println!("Included directories - {:?}", self.directories.included_directories); println!("Excluded directories - {:?}", self.directories.excluded_directories); - println!("Recursive search - {}", self.recursive_search.to_string()); + println!("Recursive search - {}", self.recursive_search); println!("Delete Method - {:?}", self.delete_method); println!("-----------------------------------------"); } diff --git a/czkawka_core/src/zeroed.rs b/czkawka_core/src/zeroed.rs index b1a016b..e5cb731 100644 --- a/czkawka_core/src/zeroed.rs +++ b/czkawka_core/src/zeroed.rs @@ -454,7 +454,7 @@ impl DebugPrint for ZeroedFiles { println!("Excluded items - {:?}", self.excluded_items.items); println!("Included directories - {:?}", self.directories.included_directories); println!("Excluded directories - {:?}", self.directories.excluded_directories); - println!("Recursive search - {}", self.recursive_search.to_string()); + println!("Recursive search - {}", self.recursive_search); println!("Delete Method - {:?}", self.delete_method); println!("Minimal File Size - {:?}", self.minimal_file_size); println!("-----------------------------------------"); diff --git a/czkawka_gui/src/connect_button_delete.rs b/czkawka_gui/src/connect_button_delete.rs index a7bdb59..56a2e42 100644 --- a/czkawka_gui/src/connect_button_delete.rs +++ b/czkawka_gui/src/connect_button_delete.rs @@ -20,6 +20,7 @@ pub fn connect_button_delete(gui_data: &GuiData) { let tree_view_empty_files_finder = gui_data.main_notebook.tree_view_empty_files_finder.clone(); let tree_view_temporary_files_finder = gui_data.main_notebook.tree_view_temporary_files_finder.clone(); let tree_view_similar_images_finder = gui_data.main_notebook.tree_view_similar_images_finder.clone(); + let tree_view_similar_videos_finder = gui_data.main_notebook.tree_view_similar_videos_finder.clone(); let tree_view_zeroed_files_finder = gui_data.main_notebook.tree_view_zeroed_files_finder.clone(); let tree_view_same_music_finder = gui_data.main_notebook.tree_view_same_music_finder.clone(); let tree_view_invalid_symlinks = gui_data.main_notebook.tree_view_invalid_symlinks.clone(); @@ -105,6 +106,26 @@ pub fn connect_button_delete(gui_data: &GuiData) { image_preview_similar_images.hide(); } } + NotebookMainEnum::SimilarVideos => { + if !check_button_settings_confirm_group_deletion.is_active() + || !check_if_deleting_all_files_in_group( + &tree_view_similar_videos_finder.clone(), + ColumnsSimilarVideos::Color as i32, + ColumnsSimilarVideos::ActiveSelectButton as i32, + &window_main, + &check_button_settings_confirm_group_deletion, + ) + { + tree_remove( + &tree_view_similar_videos_finder.clone(), + ColumnsSimilarVideos::Name as i32, + ColumnsSimilarVideos::Path as i32, + ColumnsSimilarVideos::Color as i32, + ColumnsSimilarVideos::ActiveSelectButton as i32, + &gui_data, + ); + } + } NotebookMainEnum::Zeroed => { basic_remove( &tree_view_zeroed_files_finder.clone(), diff --git a/czkawka_gui/src/connect_button_hardlink.rs b/czkawka_gui/src/connect_button_hardlink.rs index 96a69c6..8d7463d 100644 --- a/czkawka_gui/src/connect_button_hardlink.rs +++ b/czkawka_gui/src/connect_button_hardlink.rs @@ -15,6 +15,7 @@ pub fn connect_button_hardlink(gui_data: &GuiData) { let tree_view_duplicate_finder = gui_data.main_notebook.tree_view_duplicate_finder.clone(); let tree_view_similar_images_finder = gui_data.main_notebook.tree_view_similar_images_finder.clone(); + let tree_view_similar_videos_finder = gui_data.main_notebook.tree_view_similar_videos_finder.clone(); let tree_view_same_music_finder = gui_data.main_notebook.tree_view_same_music_finder.clone(); let image_preview_similar_images = gui_data.main_notebook.image_preview_similar_images.clone(); @@ -54,6 +55,17 @@ pub fn connect_button_hardlink(gui_data: &GuiData) { ); image_preview_similar_images.hide(); } + NotebookMainEnum::SimilarVideos => { + hardlink_symlink( + tree_view_similar_videos_finder.clone(), + ColumnsSimilarVideos::Name as i32, + ColumnsSimilarVideos::Path as i32, + ColumnsSimilarVideos::Color as i32, + ColumnsSimilarVideos::ActiveSelectButton as i32, + true, + &gui_data, + ); + } e => panic!("Not existent {:?}", e), }); } diff --git a/czkawka_gui/src/connect_button_move.rs b/czkawka_gui/src/connect_button_move.rs index dff3bea..eeb2931 100644 --- a/czkawka_gui/src/connect_button_move.rs +++ b/czkawka_gui/src/connect_button_move.rs @@ -55,6 +55,16 @@ pub fn connect_button_move(gui_data: &GuiData) { ); image_preview_similar_images.hide(); } + NotebookMainEnum::SimilarVideos => { + move_things( + tree_view_similar_images_finder.clone(), + ColumnsSimilarVideos::Name as i32, + ColumnsSimilarVideos::Path as i32, + Some(ColumnsSimilarVideos::Color as i32), + ColumnsSimilarVideos::ActiveSelectButton as i32, + &gui_data, + ); + } NotebookMainEnum::BigFiles => { move_things( tree_view_big_files_finder.clone(), diff --git a/czkawka_gui/src/connect_button_save.rs b/czkawka_gui/src/connect_button_save.rs index 2afc7cf..3f0d96b 100644 --- a/czkawka_gui/src/connect_button_save.rs +++ b/czkawka_gui/src/connect_button_save.rs @@ -12,6 +12,7 @@ pub fn connect_button_save(gui_data: &GuiData) { let shared_temporary_files_state = gui_data.shared_temporary_files_state.clone(); let shared_empty_files_state = gui_data.shared_empty_files_state.clone(); let shared_similar_images_state = gui_data.shared_similar_images_state.clone(); + let shared_similar_videos_state = gui_data.shared_similar_videos_state.clone(); let shared_same_music_state = gui_data.shared_same_music_state.clone(); let shared_zeroed_files_state = gui_data.shared_zeroed_files_state.clone(); let shared_same_invalid_symlinks = gui_data.shared_same_invalid_symlinks.clone(); @@ -51,6 +52,11 @@ pub fn connect_button_save(gui_data: &GuiData) { shared_similar_images_state.borrow_mut().save_results_to_file(file_name); } + NotebookMainEnum::SimilarVideos => { + file_name = "results_similar_videos.txt"; + + shared_similar_videos_state.borrow_mut().save_results_to_file(file_name); + } NotebookMainEnum::Zeroed => { file_name = "results_zeroed_files.txt"; diff --git a/czkawka_gui/src/connect_button_search.rs b/czkawka_gui/src/connect_button_search.rs index 4bdb4c1..ab50992 100644 --- a/czkawka_gui/src/connect_button_search.rs +++ b/czkawka_gui/src/connect_button_search.rs @@ -11,6 +11,7 @@ use czkawka_core::empty_folder::EmptyFolder; use czkawka_core::invalid_symlinks::InvalidSymlinks; 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::zeroed::ZeroedFiles; use glib::Sender; @@ -33,6 +34,7 @@ pub fn connect_button_search( futures_sender_big_file: futures::channel::mpsc::UnboundedSender, futures_sender_same_music: futures::channel::mpsc::UnboundedSender, futures_sender_similar_images: futures::channel::mpsc::UnboundedSender, + futures_sender_similar_videos: futures::channel::mpsc::UnboundedSender, futures_sender_temporary: futures::channel::mpsc::UnboundedSender, futures_sender_zeroed: futures::channel::mpsc::UnboundedSender, futures_sender_invalid_symlinks: futures::channel::mpsc::UnboundedSender, @@ -54,13 +56,16 @@ pub fn connect_button_search( let radio_button_duplicates_size = gui_data.main_notebook.radio_button_duplicates_size.clone(); let radio_button_duplicates_hashmb = gui_data.main_notebook.radio_button_duplicates_hashmb.clone(); let radio_button_duplicates_hash = gui_data.main_notebook.radio_button_duplicates_hash.clone(); - let scale_similarity = gui_data.main_notebook.scale_similarity.clone(); + let scale_similarity_similar_images = gui_data.main_notebook.scale_similarity_similar_images.clone(); + let scale_similarity_similar_videos = gui_data.main_notebook.scale_similarity_similar_videos.clone(); let entry_duplicate_minimal_size = gui_data.main_notebook.entry_duplicate_minimal_size.clone(); let entry_duplicate_maximal_size = gui_data.main_notebook.entry_duplicate_maximal_size.clone(); let stop_receiver = gui_data.stop_receiver.clone(); let entry_big_files_number = gui_data.main_notebook.entry_big_files_number.clone(); let entry_similar_images_minimal_size = gui_data.main_notebook.entry_similar_images_minimal_size.clone(); let entry_similar_images_maximal_size = gui_data.main_notebook.entry_similar_images_maximal_size.clone(); + let entry_similar_videos_minimal_size = gui_data.main_notebook.entry_similar_videos_minimal_size.clone(); + let entry_similar_videos_maximal_size = gui_data.main_notebook.entry_similar_videos_maximal_size.clone(); let check_button_music_title: gtk::CheckButton = gui_data.main_notebook.check_button_music_title.clone(); let check_button_music_artist: gtk::CheckButton = gui_data.main_notebook.check_button_music_artist.clone(); let check_button_music_album_title: gtk::CheckButton = gui_data.main_notebook.check_button_music_album_title.clone(); @@ -74,6 +79,7 @@ pub fn connect_button_search( let tree_view_temporary_files_finder = gui_data.main_notebook.tree_view_temporary_files_finder.clone(); let tree_view_same_music_finder = gui_data.main_notebook.tree_view_same_music_finder.clone(); let tree_view_similar_images_finder = gui_data.main_notebook.tree_view_similar_images_finder.clone(); + let tree_view_similar_videos_finder = gui_data.main_notebook.tree_view_similar_videos_finder.clone(); let tree_view_zeroed_files_finder = gui_data.main_notebook.tree_view_zeroed_files_finder.clone(); let tree_view_invalid_symlinks = gui_data.main_notebook.tree_view_invalid_symlinks.clone(); let tree_view_broken_files = gui_data.main_notebook.tree_view_broken_files.clone(); @@ -325,7 +331,7 @@ pub fn connect_button_search( let minimal_file_size = entry_similar_images_minimal_size.text().as_str().parse::().unwrap_or(1024 * 16); let maximal_file_size = entry_similar_images_maximal_size.text().as_str().parse::().unwrap_or(1024 * 1024 * 1024 * 1024); - let similarity = similar_images::Similarity::Similar(scale_similarity.value() as u32); + let similarity = similar_images::Similarity::Similar(scale_similarity_similar_images.value() as u32); let futures_sender_similar_images = futures_sender_similar_images.clone(); // Find similar images @@ -347,6 +353,35 @@ pub fn connect_button_search( let _ = glib_stop_sender.send(Message::SimilarImages(sf)); }); } + NotebookMainEnum::SimilarVideos => { + label_stage.show(); + grid_progress_stages.show_all(); + window_progress.resize(1, 1); + + get_list_store(&tree_view_similar_videos_finder).clear(); + + let minimal_file_size = entry_similar_videos_minimal_size.text().as_str().parse::().unwrap_or(1024 * 16); + let maximal_file_size = entry_similar_videos_maximal_size.text().as_str().parse::().unwrap_or(1024 * 1024 * 1024 * 1024); + + let tolerance = scale_similarity_similar_videos.value() as i32; + + let futures_sender_similar_videos = futures_sender_similar_videos.clone(); + // Find similar videos + thread::spawn(move || { + let mut sf = SimilarVideos::new(); + + sf.set_included_directory(included_directories); + sf.set_excluded_directory(excluded_directories); + sf.set_recursive_search(recursive_search); + sf.set_excluded_items(excluded_items); + sf.set_minimal_file_size(minimal_file_size); + sf.set_maximal_file_size(maximal_file_size); + sf.set_use_cache(use_cache); + sf.set_tolerance(tolerance); + sf.find_similar_videos(Some(&stop_receiver), Some(&futures_sender_similar_videos)); + let _ = glib_stop_sender.send(Message::SimilarVideos(sf)); + }); + } NotebookMainEnum::Zeroed => { label_stage.show(); grid_progress_stages.show_all(); diff --git a/czkawka_gui/src/connect_button_symlink.rs b/czkawka_gui/src/connect_button_symlink.rs index 8fbb675..a05115b 100644 --- a/czkawka_gui/src/connect_button_symlink.rs +++ b/czkawka_gui/src/connect_button_symlink.rs @@ -12,6 +12,7 @@ pub fn connect_button_symlink(gui_data: &GuiData) { let tree_view_duplicate_finder = gui_data.main_notebook.tree_view_duplicate_finder.clone(); let tree_view_similar_images_finder = gui_data.main_notebook.tree_view_similar_images_finder.clone(); + let tree_view_similar_videos_finder = gui_data.main_notebook.tree_view_similar_videos_finder.clone(); let tree_view_same_music_finder = gui_data.main_notebook.tree_view_same_music_finder.clone(); let image_preview_similar_images = gui_data.main_notebook.image_preview_similar_images.clone(); @@ -53,6 +54,17 @@ pub fn connect_button_symlink(gui_data: &GuiData) { ); image_preview_similar_images.hide(); } + NotebookMainEnum::SimilarVideos => { + hardlink_symlink( + tree_view_similar_videos_finder.clone(), + ColumnsSimilarVideos::Name as i32, + ColumnsSimilarVideos::Path as i32, + ColumnsSimilarVideos::Color as i32, + ColumnsSimilarVideos::ActiveSelectButton as i32, + false, + &gui_data, + ); + } e => panic!("Not existent {:?}", e), }); } diff --git a/czkawka_gui/src/connect_compute_results.rs b/czkawka_gui/src/connect_compute_results.rs index 588a465..02a5c46 100644 --- a/czkawka_gui/src/connect_compute_results.rs +++ b/czkawka_gui/src/connect_compute_results.rs @@ -19,6 +19,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< let tree_view_empty_files_finder = gui_data.main_notebook.tree_view_empty_files_finder.clone(); let tree_view_duplicate_finder = gui_data.main_notebook.tree_view_duplicate_finder.clone(); let tree_view_similar_images_finder = gui_data.main_notebook.tree_view_similar_images_finder.clone(); + let tree_view_similar_videos_finder = gui_data.main_notebook.tree_view_similar_videos_finder.clone(); let buttons_array = gui_data.bottom_buttons.buttons_array.clone(); let text_view_errors = gui_data.text_view_errors.clone(); let shared_duplication_state = gui_data.shared_duplication_state.clone(); @@ -35,6 +36,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< let tree_view_temporary_files_finder = gui_data.main_notebook.tree_view_temporary_files_finder.clone(); let shared_temporary_files_state = gui_data.shared_temporary_files_state.clone(); let shared_similar_images_state = gui_data.shared_similar_images_state.clone(); + let shared_similar_videos_state = gui_data.shared_similar_videos_state.clone(); let shared_zeroed_files_state = gui_data.shared_zeroed_files_state.clone(); let tree_view_same_music_finder = gui_data.main_notebook.tree_view_same_music_finder.clone(); let shared_same_music_state = gui_data.shared_same_music_state.clone(); @@ -147,7 +149,7 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< (1, &false), (2, &file), (3, &directory), - (4, &(format!("{} - ({})", NaiveDateTime::from_timestamp(entry.modified_date as i64, 0).to_string(), entry.size.file_size(options::BINARY).unwrap()))), + (4, &(format!("{} - ({})", NaiveDateTime::from_timestamp(entry.modified_date as i64, 0), entry.size.file_size(options::BINARY).unwrap()))), (5, &(entry.modified_date)), (6, &(MAIN_ROW_COLOR.to_string())), (7, &(TEXT_COLOR.to_string())), @@ -587,6 +589,96 @@ pub fn connect_compute_results(gui_data: &GuiData, glib_stop_receiver: Receiver< } } } + Message::SimilarVideos(ff) => { + if ff.get_stopped_search() { + entry_info.set_text("Searching for similar videos was stopped by user"); + } else { + //let information = ff.get_information(); + let text_messages = ff.get_text_messages(); + + let base_videos_size = ff.get_similar_videos().len(); + + entry_info.set_text(format!("Found similar videos for {} videos.", base_videos_size).as_str()); + + // Create GUI + { + let list_store = get_list_store(&tree_view_similar_videos_finder); + + let vec_struct_similar = ff.get_similar_videos(); + + for vec_file_entry in vec_struct_similar.iter() { + // Sort + let vec_file_entry = if vec_file_entry.len() >= 2 { + let mut vec_file_entry = vec_file_entry.clone(); + vec_file_entry.sort_by_key(|e| { + let t = split_path(e.path.as_path()); + (t.0, t.1) + }); + vec_file_entry + } else { + vec_file_entry.clone() + }; + + // Header + let values: [(u32, &dyn ToValue); 10] = [ + (ColumnsSimilarVideos::ActivatableSelectButton as u32, &false), + (ColumnsSimilarVideos::ActiveSelectButton as u32, &false), + (ColumnsSimilarVideos::Size as u32, &"".to_string()), + (ColumnsSimilarVideos::SizeAsBytes as u32, &(0)), + (ColumnsSimilarVideos::Name as u32, &"".to_string()), + (ColumnsSimilarVideos::Path as u32, &"".to_string()), + (ColumnsSimilarVideos::Modification as u32, &"".to_string()), + (ColumnsSimilarVideos::ModificationAsSecs as u32, &(0)), + (ColumnsSimilarVideos::Color as u32, &(HEADER_ROW_COLOR.to_string())), + (ColumnsSimilarVideos::TextColor as u32, &(TEXT_COLOR.to_string())), + ]; + list_store.set(&list_store.append(), &values); + + // Meat + for file_entry in vec_file_entry.iter() { + let (directory, file) = split_path(&file_entry.path); + let values: [(u32, &dyn ToValue); 10] = [ + (ColumnsSimilarVideos::ActivatableSelectButton as u32, &true), + (ColumnsSimilarVideos::ActiveSelectButton as u32, &false), + (ColumnsSimilarVideos::Size as u32, &file_entry.size.file_size(options::BINARY).unwrap()), + (ColumnsSimilarVideos::SizeAsBytes as u32, &file_entry.size), + (ColumnsSimilarVideos::Name as u32, &file), + (ColumnsSimilarVideos::Path as u32, &directory), + (ColumnsSimilarVideos::Modification as u32, &(NaiveDateTime::from_timestamp(file_entry.modified_date as i64, 0).to_string())), + (ColumnsSimilarVideos::ModificationAsSecs as u32, &(file_entry.modified_date)), + (ColumnsSimilarVideos::Color as u32, &(MAIN_ROW_COLOR.to_string())), + (ColumnsSimilarVideos::TextColor as u32, &(TEXT_COLOR.to_string())), + ]; + list_store.set(&list_store.append(), &values); + } + } + + print_text_messages_to_text_view(text_messages, &text_view_errors); + } + + // Set state + { + *shared_similar_videos_state.borrow_mut() = ff; + + if base_videos_size > 0 { + *shared_buttons.borrow_mut().get_mut(&NotebookMainEnum::SimilarVideos).unwrap().get_mut("save").unwrap() = true; + *shared_buttons.borrow_mut().get_mut(&NotebookMainEnum::SimilarVideos).unwrap().get_mut("delete").unwrap() = true; + *shared_buttons.borrow_mut().get_mut(&NotebookMainEnum::SimilarVideos).unwrap().get_mut("select").unwrap() = true; + *shared_buttons.borrow_mut().get_mut(&NotebookMainEnum::SimilarVideos).unwrap().get_mut("symlink").unwrap() = true; + *shared_buttons.borrow_mut().get_mut(&NotebookMainEnum::SimilarVideos).unwrap().get_mut("hardlink").unwrap() = true; + *shared_buttons.borrow_mut().get_mut(&NotebookMainEnum::SimilarVideos).unwrap().get_mut("move").unwrap() = true; + } else { + *shared_buttons.borrow_mut().get_mut(&NotebookMainEnum::SimilarVideos).unwrap().get_mut("save").unwrap() = false; + *shared_buttons.borrow_mut().get_mut(&NotebookMainEnum::SimilarVideos).unwrap().get_mut("delete").unwrap() = false; + *shared_buttons.borrow_mut().get_mut(&NotebookMainEnum::SimilarVideos).unwrap().get_mut("select").unwrap() = false; + *shared_buttons.borrow_mut().get_mut(&NotebookMainEnum::SimilarVideos).unwrap().get_mut("symlink").unwrap() = false; + *shared_buttons.borrow_mut().get_mut(&NotebookMainEnum::SimilarVideos).unwrap().get_mut("hardlink").unwrap() = false; + *shared_buttons.borrow_mut().get_mut(&NotebookMainEnum::SimilarVideos).unwrap().get_mut("move").unwrap() = false; + } + set_buttons(&mut *shared_buttons.borrow_mut().get_mut(&NotebookMainEnum::SimilarVideos).unwrap(), &buttons_array, &buttons_names); + } + } + } Message::ZeroedFiles(zf) => { if zf.get_stopped_search() { entry_info.set_text("Searching for zeroed files was stopped by user"); diff --git a/czkawka_gui/src/connect_progress_window.rs b/czkawka_gui/src/connect_progress_window.rs index 211275e..b9b27da 100644 --- a/czkawka_gui/src/connect_progress_window.rs +++ b/czkawka_gui/src/connect_progress_window.rs @@ -1,7 +1,7 @@ use crate::gui_data::GuiData; use crate::taskbar_progress::tbp_flags::TBPF_INDETERMINATE; -use czkawka_core::{big_file, broken_files, duplicate, empty_files, empty_folder, invalid_symlinks, same_music, similar_images, temporary, zeroed}; +use czkawka_core::{big_file, broken_files, duplicate, empty_files, empty_folder, invalid_symlinks, same_music, similar_images, similar_videos, temporary, zeroed}; use futures::StreamExt; @@ -16,6 +16,7 @@ pub fn connect_progress_window( mut futures_receiver_big_files: futures::channel::mpsc::UnboundedReceiver, mut futures_receiver_same_music: futures::channel::mpsc::UnboundedReceiver, mut futures_receiver_similar_images: futures::channel::mpsc::UnboundedReceiver, + mut futures_receiver_similar_videos: futures::channel::mpsc::UnboundedReceiver, mut futures_receiver_temporary: futures::channel::mpsc::UnboundedReceiver, mut futures_receiver_zeroed: futures::channel::mpsc::UnboundedReceiver, mut futures_receiver_invalid_symlinks: futures::channel::mpsc::UnboundedReceiver, @@ -229,6 +230,43 @@ pub fn connect_progress_window( }; main_context.spawn_local(future); } + { + // Similar Videos + let label_stage = gui_data.progress_window.label_stage.clone(); + let progress_bar_current_stage = gui_data.progress_window.progress_bar_current_stage.clone(); + let progress_bar_all_stages = gui_data.progress_window.progress_bar_all_stages.clone(); + let taskbar_state = gui_data.taskbar_state.clone(); + let future = async move { + while let Some(item) = futures_receiver_similar_videos.next().await { + match item.current_stage { + 0 => { + progress_bar_current_stage.hide(); + label_stage.set_text(format!("Scanned {} files", item.videos_checked).as_str()); + 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); + 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); + } else { + progress_bar_all_stages.set_fraction((1f64) / (item.max_stage + 1) as f64); + progress_bar_current_stage.set_fraction(0f64); + taskbar_state.borrow().set_progress_value(1, (item.max_stage + 1) as u64); + } + label_stage.set_text(format!("Hashing {}/{} video", item.videos_checked, item.videos_to_check).as_str()); + } + _ => { + panic!(); + } + } + } + }; + main_context.spawn_local(future); + } { // Temporary let label_stage = gui_data.progress_window.label_stage.clone(); diff --git a/czkawka_gui/src/connect_similar_image_size_change.rs b/czkawka_gui/src/connect_similar_image_size_change.rs index 5e41643..614b958 100644 --- a/czkawka_gui/src/connect_similar_image_size_change.rs +++ b/czkawka_gui/src/connect_similar_image_size_change.rs @@ -6,26 +6,26 @@ pub fn connect_similar_image_size_change(gui_data: &GuiData) { // This should set values to max possible value like in return_similarity_from_similarity_preset and get_string_from_similarity { let radio_button_similar_hash_size_4 = gui_data.main_notebook.radio_button_similar_hash_size_4.clone(); - let scale_similarity = gui_data.main_notebook.scale_similarity.clone(); + let scale_similarity_similar_images = gui_data.main_notebook.scale_similarity_similar_images.clone(); radio_button_similar_hash_size_4.connect_clicked(move |_| { - scale_similarity.set_range(0_f64, SIMILAR_VALUES[0][5] as f64); - scale_similarity.set_fill_level(SIMILAR_VALUES[0][5] as f64); + scale_similarity_similar_images.set_range(0_f64, SIMILAR_VALUES[0][5] as f64); + scale_similarity_similar_images.set_fill_level(SIMILAR_VALUES[0][5] as f64); }); } { let radio_button_similar_hash_size_8 = gui_data.main_notebook.radio_button_similar_hash_size_8.clone(); - let scale_similarity = gui_data.main_notebook.scale_similarity.clone(); + let scale_similarity_similar_images = gui_data.main_notebook.scale_similarity_similar_images.clone(); radio_button_similar_hash_size_8.connect_clicked(move |_| { - scale_similarity.set_range(0_f64, SIMILAR_VALUES[1][5] as f64); - scale_similarity.set_fill_level(SIMILAR_VALUES[1][5] as f64); + scale_similarity_similar_images.set_range(0_f64, SIMILAR_VALUES[1][5] as f64); + scale_similarity_similar_images.set_fill_level(SIMILAR_VALUES[1][5] as f64); }); } { let radio_button_similar_hash_size_16 = gui_data.main_notebook.radio_button_similar_hash_size_16.clone(); - let scale_similarity = gui_data.main_notebook.scale_similarity.clone(); + let scale_similarity_similar_images = gui_data.main_notebook.scale_similarity_similar_images.clone(); radio_button_similar_hash_size_16.connect_clicked(move |_| { - scale_similarity.set_range(0_f64, SIMILAR_VALUES[2][5] as f64); - scale_similarity.set_fill_level(SIMILAR_VALUES[2][5] as f64); + scale_similarity_similar_images.set_range(0_f64, SIMILAR_VALUES[2][5] as f64); + scale_similarity_similar_images.set_fill_level(SIMILAR_VALUES[2][5] as f64); }); } } diff --git a/czkawka_gui/src/create_tree_view.rs b/czkawka_gui/src/create_tree_view.rs index 19bedac..255652f 100644 --- a/czkawka_gui/src/create_tree_view.rs +++ b/czkawka_gui/src/create_tree_view.rs @@ -360,6 +360,75 @@ pub fn create_tree_view_similar_images(tree_view: &mut gtk::TreeView) { tree_view.set_vexpand(true); } +pub fn create_tree_view_similar_videos(tree_view: &mut gtk::TreeView) { + let model = get_list_store(tree_view); + + let renderer = gtk::CellRendererToggle::new(); + renderer.connect_toggled(move |_r, path| { + let iter = model.iter(&path).unwrap(); + let mut fixed = model + .value(&iter, ColumnsSimilarVideos::ActiveSelectButton as i32) + .get::() + .unwrap_or_else(|err| panic!("ListStore value missing at path {}: {}", path, err)); + fixed = !fixed; + model.set_value(&iter, ColumnsSimilarVideos::ActiveSelectButton as u32, &fixed.to_value()); + }); + let column = gtk::TreeViewColumn::new(); + column.pack_start(&renderer, true); + column.set_resizable(false); + column.set_fixed_width(30); + column.add_attribute(&renderer, "activatable", ColumnsSimilarVideos::ActivatableSelectButton as i32); + column.add_attribute(&renderer, "active", ColumnsSimilarVideos::ActiveSelectButton as i32); + column.add_attribute(&renderer, "cell-background", ColumnsSimilarVideos::Color as i32); + tree_view.append_column(&column); + + let renderer = gtk::CellRendererText::new(); + let column: gtk::TreeViewColumn = TreeViewColumn::new(); + column.pack_start(&renderer, true); + column.set_title("Size"); + column.set_resizable(true); + column.set_min_width(50); + column.add_attribute(&renderer, "text", ColumnsSimilarVideos::Size as i32); + column.add_attribute(&renderer, "background", ColumnsSimilarVideos::Color as i32); + column.add_attribute(&renderer, "foreground", ColumnsSimilarVideos::TextColor as i32); + tree_view.append_column(&column); + + let renderer = gtk::CellRendererText::new(); + let column: gtk::TreeViewColumn = TreeViewColumn::new(); + column.pack_start(&renderer, true); + column.set_title("File Name"); + column.set_resizable(true); + column.set_min_width(50); + column.add_attribute(&renderer, "text", ColumnsSimilarVideos::Name as i32); + column.add_attribute(&renderer, "background", ColumnsSimilarVideos::Color as i32); + column.add_attribute(&renderer, "foreground", ColumnsSimilarVideos::TextColor as i32); + tree_view.append_column(&column); + + let renderer = gtk::CellRendererText::new(); + let column: gtk::TreeViewColumn = TreeViewColumn::new(); + column.pack_start(&renderer, true); + column.set_title("Path"); + column.set_resizable(true); + column.set_min_width(50); + column.add_attribute(&renderer, "text", ColumnsSimilarVideos::Path as i32); + column.add_attribute(&renderer, "background", ColumnsSimilarVideos::Color as i32); + column.add_attribute(&renderer, "foreground", ColumnsSimilarVideos::TextColor as i32); + tree_view.append_column(&column); + + let renderer = gtk::CellRendererText::new(); + let column: gtk::TreeViewColumn = TreeViewColumn::new(); + column.pack_start(&renderer, true); + column.set_title("Modification Date"); + column.set_resizable(true); + column.set_min_width(50); + column.add_attribute(&renderer, "text", ColumnsSimilarVideos::Modification as i32); + column.add_attribute(&renderer, "background", ColumnsSimilarVideos::Color as i32); + column.add_attribute(&renderer, "foreground", ColumnsSimilarVideos::TextColor as i32); + tree_view.append_column(&column); + + tree_view.set_vexpand(true); +} + pub fn create_tree_view_directories(tree_view: &mut gtk::TreeView) { let renderer = gtk::CellRendererText::new(); let column: gtk::TreeViewColumn = TreeViewColumn::new(); diff --git a/czkawka_gui/src/double_click_opening.rs b/czkawka_gui/src/double_click_opening.rs index 5cfab70..b04450d 100644 --- a/czkawka_gui/src/double_click_opening.rs +++ b/czkawka_gui/src/double_click_opening.rs @@ -103,6 +103,19 @@ pub fn opening_enter_function_similar_images(tree_view: >k::TreeView, event: & handle_tree_keypress(tree_view, event, ColumnsSimilarImages::Name as u32, ColumnsSimilarImages::Path as u32, ColumnsSimilarImages::ActiveSelectButton as u32) } +pub fn opening_double_click_function_similar_videos(tree_view: >k::TreeView, event: &gdk::EventButton) -> gtk::Inhibit { + if event.event_type() == gdk::EventType::DoubleButtonPress && event.button() == 1 { + common_open_function(tree_view, ColumnsSimilarVideos::Name as i32, ColumnsSimilarVideos::Path as i32, OpenMode::PathAndName); + } else if event.event_type() == gdk::EventType::DoubleButtonPress && event.button() == 3 { + common_open_function(tree_view, ColumnsSimilarVideos::Name as i32, ColumnsSimilarVideos::Path as i32, OpenMode::OnlyPath); + } + gtk::Inhibit(false) +} + +pub fn opening_enter_function_similar_videos(tree_view: >k::TreeView, event: &gdk::EventKey) -> gtk::Inhibit { + handle_tree_keypress(tree_view, event, ColumnsSimilarVideos::Name as u32, ColumnsSimilarVideos::Path as u32, ColumnsSimilarVideos::ActiveSelectButton as u32) +} + pub fn opening_double_click_function_invalid_symlinks(tree_view: >k::TreeView, event: &gdk::EventButton) -> gtk::Inhibit { if event.event_type() == gdk::EventType::DoubleButtonPress && event.button() == 1 { common_open_function(tree_view, ColumnsInvalidSymlinks::Name as i32, ColumnsInvalidSymlinks::Path as i32, OpenMode::PathAndName); diff --git a/czkawka_gui/src/gui_data.rs b/czkawka_gui/src/gui_data.rs index 66741dd..73c2651 100644 --- a/czkawka_gui/src/gui_data.rs +++ b/czkawka_gui/src/gui_data.rs @@ -17,6 +17,7 @@ use czkawka_core::empty_folder::EmptyFolder; use czkawka_core::invalid_symlinks::InvalidSymlinks; use czkawka_core::same_music::SameMusic; use czkawka_core::similar_images::SimilarImages; +use czkawka_core::similar_videos::SimilarVideos; use czkawka_core::temporary::Temporary; use czkawka_core::zeroed::ZeroedFiles; use gtk::prelude::*; @@ -59,6 +60,7 @@ pub struct GuiData { pub shared_temporary_files_state: Rc>, pub shared_big_files_state: Rc>, pub shared_similar_images_state: Rc>, + pub shared_similar_videos_state: Rc>, pub shared_zeroed_files_state: Rc>, pub shared_same_music_state: Rc>, pub shared_same_invalid_symlinks: Rc>, @@ -139,6 +141,7 @@ impl GuiData { let shared_temporary_files_state: Rc> = Rc::new(RefCell::new(Temporary::new())); let shared_big_files_state: Rc> = Rc::new(RefCell::new(BigFile::new())); let shared_similar_images_state: Rc> = Rc::new(RefCell::new(SimilarImages::new())); + let shared_similar_videos_state: Rc> = Rc::new(RefCell::new(SimilarVideos::new())); let shared_zeroed_files_state: Rc> = Rc::new(RefCell::new(ZeroedFiles::new())); let shared_same_music_state: Rc> = Rc::new(RefCell::new(SameMusic::new())); let shared_same_invalid_symlinks: Rc> = Rc::new(RefCell::new(InvalidSymlinks::new())); @@ -176,6 +179,7 @@ impl GuiData { shared_temporary_files_state, shared_big_files_state, shared_similar_images_state, + shared_similar_videos_state, shared_zeroed_files_state, shared_same_music_state, shared_same_invalid_symlinks, diff --git a/czkawka_gui/src/gui_main_notebook.rs b/czkawka_gui/src/gui_main_notebook.rs index 6df640d..1f4a8b0 100644 --- a/czkawka_gui/src/gui_main_notebook.rs +++ b/czkawka_gui/src/gui_main_notebook.rs @@ -11,6 +11,7 @@ pub struct GuiMainNotebook { pub scrolled_window_temporary_files_finder: gtk::ScrolledWindow, pub scrolled_window_big_files_finder: gtk::ScrolledWindow, pub scrolled_window_similar_images_finder: gtk::ScrolledWindow, + pub scrolled_window_similar_videos_finder: gtk::ScrolledWindow, pub scrolled_window_zeroed_files_finder: gtk::ScrolledWindow, pub scrolled_window_same_music_finder: gtk::ScrolledWindow, pub scrolled_window_invalid_symlinks: gtk::ScrolledWindow, @@ -22,6 +23,7 @@ pub struct GuiMainNotebook { pub tree_view_temporary_files_finder: gtk::TreeView, pub tree_view_big_files_finder: gtk::TreeView, pub tree_view_similar_images_finder: gtk::TreeView, + pub tree_view_similar_videos_finder: gtk::TreeView, pub tree_view_zeroed_files_finder: gtk::TreeView, pub tree_view_same_music_finder: gtk::TreeView, pub tree_view_invalid_symlinks: gtk::TreeView, @@ -29,6 +31,8 @@ pub struct GuiMainNotebook { pub entry_similar_images_minimal_size: gtk::Entry, pub entry_similar_images_maximal_size: gtk::Entry, + pub entry_similar_videos_minimal_size: gtk::Entry, + pub entry_similar_videos_maximal_size: gtk::Entry, pub entry_duplicate_minimal_size: gtk::Entry, pub entry_duplicate_maximal_size: gtk::Entry, pub entry_same_music_minimal_size: gtk::Entry, @@ -50,7 +54,8 @@ pub struct GuiMainNotebook { pub radio_button_duplicates_hashmb: gtk::RadioButton, pub radio_button_duplicates_hash: gtk::RadioButton, - pub scale_similarity: gtk::Scale, + pub scale_similarity_similar_images: gtk::Scale, + pub scale_similarity_similar_videos: gtk::Scale, pub radio_button_hash_type_blake3: gtk::RadioButton, pub radio_button_hash_type_crc32: gtk::RadioButton, @@ -86,6 +91,7 @@ impl GuiMainNotebook { let scrolled_window_temporary_files_finder: gtk::ScrolledWindow = builder.object("scrolled_window_temporary_files_finder").unwrap(); let scrolled_window_big_files_finder: gtk::ScrolledWindow = builder.object("scrolled_window_big_files_finder").unwrap(); let scrolled_window_similar_images_finder: gtk::ScrolledWindow = builder.object("scrolled_window_similar_images_finder").unwrap(); + let scrolled_window_similar_videos_finder: gtk::ScrolledWindow = builder.object("scrolled_window_similar_videos_finder").unwrap(); let scrolled_window_zeroed_files_finder: gtk::ScrolledWindow = builder.object("scrolled_window_zeroed_files_finder").unwrap(); let scrolled_window_same_music_finder: gtk::ScrolledWindow = builder.object("scrolled_window_same_music_finder").unwrap(); let scrolled_window_invalid_symlinks: gtk::ScrolledWindow = builder.object("scrolled_window_invalid_symlinks").unwrap(); @@ -97,6 +103,7 @@ impl GuiMainNotebook { let tree_view_temporary_files_finder: gtk::TreeView = TreeView::new(); let tree_view_big_files_finder: gtk::TreeView = TreeView::new(); let tree_view_similar_images_finder: gtk::TreeView = TreeView::new(); + let tree_view_similar_videos_finder: gtk::TreeView = TreeView::new(); let tree_view_zeroed_files_finder: gtk::TreeView = TreeView::new(); let tree_view_same_music_finder: gtk::TreeView = TreeView::new(); let tree_view_invalid_symlinks: gtk::TreeView = TreeView::new(); @@ -104,6 +111,8 @@ impl GuiMainNotebook { let entry_similar_images_minimal_size: gtk::Entry = builder.object("entry_similar_images_minimal_size").unwrap(); let entry_similar_images_maximal_size: gtk::Entry = builder.object("entry_similar_images_maximal_size").unwrap(); + let entry_similar_videos_minimal_size: gtk::Entry = builder.object("entry_similar_videos_minimal_size").unwrap(); + let entry_similar_videos_maximal_size: gtk::Entry = builder.object("entry_similar_videos_maximal_size").unwrap(); let entry_duplicate_minimal_size: gtk::Entry = builder.object("entry_duplicate_minimal_size").unwrap(); let entry_duplicate_maximal_size: gtk::Entry = builder.object("entry_duplicate_maximal_size").unwrap(); let entry_same_music_minimal_size: gtk::Entry = builder.object("entry_same_music_minimal_size").unwrap(); @@ -124,7 +133,8 @@ impl GuiMainNotebook { let radio_button_duplicates_hashmb: gtk::RadioButton = builder.object("radio_button_duplicates_hashmb").unwrap(); let radio_button_duplicates_hash: gtk::RadioButton = builder.object("radio_button_duplicates_hash").unwrap(); - let scale_similarity: gtk::Scale = builder.object("scale_similarity").unwrap(); + let scale_similarity_similar_images: gtk::Scale = builder.object("scale_similarity_similar_images").unwrap(); + let scale_similarity_similar_videos: gtk::Scale = builder.object("scale_similarity_similar_videos").unwrap(); let radio_button_hash_type_blake3: gtk::RadioButton = builder.object("radio_button_hash_type_blake3").unwrap(); let radio_button_hash_type_crc32: gtk::RadioButton = builder.object("radio_button_hash_type_crc32").unwrap(); @@ -157,6 +167,7 @@ impl GuiMainNotebook { scrolled_window_temporary_files_finder, scrolled_window_big_files_finder, scrolled_window_similar_images_finder, + scrolled_window_similar_videos_finder, scrolled_window_zeroed_files_finder, scrolled_window_same_music_finder, scrolled_window_invalid_symlinks, @@ -167,12 +178,15 @@ impl GuiMainNotebook { tree_view_temporary_files_finder, tree_view_big_files_finder, tree_view_similar_images_finder, + tree_view_similar_videos_finder, tree_view_zeroed_files_finder, tree_view_same_music_finder, tree_view_invalid_symlinks, tree_view_broken_files, entry_similar_images_minimal_size, entry_similar_images_maximal_size, + entry_similar_videos_minimal_size, + entry_similar_videos_maximal_size, entry_duplicate_minimal_size, entry_big_files_number, entry_same_music_minimal_size, @@ -185,7 +199,8 @@ impl GuiMainNotebook { radio_button_duplicates_size, radio_button_duplicates_hashmb, radio_button_duplicates_hash, - scale_similarity, + scale_similarity_similar_images, + scale_similarity_similar_videos, radio_button_hash_type_blake3, radio_button_hash_type_crc32, radio_button_hash_type_xxh3, diff --git a/czkawka_gui/src/help_functions.rs b/czkawka_gui/src/help_functions.rs index 7466e32..0cb97e5 100644 --- a/czkawka_gui/src/help_functions.rs +++ b/czkawka_gui/src/help_functions.rs @@ -8,6 +8,7 @@ use czkawka_core::invalid_symlinks; use czkawka_core::invalid_symlinks::InvalidSymlinks; use czkawka_core::same_music::SameMusic; use czkawka_core::similar_images::SimilarImages; +use czkawka_core::similar_videos::SimilarVideos; use czkawka_core::temporary::Temporary; use czkawka_core::zeroed::ZeroedFiles; use gtk::prelude::*; @@ -22,6 +23,7 @@ pub enum Message { BigFiles(BigFile), Temporary(Temporary), SimilarImages(SimilarImages), + SimilarVideos(SimilarVideos), ZeroedFiles(ZeroedFiles), SameMusic(SameMusic), InvalidSymlinks(InvalidSymlinks), @@ -85,6 +87,19 @@ pub enum ColumnsSimilarImages { Color, TextColor, } + +pub enum ColumnsSimilarVideos { + ActivatableSelectButton = 0, + ActiveSelectButton, + Size, + SizeAsBytes, + Name, + Path, + Modification, + ModificationAsSecs, + Color, + TextColor, +} pub enum ColumnsZeroedFiles { ActiveSelectButton = 0, Size, @@ -242,6 +257,15 @@ pub fn select_function_similar_images(_tree_selection: >k::TreeSelection, tree true } +pub fn select_function_similar_videos(_tree_selection: >k::TreeSelection, tree_model: >k::TreeModel, tree_path: >k::TreePath, _is_path_currently_selected: bool) -> bool { + let color = tree_model.value(&tree_model.iter(tree_path).unwrap(), ColumnsSimilarVideos::Color as i32).get::().unwrap(); + + if color == HEADER_ROW_COLOR { + return false; + } + + true +} pub fn set_buttons(hashmap: &mut HashMap, buttons_array: &[gtk::Button], button_names: &[String]) { for (index, button) in buttons_array.iter().enumerate() { diff --git a/czkawka_gui/src/initialize_gui.rs b/czkawka_gui/src/initialize_gui.rs index 50d36ec..b8a2a8e 100644 --- a/czkawka_gui/src/initialize_gui.rs +++ b/czkawka_gui/src/initialize_gui.rs @@ -4,6 +4,7 @@ use crate::double_click_opening::*; use crate::gui_data::*; use crate::help_functions::*; use czkawka_core::similar_images::SIMILAR_VALUES; +use czkawka_core::similar_videos::MAX_TOLERANCE; use directories_next::ProjectDirs; use gtk::prelude::*; use gtk::{CheckButton, Image, SelectionMode, TextView, TreeView}; @@ -42,6 +43,7 @@ pub fn initialize_gui(gui_data: &mut GuiData) { let scrolled_window_temporary_files_finder = gui_data.main_notebook.scrolled_window_temporary_files_finder.clone(); let scrolled_window_big_files_finder = gui_data.main_notebook.scrolled_window_big_files_finder.clone(); let scrolled_window_similar_images_finder = gui_data.main_notebook.scrolled_window_similar_images_finder.clone(); + let scrolled_window_similar_videos_finder = gui_data.main_notebook.scrolled_window_similar_videos_finder.clone(); let scrolled_window_same_music_finder = gui_data.main_notebook.scrolled_window_same_music_finder.clone(); let scrolled_window_invalid_symlinks = gui_data.main_notebook.scrolled_window_invalid_symlinks.clone(); let scrolled_window_zeroed_files_finder = gui_data.main_notebook.scrolled_window_zeroed_files_finder.clone(); @@ -53,13 +55,21 @@ pub fn initialize_gui(gui_data: &mut GuiData) { let check_button_settings_show_preview_duplicates = gui_data.settings.check_button_settings_show_preview_duplicates.clone(); let text_view_errors = gui_data.text_view_errors.clone(); - let scale_similarity = gui_data.main_notebook.scale_similarity.clone(); + let scale_similarity_similar_images = gui_data.main_notebook.scale_similarity_similar_images.clone(); + let scale_similarity_similar_videos = gui_data.main_notebook.scale_similarity_similar_videos.clone(); // Set step increment { - scale_similarity.set_range(0_f64, SIMILAR_VALUES[1][5] as f64); // This defaults to value of minimal size of hash 8 - scale_similarity.set_fill_level(SIMILAR_VALUES[1][5] as f64); - scale_similarity.adjustment().set_step_increment(1_f64); + scale_similarity_similar_images.set_range(0_f64, SIMILAR_VALUES[1][5] as f64); // This defaults to value of minimal size of hash 8 + scale_similarity_similar_images.set_fill_level(SIMILAR_VALUES[1][5] as f64); + scale_similarity_similar_images.adjustment().set_step_increment(1_f64); + } + // Set step increment + { + scale_similarity_similar_videos.set_range(0_f64, MAX_TOLERANCE as f64); // This defaults to value of minimal size of hash 8 + scale_similarity_similar_videos.set_value(15_f64); + scale_similarity_similar_videos.set_fill_level(MAX_TOLERANCE as f64); + scale_similarity_similar_videos.adjustment().set_step_increment(1_f64); } // Set Main Scrolled Window Treeviews @@ -363,6 +373,71 @@ pub fn initialize_gui(gui_data: &mut GuiData) { gtk::Inhibit(false) }); } + // Similar Videos + { + let col_types: [glib::types::Type; 10] = [ + glib::types::Type::BOOL, // ActivatableSelectButton + glib::types::Type::BOOL, // ActiveSelectButton + 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::STRING, // TextColor + ]; + let list_store: gtk::ListStore = gtk::ListStore::new(&col_types); + + let mut tree_view: gtk::TreeView = TreeView::with_model(&list_store); + + tree_view.selection().set_mode(SelectionMode::Multiple); + tree_view.selection().set_select_function(Some(Box::new(select_function_similar_videos))); + + create_tree_view_similar_videos(&mut tree_view); + + tree_view.connect_button_press_event(opening_double_click_function_similar_videos); + tree_view.connect_key_press_event(opening_enter_function_similar_videos); + + gui_data.main_notebook.tree_view_similar_videos_finder = tree_view.clone(); + scrolled_window_similar_videos_finder.add(&tree_view); + scrolled_window_similar_videos_finder.show_all(); + + let gui_data = gui_data.clone(); + tree_view.connect_key_release_event(move |tree_view, e| { + if let Some(button_number) = e.keycode() { + // Handle delete button + if button_number == 119 { + if tree_view.selection().selected_rows().0.is_empty() { + return gtk::Inhibit(false); + } + if !check_if_can_delete_files(&gui_data.settings.check_button_settings_confirm_deletion, &gui_data.window_main) { + return gtk::Inhibit(false); + } + if gui_data.settings.check_button_settings_confirm_group_deletion.is_active() + && check_if_deleting_all_files_in_group( + &tree_view.clone(), + ColumnsSimilarVideos::Color as i32, + ColumnsSimilarVideos::ActiveSelectButton as i32, + &gui_data.window_main, + &gui_data.settings.check_button_settings_confirm_group_deletion, + ) + { + return gtk::Inhibit(false); + } + tree_remove( + tree_view, + ColumnsSimilarVideos::Name as i32, + ColumnsSimilarVideos::Path as i32, + ColumnsSimilarVideos::Color as i32, + ColumnsSimilarVideos::ActiveSelectButton as i32, + &gui_data, + ); + } + } + gtk::Inhibit(false) + }); + } // Zeroed Files { let col_types: [glib::types::Type; 6] = [ diff --git a/czkawka_gui/src/main.rs b/czkawka_gui/src/main.rs index b882a88..b045078 100644 --- a/czkawka_gui/src/main.rs +++ b/czkawka_gui/src/main.rs @@ -99,6 +99,8 @@ fn main() { let (futures_sender_same_music, futures_receiver_same_music): (futures::channel::mpsc::UnboundedSender, futures::channel::mpsc::UnboundedReceiver) = futures::channel::mpsc::unbounded(); let (futures_sender_similar_images, futures_receiver_similar_images): (futures::channel::mpsc::UnboundedSender, futures::channel::mpsc::UnboundedReceiver) = futures::channel::mpsc::unbounded(); + let (futures_sender_similar_videos, futures_receiver_similar_videos): (futures::channel::mpsc::UnboundedSender, futures::channel::mpsc::UnboundedReceiver) = + futures::channel::mpsc::unbounded(); let (futures_sender_temporary, futures_receiver_temporary): (futures::channel::mpsc::UnboundedSender, futures::channel::mpsc::UnboundedReceiver) = futures::channel::mpsc::unbounded(); let (futures_sender_zeroed, futures_receiver_zeroed): (futures::channel::mpsc::UnboundedSender, futures::channel::mpsc::UnboundedReceiver) = futures::channel::mpsc::unbounded(); let (futures_sender_invalid_symlinks, futures_receiver_invalid_symlinks): (futures::channel::mpsc::UnboundedSender, futures::channel::mpsc::UnboundedReceiver) = @@ -120,6 +122,7 @@ fn main() { futures_sender_big_file, futures_sender_same_music, futures_sender_similar_images, + futures_sender_similar_videos, futures_sender_temporary, futures_sender_zeroed, futures_sender_invalid_symlinks, @@ -142,6 +145,7 @@ fn main() { futures_receiver_big_file, futures_receiver_same_music, futures_receiver_similar_images, + futures_receiver_similar_videos, futures_receiver_temporary, futures_receiver_zeroed, futures_receiver_invalid_symlinks, diff --git a/czkawka_gui/src/notebook_enums.rs b/czkawka_gui/src/notebook_enums.rs index d48690a..0d20140 100644 --- a/czkawka_gui/src/notebook_enums.rs +++ b/czkawka_gui/src/notebook_enums.rs @@ -1,4 +1,4 @@ -pub const NUMBER_OF_NOTEBOOK_MAIN_TABS: usize = 10; +pub const NUMBER_OF_NOTEBOOK_MAIN_TABS: usize = 11; pub const NUMBER_OF_NOTEBOOK_UPPER_TABS: usize = 4; // Needs to be updated when changed order of notebook tabs @@ -10,6 +10,7 @@ pub enum NotebookMainEnum { EmptyFiles, Temporary, SimilarImages, + SimilarVideos, SameMusic, Zeroed, Symlinks, @@ -23,10 +24,11 @@ pub fn to_notebook_main_enum(notebook_number: u32) -> NotebookMainEnum { 3 => NotebookMainEnum::EmptyFiles, 4 => NotebookMainEnum::Temporary, 5 => NotebookMainEnum::SimilarImages, - 6 => NotebookMainEnum::SameMusic, - 7 => NotebookMainEnum::Zeroed, - 8 => NotebookMainEnum::Symlinks, - 9 => NotebookMainEnum::BrokenFiles, + 6 => NotebookMainEnum::SimilarVideos, + 7 => NotebookMainEnum::SameMusic, + 8 => NotebookMainEnum::Zeroed, + 9 => NotebookMainEnum::Symlinks, + 10 => NotebookMainEnum::BrokenFiles, _ => panic!("Invalid Notebook Tab"), } } @@ -42,6 +44,7 @@ pub fn get_all_main_tabs() -> [NotebookMainEnum; NUMBER_OF_NOTEBOOK_MAIN_TABS] { to_notebook_main_enum(7), to_notebook_main_enum(8), to_notebook_main_enum(9), + to_notebook_main_enum(10), ] } diff --git a/czkawka_gui/ui/main_window.glade b/czkawka_gui/ui/main_window.glade index 6ecb1a0..bbe547b 100644 --- a/czkawka_gui/ui/main_window.glade +++ b/czkawka_gui/ui/main_window.glade @@ -1467,7 +1467,7 @@ Author: Rafał Mikrut - + True True 100 @@ -1552,6 +1552,182 @@ Author: Rafał Mikrut False + + + True + False + vertical + + + True + False + 8 + + + True + False + Size(bytes) + + + False + True + 0 + + + + + True + False + Min: + + + False + True + 1 + + + + + True + True + 15 + 16384 + False + number + + + True + True + 2 + + + + + True + False + Max: + + + False + True + 4 + + + + + True + True + 15 + 1099512000000 + False + number + + + True + True + 5 + + + + + False + True + 3 + + + + + True + False + + + True + False + Similarity + + + False + True + 0 + + + + + True + False + Very High + + + False + True + 1 + + + + + True + True + 100 + 0 + 0 + right + + + True + True + 2 + + + + + True + False + Minimal + + + False + True + 3 + + + + + False + True + 4 + + + + + True + True + in + + + + + + True + True + 5 + + + + + 6 + + + + + True + False + Similar Videos + + + 6 + False + + True @@ -1736,7 +1912,7 @@ Author: Rafał Mikrut - 6 + 7 @@ -1746,7 +1922,7 @@ Author: Rafał Mikrut Music Duplicates - 6 + 7 False @@ -1772,7 +1948,7 @@ Author: Rafał Mikrut - 7 + 8 @@ -1782,7 +1958,7 @@ Author: Rafał Mikrut Zeroed Files - 7 + 8 False @@ -1796,7 +1972,7 @@ Author: Rafał Mikrut - 8 + 9 @@ -1806,7 +1982,7 @@ Author: Rafał Mikrut Invalid Symlinks - 8 + 9 False @@ -1820,7 +1996,7 @@ Author: Rafał Mikrut - 9 + 10 @@ -1830,7 +2006,7 @@ Author: Rafał Mikrut Broken Files - 9 + 10 False diff --git a/flatpak/cargo-sources.json b/flatpak/cargo-sources.json deleted file mode 100644 index 24e8199..0000000 --- a/flatpak/cargo-sources.json +++ /dev/null @@ -1,2953 +0,0 @@ -[ - { - "type": "file", - "url": "https://static.crates.io/crates/adler/adler-1.0.2.crate", - "sha256": "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe", - "dest": "cargo/vendor", - "dest-filename": "adler-1.0.2.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/adler-1.0.2", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/adler32/adler32-1.2.0.crate", - "sha256": "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234", - "dest": "cargo/vendor", - "dest-filename": "adler32-1.2.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/adler32-1.2.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/alsa/alsa-0.5.0.crate", - "sha256": "75c4da790adcb2ce5e758c064b4f3ec17a30349f9961d3e5e6c9688b052a9e18", - "dest": "cargo/vendor", - "dest-filename": "alsa-0.5.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2275c4da790adcb2ce5e758c064b4f3ec17a30349f9961d3e5e6c9688b052a9e18%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/alsa-0.5.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/alsa-sys/alsa-sys-0.3.1.crate", - "sha256": "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527", - "dest": "cargo/vendor", - "dest-filename": "alsa-sys-0.3.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/alsa-sys-0.3.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/ansi_term/ansi_term-0.11.0.crate", - "sha256": "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b", - "dest": "cargo/vendor", - "dest-filename": "ansi_term-0.11.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/ansi_term-0.11.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/anyhow/anyhow-1.0.40.crate", - "sha256": "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b", - "dest": "cargo/vendor", - "dest-filename": "anyhow-1.0.40.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2228b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/anyhow-1.0.40", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/arrayref/arrayref-0.3.6.crate", - "sha256": "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544", - "dest": "cargo/vendor", - "dest-filename": "arrayref-0.3.6.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/arrayref-0.3.6", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/arrayvec/arrayvec-0.5.2.crate", - "sha256": "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b", - "dest": "cargo/vendor", - "dest-filename": "arrayvec-0.5.2.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2223b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/arrayvec-0.5.2", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/atk/atk-0.9.0.crate", - "sha256": "812b4911e210bd51b24596244523c856ca749e6223c50a7fbbba3f89ee37c426", - "dest": "cargo/vendor", - "dest-filename": "atk-0.9.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22812b4911e210bd51b24596244523c856ca749e6223c50a7fbbba3f89ee37c426%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/atk-0.9.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/atk-sys/atk-sys-0.10.0.crate", - "sha256": "f530e4af131d94cc4fa15c5c9d0348f0ef28bac64ba660b6b2a1cf2605dedfce", - "dest": "cargo/vendor", - "dest-filename": "atk-sys-0.10.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22f530e4af131d94cc4fa15c5c9d0348f0ef28bac64ba660b6b2a1cf2605dedfce%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/atk-sys-0.10.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/atty/atty-0.2.14.crate", - "sha256": "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8", - "dest": "cargo/vendor", - "dest-filename": "atty-0.2.14.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/atty-0.2.14", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/audiotags/audiotags-0.2.7182.crate", - "sha256": "b87d111118f42416bb5f13c5dd2e2d879925964702a435be711d4f78fa9ce6d8", - "dest": "cargo/vendor", - "dest-filename": "audiotags-0.2.7182.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22b87d111118f42416bb5f13c5dd2e2d879925964702a435be711d4f78fa9ce6d8%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/audiotags-0.2.7182", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/audiotags-dev-macro/audiotags-dev-macro-0.1.4.crate", - "sha256": "3b79298591161f312f06327df7963063ee07466be303dcc3084a44ec293cb36e", - "dest": "cargo/vendor", - "dest-filename": "audiotags-dev-macro-0.1.4.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%223b79298591161f312f06327df7963063ee07466be303dcc3084a44ec293cb36e%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/audiotags-dev-macro-0.1.4", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/autocfg/autocfg-1.0.1.crate", - "sha256": "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a", - "dest": "cargo/vendor", - "dest-filename": "autocfg-1.0.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/autocfg-1.0.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/base64/base64-0.13.0.crate", - "sha256": "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd", - "dest": "cargo/vendor", - "dest-filename": "base64-0.13.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/base64-0.13.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/bindgen/bindgen-0.56.0.crate", - "sha256": "2da379dbebc0b76ef63ca68d8fc6e71c0f13e59432e0987e508c1820e6ab5239", - "dest": "cargo/vendor", - "dest-filename": "bindgen-0.56.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%222da379dbebc0b76ef63ca68d8fc6e71c0f13e59432e0987e508c1820e6ab5239%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/bindgen-0.56.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/bitflags/bitflags-1.2.1.crate", - "sha256": "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693", - "dest": "cargo/vendor", - "dest-filename": "bitflags-1.2.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/bitflags-1.2.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/bk-tree/bk-tree-0.3.0.crate", - "sha256": "5488039ea2c6de8668351415e39a0218a8955bffadcff0cf01d1293a20854584", - "dest": "cargo/vendor", - "dest-filename": "bk-tree-0.3.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%225488039ea2c6de8668351415e39a0218a8955bffadcff0cf01d1293a20854584%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/bk-tree-0.3.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/blake3/blake3-0.3.7.crate", - "sha256": "e9ff35b701f3914bdb8fad3368d822c766ef2858b2583198e41639b936f09d3f", - "dest": "cargo/vendor", - "dest-filename": "blake3-0.3.7.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22e9ff35b701f3914bdb8fad3368d822c766ef2858b2583198e41639b936f09d3f%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/blake3-0.3.7", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/bumpalo/bumpalo-3.6.1.crate", - "sha256": "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe", - "dest": "cargo/vendor", - "dest-filename": "bumpalo-3.6.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2263396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/bumpalo-3.6.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/bytemuck/bytemuck-1.5.1.crate", - "sha256": "bed57e2090563b83ba8f83366628ce535a7584c9afa4c9fc0612a03925c6df58", - "dest": "cargo/vendor", - "dest-filename": "bytemuck-1.5.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22bed57e2090563b83ba8f83366628ce535a7584c9afa4c9fc0612a03925c6df58%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/bytemuck-1.5.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/byteorder/byteorder-1.4.3.crate", - "sha256": "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610", - "dest": "cargo/vendor", - "dest-filename": "byteorder-1.4.3.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2214c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/byteorder-1.4.3", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/bytes/bytes-1.0.1.crate", - "sha256": "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040", - "dest": "cargo/vendor", - "dest-filename": "bytes-1.0.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/bytes-1.0.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/bzip2/bzip2-0.3.3.crate", - "sha256": "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b", - "dest": "cargo/vendor", - "dest-filename": "bzip2-0.3.3.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2242b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/bzip2-0.3.3", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/bzip2-sys/bzip2-sys-0.1.10+1.0.8.crate", - "sha256": "17fa3d1ac1ca21c5c4e36a97f3c3eb25084576f6fc47bf0139c1123434216c6c", - "dest": "cargo/vendor", - "dest-filename": "bzip2-sys-0.1.10+1.0.8.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2217fa3d1ac1ca21c5c4e36a97f3c3eb25084576f6fc47bf0139c1123434216c6c%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/bzip2-sys-0.1.10+1.0.8", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/cairo-rs/cairo-rs-0.9.1.crate", - "sha256": "c5c0f2e047e8ca53d0ff249c54ae047931d7a6ebe05d00af73e0ffeb6e34bdb8", - "dest": "cargo/vendor", - "dest-filename": "cairo-rs-0.9.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22c5c0f2e047e8ca53d0ff249c54ae047931d7a6ebe05d00af73e0ffeb6e34bdb8%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/cairo-rs-0.9.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/cairo-sys-rs/cairo-sys-rs-0.10.0.crate", - "sha256": "2ed2639b9ad5f1d6efa76de95558e11339e7318426d84ac4890b86c03e828ca7", - "dest": "cargo/vendor", - "dest-filename": "cairo-sys-rs-0.10.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%222ed2639b9ad5f1d6efa76de95558e11339e7318426d84ac4890b86c03e828ca7%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/cairo-sys-rs-0.10.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/cc/cc-1.0.67.crate", - "sha256": "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd", - "dest": "cargo/vendor", - "dest-filename": "cc-1.0.67.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/cc-1.0.67", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/cesu8/cesu8-1.1.0.crate", - "sha256": "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c", - "dest": "cargo/vendor", - "dest-filename": "cesu8-1.1.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%226d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/cesu8-1.1.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/cexpr/cexpr-0.4.0.crate", - "sha256": "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27", - "dest": "cargo/vendor", - "dest-filename": "cexpr-0.4.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/cexpr-0.4.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/cfg-if/cfg-if-0.1.10.crate", - "sha256": "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822", - "dest": "cargo/vendor", - "dest-filename": "cfg-if-0.1.10.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%224785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/cfg-if-0.1.10", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/cfg-if/cfg-if-1.0.0.crate", - "sha256": "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd", - "dest": "cargo/vendor", - "dest-filename": "cfg-if-1.0.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/cfg-if-1.0.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/chrono/chrono-0.4.19.crate", - "sha256": "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73", - "dest": "cargo/vendor", - "dest-filename": "chrono-0.4.19.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/chrono-0.4.19", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/clang-sys/clang-sys-1.2.0.crate", - "sha256": "853eda514c284c2287f4bf20ae614f8781f40a81d32ecda6e91449304dfe077c", - "dest": "cargo/vendor", - "dest-filename": "clang-sys-1.2.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22853eda514c284c2287f4bf20ae614f8781f40a81d32ecda6e91449304dfe077c%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/clang-sys-1.2.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/clap/clap-2.33.3.crate", - "sha256": "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002", - "dest": "cargo/vendor", - "dest-filename": "clap-2.33.3.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2237e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/clap-2.33.3", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/claxon/claxon-0.4.3.crate", - "sha256": "4bfbf56724aa9eca8afa4fcfadeb479e722935bb2a0900c2d37e0cc477af0688", - "dest": "cargo/vendor", - "dest-filename": "claxon-0.4.3.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%224bfbf56724aa9eca8afa4fcfadeb479e722935bb2a0900c2d37e0cc477af0688%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/claxon-0.4.3", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/color_quant/color_quant-1.1.0.crate", - "sha256": "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b", - "dest": "cargo/vendor", - "dest-filename": "color_quant-1.1.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%223d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/color_quant-1.1.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/combine/combine-4.5.2.crate", - "sha256": "cc4369b5e4c0cddf64ad8981c0111e7df4f7078f4d6ba98fb31f2e17c4c57b7e", - "dest": "cargo/vendor", - "dest-filename": "combine-4.5.2.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22cc4369b5e4c0cddf64ad8981c0111e7df4f7078f4d6ba98fb31f2e17c4c57b7e%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/combine-4.5.2", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/constant_time_eq/constant_time_eq-0.1.5.crate", - "sha256": "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc", - "dest": "cargo/vendor", - "dest-filename": "constant_time_eq-0.1.5.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/constant_time_eq-0.1.5", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/core-foundation-sys/core-foundation-sys-0.6.2.crate", - "sha256": "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b", - "dest": "cargo/vendor", - "dest-filename": "core-foundation-sys-0.6.2.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/core-foundation-sys-0.6.2", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/coreaudio-rs/coreaudio-rs-0.10.0.crate", - "sha256": "11894b20ebfe1ff903cbdc52259693389eea03b94918a2def2c30c3bf227ad88", - "dest": "cargo/vendor", - "dest-filename": "coreaudio-rs-0.10.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2211894b20ebfe1ff903cbdc52259693389eea03b94918a2def2c30c3bf227ad88%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/coreaudio-rs-0.10.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/coreaudio-sys/coreaudio-sys-0.2.8.crate", - "sha256": "2b7e3347be6a09b46aba228d6608386739fb70beff4f61e07422da87b0bb31fa", - "dest": "cargo/vendor", - "dest-filename": "coreaudio-sys-0.2.8.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%222b7e3347be6a09b46aba228d6608386739fb70beff4f61e07422da87b0bb31fa%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/coreaudio-sys-0.2.8", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/cpal/cpal-0.13.3.crate", - "sha256": "8351ddf2aaa3c583fa388029f8b3d26f3c7035a20911fdd5f2e2ed7ab57dad25", - "dest": "cargo/vendor", - "dest-filename": "cpal-0.13.3.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%228351ddf2aaa3c583fa388029f8b3d26f3c7035a20911fdd5f2e2ed7ab57dad25%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/cpal-0.13.3", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/crc32fast/crc32fast-1.2.1.crate", - "sha256": "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a", - "dest": "cargo/vendor", - "dest-filename": "crc32fast-1.2.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2281156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/crc32fast-1.2.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/crossbeam-channel/crossbeam-channel-0.5.1.crate", - "sha256": "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4", - "dest": "cargo/vendor", - "dest-filename": "crossbeam-channel-0.5.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2206ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/crossbeam-channel-0.5.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/crossbeam-deque/crossbeam-deque-0.8.0.crate", - "sha256": "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9", - "dest": "cargo/vendor", - "dest-filename": "crossbeam-deque-0.8.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2294af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/crossbeam-deque-0.8.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/crossbeam-epoch/crossbeam-epoch-0.9.4.crate", - "sha256": "52fb27eab85b17fbb9f6fd667089e07d6a2eb8743d02639ee7f6a7a7729c9c94", - "dest": "cargo/vendor", - "dest-filename": "crossbeam-epoch-0.9.4.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2252fb27eab85b17fbb9f6fd667089e07d6a2eb8743d02639ee7f6a7a7729c9c94%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/crossbeam-epoch-0.9.4", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/crossbeam-utils/crossbeam-utils-0.8.4.crate", - "sha256": "4feb231f0d4d6af81aed15928e58ecf5816aa62a2393e2c82f46973e92a9a278", - "dest": "cargo/vendor", - "dest-filename": "crossbeam-utils-0.8.4.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%224feb231f0d4d6af81aed15928e58ecf5816aa62a2393e2c82f46973e92a9a278%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/crossbeam-utils-0.8.4", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/crypto-mac/crypto-mac-0.8.0.crate", - "sha256": "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab", - "dest": "cargo/vendor", - "dest-filename": "crypto-mac-0.8.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/crypto-mac-0.8.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/darling/darling-0.10.2.crate", - "sha256": "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858", - "dest": "cargo/vendor", - "dest-filename": "darling-0.10.2.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%220d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/darling-0.10.2", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/darling_core/darling_core-0.10.2.crate", - "sha256": "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b", - "dest": "cargo/vendor", - "dest-filename": "darling_core-0.10.2.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/darling_core-0.10.2", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/darling_macro/darling_macro-0.10.2.crate", - "sha256": "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72", - "dest": "cargo/vendor", - "dest-filename": "darling_macro-0.10.2.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/darling_macro-0.10.2", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/deflate/deflate-0.8.6.crate", - "sha256": "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174", - "dest": "cargo/vendor", - "dest-filename": "deflate-0.8.6.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2273770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/deflate-0.8.6", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/derivative/derivative-2.2.0.crate", - "sha256": "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b", - "dest": "cargo/vendor", - "dest-filename": "derivative-2.2.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/derivative-2.2.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/digest/digest-0.9.0.crate", - "sha256": "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066", - "dest": "cargo/vendor", - "dest-filename": "digest-0.9.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/digest-0.9.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/directories-next/directories-next-2.0.0.crate", - "sha256": "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc", - "dest": "cargo/vendor", - "dest-filename": "directories-next-2.0.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/directories-next-2.0.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/dirs-sys-next/dirs-sys-next-0.1.2.crate", - "sha256": "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d", - "dest": "cargo/vendor", - "dest-filename": "dirs-sys-next-0.1.2.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%224ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/dirs-sys-next-0.1.2", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/either/either-1.6.1.crate", - "sha256": "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457", - "dest": "cargo/vendor", - "dest-filename": "either-1.6.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/either-1.6.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/flate2/flate2-1.0.20.crate", - "sha256": "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0", - "dest": "cargo/vendor", - "dest-filename": "flate2-1.0.20.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/flate2-1.0.20", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/fnv/fnv-1.0.7.crate", - "sha256": "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1", - "dest": "cargo/vendor", - "dest-filename": "fnv-1.0.7.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%223f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/fnv-1.0.7", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/futures/futures-0.3.14.crate", - "sha256": "a9d5813545e459ad3ca1bff9915e9ad7f1a47dc6a91b627ce321d5863b7dd253", - "dest": "cargo/vendor", - "dest-filename": "futures-0.3.14.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22a9d5813545e459ad3ca1bff9915e9ad7f1a47dc6a91b627ce321d5863b7dd253%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/futures-0.3.14", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/futures-channel/futures-channel-0.3.14.crate", - "sha256": "ce79c6a52a299137a6013061e0cf0e688fce5d7f1bc60125f520912fdb29ec25", - "dest": "cargo/vendor", - "dest-filename": "futures-channel-0.3.14.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22ce79c6a52a299137a6013061e0cf0e688fce5d7f1bc60125f520912fdb29ec25%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/futures-channel-0.3.14", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/futures-core/futures-core-0.3.14.crate", - "sha256": "098cd1c6dda6ca01650f1a37a794245eb73181d0d4d4e955e2f3c37db7af1815", - "dest": "cargo/vendor", - "dest-filename": "futures-core-0.3.14.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22098cd1c6dda6ca01650f1a37a794245eb73181d0d4d4e955e2f3c37db7af1815%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/futures-core-0.3.14", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/futures-executor/futures-executor-0.3.14.crate", - "sha256": "10f6cb7042eda00f0049b1d2080aa4b93442997ee507eb3828e8bd7577f94c9d", - "dest": "cargo/vendor", - "dest-filename": "futures-executor-0.3.14.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2210f6cb7042eda00f0049b1d2080aa4b93442997ee507eb3828e8bd7577f94c9d%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/futures-executor-0.3.14", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/futures-io/futures-io-0.3.14.crate", - "sha256": "365a1a1fb30ea1c03a830fdb2158f5236833ac81fa0ad12fe35b29cddc35cb04", - "dest": "cargo/vendor", - "dest-filename": "futures-io-0.3.14.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22365a1a1fb30ea1c03a830fdb2158f5236833ac81fa0ad12fe35b29cddc35cb04%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/futures-io-0.3.14", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/futures-macro/futures-macro-0.3.14.crate", - "sha256": "668c6733a182cd7deb4f1de7ba3bf2120823835b3bcfbeacf7d2c4a773c1bb8b", - "dest": "cargo/vendor", - "dest-filename": "futures-macro-0.3.14.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22668c6733a182cd7deb4f1de7ba3bf2120823835b3bcfbeacf7d2c4a773c1bb8b%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/futures-macro-0.3.14", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/futures-sink/futures-sink-0.3.14.crate", - "sha256": "5c5629433c555de3d82861a7a4e3794a4c40040390907cfbfd7143a92a426c23", - "dest": "cargo/vendor", - "dest-filename": "futures-sink-0.3.14.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%225c5629433c555de3d82861a7a4e3794a4c40040390907cfbfd7143a92a426c23%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/futures-sink-0.3.14", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/futures-task/futures-task-0.3.14.crate", - "sha256": "ba7aa51095076f3ba6d9a1f702f74bd05ec65f555d70d2033d55ba8d69f581bc", - "dest": "cargo/vendor", - "dest-filename": "futures-task-0.3.14.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22ba7aa51095076f3ba6d9a1f702f74bd05ec65f555d70d2033d55ba8d69f581bc%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/futures-task-0.3.14", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/futures-util/futures-util-0.3.14.crate", - "sha256": "3c144ad54d60f23927f0a6b6d816e4271278b64f005ad65e4e35291d2de9c025", - "dest": "cargo/vendor", - "dest-filename": "futures-util-0.3.14.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%223c144ad54d60f23927f0a6b6d816e4271278b64f005ad65e4e35291d2de9c025%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/futures-util-0.3.14", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/gdk/gdk-0.13.2.crate", - "sha256": "db00839b2a68a7a10af3fa28dfb3febaba3a20c3a9ac2425a33b7df1f84a6b7d", - "dest": "cargo/vendor", - "dest-filename": "gdk-0.13.2.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22db00839b2a68a7a10af3fa28dfb3febaba3a20c3a9ac2425a33b7df1f84a6b7d%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/gdk-0.13.2", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/gdk-pixbuf/gdk-pixbuf-0.9.0.crate", - "sha256": "8f6dae3cb99dd49b758b88f0132f8d401108e63ae8edd45f432d42cdff99998a", - "dest": "cargo/vendor", - "dest-filename": "gdk-pixbuf-0.9.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%228f6dae3cb99dd49b758b88f0132f8d401108e63ae8edd45f432d42cdff99998a%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/gdk-pixbuf-0.9.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/gdk-pixbuf-sys/gdk-pixbuf-sys-0.10.0.crate", - "sha256": "3bfe468a7f43e97b8d193a762b6c5cf67a7d36cacbc0b9291dbcae24bfea1e8f", - "dest": "cargo/vendor", - "dest-filename": "gdk-pixbuf-sys-0.10.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%223bfe468a7f43e97b8d193a762b6c5cf67a7d36cacbc0b9291dbcae24bfea1e8f%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/gdk-pixbuf-sys-0.10.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/gdk-sys/gdk-sys-0.10.0.crate", - "sha256": "0a9653cfc500fd268015b1ac055ddbc3df7a5c9ea3f4ccef147b3957bd140d69", - "dest": "cargo/vendor", - "dest-filename": "gdk-sys-0.10.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%220a9653cfc500fd268015b1ac055ddbc3df7a5c9ea3f4ccef147b3957bd140d69%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/gdk-sys-0.10.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/generic-array/generic-array-0.14.4.crate", - "sha256": "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817", - "dest": "cargo/vendor", - "dest-filename": "generic-array-0.14.4.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/generic-array-0.14.4", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/getrandom/getrandom-0.2.2.crate", - "sha256": "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8", - "dest": "cargo/vendor", - "dest-filename": "getrandom-0.2.2.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/getrandom-0.2.2", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/gif/gif-0.11.2.crate", - "sha256": "5a668f699973d0f573d15749b7002a9ac9e1f9c6b220e7b165601334c173d8de", - "dest": "cargo/vendor", - "dest-filename": "gif-0.11.2.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%225a668f699973d0f573d15749b7002a9ac9e1f9c6b220e7b165601334c173d8de%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/gif-0.11.2", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/gio/gio-0.9.1.crate", - "sha256": "1fb60242bfff700772dae5d9e3a1f7aa2e4ebccf18b89662a16acb2822568561", - "dest": "cargo/vendor", - "dest-filename": "gio-0.9.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%221fb60242bfff700772dae5d9e3a1f7aa2e4ebccf18b89662a16acb2822568561%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/gio-0.9.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/gio-sys/gio-sys-0.10.1.crate", - "sha256": "5e24fb752f8f5d2cf6bbc2c606fd2bc989c81c5e2fe321ab974d54f8b6344eac", - "dest": "cargo/vendor", - "dest-filename": "gio-sys-0.10.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%225e24fb752f8f5d2cf6bbc2c606fd2bc989c81c5e2fe321ab974d54f8b6344eac%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/gio-sys-0.10.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/glib/glib-0.10.3.crate", - "sha256": "0c685013b7515e668f1b57a165b009d4d28cb139a8a989bbd699c10dad29d0c5", - "dest": "cargo/vendor", - "dest-filename": "glib-0.10.3.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%220c685013b7515e668f1b57a165b009d4d28cb139a8a989bbd699c10dad29d0c5%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/glib-0.10.3", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/glib-macros/glib-macros-0.10.1.crate", - "sha256": "41486a26d1366a8032b160b59065a59fb528530a46a49f627e7048fb8c064039", - "dest": "cargo/vendor", - "dest-filename": "glib-macros-0.10.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2241486a26d1366a8032b160b59065a59fb528530a46a49f627e7048fb8c064039%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/glib-macros-0.10.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/glib-sys/glib-sys-0.10.1.crate", - "sha256": "c7e9b997a66e9a23d073f2b1abb4dbfc3925e0b8952f67efd8d9b6e168e4cdc1", - "dest": "cargo/vendor", - "dest-filename": "glib-sys-0.10.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22c7e9b997a66e9a23d073f2b1abb4dbfc3925e0b8952f67efd8d9b6e168e4cdc1%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/glib-sys-0.10.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/glob/glob-0.3.0.crate", - "sha256": "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574", - "dest": "cargo/vendor", - "dest-filename": "glob-0.3.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%229b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/glob-0.3.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/gobject-sys/gobject-sys-0.10.0.crate", - "sha256": "952133b60c318a62bf82ee75b93acc7e84028a093e06b9e27981c2b6fe68218c", - "dest": "cargo/vendor", - "dest-filename": "gobject-sys-0.10.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22952133b60c318a62bf82ee75b93acc7e84028a093e06b9e27981c2b6fe68218c%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/gobject-sys-0.10.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/gtk/gtk-0.9.2.crate", - "sha256": "2f022f2054072b3af07666341984562c8e626a79daa8be27b955d12d06a5ad6a", - "dest": "cargo/vendor", - "dest-filename": "gtk-0.9.2.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%222f022f2054072b3af07666341984562c8e626a79daa8be27b955d12d06a5ad6a%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/gtk-0.9.2", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/gtk-sys/gtk-sys-0.10.0.crate", - "sha256": "89acda6f084863307d948ba64a4b1ef674e8527dddab147ee4cdcc194c880457", - "dest": "cargo/vendor", - "dest-filename": "gtk-sys-0.10.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2289acda6f084863307d948ba64a4b1ef674e8527dddab147ee4cdcc194c880457%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/gtk-sys-0.10.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/hamming/hamming-0.1.3.crate", - "sha256": "65043da274378d68241eb9a8f8f8aa54e349136f7b8e12f63e3ef44043cc30e1", - "dest": "cargo/vendor", - "dest-filename": "hamming-0.1.3.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2265043da274378d68241eb9a8f8f8aa54e349136f7b8e12f63e3ef44043cc30e1%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/hamming-0.1.3", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/heck/heck-0.3.2.crate", - "sha256": "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac", - "dest": "cargo/vendor", - "dest-filename": "heck-0.3.2.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2287cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/heck-0.3.2", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/hermit-abi/hermit-abi-0.1.18.crate", - "sha256": "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c", - "dest": "cargo/vendor", - "dest-filename": "hermit-abi-0.1.18.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/hermit-abi-0.1.18", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/hex/hex-0.4.3.crate", - "sha256": "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70", - "dest": "cargo/vendor", - "dest-filename": "hex-0.4.3.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%227f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/hex-0.4.3", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/hound/hound-3.4.0.crate", - "sha256": "8a164bb2ceaeff4f42542bdb847c41517c78a60f5649671b2a07312b6e117549", - "dest": "cargo/vendor", - "dest-filename": "hound-3.4.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%228a164bb2ceaeff4f42542bdb847c41517c78a60f5649671b2a07312b6e117549%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/hound-3.4.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/humansize/humansize-1.1.0.crate", - "sha256": "b6cab2627acfc432780848602f3f558f7e9dd427352224b0d9324025796d2a5e", - "dest": "cargo/vendor", - "dest-filename": "humansize-1.1.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22b6cab2627acfc432780848602f3f558f7e9dd427352224b0d9324025796d2a5e%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/humansize-1.1.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/id3/id3-0.5.3.crate", - "sha256": "8cb37ae5aa60d57c5f3412df1f3e5a48a978804f4a7e70700bb5f97e8f1a6331", - "dest": "cargo/vendor", - "dest-filename": "id3-0.5.3.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%228cb37ae5aa60d57c5f3412df1f3e5a48a978804f4a7e70700bb5f97e8f1a6331%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/id3-0.5.3", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/ident_case/ident_case-1.0.1.crate", - "sha256": "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39", - "dest": "cargo/vendor", - "dest-filename": "ident_case-1.0.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/ident_case-1.0.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/image/image-0.23.14.crate", - "sha256": "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1", - "dest": "cargo/vendor", - "dest-filename": "image-0.23.14.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2224ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/image-0.23.14", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/img_hash/img_hash-3.2.0.crate", - "sha256": "5ea4eac6fc4f64ed363d5c210732b747bfa5ddd8a25ac347d887f298c3a70b49", - "dest": "cargo/vendor", - "dest-filename": "img_hash-3.2.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%225ea4eac6fc4f64ed363d5c210732b747bfa5ddd8a25ac347d887f298c3a70b49%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/img_hash-3.2.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/instant/instant-0.1.9.crate", - "sha256": "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec", - "dest": "cargo/vendor", - "dest-filename": "instant-0.1.9.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2261124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/instant-0.1.9", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/itertools/itertools-0.9.0.crate", - "sha256": "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b", - "dest": "cargo/vendor", - "dest-filename": "itertools-0.9.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/itertools-0.9.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/jni/jni-0.18.0.crate", - "sha256": "24967112a1e4301ca5342ea339763613a37592b8a6ce6cf2e4494537c7a42faf", - "dest": "cargo/vendor", - "dest-filename": "jni-0.18.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2224967112a1e4301ca5342ea339763613a37592b8a6ce6cf2e4494537c7a42faf%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/jni-0.18.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/jni-sys/jni-sys-0.3.0.crate", - "sha256": "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130", - "dest": "cargo/vendor", - "dest-filename": "jni-sys-0.3.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%228eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/jni-sys-0.3.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/jobserver/jobserver-0.1.22.crate", - "sha256": "972f5ae5d1cb9c6ae417789196c803205313edde988685da5e3aae0827b9e7fd", - "dest": "cargo/vendor", - "dest-filename": "jobserver-0.1.22.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22972f5ae5d1cb9c6ae417789196c803205313edde988685da5e3aae0827b9e7fd%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/jobserver-0.1.22", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/jpeg-decoder/jpeg-decoder-0.1.22.crate", - "sha256": "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2", - "dest": "cargo/vendor", - "dest-filename": "jpeg-decoder-0.1.22.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/jpeg-decoder-0.1.22", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/js-sys/js-sys-0.3.50.crate", - "sha256": "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c", - "dest": "cargo/vendor", - "dest-filename": "js-sys-0.3.50.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%222d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/js-sys-0.3.50", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/lazy_static/lazy_static-1.4.0.crate", - "sha256": "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646", - "dest": "cargo/vendor", - "dest-filename": "lazy_static-1.4.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/lazy_static-1.4.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/lazycell/lazycell-1.3.0.crate", - "sha256": "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55", - "dest": "cargo/vendor", - "dest-filename": "lazycell-1.3.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/lazycell-1.3.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/lewton/lewton-0.10.2.crate", - "sha256": "777b48df9aaab155475a83a7df3070395ea1ac6902f5cd062b8f2b028075c030", - "dest": "cargo/vendor", - "dest-filename": "lewton-0.10.2.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22777b48df9aaab155475a83a7df3070395ea1ac6902f5cd062b8f2b028075c030%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/lewton-0.10.2", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/libc/libc-0.2.94.crate", - "sha256": "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e", - "dest": "cargo/vendor", - "dest-filename": "libc-0.2.94.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2218794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/libc-0.2.94", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/libloading/libloading-0.7.0.crate", - "sha256": "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a", - "dest": "cargo/vendor", - "dest-filename": "libloading-0.7.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%226f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/libloading-0.7.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/lock_api/lock_api-0.4.4.crate", - "sha256": "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb", - "dest": "cargo/vendor", - "dest-filename": "lock_api-0.4.4.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%220382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/lock_api-0.4.4", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/log/log-0.4.14.crate", - "sha256": "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710", - "dest": "cargo/vendor", - "dest-filename": "log-0.4.14.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2251b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/log-0.4.14", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/mach/mach-0.3.2.crate", - "sha256": "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa", - "dest": "cargo/vendor", - "dest-filename": "mach-0.3.2.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/mach-0.3.2", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/memchr/memchr-2.4.0.crate", - "sha256": "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc", - "dest": "cargo/vendor", - "dest-filename": "memchr-2.4.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/memchr-2.4.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/memoffset/memoffset-0.6.3.crate", - "sha256": "f83fb6581e8ed1f85fd45c116db8405483899489e38406156c25eb743554361d", - "dest": "cargo/vendor", - "dest-filename": "memoffset-0.6.3.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22f83fb6581e8ed1f85fd45c116db8405483899489e38406156c25eb743554361d%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/memoffset-0.6.3", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/metaflac/metaflac-0.2.4.crate", - "sha256": "4685bf0039a9d2919c2dbb281cba1c58d168dce58f519cbd70c468ce2c36a748", - "dest": "cargo/vendor", - "dest-filename": "metaflac-0.2.4.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%224685bf0039a9d2919c2dbb281cba1c58d168dce58f519cbd70c468ce2c36a748%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/metaflac-0.2.4", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/minimp3/minimp3-0.5.1.crate", - "sha256": "985438f75febf74c392071a975a29641b420dd84431135a6e6db721de4b74372", - "dest": "cargo/vendor", - "dest-filename": "minimp3-0.5.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22985438f75febf74c392071a975a29641b420dd84431135a6e6db721de4b74372%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/minimp3-0.5.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/minimp3-sys/minimp3-sys-0.3.2.crate", - "sha256": "e21c73734c69dc95696c9ed8926a2b393171d98b3f5f5935686a26a487ab9b90", - "dest": "cargo/vendor", - "dest-filename": "minimp3-sys-0.3.2.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22e21c73734c69dc95696c9ed8926a2b393171d98b3f5f5935686a26a487ab9b90%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/minimp3-sys-0.3.2", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/miniz_oxide/miniz_oxide-0.3.7.crate", - "sha256": "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435", - "dest": "cargo/vendor", - "dest-filename": "miniz_oxide-0.3.7.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/miniz_oxide-0.3.7", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/miniz_oxide/miniz_oxide-0.4.4.crate", - "sha256": "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b", - "dest": "cargo/vendor", - "dest-filename": "miniz_oxide-0.4.4.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/miniz_oxide-0.4.4", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/mp4ameta/mp4ameta-0.6.1.crate", - "sha256": "1ef7a2ba51feaa9e7be2209b6e5d7472d08427ef0ce88616ed93c66dae9601b2", - "dest": "cargo/vendor", - "dest-filename": "mp4ameta-0.6.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%221ef7a2ba51feaa9e7be2209b6e5d7472d08427ef0ce88616ed93c66dae9601b2%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/mp4ameta-0.6.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/mp4ameta_proc/mp4ameta_proc-0.1.1.crate", - "sha256": "64ae83441f6b67e3b7f009295618e90f03228b0f1a149f56ee8cd0f6bb5602c5", - "dest": "cargo/vendor", - "dest-filename": "mp4ameta_proc-0.1.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2264ae83441f6b67e3b7f009295618e90f03228b0f1a149f56ee8cd0f6bb5602c5%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/mp4ameta_proc-0.1.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/ndk/ndk-0.3.0.crate", - "sha256": "8794322172319b972f528bf90c6b467be0079f1fa82780ffb431088e741a73ab", - "dest": "cargo/vendor", - "dest-filename": "ndk-0.3.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%228794322172319b972f528bf90c6b467be0079f1fa82780ffb431088e741a73ab%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/ndk-0.3.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/ndk-glue/ndk-glue-0.3.0.crate", - "sha256": "c5caf0c24d51ac1c905c27d4eda4fa0635bbe0de596b8f79235e0b17a4d29385", - "dest": "cargo/vendor", - "dest-filename": "ndk-glue-0.3.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22c5caf0c24d51ac1c905c27d4eda4fa0635bbe0de596b8f79235e0b17a4d29385%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/ndk-glue-0.3.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/ndk-macro/ndk-macro-0.2.0.crate", - "sha256": "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d", - "dest": "cargo/vendor", - "dest-filename": "ndk-macro-0.2.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2205d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/ndk-macro-0.2.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/ndk-sys/ndk-sys-0.2.1.crate", - "sha256": "c44922cb3dbb1c70b5e5f443d63b64363a898564d739ba5198e3a9138442868d", - "dest": "cargo/vendor", - "dest-filename": "ndk-sys-0.2.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22c44922cb3dbb1c70b5e5f443d63b64363a898564d739ba5198e3a9138442868d%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/ndk-sys-0.2.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/nix/nix-0.20.0.crate", - "sha256": "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a", - "dest": "cargo/vendor", - "dest-filename": "nix-0.20.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/nix-0.20.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/nom/nom-5.1.2.crate", - "sha256": "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af", - "dest": "cargo/vendor", - "dest-filename": "nom-5.1.2.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/nom-5.1.2", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/num-complex/num-complex-0.2.4.crate", - "sha256": "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95", - "dest": "cargo/vendor", - "dest-filename": "num-complex-0.2.4.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/num-complex-0.2.4", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/num-derive/num-derive-0.3.3.crate", - "sha256": "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d", - "dest": "cargo/vendor", - "dest-filename": "num-derive-0.3.3.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/num-derive-0.3.3", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/num-integer/num-integer-0.1.44.crate", - "sha256": "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db", - "dest": "cargo/vendor", - "dest-filename": "num-integer-0.1.44.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/num-integer-0.1.44", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/num-iter/num-iter-0.1.42.crate", - "sha256": "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59", - "dest": "cargo/vendor", - "dest-filename": "num-iter-0.1.42.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/num-iter-0.1.42", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/num-rational/num-rational-0.3.2.crate", - "sha256": "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07", - "dest": "cargo/vendor", - "dest-filename": "num-rational-0.3.2.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2212ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/num-rational-0.3.2", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/num-traits/num-traits-0.2.14.crate", - "sha256": "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290", - "dest": "cargo/vendor", - "dest-filename": "num-traits-0.2.14.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%229a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/num-traits-0.2.14", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/num_cpus/num_cpus-1.13.0.crate", - "sha256": "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3", - "dest": "cargo/vendor", - "dest-filename": "num_cpus-1.13.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2205499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/num_cpus-1.13.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/num_enum/num_enum-0.5.1.crate", - "sha256": "226b45a5c2ac4dd696ed30fa6b94b057ad909c7b7fc2e0d0808192bced894066", - "dest": "cargo/vendor", - "dest-filename": "num_enum-0.5.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22226b45a5c2ac4dd696ed30fa6b94b057ad909c7b7fc2e0d0808192bced894066%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/num_enum-0.5.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/num_enum_derive/num_enum_derive-0.5.1.crate", - "sha256": "1c0fd9eba1d5db0994a239e09c1be402d35622277e35468ba891aa5e3188ce7e", - "dest": "cargo/vendor", - "dest-filename": "num_enum_derive-0.5.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%221c0fd9eba1d5db0994a239e09c1be402d35622277e35468ba891aa5e3188ce7e%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/num_enum_derive-0.5.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/oboe/oboe-0.4.1.crate", - "sha256": "4cfb2390bddb9546c0f7448fd1d2abdd39e6075206f960991eb28c7fa7f126c4", - "dest": "cargo/vendor", - "dest-filename": "oboe-0.4.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%224cfb2390bddb9546c0f7448fd1d2abdd39e6075206f960991eb28c7fa7f126c4%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/oboe-0.4.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/oboe-sys/oboe-sys-0.4.0.crate", - "sha256": "fe069264d082fc820dfa172f79be3f2e088ecfece9b1c47b0c9fd838d2bef103", - "dest": "cargo/vendor", - "dest-filename": "oboe-sys-0.4.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22fe069264d082fc820dfa172f79be3f2e088ecfece9b1c47b0c9fd838d2bef103%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/oboe-sys-0.4.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/ogg/ogg-0.8.0.crate", - "sha256": "6951b4e8bf21c8193da321bcce9c9dd2e13c858fe078bf9054a288b419ae5d6e", - "dest": "cargo/vendor", - "dest-filename": "ogg-0.8.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%226951b4e8bf21c8193da321bcce9c9dd2e13c858fe078bf9054a288b419ae5d6e%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/ogg-0.8.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/once_cell/once_cell-1.7.2.crate", - "sha256": "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3", - "dest": "cargo/vendor", - "dest-filename": "once_cell-1.7.2.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/once_cell-1.7.2", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/open/open-1.7.0.crate", - "sha256": "1711eb4b31ce4ad35b0f316d8dfba4fe5c7ad601c448446d84aae7a896627b20", - "dest": "cargo/vendor", - "dest-filename": "open-1.7.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%221711eb4b31ce4ad35b0f316d8dfba4fe5c7ad601c448446d84aae7a896627b20%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/open-1.7.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/pango/pango-0.9.1.crate", - "sha256": "9937068580bebd8ced19975938573803273ccbcbd598c58d4906efd4ac87c438", - "dest": "cargo/vendor", - "dest-filename": "pango-0.9.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%229937068580bebd8ced19975938573803273ccbcbd598c58d4906efd4ac87c438%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/pango-0.9.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/pango-sys/pango-sys-0.10.0.crate", - "sha256": "24d2650c8b62d116c020abd0cea26a4ed96526afda89b1c4ea567131fdefc890", - "dest": "cargo/vendor", - "dest-filename": "pango-sys-0.10.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2224d2650c8b62d116c020abd0cea26a4ed96526afda89b1c4ea567131fdefc890%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/pango-sys-0.10.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/parking_lot/parking_lot-0.11.1.crate", - "sha256": "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb", - "dest": "cargo/vendor", - "dest-filename": "parking_lot-0.11.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%226d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/parking_lot-0.11.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/parking_lot_core/parking_lot_core-0.8.3.crate", - "sha256": "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018", - "dest": "cargo/vendor", - "dest-filename": "parking_lot_core-0.8.3.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/parking_lot_core-0.8.3", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/peeking_take_while/peeking_take_while-0.1.2.crate", - "sha256": "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099", - "dest": "cargo/vendor", - "dest-filename": "peeking_take_while-0.1.2.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2219b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/peeking_take_while-0.1.2", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/pin-project-lite/pin-project-lite-0.2.6.crate", - "sha256": "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905", - "dest": "cargo/vendor", - "dest-filename": "pin-project-lite-0.2.6.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/pin-project-lite-0.2.6", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/pin-utils/pin-utils-0.1.0.crate", - "sha256": "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184", - "dest": "cargo/vendor", - "dest-filename": "pin-utils-0.1.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%228b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/pin-utils-0.1.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/pkg-config/pkg-config-0.3.19.crate", - "sha256": "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c", - "dest": "cargo/vendor", - "dest-filename": "pkg-config-0.3.19.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%223831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/pkg-config-0.3.19", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/png/png-0.16.8.crate", - "sha256": "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6", - "dest": "cargo/vendor", - "dest-filename": "png-0.16.8.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%223c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/png-0.16.8", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/ppv-lite86/ppv-lite86-0.2.10.crate", - "sha256": "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857", - "dest": "cargo/vendor", - "dest-filename": "ppv-lite86-0.2.10.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/ppv-lite86-0.2.10", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/proc-macro-crate/proc-macro-crate-0.1.5.crate", - "sha256": "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785", - "dest": "cargo/vendor", - "dest-filename": "proc-macro-crate-0.1.5.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%221d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/proc-macro-crate-0.1.5", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/proc-macro-error/proc-macro-error-1.0.4.crate", - "sha256": "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c", - "dest": "cargo/vendor", - "dest-filename": "proc-macro-error-1.0.4.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/proc-macro-error-1.0.4", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/proc-macro-error-attr/proc-macro-error-attr-1.0.4.crate", - "sha256": "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869", - "dest": "cargo/vendor", - "dest-filename": "proc-macro-error-attr-1.0.4.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/proc-macro-error-attr-1.0.4", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/proc-macro-hack/proc-macro-hack-0.5.19.crate", - "sha256": "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5", - "dest": "cargo/vendor", - "dest-filename": "proc-macro-hack-0.5.19.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/proc-macro-hack-0.5.19", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/proc-macro-nested/proc-macro-nested-0.1.7.crate", - "sha256": "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086", - "dest": "cargo/vendor", - "dest-filename": "proc-macro-nested-0.1.7.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/proc-macro-nested-0.1.7", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/proc-macro2/proc-macro2-1.0.26.crate", - "sha256": "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec", - "dest": "cargo/vendor", - "dest-filename": "proc-macro2-1.0.26.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/proc-macro2-1.0.26", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/quote/quote-1.0.9.crate", - "sha256": "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7", - "dest": "cargo/vendor", - "dest-filename": "quote-1.0.9.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/quote-1.0.9", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/rand/rand-0.8.3.crate", - "sha256": "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e", - "dest": "cargo/vendor", - "dest-filename": "rand-0.8.3.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%220ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/rand-0.8.3", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/rand_chacha/rand_chacha-0.3.0.crate", - "sha256": "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d", - "dest": "cargo/vendor", - "dest-filename": "rand_chacha-0.3.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/rand_chacha-0.3.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/rand_core/rand_core-0.6.2.crate", - "sha256": "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7", - "dest": "cargo/vendor", - "dest-filename": "rand_core-0.6.2.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2234cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/rand_core-0.6.2", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/rand_hc/rand_hc-0.3.0.crate", - "sha256": "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73", - "dest": "cargo/vendor", - "dest-filename": "rand_hc-0.3.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%223190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/rand_hc-0.3.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/rayon/rayon-1.5.0.crate", - "sha256": "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674", - "dest": "cargo/vendor", - "dest-filename": "rayon-1.5.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%228b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/rayon-1.5.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/rayon-core/rayon-core-1.9.0.crate", - "sha256": "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a", - "dest": "cargo/vendor", - "dest-filename": "rayon-core-1.9.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%229ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/rayon-core-1.9.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/redox_syscall/redox_syscall-0.2.8.crate", - "sha256": "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc", - "dest": "cargo/vendor", - "dest-filename": "redox_syscall-0.2.8.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/redox_syscall-0.2.8", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/redox_users/redox_users-0.4.0.crate", - "sha256": "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64", - "dest": "cargo/vendor", - "dest-filename": "redox_users-0.4.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/redox_users-0.4.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/regex/regex-1.5.3.crate", - "sha256": "ce5f1ceb7f74abbce32601642fcf8e8508a8a8991e0621c7d750295b9095702b", - "dest": "cargo/vendor", - "dest-filename": "regex-1.5.3.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22ce5f1ceb7f74abbce32601642fcf8e8508a8a8991e0621c7d750295b9095702b%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/regex-1.5.3", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/regex-syntax/regex-syntax-0.6.25.crate", - "sha256": "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b", - "dest": "cargo/vendor", - "dest-filename": "regex-syntax-0.6.25.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/regex-syntax-0.6.25", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/remove_dir_all/remove_dir_all-0.5.3.crate", - "sha256": "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7", - "dest": "cargo/vendor", - "dest-filename": "remove_dir_all-0.5.3.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%223acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/remove_dir_all-0.5.3", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/rodio/rodio-0.13.1.crate", - "sha256": "b65c2eda643191f6d1bb12ea323a9db8d9ba95374e9be3780b5a9fb5cfb8520f", - "dest": "cargo/vendor", - "dest-filename": "rodio-0.13.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22b65c2eda643191f6d1bb12ea323a9db8d9ba95374e9be3780b5a9fb5cfb8520f%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/rodio-0.13.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/rustc-hash/rustc-hash-1.1.0.crate", - "sha256": "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2", - "dest": "cargo/vendor", - "dest-filename": "rustc-hash-1.1.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2208d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/rustc-hash-1.1.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/rustdct/rustdct-0.4.0.crate", - "sha256": "ef4d167674b4cf68c2114bdbcd34c95aa9071652b73b0f43b19298f1d2780b7d", - "dest": "cargo/vendor", - "dest-filename": "rustdct-0.4.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22ef4d167674b4cf68c2114bdbcd34c95aa9071652b73b0f43b19298f1d2780b7d%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/rustdct-0.4.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/rustfft/rustfft-3.0.1.crate", - "sha256": "77008ed59a8923c8b4ac2e5eaa6d28fbe893d3b9515098a4a5fc7767d6430fe5", - "dest": "cargo/vendor", - "dest-filename": "rustfft-3.0.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2277008ed59a8923c8b4ac2e5eaa6d28fbe893d3b9515098a4a5fc7767d6430fe5%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/rustfft-3.0.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/same-file/same-file-1.0.6.crate", - "sha256": "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502", - "dest": "cargo/vendor", - "dest-filename": "same-file-1.0.6.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2293fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/same-file-1.0.6", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/scoped_threadpool/scoped_threadpool-0.1.9.crate", - "sha256": "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8", - "dest": "cargo/vendor", - "dest-filename": "scoped_threadpool-0.1.9.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%221d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/scoped_threadpool-0.1.9", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/scopeguard/scopeguard-1.1.0.crate", - "sha256": "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd", - "dest": "cargo/vendor", - "dest-filename": "scopeguard-1.1.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/scopeguard-1.1.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/serde/serde-1.0.125.crate", - "sha256": "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171", - "dest": "cargo/vendor", - "dest-filename": "serde-1.0.125.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/serde-1.0.125", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/serde_derive/serde_derive-1.0.125.crate", - "sha256": "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d", - "dest": "cargo/vendor", - "dest-filename": "serde_derive-1.0.125.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/serde_derive-1.0.125", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/shlex/shlex-0.1.1.crate", - "sha256": "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2", - "dest": "cargo/vendor", - "dest-filename": "shlex-0.1.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%227fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/shlex-0.1.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/slab/slab-0.4.3.crate", - "sha256": "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527", - "dest": "cargo/vendor", - "dest-filename": "slab-0.4.3.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/slab-0.4.3", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/slice-deque/slice-deque-0.3.0.crate", - "sha256": "31ef6ee280cdefba6d2d0b4b78a84a1c1a3f3a4cec98c2d4231c8bc225de0f25", - "dest": "cargo/vendor", - "dest-filename": "slice-deque-0.3.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2231ef6ee280cdefba6d2d0b4b78a84a1c1a3f3a4cec98c2d4231c8bc225de0f25%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/slice-deque-0.3.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/smallvec/smallvec-1.6.1.crate", - "sha256": "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e", - "dest": "cargo/vendor", - "dest-filename": "smallvec-1.6.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/smallvec-1.6.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/stdweb/stdweb-0.1.3.crate", - "sha256": "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e", - "dest": "cargo/vendor", - "dest-filename": "stdweb-0.1.3.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/stdweb-0.1.3", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/strength_reduce/strength_reduce-0.2.3.crate", - "sha256": "a3ff2f71c82567c565ba4b3009a9350a96a7269eaa4001ebedae926230bc2254", - "dest": "cargo/vendor", - "dest-filename": "strength_reduce-0.2.3.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22a3ff2f71c82567c565ba4b3009a9350a96a7269eaa4001ebedae926230bc2254%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/strength_reduce-0.2.3", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/strsim/strsim-0.8.0.crate", - "sha256": "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a", - "dest": "cargo/vendor", - "dest-filename": "strsim-0.8.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%228ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/strsim-0.8.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/strsim/strsim-0.9.3.crate", - "sha256": "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c", - "dest": "cargo/vendor", - "dest-filename": "strsim-0.9.3.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%226446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/strsim-0.9.3", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/structopt/structopt-0.3.21.crate", - "sha256": "5277acd7ee46e63e5168a80734c9f6ee81b1367a7d8772a2d765df2a3705d28c", - "dest": "cargo/vendor", - "dest-filename": "structopt-0.3.21.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%225277acd7ee46e63e5168a80734c9f6ee81b1367a7d8772a2d765df2a3705d28c%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/structopt-0.3.21", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/structopt-derive/structopt-derive-0.4.14.crate", - "sha256": "5ba9cdfda491b814720b6b06e0cac513d922fc407582032e8706e9f137976f90", - "dest": "cargo/vendor", - "dest-filename": "structopt-derive-0.4.14.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%225ba9cdfda491b814720b6b06e0cac513d922fc407582032e8706e9f137976f90%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/structopt-derive-0.4.14", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/strum/strum-0.18.0.crate", - "sha256": "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b", - "dest": "cargo/vendor", - "dest-filename": "strum-0.18.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2257bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/strum-0.18.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/strum_macros/strum_macros-0.18.0.crate", - "sha256": "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c", - "dest": "cargo/vendor", - "dest-filename": "strum_macros-0.18.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2287c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/strum_macros-0.18.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/subtle/subtle-2.4.0.crate", - "sha256": "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2", - "dest": "cargo/vendor", - "dest-filename": "subtle-2.4.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%221e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/subtle-2.4.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/syn/syn-1.0.72.crate", - "sha256": "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82", - "dest": "cargo/vendor", - "dest-filename": "syn-1.0.72.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/syn-1.0.72", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/system-deps/system-deps-1.3.2.crate", - "sha256": "0f3ecc17269a19353b3558b313bba738b25d82993e30d62a18406a24aba4649b", - "dest": "cargo/vendor", - "dest-filename": "system-deps-1.3.2.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%220f3ecc17269a19353b3558b313bba738b25d82993e30d62a18406a24aba4649b%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/system-deps-1.3.2", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/tempfile/tempfile-3.2.0.crate", - "sha256": "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22", - "dest": "cargo/vendor", - "dest-filename": "tempfile-3.2.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/tempfile-3.2.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/textwrap/textwrap-0.11.0.crate", - "sha256": "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060", - "dest": "cargo/vendor", - "dest-filename": "textwrap-0.11.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/textwrap-0.11.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/thiserror/thiserror-1.0.24.crate", - "sha256": "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e", - "dest": "cargo/vendor", - "dest-filename": "thiserror-1.0.24.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/thiserror-1.0.24", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/thiserror-impl/thiserror-impl-1.0.24.crate", - "sha256": "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0", - "dest": "cargo/vendor", - "dest-filename": "thiserror-impl-1.0.24.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%227765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/thiserror-impl-1.0.24", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/tiff/tiff-0.6.1.crate", - "sha256": "9a53f4706d65497df0c4349241deddf35f84cee19c87ed86ea8ca590f4464437", - "dest": "cargo/vendor", - "dest-filename": "tiff-0.6.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%229a53f4706d65497df0c4349241deddf35f84cee19c87ed86ea8ca590f4464437%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/tiff-0.6.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/time/time-0.1.43.crate", - "sha256": "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438", - "dest": "cargo/vendor", - "dest-filename": "time-0.1.43.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/time-0.1.43", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/tinyvec/tinyvec-1.2.0.crate", - "sha256": "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342", - "dest": "cargo/vendor", - "dest-filename": "tinyvec-1.2.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%225b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/tinyvec-1.2.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/tinyvec_macros/tinyvec_macros-0.1.0.crate", - "sha256": "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c", - "dest": "cargo/vendor", - "dest-filename": "tinyvec_macros-0.1.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/tinyvec_macros-0.1.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/toml/toml-0.5.8.crate", - "sha256": "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa", - "dest": "cargo/vendor", - "dest-filename": "toml-0.5.8.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/toml-0.5.8", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/transpose/transpose-0.1.0.crate", - "sha256": "643e21580bb0627c7bb09e5cedbb42c8705b19d012de593ed6b0309270b3cd1e", - "dest": "cargo/vendor", - "dest-filename": "transpose-0.1.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22643e21580bb0627c7bb09e5cedbb42c8705b19d012de593ed6b0309270b3cd1e%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/transpose-0.1.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/transpose/transpose-0.2.1.crate", - "sha256": "95f9c900aa98b6ea43aee227fd680550cdec726526aab8ac801549eadb25e39f", - "dest": "cargo/vendor", - "dest-filename": "transpose-0.2.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2295f9c900aa98b6ea43aee227fd680550cdec726526aab8ac801549eadb25e39f%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/transpose-0.2.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/trash/trash-1.3.0.crate", - "sha256": "90df96afb154814e214f37eac04920c66886fd95962f22febb4d537b0dacd512", - "dest": "cargo/vendor", - "dest-filename": "trash-1.3.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2290df96afb154814e214f37eac04920c66886fd95962f22febb4d537b0dacd512%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/trash-1.3.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/typenum/typenum-1.13.0.crate", - "sha256": "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06", - "dest": "cargo/vendor", - "dest-filename": "typenum-1.13.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/typenum-1.13.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/unicode-segmentation/unicode-segmentation-1.7.1.crate", - "sha256": "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796", - "dest": "cargo/vendor", - "dest-filename": "unicode-segmentation-1.7.1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/unicode-segmentation-1.7.1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/unicode-width/unicode-width-0.1.8.crate", - "sha256": "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3", - "dest": "cargo/vendor", - "dest-filename": "unicode-width-0.1.8.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%229337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/unicode-width-0.1.8", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/unicode-xid/unicode-xid-0.2.2.crate", - "sha256": "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3", - "dest": "cargo/vendor", - "dest-filename": "unicode-xid-0.2.2.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%228ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/unicode-xid-0.2.2", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/vec_map/vec_map-0.8.2.crate", - "sha256": "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191", - "dest": "cargo/vendor", - "dest-filename": "vec_map-0.8.2.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/vec_map-0.8.2", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/version-compare/version-compare-0.0.10.crate", - "sha256": "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1", - "dest": "cargo/vendor", - "dest-filename": "version-compare-0.0.10.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/version-compare-0.0.10", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/version_check/version_check-0.9.3.crate", - "sha256": "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe", - "dest": "cargo/vendor", - "dest-filename": "version_check-0.9.3.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%225fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/version_check-0.9.3", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/walkdir/walkdir-2.3.2.crate", - "sha256": "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56", - "dest": "cargo/vendor", - "dest-filename": "walkdir-2.3.2.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/walkdir-2.3.2", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/wasi/wasi-0.10.2+wasi-snapshot-preview1.crate", - "sha256": "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6", - "dest": "cargo/vendor", - "dest-filename": "wasi-0.10.2+wasi-snapshot-preview1.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/wasi-0.10.2+wasi-snapshot-preview1", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/wasm-bindgen/wasm-bindgen-0.2.73.crate", - "sha256": "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9", - "dest": "cargo/vendor", - "dest-filename": "wasm-bindgen-0.2.73.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2283240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/wasm-bindgen-0.2.73", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/wasm-bindgen-backend/wasm-bindgen-backend-0.2.73.crate", - "sha256": "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae", - "dest": "cargo/vendor", - "dest-filename": "wasm-bindgen-backend-0.2.73.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/wasm-bindgen-backend-0.2.73", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/wasm-bindgen-macro/wasm-bindgen-macro-0.2.73.crate", - "sha256": "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f", - "dest": "cargo/vendor", - "dest-filename": "wasm-bindgen-macro-0.2.73.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%223e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/wasm-bindgen-macro-0.2.73", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/wasm-bindgen-macro-support/wasm-bindgen-macro-support-0.2.73.crate", - "sha256": "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c", - "dest": "cargo/vendor", - "dest-filename": "wasm-bindgen-macro-support-0.2.73.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/wasm-bindgen-macro-support-0.2.73", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/wasm-bindgen-shared/wasm-bindgen-shared-0.2.73.crate", - "sha256": "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489", - "dest": "cargo/vendor", - "dest-filename": "wasm-bindgen-shared-0.2.73.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/wasm-bindgen-shared-0.2.73", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/web-sys/web-sys-0.3.50.crate", - "sha256": "a905d57e488fec8861446d3393670fb50d27a262344013181c2cdf9fff5481be", - "dest": "cargo/vendor", - "dest-filename": "web-sys-0.3.50.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22a905d57e488fec8861446d3393670fb50d27a262344013181c2cdf9fff5481be%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/web-sys-0.3.50", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/weezl/weezl-0.1.5.crate", - "sha256": "d8b77fdfd5a253be4ab714e4ffa3c49caf146b4de743e97510c0656cf90f1e8e", - "dest": "cargo/vendor", - "dest-filename": "weezl-0.1.5.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22d8b77fdfd5a253be4ab714e4ffa3c49caf146b4de743e97510c0656cf90f1e8e%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/weezl-0.1.5", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/which/which-4.1.0.crate", - "sha256": "b55551e42cbdf2ce2bedd2203d0cc08dba002c27510f86dab6d0ce304cba3dfe", - "dest": "cargo/vendor", - "dest-filename": "which-4.1.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22b55551e42cbdf2ce2bedd2203d0cc08dba002c27510f86dab6d0ce304cba3dfe%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/which-4.1.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/winapi/winapi-0.3.9.crate", - "sha256": "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419", - "dest": "cargo/vendor", - "dest-filename": "winapi-0.3.9.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%225c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/winapi-0.3.9", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/winapi-i686-pc-windows-gnu/winapi-i686-pc-windows-gnu-0.4.0.crate", - "sha256": "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6", - "dest": "cargo/vendor", - "dest-filename": "winapi-i686-pc-windows-gnu-0.4.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/winapi-i686-pc-windows-gnu-0.4.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/winapi-util/winapi-util-0.1.5.crate", - "sha256": "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178", - "dest": "cargo/vendor", - "dest-filename": "winapi-util-0.1.5.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%2270ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/winapi-util-0.1.5", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/winapi-x86_64-pc-windows-gnu/winapi-x86_64-pc-windows-gnu-0.4.0.crate", - "sha256": "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f", - "dest": "cargo/vendor", - "dest-filename": "winapi-x86_64-pc-windows-gnu-0.4.0.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/winapi-x86_64-pc-windows-gnu-0.4.0", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/xxhash-rust/xxhash-rust-0.8.2.crate", - "sha256": "e575e15bedf6e57b5c2d763ffc6c3c760143466cbd09d762d539680ab5992ded", - "dest": "cargo/vendor", - "dest-filename": "xxhash-rust-0.8.2.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%22e575e15bedf6e57b5c2d763ffc6c3c760143466cbd09d762d539680ab5992ded%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/xxhash-rust-0.8.2", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "file", - "url": "https://static.crates.io/crates/zip/zip-0.5.12.crate", - "sha256": "9c83dc9b784d252127720168abd71ea82bf8c3d96b17dc565b5e2a02854f2b27", - "dest": "cargo/vendor", - "dest-filename": "zip-0.5.12.crate" - }, - { - "type": "file", - "url": "data:%7B%22package%22%3A%20%229c83dc9b784d252127720168abd71ea82bf8c3d96b17dc565b5e2a02854f2b27%22%2C%20%22files%22%3A%20%7B%7D%7D", - "dest": "cargo/vendor/zip-0.5.12", - "dest-filename": ".cargo-checksum.json" - }, - { - "type": "shell", - "dest": "cargo/vendor", - "commands": [ - "for c in *.crate; do tar -xf $c; done" - ] - }, - { - "type": "file", - "url": "data:%5Bsource.vendored-sources%5D%0Adirectory%20%3D%20%22cargo/vendor%22%0A%0A%5Bsource.crates-io%5D%0Areplace-with%20%3D%20%22vendored-sources%22%0A", - "dest": "cargo", - "dest-filename": "config" - } -] \ No newline at end of file diff --git a/flatpak/com.github.qarmin.czkawka.yaml b/flatpak/com.github.qarmin.czkawka.yaml deleted file mode 100644 index e934826..0000000 --- a/flatpak/com.github.qarmin.czkawka.yaml +++ /dev/null @@ -1,32 +0,0 @@ -app-id: com.github.qarmin.czkawka -runtime: org.gnome.Platform -runtime-version: '3.38' -sdk: org.gnome.Sdk -sdk-extensions: -- org.freedesktop.Sdk.Extension.rust-stable -command: czkawka_gui -finish-args: -- "--share=ipc" -- "--socket=fallback-x11" -- "--socket=wayland" -- "--filesystem=host" -- "--device=dri" -build-options: - append-path: "/usr/lib/sdk/rust-stable/bin" - env: - CARGO_HOME: "/run/build/czkawka_gui/cargo" -modules: -- name: czkawka_gui - buildsystem: simple - build-commands: - - cargo --offline fetch --manifest-path Cargo.toml - - cargo --offline build --release - - install -Dm755 ./target/release/czkawka_gui -t /app/bin/ - - install -Dm644 ./data/icons/com.github.qarmin.czkawka.svg -t /app/share/icons/hicolor/scalable/apps/ - - install -Dm644 ./pkgs/com.github.qarmin.czkawka.desktop -t /app/share/applications/ - - install -Dm644 ./data/com.github.qarmin.czkawka.metainfo.xml -t /app/share/metainfo - sources: - - cargo-sources.json - - type: git - url: https://github.com/qarmin/czkawka.git - tag: 3.3.1 diff --git a/instructions/Installation.md b/instructions/Installation.md index a5a5e88..e3ee622 100644 --- a/instructions/Installation.md +++ b/instructions/Installation.md @@ -1,28 +1,34 @@ # Installation ## Requirements ### Linux -If you use Snap, Flatpak or Appimage, you may skip this section. +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). +`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 +#### Ubuntu/Debian/Linux Mint ``` -sudo apt install libgtk-3-dev +sudo apt install libgtk-3-dev ffmpeg ``` -#### Fedora/CentOS +#### Fedora/Rocky Linux ``` sudo yum install gtk3-devel glib2-devel +sudo dnf -y install https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm +sudo dnf -y install https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm +sudo dnf -y install ffmpeg ``` #### Void Linux (CLI only) ``` -sudo xbps-install gcc pkg-config alsa-lib-devel +sudo xbps-install gcc pkg-config alsa-lib-devel ffpmeg ``` ### macOS -Currently, you need to manually install `GTK 3` libraries and the Adwaita theme, because they are dynamically loaded from the OS (*help in linking statically these things is needed*). One very straight-forward way to do this is by using [Homebrew](https://brew.sh/). Installation in the terminal: +Currently, you need to manually install `GTK 3` libraries, `FFmpeg` and the Adwaita theme, because they are dynamically loaded from the OS (*help in linking statically these things is needed*). +One very straight-forward way to do this is by using [Homebrew](https://brew.sh/). +Installation in the terminal: ```shell /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" -brew install gtk+3 adwaita-icon-theme +brew install gtk+3 adwaita-icon-theme ffmpeg ``` After that, go to the location where you downloaded Czkawka and add the `executable` permission to this file. ```shell @@ -37,6 +43,8 @@ At the end execute it: By default, all needed libraries are bundled with the app, inside `windows_czkawka_gui.zip`, but if you compile the app or just move `czkawka_gui.exe`, then you will need to install the `GTK 3` runtime from [**here**](https://github.com/tschoonj/GTK-for-Windows-Runtime-Environment-Installer/releases). +FFmpeg to be able to use Similar Videos, you can download and install from this [**link**](https://ffmpeg.org/). + ## Installation ### Precompiled binaries Ready-to-go executables for Linux, Windows and macOS are available [**here**](https://github.com/qarmin/czkawka/releases/). @@ -49,7 +57,7 @@ Artifacts from each commit can be downloaded [**here**](https://github.com/qarmi ### Appimage Appimage files are available in release page - [**GitHub releases**](https://github.com/qarmin/czkawka/releases/) This version is bundled with its own theme. -There is also a small problem with not being able to open 2 images at once. +There is also minimal appimage which use system theme. ### Cargo The easiest method to install Czkawka is using the `cargo` command. To compile it, you need to get all the @@ -93,10 +101,13 @@ sudo apt-get update sudo apt-get install czkawka ``` +alternatively you can use instruction from this [xtradeb site](https://xtradeb.net/wiki/how-to-install-applications-from-this-web-site/) + ### AUR - Arch Linux Package (unofficial) Czkawka is also available in Arch Linux's AUR from which it can be easily installed. ``` -yay -Syu czkawka-git +yay -Syu czkawka-gui +yay -Syu czkawka-cli ``` or ``` diff --git a/instructions/Instruction.md b/instructions/Instruction.md index 6b9899a..e7a0bc2 100644 --- a/instructions/Instruction.md +++ b/instructions/Instruction.md @@ -7,8 +7,6 @@ - [Tools](#tools) Czkawka for now contains two independent frontends - the terminal and graphical interface which share the core module. -Using Rust language without unsafe code helps to create safe, fast, and low resources requirements app. -This code also has good support for multi-threading. ## GUI GTK @@ -93,9 +91,10 @@ Windows - `C:\Users\Username\AppData\Local\Qarmin\Czkawka\cache` - **Not all columns are visible** For now it is possible that some columns will not be visible when some are too wide. There are 2 workarounds for now - View can be scrolled via horizontal scroll bar - - Size of other columns can be slimmed - - This is handled via https://github.com/qarmin/czkawka/issues/169 + - Size of other columns can be slimmed + This is checked if is possible to do in https://github.com/qarmin/czkawka/issues/169 +- **Opening parent folders** + - It is possible to open parent folder of selected items with double click with right mouse button(RMB) - it is also possible to open such item with double click with left mouse buttom(LMB). ![AA](https://user-images.githubusercontent.com/41945903/125684641-728e264a-34ab-41b1-9853-ab45dc25551f.png) @@ -241,6 +240,20 @@ Some tidbits: - Smaller hash size not always means that calculating it will take more time - `Blockhash` is the only algorithm that don't resize images before hashing - `Nearest` resize algorithm can be faster even 5 times than any other available but provide worse results + +### Similar Videos +Tool works similar as Similar Images. + +To work require `FFmpeg`, so it will show an error when it is not found in OS. +Also only checks files which are longer than 30s. + +At first, it collects video files by extension (`mp4`, `mpv`, `avi` etc.). +Next each file is hashed. Implementation is hidden in library but looks that generate 10 images from this video and hash them with help of perceptual hash. + +Such hashes are saved to cache to be able to use them later. + +Next, with provided by user tolerance, they are compared to each other and group of similar hashes are returned. + ### Broken Files This tool finds files which are corrupted or have an invalid extension. diff --git a/misc/flathub.sh b/misc/flathub.sh index 4983f4d..803f6c9 100755 --- a/misc/flathub.sh +++ b/misc/flathub.sh @@ -1,5 +1,6 @@ #!/bin/bash pip3 install aiohttp toml wget https://raw.githubusercontent.com/flatpak/flatpak-builder-tools/master/cargo/flatpak-cargo-generator.py +mkdir flatpak python3 flatpak-cargo-generator.py ./Cargo.lock -o flatpak/cargo-sources.json rm flatpak-cargo-generator.py