From 55b2744bf4d97d6fafabbfd6c64d103551ede056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mikrut?= <41945903+qarmin@users.noreply.github.com> Date: Fri, 9 Jun 2023 22:11:47 +0200 Subject: [PATCH] Simplify, fix and improve similar images algorithm (#983) * Random changer * CD * A1 * Almost? * Nein * Heif * Tests that needs to be fixed * Fixed test * Tests * Fixed image counting in reference folders * Lock * Catch possible more bugs in pdf * Find ever more bugs --- Cargo.lock | 630 +++++++---------- Changelog.md | 12 + czkawka_cli/Cargo.toml | 4 +- czkawka_core/Cargo.toml | 21 +- czkawka_core/src/broken_files.rs | 47 +- czkawka_core/src/common.rs | 2 +- czkawka_core/src/common_dir_traversal.rs | 2 +- czkawka_core/src/common_directory.rs | 4 +- czkawka_core/src/similar_images.rs | 634 +++++++++++------- czkawka_gui/Cargo.toml | 14 +- czkawka_gui/src/compute_results.rs | 24 +- .../connect_things/connect_popovers_select.rs | 1 - 12 files changed, 737 insertions(+), 658 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cfd179a..78bfeec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,18 +14,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" -[[package]] -name = "aes" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" -dependencies = [ - "cfg-if", - "cipher 0.3.0", - "cpufeatures", - "opaque-debug", -] - [[package]] name = "aes" version = "0.8.2" @@ -33,19 +21,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "433cfd6710c9986c576a25ca913c39d66a6474107b406f34f91d4a8923395241" dependencies = [ "cfg-if", - "cipher 0.4.4", + "cipher", "cpufeatures", ] [[package]] name = "aho-corasick" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" dependencies = [ "memchr", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -91,7 +85,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -101,7 +95,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" dependencies = [ "anstyle", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -136,7 +130,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.18", ] [[package]] @@ -156,15 +150,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "base64" -version = "0.13.1" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "base64" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" [[package]] name = "base64ct" @@ -195,9 +183,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.2.1" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24a6904aef64d73cf10ab17ebace7befb918b82164785cb89907993be7f83813" +checksum = "6776fc96284a0bb647b615056fc496d1fe1644a7ab01829818a6d91cae888b84" [[package]] name = "bk-tree" @@ -211,9 +199,9 @@ dependencies = [ [[package]] name = "blake3" -version = "1.3.3" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ae2468a89544a466886840aa467a25b766499f4f04bf7d9fcd10ecee9fccef" +checksum = "729b71f35bd3fa1a4c86b85d32c8b9069ea7fe14f7a53cfabb65f62d4265b888" dependencies = [ "arrayref", "arrayvec", @@ -249,9 +237,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.12.1" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b1ce199063694f33ffb7dd4e0ee620741495c32833cde5aa08f02a0bf96f0c8" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "bytemuck" @@ -288,9 +276,9 @@ dependencies = [ [[package]] name = "cairo-rs" -version = "0.17.0" +version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8af54f5d48af1226928adc1f57edd22f5df1349e7da1fc96ae15cf43db0e871" +checksum = "ab3603c4028a5e368d09b51c8b624b9a46edcd7c3778284077a6125af73c9f0a" dependencies = [ "bitflags 1.3.2", "cairo-sys-rs", @@ -302,9 +290,9 @@ dependencies = [ [[package]] name = "cairo-sys-rs" -version = "0.17.0" +version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55382a01d30e5e53f185eee269124f5e21ab526595b872751278dfbb463594e" +checksum = "691d0c66b1fb4881be80a760cb8fe76ea97218312f9dfe2c9cc0f496ca279cb1" dependencies = [ "glib-sys", "libc", @@ -317,7 +305,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" dependencies = [ - "cipher 0.4.4", + "cipher", ] [[package]] @@ -339,9 +327,9 @@ dependencies = [ [[package]] name = "cfg-expr" -version = "0.15.1" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8790cf1286da485c72cf5fc7aeba308438800036ec67d89425924c4807268c9" +checksum = "e70d3ad08698a0568b0562f22710fe6bfc1f4a61a367c77d0398c562eadd453a" dependencies = [ "smallvec", "target-lexicon", @@ -355,28 +343,19 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.24" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" +checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" dependencies = [ + "android-tzdata", "iana-time-zone", "js-sys", - "num-integer", "num-traits", "time 0.1.45", "wasm-bindgen", "winapi", ] -[[package]] -name = "cipher" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" -dependencies = [ - "generic-array", -] - [[package]] name = "cipher" version = "0.4.4" @@ -389,9 +368,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.2.7" +version = "4.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34d21f9bf1b425d2968943631ec91202fe5e837264063503708b83013f8fc938" +checksum = "ca8f255e4b8027970e78db75e78831229c9815fdbfa67eb1a1b777a62e24b4a0" dependencies = [ "clap_builder", "clap_derive", @@ -400,9 +379,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.2.7" +version = "4.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "914c8c79fb560f238ef6429439a30023c862f7a28e688c58f7203f12b29970bd" +checksum = "acd4f3c17c83b0ba34ffbc4f8bbd74f079413f747f84a6f89292f138057e36ab" dependencies = [ "anstream", "anstyle", @@ -413,31 +392,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.2.0" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4" +checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.18", ] [[package]] name = "clap_lex" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" - -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" [[package]] name = "color_quant" @@ -517,7 +486,7 @@ dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset", + "memoffset 0.8.0", "scopeguard", ] @@ -546,50 +515,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "cxx" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn 2.0.15", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.15", -] - [[package]] name = "czkawka_cli" version = "5.1.0" @@ -606,7 +531,7 @@ dependencies = [ "anyhow", "audio_checker", "bincode", - "bitflags 2.2.1", + "bitflags 2.3.1", "bk-tree", "blake3", "crc32fast", @@ -623,6 +548,7 @@ dependencies = [ "imagepipe", "infer", "libheif-rs", + "libheif-sys", "lofty", "mime_guess", "num_cpus", @@ -712,9 +638,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", @@ -750,7 +676,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.18", ] [[package]] @@ -782,7 +708,7 @@ checksum = "48016319042fb7c87b78d2993084a831793a897a5cd1a2a67cab9d1eeb4b7d76" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.18", ] [[package]] @@ -793,7 +719,7 @@ checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -808,15 +734,15 @@ dependencies = [ [[package]] name = "exr" -version = "1.6.3" +version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdd2162b720141a91a054640662d3edce3d50a944a50ffca5313cd951abb35b4" +checksum = "279d3efcc55e19917fff7ab3ddd6c14afb6a90881a0078465196fe2f99d08c56" dependencies = [ "bit_field", "flume", "half", "lebe", - "miniz_oxide 0.6.2", + "miniz_oxide", "rayon-core", "smallvec", "zune-inflate", @@ -862,9 +788,9 @@ dependencies = [ [[package]] name = "ffmpeg_cmdline_utils" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f1563b3b2e6ae3848990db34c5fdebc9418f67e67814cd1df83573d949461d7" +checksum = "4465342596fe680b4670e2f235066aaa123e44a0149fecb86378f288b32c83db" dependencies = [ "image", "rayon", @@ -876,11 +802,11 @@ dependencies = [ [[package]] name = "field-offset" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3cf3a800ff6e860c863ca6d4b16fd999db8b752819c1606884047b73e468535" +checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" dependencies = [ - "memoffset", + "memoffset 0.9.0", "rustc_version", ] @@ -900,7 +826,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" dependencies = [ "crc32fast", - "miniz_oxide 0.7.1", + "miniz_oxide", ] [[package]] @@ -968,9 +894,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ "percent-encoding", ] @@ -1043,7 +969,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.18", ] [[package]] @@ -1078,9 +1004,9 @@ dependencies = [ [[package]] name = "gdk-pixbuf" -version = "0.17.0" +version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b023fbe0c6b407bd3d9805d107d9800da3829dc5a676653210f1d5f16d7f59bf" +checksum = "695d6bc846438c5708b07007537b9274d883373dd30858ca881d7d71b5540717" dependencies = [ "bitflags 1.3.2", "gdk-pixbuf-sys", @@ -1092,9 +1018,9 @@ dependencies = [ [[package]] name = "gdk-pixbuf-sys" -version = "0.17.0" +version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b41bd2b44ed49d99277d3925652a163038bd5ed943ec9809338ffb2f4391e3b" +checksum = "9285ec3c113c66d7d0ab5676599176f1f42f4944ca1b581852215bf5694870cb" dependencies = [ "gio-sys", "glib-sys", @@ -1161,9 +1087,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "js-sys", @@ -1184,9 +1110,9 @@ dependencies = [ [[package]] name = "gio" -version = "0.17.9" +version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d14522e56c6bcb6f7a3aebc25cbcfb06776af4c0c25232b601b4383252d7cb92" +checksum = "a6973e92937cf98689b6a054a9e56c657ed4ff76de925e36fc331a15f0c5d30a" dependencies = [ "bitflags 1.3.2", "futures-channel", @@ -1204,9 +1130,9 @@ dependencies = [ [[package]] name = "gio-sys" -version = "0.17.4" +version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b1d43b0d7968b48455244ecafe41192871257f5740aa6b095eb19db78e362a5" +checksum = "0ccf87c30a12c469b6d958950f6a9c09f2be20b7773f7e70d20b867fdf2628c3" dependencies = [ "glib-sys", "gobject-sys", @@ -1217,9 +1143,9 @@ dependencies = [ [[package]] name = "glib" -version = "0.17.9" +version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7f1de7cbde31ea4f0a919453a2dcece5d54d5b70e08f8ad254dc4840f5f09b6" +checksum = "d3fad45ba8d4d2cea612b432717e834f48031cd8853c8aaf43b2c79fec8d144b" dependencies = [ "bitflags 1.3.2", "futures-channel", @@ -1240,9 +1166,9 @@ dependencies = [ [[package]] name = "glib-macros" -version = "0.17.9" +version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a7206c5c03851ef126ea1444990e81fdd6765fb799d5bc694e4897ca01bb97f" +checksum = "eca5c79337338391f1ab8058d6698125034ce8ef31b72a442437fa6c8580de26" dependencies = [ "anyhow", "heck", @@ -1255,9 +1181,9 @@ dependencies = [ [[package]] name = "glib-sys" -version = "0.17.4" +version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f00ad0a1bf548e61adfff15d83430941d9e1bb620e334f779edd1c745680a5" +checksum = "d80aa6ea7bba0baac79222204aa786a6293078c210abe69ef1336911d4bdc4f0" dependencies = [ "libc", "system-deps", @@ -1280,9 +1206,9 @@ dependencies = [ [[package]] name = "gobject-sys" -version = "0.17.4" +version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e75b0000a64632b2d8ca3cf856af9308e3a970844f6e9659bd197f026793d0" +checksum = "cd34c3317740a6358ec04572c1bcfd3ac0b5b6529275fae255b237b314bb8062" dependencies = [ "glib-sys", "libc", @@ -1291,9 +1217,9 @@ dependencies = [ [[package]] name = "graphene-rs" -version = "0.17.1" +version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21cf11565bb0e4dfc2f99d4775b6c329f0d40a2cff9c0066214d31a0e1b46256" +checksum = "def4bb01265b59ed548b05455040d272d989b3012c42d4c1bbd39083cb9b40d9" dependencies = [ "glib", "graphene-sys", @@ -1302,9 +1228,9 @@ dependencies = [ [[package]] name = "graphene-sys" -version = "0.17.0" +version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf80a4849a8d9565410a8fec6fc3678e9c617f4ac7be182ca55ab75016e07af9" +checksum = "1856fc817e6a6675e36cea0bd9a3afe296f5d9709d1e2d3182803ac77f0ab21d" dependencies = [ "glib-sys", "libc", @@ -1462,23 +1388,23 @@ dependencies = [ [[package]] name = "i18n-config" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d9f93ceee6543011739bc81699b5e0cf1f23f3a80364649b6d80de8636bc8df" +checksum = "b987084cadad6e2f2b1e6ea62c44123591a3c044793a1beabf71a8356ea768d5" dependencies = [ "log", "serde", "serde_derive", "thiserror", - "toml 0.5.11", + "toml 0.7.4", "unic-langid", ] [[package]] name = "i18n-embed" -version = "0.13.8" +version = "0.13.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2653dd1a8be0726315603f1c180b29f90e5b2a58f8b943d949d5170d9ad81101" +checksum = "92a86226a7a16632de6723449ee5fe70bac5af718bc642ee9ca2f0f6e14fa1fa" dependencies = [ "arc-swap", "fluent", @@ -1498,9 +1424,9 @@ dependencies = [ [[package]] name = "i18n-embed-fl" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b5809e2295beeb55013705c3b947cbbe83b8cadf3c73a1e6dca06381927212a" +checksum = "d26a3d3569737dfaac7fc1c4078e6af07471c3060b8e570bcd83cdd5f4685395" dependencies = [ "dashmap", "find-crate", @@ -1513,15 +1439,15 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 1.0.109", + "syn 2.0.18", "unic-langid", ] [[package]] name = "i18n-embed-impl" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0db2330e035808eb064afb67e6743ddce353763af3e0f2bdfc2476e00ce76136" +checksum = "e9a95d065e6be4499e50159172395559a388d20cf13c84c77e4a1e341786f219" dependencies = [ "find-crate", "i18n-config", @@ -1532,9 +1458,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.56" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" +checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1546,19 +1472,18 @@ dependencies = [ [[package]] name = "iana-time-zone-haiku" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ - "cxx", - "cxx-build", + "cc", ] [[package]] name = "idna" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1585,11 +1510,11 @@ dependencies = [ [[package]] name = "image_hasher" -version = "1.1.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a465709ca502270eba7ae8129c6a680f5668748d7edafa85da0f8ceae596bb2b" +checksum = "8f9e64a8c472ea9f81ac448e3b488fd82dcdfce6434cf880882bf36bfb5c268a" dependencies = [ - "base64 0.13.1", + "base64", "image", "rustdct 0.7.1", "serde", @@ -1684,13 +1609,13 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ "hermit-abi 0.3.1", "libc", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -1711,7 +1636,7 @@ dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", "rustix", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -1759,9 +1684,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.61" +version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" dependencies = [ "wasm-bindgen", ] @@ -1780,9 +1705,9 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" [[package]] name = "libc" -version = "0.2.143" +version = "0.2.146" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc207893e85c5d6be840e969b496b53d94cec8be2d501b214f50daa97fa8024" +checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" [[package]] name = "libheif-rs" @@ -1806,18 +1731,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" - -[[package]] -name = "link-cplusplus" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" -dependencies = [ - "cc", -] +checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" [[package]] name = "linked-hash-map" @@ -1827,9 +1743,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "locale_config" @@ -1846,9 +1762,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -1856,11 +1772,11 @@ dependencies = [ [[package]] name = "lofty" -version = "0.12.1" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd1b8e18439c8fabf316e0a87e9cdca9667e90bcf5a080946a264fd60bbed5e8" +checksum = "ddd367f21a745a75e8e92b7ce8b83411cf12bf84a23978e671764ef823a6b3b4" dependencies = [ - "base64 0.21.0", + "base64", "byteorder", "flate2", "lofty_attr", @@ -1872,23 +1788,20 @@ dependencies = [ [[package]] name = "lofty_attr" -version = "0.6.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "336dfabb2fdfd932cebfcaa5d0fc57abac0d49f6ae9ddaa7c47a51bf9f74f966" +checksum = "e992e1fc7c53fec81c09a605b990b0f5ff3b82fb9d5c26389ec3c9fbc9773ab2" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.18", ] [[package]] name = "log" -version = "0.4.17" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" [[package]] name = "loom" @@ -1944,6 +1857,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + [[package]] name = "mime" version = "0.3.17" @@ -1960,15 +1882,6 @@ dependencies = [ "unicase", ] -[[package]] -name = "miniz_oxide" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" -dependencies = [ - "adler", -] - [[package]] name = "miniz_oxide" version = "0.7.1" @@ -2105,15 +2018,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "open" @@ -2133,9 +2040,9 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "pango" -version = "0.17.4" +version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52c280b82a881e4208afb3359a8e7fde27a1b272280981f1f34610bed5770d37" +checksum = "35be456fc620e61f62dff7ff70fbd54dcbaf0a4b920c0f16de1107c47d921d48" dependencies = [ "bitflags 1.3.2", "gio", @@ -2147,9 +2054,9 @@ dependencies = [ [[package]] name = "pango-sys" -version = "0.17.0" +version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4293d0f0b5525eb5c24734d30b0ed02cd02aa734f216883f376b54de49625de8" +checksum = "3da69f9f3850b0d8990d462f8c709561975e95f689c1cdf0fecdebde78b35195" dependencies = [ "glib-sys", "gobject-sys", @@ -2169,15 +2076,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.2.16", + "redox_syscall 0.3.5", "smallvec", - "windows-sys 0.45.0", + "windows-targets 0.48.0", ] [[package]] @@ -2221,7 +2128,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e375ec076445f61d4dbc4636e9e788f841d279c65d6fea8a3875caddd4f2dd82" dependencies = [ - "aes 0.8.2", + "aes", "bitflags 1.3.2", "cbc", "datasize", @@ -2255,28 +2162,28 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pin-project" -version = "1.0.12" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.12" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.18", ] [[package]] @@ -2307,7 +2214,7 @@ dependencies = [ "crc32fast", "fdeflate", "flate2", - "miniz_oxide 0.7.1", + "miniz_oxide", ] [[package]] @@ -2361,9 +2268,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.56" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" dependencies = [ "unicode-ident", ] @@ -2379,9 +2286,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.26" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" dependencies = [ "proc-macro2", ] @@ -2455,9 +2362,9 @@ dependencies = [ [[package]] name = "realfft" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6b8e8f0c6d2234aa58048d7290c60bf92cd36fd2888cd8331c66ad4f2e1d2" +checksum = "953d9f7e5cdd80963547b456251296efc2626ed4e3cbf36c869d9564e0220571" dependencies = [ "rustfft 6.1.0", ] @@ -2493,13 +2400,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.1" +version = "1.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" +checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.1", + "regex-syntax 0.7.2", ] [[package]] @@ -2519,9 +2426,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" [[package]] name = "rubato" @@ -2537,9 +2444,9 @@ dependencies = [ [[package]] name = "rust-embed" -version = "6.6.1" +version = "6.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b68543d5527e158213414a92832d2aab11a84d2571a5eb021ebe22c43aab066" +checksum = "b73e721f488c353141288f223b599b4ae9303ecf3e62923f40a492f0634a4dc3" dependencies = [ "rust-embed-impl", "rust-embed-utils", @@ -2548,14 +2455,14 @@ dependencies = [ [[package]] name = "rust-embed-impl" -version = "6.5.0" +version = "6.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4e0f0ced47ded9a68374ac145edd65a6c1fa13a96447b873660b2a568a0fd7" +checksum = "e22ce362f5561923889196595504317a4372b84210e6e335da529a65ea5452b5" dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 1.0.109", + "syn 2.0.18", "walkdir", ] @@ -2642,7 +2549,7 @@ dependencies = [ "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -2688,12 +2595,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "scratch" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" - [[package]] name = "self_cell" version = "0.10.2" @@ -2708,22 +2609,22 @@ checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" [[package]] name = "serde" -version = "1.0.162" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71b2f6e1ab5c2b98c05f0f35b236b22e8df7ead6ffbf51d7808da7f8817e7ab6" +checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.162" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2a0814352fd64b58489904a44ea8d90cb1a91dcb6b4f5ebabc32c8318e93cb6" +checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.18", ] [[package]] @@ -2739,9 +2640,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4" +checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d" dependencies = [ "serde", ] @@ -2843,9 +2744,9 @@ dependencies = [ [[package]] name = "state" -version = "0.5.3" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbe866e1e51e8260c9eed836a042a5e7f6726bb2b411dffeaa712e19c388f23b" +checksum = "2b8c4a4445d81357df8b1a650d0d0d6fbbbfe99d064aa5e02f3e4022061476d8" dependencies = [ "loom", ] @@ -2874,15 +2775,15 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "subtle" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "symphonia" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3671dd6f64f4f9d5c87179525054cfc1f60de23ba1f193bd6ceab812737403f1" +checksum = "62e48dba70095f265fdb269b99619b95d04c89e619538138383e63310b14d941" dependencies = [ "lazy_static", "symphonia-bundle-flac", @@ -2902,9 +2803,9 @@ dependencies = [ [[package]] name = "symphonia-bundle-flac" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dc2deed3204967871ba60f913378f95820cb47a2fe9b2eef5a9eedb417dfdc8" +checksum = "7f23b0482a7cb18fcdf9981ab0b78df800ef0080187d294650023c462439058d" dependencies = [ "log", "symphonia-core", @@ -2914,9 +2815,9 @@ dependencies = [ [[package]] name = "symphonia-bundle-mp3" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55a0846e7a2c9a8081ff799fc83a975170417ad2a143f644a77ec2e3e82a2b73" +checksum = "0f31d7fece546f1e6973011a9eceae948133bbd18fd3d52f6073b1e38ae6368a" dependencies = [ "bitflags 1.3.2", "lazy_static", @@ -2927,9 +2828,9 @@ dependencies = [ [[package]] name = "symphonia-codec-aac" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fcdd4a10695ca0528572360ec020586320357350eb62791693667e7de8c871a" +checksum = "68bdd75b25ce4b84b12a4bd20bfea2460c2dbd7fc1d227ef5533504d3168109d" dependencies = [ "lazy_static", "log", @@ -2938,9 +2839,9 @@ dependencies = [ [[package]] name = "symphonia-codec-adpcm" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a5cfb8d4405e26eb9593157dc45b05e102b8d774b38ed2a95946d6bb9e26e3e" +checksum = "870e7dc1865d818c7b6318879d060553a73a3b2a3b8443dff90910f10ac41150" dependencies = [ "log", "symphonia-core", @@ -2948,9 +2849,9 @@ dependencies = [ [[package]] name = "symphonia-codec-alac" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c49e1b209318bcefa7ff452bd85f1f593210943a7d9786b7d4250e8991a7449c" +checksum = "3a27e8763d1c9eff666faf903e73a99d4de2f7a93fca4e3c214c1d68432903b9" dependencies = [ "log", "symphonia-core", @@ -2958,9 +2859,9 @@ dependencies = [ [[package]] name = "symphonia-codec-pcm" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cb9a9f0b9991cccf3217b74644af412d5d082a4815e5e2943f26e0ecabdf3c9" +checksum = "47f1fbd220a06a641c8ce2ddad10f5ef6ee5cc0c54d9044d25d43b0d3119deaa" dependencies = [ "log", "symphonia-core", @@ -2968,9 +2869,9 @@ dependencies = [ [[package]] name = "symphonia-codec-vorbis" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dfed6f7b6bfa21d7cef1acefc8eae5db80df1608a1aca91871b07cbd28d7b74" +checksum = "3953397e3506aa01350c4205817e4f95b58d476877a42f0458d07b665749e203" dependencies = [ "log", "symphonia-core", @@ -2979,9 +2880,9 @@ dependencies = [ [[package]] name = "symphonia-core" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9567e2d8a5f866b2f94f5d366d811e0c6826babcff6d37de9e1a6690d38869" +checksum = "f7c73eb88fee79705268cc7b742c7bc93a7b76e092ab751d0833866970754142" dependencies = [ "arrayvec", "bitflags 1.3.2", @@ -2992,9 +2893,9 @@ dependencies = [ [[package]] name = "symphonia-format-isomp4" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1818f6f54b4eaba5ec004a8dbcca637c57e617eb1ff4c9addbd3fc065eba437" +checksum = "ffdf14bae5cf352032416bc64151e5d6242d29d33cbf3238513b44d4427a1efb" dependencies = [ "encoding_rs", "log", @@ -3005,9 +2906,9 @@ dependencies = [ [[package]] name = "symphonia-format-mkv" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bd22f2def8c8f078495ad66111648bfc7d5222ee33774f2077cb665588f3119" +checksum = "f5c61dfc851ad25d4043d8c231d8617e8f7cd02a6cc0edad21ade21848d58895" dependencies = [ "lazy_static", "log", @@ -3018,9 +2919,9 @@ dependencies = [ [[package]] name = "symphonia-format-ogg" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "474df6e86b871dcb56913130bada1440245f483057c4a2d8a2981455494c4439" +checksum = "9bf1a00ccd11452d44048a0368828040f778ae650418dbd9d8765b7ee2574c8d" dependencies = [ "log", "symphonia-core", @@ -3030,9 +2931,9 @@ dependencies = [ [[package]] name = "symphonia-format-wav" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06679bd5646b3037300f88891dfc8a6e1cc4e1133206cc17a98e5d7c22f88296" +checksum = "da76614728fa27c003bdcdfbac51396bd8fcbf94c95fe8e62f1d2bac58ef03a4" dependencies = [ "log", "symphonia-core", @@ -3041,9 +2942,9 @@ dependencies = [ [[package]] name = "symphonia-metadata" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acd35c263223ef6161000be79b124a75de3e065eea563bf3ef169b3e94c7bb2e" +checksum = "89c3e1937e31d0e068bbe829f66b2f2bfaa28d056365279e0ef897172c3320c0" dependencies = [ "encoding_rs", "lazy_static", @@ -3053,9 +2954,9 @@ dependencies = [ [[package]] name = "symphonia-utils-xiph" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce340a6c33ac06cb42de01220308ec056e8a2a3d5cc664aaf34567392557136b" +checksum = "a450ca645b80d69aff8b35576cbfdc7f20940b29998202aab910045714c951f8" dependencies = [ "symphonia-core", "symphonia-metadata", @@ -3074,9 +2975,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.15" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" dependencies = [ "proc-macro2", "quote", @@ -3085,14 +2986,14 @@ dependencies = [ [[package]] name = "system-deps" -version = "6.0.5" +version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0fe581ad25d11420b873cf9aedaca0419c2b411487b134d4d21065f3d092055" +checksum = "e5fa6fb9ee296c0dc2df41a656ca7948546d061958115ddb0bcaae43ad0d17d2" dependencies = [ "cfg-expr", "heck", "pkg-config", - "toml 0.7.3", + "toml 0.7.4", "version-compare", ] @@ -3104,24 +3005,16 @@ checksum = "fd1ba337640d60c3e96bc6f0638a939b9c9a7f2c316a1598c279828b3d1dc8c5" [[package]] name = "tempfile" -version = "3.5.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" dependencies = [ + "autocfg", "cfg-if", "fastrand", "redox_syscall 0.3.5", "rustix", - "windows-sys 0.45.0", -] - -[[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", + "windows-sys", ] [[package]] @@ -3141,7 +3034,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.18", ] [[package]] @@ -3178,9 +3071,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.21" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc" +checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" dependencies = [ "serde", "time-core", @@ -3227,9 +3120,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21" +checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec" dependencies = [ "serde", "serde_spanned", @@ -3239,18 +3132,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.19.8" +version = "0.19.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" +checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739" dependencies = [ "indexmap", "serde", @@ -3279,14 +3172,14 @@ checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.18", ] [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", "valuable", @@ -3333,9 +3226,9 @@ dependencies = [ [[package]] name = "trash" -version = "3.0.1" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27b2a127810fceb959593bbc6c7b8e0282c2d318d76f0749252197c52a1dd0c" +checksum = "6b782240476bca40f750a7f205510ac1449ab707d3ac3f451c4b356f557c0ecd" dependencies = [ "chrono", "libc", @@ -3404,9 +3297,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" [[package]] name = "unicode-normalization" @@ -3417,17 +3310,11 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - [[package]] name = "url" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" dependencies = [ "form_urlencoded", "idna", @@ -3442,9 +3329,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.3.2" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dad5567ad0cf5b760e5665964bec1b47dfd077ba8a2544b513f3556d3d239a2" +checksum = "345444e32442451b267fc254ae85a209c64be56d2890e601a0c37ff0c3c5ecd2" [[package]] name = "valuable" @@ -3505,9 +3392,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.84" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3515,24 +3402,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.84" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.18", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.84" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3540,22 +3427,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.84" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.18", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.84" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" [[package]] name = "weezl" @@ -3612,15 +3499,6 @@ dependencies = [ "windows-targets 0.48.0", ] -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - [[package]] name = "windows-sys" version = "0.48.0" @@ -3770,11 +3648,11 @@ dependencies = [ [[package]] name = "zip" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e92305c174683d78035cbf1b70e18db6329cc0f1b9cae0a52ca90bf5bfe7125" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" dependencies = [ - "aes 0.7.5", + "aes", "byteorder", "bzip2", "constant_time_eq 0.1.5", @@ -3784,7 +3662,7 @@ dependencies = [ "hmac", "pbkdf2", "sha1", - "time 0.3.21", + "time 0.3.22", ] [[package]] diff --git a/Changelog.md b/Changelog.md index 48ac1e2..5ae6295 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,15 @@ +## Version 5.2.0 - ? +- Add finding similar audio files by content - [#970](https://github.com/qarmin/czkawka/pull/970) +- Allow to find duplicates by name/size at once - [#956](https://github.com/qarmin/czkawka/pull/956) +- Fixed bug when cache for music tags not worked - [#970](https://github.com/qarmin/czkawka/pull/970) +- Allow to set number of threads from CLI - [#972](https://github.com/qarmin/czkawka/pull/972) +- Fix problem with invalid item sorting in bad extensions mode - [#972](https://github.com/qarmin/czkawka/pull/972) +- Big refactor/cleaning of code - [#956](https://github.com/qarmin/czkawka/pull/956)/[#970](https://github.com/qarmin/czkawka/pull/970)/[#972](https://github.com/qarmin/czkawka/pull/972) +- Use builtin gtk webp loader for previews - [#923](https://github.com/qarmin/czkawka/pull/923) +- Fixed docker build - [#947](https://github.com/qarmin/czkawka/pull/947) +- Restore snap builds broken since GTk 4 port - [#965](https://github.com/qarmin/czkawka/pull/947) +- Instruction how to build native ARM64 binaries on Mac - [#945](https://github.com/qarmin/czkawka/pull/945)/[#971](https://github.com/qarmin/czkawka/pull/971) + ## Version 5.1.0 - 19.02.2023r - Added sort button - [#894](https://github.com/qarmin/czkawka/pull/894) - Allow to set number of thread used to scan - [#839](https://github.com/qarmin/czkawka/pull/839) diff --git a/czkawka_cli/Cargo.toml b/czkawka_cli/Cargo.toml index 35dfa9b..608bc49 100644 --- a/czkawka_cli/Cargo.toml +++ b/czkawka_cli/Cargo.toml @@ -10,10 +10,10 @@ homepage = "https://github.com/qarmin/czkawka" repository = "https://github.com/qarmin/czkawka" [dependencies] -clap = { version = "4.2", features = ["derive"] } +clap = { version = "4.3", features = ["derive"] } # For enum types -image_hasher = "1.1" +image_hasher = "1.2" [dependencies.czkawka_core] path = "../czkawka_core" diff --git a/czkawka_core/Cargo.toml b/czkawka_core/Cargo.toml index 14a3b8a..140ceb2 100644 --- a/czkawka_core/Cargo.toml +++ b/czkawka_core/Cargo.toml @@ -19,14 +19,14 @@ crossbeam-channel = "0.5" directories-next = "2.0" # Needed by similar images -image_hasher = "1.1" +image_hasher = "1.2" bk-tree = "0.5" image = "0.24" hamming = "0.1" # Needed by same music -bitflags = "2.2" -lofty = "0.12" +bitflags = "2.3" +lofty = "0.14" # Futures - needed by async progress sender futures = "0.3.28" @@ -41,11 +41,11 @@ rusty-chromaprint = "0.1" symphonia = { version = "0.5", features = ["all"] } # Hashes for duplicate files -blake3 = "1.3" +blake3 = "1.4" crc32fast = "1.3" xxhash-rust = { version = "0.8", features = ["xxh3"] } -tempfile = "3.5" +tempfile = "3.6" # Video Duplicates vid_dup_finder_lib = "0.1" @@ -59,8 +59,8 @@ serde_json = "1.0" # Language i18n-embed = { version = "0.13", features = ["fluent-system", "desktop-requester"] } i18n-embed-fl = "0.6" -rust-embed = "6.6" -once_cell = "1.17" +rust-embed = "6.7" +once_cell = "1.18" # Raw image files rawloader = "0.37" @@ -73,11 +73,12 @@ infer = "0.13" num_cpus = "1.15" # Heif/Heic -libheif-rs = { version = "0.18.0", optional = true } # Do not upgrade now, since Ubuntu 22.04 not works with newer version +libheif-rs = { version = "=0.18.0", optional = true } # Do not upgrade now, since Ubuntu 22.04 not works with newer version +libheif-sys = { version = "=1.14.2", optional = true } # 1.14.3 brake compilation on Ubuntu 22.04 anyhow = { version = "1.0" } -state = "0.5" +state = "0.6" [features] default = [] -heif = ["dep:libheif-rs"] +heif = ["dep:libheif-rs", "dep:libheif-sys"] diff --git a/czkawka_core/src/broken_files.rs b/czkawka_core/src/broken_files.rs index 0ca48a3..f5d7801 100644 --- a/czkawka_core/src/broken_files.rs +++ b/czkawka_core/src/broken_files.rs @@ -372,23 +372,27 @@ impl BrokenFiles { let mut file_entry_clone = file_entry.clone(); let result = panic::catch_unwind(|| { - if let Err(e) = FileOptions::cached().parse_options(parser_options).open(&file_entry.path) { - if let PdfError::Io { .. } = e { - return None; - } - - let mut error_string = e.to_string(); - // Workaround for strange error message https://github.com/qarmin/czkawka/issues/898 - if error_string.starts_with("Try at") { - if let Some(start_index) = error_string.find("/pdf-") { - error_string = format!("Decoding error in pdf-rs library - {}", &error_string[start_index..]); + match FileOptions::cached().parse_options(parser_options).open(&file_entry.path) { + Ok(file) => { + for idx in 0..file.num_pages() { + if let Err(e) = file.get_page(idx) { + let err = validate_pdf_error(&mut file_entry, e); + if let PdfError::InvalidPassword = err { + return None; + } else { + break; + } + } } } - - file_entry.error_string = error_string; - let error = unpack_pdf_error(e); - if let PdfError::InvalidPassword = error { - return None; + Err(e) => { + if let PdfError::Io { .. } = e { + return None; + } + let err = validate_pdf_error(&mut file_entry, e); + if let PdfError::InvalidPassword = err { + return None; + } } } Some(file_entry) @@ -708,3 +712,16 @@ fn unpack_pdf_error(e: PdfError) -> PdfError { e } } + +fn validate_pdf_error(file_entry: &mut FileEntry, e: PdfError) -> PdfError { + let mut error_string = e.to_string(); + // Workaround for strange error message https://github.com/qarmin/czkawka/issues/898 + if error_string.starts_with("Try at") { + if let Some(start_index) = error_string.find("/pdf-") { + error_string = format!("Decoding error in pdf-rs library - {}", &error_string[start_index..]); + } + } + + file_entry.error_string = error_string; + unpack_pdf_error(e) +} diff --git a/czkawka_core/src/common.rs b/czkawka_core/src/common.rs index 36de405..b7a3418 100644 --- a/czkawka_core/src/common.rs +++ b/czkawka_core/src/common.rs @@ -24,7 +24,7 @@ use crate::common_directory::Directories; use crate::common_items::ExcludedItems; use crate::common_traits::ResultEntry; -static NUMBER_OF_THREADS: state::Storage = state::Storage::new(); +static NUMBER_OF_THREADS: state::InitCell = state::InitCell::new(); pub fn get_number_of_threads() -> usize { let data = NUMBER_OF_THREADS.get(); diff --git a/czkawka_core/src/common_dir_traversal.rs b/czkawka_core/src/common_dir_traversal.rs index 6567ac8..c1b40b8 100644 --- a/czkawka_core/src/common_dir_traversal.rs +++ b/czkawka_core/src/common_dir_traversal.rs @@ -473,7 +473,7 @@ where } } if counter > 0 { - // Do not increase counter one by one in threads, because usually it + // Increase counter in batch, because usually it may be slow to add multiple times atomic value atomic_counter.fetch_add(counter, Ordering::Relaxed); } (dir_result, warnings, fe_result, set_as_not_empty_folder_list, folder_entries_list) diff --git a/czkawka_core/src/common_directory.rs b/czkawka_core/src/common_directory.rs index 0d73937..e509877 100644 --- a/czkawka_core/src/common_directory.rs +++ b/czkawka_core/src/common_directory.rs @@ -13,9 +13,9 @@ pub struct Directories { pub excluded_directories: Vec, pub included_directories: Vec, pub reference_directories: Vec, - exclude_other_filesystems: Option, + pub exclude_other_filesystems: Option, #[cfg(target_family = "unix")] - included_dev_ids: Vec, + pub included_dev_ids: Vec, } impl Directories { diff --git a/czkawka_core/src/similar_images.rs b/czkawka_core/src/similar_images.rs index 29dcdcb..fc71867 100644 --- a/czkawka_core/src/similar_images.rs +++ b/czkawka_core/src/similar_images.rs @@ -5,8 +5,7 @@ use std::io::*; use std::mem; use std::panic; use std::path::{Path, PathBuf}; -use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; -use std::sync::Arc; +use std::sync::atomic::Ordering; use std::time::SystemTime; use bk_tree::BKTree; @@ -22,8 +21,8 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "heif")] use crate::common::get_dynamic_image_from_heic; use crate::common::{ - check_folder_children, create_crash_message, get_dynamic_image_from_raw_image, get_number_of_threads, open_cache_folder, prepare_thread_handler_common, - send_info_and_wait_for_ending_all_threads, HEIC_EXTENSIONS, IMAGE_RS_SIMILAR_IMAGES_EXTENSIONS, RAW_IMAGE_EXTENSIONS, + check_folder_children, create_crash_message, get_dynamic_image_from_raw_image, open_cache_folder, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads, + HEIC_EXTENSIONS, IMAGE_RS_SIMILAR_IMAGES_EXTENSIONS, RAW_IMAGE_EXTENSIONS, }; use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData, ToolType}; use crate::common_directory::Directories; @@ -564,81 +563,25 @@ impl SimilarImages { (file_entry, buf) } - fn compare_hashes( - &self, - hashes_to_check: &[ImHash], - atomic_counter: &Arc, - stop_receiver: Option<&Receiver<()>>, - check_was_stopped: &AtomicBool, - tolerance: u32, - hashes_with_multiple_images: &HashSet, - all_hashed_images: &HashMap>, - ) -> Option<(HashMap, HashMap)> { - let mut hashes_parents: HashMap = Default::default(); // Hashes used as parent (hash, children_number_of_hash) - let mut hashes_similarity: HashMap = Default::default(); // Hashes used as child, (parent_hash, similarity) - - // Sprawdź czy hash nie jest użyty jako master gdzie indziej - // Jeśli tak to przejdź do sprawdzania kolejnego elementu - // Zweryfikuj czy sprawdzany element ma rodzica - // Jeśli ma to sprawdź czy similarity nowego rodzica jest mniejsze niż starego - // // Jeśli tak to zmniejsz ilość dzieci starego rodzica, dodaj ilość dzieci w nowym rodzicu i podmień rekord hashes_similarity - // // Jeśli nie to dodaj nowy rekord w hashes_similarity jak i hashes_parents z liczbą dzieci równą 1 - - for (index, hash_to_check) in hashes_to_check.iter().enumerate() { - // Don't check for user stop too often - // Also don't add too often data to atomic variable - const CYCLES_COUNTER: usize = 0b11_1111; - if ((index & CYCLES_COUNTER) == CYCLES_COUNTER) && index != 0 { - atomic_counter.fetch_add(CYCLES_COUNTER, Ordering::Relaxed); - if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() { - check_was_stopped.store(true, Ordering::Relaxed); - return None; - } - } - hashes_parents.insert((*hash_to_check).clone(), 0); - - let mut found_items = self - .bktree - .find(hash_to_check, tolerance) - .filter(|(similarity, _hash)| if self.use_reference_folders { true } else { *similarity != 0 }) - .collect::>(); - - found_items.sort_unstable_by_key(|f| f.0); - - for (similarity, compared_hash) in found_items { - image_to_check( - &mut hashes_parents, - &mut hashes_similarity, - hashes_with_multiple_images, - hash_to_check, - compared_hash, - similarity, - ); - } - } - - debug_check_for_duplicated_things(self.use_reference_folders, &hashes_parents, &hashes_similarity, all_hashed_images, "BEFORE"); - - Some((hashes_parents, hashes_similarity)) - } - - fn chunk_hashes(&mut self, all_hashed_images: &HashMap>, all_hashes: &Vec) -> (Vec>, HashSet) { - let mut hashes_with_multiple_images: HashSet = Default::default(); // Fast way to check if hash have multiple images - let mut files_from_referenced_folders: HashMap> = HashMap::new(); - let mut normal_files: HashMap> = HashMap::new(); - - let number_of_processors = get_number_of_threads(); - let chunk_size; - - let mut initial_hashes: Vec = Vec::new(); - let mut additional_chunk_to_check: Vec = Default::default(); - - let mut chunks: Vec>; + // Split hashes at 2 parts, base hashes and hashes to compare, 3 argument is set of hashes with multiple images + fn split_hashes(&mut self, all_hashed_images: &HashMap>) -> (Vec, HashSet) { + let hashes_with_multiple_images: HashSet = all_hashed_images + .iter() + .filter_map(|(hash, vec_file_entry)| { + if vec_file_entry.len() >= 2 { + return Some(hash.clone()); + }; + None + }) + .collect(); + let mut base_hashes = Vec::new(); // Initial hashes if self.use_reference_folders { - let reference_directories = self.directories.reference_directories.clone(); + let mut files_from_referenced_folders: HashMap> = HashMap::new(); + let mut normal_files: HashMap> = HashMap::new(); + all_hashed_images.clone().into_iter().for_each(|(hash, vec_file_entry)| { for file_entry in vec_file_entry { - if reference_directories.iter().any(|e| file_entry.path.starts_with(e)) { + if is_in_reference_folder(&self.directories.reference_directories, &file_entry.path) { files_from_referenced_folders.entry(hash.clone()).or_insert_with(Vec::new).push(file_entry); } else { normal_files.entry(hash.clone()).or_insert_with(Vec::new).push(file_entry); @@ -646,44 +589,20 @@ impl SimilarImages { } }); - for (hash, vec_files) in normal_files { - if vec_files.len() >= 2 { - hashes_with_multiple_images.insert(hash.clone()); - } + for hash in normal_files.into_keys() { self.bktree.add(hash); } - for (hash, vec_files) in files_from_referenced_folders { - if vec_files.len() >= 2 { - hashes_with_multiple_images.insert(hash.clone()); - } - initial_hashes.push(hash); - } - chunk_size = initial_hashes.len() / number_of_processors; - chunks = if chunk_size > 0 { - initial_hashes.chunks(chunk_size).map(<[std::vec::Vec]>::to_vec).collect::>() - } else { - vec![initial_hashes] - }; + for hash in files_from_referenced_folders.into_keys() { + base_hashes.push(hash); + } } else { - for (hash, vec_files) in all_hashed_images { - if vec_files.len() >= 2 { - additional_chunk_to_check.push(hash.clone()); - hashes_with_multiple_images.insert(hash.clone()); - } else { - self.bktree.add(hash.clone()); - } + for original_hash in all_hashed_images.keys() { + self.bktree.add(original_hash.clone()); } - chunk_size = all_hashes.len() / number_of_processors; - chunks = if chunk_size > 0 { - all_hashes.chunks(chunk_size).map(<[Vec]>::to_vec).collect::>() - } else { - vec![all_hashes.clone()] - }; - chunks.push(additional_chunk_to_check); + base_hashes = all_hashed_images.keys().cloned().collect::>(); } - - (chunks, hashes_with_multiple_images) + (base_hashes, hashes_with_multiple_images) } fn collect_hash_compare_result( @@ -720,7 +639,7 @@ impl SimilarImages { .filter(|e| !is_in_reference_folder(&self.directories.reference_directories, &e.path)) .cloned() .collect(); - for mut fe in &mut vec_fe { + for fe in &mut vec_fe { fe.similarity = similarity; } collected_similar_images.get_mut(&parent_hash).unwrap().append(&mut vec_fe); @@ -737,7 +656,7 @@ impl SimilarImages { for (child_hash, (parent_hash, similarity)) in hashes_similarity { let mut vec_fe = all_hashed_images.get(&child_hash).unwrap().clone(); - for mut fe in &mut vec_fe { + for fe in &mut vec_fe { fe.similarity = similarity; } collected_similar_images.get_mut(&parent_hash).unwrap().append(&mut vec_fe); @@ -745,55 +664,135 @@ impl SimilarImages { } } - fn check_for_duplicate_hashes( - &self, - parts: Vec<(HashMap, HashMap)>, - hashes_with_multiple_images: &HashSet, + fn compare_hashes_with_non_zero_tolerance( + &mut self, all_hashed_images: &HashMap>, collected_similar_images: &mut HashMap>, - ) { - let mut hashes_parents: HashMap = Default::default(); - let mut hashes_similarity: HashMap = Default::default(); - let mut iter = parts.into_iter(); - // At start fill arrays with first item - // Normal algorithm would do exactly same thing, but slower, one record after one - if let Some((first_hashes_parents, first_hashes_similarity)) = iter.next() { - hashes_parents = first_hashes_parents; - hashes_similarity = first_hashes_similarity; + progress_sender: Option<&UnboundedSender>, + stop_receiver: Option<&Receiver<()>>, + tolerance: u32, + ) -> bool { + // Don't use hashes with multiple images in bktree, because they will always be master of group and cannot be find by other hashes + let (base_hashes, hashes_with_multiple_images) = self.split_hashes(all_hashed_images); + + let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) = + prepare_thread_handler_common(progress_sender, 2, 2, base_hashes.len(), CheckingMethod::None, self.tool_type); + + let mut hashes_parents: HashMap = Default::default(); // Hashes used as parent (hash, children_number_of_hash) + let mut hashes_similarity: HashMap = Default::default(); // Hashes used as child, (parent_hash, similarity) + + // Check them in chunks, to decrease number of used memory + let base_hashes_chunks = base_hashes.chunks(1000); + for chunk in base_hashes_chunks { + let partial_results = chunk + .into_par_iter() + .map(|hash_to_check| { + atomic_counter.fetch_add(1, Ordering::Relaxed); + + if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() { + check_was_stopped.store(true, Ordering::Relaxed); + return None; + } + let mut found_items = self + .bktree + .find(hash_to_check, tolerance) + .filter(|(similarity, compared_hash)| { + *similarity != 0 && !hashes_parents.contains_key(*compared_hash) && !hashes_with_multiple_images.contains(*compared_hash) + }) + .filter(|(similarity, compared_hash)| { + if let Some((_, other_similarity_with_parent)) = hashes_similarity.get(*compared_hash) { + // If current hash is more similar to other hash than to current parent hash, then skip check earlier + // Because there is no way to be more similar to other hash than to current parent hash + if *similarity >= *other_similarity_with_parent { + return false; + } + } + true + }) + .collect::>(); + + found_items.sort_unstable_by_key(|f| f.0); + Some((hash_to_check, found_items)) + }) + .while_some() + .filter(|(original_hash, vec_similar_hashes)| !vec_similar_hashes.is_empty() || hashes_with_multiple_images.contains(*original_hash)) + .collect::>(); + + if check_was_stopped.load(Ordering::Relaxed) { + send_info_and_wait_for_ending_all_threads(&progress_thread_run, progress_thread_handle); + return false; + } + + self.connect_results(partial_results, &mut hashes_parents, &mut hashes_similarity, &hashes_with_multiple_images); } - for (partial_hashes_with_parents, partial_hashes_with_similarity) in iter { - for (parent_hash, _child_number) in partial_hashes_with_parents { - if !hashes_parents.contains_key(&parent_hash) && !hashes_similarity.contains_key(&parent_hash) { - hashes_parents.insert(parent_hash, 0); + send_info_and_wait_for_ending_all_threads(&progress_thread_run, progress_thread_handle); + + debug_check_for_duplicated_things(self.use_reference_folders, &hashes_parents, &hashes_similarity, all_hashed_images, "LATTER"); + self.collect_hash_compare_result(hashes_parents, &hashes_with_multiple_images, all_hashed_images, collected_similar_images, hashes_similarity); + + true + } + + fn connect_results( + &self, + partial_results: Vec<(&ImHash, Vec<(u32, &ImHash)>)>, + hashes_parents: &mut HashMap, + hashes_similarity: &mut HashMap, + hashes_with_multiple_images: &HashSet, + ) { + for (original_hash, vec_compared_hashes) in partial_results { + let mut number_of_added_child_items = 0; + for (similarity, compared_hash) in vec_compared_hashes { + // If hash is already in results skip it + // This check duplicates check from bktree.find, but it is needed to because when iterating over elements, this structure can change + if hashes_parents.contains_key(compared_hash) { + continue; + } + + // If there is already record, with smaller sensitivity, then replace it + let mut need_to_add = false; + let mut need_to_check = false; + + // TODO consider to replace variables from above with closures + // If current checked hash, have parent, first we must check if similarity between them is lower than checked item + if let Some((current_parent_hash, current_similarity_with_parent)) = hashes_similarity.get(original_hash) { + if *current_similarity_with_parent > similarity { + need_to_check = true; + + *hashes_parents.get_mut(current_parent_hash).unwrap() -= 1; + if hashes_parents.get(current_parent_hash) == Some(&0) && !hashes_with_multiple_images.contains(current_parent_hash) { + hashes_parents.remove(current_parent_hash); + } + hashes_similarity.remove(original_hash).unwrap(); + } + } else { + need_to_check = true; + } + + if need_to_check { + if let Some((other_parent_hash, other_similarity)) = hashes_similarity.get(compared_hash) { + if *other_similarity > similarity { + need_to_add = true; + *hashes_parents.get_mut(other_parent_hash).unwrap() -= 1; + } + } + // But when there is no record, just add it + else { + need_to_add = true; + } + } + + if need_to_add { + hashes_similarity.insert(compared_hash.clone(), (original_hash.clone(), similarity)); + number_of_added_child_items += 1; } } - for (hash_to_check, (compared_hash, similarity)) in partial_hashes_with_similarity { - image_to_check( - &mut hashes_parents, - &mut hashes_similarity, - hashes_with_multiple_images, - &hash_to_check, - &compared_hash, - similarity, - ); + if number_of_added_child_items > 0 || hashes_with_multiple_images.contains(original_hash) { + hashes_parents.insert((*original_hash).clone(), number_of_added_child_items); } } - - debug_check_for_duplicated_things(self.use_reference_folders, &hashes_parents, &hashes_similarity, all_hashed_images, "LATTER"); - - // Just simple check if all original hashes with multiple entries are available in end results - let original_hashes_at_start = hashes_with_multiple_images.len(); - let original_hashes_in_end_results = hashes_parents - .iter() - .filter(|(parent_hash, _child_number)| hashes_with_multiple_images.contains(*parent_hash)) - .count(); - if !self.use_reference_folders { - assert_eq!(original_hashes_at_start, original_hashes_in_end_results); - } - - self.collect_hash_compare_result(hashes_parents, hashes_with_multiple_images, all_hashed_images, collected_similar_images, hashes_similarity); } fn find_similar_hashes(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) -> bool { @@ -808,55 +807,27 @@ impl SimilarImages { let all_hashed_images = mem::take(&mut self.image_hashes); - let all_hashes: Vec<_> = all_hashed_images.clone().into_keys().collect(); - // Checking entries with tolerance 0 is really easy and fast, because only entries with same hashes needs to be checked if tolerance == 0 { - for (hash, vec_file_entry) in all_hashed_images.clone() { + for (hash, vec_file_entry) in all_hashed_images { if vec_file_entry.len() >= 2 { collected_similar_images.insert(hash, vec_file_entry); } } } else { - let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) = - prepare_thread_handler_common(progress_sender, 2, 2, all_hashes.len(), CheckingMethod::None, self.tool_type); - - // Don't use hashes with multiple images in bktree, because they will always be master of group and cannot be find by other hashes - - let (chunks, hashes_with_multiple_images) = self.chunk_hashes(&all_hashed_images, &all_hashes); - - let parts: Vec<_> = chunks - .into_par_iter() - .map(|hashes_to_check| { - self.compare_hashes( - &hashes_to_check, - &atomic_counter, - stop_receiver, - &check_was_stopped, - tolerance, - &hashes_with_multiple_images, - &all_hashed_images, - ) - }) - .while_some() - .collect(); - - send_info_and_wait_for_ending_all_threads(&progress_thread_run, progress_thread_handle); - - if check_was_stopped.load(Ordering::Relaxed) { + if !self.compare_hashes_with_non_zero_tolerance(&all_hashed_images, &mut collected_similar_images, progress_sender, stop_receiver, tolerance) { return false; } - - self.check_for_duplicate_hashes(parts, &hashes_with_multiple_images, &all_hashed_images, &mut collected_similar_images); } self.verify_duplicated_items(&collected_similar_images); + // Info about hashes is not needed anymore, so we drop this info self.similar_vectors = collected_similar_images.into_values().collect(); self.exclude_items_with_same_size(); - self.check_for_reference_folders(); + self.remove_multiple_records_from_reference_folders(); if self.use_reference_folders { for (_fe, vector) in &self.similar_referenced_vectors { @@ -896,7 +867,7 @@ impl SimilarImages { } } - fn check_for_reference_folders(&mut self) { + fn remove_multiple_records_from_reference_folders(&mut self) { if self.use_reference_folders { self.similar_referenced_vectors = mem::take(&mut self.similar_vectors) .into_iter() @@ -917,12 +888,14 @@ impl SimilarImages { #[allow(dead_code)] #[allow(unreachable_code)] #[allow(unused_variables)] + // TODO this probably not works good when reference folders are used pub fn verify_duplicated_items(&self, collected_similar_images: &HashMap>) { #[cfg(not(debug_assertions))] return; // Validating if group contains duplicated results let mut result_hashset: HashSet = Default::default(); let mut found = false; + // dbg!(collected_similar_images.len()); for vec_file_entry in collected_similar_images.values() { if vec_file_entry.is_empty() { println!("Empty group"); @@ -965,61 +938,6 @@ impl SimilarImages { } } -fn image_to_check<'a>( - hashes_parents: &mut HashMap, - hashes_similarity: &mut HashMap, - hashes_with_multiple_images: &HashSet, - hash_to_check: &'a ImHash, - compared_hash: &'a ImHash, - similarity: u32, -) { - if let Some(children_number) = hashes_parents.get(compared_hash) { - if *children_number > 0 || hashes_with_multiple_images.contains(compared_hash) { - return; - } - } - - // If there is already record, with smaller sensitivity, then replace it - let mut need_to_add = false; - let mut need_to_check = false; - - // TODO consider to replace variables from above with closures - // If current checked hash, have parent, first we must check if similarity between them is lower than checked item - if let Some((current_parent_hash, current_similarity_with_parent)) = hashes_similarity.get(hash_to_check) { - if *current_similarity_with_parent > similarity { - need_to_check = true; - - *hashes_parents.get_mut(current_parent_hash).unwrap() -= 1; - hashes_similarity.remove(hash_to_check).unwrap(); - } - } else { - need_to_check = true; - } - - if need_to_check { - if let Some((other_parent_hash, other_similarity)) = hashes_similarity.get(compared_hash) { - if *other_similarity > similarity { - need_to_add = true; - *hashes_parents.get_mut(other_parent_hash).unwrap() -= 1; - } - } - // But when there is no record, just add it - else { - need_to_add = true; - } - } - - if need_to_add { - hashes_similarity.insert(compared_hash.clone(), (hash_to_check.clone(), similarity)); - - if let Some(number_of_children) = hashes_parents.get_mut(hash_to_check) { - *number_of_children += 1; - } else { - hashes_parents.insert(hash_to_check.clone(), 1); - } - } -} - fn is_in_reference_folder(reference_directories: &[PathBuf], path: &Path) -> bool { reference_directories.iter().any(|e| path.starts_with(e)) } @@ -1216,7 +1134,7 @@ pub fn get_string_from_similarity(similarity: &u32, hash_size: u8) -> String { 16 => 1, 32 => 2, 64 => 3, - _ => panic!(), + _ => panic!("Invalid hash size {hash_size}"), }; if *similarity == 0 { @@ -1382,3 +1300,241 @@ fn debug_check_for_duplicated_things( assert!(!found_broken_thing); } + +#[cfg(test)] +mod tests { + use bk_tree::BKTree; + use std::path::PathBuf; + + use crate::common_directory::Directories; + use crate::similar_images::{FileEntry, Hamming, SimilarImages}; + + #[test] + fn test_compare_no_images() { + let mut similar_images = SimilarImages::default(); + similar_images.find_similar_images(None, None); + assert_eq!(similar_images.get_similar_images().len(), 0); + } + + #[test] + fn test_compare_tolerance_0_normal_mode() { + let mut similar_images = SimilarImages { + similarity: 0, + ..Default::default() + }; + + let fe1 = create_random_file_entry(vec![1, 1, 1, 1, 1, 1, 1, 1], "abc.txt"); + let fe2 = create_random_file_entry(vec![1, 1, 1, 1, 1, 1, 1, 1], "bcd.txt"); + let fe3 = create_random_file_entry(vec![1, 1, 1, 1, 1, 1, 1, 2], "cde.txt"); + let fe4 = create_random_file_entry(vec![1, 1, 1, 1, 1, 1, 1, 2], "rrt.txt"); + let fe5 = create_random_file_entry(vec![1, 1, 1, 1, 1, 1, 1, 2], "bld.txt"); + similar_images.image_hashes.insert(fe1.hash.clone(), vec![fe1.clone(), fe2.clone()]); + similar_images.image_hashes.insert(fe3.hash.clone(), vec![fe3.clone(), fe4.clone(), fe5.clone()]); + + similar_images.find_similar_hashes(None, None); + assert_eq!(similar_images.get_similar_images().len(), 2); + let first_group = similar_images.get_similar_images()[0].iter().map(|e| &e.path).collect::>(); + let second_group = similar_images.get_similar_images()[1].iter().map(|e| &e.path).collect::>(); + // Initial order is not guaranteed, so we need to check both options + if similar_images.get_similar_images()[0][0].hash == fe1.hash { + assert_eq!(first_group, vec![&fe1.path, &fe2.path]); + assert_eq!(second_group, vec![&fe3.path, &fe4.path, &fe5.path]); + } else { + assert_eq!(first_group, vec![&fe3.path, &fe4.path, &fe5.path]); + assert_eq!(second_group, vec![&fe1.path, &fe2.path]); + } + } + + #[test] + fn test_simple_normal_one_group() { + let mut similar_images = SimilarImages { + similarity: 1, + ..Default::default() + }; + + let fe1 = create_random_file_entry(vec![1, 1, 1, 1, 1, 1, 1, 1], "abc.txt"); + let fe2 = create_random_file_entry(vec![1, 1, 1, 1, 1, 1, 1, 1], "bcd.txt"); + + similar_images.image_hashes.insert(fe1.hash.clone(), vec![fe1, fe2]); + + similar_images.find_similar_hashes(None, None); + assert_eq!(similar_images.get_similar_images().len(), 1); + } + + #[test] + fn test_simple_normal_one_group_extended() { + let mut similar_images = SimilarImages { + similarity: 2, + use_reference_folders: false, + ..Default::default() + }; + + let fe1 = create_random_file_entry(vec![1, 1, 1, 1, 1, 1, 1, 1], "abc.txt"); + let fe2 = create_random_file_entry(vec![1, 1, 1, 1, 1, 1, 1, 1], "bcd.txt"); + let fe3 = create_random_file_entry(vec![1, 1, 1, 1, 1, 1, 1, 2], "rrd.txt"); + + similar_images.image_hashes.insert(fe1.hash.clone(), vec![fe1, fe2]); + similar_images.image_hashes.insert(fe3.hash.clone(), vec![fe3]); + + similar_images.find_similar_hashes(None, None); + assert_eq!(similar_images.get_similar_images().len(), 1); + assert_eq!(similar_images.get_similar_images()[0].len(), 3); + } + + #[test] + fn test_simple_referenced_same_group() { + let mut similar_images = SimilarImages { + similarity: 0, + use_reference_folders: true, + directories: Directories { + reference_directories: vec![PathBuf::from("/home/rr/")], + ..Default::default() + }, + ..Default::default() + }; + + let fe1 = create_random_file_entry(vec![1, 1, 1, 1, 1, 1, 1, 1], "/home/rr/abc.txt"); + let fe2 = create_random_file_entry(vec![1, 1, 1, 1, 1, 1, 1, 1], "/home/rr/bcd.txt"); + + similar_images.image_hashes.insert(fe1.hash.clone(), vec![fe1, fe2]); + + similar_images.find_similar_hashes(None, None); + assert_eq!(similar_images.get_similar_images().len(), 0); + } + + #[test] + fn test_simple_referenced_group_extended() { + let mut similar_images = SimilarImages { + similarity: 0, + use_reference_folders: true, + directories: Directories { + reference_directories: vec![PathBuf::from("/home/rr/")], + ..Default::default() + }, + ..Default::default() + }; + + let fe1 = create_random_file_entry(vec![1, 1, 1, 1, 1, 1, 1, 1], "/home/rr/abc.txt"); + let fe2 = create_random_file_entry(vec![1, 1, 1, 1, 1, 1, 1, 1], "/home/kk/bcd.txt"); + + similar_images.image_hashes.insert(fe1.hash.clone(), vec![fe1, fe2]); + + similar_images.find_similar_hashes(None, None); + assert_eq!(similar_images.get_similar_images_referenced().len(), 1); + assert_eq!(similar_images.get_similar_images_referenced()[0].1.len(), 1); + } + + #[test] + fn test_simple_referenced_group_extended2() { + let mut similar_images = SimilarImages { + similarity: 0, + use_reference_folders: true, + directories: Directories { + reference_directories: vec![PathBuf::from("/home/rr/")], + ..Default::default() + }, + ..Default::default() + }; + + let fe1 = create_random_file_entry(vec![1, 1, 1, 1, 1, 1, 1, 1], "/home/rr/abc.txt"); + let fe2 = create_random_file_entry(vec![1, 1, 1, 1, 1, 1, 1, 1], "/home/rr/abc2.txt"); + let fe3 = create_random_file_entry(vec![1, 1, 1, 1, 1, 1, 1, 1], "/home/kk/bcd.txt"); + let fe4 = create_random_file_entry(vec![1, 1, 1, 1, 1, 1, 1, 1], "/home/kk/bcd2.txt"); + + similar_images.image_hashes.insert(fe1.hash.clone(), vec![fe1, fe2, fe3, fe4]); + + similar_images.find_similar_hashes(None, None); + let res = similar_images.get_similar_images_referenced(); + assert_eq!(res.len(), 1); + assert_eq!(res[0].1.len(), 2); + assert!(res[0].1.iter().all(|e| e.path.starts_with("/home/kk/"))); + } + + #[test] + fn test_simple_normal_too_small_similarity() { + for _ in 0..50 { + let mut similar_images = SimilarImages { + similarity: 1, + use_reference_folders: false, + ..Default::default() + }; + + let fe1 = create_random_file_entry(vec![1, 1, 1, 1, 1, 1, 1, 0b00001], "abc.txt"); + let fe2 = create_random_file_entry(vec![1, 1, 1, 1, 1, 1, 1, 0b00100], "bcd.txt"); + let fe3 = create_random_file_entry(vec![1, 1, 1, 1, 1, 1, 1, 0b10000], "rrd.txt"); + + similar_images.image_hashes.insert(fe1.hash.clone(), vec![fe1]); + similar_images.image_hashes.insert(fe2.hash.clone(), vec![fe2]); + similar_images.image_hashes.insert(fe3.hash.clone(), vec![fe3]); + + similar_images.find_similar_hashes(None, None); + let res = similar_images.get_similar_images(); + // dbg!(&res); + assert!(res.is_empty()); + } + } + + #[test] + fn test_simple_normal_union_of_similarity() { + for _ in 0..100 { + let mut similar_images = SimilarImages { + similarity: 4, + use_reference_folders: false, + ..Default::default() + }; + + let fe1 = create_random_file_entry(vec![1, 1, 1, 1, 1, 1, 1, 0b0000_0001], "abc.txt"); + let fe2 = create_random_file_entry(vec![1, 1, 1, 1, 1, 1, 1, 0b0000_1111], "bcd.txt"); + let fe3 = create_random_file_entry(vec![1, 1, 1, 1, 1, 1, 1, 0b0111_1111], "rrd.txt"); + + similar_images.image_hashes.insert(fe1.hash.clone(), vec![fe1]); + similar_images.image_hashes.insert(fe2.hash.clone(), vec![fe2]); + similar_images.image_hashes.insert(fe3.hash.clone(), vec![fe3]); + + similar_images.find_similar_hashes(None, None); + let res = similar_images.get_similar_images(); + assert_eq!(res.len(), 1); + let mut path = res[0].iter().map(|e| e.path.to_string_lossy().to_string()).collect::>(); + path.sort(); + if res[0].len() == 3 { + assert_eq!(path, vec!["abc.txt".to_string(), "bcd.txt".to_string(), "rrd.txt".to_string()]); + } else if res[0].len() == 2 { + assert!(path == vec!["abc.txt".to_string(), "bcd.txt".to_string()] || path == vec!["bcd.txt".to_string(), "rrd.txt".to_string()]); + } else { + panic!("Invalid number of items"); + } + } + } + + #[test] + fn test_tolerance() { + // This test not really tests anything, but shows that current hamming distance works + // in bits instead of bytes + // I tried to make it work in bytes, but it was terrible, so Hamming should be really Ok + + let fe1 = vec![1, 1, 1, 1, 1, 1, 1, 1]; + let fe2 = vec![1, 1, 1, 1, 1, 1, 1, 2]; + let mut bktree = BKTree::new(Hamming); + bktree.add(fe1); + let (similarity, _hash) = bktree.find(&fe2, 100).next().unwrap(); + assert_eq!(similarity, 2); + + let fe1 = vec![1, 1, 1, 1, 1, 1, 1, 1]; + let fe2 = vec![1, 1, 1, 1, 1, 1, 1, 3]; + let mut bktree = BKTree::new(Hamming); + bktree.add(fe1); + let (similarity, _hash) = bktree.find(&fe2, 100).next().unwrap(); + assert_eq!(similarity, 1); + } + + fn create_random_file_entry(hash: Vec, name: &str) -> FileEntry { + FileEntry { + path: PathBuf::from(name.to_string()), + size: 0, + dimensions: String::new(), + modified_date: 0, + hash, + similarity: 0, + } + } +} diff --git a/czkawka_gui/Cargo.toml b/czkawka_gui/Cargo.toml index 93c6580..ae6e8e1 100644 --- a/czkawka_gui/Cargo.toml +++ b/czkawka_gui/Cargo.toml @@ -10,11 +10,11 @@ homepage = "https://github.com/qarmin/czkawka" repository = "https://github.com/qarmin/czkawka" [dependencies] -gdk4 = "0.6.3" -glib = "0.17.9" +gdk4 = "0.6" +glib = "0.17" humansize = "2.1" -chrono = "0.4.24" +chrono = "0.4.26" # Used for sending stop signal across threads crossbeam-channel = "0.5.8" @@ -35,19 +35,19 @@ image = "0.24" regex = "1.8" # To get image_hasher types -image_hasher = "1.1" +image_hasher = "1.2" # Move files to trash trash = "3.0" -# For moving files(why std::fs doesn't have such features) +# For moving files(why std::fs doesn't have such features?) fs_extra = "1.3" # Language i18n-embed = { version = "0.13", features = ["fluent-system", "desktop-requester"] } i18n-embed-fl = "0.6" -rust-embed = "6.6" -once_cell = "1.17" +rust-embed = "6.7" +once_cell = "1.18" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3.9", features = ["combaseapi", "objbase", "shobjidl_core", "windef", "winerror", "wtypesbase", "winuser"] } diff --git a/czkawka_gui/src/compute_results.rs b/czkawka_gui/src/compute_results.rs index f406225..e75321d 100644 --- a/czkawka_gui/src/compute_results.rs +++ b/czkawka_gui/src/compute_results.rs @@ -775,7 +775,18 @@ fn computer_similar_images( // Header let (directory, file) = split_path(&base_file_entry.path); - similar_images_add_to_list_store(&list_store, &file, &directory, 0, 0, "", 0, 0, true, true); + similar_images_add_to_list_store( + &list_store, + &file, + &directory, + base_file_entry.size, + base_file_entry.modified_date, + &base_file_entry.dimensions, + 0, + hash_size, + true, + true, + ); for file_entry in &vec_file_entry { let (directory, file) = split_path(&file_entry.path); similar_images_add_to_list_store( @@ -1396,15 +1407,20 @@ fn similar_images_add_to_list_store( let string_date; let similarity_string; let color = if is_header { HEADER_ROW_COLOR } else { MAIN_ROW_COLOR }; + + if is_header { + similarity_string = String::new(); + } else { + similarity_string = similar_images::get_string_from_similarity(&similarity, hash_size); + }; + if is_header && !is_reference_folder { size_str = String::new(); string_date = String::new(); - similarity_string = String::new(); } else { size_str = format_size(size, BINARY); string_date = NaiveDateTime::from_timestamp_opt(modified_date as i64, 0).unwrap().to_string(); - similarity_string = similar_images::get_string_from_similarity(&similarity, hash_size); - }; + } let values: [(u32, &dyn ToValue); COLUMNS_NUMBER] = [ (ColumnsSimilarImages::ActivatableSelectButton as u32, &(!is_header)), diff --git a/czkawka_gui/src/connect_things/connect_popovers_select.rs b/czkawka_gui/src/connect_things/connect_popovers_select.rs index 280bd08..4168180 100644 --- a/czkawka_gui/src/connect_things/connect_popovers_select.rs +++ b/czkawka_gui/src/connect_things/connect_popovers_select.rs @@ -311,7 +311,6 @@ fn popover_custom_select_unselect( { let check_button_path = check_button_path.clone(); let check_button_name = check_button_name.clone(); - let check_button_rust_regex = check_button_rust_regex.clone(); let entry_path = entry_path.clone(); let entry_name = entry_name.clone(); let entry_rust_regex = entry_rust_regex.clone();