├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── linux.yml │ ├── mac.yml │ ├── quality.yml │ └── windows.yml ├── .gitignore ├── .mailmap ├── .rustfmt.toml ├── Cargo.lock ├── Cargo.toml ├── Changelog.md ├── LICENSE_CC_BY_4_ICONS ├── README.md ├── ci_tester ├── Cargo.toml └── src │ └── main.rs ├── clippy.toml ├── czkawka_cli ├── Cargo.toml ├── LICENSE_MIT ├── README.md ├── data └── src │ ├── commands.rs │ ├── main.rs │ └── progress.rs ├── czkawka_core ├── Cargo.toml ├── LICENSE_MIT ├── README.md ├── benches │ └── hash_calculation_benchmark.rs ├── build.rs ├── data ├── i18n.toml ├── i18n │ ├── ar │ │ └── czkawka_core.ftl │ ├── bg │ │ └── czkawka_core.ftl │ ├── cs │ │ └── czkawka_core.ftl │ ├── de │ │ └── czkawka_core.ftl │ ├── el │ │ └── czkawka_core.ftl │ ├── en │ │ └── czkawka_core.ftl │ ├── es-ES │ │ └── czkawka_core.ftl │ ├── fr │ │ └── czkawka_core.ftl │ ├── it │ │ └── czkawka_core.ftl │ ├── ja │ │ └── czkawka_core.ftl │ ├── ko │ │ └── czkawka_core.ftl │ ├── nl │ │ └── czkawka_core.ftl │ ├── no │ │ └── czkawka_core.ftl │ ├── pl │ │ └── czkawka_core.ftl │ ├── pt-BR │ │ └── czkawka_core.ftl │ ├── pt-PT │ │ └── czkawka_core.ftl │ ├── ro │ │ └── czkawka_core.ftl │ ├── ru │ │ └── czkawka_core.ftl │ ├── sv-SE │ │ └── czkawka_core.ftl │ ├── tr │ │ └── czkawka_core.ftl │ ├── uk │ │ └── czkawka_core.ftl │ ├── zh-CN │ │ └── czkawka_core.ftl │ └── zh-TW │ │ └── czkawka_core.ftl └── src │ ├── common.rs │ ├── common_cache.rs │ ├── common_dir_traversal.rs │ ├── common_directory.rs │ ├── common_extensions.rs │ ├── common_image.rs │ ├── common_items.rs │ ├── common_messages.rs │ ├── common_tool.rs │ ├── common_traits.rs │ ├── lib.rs │ ├── localizer_core.rs │ ├── progress_data.rs │ └── tools │ ├── bad_extensions.rs │ ├── big_file.rs │ ├── broken_files.rs │ ├── duplicate.rs │ ├── empty_files.rs │ ├── empty_folder.rs │ ├── invalid_symlinks.rs │ ├── mod.rs │ ├── same_music.rs │ ├── similar_images.rs │ ├── similar_videos.rs │ └── temporary.rs ├── czkawka_gui ├── Cargo.toml ├── LICENSE_CC_BY_4_ICONS ├── LICENSE_MIT_APP_CODE ├── LICENSE_MIT_WINDOWS_THEME ├── README.md ├── data ├── i18n.toml ├── i18n │ ├── ar │ │ └── czkawka_gui.ftl │ ├── bg │ │ └── czkawka_gui.ftl │ ├── cs │ │ └── czkawka_gui.ftl │ ├── de │ │ └── czkawka_gui.ftl │ ├── el │ │ └── czkawka_gui.ftl │ ├── en │ │ └── czkawka_gui.ftl │ ├── es-ES │ │ └── czkawka_gui.ftl │ ├── fr │ │ └── czkawka_gui.ftl │ ├── it │ │ └── czkawka_gui.ftl │ ├── ja │ │ └── czkawka_gui.ftl │ ├── ko │ │ └── czkawka_gui.ftl │ ├── nl │ │ └── czkawka_gui.ftl │ ├── no │ │ └── czkawka_gui.ftl │ ├── pl │ │ └── czkawka_gui.ftl │ ├── pt-BR │ │ └── czkawka_gui.ftl │ ├── pt-PT │ │ └── czkawka_gui.ftl │ ├── ro │ │ └── czkawka_gui.ftl │ ├── ru │ │ └── czkawka_gui.ftl │ ├── sv-SE │ │ └── czkawka_gui.ftl │ ├── tr │ │ └── czkawka_gui.ftl │ ├── uk │ │ └── czkawka_gui.ftl │ ├── zh-CN │ │ └── czkawka_gui.ftl │ └── zh-TW │ │ └── czkawka_gui.ftl ├── icons │ ├── czk_add.svg │ ├── czk_compare.svg │ ├── czk_delete.svg │ ├── czk_hardlink.svg │ ├── czk_hide_down.svg │ ├── czk_hide_up.svg │ ├── czk_info.svg │ ├── czk_left.svg │ ├── czk_manual_add.svg │ ├── czk_move.svg │ ├── czk_right.svg │ ├── czk_save.svg │ ├── czk_search.svg │ ├── czk_select.svg │ ├── czk_settings.svg │ ├── czk_sort.svg │ ├── czk_stop.svg │ ├── czk_symlink.svg │ ├── czk_trash.svg │ └── icon_about.png ├── src │ ├── compute_results.rs │ ├── connect_things │ │ ├── connect_about_buttons.rs │ │ ├── connect_button_compare.rs │ │ ├── connect_button_delete.rs │ │ ├── connect_button_hardlink.rs │ │ ├── connect_button_move.rs │ │ ├── connect_button_save.rs │ │ ├── connect_button_search.rs │ │ ├── connect_button_select.rs │ │ ├── connect_button_sort.rs │ │ ├── connect_button_stop.rs │ │ ├── connect_change_language.rs │ │ ├── connect_duplicate_buttons.rs │ │ ├── connect_header_buttons.rs │ │ ├── connect_notebook_tabs.rs │ │ ├── connect_popovers_select.rs │ │ ├── connect_popovers_sort.rs │ │ ├── connect_progress_window.rs │ │ ├── connect_same_music_mode_changed.rs │ │ ├── connect_selection_of_directories.rs │ │ ├── connect_settings.rs │ │ ├── connect_show_hide_ui.rs │ │ ├── connect_similar_image_size_change.rs │ │ └── mod.rs │ ├── create_tree_view.rs │ ├── gui_structs │ │ ├── gui_about.rs │ │ ├── gui_bottom_buttons.rs │ │ ├── gui_compare_images.rs │ │ ├── gui_data.rs │ │ ├── gui_header.rs │ │ ├── gui_main_notebook.rs │ │ ├── gui_popovers_select.rs │ │ ├── gui_popovers_sort.rs │ │ ├── gui_progress_dialog.rs │ │ ├── gui_settings.rs │ │ ├── gui_upper_notebook.rs │ │ └── mod.rs │ ├── help_combo_box.rs │ ├── help_functions.rs │ ├── initialize_gui.rs │ ├── language_functions.rs │ ├── localizer_gui.rs │ ├── main.rs │ ├── notebook_enums.rs │ ├── notebook_info.rs │ ├── opening_selecting_records.rs │ ├── saving_loading.rs │ ├── taskbar_progress.rs │ ├── taskbar_progress_dummy.rs │ ├── taskbar_progress_win.rs │ └── tests.rs └── ui │ ├── about_dialog.ui │ ├── compare_images.ui │ ├── czkawka.cmb │ ├── main_window.ui │ ├── popover_right_click.ui │ ├── popover_select.ui │ ├── popover_sort.ui │ ├── progress.ui │ └── settings.ui ├── data ├── com.github.qarmin.czkawka.desktop ├── com.github.qarmin.czkawka.metainfo.xml └── icons │ ├── com.github.qarmin.czkawka-symbolic.svg │ ├── com.github.qarmin.czkawka.Devel.svg │ └── com.github.qarmin.czkawka.svg ├── instructions ├── Instruction.md └── Translations.md ├── justfile ├── krokiet ├── .clippy.toml ├── Cargo.toml ├── LICENSE_CC_BY_4_ICONS ├── LICENSE_GPL_APP ├── LICENSE_MIT_CODE ├── README.md ├── build.rs ├── i18n.toml ├── i18n │ ├── ar │ │ └── krokiet.ftl │ ├── bg │ │ └── krokiet.ftl │ ├── cs │ │ └── krokiet.ftl │ ├── de │ │ └── krokiet.ftl │ ├── el │ │ └── krokiet.ftl │ ├── en │ │ └── krokiet.ftl │ ├── es-ES │ │ └── krokiet.ftl │ ├── fr │ │ └── krokiet.ftl │ ├── it │ │ └── krokiet.ftl │ ├── ja │ │ └── krokiet.ftl │ ├── ko │ │ └── krokiet.ftl │ ├── nl │ │ └── krokiet.ftl │ ├── no │ │ └── krokiet.ftl │ ├── pl │ │ └── krokiet.ftl │ ├── pt-BR │ │ └── krokiet.ftl │ ├── pt-PT │ │ └── krokiet.ftl │ ├── ro │ │ └── krokiet.ftl │ ├── ru │ │ └── krokiet.ftl │ ├── sv-SE │ │ └── krokiet.ftl │ ├── tr │ │ └── krokiet.ftl │ ├── uk │ │ └── krokiet.ftl │ ├── zh-CN │ │ └── krokiet.ftl │ └── zh-TW │ │ └── krokiet.ftl ├── icons │ ├── krokiet_add.svg │ ├── krokiet_delete.svg │ ├── krokiet_dir.svg │ ├── krokiet_info.svg │ ├── krokiet_logo.png │ ├── krokiet_logo_small.png │ ├── krokiet_manual_add.svg │ ├── krokiet_move.svg │ ├── krokiet_remove.svg │ ├── krokiet_rename.svg │ ├── krokiet_save.svg │ ├── krokiet_search.svg │ ├── krokiet_select.svg │ ├── krokiet_settings.svg │ ├── krokiet_sort.svg │ ├── krokiet_stop.svg │ └── krokiet_subsettings.svg ├── src │ ├── common.rs │ ├── connect_delete.rs │ ├── connect_directories_changes.rs │ ├── connect_move.rs │ ├── connect_open.rs │ ├── connect_progress_receiver.rs │ ├── connect_rename.rs │ ├── connect_row_selection.rs │ ├── connect_save.rs │ ├── connect_scan.rs │ ├── connect_select.rs │ ├── connect_show_preview.rs │ ├── connect_sort.rs │ ├── connect_stop.rs │ ├── connect_translation.rs │ ├── localizer_krokiet.rs │ ├── main.rs │ ├── model_operations.rs │ ├── set_initial_gui_info.rs │ ├── settings.rs │ ├── shared_models.rs │ └── test_common.rs └── ui │ ├── about.slint │ ├── action_buttons.slint │ ├── bottom_panel.slint │ ├── callabler.slint │ ├── color_palette.slint │ ├── common.slint │ ├── gui_state.slint │ ├── included_directories.slint │ ├── left_side_panel.slint │ ├── main_lists.slint │ ├── main_window.slint │ ├── popup_base.slint │ ├── popup_centered_text.slint │ ├── popup_delete.slint │ ├── popup_move_folders.slint │ ├── popup_new_directories.slint │ ├── popup_rename_files.slint │ ├── popup_save.slint │ ├── popup_select_results.slint │ ├── popup_sort.slint │ ├── preview.slint │ ├── progress.slint │ ├── selectable_tree_view.slint │ ├── settings.slint │ ├── settings_list.slint │ ├── tool_settings.slint │ └── translations.slint └── misc ├── .idea ├── czkawka.iml ├── modules.xml ├── vcs.xml └── workspace.xml ├── cargo ├── PublishCore.sh └── PublishOther.sh ├── czkawka-appimage-recipe.yml ├── delete_unused_krokiet_slint_imports.py ├── docker └── Dockerfile ├── flathub.sh ├── generate_krokiet_translations.py ├── test_image_perf ├── Cargo.toml └── src │ └── main.rs └── test_read_perf ├── Cargo.toml └── src └── main.rs /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: qarmin # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve app 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Bug Description** 11 | 12 | **Steps to reproduce:** 13 | 14 | 15 | **Terminal output** (optional): 16 | 17 | ``` 18 | 23 | 24 |
25 | Debug log 26 | 27 | # UNCOMMENT DETAILS AND PUT LOGS HERE 28 | 29 |
30 | ``` 31 | 32 | **System** 33 | 34 | 35 | 36 | 37 | 38 | - Czkawka/Krokiet version: 39 | - OS version: 40 | - Installation method: 41 | 42 | 43 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Feature Description** 11 | ... 12 | -------------------------------------------------------------------------------- /.github/workflows/quality.yml: -------------------------------------------------------------------------------- 1 | name: Quality 2 | on: 3 | push: 4 | pull_request: 5 | schedule: 6 | - cron: '0 0 * * 2' 7 | 8 | env: 9 | CARGO_TERM_COLOR: always 10 | 11 | jobs: 12 | quality: 13 | runs-on: ubuntu-24.04 14 | steps: 15 | - uses: actions/checkout@v4 16 | 17 | - name: Install Gtk 4 18 | run: sudo apt update || true; sudo apt install -y libgtk-4-dev libraw-dev libheif-dev libavif-dev libdav1d-dev -y 19 | 20 | - name: Setup rust version 21 | run: | 22 | rustup default 1.85.0 23 | rustup component add rustfmt 24 | rustup component add clippy 25 | 26 | - name: Disable optimizations 27 | run: | 28 | sed -i 's/^\(\[profile\.dev\.package.*\)/#\1/' Cargo.toml 29 | sed -i 's|^opt-level = 3 # OPT PACKAGES|#opt-level = 3 # OPT PACKAGES|' Cargo.toml 30 | 31 | - name: Check the format 32 | run: cargo fmt --all -- --check 33 | 34 | - name: Run clippy 35 | run: cargo clippy --all-targets --all-features -- -D warnings 36 | 37 | - name: Run clippy 38 | run: cargo clippy -- -D warnings 39 | 40 | - name: Check tools 41 | run: | 42 | cd misc/test_image_perf 43 | cargo check 44 | cd ../../ 45 | 46 | cd misc/test_read_perf 47 | cargo check 48 | cd ../../ 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .idea/ 3 | *.iml 4 | *~ 5 | *# 6 | results*.txt 7 | TestSuite* 8 | *.snap 9 | flatpak/ 10 | *.zip 11 | *.zst 12 | *.profraw 13 | *.profdata 14 | /lcov_report* 15 | /report 16 | ci_tester/target 17 | ci_tester/Cargo.lock 18 | krokiet/Cargo.lock 19 | krokiet/target 20 | *.json 21 | *.mm_profdata 22 | perf.data 23 | perf.data.old 24 | krokiet/ui/test.slint 25 | *.html 26 | misc/*/*.lock 27 | misc/*/target/ 28 | misc/*/.idea 29 | benchmarks -------------------------------------------------------------------------------- /.mailmap: -------------------------------------------------------------------------------- 1 | TheEvilSkeleton Proprietary Chrome-chan 2 | Rafał Mikrut <41945903+qarmin@users.noreply.github.com> 3 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | newline_style = "Unix" 2 | max_width = 180 3 | 4 | # Enable only with nightly channel via - cargo +nightly fmt 5 | imports_granularity = "Module" 6 | group_imports = "StdExternalCrate" -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "czkawka_core", 4 | "czkawka_cli", 5 | "czkawka_gui", 6 | "krokiet" 7 | ] 8 | exclude = [ 9 | "misc/test_read_perf", 10 | "misc/test_image_perf", 11 | "ci_tester", 12 | ] 13 | resolver = "3" 14 | 15 | [profile.release] 16 | # panic = "unwind" in opposite to "abort", allows to catch panic!() 17 | # Since Czkawka parse different types of files with few libraries, it is possible 18 | # that some files will cause crash, so at this moment I don't recommend to use "abort" 19 | # until you are ready to occasional crashes 20 | panic = "unwind" 21 | 22 | # Should find more panics, that now are hidden from user - in long term it should decrease bugs in app 23 | # There is one big disadvantage - in case of overflow/underflow entire app crashes and not everywhere I catch this panic so app aborts 24 | # So feel free to disable it, if you want 25 | overflow-checks = true 26 | 27 | # LTO setting is disabled by default, because release mode is usually needed to develop app and compilation with LTO would take a lot of time 28 | # But it is used to optimize release builds(and probably also in CI, where time is not so important as in local development) 29 | #lto = "thin" 30 | 31 | # Optimize all dependencies except application/workspaces, even in debug builds to get reasonable performance e.g. when opening images 32 | [profile.dev.package."*"] # OPT PACKAGES 33 | opt-level = 3 # OPT PACKAGES 34 | 35 | [profile.test] 36 | debug-assertions = true # Forces to crash when there is duplicated item in cli 37 | overflow-checks = true 38 | opt-level = 3 39 | 40 | # Unsafe profile, just to check, how fast and small app could be 41 | [profile.fastest] 42 | inherits = "release" 43 | panic = "abort" 44 | lto = "thin" 45 | strip = "symbols" 46 | codegen-units = 1 47 | opt-level = 3 48 | debug = false -------------------------------------------------------------------------------- /ci_tester/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ci_tester" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | 9 | [profile.release] 10 | debug-assertions = true 11 | overflow-checks = true 12 | 13 | [dependencies] 14 | state = "0.6.0" 15 | handsome_logger = "0.8.0" 16 | log = "0.4.20" -------------------------------------------------------------------------------- /clippy.toml: -------------------------------------------------------------------------------- 1 | allow-indexing-slicing-in-tests = true -------------------------------------------------------------------------------- /czkawka_cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "czkawka_cli" 3 | version = "9.0.0" 4 | authors = ["Rafał Mikrut "] 5 | edition = "2024" 6 | rust-version = "1.85.0" 7 | description = "CLI frontend of Czkawka" 8 | license = "MIT" 9 | homepage = "https://github.com/qarmin/czkawka" 10 | repository = "https://github.com/qarmin/czkawka" 11 | 12 | [dependencies] 13 | clap = { version = "4.5", features = ["derive"] } 14 | 15 | # For enum types 16 | image_hasher = "3.0" 17 | 18 | log = "0.4.22" 19 | czkawka_core = { path = "../czkawka_core", version = "9.0.0", features = [] } 20 | indicatif = "0.17" 21 | crossbeam-channel = { version = "0.5", features = [] } 22 | ctrlc = { version = "3.4", features = ["termination"] } 23 | humansize = "2.1" 24 | 25 | [features] 26 | default = ["fast_image_resize"] 27 | heif = ["czkawka_core/heif"] 28 | libraw = ["czkawka_core/libraw"] 29 | libavif = ["czkawka_core/libavif"] 30 | fast_image_resize = ["czkawka_core/fast_image_resize"] 31 | -------------------------------------------------------------------------------- /czkawka_cli/LICENSE_MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2025 Rafał Mikrut 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /czkawka_cli/README.md: -------------------------------------------------------------------------------- 1 | # Czkawka CLI 2 | 3 | CLI frontend, allows to use Czkawka from terminal. 4 | 5 | ## Requirements 6 | 7 | Precompiled binaries should work without any additional dependencies with Linux(Ubuntu 20.04+), Windows(10+) and macOS( 8 | 10.15+). 9 | 10 | If you decide to compile the app, you probably will be able to run it on even older versions of OS, like Ubuntu 16.04 or 11 | Windows 7. 12 | 13 | On linux it is even possible with eyra to avoid entirely libc and using fully static rust binary. 14 | 15 | If you want to use similar videos tool, you need to install ffmpeg(runtime dependency). 16 | If you want to use heif/libraw/libavif(build/runtime dependency) you need to install required packages(may require 17 | bigger os version than czkawka). 18 | 19 | - mac - `brew install ffmpeg libraw libheif libavif` - https://formulae.brew.sh/formula/ffmpeg 20 | - linux - `sudo apt install ffmpeg libraw-dev libheif-dev libavif-dev libdav1d-dev` 21 | - windows - `choco install ffmpeg` - or if not working, download from https://ffmpeg.org/download.html#build-windows and 22 | unpack to location with `czkawka_cli.exe`, heif and libraw are not supported on windows 23 | 24 | ## Compilation 25 | 26 | For compilation, you need to have installed Rust via rustup - https://rustup.rs/ and compile it e.g. via 27 | 28 | ```shell 29 | cargo run --release --bin czkawka_cli 30 | ``` 31 | 32 | you can enable additional features via 33 | 34 | ```shell 35 | cargo run --release --bin czkawka_cli --features "heif,libraw,libavif" 36 | ``` 37 | 38 | on linux to build fully static binary with eyra you need to use (this is only for crazy people, so just use command 39 | above if you don't know what you are doing) 40 | 41 | ```shell 42 | rustup default nightly-2025-01-01 # or any newer nightly that works fine with eyra 43 | cd czkawka_cli 44 | cargo add eyra --rename=std 45 | echo 'fn main() { println!("cargo:rustc-link-arg=-nostartfiles"); }' > build.rs 46 | cd .. 47 | cargo build --release --bin czkawka_cli 48 | ``` 49 | 50 | ## LICENSE 51 | 52 | MIT -------------------------------------------------------------------------------- /czkawka_cli/data: -------------------------------------------------------------------------------- 1 | ../data/ -------------------------------------------------------------------------------- /czkawka_core/LICENSE_MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2025 Rafał Mikrut 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /czkawka_core/README.md: -------------------------------------------------------------------------------- 1 | # Czkawka Core 2 | 3 | Core of Czkawka GUI/CLI and Krokiet projects. 4 | -------------------------------------------------------------------------------- /czkawka_core/benches/hash_calculation_benchmark.rs: -------------------------------------------------------------------------------- 1 | use std::env::temp_dir; 2 | use std::fs::File; 3 | use std::io::Write; 4 | use std::path::PathBuf; 5 | use std::sync::Arc; 6 | 7 | use criterion::{Criterion, black_box, criterion_group, criterion_main}; 8 | use czkawka_core::tools::duplicate::{DuplicateEntry, HashType, hash_calculation}; 9 | 10 | fn setup_test_file(size: u64) -> PathBuf { 11 | let mut path = temp_dir(); 12 | path.push("test_file"); 13 | let mut file = File::create(&path).expect("Failed to create test file"); 14 | file.write_all(&vec![0u8; size as usize]).expect("Failed to write to test file"); 15 | path 16 | } 17 | 18 | fn get_file_entry(size: u64) -> DuplicateEntry { 19 | let path = setup_test_file(size); 20 | DuplicateEntry { 21 | path, 22 | modified_date: 0, 23 | size, 24 | hash: String::new(), 25 | } 26 | } 27 | 28 | fn benchmark_hash_calculation_vec(c: &mut Criterion) { 29 | let file_entry = get_file_entry(FILE_SIZE); 30 | let function_name = format!("hash_calculation_vec_file_{FILE_SIZE}_buffer_{BUFFER_SIZE}"); 31 | 32 | c.bench_function(&function_name, |b| { 33 | b.iter(|| { 34 | let mut buffer = vec![0u8; BUFFER_SIZE]; 35 | hash_calculation(black_box(&mut buffer), black_box(&file_entry), black_box(HashType::Blake3), &Arc::default(), None).expect("Failed to calculate hash"); 36 | }); 37 | }); 38 | } 39 | 40 | fn benchmark_hash_calculation_arr(c: &mut Criterion) { 41 | let file_entry = get_file_entry(FILE_SIZE); 42 | let function_name = format!("hash_calculation_arr_file_{FILE_SIZE}_buffer_{BUFFER_SIZE}"); 43 | 44 | c.bench_function(&function_name, |b| { 45 | b.iter(|| { 46 | let mut buffer = [0u8; BUFFER_SIZE]; 47 | hash_calculation(black_box(&mut buffer), black_box(&file_entry), black_box(HashType::Blake3), &Arc::default(), None).expect("Failed to calculate hash"); 48 | }); 49 | }); 50 | } 51 | 52 | criterion_group!(benches, 53 | benchmark_hash_calculation_vec<{16 * 1024 * 1024}, {16 * 1024}>, 54 | benchmark_hash_calculation_vec<{16 * 1024 * 1024}, {1024 * 1024}>, 55 | benchmark_hash_calculation_arr<{16 * 1024 * 1024}, {16 * 1024}>, 56 | benchmark_hash_calculation_arr<{16 * 1024 * 1024}, {1024 * 1024}>, 57 | ); 58 | criterion_main!(benches); 59 | -------------------------------------------------------------------------------- /czkawka_core/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let rust_version = match rustc_version::version_meta() { 3 | Ok(meta) => { 4 | let rust_v = meta.semver.to_string(); 5 | let rust_date = meta.commit_date.unwrap_or_default(); 6 | format!("{rust_v} ({rust_date})") 7 | } 8 | Err(_) => "".to_string(), 9 | }; 10 | println!("cargo:rustc-env=RUST_VERSION_INTERNAL={rust_version}"); 11 | 12 | if let Ok(encoded) = std::env::var("CARGO_ENCODED_RUSTFLAGS") { 13 | println!("cargo:rustc-env=UUSED_RUSTFLAGS={encoded}"); 14 | } 15 | 16 | let using_cranelift = 17 | std::env::var("CARGO_PROFILE_RELEASE_CODEGEN_UNITS") == Ok("1".to_string()) || std::env::var("CARGO_PROFILE_DEV_CODEGEN_BACKEND") == Ok("cranelift".to_string()); 18 | 19 | if using_cranelift { 20 | println!("cargo:rustc-env=USING_CRANELIFT=1"); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /czkawka_core/data: -------------------------------------------------------------------------------- 1 | ../data/ -------------------------------------------------------------------------------- /czkawka_core/i18n.toml: -------------------------------------------------------------------------------- 1 | # (Required) The language identifier of the language used in the 2 | # source code for gettext system, and the primary fallback language 3 | # (for which all strings must be present) when using the fluent 4 | # system. 5 | fallback_language = "en" 6 | 7 | # Use the fluent localization system. 8 | [fluent] 9 | # (Required) The path to the assets directory. 10 | # The paths inside the assets directory should be structured like so: 11 | # `assets_dir/{language}/{domain}.ftl` 12 | assets_dir = "i18n" 13 | 14 | -------------------------------------------------------------------------------- /czkawka_core/i18n/ar/czkawka_core.ftl: -------------------------------------------------------------------------------- 1 | # Core 2 | core_similarity_original = الأصل 3 | core_similarity_very_high = عالية جدا 4 | core_similarity_high = مرتفع 5 | core_similarity_medium = متوسط 6 | core_similarity_small = صغير 7 | core_similarity_very_small = صغير جدا 8 | core_similarity_minimal = الحد الأدنى 9 | core_cannot_open_dir = لا يمكن فتح dir { $dir }، السبب { $reason } 10 | core_cannot_read_entry_dir = لا يمكن قراءة الإدخال في dir { $dir }، السبب { $reason } 11 | core_cannot_read_metadata_dir = لا يمكن قراءة البيانات الوصفية في dir { $dir }، السبب { $reason } 12 | core_file_not_utf8_name = الملف { $name } ليس لديه اسم UTF-8 صالح (قد لا تظهر بعض الأحرف) 13 | core_file_modified_before_epoch = يبدو أن الملف { $name } قد تم تعديله قبل يونكس Epoch 14 | core_folder_modified_before_epoch = يبدو أن المجلد { $name } قد تم تعديله قبل يونكس Epoch 15 | core_file_no_modification_date = غير قادر على الحصول على تاريخ التعديل من الملف { $name }، السبب { $reason } 16 | core_folder_no_modification_date = غير قادر على الحصول على تاريخ التعديل من المجلد { $name }، السبب { $reason } 17 | core_missing_no_chosen_included_directory = يجب توفير دليل واحد على الأقل 18 | core_directory_wildcard_no_supported = الأدلة: البطاقات البرية في المسار غير مدعومة، تجاهل { $path } 19 | core_directory_must_exists = الأدلة: يجب أن يكون مسار المجلد المتوفر موجودا، تجاهل { $path } 20 | core_directory_must_be_directory = الأدلة: المسار المقدم يجب أن يشير إلى الدليل، تجاهل { $path } 21 | core_included_directory_zero_valid_directories = خطأ في الدليل المضمن: لا يوجد حتى مسار واحد صحيح للإدراج المطلوب 22 | core_excluded_directory_pointless_slash = الأدلة: استبعاد / لا معنى له، لأنه يعني أنه لن يتم مسح أي ملفات 23 | core_directory_overlap = الأدلة: جميع الدلائل للبحث عن التداخل مع الدلائل المستبعدة 24 | core_directory_unable_to_get_device_id = الأدلة: غير قادر على الحصول على معرف الجهاز من المجلد { $path } 25 | core_ffmpeg_not_found = لا يمكن العثور على التثبيت الصحيح لFFmpeg 26 | core_ffmpeg_not_found_windows = تأكد من أن ffmpeg.exe و ffprobe.exe متاحان في PATH أو يتم وضعهما مباشرة لنفس المجلد حيث التطبيق قابل للتنفيذ 27 | core_ffmpeg_missing_in_snap = مقاطع فيديو مشابهة لا تعمل حاليا مع السعادة، إذا كنت تريد المساعدة في النظر - { $url } 28 | core_saving_to_cache = تم الحفظ في الملف { $number } إدخالات ذاكرة التخزين المؤقت 29 | core_loading_from_cache = تحميل من ذاكرة التخزين المؤقت { $number } إدخالات 30 | -------------------------------------------------------------------------------- /czkawka_core/i18n/bg/czkawka_core.ftl: -------------------------------------------------------------------------------- 1 | # Core 2 | core_similarity_original = Оригинален 3 | core_similarity_very_high = Много висок 4 | core_similarity_high = Висок 5 | core_similarity_medium = Среден 6 | core_similarity_small = Малък 7 | core_similarity_very_small = Много малък 8 | core_similarity_minimal = Минимален 9 | core_cannot_open_dir = Не може да се отвори папка { $dir }, причината е { $reason } 10 | core_cannot_read_entry_dir = Не може да се прочете папка { $dir }, причината е { $reason } 11 | core_cannot_read_metadata_dir = Не могат да се прочетат мета-данните в папка { $dir }, причината е { $reason } 12 | core_file_not_utf8_name = Файлът { $name } няма валидно UTF-8 име (някои от символите може да не се визуализират) 13 | core_file_modified_before_epoch = Файлът { $name } изглежда да е променен преди Unix Epoc 14 | core_folder_modified_before_epoch = Папка { $name } изглежда да е променена преди Unix Epoc 15 | core_file_no_modification_date = Невъзможно е да се получи променената дата от файл { $name }, причината е { $reason } 16 | core_folder_no_modification_date = Невъзможно е да се извлече променената дата от файл { $name }, причината е { $reason } 17 | core_missing_no_chosen_included_directory = Трябва да се предостави поне една директория 18 | core_directory_wildcard_no_supported = Директории: Не се поддържат заместващи знаци в пътя, игнорирайки { $path } 19 | core_directory_must_exists = Директории: Предоставеният път до папката трябва да съществува, като се игнорира { $path } 20 | core_directory_must_be_directory = Директории: Предоставеният път трябва да сочи към директорията, като не се взема под внимание { $path } 21 | core_included_directory_zero_valid_directories = Включена директория ГРЕШКА: Не е намерен дори един правилен път към включената директория, която се изисква 22 | core_excluded_directory_pointless_slash = Директории: Изключването на / е безсмислено, защото означава, че няма да бъдат сканирани никакви файлове 23 | core_directory_overlap = Директории: Всички директории за търсене се припокриват с изключените директории 24 | core_directory_unable_to_get_device_id = Директории: Невъзможно е да се получи идентификатор на устройството от папка { $path } 25 | core_ffmpeg_not_found = Не мога да намеря правилната инсталация на FFmpeg 26 | core_ffmpeg_not_found_windows = Уверете се, че ffmpeg.exe и ffprobe.exe са налични в PATH или са поставени директно в същата папка, където е изпълнимото приложение 27 | core_ffmpeg_missing_in_snap = Подобни видеоклипове не работят в момента със snap, ако искате помощ, погледнете - { $url } 28 | core_saving_to_cache = Запазени във файл {$number } записи в кеша 29 | core_loading_from_cache = Заредени от кеш { $number } вписвания 30 | -------------------------------------------------------------------------------- /czkawka_core/i18n/cs/czkawka_core.ftl: -------------------------------------------------------------------------------- 1 | # Core 2 | core_similarity_original = Originál 3 | core_similarity_very_high = Velmi vysoká 4 | core_similarity_high = Vysoká 5 | core_similarity_medium = Střední 6 | core_similarity_small = Malá 7 | core_similarity_very_small = Velmi malá 8 | core_similarity_minimal = Minimální 9 | core_cannot_open_dir = Nelze otevřít adresář { $dir }, důvod { $reason } 10 | core_cannot_read_entry_dir = Nelze načíst záznam v adresáři { $dir }, důvod { $reason } 11 | core_cannot_read_metadata_dir = Nelze načíst metadata v adresáři { $dir }, důvod { $reason } 12 | core_file_not_utf8_name = Soubor { $name } nemá platný název UTF-8 (některé znaky nemusí být zobrazeny) 13 | core_file_modified_before_epoch = Soubor { $name } se zdá být upraven před unixovým Epochem (1.1.1970) 14 | core_folder_modified_before_epoch = Složka { $name } se zdá být upravena před unixovým Epochem (1.1.1970) 15 | core_file_no_modification_date = Nelze získat datum úpravy ze souboru { $name }, důvod { $reason } 16 | core_folder_no_modification_date = Nelze získat datum úpravy ze složky { $name }, důvod { $reason } 17 | core_missing_no_chosen_included_directory = Musí být uveden alespoň jeden adresář 18 | core_directory_wildcard_no_supported = Adresáře: Zástupné znaky v cestě nejsou podporovány, ignoruji { $path } 19 | core_directory_must_exists = Adresáře: Poskytnutá cesta ke složce musí existovat, ignoruji { $path } 20 | core_directory_must_be_directory = Adresáře: Poskytnutá cesta musí směřovat do adresáře, ignoruji { $path } 21 | core_included_directory_zero_valid_directories = CHYBA zahrnutí adresáře: Nenalezena ani jedna správná cesta k zahrnutí, která je vyžadována 22 | core_excluded_directory_pointless_slash = Adresáře: Vyloučení / je bezúčelné, protože to znamená, že žádné soubory nebudou naskenovány 23 | core_directory_overlap = Adresáře: Všechny adresáře pro vyhledávání se překrývají s vyloučením adresářů 24 | core_directory_unable_to_get_device_id = Adresáře: Nelze získat ID zařízení ze složky { $path } 25 | core_ffmpeg_not_found = Nelze najít správnou instalaci FFmpeg 26 | core_ffmpeg_not_found_windows = Ujistěte se, že ffmpeg.exe a ffprobe.exe jsou k dispozici v PATH nebo jsou umístěny přímo do stejné složky, kde lze spustit aplikaci 27 | core_ffmpeg_missing_in_snap = Podobná videa v současné době nefungují se snapem, pokud chcete nápovědu sledovat - { $url } 28 | core_saving_to_cache = Uloženo do souboru { $number } položek mezipaměti 29 | core_loading_from_cache = Načteno z { $number } položek keše 30 | -------------------------------------------------------------------------------- /czkawka_core/i18n/de/czkawka_core.ftl: -------------------------------------------------------------------------------- 1 | # Core 2 | core_similarity_original = Original 3 | core_similarity_very_high = Sehr Hoch 4 | core_similarity_high = Hoch 5 | core_similarity_medium = Mittel 6 | core_similarity_small = Klein 7 | core_similarity_very_small = Sehr klein 8 | core_similarity_minimal = Minimal 9 | core_cannot_open_dir = Verzeichnis { $dir } kann nicht geöffnet werden, Grund { $reason } 10 | core_cannot_read_entry_dir = Kann Eintrag in Verzeichnis { $dir } nicht lesen, Grund { $reason } 11 | core_cannot_read_metadata_dir = Metadaten können in Verzeichnis { $dir } nicht gelesen werden, Grund { $reason } 12 | core_file_not_utf8_name = Datei { $name } hat keinen gültigen UTF-8-Namen (einige Zeichen könnten nicht angezeigt werden) 13 | core_file_modified_before_epoch = Datei { $name } scheint vor dieser Unix-Epoche geändert worden zu sein 14 | core_folder_modified_before_epoch = Ordner { $name } scheint vor dieser Unix-Epoche geändert worden zu sein 15 | core_file_no_modification_date = Konnte das Änderungsdatum von Datei { $name } nicht abrufen, Grund { $reason } 16 | core_folder_no_modification_date = Konnte das Änderungsdatum aus dem Ordner { $name } nicht abrufen, Grund { $reason } 17 | core_missing_no_chosen_included_directory = Mindestens ein Verzeichnis muss angegeben werden 18 | core_directory_wildcard_no_supported = Verzeichnisse: Wildcards im Pfad werden nicht unterstützt, { $path } wird ignoriert 19 | core_directory_must_exists = Verzeichnisse: Der angegebene Ordnerpfad muss existieren, { $path } wird ignoriert 20 | core_directory_must_be_directory = Verzeichnisse: Der angegebene Pfad muss auf das Verzeichnis zeigen, { $path } wird ignoriert 21 | core_included_directory_zero_valid_directories = Einbezogenes Verzeichnis-FEHLER: Kein korrekter Pfad gefunden, welcher einbezogen werden soll, was erforderlich ist 22 | core_excluded_directory_pointless_slash = Verzeichnisse: / auszuschließen ist sinnlos, weil somit keine Dateien gescannt werden 23 | core_directory_overlap = Verzeichnisse: Alle zu durchsuchende Verzeichnisse überlappen mit den ausgeschlossenen Verzeichnissen 24 | core_directory_unable_to_get_device_id = Verzeichnisse: Geräte-ID kann nicht aus dem Ordner { $path } geholt werden 25 | core_ffmpeg_not_found = Keine richtige Installation von FFmpeg gefunden 26 | core_ffmpeg_not_found_windows = Stellen Sie sicher, dass ffmpeg.exe und ffprobe.exe in PATH verfügbar sind oder direkt in den gleichen Ordner gelegt werden, in dem die App ausführbar ist 27 | core_ffmpeg_missing_in_snap = Ähnliche Videos funktionieren derzeit nicht mit Snap, wenn du Hilfe möchtest, besuche - { $url } 28 | core_saving_to_cache = { $number } Cache-Einträge in der Datei gespeichert 29 | core_loading_from_cache = { $number } Einträge aus dem Cache geladen 30 | -------------------------------------------------------------------------------- /czkawka_core/i18n/el/czkawka_core.ftl: -------------------------------------------------------------------------------- 1 | # Core 2 | core_similarity_original = Αρχικό 3 | core_similarity_very_high = Πολύ Υψηλή 4 | core_similarity_high = Υψηλή 5 | core_similarity_medium = Μεσαίο 6 | core_similarity_small = Μικρό 7 | core_similarity_very_small = Πολύ Μικρό 8 | core_similarity_minimal = Ελάχιστα 9 | core_cannot_open_dir = Αδυναμία ανοίγματος dir { $dir }, λόγος { $reason } 10 | core_cannot_read_entry_dir = Αδυναμία ανάγνωσης καταχώρησης στον κατάλογο { $dir }, λόγος { $reason } 11 | core_cannot_read_metadata_dir = Αδύνατη η ανάγνωση μεταδεδομένων στον κατάλογο { $dir }, λόγος { $reason } 12 | core_file_not_utf8_name = Το αρχείο { $name } δεν έχει ένα έγκυρο όνομα UTF-8 (ορισμένοι χαρακτήρες μπορεί να μην εμφανίζονται) 13 | core_file_modified_before_epoch = Το { $name } φαίνεται να τροποποιείται πριν το Unix Epoch 14 | core_folder_modified_before_epoch = Ο φάκελος { $name } φαίνεται να τροποποιείται πριν το Unix Epoch 15 | core_file_no_modification_date = Δεν είναι δυνατή η λήψη ημερομηνίας τροποποίησης από το αρχείο { $name }, λόγος { $reason } 16 | core_folder_no_modification_date = Δεν είναι δυνατή η λήψη ημερομηνίας τροποποίησης από το φάκελο { $name }, λόγος { $reason } 17 | core_missing_no_chosen_included_directory = Πρέπει να παρέχεται τουλάχιστον ένας κατάλογος 18 | core_directory_wildcard_no_supported = Κατάλογοι: Δεν υποστηρίζονται μπαλαντέρ στο μονοπάτι, αγνοώντας { $path } 19 | core_directory_must_exists = Κατάλογοι: Η παρεχόμενη διαδρομή φακέλου πρέπει να υπάρχει, αγνοώντας { $path } 20 | core_directory_must_be_directory = Κατάλογοι: Παρέχεται διαδρομή πρέπει να δείχνει στον κατάλογο, αγνοώντας { $path } 21 | core_included_directory_zero_valid_directories = Συμπεριλαμβανόμενος κατάλογος ΣΦΑΛΜΑ: Δεν βρέθηκε ούτε μια σωστή διαδρομή για να συμπεριληφθεί η οποία απαιτείται 22 | core_excluded_directory_pointless_slash = Κατάλογοι: Εξαιρούνται / είναι άσκοπες, επειδή σημαίνει ότι δεν θα σαρωθούν αρχεία 23 | core_directory_overlap = Κατάλογοι: Όλοι οι κατάλογοι για αναζήτηση επικαλύψεων με αποκλεισμένους καταλόγους 24 | core_directory_unable_to_get_device_id = Κατάλογοι: Αδυναμία λήψης id συσκευής από το φάκελο { $path } 25 | core_ffmpeg_not_found = Αδυναμία εύρεσης σωστής εγκατάστασης του FFmpeg 26 | core_ffmpeg_not_found_windows = Να είστε βέβαιος ότι ffmpeg.exe και ffprobe.exe είναι διαθέσιμα σε PATH ή τίθενται απευθείας στον ίδιο φάκελο όπου είναι εκτελέσιμο app 27 | core_ffmpeg_missing_in_snap = Παρόμοια βίντεο δεν λειτουργούν αυτή τη στιγμή με συμπληρωματικό πρόγραμμα, αν θέλετε να δείτε βοήθεια - { $url } 28 | core_saving_to_cache = Αποθηκεύτηκε στο αρχείο καταχωρήσεις { $number } cache 29 | core_loading_from_cache = Φορτώθηκε από καταχωρήσεις της λανθάνουσας μνήμης { $number } 30 | -------------------------------------------------------------------------------- /czkawka_core/i18n/en/czkawka_core.ftl: -------------------------------------------------------------------------------- 1 | # Core 2 | core_similarity_original = Original 3 | core_similarity_very_high = Very High 4 | core_similarity_high = High 5 | core_similarity_medium = Medium 6 | core_similarity_small = Small 7 | core_similarity_very_small = Very Small 8 | core_similarity_minimal = Minimal 9 | 10 | core_cannot_open_dir = Cannot open dir {$dir}, reason {$reason} 11 | core_cannot_read_entry_dir = Cannot read entry in dir {$dir}, reason {$reason} 12 | core_cannot_read_metadata_dir = Cannot read metadata in dir {$dir}, reason {$reason} 13 | core_file_not_utf8_name = File {$name} does not have a valid UTF-8 name (some characters may not be shown) 14 | core_file_modified_before_epoch = File {$name} seems to be modified before Unix Epoch 15 | core_folder_modified_before_epoch = Folder {$name} seems to be modified before Unix Epoch 16 | core_file_no_modification_date = Unable to get modification date from file {$name}, reason {$reason} 17 | core_folder_no_modification_date = Unable to get modification date from folder {$name}, reason {$reason} 18 | 19 | core_missing_no_chosen_included_directory = At least one directory must be provided 20 | core_directory_wildcard_no_supported = Directories: Wildcards in path are not supported, ignoring { $path } 21 | core_directory_must_exists = Directories: Provided folder path must exist, ignoring { $path } 22 | core_directory_must_be_directory = Directories: Provided path must point at the directory, ignoring { $path } 23 | core_included_directory_zero_valid_directories = Included Directory ERROR: Not found even one correct path to included which is required 24 | core_excluded_directory_pointless_slash = Directories: Excluding / is pointless, because it means that no files will be scanned 25 | core_directory_overlap = Directories: All directories to search overlaps with excluded directories 26 | core_directory_unable_to_get_device_id = Directories: Unable to get device id from folder { $path } 27 | 28 | core_ffmpeg_not_found = Cannot find proper installation of FFmpeg 29 | core_ffmpeg_not_found_windows = Be sure that ffmpeg.exe and ffprobe.exe are available in PATH or are put directly to same folder where is app executable 30 | 31 | core_saving_to_cache = Saved to file { $number } cache entries 32 | core_loading_from_cache = Loaded from cache { $number } entries 33 | -------------------------------------------------------------------------------- /czkawka_core/i18n/es-ES/czkawka_core.ftl: -------------------------------------------------------------------------------- 1 | # Core 2 | core_similarity_original = Original 3 | core_similarity_very_high = Muy alta 4 | core_similarity_high = Alta 5 | core_similarity_medium = Medio 6 | core_similarity_small = Pequeño 7 | core_similarity_very_small = Muy pequeño 8 | core_similarity_minimal = Mínimo 9 | core_cannot_open_dir = No se puede abrir el directorio { $dir }, razón { $reason } 10 | core_cannot_read_entry_dir = No se puede leer la entrada en directorio { $dir }, razón { $reason } 11 | core_cannot_read_metadata_dir = No se pueden leer metadatos en el directorio { $dir }, razón { $reason } 12 | core_file_not_utf8_name = El archivo { $name } no tiene un nombre UTF-8 válido (algunos caracteres pueden no mostrarse) 13 | core_file_modified_before_epoch = El archivo { $name } parece ser modificado antes de Unix Epoch 14 | core_folder_modified_before_epoch = La carpeta { $name } parece ser modificada antes del Epoch Unix 15 | core_file_no_modification_date = No se puede obtener la fecha de modificación del archivo { $name }, razón { $reason } 16 | core_folder_no_modification_date = No se puede obtener la fecha de modificación de la carpeta { $name }, razón { $reason } 17 | core_missing_no_chosen_included_directory = Debe proporcionarse al menos un directorio 18 | core_directory_wildcard_no_supported = Directorios: Los comodines en la ruta no son compatibles, ignorando { $path } 19 | core_directory_must_exists = Directorios: La ruta de la carpeta debe salir, ignorando { $path } 20 | core_directory_must_be_directory = Directorios: La ruta proporcionada debe apuntar al directorio, ignorando { $path } 21 | core_included_directory_zero_valid_directories = ERROR del directorio incluido: No se ha encontrado ni una ruta correcta a incluida que es necesaria 22 | core_excluded_directory_pointless_slash = Directorios: Excluyendo / es inútil, ya que no se analizarán archivos 23 | core_directory_overlap = Directorios: Todos los directorios para buscar superposiciones con directorios excluidos 24 | core_directory_unable_to_get_device_id = Directorios: No se puede obtener el id del dispositivo de la carpeta { $path } 25 | core_ffmpeg_not_found = No se puede encontrar la instalación correcta de FFmpeg 26 | core_ffmpeg_not_found_windows = Asegúrese de que ffmpeg.exe y ffprobe.exe están disponibles en PATH o se colocan directamente en la misma carpeta donde es ejecutable la aplicación 27 | core_ffmpeg_missing_in_snap = Los Videos Similares no funcionan actualmente con el snap, si quieres ayuda mira - { $url } 28 | core_saving_to_cache = Guardado en el archivo { $number } entradas de caché 29 | core_loading_from_cache = Cargado desde { $number } entradas de caché 30 | -------------------------------------------------------------------------------- /czkawka_core/i18n/fr/czkawka_core.ftl: -------------------------------------------------------------------------------- 1 | # Core 2 | core_similarity_original = Originale 3 | core_similarity_very_high = Très haute 4 | core_similarity_high = Haute 5 | core_similarity_medium = Moyenne 6 | core_similarity_small = Basse 7 | core_similarity_very_small = Très basse 8 | core_similarity_minimal = Minimale 9 | core_cannot_open_dir = Impossible d’ouvrir le répertoire { $dir }. Raison : { $reason } 10 | core_cannot_read_entry_dir = Impossible de lire l'entrée dans le répertoire { $dir }. Raison : { $reason } 11 | core_cannot_read_metadata_dir = Impossible de lire les métadonnées dans le répertoire { $dir }. Raison  : { $reason } 12 | core_file_not_utf8_name = Le fichier { $name } n'a pas de nom UTF-8 valide (certains caractères peuvent ne pas être affichés) 13 | core_file_modified_before_epoch = Le fichier { $name } semble avoir été modifié avant l'epoch Unix 14 | core_folder_modified_before_epoch = Le dossier { $name } semble avoir été modifié avant l'epoch Unix 15 | core_file_no_modification_date = Impossible d'obtenir la date de modification du fichier { $name }. Raison  : { $reason } 16 | core_folder_no_modification_date = Impossible d'obtenir la date de modification du dossier { $name }. Raison : { $reason } 17 | core_missing_no_chosen_included_directory = Au moins un répertoire doit être fourni 18 | core_directory_wildcard_no_supported = Répertoires : les jokers dans le chemin ne sont pas pris en charge. { $path } est ignoré 19 | core_directory_must_exists = Répertoires : le chemin du dossier fourni doit exister. { $path } est ignoré 20 | core_directory_must_be_directory = Répertoires : le chemin fourni doit pointer vers le répertoire, { $path } est ignoré 21 | core_included_directory_zero_valid_directories = ERREUR de répertoire inclus : aucun chemin correct n'a été trouvé alors qu'au moins un est nécessaire 22 | core_excluded_directory_pointless_slash = Répertoires: exclure « / » est inutile car cela signifie qu'aucun fichier ne sera scanné 23 | core_directory_overlap = Répertoires : tous les répertoires dans lesquels rechercher des chevauchements avec des répertoires exclus 24 | core_directory_unable_to_get_device_id = Répertoires : impossible d'obtenir l'ID de l'appareil depuis le dossier { $path } 25 | core_ffmpeg_not_found = Impossible de trouver une installation correcte de FFmpeg 26 | core_ffmpeg_not_found_windows = Assurez-vous que ffmpeg.exe et ffprobe.exe sont disponibles dans PATH ou sont présents dans le même dossier que l'exécutable de l'application 27 | core_ffmpeg_missing_in_snap = Les vidéos similaires ne fonctionnent pas actuellement avec snap. Si vous voulez de l'aide référez vous à - { $url } 28 | core_saving_to_cache = { $number } entrées du cache enregistres dans un fichier 29 | core_loading_from_cache = { $number } entrées chargées depuis le cache 30 | -------------------------------------------------------------------------------- /czkawka_core/i18n/it/czkawka_core.ftl: -------------------------------------------------------------------------------- 1 | # Core 2 | core_similarity_original = Originali 3 | core_similarity_very_high = Altissima 4 | core_similarity_high = Alta 5 | core_similarity_medium = Media 6 | core_similarity_small = Piccola 7 | core_similarity_very_small = Piccolissima 8 | core_similarity_minimal = Minima 9 | core_cannot_open_dir = Impossibile aprire cartella { $dir }, motivo { $reason } 10 | core_cannot_read_entry_dir = Impossibile leggere elemento nella cartella { $dir }, ragione { $reason } 11 | core_cannot_read_metadata_dir = Impossibile leggere metadati nella cartella { $dir }, ragione { $reason } 12 | core_file_not_utf8_name = Il file { $name } non ha un nome UTF-8 valido (alcuni caratteri potrebbero non essere mostrati) 13 | core_file_modified_before_epoch = Il file { $name } sembra essere stato modificato prima dell'Epoca Unix 14 | core_folder_modified_before_epoch = La cartella { $name } sembra essere stato modificata prima dell'Epoca Unix 15 | core_file_no_modification_date = Impossibile recuperare data di modifica dal file { $name }, ragione { $reason } 16 | core_folder_no_modification_date = Impossibile recuperare data di modifica dalla cartella { $name }, ragione { $reason } 17 | core_missing_no_chosen_included_directory = Almeno una directory deve essere fornita 18 | core_directory_wildcard_no_supported = Cartelle: i caratteri jolly nel percorso non sono supportati, ignorando { $path } 19 | core_directory_must_exists = Directories: Il percorso della cartella fornito deve uscire, ignorando { $path } 20 | core_directory_must_be_directory = Directories: Il percorso fornito deve puntare alla directory, ignorando { $path } 21 | core_included_directory_zero_valid_directories = ERRORE Directory incluso: Non trovato nemmeno un percorso corretto incluso che è richiesto 22 | core_excluded_directory_pointless_slash = Cartelle: Escludere / è inutile, perché significa che nessun file verrà scansionato 23 | core_directory_overlap = Directories: Tutte le directory per cercare sovrapposizioni con directory escluse 24 | core_directory_unable_to_get_device_id = Directory: non è possibile ottenere l'id del dispositivo dalla cartella { $path } 25 | core_ffmpeg_not_found = Impossibile trovare la corretta installazione di FFmpeg 26 | core_ffmpeg_not_found_windows = Quando si utilizza Windows essere sicuri che ffmpeg.exe e ffprobe.exe sono disponibili in PATH o sono messi direttamente nella stessa cartella dove è eseguibile l'applicazione 27 | core_ffmpeg_missing_in_snap = Video simili non funzionano attualmente con snap, se si desidera aiutare a guardare - { $url } 28 | core_saving_to_cache = Salvato nel file { $number } voci cache 29 | core_loading_from_cache = Caricato dalla cache { $number } voci 30 | -------------------------------------------------------------------------------- /czkawka_core/i18n/ja/czkawka_core.ftl: -------------------------------------------------------------------------------- 1 | # Core 2 | core_similarity_original = 新規に作成 3 | core_similarity_very_high = 非常に高い 4 | core_similarity_high = 高い 5 | core_similarity_medium = ミディアム 6 | core_similarity_small = 小 7 | core_similarity_very_small = 非常に小さい 8 | core_similarity_minimal = 最小 9 | core_cannot_open_dir = ディレクトリを開くことができません { $dir }、理由 { $reason } 10 | core_cannot_read_entry_dir = Dir { $dir } でエントリを読み込めません、理由 { $reason } 11 | core_cannot_read_metadata_dir = Dir { $dir } でメタデータを読み込めません、理由 { $reason } 12 | core_file_not_utf8_name = ファイル { $name } に有効な UTF-8 名がありません (一部の文字は表示されない可能性があります) 13 | core_file_modified_before_epoch = ファイル { $name } は Unix Epoch より前に変更されているようです 14 | core_folder_modified_before_epoch = フォルダ { $name } は、Unix Epoch の前に変更されているようです 15 | core_file_no_modification_date = ファイル { $name } から変更日を取得できません、理由 { $reason } 16 | core_folder_no_modification_date = フォルダ { $name } から変更日を取得できません、理由 { $reason } 17 | core_missing_no_chosen_included_directory = 少なくとも 1 つのディレクトリを指定する必要があります。 18 | core_directory_wildcard_no_supported = ディレクトリ: パス内のワイルドカードはサポートされていません。 { $path } を無視してください 19 | core_directory_must_exists = ディレクトリ: 指定されたフォルダパスは、 { $path } を無視して終了する必要があります 20 | core_directory_must_be_directory = ディレクトリ: 指定されたパスはディレクトリを指す必要があります。 { $path } を無視します 21 | core_included_directory_zero_valid_directories = 含まれるディレクトリエラー: 必須の正しいパスが1つも見つかりません 22 | core_excluded_directory_pointless_slash = ディレクトリ: ファイルがスキャンされないことを意味するため、除外/無意味です 23 | core_directory_overlap = ディレクトリ: 除外されたディレクトリとオーバーラップを検索するすべてのディレクトリ 24 | core_directory_unable_to_get_device_id = ディレクトリ: フォルダ { $path } からデバイス ID を取得できません 25 | core_ffmpeg_not_found = 適切なFFmpegのインストールが見つかりません 26 | core_ffmpeg_not_found_windows = ffmpeg.exeとffprobe.exeがPATHで使用できることを確認するか、アプリ実行ファイルのある同じフォルダに直接配置してください。 27 | core_ffmpeg_missing_in_snap = ヘルプを見たい場合は、現在同様のビデオはスナップでは動作しません - { $url } 28 | core_saving_to_cache = { $number } 個のキャッシュエントリをファイルに保存しました 29 | core_loading_from_cache = キャッシュから { $number } 個のエントリが読み込まれました 30 | -------------------------------------------------------------------------------- /czkawka_core/i18n/ko/czkawka_core.ftl: -------------------------------------------------------------------------------- 1 | # Core 2 | core_similarity_original = 원본 3 | core_similarity_very_high = 매우 높음 4 | core_similarity_high = 높음 5 | core_similarity_medium = 보통 6 | core_similarity_small = 낮음 7 | core_similarity_very_small = 매우 낮음 8 | core_similarity_minimal = 최소 9 | core_cannot_open_dir = { $dir } 디렉터리를 열 수 없습니다. 이유: { $reason } 10 | core_cannot_read_entry_dir = { $dir } 디렉터리를 열 수 없습니다. 이유: { $reason } 11 | core_cannot_read_metadata_dir = { $dir } 디렉터리의 메타데이터를 열 수 없습니다. 이유: { $reason } 12 | core_file_not_utf8_name = 파일 이름 "{ $name }"은 유효한 UTF-8 이름이 아닙니다. 일부 글자가 보이지 않을 수 있습니다. 13 | core_file_modified_before_epoch = { $name } 파일이 Unix 시간 이전에 수정된 것 같습니다. 14 | core_folder_modified_before_epoch = { $name } 폴더가 Unix 시간 이전에 수정된 것 같습니다. 15 | core_file_no_modification_date = { $name } 파일의 수정된 시각을 읽을 수 없습니다. 이유: { $reason } 16 | core_folder_no_modification_date = { $name } 폴더의 수정된 시각을 읽을 수 없습니다. 이유: { $reason } 17 | core_missing_no_chosen_included_directory = 적어도 1개 이상의 디렉터리가 주어져야 합니다. 18 | core_directory_wildcard_no_supported = 디렉터리: 경로에는 와일드 카드가 지원되지 않습니다. "{ $path }"는 무시됩니다. 19 | core_directory_must_exists = 디렉터리: 주어진 폴더 경로는 반드시 존재해야 합니다. "{ $path }"는 무시됩니다. 20 | core_directory_must_be_directory = 디렉터리: 주어진 경로는 디렉터리를 가리켜야 합니다. "{ $path }"는 무시됩니다. 21 | core_included_directory_zero_valid_directories = 검색 대상 디렉터리 오류: 적어도 1개 이상의 유효한 경로가 주어져야 합니다. 유효한 경로가 하나도 없습니다. 22 | core_excluded_directory_pointless_slash = 디렉터리: "/"를 제외하는 것은 아무런 파일도 스캔하지 않는다는 것이므로, 의미가 없습니다. 23 | core_directory_overlap = 디렉터리: 모든 주어진 경로가 검색 제외 경로와 겹칩니다. 24 | core_directory_unable_to_get_device_id = 디렉터리: { $path }의 장치 ID를 가져올 수 없습니다. 25 | core_ffmpeg_not_found = 유효한 FFmpeg 설치를 발견하지 못했습니다. 26 | core_ffmpeg_not_found_windows = ffmpeg.exe와 ffprobe.exe가 시스템 변수 PATH에서 사용 가능하거나, 이 프로그램의 경로와 같은 곳에 위치하는지 확인하세요. 27 | core_ffmpeg_missing_in_snap = 현재 ffmpeg snap에서는 유사한 영상 검색이 지원되지 않습니다. 더 많은 정보는 { $url }에서 확인하세요. 28 | core_saving_to_cache = { $number }개의 파일을 캐시에 저장했습니다. 29 | core_loading_from_cache = { $number }개의 파일을 캐시에서 불러왔습니다. 30 | -------------------------------------------------------------------------------- /czkawka_core/i18n/nl/czkawka_core.ftl: -------------------------------------------------------------------------------- 1 | # Core 2 | core_similarity_original = Origineel 3 | core_similarity_very_high = Zeer hoog 4 | core_similarity_high = hoog 5 | core_similarity_medium = Middelgroot 6 | core_similarity_small = Klein 7 | core_similarity_very_small = Zeer Klein 8 | core_similarity_minimal = Minimaal 9 | core_cannot_open_dir = Kan dir { $dir }niet openen, reden { $reason } 10 | core_cannot_read_entry_dir = Kan invoer niet lezen in map { $dir }, reden { $reason } 11 | core_cannot_read_metadata_dir = Kan metadata niet lezen in map { $dir }, reden { $reason } 12 | core_file_not_utf8_name = Bestand { $name } heeft geen geldige UTF-8-naam (sommige tekens kunnen niet worden getoond) 13 | core_file_modified_before_epoch = Het bestand { $name } lijkt aangepast te zijn voor Unix Epoch 14 | core_folder_modified_before_epoch = Map { $name } lijkt aangepast te zijn voor Unix Epoch 15 | core_file_no_modification_date = Niet in staat om de datum van bestand { $name }te krijgen, reden { $reason } 16 | core_folder_no_modification_date = Niet in staat om wijzigingsdatum van map { $name }te krijgen, reden { $reason } 17 | core_missing_no_chosen_included_directory = Ten minste één map moet worden opgegeven 18 | core_directory_wildcard_no_supported = Maps: Wildcards op pad worden niet ondersteund, negeer { $path } 19 | core_directory_must_exists = Maps: Opgegeven mappad moet bestaan, afwijzend { $path } 20 | core_directory_must_be_directory = Directories: Het opgegeven pad moet naar de map wijzen, { $path } wordt genegeerd 21 | core_included_directory_zero_valid_directories = Inclusief map FOUT: Er is niet één juist pad gevonden naar de map die vereist is 22 | core_excluded_directory_pointless_slash = Maps: Uitsluiten/is zinloos, omdat er geen bestanden worden gescand 23 | core_directory_overlap = Maps: alle mappen om overlappingen te zoeken met uitgesloten mappen 24 | core_directory_unable_to_get_device_id = Maps: Kan apparaat-id niet ophalen uit map { $path } 25 | core_ffmpeg_not_found = Kan de juiste installatie van FFmpeg niet vinden 26 | core_ffmpeg_not_found_windows = Zorg ervoor dat ffmpeg.exe en ffprobe.exe beschikbaar zijn in PATH of direct in dezelfde map geplaatst zijn waar de app uitvoerbaar is 27 | core_ffmpeg_missing_in_snap = Vergelijkbare video's werken momenteel niet met snap, als je wilt helpen kijken naar - { $url } 28 | core_saving_to_cache = Opgeslagen in bestand { $number } cache items 29 | core_loading_from_cache = Geladen uit cache { $number } items 30 | -------------------------------------------------------------------------------- /czkawka_core/i18n/no/czkawka_core.ftl: -------------------------------------------------------------------------------- 1 | # Core 2 | core_similarity_original = Opprinnelig 3 | core_similarity_very_high = Veldig høy 4 | core_similarity_high = Høy 5 | core_similarity_medium = Middels 6 | core_similarity_small = Liten 7 | core_similarity_very_small = Veldig liten 8 | core_similarity_minimal = Minimal 9 | core_cannot_open_dir = Kan ikke åpne dir { $dir }, årsak { $reason } 10 | core_cannot_read_entry_dir = Kan ikke lese oppføringen i dir { $dir }, årsak { $reason } 11 | core_cannot_read_metadata_dir = Kan ikke lese metadata i dir { $dir }, årsak { $reason } 12 | core_file_not_utf8_name = Filen { $name } har ikke et gyldig UTF-8-navn (noen tegn kan ikke vises) 13 | core_file_modified_before_epoch = Filen { $name } ser ut til å bli endret før Unix Epoch 14 | core_folder_modified_before_epoch = Mappen { $name } ser ut til å bli endret før Unix Epoch 15 | core_file_no_modification_date = Klarte ikke å hente endringsdato fra filen { $name }. Årsak { $reason } 16 | core_folder_no_modification_date = Klarte ikke å hente endringsdato fra mappen { $name }. Årsak { $reason } 17 | core_missing_no_chosen_included_directory = Minst en katalog må angis 18 | core_directory_wildcard_no_supported = Kataloger: Jokertegn i stien støttes ikke, ignorerer { $path } 19 | core_directory_must_exists = Kataloger: Angitt sti for mappe må eksistere. Ignorerer { $path } 20 | core_directory_must_be_directory = Kataloger: Angitt sti må peke på mappen. Ignorerer { $path } 21 | core_included_directory_zero_valid_directories = Feil med inkludert katalog: Fant ikke én eneste sti til den inkluderte mappen, noe som er påkrevd 22 | core_excluded_directory_pointless_slash = Kataloger: Ekskludere / er poengløst, fordi det betyr at ingen filer vil bli skannet 23 | core_directory_overlap = Kataloger: Alle kataloger å søke overlapper med ekskluderte mapper 24 | core_directory_unable_to_get_device_id = Mapper: Kan ikke hente enhets id fra mappen { $path } 25 | core_ffmpeg_not_found = Klarte ikke å finne riktig installasjon av FFmpeg 26 | core_ffmpeg_not_found_windows = Pass på at ffmpeg.exe og ffprobe.exe er tilgjengelig i PATH eller plasseres direkte i samme mappe som appen kan kjøres 27 | core_ffmpeg_missing_in_snap = Lignende videoer fungerer ikke for øyeblikket med snap. Hvis du vil ha hjelp kan du se her - { $url } 28 | core_saving_to_cache = Lagret i filen { $number } cache-oppføringer 29 | core_loading_from_cache = Lastet fra hurtigbuffer { $number } oppføringer 30 | -------------------------------------------------------------------------------- /czkawka_core/i18n/pl/czkawka_core.ftl: -------------------------------------------------------------------------------- 1 | # Core 2 | core_similarity_original = Oryginalny 3 | core_similarity_very_high = Bardzo Duże 4 | core_similarity_high = Duże 5 | core_similarity_medium = Średnie 6 | core_similarity_small = Małe 7 | core_similarity_very_small = Bardzo Małe 8 | core_similarity_minimal = Minimalne 9 | core_cannot_open_dir = Nie można otworzyć folderu { $dir }, powód { $reason } 10 | core_cannot_read_entry_dir = Nie można odczytać danych z folderu { $dir }, powód { $reason } 11 | core_cannot_read_metadata_dir = Nie można odczytać metadanych folderu { $dir }, powód { $reason } 12 | core_file_not_utf8_name = Plik { $name } nie posiada nazwy zakodowanej za pomocą UTF-8(niektóre znaki mogą się nie wyświetlać) 13 | core_file_modified_before_epoch = Plik { $name } ma datę modyfikacji sprzed epoki unixa 14 | core_folder_modified_before_epoch = Folder { $name } ma datę modyfikacji sprzed epoki unixa 15 | core_file_no_modification_date = Nie udało się pobrać daty modyfikacji z pliku { $name }, powód { $reason } 16 | core_folder_no_modification_date = Nie udało się pobrać daty modyfikacji z folderu { $name }, powód { $reason } 17 | core_missing_no_chosen_included_directory = Należy podać co najmniej jeden katalog 18 | core_directory_wildcard_no_supported = Katalogi: Wildcard na ścieżce nie są obsługiwane, ignorowanie { $path } 19 | core_directory_must_exists = Katalogi: Podana ścieżka do folderu musi istnieć, ignorowanie { $path } 20 | core_directory_must_be_directory = Katalogi: Podana ścieżka musi wskazywać na katalog, ignorowanie { $path } 21 | core_included_directory_zero_valid_directories = Błąd katalogów do przeszukiwania: Nie znaleziono nawet jednej poprawnej ścieżki do przeszukania 22 | core_excluded_directory_pointless_slash = Katalogi: Wykluczanie folderu / jest bezcelowe, ponieważ oznacza to, że żadne pliki nie zostaną sprawdzone 23 | core_directory_overlap = Katalogi: Wszystkie katalogi do wyszukiwania pokrywają się z wykluczonymi 24 | core_directory_unable_to_get_device_id = Katalogi: Nie można uzyskać identyfikatora urządzenia z folderu { $path } 25 | core_ffmpeg_not_found = Nie można odnaleźć poprawnej instalacji FFmpeg 26 | core_ffmpeg_not_found_windows = Upewnij się, że ffmpeg.exe i ffprobe.exe są dostępne w PATH lub są umieszczone bezpośrednio w tym samym folderze, w którym aplikacja jest uruchamiana. 27 | core_ffmpeg_missing_in_snap = Wyszukiwanie podobnych filmów nie działa obecnie w snapach, jeśli chcesz pomóc spójrz na - { $url } 28 | core_saving_to_cache = Zapisano do pliku { $number } obiektów 29 | core_loading_from_cache = Załadowano z pamięci podręcznej { $number } obiektów 30 | -------------------------------------------------------------------------------- /czkawka_core/i18n/pt-BR/czkawka_core.ftl: -------------------------------------------------------------------------------- 1 | # Core 2 | core_similarity_original = Original 3 | core_similarity_very_high = Muito alto 4 | core_similarity_high = alta 5 | core_similarity_medium = Média 6 | core_similarity_small = Pequeno 7 | core_similarity_very_small = Muito Pequeno 8 | core_similarity_minimal = Mínimo 9 | core_cannot_open_dir = Não é possível abrir o dir { $dir }, razão { $reason } 10 | core_cannot_read_entry_dir = Não é possível ler a entrada no diretório { $dir }, razão { $reason } 11 | core_cannot_read_metadata_dir = Não é possível ler os metadados no diretório { $dir }, razão { $reason } 12 | core_file_not_utf8_name = O arquivo { $name } não possui um nome UTF-8 válido (alguns caracteres não podem ser exibidos) 13 | core_file_modified_before_epoch = O arquivo { $name } parece ser modificado antes do Epoch Unix 14 | core_folder_modified_before_epoch = Pasta { $name } parece ser modificada antes do Epoch Unix 15 | core_file_no_modification_date = Não é possível obter a data de modificação do arquivo { $name }, motivo { $reason } 16 | core_folder_no_modification_date = Não é possível obter a data de modificação da pasta { $name }, motivo { $reason } 17 | core_missing_no_chosen_included_directory = Pelo menos um diretório deve ser fornecido 18 | core_directory_wildcard_no_supported = Directorias: Caracteres curinga no caminho não são suportados, ignorando { $path } 19 | core_directory_must_exists = Diretórios: Caminho da pasta fornecida deve existir, ignorando { $path } 20 | core_directory_must_be_directory = Directorias: Caminho fornecido deve apontar para o diretório, ignorando { $path } 21 | core_included_directory_zero_valid_directories = ERRO do Diretório incluído: Não foi encontrado nenhum caminho correto que é necessário incluir 22 | core_excluded_directory_pointless_slash = Directorias: Excluir / não faz sentido, porque significa que nenhum arquivo será escaneado 23 | core_directory_overlap = Diretórios: Todos os diretórios para pesquisar sobreposições com diretórios excluídos 24 | core_directory_unable_to_get_device_id = Directorias: Não foi possível obter o dispositivo de ajuda da pasta { $path } 25 | core_ffmpeg_not_found = Instalação adequada do FFmpeg não encontrada 26 | core_ffmpeg_not_found_windows = Certifique-se de que o ffmpeg.exe e ffprobe.exe estão disponíveis no PATH ou são colocados diretamente na mesma pasta onde o aplicativo é executável 27 | core_ffmpeg_missing_in_snap = Vídeos similares não funcionam atualmente com o snap, se você quiser ajudar a olhar - { $url } 28 | core_saving_to_cache = Salvo no arquivo { $number } entradas de cache 29 | core_loading_from_cache = Foram carregados "{ $number }" dados do arquivo de ‘cache’ 30 | -------------------------------------------------------------------------------- /czkawka_core/i18n/pt-PT/czkawka_core.ftl: -------------------------------------------------------------------------------- 1 | # Core 2 | core_similarity_original = Original 3 | core_similarity_very_high = Muito alto 4 | core_similarity_high = Alto 5 | core_similarity_medium = Média 6 | core_similarity_small = Pequeno 7 | core_similarity_very_small = Muito Pequeno 8 | core_similarity_minimal = Mínimo 9 | core_cannot_open_dir = Não é possível abrir o diretório { $dir }, razão { $reason } 10 | core_cannot_read_entry_dir = Não é possível ler a entrada no diretório { $dir }, razão { $reason } 11 | core_cannot_read_metadata_dir = Não é possível ler os metadados no diretório { $dir }, razão { $reason } 12 | core_file_not_utf8_name = Arquivo { $name } não tem nome UTF-8 válido (alguns caracteres não podem ser exibidos) 13 | core_file_modified_before_epoch = Arquivo { $name } parece ser modificado antes do Epoch Unix 14 | core_folder_modified_before_epoch = A pasta { $name } parece ser modificada antes do Epoch Unix 15 | core_file_no_modification_date = Não foi possível obter a data de modificação do arquivo { $name }, motivo { $reason } 16 | core_folder_no_modification_date = Não foi possível obter a data de modificação da pasta { $name }, motivo { $reason } 17 | core_missing_no_chosen_included_directory = Pelo menos um diretório deve ser fornecido 18 | core_directory_wildcard_no_supported = Directorias: Caracteres curinga no caminho não são suportados, ignorando { $path } 19 | core_directory_must_exists = Directórios: Caminho da pasta fornecida deve sair, ignorando { $path } 20 | core_directory_must_be_directory = Diretórios: Caminho fornecido deve apontar para o diretório, ignorando { $path } 21 | core_included_directory_zero_valid_directories = ERRO do Diretório incluído: Não foi encontrado nenhum caminho correto que é necessário incluir 22 | core_excluded_directory_pointless_slash = Directorias: Excluir / não faz sentido, porque significa que nenhum arquivo será escaneado 23 | core_directory_overlap = Diretórios: Todos os diretórios para pesquisar sobreposições com diretórios excluídos 24 | core_directory_unable_to_get_device_id = Directorias: Não foi possível obter o dispositivo id da pasta { $path } 25 | core_ffmpeg_not_found = Instalação adequada do FFmpeg não encontrada 26 | core_ffmpeg_not_found_windows = Certifique-se de que o ffmpeg.exe e ffprobe.exe estão disponíveis no PATH ou são colocados diretamente na mesma pasta onde o aplicativo é executável 27 | core_ffmpeg_missing_in_snap = Vídeos similares não funcionam atualmente com o snap, se você quiser ajudar a olhar - { $url } 28 | core_saving_to_cache = Salvo no arquivo { $number } entradas de cache 29 | core_loading_from_cache = Carregado do cache { $number } entradas 30 | -------------------------------------------------------------------------------- /czkawka_core/i18n/ro/czkawka_core.ftl: -------------------------------------------------------------------------------- 1 | # Core 2 | core_similarity_original = Originală 3 | core_similarity_very_high = Foarte Mare 4 | core_similarity_high = Ridicat 5 | core_similarity_medium = Medie 6 | core_similarity_small = Mică 7 | core_similarity_very_small = Foarte mic 8 | core_similarity_minimal = Minimă 9 | core_cannot_open_dir = Nu se poate deschide dir { $dir }, motiv { $reason } 10 | core_cannot_read_entry_dir = Nu se poate citi intrarea în dir { $dir }, motivul { $reason } 11 | core_cannot_read_metadata_dir = Metadatele nu pot fi citite în dir { $dir }, motivul { $reason } 12 | core_file_not_utf8_name = Fișierul { $name } nu are un nume valid UTF-8 (este posibil ca unele caractere să nu fie afișate) 13 | core_file_modified_before_epoch = Fișierul { $name } pare să fie modificat înainte de Epoch Unix 14 | core_folder_modified_before_epoch = Dosarul { $name } pare să fie modificat înainte de Epoc Unix 15 | core_file_no_modification_date = Imposibil de obținut data modificării din fișierul { $name }, motivul { $reason } 16 | core_folder_no_modification_date = Imposibil de obținut data modificării din dosarul { $name }, motivul { $reason } 17 | core_missing_no_chosen_included_directory = Trebuie furnizat cel puțin un director 18 | core_directory_wildcard_no_supported = Directoare: Wildcards pe cale nu sunt acceptate, ignorând { $path } 19 | core_directory_must_exists = Directoare: Calea dosarului furnizat trebuie să existe, ignorând { $path } 20 | core_directory_must_be_directory = Directoare: Calea specificată trebuie să indice în director, ignorând { $path } 21 | core_included_directory_zero_valid_directories = EROARE din Director inclusă: Nici măcar o cale corectă de inclus, care este necesară 22 | core_excluded_directory_pointless_slash = Directoare: Excludere / este inutilă, deoarece înseamnă că niciun fișier nu va fi scanat 23 | core_directory_overlap = Directoare: Toate directoarele pentru a căuta suprapuneri cu directoarele excluse 24 | core_directory_unable_to_get_device_id = Directoare: Imposibil de obținut ID-ul dispozitivului din folderul { $path } 25 | core_ffmpeg_not_found = Nu se poate găsi instalarea corectă a FFmpeg 26 | core_ffmpeg_not_found_windows = Asigurați-vă că ffmpeg.exe și ffprobe.exe sunt disponibile în PATH sau sunt puse direct în același folder unde este executabilă aplicația 27 | core_ffmpeg_missing_in_snap = Videoclipuri similare nu funcționează în prezent cu ancorare, dacă doriți să vă uitați - { $url } 28 | core_saving_to_cache = Intrări cache salvate în fişierul { $number } 29 | core_loading_from_cache = Încărcat din geocutia { $number } 30 | -------------------------------------------------------------------------------- /czkawka_core/i18n/ru/czkawka_core.ftl: -------------------------------------------------------------------------------- 1 | # Core 2 | core_similarity_original = Оригинальное 3 | core_similarity_very_high = Очень высокое 4 | core_similarity_high = Высокое 5 | core_similarity_medium = Среднее 6 | core_similarity_small = Низкое 7 | core_similarity_very_small = Очень низкое 8 | core_similarity_minimal = Минимальное 9 | core_cannot_open_dir = Невозможно открыть каталог { $dir }, причина: { $reason } 10 | core_cannot_read_entry_dir = Невозможно прочитать запись в директории { $dir }, причина: { $reason } 11 | core_cannot_read_metadata_dir = Невозможно прочитать метаданные в директории { $dir }, причина: { $reason } 12 | core_file_not_utf8_name = У файла { $name } неверное имя UTF-8 (некоторые символы могут не отображаться) 13 | core_file_modified_before_epoch = Файл { $name }, кажется, изменён до начала эпохи Unix 14 | core_folder_modified_before_epoch = Папка { $name }, кажется, изменена до начала эпохи Unix 15 | core_file_no_modification_date = Не удаётся получить дату изменения из файла { $name }, причина: { $reason } 16 | core_folder_no_modification_date = Не удаётся получить дату изменения из папки { $name }, причина: { $reason } 17 | core_missing_no_chosen_included_directory = Должен быть указан хотя бы один каталог 18 | core_directory_wildcard_no_supported = Директории: Не поддерживаются маски в путях, будет проигнорирован { $path } 19 | core_directory_must_exists = Директории: Указанный путь к папке должен существовать, будет проигнорирован{ $path } 20 | core_directory_must_be_directory = Директории: Указанный путь должен указывать на директорию, будет проигнорирован { $path } 21 | core_included_directory_zero_valid_directories = Включённый каталог, ОШИБКА: Не найдено ни одного корректного пути для включения в список поиска — обязательно добавить хотя бы один 22 | core_excluded_directory_pointless_slash = Директории: Исключение корневой папки «/» бессмысленно, потому что в таком случае ни один файл не будет просканирован 23 | core_directory_overlap = Каталоги: Все директории для поиска также присутствуют в списке исключённых каталогов 24 | core_directory_unable_to_get_device_id = Каталоги: Не удалось получить идентификатор устройства из папки { $path } 25 | core_ffmpeg_not_found = Не удалось найти путь, содержащий корректную инсталляцию FFmpeg 26 | core_ffmpeg_not_found_windows = Убедитесь, что ffmpeg.exe и ffprobe.exe доступны в PATH или находятся в той же папке, где это исполняемый файл 27 | core_ffmpeg_missing_in_snap = Функция поиска похожих видео пока не работает — если хотите помочь проекту, см. { $url } 28 | core_saving_to_cache = Сохранено в файл записей кэша: { $number } 29 | core_loading_from_cache = Загружено записей из кэша: { $number } 30 | -------------------------------------------------------------------------------- /czkawka_core/i18n/sv-SE/czkawka_core.ftl: -------------------------------------------------------------------------------- 1 | # Core 2 | core_similarity_original = Ursprunglig 3 | core_similarity_very_high = Mycket Hög 4 | core_similarity_high = Hög 5 | core_similarity_medium = Mellan 6 | core_similarity_small = Litet 7 | core_similarity_very_small = Väldigt Liten 8 | core_similarity_minimal = Minimalt 9 | core_cannot_open_dir = Kan inte öppna dir { $dir }anledning { $reason } 10 | core_cannot_read_entry_dir = Kan inte läsa post i dir { $dir }, anledning { $reason } 11 | core_cannot_read_metadata_dir = Kan inte läsa metadata i dir { $dir }, anledning { $reason } 12 | core_file_not_utf8_name = Filen { $name } har inte ett giltigt UTF-8-namn (vissa tecken kan inte visas) 13 | core_file_modified_before_epoch = Filen { $name } verkar ändras innan Unix Epoch 14 | core_folder_modified_before_epoch = Mappen { $name } verkar ändras innan Unix Epoch 15 | core_file_no_modification_date = Det går inte att hämta ändringsdatum från filen { $name }, anledning { $reason } 16 | core_folder_no_modification_date = Det går inte att hämta ändringsdatum från mappen { $name }, anledning { $reason } 17 | core_missing_no_chosen_included_directory = Minst en katalog måste tillhandahållas 18 | core_directory_wildcard_no_supported = Kataloger: Wildcards i sökvägen stöds inte, ignorerar { $path } 19 | core_directory_must_exists = Kataloger: Tillhandahållen mappsökväg måste finnas, ignorerar { $path } 20 | core_directory_must_be_directory = Kataloger: Tillhandahållen sökväg måste peka på katalogen, ignorerar { $path } 21 | core_included_directory_zero_valid_directories = Inkluderad katalog FEL: Hittas inte ens en korrekt sökväg till inkluderad som krävs 22 | core_excluded_directory_pointless_slash = Kataloger: Exklusive / är meningslös, eftersom det innebär att inga filer kommer att skannas 23 | core_directory_overlap = Kataloger: Alla kataloger att söka överlappar med uteslutna kataloger 24 | core_directory_unable_to_get_device_id = Kataloger: Det går inte att hämta enhets-id från mappen { $path } 25 | core_ffmpeg_not_found = Kan inte hitta rätt installation av FFmpeg 26 | core_ffmpeg_not_found_windows = Se till att ffmpeg.exe och ffprobe.exe är tillgängliga i PATH eller sätts direkt till samma mapp där är app körbar 27 | core_ffmpeg_missing_in_snap = Liknande videor fungerar inte just nu med snap, om du vill ha hjälp att titta på - { $url } 28 | core_saving_to_cache = Sparad i filen { $number } cacheposter 29 | core_loading_from_cache = Laddad från cache { $number } poster 30 | -------------------------------------------------------------------------------- /czkawka_core/i18n/tr/czkawka_core.ftl: -------------------------------------------------------------------------------- 1 | # Core 2 | core_similarity_original = Asıl 3 | core_similarity_very_high = Çok Yüksek 4 | core_similarity_high = Yüksek 5 | core_similarity_medium = Orta 6 | core_similarity_small = Düşük 7 | core_similarity_very_small = Çok Düşük 8 | core_similarity_minimal = Aşırı Düşük 9 | core_cannot_open_dir = { $dir } dizini açılamıyor, nedeni: { $reason } 10 | core_cannot_read_entry_dir = { $dir } dizinindeki girdi okunamıyor, nedeni: { $reason } 11 | core_cannot_read_metadata_dir = { $dir } dizinindeki metaveri okunamıyor, nedei: { $reason } 12 | core_file_not_utf8_name = { $name } dosyasının geçerli bir UTF-8 adı yok (kimi karakterler gösterilemeyebilir) 13 | core_file_modified_before_epoch = { $name } dosyası Unix Epoch'tan önce değiştirilmiş gibi görünüyor. 14 | core_folder_modified_before_epoch = { $name } klasörü Unix Epoch'tan önce değiştirilmiş gibi görünüyor. 15 | core_file_no_modification_date = { $name } dosyasının değişiklik tarihine erişilemiyor, nedeni: { $reason } 16 | core_folder_no_modification_date = { $name } klasörünün değişiklik tarihine erişilemiyor, nedeni: { $reason } 17 | core_missing_no_chosen_included_directory = "Aranacak Dizinler" listesinde en az bir dizin yer almalıdır. 18 | core_directory_wildcard_no_supported = Dizinler: Yol adında joker karakterler desteklenmez, { $path } yok sayıldı. 19 | core_directory_must_exists = Dizinler: Girilen klasör yolu var olmalı, { $path } yok sayıldı. 20 | core_directory_must_be_directory = Dizinler: Girilen yol bir dizini göstermelidir, { $path } yok sayıldı. 21 | core_included_directory_zero_valid_directories = "Aranacak Dizinler" listesinde HATA: Tarama yapılması için gerekli olan tek bir doğru yol bile bulunamadı. 22 | core_excluded_directory_pointless_slash = Dizinler: "/" kök dizinini hariç tutmak anlamsızdır, çünkü bu hiçbir dosyanın taranmayacağı anlamına gelir. 23 | core_directory_overlap = Dizinler: Aranacak tüm dizinler, hariç tutulan dizinlerle çakışıyor. 24 | core_directory_unable_to_get_device_id = Dizinler: { $path } klasörünün aygıt kimliği bilgisine erişilemiyor. 25 | core_ffmpeg_not_found = FFmpeg'in uygun kurulumu bulunamıyor. 26 | core_ffmpeg_not_found_windows = "ffmpeg(.exe)" ve "ffprobe(.exe)" uygulamalarının PATH dizininde ya da uygulamanın doğrudan yürütüldüğü dizinde yer aldığından ve 'yürütülebilir' olarak işaretlendiğinden emin olun. 27 | core_ffmpeg_missing_in_snap = Benzer Videolar şu anda snap ile çalışmıyor, eğer yardım istiyorsanız - { $url } 28 | core_saving_to_cache = { $number } adet önbellek kaydı dosyaya kaydedildi 29 | core_loading_from_cache = Önbellekten { $number } adet kayıt yüklendi 30 | -------------------------------------------------------------------------------- /czkawka_core/i18n/uk/czkawka_core.ftl: -------------------------------------------------------------------------------- 1 | # Core 2 | core_similarity_original = Оригінал 3 | core_similarity_very_high = Дуже висока 4 | core_similarity_high = Висока 5 | core_similarity_medium = Середня 6 | core_similarity_small = Низька 7 | core_similarity_very_small = Дуже низька 8 | core_similarity_minimal = Мінімальна 9 | core_cannot_open_dir = Не вдалося відкрити каталог { $dir }, причина: { $reason } 10 | core_cannot_read_entry_dir = Не вдалося прочитати запис в каталозі { $dir }, причина: { $reason } 11 | core_cannot_read_metadata_dir = Не вдалося прочитати метадані в каталозі { $dir }, причина: { $reason } 12 | core_file_not_utf8_name = Файл { $name } не має припустимого імені UTF-8 (деякі символи не можуть бути показані) 13 | core_file_modified_before_epoch = Файл { $name }, здається, змінено до початку епохи Unix 14 | core_folder_modified_before_epoch = Папка { $name }, здається, змінена до початку епохи Unix 15 | core_file_no_modification_date = Не вдалося отримати дату модифікації з файлу { $name }, причина: { $reason } 16 | core_folder_no_modification_date = Не вдалося отримати дату модифікації з каталогу { $name }, причина: { $reason } 17 | core_missing_no_chosen_included_directory = Необхідно вказати принаймні один каталог 18 | core_directory_wildcard_no_supported = Директорії: Не підтримуються маски у шляхах, буде проігнорован { $path } 19 | core_directory_must_exists = Директорії: Вказаний шлях до папки має існувати, буде проігнорован { $path } 20 | core_directory_must_be_directory = Директорії: Вказаний шлях повинен вказувати на директорію, буде проігнорован { $path } 21 | core_included_directory_zero_valid_directories = Включений каталог, ПОМИЛКА: Не знайдено жодного коректного шляху для включення до списку пошуку — обов'язково додати хоча б один 22 | core_excluded_directory_pointless_slash = Директорії: Виключення кореневого каталогу «/» не має сенсу, тому що в такому разі жоден файл не буде просканований 23 | core_directory_overlap = Каталоги: Усі директорії для пошуку також присутні у списку виключених каталогів 24 | core_directory_unable_to_get_device_id = Каталоги: Не вдалося отримати ідентифікатор пристрою з папки { $path } 25 | core_ffmpeg_not_found = Неможливо знайти шлях, що містить коректну інсталяцію FFmpeg 26 | core_ffmpeg_not_found_windows = Будьте впевнені, що ffmpeg.exe і ffprobe.exe доступні в PATH або прямо в тій же папці, де є виконуваний додаток 27 | core_ffmpeg_missing_in_snap = Функція пошуку схожих відео поки не працює — якщо хочете допомогти проекту, див. {$url} 28 | core_saving_to_cache = Збережено записів кешу у файл: { $number } 29 | core_loading_from_cache = Завантажено записів з кешу: { $number } 30 | -------------------------------------------------------------------------------- /czkawka_core/i18n/zh-CN/czkawka_core.ftl: -------------------------------------------------------------------------------- 1 | # Core 2 | core_similarity_original = 原版 3 | core_similarity_very_high = 非常高 4 | core_similarity_high = 高 5 | core_similarity_medium = 中 6 | core_similarity_small = 小的 7 | core_similarity_very_small = 非常小 8 | core_similarity_minimal = 最小化 9 | core_cannot_open_dir = 无法打开目录 { $dir },因为 { $reason } 10 | core_cannot_read_entry_dir = 无法在目录 { $dir } 中读取条目,因为 { $reason } 11 | core_cannot_read_metadata_dir = 无法读取目录 { $dir } 中的元数据,因为 { $reason } 12 | core_file_not_utf8_name = 文件 { $name } 没有有效的 UTF-8 名称 (可能无法显示一些字符) 13 | core_file_modified_before_epoch = 文件 { $name } 似乎在 Unix Epoch 之前被修改过 14 | core_folder_modified_before_epoch = 文件夹 { $name } 似乎在 Unix Epoch 之前被修改过 15 | core_file_no_modification_date = 无法从文件 { $name } 获取修改日期,因为 { $reason } 16 | core_folder_no_modification_date = 无法从文件夹 { $name } 获取修改日期,因为 { $reason } 17 | core_missing_no_chosen_included_directory = 必须至少提供一个目录 18 | core_directory_wildcard_no_supported = 目录:不支持路径中的通配符,忽略 { $path } 19 | core_directory_must_exists = 目录:提供的文件夹路径必须退出,忽略 { $path } 20 | core_directory_must_be_directory = 目录:提供的路径必须指向目录,忽略 { $path } 21 | core_included_directory_zero_valid_directories = 包括目录错误:即使找不到一个需要包含的正确路径 22 | core_excluded_directory_pointless_slash = 目录:不包括 / 无意义,因为它意味着没有文件将被扫描 23 | core_directory_overlap = 目录:所有要搜索与排除目录重叠的目录 24 | core_directory_unable_to_get_device_id = 目录:无法从文件夹 { $path } 获取设备 id 25 | core_ffmpeg_not_found = FFmpeg未被正确安装 26 | core_ffmpeg_not_found_windows = 请确保 ffmpeg.exe 和 ffprobe.exe 在 PATH 中可用,或者直接放入应用可执行文件的同一文件夹中 27 | core_ffmpeg_missing_in_snap = 类似的视频目前不适用于快照,如果您想要帮助查看- { $url } 28 | core_saving_to_cache = 保存到文件 { $number } 个缓存条目 29 | core_loading_from_cache = 从缓存加载 { $number } 个条目 30 | -------------------------------------------------------------------------------- /czkawka_core/i18n/zh-TW/czkawka_core.ftl: -------------------------------------------------------------------------------- 1 | # Core 2 | core_similarity_original = 原始 3 | core_similarity_very_high = 極高 4 | core_similarity_high = 高 5 | core_similarity_medium = 中等 6 | core_similarity_small = 小 7 | core_similarity_very_small = 非常小 8 | core_similarity_minimal = 最小 9 | core_cannot_open_dir = 無法開啟目錄 { $dir },原因是 { $reason } 10 | core_cannot_read_entry_dir = 無法讀取目錄 { $dir } 中的項目,原因是 { $reason } 11 | core_cannot_read_metadata_dir = 無法讀取目錄 { $dir } 的中繼資料,原因是 { $reason } 12 | core_file_not_utf8_name = 檔案 { $name } 名稱非有效的 UTF-8 格式(部分字元可能無法顯示) 13 | core_file_modified_before_epoch = 檔案 { $name } 似乎在 Unix Epoch 之前就已被修改 14 | core_folder_modified_before_epoch = 資料夾 { $name } 似乎在 Unix Epoch 之前就已被修改 15 | core_file_no_modification_date = 無法取得檔案 { $name } 的修改日期,原因是 { $reason } 16 | core_folder_no_modification_date = 無法取得資料夾 { $name } 的修改日期,原因是 { $reason } 17 | core_missing_no_chosen_included_directory = 必須至少選擇一個目錄 18 | core_directory_wildcard_no_supported = 目錄:不支援路徑中的萬用字元,已忽略 { $path } 19 | core_directory_must_exists = 目錄:所提供的資料夾路徑必須存在,已忽略 { $path } 20 | core_directory_must_be_directory = 目錄:所提供的路徑必須為目錄,已忽略 { $path } 21 | core_included_directory_zero_valid_directories = 包含目錄錯誤:未找到任何有效的包含路徑 22 | core_excluded_directory_pointless_slash = 目錄:排除 / 是無意義的,因為這意味著不會有任何檔案被掃描 23 | core_directory_overlap = 目錄:所有搜尋目錄與排除目錄均有重疊 24 | core_directory_unable_to_get_device_id = 目錄:無法從資料夾 { $path } 取得裝置 ID 25 | core_ffmpeg_not_found = 找不到已正確安裝的 FFmpeg 26 | core_ffmpeg_not_found_windows = 請確保 ffmpeg.exe 和 ffprobe.exe 在 PATH 中可用,或者直接將它們放在與可執行應用程式的同一個資料夾中 27 | core_ffmpeg_missing_in_snap = 快照中目前無法使用相似影片功能,如需協助,請參考 { $url } 28 | core_saving_to_cache = 已將 { $number } 個項目儲存至快取 29 | core_loading_from_cache = 已從快取載入 { $number } 個項目 30 | -------------------------------------------------------------------------------- /czkawka_core/src/common_messages.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Default, Clone)] 2 | pub struct Messages { 3 | pub messages: Vec, 4 | pub warnings: Vec, 5 | pub errors: Vec, 6 | } 7 | 8 | impl Messages { 9 | pub fn new() -> Self { 10 | Default::default() 11 | } 12 | pub fn new_from_errors(errors: Vec) -> Self { 13 | Self { errors, ..Default::default() } 14 | } 15 | pub fn new_from_warnings(warnings: Vec) -> Self { 16 | Self { warnings, ..Default::default() } 17 | } 18 | pub fn new_from_messages(messages: Vec) -> Self { 19 | Self { messages, ..Default::default() } 20 | } 21 | #[allow(clippy::print_stdout)] 22 | pub fn print_messages(&self) { 23 | println!("{}", self.create_messages_text()); 24 | } 25 | 26 | pub fn create_messages_text(&self) -> String { 27 | let mut text_to_return: String = String::new(); 28 | 29 | if !self.messages.is_empty() { 30 | text_to_return += "-------------------------------MESSAGES--------------------------------\n"; 31 | for i in &self.messages { 32 | text_to_return += i; 33 | text_to_return += "\n"; 34 | } 35 | text_to_return += "---------------------------END OF MESSAGES-----------------------------\n"; 36 | } 37 | 38 | if !self.warnings.is_empty() { 39 | text_to_return += "-------------------------------WARNINGS--------------------------------\n"; 40 | 41 | for i in &self.warnings { 42 | text_to_return += i; 43 | text_to_return += "\n"; 44 | } 45 | text_to_return += "---------------------------END OF WARNINGS-----------------------------\n"; 46 | } 47 | 48 | if !self.errors.is_empty() { 49 | text_to_return += "--------------------------------ERRORS---------------------------------\n"; 50 | 51 | for i in &self.errors { 52 | text_to_return += i; 53 | text_to_return += "\n"; 54 | } 55 | text_to_return += "----------------------------END OF ERRORS------------------------------\n"; 56 | } 57 | 58 | text_to_return 59 | } 60 | 61 | pub fn extend_messages_with(&mut self, messages: Vec, warnings: Vec, errors: Vec) { 62 | self.messages.extend(messages); 63 | self.warnings.extend(warnings); 64 | self.errors.extend(errors); 65 | } 66 | 67 | pub fn extend_with_another_messages(&mut self, messages: Self) { 68 | let (messages, warnings, errors) = (messages.messages, messages.warnings, messages.errors); 69 | self.messages.extend(messages); 70 | self.warnings.extend(warnings); 71 | self.errors.extend(errors); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /czkawka_core/src/common_traits.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::io::{BufWriter, Write}; 3 | use std::path::Path; 4 | 5 | use fun_time::fun_time; 6 | use serde::Serialize; 7 | 8 | pub trait DebugPrint { 9 | fn debug_print(&self); 10 | } 11 | 12 | pub trait PrintResults { 13 | fn write_results(&self, writer: &mut T) -> std::io::Result<()>; 14 | 15 | #[fun_time(message = "print_results_to_output", level = "debug")] 16 | fn print_results_to_output(&self) { 17 | let stdout = std::io::stdout(); 18 | let mut handle = stdout.lock(); 19 | // Panics here are allowed, because it is used only in CLI 20 | self.write_results(&mut handle).expect("Error while writing to stdout"); 21 | handle.flush().expect("Error while flushing stdout"); 22 | } 23 | 24 | #[fun_time(message = "print_results_to_file", level = "debug")] 25 | fn print_results_to_file(&self, file_name: &str) -> std::io::Result<()> { 26 | let file_name: String = match file_name { 27 | "" => "results.txt".to_string(), 28 | k => k.to_string(), 29 | }; 30 | 31 | let file_handler = File::create(file_name)?; 32 | let mut writer = BufWriter::new(file_handler); 33 | self.write_results(&mut writer)?; 34 | writer.flush()?; 35 | Ok(()) 36 | } 37 | 38 | fn save_results_to_file_as_json(&self, file_name: &str, pretty_print: bool) -> std::io::Result<()>; 39 | 40 | fn save_results_to_file_as_json_internal(&self, file_name: &str, item_to_serialize: &T, pretty_print: bool) -> std::io::Result<()> { 41 | if pretty_print { 42 | self.save_results_to_file_as_json_pretty(file_name, item_to_serialize) 43 | } else { 44 | self.save_results_to_file_as_json_compact(file_name, item_to_serialize) 45 | } 46 | } 47 | 48 | #[fun_time(message = "save_results_to_file_as_json_pretty", level = "debug")] 49 | fn save_results_to_file_as_json_pretty(&self, file_name: &str, item_to_serialize: &T) -> std::io::Result<()> { 50 | let file_handler = File::create(file_name)?; 51 | let mut writer = BufWriter::new(file_handler); 52 | serde_json::to_writer_pretty(&mut writer, item_to_serialize)?; 53 | Ok(()) 54 | } 55 | 56 | #[fun_time(message = "save_results_to_file_as_json_compact", level = "debug")] 57 | fn save_results_to_file_as_json_compact(&self, file_name: &str, item_to_serialize: &T) -> std::io::Result<()> { 58 | let file_handler = File::create(file_name)?; 59 | let mut writer = BufWriter::new(file_handler); 60 | serde_json::to_writer(&mut writer, item_to_serialize)?; 61 | Ok(()) 62 | } 63 | 64 | fn save_all_in_one(&self, folder: &str, base_file_name: &str) -> std::io::Result<()> { 65 | let pretty_name = format!("{folder}/{base_file_name}_pretty.json"); 66 | self.save_results_to_file_as_json(&pretty_name, true)?; 67 | let compact_name = format!("{folder}/{base_file_name}_compact.json"); 68 | self.save_results_to_file_as_json(&compact_name, false)?; 69 | let txt_name = format!("{folder}/{base_file_name}.txt"); 70 | self.print_results_to_file(&txt_name)?; 71 | Ok(()) 72 | } 73 | } 74 | 75 | pub trait ResultEntry { 76 | fn get_path(&self) -> &Path; 77 | fn get_modified_date(&self) -> u64; 78 | fn get_size(&self) -> u64; 79 | } 80 | -------------------------------------------------------------------------------- /czkawka_core/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::collapsible_else_if)] 2 | #![allow(clippy::type_complexity)] 3 | #![allow(clippy::needless_late_init)] 4 | #![allow(clippy::too_many_arguments)] 5 | #![warn(clippy::unwrap_used)] 6 | #![warn(clippy::print_stderr)] 7 | #![warn(clippy::print_stdout)] 8 | #![warn(clippy::dbg_macro)] 9 | #![warn(clippy::string_slice)] 10 | 11 | #[macro_use] 12 | extern crate bitflags; 13 | extern crate core; 14 | 15 | pub mod common; 16 | pub mod common_cache; 17 | pub mod common_dir_traversal; 18 | pub mod common_directory; 19 | pub mod common_extensions; 20 | pub mod common_image; 21 | pub mod common_items; 22 | pub mod common_messages; 23 | pub mod common_tool; 24 | pub mod common_traits; 25 | pub mod localizer_core; 26 | pub mod progress_data; 27 | pub mod tools; 28 | 29 | pub const CZKAWKA_VERSION: &str = env!("CARGO_PKG_VERSION"); 30 | pub const TOOLS_NUMBER: usize = 11; 31 | -------------------------------------------------------------------------------- /czkawka_core/src/localizer_core.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use i18n_embed::fluent::{FluentLanguageLoader, fluent_language_loader}; 4 | use i18n_embed::{DefaultLocalizer, LanguageLoader, Localizer}; 5 | use once_cell::sync::Lazy; 6 | use rust_embed::RustEmbed; 7 | 8 | #[derive(RustEmbed)] 9 | #[folder = "i18n/"] 10 | struct Localizations; 11 | 12 | pub static LANGUAGE_LOADER_CORE: Lazy = Lazy::new(|| { 13 | let loader: FluentLanguageLoader = fluent_language_loader!(); 14 | 15 | loader.load_fallback_language(&Localizations).expect("Error while loading fallback language"); 16 | 17 | loader 18 | }); 19 | 20 | #[macro_export] 21 | macro_rules! flc { 22 | ($message_id:literal) => {{ 23 | i18n_embed_fl::fl!($crate::localizer_core::LANGUAGE_LOADER_CORE, $message_id) 24 | }}; 25 | 26 | ($message_id:literal, $($args:expr),*) => {{ 27 | i18n_embed_fl::fl!($crate::localizer_core::LANGUAGE_LOADER_CORE, $message_id, $($args), *) 28 | }}; 29 | } 30 | 31 | // Get the `Localizer` to be used for localizing this library. 32 | 33 | pub fn localizer_core() -> Box { 34 | Box::from(DefaultLocalizer::new(&*LANGUAGE_LOADER_CORE, &Localizations)) 35 | } 36 | 37 | pub fn generate_translation_hashmap(vec: Vec<(&'static str, String)>) -> HashMap<&'static str, String> { 38 | let mut hashmap: HashMap<&'static str, String> = Default::default(); 39 | for (key, value) in vec { 40 | hashmap.insert(key, value); 41 | } 42 | hashmap 43 | } 44 | 45 | pub fn fnc_get_similarity_very_high() -> String { 46 | flc!("core_similarity_very_high") 47 | } 48 | 49 | pub fn fnc_get_similarity_minimal() -> String { 50 | flc!("core_similarity_minimal") 51 | } 52 | -------------------------------------------------------------------------------- /czkawka_core/src/tools/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod bad_extensions; 2 | pub mod big_file; 3 | pub mod broken_files; 4 | pub mod duplicate; 5 | pub mod empty_files; 6 | pub mod empty_folder; 7 | pub mod invalid_symlinks; 8 | pub mod same_music; 9 | pub mod similar_images; 10 | pub mod similar_videos; 11 | pub mod temporary; 12 | -------------------------------------------------------------------------------- /czkawka_gui/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "czkawka_gui" 3 | version = "9.0.0" 4 | authors = ["Rafał Mikrut "] 5 | edition = "2024" 6 | rust-version = "1.85.0" 7 | description = "GTK frontend of Czkawka" 8 | license = "MIT" 9 | homepage = "https://github.com/qarmin/czkawka" 10 | repository = "https://github.com/qarmin/czkawka" 11 | 12 | [dependencies] 13 | gdk4 = { version = "0.9", default-features = false, features = ["v4_6"] } 14 | glib = "0.20" 15 | gtk4 = { version = "0.9", default-features = false, features = ["v4_6"] } 16 | 17 | humansize = "2.1" 18 | chrono = "0.4.38" 19 | crossbeam-channel = "0.5" 20 | directories-next = "2.0" 21 | open = "5.3" 22 | image = "0.25" 23 | regex = "1.11" 24 | image_hasher = "3.0" 25 | trash = "5.1" 26 | fs_extra = "1.3" 27 | 28 | i18n-embed = { version = "0.15", features = ["fluent-system", "desktop-requester"] } 29 | i18n-embed-fl = "0.9" 30 | rust-embed = { version = "8.5", features = ["debug-embed"] } 31 | once_cell = "1.20" 32 | 33 | log = "0.4.22" 34 | fun_time = { version = "0.3", features = ["log"] } 35 | rayon = "1.10" 36 | 37 | czkawka_core = { path = "../czkawka_core", version = "9.0.0", features = [] } 38 | 39 | [dev-dependencies] 40 | rand = "0.9.0" 41 | 42 | [target.'cfg(windows)'.dependencies] 43 | winapi = { version = "0.3.9", features = ["combaseapi", "objbase", "shobjidl_core", "windef", "winerror", "wtypesbase", "winuser"] } 44 | 45 | [features] 46 | default = ["fast_image_resize"] 47 | heif = ["czkawka_core/heif"] 48 | libraw = ["czkawka_core/libraw"] 49 | libavif = ["czkawka_core/libavif"] 50 | fast_image_resize = ["czkawka_core/fast_image_resize"] 51 | -------------------------------------------------------------------------------- /czkawka_gui/LICENSE_MIT_APP_CODE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2025 Rafał Mikrut 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /czkawka_gui/LICENSE_MIT_WINDOWS_THEME: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-2020 Nick Rhodes 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /czkawka_gui/data: -------------------------------------------------------------------------------- 1 | ../data/ -------------------------------------------------------------------------------- /czkawka_gui/i18n.toml: -------------------------------------------------------------------------------- 1 | # (Required) The language identifier of the language used in the 2 | # source code for gettext system, and the primary fallback language 3 | # (for which all strings must be present) when using the fluent 4 | # system. 5 | fallback_language = "en" 6 | 7 | # Use the fluent localization system. 8 | [fluent] 9 | # (Required) The path to the assets directory. 10 | # The paths inside the assets directory should be structured like so: 11 | # `assets_dir/{language}/{domain}.ftl` 12 | assets_dir = "i18n" 13 | 14 | -------------------------------------------------------------------------------- /czkawka_gui/icons/czk_add.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /czkawka_gui/icons/czk_delete.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /czkawka_gui/icons/czk_hide_down.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /czkawka_gui/icons/czk_hide_up.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /czkawka_gui/icons/czk_info.svg: -------------------------------------------------------------------------------- 1 | i -------------------------------------------------------------------------------- /czkawka_gui/icons/czk_left.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /czkawka_gui/icons/czk_manual_add.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /czkawka_gui/icons/czk_move.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /czkawka_gui/icons/czk_right.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /czkawka_gui/icons/czk_save.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /czkawka_gui/icons/czk_search.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /czkawka_gui/icons/czk_select.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /czkawka_gui/icons/czk_settings.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /czkawka_gui/icons/czk_sort.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /czkawka_gui/icons/czk_stop.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /czkawka_gui/icons/czk_symlink.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /czkawka_gui/icons/czk_trash.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /czkawka_gui/icons/icon_about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qarmin/czkawka/2be42d9478501a90c36e8b1002fa3c7e5cb5ad2d/czkawka_gui/icons/icon_about.png -------------------------------------------------------------------------------- /czkawka_gui/src/connect_things/connect_about_buttons.rs: -------------------------------------------------------------------------------- 1 | use gtk4::prelude::*; 2 | use log::error; 3 | 4 | use crate::gui_structs::gui_data::GuiData; 5 | 6 | const SPONSOR_SITE: &str = "https://github.com/sponsors/qarmin"; 7 | const REPOSITORY_SITE: &str = "https://github.com/qarmin/czkawka"; 8 | const INSTRUCTION_SITE: &str = "https://github.com/qarmin/czkawka/blob/master/instructions/Instruction.md"; 9 | const TRANSLATION_SITE: &str = "https://crwd.in/czkawka"; 10 | 11 | pub fn connect_about_buttons(gui_data: &GuiData) { 12 | let button_donation = gui_data.about.button_donation.clone(); 13 | button_donation.connect_clicked(move |_| { 14 | if let Err(e) = open::that(SPONSOR_SITE) { 15 | error!("Failed to open sponsor site: {SPONSOR_SITE}, reason {e}"); 16 | }; 17 | }); 18 | 19 | let button_instruction = gui_data.about.button_instruction.clone(); 20 | button_instruction.connect_clicked(move |_| { 21 | if let Err(e) = open::that(INSTRUCTION_SITE) { 22 | error!("Failed to open instruction site: {INSTRUCTION_SITE}, reason {e}"); 23 | }; 24 | }); 25 | 26 | let button_repository = gui_data.about.button_repository.clone(); 27 | button_repository.connect_clicked(move |_| { 28 | if let Err(e) = open::that(REPOSITORY_SITE) { 29 | error!("Failed to open repository site: {REPOSITORY_SITE}, reason {e}"); 30 | }; 31 | }); 32 | 33 | let button_translation = gui_data.about.button_translation.clone(); 34 | button_translation.connect_clicked(move |_| { 35 | if let Err(e) = open::that(TRANSLATION_SITE) { 36 | error!("Failed to open translation site: {TRANSLATION_SITE}, reason {e}"); 37 | }; 38 | }); 39 | } 40 | -------------------------------------------------------------------------------- /czkawka_gui/src/connect_things/connect_button_sort.rs: -------------------------------------------------------------------------------- 1 | use gtk4::prelude::*; 2 | 3 | use crate::gui_structs::gui_data::GuiData; 4 | use crate::gui_structs::gui_popovers_sort::GuiSortPopovers; 5 | use crate::help_functions::PopoverTypes; 6 | use crate::notebook_enums::{NotebookMainEnum, to_notebook_main_enum}; 7 | use crate::notebook_info::NOTEBOOKS_INFO; 8 | 9 | pub fn connect_button_sort(gui_data: &GuiData) { 10 | let popovers_sort = gui_data.popovers_sort.clone(); 11 | let notebook_main = gui_data.main_notebook.notebook_main.clone(); 12 | let gc_buttons_sort = gui_data.bottom_buttons.gc_buttons_sort.clone(); 13 | 14 | gc_buttons_sort.connect_pressed(move |_, _, _, _| { 15 | show_required_popovers(&popovers_sort, to_notebook_main_enum(notebook_main.current_page().expect("Current page not set"))); 16 | }); 17 | } 18 | 19 | fn show_required_popovers(popovers_sort: &GuiSortPopovers, current_mode: NotebookMainEnum) { 20 | let buttons_popover_sort_file_name = popovers_sort.buttons_popover_sort_file_name.clone(); 21 | let buttons_popover_sort_size = popovers_sort.buttons_popover_sort_size.clone(); 22 | let buttons_popover_sort_folder_name = popovers_sort.buttons_popover_sort_folder_name.clone(); 23 | let buttons_popover_sort_full_name = popovers_sort.buttons_popover_sort_full_name.clone(); 24 | let buttons_popover_sort_selection = popovers_sort.buttons_popover_sort_selection.clone(); 25 | 26 | let arr = &NOTEBOOKS_INFO[current_mode as usize].available_modes; 27 | 28 | buttons_popover_sort_full_name.hide(); 29 | 30 | if arr.contains(&PopoverTypes::All) { 31 | buttons_popover_sort_selection.show(); 32 | buttons_popover_sort_file_name.show(); 33 | buttons_popover_sort_folder_name.show(); 34 | // buttons_popover_sort_full_name.show(); // TODO, this needs to be handled a little different 35 | } else { 36 | buttons_popover_sort_selection.hide(); 37 | buttons_popover_sort_file_name.hide(); 38 | buttons_popover_sort_folder_name.hide(); 39 | // buttons_popover_sort_full_name.hide(); 40 | } 41 | 42 | if arr.contains(&PopoverTypes::Size) { 43 | buttons_popover_sort_size.show(); 44 | } else { 45 | buttons_popover_sort_size.hide(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /czkawka_gui/src/connect_things/connect_button_stop.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | use std::sync::atomic::AtomicBool; 3 | 4 | use gtk4::prelude::*; 5 | 6 | use crate::flg; 7 | use crate::gui_structs::gui_data::GuiData; 8 | use crate::help_functions::KEY_ENTER; 9 | 10 | fn send_stop_message(stop_flag: &Arc) { 11 | stop_flag.store(true, std::sync::atomic::Ordering::Relaxed); 12 | } 13 | 14 | pub fn connect_button_stop(gui_data: &GuiData) { 15 | let evk_button_stop_in_dialog = gui_data.progress_window.evk_button_stop_in_dialog.clone(); 16 | let stop_dialog = gui_data.progress_window.window_progress.clone(); 17 | let stop_flag = gui_data.stop_flag.clone(); 18 | evk_button_stop_in_dialog.connect_key_released(move |_, _, key_code, _| { 19 | if key_code == KEY_ENTER { 20 | stop_dialog.set_title(Some(&format!("{} ({})", flg!("window_progress_title"), flg!("progress_stop_additional_message")))); 21 | send_stop_message(&stop_flag); 22 | } 23 | }); 24 | 25 | let button_stop_in_dialog = gui_data.progress_window.button_stop_in_dialog.clone(); 26 | let stop_dialog = gui_data.progress_window.window_progress.clone(); 27 | let stop_flag = gui_data.stop_flag.clone(); 28 | 29 | button_stop_in_dialog.connect_clicked(move |_a| { 30 | stop_dialog.set_title(Some(&format!("{} ({})", flg!("window_progress_title"), flg!("progress_stop_additional_message")))); 31 | send_stop_message(&stop_flag); 32 | }); 33 | } 34 | -------------------------------------------------------------------------------- /czkawka_gui/src/connect_things/connect_change_language.rs: -------------------------------------------------------------------------------- 1 | use gtk4::prelude::*; 2 | use i18n_embed::DesktopLanguageRequester; 3 | use i18n_embed::unic_langid::LanguageIdentifier; 4 | use log::error; 5 | 6 | use crate::language_functions::get_language_from_combo_box_text; 7 | use crate::{GuiData, LANGUAGES_ALL, localizer_gui}; 8 | 9 | // use i18n_embed::{DesktopLanguageRequester, Localizer}; 10 | 11 | pub fn connect_change_language(gui_data: &GuiData) { 12 | change_language(gui_data); 13 | 14 | let combo_box_settings_language = gui_data.settings.combo_box_settings_language.clone(); 15 | let gui_data = gui_data.clone(); 16 | combo_box_settings_language.connect_changed(move |_| { 17 | change_language(&gui_data); 18 | }); 19 | } 20 | 21 | fn change_language(gui_data: &GuiData) { 22 | let localizers = vec![ 23 | ("czkawka_core", czkawka_core::localizer_core::localizer_core()), 24 | ("czkawka_gui", localizer_gui::localizer_gui()), 25 | ]; 26 | 27 | let lang_short = get_language_from_combo_box_text(&gui_data.settings.combo_box_settings_language.active_text().expect("No active text")).short_text; 28 | 29 | let lang_identifier = vec![LanguageIdentifier::from_bytes(lang_short.as_bytes()).expect("Failed to create LanguageIdentifier")]; 30 | for (lib, localizer) in localizers { 31 | if let Err(error) = localizer.select(&lang_identifier) { 32 | error!("Error while loadings languages for {lib} {error:?}"); 33 | } 34 | } 35 | gui_data.update_language(); 36 | } 37 | 38 | pub fn load_system_language(gui_data: &GuiData) { 39 | let requested_languages = DesktopLanguageRequester::requested_languages(); 40 | 41 | if let Some(language) = requested_languages.first() { 42 | let old_short_lang = language.to_string(); 43 | let mut short_lang = String::new(); 44 | // removes from e.g. en_zb, ending _zd since Czkawka don't support this(maybe could add this in future, but only when) 45 | for i in old_short_lang.chars() { 46 | if i.is_ascii_alphabetic() { 47 | short_lang.push(i); 48 | } else { 49 | break; 50 | } 51 | } 52 | // let mut found: bool = false; 53 | for (index, lang) in LANGUAGES_ALL.iter().enumerate() { 54 | if lang.short_text == short_lang { 55 | // found = true; 56 | gui_data.settings.combo_box_settings_language.set_active(Some(index as u32)); 57 | break; 58 | } 59 | } 60 | // if found { 61 | // println!("INFO: Default system language {} is available, so choosing them", short_lang); 62 | // } else { 63 | // println!("INFO: Default system language {} is not available, using English(en) instead", short_lang); 64 | // } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /czkawka_gui/src/connect_things/connect_duplicate_buttons.rs: -------------------------------------------------------------------------------- 1 | use czkawka_core::common_dir_traversal::CheckingMethod; 2 | use gtk4::prelude::*; 3 | 4 | use crate::gui_structs::gui_data::GuiData; 5 | use crate::help_combo_box::DUPLICATES_CHECK_METHOD_COMBO_BOX; 6 | 7 | pub fn connect_duplicate_combo_box(gui_data: &GuiData) { 8 | let combo_box_duplicate_check_method = gui_data.main_notebook.combo_box_duplicate_check_method.clone(); 9 | let combo_box_duplicate_hash_type = gui_data.main_notebook.combo_box_duplicate_hash_type.clone(); 10 | let label_duplicate_hash_type = gui_data.main_notebook.label_duplicate_hash_type.clone(); 11 | let check_button_duplicate_case_sensitive_name = gui_data.main_notebook.check_button_duplicate_case_sensitive_name.clone(); 12 | combo_box_duplicate_check_method.connect_changed(move |combo_box_duplicate_check_method| { 13 | // None active can be if when adding elements(this signal is activated when e.g. adding new fields or removing them) 14 | if let Some(chosen_index) = combo_box_duplicate_check_method.active() { 15 | if DUPLICATES_CHECK_METHOD_COMBO_BOX[chosen_index as usize].check_method == CheckingMethod::Hash { 16 | combo_box_duplicate_hash_type.set_visible(true); 17 | label_duplicate_hash_type.set_visible(true); 18 | } else { 19 | combo_box_duplicate_hash_type.set_visible(false); 20 | label_duplicate_hash_type.set_visible(false); 21 | } 22 | 23 | if [CheckingMethod::Name, CheckingMethod::SizeName].contains(&DUPLICATES_CHECK_METHOD_COMBO_BOX[chosen_index as usize].check_method) { 24 | check_button_duplicate_case_sensitive_name.set_visible(true); 25 | } else { 26 | check_button_duplicate_case_sensitive_name.set_visible(false); 27 | } 28 | } 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /czkawka_gui/src/connect_things/connect_header_buttons.rs: -------------------------------------------------------------------------------- 1 | use gtk4::prelude::*; 2 | 3 | use crate::gui_structs::gui_data::GuiData; 4 | 5 | pub fn connect_button_about(gui_data: &GuiData) { 6 | let about_dialog = gui_data.about.about_dialog.clone(); 7 | let button_app_info = gui_data.header.button_app_info.clone(); 8 | button_app_info.connect_clicked(move |_| { 9 | about_dialog.show(); 10 | 11 | // Prevent from deleting dialog after close 12 | about_dialog.connect_close_request(|dialog| { 13 | dialog.hide(); 14 | glib::Propagation::Stop 15 | }); 16 | }); 17 | } 18 | -------------------------------------------------------------------------------- /czkawka_gui/src/connect_things/connect_notebook_tabs.rs: -------------------------------------------------------------------------------- 1 | use crate::gui_structs::gui_data::GuiData; 2 | use crate::help_functions::*; 3 | use crate::notebook_enums::*; 4 | 5 | pub fn connect_notebook_tabs(gui_data: &GuiData) { 6 | let shared_buttons = gui_data.shared_buttons.clone(); 7 | let buttons_array = gui_data.bottom_buttons.buttons_array.clone(); 8 | let notebook_main_clone = gui_data.main_notebook.notebook_main.clone(); 9 | let buttons_names = gui_data.bottom_buttons.buttons_names; 10 | 11 | notebook_main_clone.connect_switch_page(move |_, _, number| { 12 | let current_tab_in_main_notebook = to_notebook_main_enum(number); 13 | 14 | // Buttons 15 | set_buttons( 16 | &mut *shared_buttons.borrow_mut().get_mut(¤t_tab_in_main_notebook).expect("Failed to get current tab"), 17 | &buttons_array, 18 | &buttons_names, 19 | ); 20 | }); 21 | } 22 | -------------------------------------------------------------------------------- /czkawka_gui/src/connect_things/connect_show_hide_ui.rs: -------------------------------------------------------------------------------- 1 | use gtk4::prelude::*; 2 | 3 | use crate::gui_structs::gui_data::GuiData; 4 | 5 | pub fn connect_show_hide_ui(gui_data: &GuiData) { 6 | let check_button_settings_show_text_view = gui_data.settings.check_button_settings_show_text_view.clone(); 7 | let buttons_show_errors = gui_data.bottom_buttons.buttons_show_errors.clone(); 8 | let scrolled_window_errors = gui_data.scrolled_window_errors.clone(); 9 | 10 | buttons_show_errors.connect_clicked(move |_| { 11 | if scrolled_window_errors.is_visible() { 12 | scrolled_window_errors.hide(); 13 | check_button_settings_show_text_view.set_active(false); 14 | } else { 15 | scrolled_window_errors.show(); 16 | check_button_settings_show_text_view.set_active(true); 17 | } 18 | }); 19 | 20 | let buttons_show_upper_notebook = gui_data.bottom_buttons.buttons_show_upper_notebook.clone(); 21 | let notebook_upper = gui_data.upper_notebook.notebook_upper.clone(); 22 | 23 | buttons_show_upper_notebook.connect_clicked(move |_| { 24 | if notebook_upper.is_visible() { 25 | notebook_upper.hide(); 26 | } else { 27 | notebook_upper.show(); 28 | } 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /czkawka_gui/src/connect_things/connect_similar_image_size_change.rs: -------------------------------------------------------------------------------- 1 | use czkawka_core::tools::similar_images::{SIMILAR_VALUES, get_string_from_similarity}; 2 | use gtk4::prelude::*; 3 | 4 | use crate::gui_structs::gui_data::GuiData; 5 | use crate::help_combo_box::IMAGES_HASH_SIZE_COMBO_BOX; 6 | 7 | pub fn connect_similar_image_size_change(gui_data: &GuiData) { 8 | let label_similar_images_minimal_similarity = gui_data.main_notebook.label_similar_images_minimal_similarity.clone(); 9 | label_similar_images_minimal_similarity.set_text(&get_string_from_similarity(&SIMILAR_VALUES[0][5], 8)); 10 | 11 | let combo_box_image_hash_size = gui_data.main_notebook.combo_box_image_hash_size.clone(); 12 | let label_similar_images_minimal_similarity = gui_data.main_notebook.label_similar_images_minimal_similarity.clone(); 13 | let scale_similarity_similar_images = gui_data.main_notebook.scale_similarity_similar_images.clone(); 14 | combo_box_image_hash_size.connect_changed(move |combo_box_image_hash_size| { 15 | let hash_size_index = combo_box_image_hash_size.active().expect("Failed to get active item") as usize; 16 | let hash_size = IMAGES_HASH_SIZE_COMBO_BOX[hash_size_index]; 17 | 18 | let index = match hash_size { 19 | 8 => 0, 20 | 16 => 1, 21 | 32 => 2, 22 | 64 => 3, 23 | _ => panic!(), 24 | }; 25 | 26 | scale_similarity_similar_images.set_range(0_f64, SIMILAR_VALUES[index][5] as f64); 27 | scale_similarity_similar_images.set_fill_level(SIMILAR_VALUES[index][5] as f64); 28 | label_similar_images_minimal_similarity.set_text(&get_string_from_similarity(&SIMILAR_VALUES[index][5], hash_size as u8)); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /czkawka_gui/src/connect_things/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod connect_about_buttons; 2 | pub mod connect_button_compare; 3 | pub mod connect_button_delete; 4 | pub mod connect_button_hardlink; 5 | pub mod connect_button_move; 6 | pub mod connect_button_save; 7 | pub mod connect_button_search; 8 | pub mod connect_button_select; 9 | pub mod connect_button_sort; 10 | pub mod connect_button_stop; 11 | pub mod connect_change_language; 12 | pub mod connect_duplicate_buttons; 13 | pub mod connect_header_buttons; 14 | pub mod connect_notebook_tabs; 15 | pub mod connect_popovers_select; 16 | pub mod connect_popovers_sort; 17 | pub mod connect_progress_window; 18 | pub mod connect_same_music_mode_changed; 19 | pub mod connect_selection_of_directories; 20 | pub mod connect_settings; 21 | pub mod connect_show_hide_ui; 22 | pub mod connect_similar_image_size_change; 23 | -------------------------------------------------------------------------------- /czkawka_gui/src/gui_structs/gui_header.rs: -------------------------------------------------------------------------------- 1 | use gtk4::prelude::*; 2 | 3 | use crate::help_functions::set_icon_of_button; 4 | use crate::{CZK_ICON_INFO, CZK_ICON_SETTINGS, flg}; 5 | 6 | #[derive(Clone)] 7 | pub struct GuiHeader { 8 | pub button_settings: gtk4::Button, 9 | pub button_app_info: gtk4::Button, 10 | } 11 | 12 | impl GuiHeader { 13 | pub fn create_from_builder(builder: >k4::Builder) -> Self { 14 | let button_settings: gtk4::Button = builder.object("button_settings").expect("Cambalache"); 15 | let button_app_info: gtk4::Button = builder.object("button_app_info").expect("Cambalache"); 16 | 17 | set_icon_of_button(&button_settings, CZK_ICON_SETTINGS); 18 | set_icon_of_button(&button_app_info, CZK_ICON_INFO); 19 | 20 | Self { button_settings, button_app_info } 21 | } 22 | 23 | pub fn update_language(&self) { 24 | self.button_settings.set_tooltip_text(Some(&flg!("header_setting_button_tooltip"))); 25 | self.button_app_info.set_tooltip_text(Some(&flg!("header_about_button_tooltip"))); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /czkawka_gui/src/gui_structs/gui_popovers_sort.rs: -------------------------------------------------------------------------------- 1 | use gtk4::Builder; 2 | use gtk4::prelude::*; 3 | 4 | use crate::flg; 5 | 6 | #[derive(Clone)] 7 | pub struct GuiSortPopovers { 8 | pub buttons_popover_sort_file_name: gtk4::Button, 9 | pub buttons_popover_sort_folder_name: gtk4::Button, 10 | pub buttons_popover_sort_full_name: gtk4::Button, 11 | pub buttons_popover_sort_size: gtk4::Button, 12 | pub buttons_popover_sort_selection: gtk4::Button, 13 | 14 | pub popover_sort: gtk4::Popover, 15 | } 16 | 17 | impl GuiSortPopovers { 18 | pub fn create_from_builder() -> Self { 19 | let glade_src = include_str!("../../ui/popover_sort.ui").to_string(); 20 | let builder = Builder::from_string(glade_src.as_str()); 21 | 22 | let buttons_popover_sort_file_name: gtk4::Button = builder.object("buttons_popover_sort_file_name").expect("Cambalache"); 23 | let buttons_popover_sort_folder_name: gtk4::Button = builder.object("buttons_popover_sort_folder_name").expect("Cambalache"); 24 | let buttons_popover_sort_full_name: gtk4::Button = builder.object("buttons_popover_sort_full_name").expect("Cambalache"); 25 | let buttons_popover_sort_size: gtk4::Button = builder.object("buttons_popover_sort_size").expect("Cambalache"); 26 | let buttons_popover_sort_selection: gtk4::Button = builder.object("buttons_popover_sort_selection").expect("Cambalache"); 27 | 28 | let popover_sort: gtk4::Popover = builder.object("popover_sort").expect("Cambalache"); 29 | 30 | Self { 31 | buttons_popover_sort_file_name, 32 | buttons_popover_sort_folder_name, 33 | buttons_popover_sort_full_name, 34 | buttons_popover_sort_size, 35 | buttons_popover_sort_selection, 36 | popover_sort, 37 | } 38 | } 39 | pub fn update_language(&self) { 40 | self.buttons_popover_sort_file_name.set_label(&flg!("popover_sort_file_name")); 41 | self.buttons_popover_sort_folder_name.set_label(&flg!("popover_sort_folder_name")); 42 | self.buttons_popover_sort_full_name.set_label(&flg!("popover_sort_full_name")); 43 | self.buttons_popover_sort_size.set_label(&flg!("popover_sort_size")); 44 | self.buttons_popover_sort_selection.set_label(&flg!("popover_sort_selection")); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /czkawka_gui/src/gui_structs/gui_progress_dialog.rs: -------------------------------------------------------------------------------- 1 | use gtk4::prelude::*; 2 | use gtk4::{Builder, EventControllerKey, Window}; 3 | 4 | use crate::help_functions::{get_custom_label_from_widget, set_icon_of_button}; 5 | use crate::{CZK_ICON_STOP, flg}; 6 | 7 | #[derive(Clone)] 8 | pub struct GuiProgressDialog { 9 | pub window_progress: gtk4::Dialog, 10 | 11 | pub progress_bar_current_stage: gtk4::ProgressBar, 12 | pub progress_bar_all_stages: gtk4::ProgressBar, 13 | 14 | pub label_stage: gtk4::Label, 15 | pub label_progress_current_stage: gtk4::Label, 16 | pub label_progress_all_stages: gtk4::Label, 17 | 18 | pub grid_progress: gtk4::Grid, 19 | 20 | pub button_stop_in_dialog: gtk4::Button, 21 | pub evk_button_stop_in_dialog: EventControllerKey, 22 | } 23 | 24 | impl GuiProgressDialog { 25 | pub fn create_from_builder(window_main: &Window) -> Self { 26 | let glade_src = include_str!("../../ui/progress.ui").to_string(); 27 | let builder = Builder::from_string(glade_src.as_str()); 28 | 29 | let window_progress: gtk4::Dialog = builder.object("window_progress").expect("Cambalache"); 30 | window_progress.set_title(Some(&flg!("window_progress_title"))); 31 | window_progress.set_transient_for(Some(window_main)); 32 | window_progress.set_modal(true); 33 | 34 | let progress_bar_current_stage: gtk4::ProgressBar = builder.object("progress_bar_current_stage").expect("Cambalache"); 35 | let progress_bar_all_stages: gtk4::ProgressBar = builder.object("progress_bar_all_stages").expect("Cambalache"); 36 | 37 | let label_stage: gtk4::Label = builder.object("label_stage").expect("Cambalache"); 38 | let label_progress_current_stage: gtk4::Label = builder.object("label_progress_current_stage").expect("Cambalache"); 39 | let label_progress_all_stages: gtk4::Label = builder.object("label_progress_all_stages").expect("Cambalache"); 40 | 41 | let grid_progress: gtk4::Grid = builder.object("grid_progress").expect("Cambalache"); 42 | 43 | let button_stop_in_dialog: gtk4::Button = builder.object("button_stop_in_dialog").expect("Cambalache"); 44 | let evk_button_stop_in_dialog = EventControllerKey::new(); 45 | button_stop_in_dialog.add_controller(evk_button_stop_in_dialog.clone()); 46 | 47 | set_icon_of_button(&button_stop_in_dialog, CZK_ICON_STOP); 48 | 49 | Self { 50 | window_progress, 51 | progress_bar_current_stage, 52 | progress_bar_all_stages, 53 | label_stage, 54 | label_progress_current_stage, 55 | label_progress_all_stages, 56 | grid_progress, 57 | button_stop_in_dialog, 58 | evk_button_stop_in_dialog, 59 | } 60 | } 61 | pub fn update_language(&self) { 62 | self.window_progress.set_title(Some(&flg!("window_progress_title"))); 63 | 64 | get_custom_label_from_widget(&self.button_stop_in_dialog.clone()).set_text(&flg!("progress_stop_button")); 65 | 66 | self.label_progress_current_stage.set_label(&flg!("progress_current_stage")); 67 | self.label_progress_all_stages.set_label(&flg!("progress_all_stages")); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /czkawka_gui/src/gui_structs/mod.rs: -------------------------------------------------------------------------------- 1 | mod gui_about; 2 | mod gui_bottom_buttons; 3 | mod gui_compare_images; 4 | pub mod gui_data; 5 | mod gui_header; 6 | pub mod gui_main_notebook; 7 | pub mod gui_popovers_select; 8 | pub mod gui_popovers_sort; 9 | mod gui_progress_dialog; 10 | pub mod gui_settings; 11 | pub mod gui_upper_notebook; 12 | -------------------------------------------------------------------------------- /czkawka_gui/src/language_functions.rs: -------------------------------------------------------------------------------- 1 | #[derive(Clone)] 2 | pub struct Language { 3 | pub combo_box_text: &'static str, 4 | pub short_text: &'static str, 5 | } 6 | 7 | pub const LANGUAGES_ALL: &[Language] = &[ 8 | Language { 9 | combo_box_text: "English", 10 | short_text: "en", 11 | }, 12 | Language { 13 | combo_box_text: "Français (French)", 14 | short_text: "fr", 15 | }, 16 | Language { 17 | combo_box_text: "Italiano (Italian)", 18 | short_text: "it", 19 | }, 20 | Language { 21 | combo_box_text: "Polski (Polish)", 22 | short_text: "pl", 23 | }, 24 | Language { 25 | combo_box_text: "Русский (Russian)", 26 | short_text: "ru", 27 | }, 28 | Language { 29 | combo_box_text: "український (Ukrainian)", 30 | short_text: "uk", 31 | }, 32 | Language { 33 | combo_box_text: "한국인 (Korean)", 34 | short_text: "ko", 35 | }, 36 | Language { 37 | combo_box_text: "Česky (Czech)", 38 | short_text: "cs", 39 | }, 40 | Language { 41 | combo_box_text: "Deutsch (German)", 42 | short_text: "de", 43 | }, 44 | Language { 45 | combo_box_text: "やまと (Japanese)", 46 | short_text: "ja", 47 | }, 48 | Language { 49 | combo_box_text: "Português (Portuguese)", 50 | short_text: "pt-PT", 51 | }, 52 | Language { 53 | combo_box_text: "Português Brasileiro (Brazilian Portuguese)", 54 | short_text: "pt-BR", 55 | }, 56 | Language { 57 | combo_box_text: "简体中文 (Simplified Chinese)", 58 | short_text: "zh-CN", 59 | }, 60 | Language { 61 | combo_box_text: "繁體中文 (Traditional Chinese)", 62 | short_text: "zh-TW", 63 | }, 64 | Language { 65 | combo_box_text: "Español (Spanish)", 66 | short_text: "es-ES", 67 | }, 68 | Language { 69 | combo_box_text: "Norsk (Norwegian)", 70 | short_text: "no", 71 | }, 72 | Language { 73 | combo_box_text: "Swedish (Svenska)", 74 | short_text: "sv-SE", 75 | }, 76 | Language { 77 | combo_box_text: "المملكة العربية السعودية (Saudi Arabia)", 78 | short_text: "ar", 79 | }, 80 | Language { 81 | combo_box_text: "България (Bulgaria)", 82 | short_text: "bg", 83 | }, 84 | Language { 85 | combo_box_text: "Ελλάδα (Greece)", 86 | short_text: "el", 87 | }, 88 | Language { 89 | combo_box_text: "Nederland (Netherlands)", 90 | short_text: "nl", 91 | }, 92 | Language { 93 | combo_box_text: "România (Romania)", 94 | short_text: "ro", 95 | }, 96 | ]; 97 | 98 | pub fn get_language_from_combo_box_text(combo_box_text: &str) -> Language { 99 | for lang in LANGUAGES_ALL { 100 | if lang.combo_box_text == combo_box_text { 101 | return lang.clone(); 102 | } 103 | } 104 | 105 | panic!("Not found proper text"); 106 | } 107 | -------------------------------------------------------------------------------- /czkawka_gui/src/localizer_gui.rs: -------------------------------------------------------------------------------- 1 | use i18n_embed::fluent::{FluentLanguageLoader, fluent_language_loader}; 2 | use i18n_embed::{DefaultLocalizer, LanguageLoader, Localizer}; 3 | use once_cell::sync::Lazy; 4 | use rust_embed::RustEmbed; 5 | 6 | #[derive(RustEmbed)] 7 | #[folder = "i18n/"] 8 | struct Localizations; 9 | 10 | pub static LANGUAGE_LOADER_GUI: Lazy = Lazy::new(|| { 11 | let loader: FluentLanguageLoader = fluent_language_loader!(); 12 | 13 | loader.load_fallback_language(&Localizations).expect("Error while loading fallback language"); 14 | 15 | loader 16 | }); 17 | 18 | #[macro_export] 19 | macro_rules! flg { 20 | ($message_id:literal) => {{ 21 | i18n_embed_fl::fl!($crate::localizer_gui::LANGUAGE_LOADER_GUI, $message_id) 22 | }}; 23 | 24 | ($message_id:literal, $($args:expr),*) => {{ 25 | i18n_embed_fl::fl!($crate::localizer_gui::LANGUAGE_LOADER_GUI, $message_id, $($args), *) 26 | }}; 27 | } 28 | 29 | // Get the `Localizer` to be used for localizing this library. 30 | pub fn localizer_gui() -> Box { 31 | Box::from(DefaultLocalizer::new(&*LANGUAGE_LOADER_GUI, &Localizations)) 32 | } 33 | -------------------------------------------------------------------------------- /czkawka_gui/src/notebook_enums.rs: -------------------------------------------------------------------------------- 1 | use czkawka_core::TOOLS_NUMBER; 2 | 3 | pub const NUMBER_OF_NOTEBOOK_MAIN_TABS: usize = TOOLS_NUMBER; 4 | // pub const NUMBER_OF_NOTEBOOK_UPPER_TABS: usize = 3; 5 | 6 | // Needs to be updated when changed order of notebook tabs 7 | #[derive(Eq, PartialEq, Hash, Clone, Debug, Copy)] 8 | pub enum NotebookMainEnum { 9 | Duplicate = 0, 10 | EmptyDirectories, 11 | BigFiles, 12 | EmptyFiles, 13 | Temporary, 14 | SimilarImages, 15 | SimilarVideos, 16 | SameMusic, 17 | Symlinks, 18 | BrokenFiles, 19 | BadExtensions, 20 | } 21 | 22 | pub fn to_notebook_main_enum(notebook_number: u32) -> NotebookMainEnum { 23 | match notebook_number { 24 | 0 => NotebookMainEnum::Duplicate, 25 | 1 => NotebookMainEnum::EmptyDirectories, 26 | 2 => NotebookMainEnum::BigFiles, 27 | 3 => NotebookMainEnum::EmptyFiles, 28 | 4 => NotebookMainEnum::Temporary, 29 | 5 => NotebookMainEnum::SimilarImages, 30 | 6 => NotebookMainEnum::SimilarVideos, 31 | 7 => NotebookMainEnum::SameMusic, 32 | 8 => NotebookMainEnum::Symlinks, 33 | 9 => NotebookMainEnum::BrokenFiles, 34 | 10 => NotebookMainEnum::BadExtensions, 35 | _ => panic!("Invalid Notebook Tab"), 36 | } 37 | } 38 | 39 | pub fn get_all_main_tabs() -> [NotebookMainEnum; NUMBER_OF_NOTEBOOK_MAIN_TABS] { 40 | [ 41 | to_notebook_main_enum(0), 42 | to_notebook_main_enum(1), 43 | to_notebook_main_enum(2), 44 | to_notebook_main_enum(3), 45 | to_notebook_main_enum(4), 46 | to_notebook_main_enum(5), 47 | to_notebook_main_enum(6), 48 | to_notebook_main_enum(7), 49 | to_notebook_main_enum(8), 50 | to_notebook_main_enum(9), 51 | to_notebook_main_enum(10), 52 | ] 53 | } 54 | 55 | #[derive(Eq, PartialEq, Hash, Clone, Debug, Copy)] 56 | pub enum NotebookUpperEnum { 57 | IncludedDirectories = 0, 58 | ExcludedDirectories, 59 | ItemsConfiguration, 60 | } 61 | 62 | pub fn to_notebook_upper_enum(notebook_number: u32) -> NotebookUpperEnum { 63 | match notebook_number { 64 | 0 => NotebookUpperEnum::IncludedDirectories, 65 | 1 => NotebookUpperEnum::ExcludedDirectories, 66 | 2 => NotebookUpperEnum::ItemsConfiguration, 67 | _ => panic!("Invalid Upper Notebook Tab"), 68 | } 69 | } 70 | 71 | // pub fn get_all_upper_tabs() -> [NotebookUpperEnum; NUMBER_OF_NOTEBOOK_UPPER_TABS] { 72 | // [to_notebook_upper_enum(0), to_notebook_upper_enum(1), to_notebook_upper_enum(2)] 73 | // } 74 | -------------------------------------------------------------------------------- /czkawka_gui/src/taskbar_progress.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_os = "windows"))] 2 | pub use crate::taskbar_progress_dummy::{TaskbarProgress, tbp_flags}; 3 | #[cfg(target_os = "windows")] 4 | pub use crate::taskbar_progress_win::{TaskbarProgress, tbp_flags}; 5 | -------------------------------------------------------------------------------- /czkawka_gui/src/taskbar_progress_dummy.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::upper_case_acronyms)] 2 | #![allow(clippy::needless_pass_by_value)] 3 | #![allow(clippy::pedantic)] 4 | #![cfg(not(target_os = "windows"))] 5 | 6 | use std::convert::From; 7 | 8 | enum HWND__ {} 9 | 10 | type HWND = *mut HWND__; 11 | 12 | #[allow(non_camel_case_types, dead_code)] 13 | pub enum TBPFLAG { 14 | TBPF_NOPROGRESS = 0, 15 | TBPF_INDETERMINATE = 0x1, 16 | TBPF_NORMAL = 0x2, 17 | TBPF_ERROR = 0x4, 18 | TBPF_PAUSED = 0x8, 19 | } 20 | 21 | pub mod tbp_flags { 22 | pub use super::TBPFLAG::*; 23 | } 24 | 25 | pub struct TaskbarProgress {} 26 | 27 | impl TaskbarProgress { 28 | pub fn new() -> Self { 29 | Self {} 30 | } 31 | 32 | pub fn set_progress_state(&self, _tbp_flags: TBPFLAG) {} 33 | 34 | pub fn set_progress_value(&self, _completed: u64, _total: u64) {} 35 | 36 | pub fn hide(&self) {} 37 | 38 | pub fn show(&self) {} 39 | 40 | #[allow(clippy::needless_pass_by_ref_mut)] 41 | pub fn release(&mut self) {} 42 | } 43 | 44 | impl From for TaskbarProgress { 45 | fn from(_hwnd: HWND) -> Self { 46 | Self {} 47 | } 48 | } 49 | 50 | impl Drop for TaskbarProgress { 51 | fn drop(&mut self) {} 52 | } 53 | -------------------------------------------------------------------------------- /czkawka_gui/src/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::GuiData; 2 | use crate::help_functions::get_notebook_enum_from_tree_view; 3 | use crate::notebook_enums::to_notebook_main_enum; 4 | use crate::notebook_info::NOTEBOOKS_INFO; 5 | 6 | pub fn validate_notebook_data(gui_data: &GuiData) { 7 | // Test treeviews names, each treeview should have set name same as variable name 8 | 9 | for item in &gui_data.main_notebook.get_main_tree_views() { 10 | // println!("Checking {} element", i); 11 | 12 | get_notebook_enum_from_tree_view(item); 13 | } 14 | 15 | // This test main info about notebooks 16 | // Should have same order as notebook enum types 17 | for (i, item) in NOTEBOOKS_INFO.iter().enumerate() { 18 | let en = to_notebook_main_enum(i as u32); 19 | assert_eq!(item.notebook_type, en); 20 | } 21 | 22 | // Tests if data returned from array get_notebook_enum_from_tree_view are in right 23 | for (i, item) in gui_data.main_notebook.get_main_tree_views().iter().enumerate() { 24 | let nb_en = get_notebook_enum_from_tree_view(item); 25 | assert_eq!(to_notebook_main_enum(i as u32), nb_en); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /czkawka_gui/ui/about_dialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 2020 - 2025 8 | Rafał Mikrut (qarmin) and contributors 9 | This program is free to use and will always be. 10 | App is now in maintenance mode, so check Krokiet, the sucessor of Czkawka. 11 | 12 | mit-x11 13 | help-about-symbolic 14 | Czkawka 15 | 9.0.0 16 | 17 | 18 | -------------------------------------------------------------------------------- /czkawka_gui/ui/compare_images.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | vertical 10 | 1 11 | 12 | 13 | 14 | 15 | 1 16 | 1 17 | 18 | 19 | image-missing 20 | 21 | 22 | 23 | 24 | 25 | 26 | center 27 | 1 28 | Group XD/PER XD (99 images in current group) 29 | 30 | 31 | 32 | 33 | 1 34 | 1 35 | 36 | 37 | image-missing 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 1 47 | 48 | 49 | 1 50 | First Game 51 | 52 | 53 | 54 | 55 | 1 56 | Second Game 57 | 58 | 59 | 60 | 61 | 62 | 63 | 1 64 | 1 65 | 66 | 67 | 100 68 | 69 | 70 | 71 | 72 | 100 73 | 74 | 75 | 76 | 77 | 78 | 79 | 1 80 | 150 81 | 150 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /czkawka_gui/ui/popover_right_click.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | vertical 10 | 11 | 12 | 1 13 | Open File 14 | 1 15 | 16 | 17 | 18 | 19 | 1 20 | Open Folder 21 | 1 22 | 23 | 24 | 25 | 26 | left 27 | 28 | 29 | -------------------------------------------------------------------------------- /czkawka_gui/ui/popover_sort.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | vertical 10 | 11 | 12 | 1 13 | File name 14 | 1 15 | 16 | 17 | 18 | 19 | 1 20 | Folder name 21 | 1 22 | 23 | 24 | 25 | 26 | 1 27 | Full name 28 | 1 29 | 30 | 31 | 32 | 33 | 1 34 | Size 35 | 1 36 | 37 | 38 | 39 | 40 | 1 41 | Selection 42 | 1 43 | 44 | 45 | 46 | 47 | top 48 | 49 | 50 | -------------------------------------------------------------------------------- /data/com.github.qarmin.czkawka.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Terminal=false 4 | Exec=czkawka_gui 5 | Name=Czkawka 6 | Name[it]=Singhiozzo 7 | Comment=Multi functional app to clean OS which allow to find duplicates, empty folders, similar files etc. 8 | Comment[it]=Programma multifunzionale per pulire il sistema, che permette di trovare file duplicati, cartelle vuote, file simili, ecc... 9 | Comment[zh_CN]=可用于清理文件副本、空文件夹、相似文件等的系统清理工具 10 | Comment[zh_TW]=可用於清理重複檔案、空資料夾、相似檔案等的系統清理工具 11 | Icon=com.github.qarmin.czkawka 12 | Categories=System;FileTools 13 | Keywords=Hiccup;duplicate;same;similar;cleaner 14 | StartupWMClass=czkawka_gui 15 | TryExec=czkawka_gui 16 | -------------------------------------------------------------------------------- /data/com.github.qarmin.czkawka.metainfo.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.github.qarmin.czkawka 4 | Czkawka 5 | Multi functional app to find duplicates, empty folders, similar images, broken files etc. 6 | CC0-1.0 7 | MIT 8 | 9 |

10 | Czkawka is simple, fast and easy to use app to remove unnecessary files from your computer. 11 |

12 |
13 | com.github.qarmin.czkawka.desktop 14 | 15 | 16 | https://user-images.githubusercontent.com/41945903/147875238-7f82fa27-c6dd-47e7-87ed-e253fb2cbc3e.png 17 | 18 | 19 | https://user-images.githubusercontent.com/41945903/147875239-bcf9776c-885d-45ac-ba82-5a426d8e1647.png 20 | 21 | 22 | https://user-images.githubusercontent.com/41945903/147875243-e654e683-37f7-46fa-8321-119a4c5775e7.png 23 | 24 | 25 | 26 | 27 | 28 | 29 | Rafał Mikrut 30 | 31 | Rafał Mikrut 32 | 33 | https://github.com/qarmin/czkawka 34 | https://github.com/qarmin/czkawka/issues 35 | https://github.com/sponsors/qarmin 36 | https://crowdin.com/project/czkawka 37 |
38 | -------------------------------------------------------------------------------- /krokiet/.clippy.toml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qarmin/czkawka/2be42d9478501a90c36e8b1002fa3c7e5cb5ad2d/krokiet/.clippy.toml -------------------------------------------------------------------------------- /krokiet/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "krokiet" 3 | version = "9.0.0" 4 | authors = ["Rafał Mikrut "] 5 | edition = "2024" 6 | rust-version = "1.85.0" 7 | description = "Slint frontend of Czkawka Core" 8 | license = "GPL-3.0-only" 9 | homepage = "https://github.com/qarmin/czkawka" 10 | repository = "https://github.com/qarmin/czkawka" 11 | build = "build.rs" 12 | 13 | [dependencies] 14 | czkawka_core = { version = "9.0.0", path = "../czkawka_core" } 15 | chrono = "0.4.38" 16 | open = "5.3" 17 | crossbeam-channel = "0.5" 18 | rfd = { version = "0.15", default-features = false, features = ["xdg-portal", "async-std"] } 19 | home = "0.5" 20 | log = "0.4.22" 21 | serde = "1.0" 22 | serde_json = "1.0" 23 | humansize = "2.1" 24 | image = "0.25" 25 | image_hasher = "3.0" 26 | rayon = "1.10" 27 | fs_extra = "1.3" # TODO replace with less buggy library 28 | trash = "5.1" 29 | 30 | # Translations 31 | i18n-embed = { version = "0.15", features = ["fluent-system", "desktop-requester"] } 32 | i18n-embed-fl = "0.9" 33 | rust-embed = { version = "8.5", features = ["debug-embed"] } 34 | once_cell = "1.20" 35 | 36 | # Try to use only needed features from https://github.com/slint-ui/slint/blob/master/api/rs/slint/Cargo.toml#L23-L31 37 | #slint = { path = "/home/rafal/test/slint/api/rs/slint/", default-features = false, features = ["std", 38 | #slint = { git = "https://github.com/slint-ui/slint.git", default-features = false, features = [ 39 | slint = { version = "1.10", default-features = false, features = [ 40 | "std", 41 | "backend-winit", 42 | "compat-1-2" 43 | ] } 44 | [build-dependencies] 45 | #slint-build = { path = "/home/rafal/test/slint/api/rs/build/"} 46 | #slint-build = { git = "https://github.com/slint-ui/slint.git" } 47 | slint-build = "1.8" 48 | 49 | [features] 50 | default = ["winit_femtovg", "winit_software"] 51 | skia_opengl = ["slint/renderer-skia-opengl"] 52 | skia_vulkan = ["slint/renderer-skia-vulkan"] 53 | software = ["slint/renderer-software"] 54 | femtovg = ["slint/renderer-femtovg"] 55 | winit_femtovg = ["slint/renderer-winit-femtovg"] 56 | winit_skia_opengl = ["slint/renderer-winit-skia-opengl"] 57 | winit_skia_vulkan = ["slint/renderer-winit-skia-vulkan"] 58 | winit_software = ["slint/renderer-winit-software"] 59 | 60 | heif = ["czkawka_core/heif"] 61 | libraw = ["czkawka_core/libraw"] 62 | libavif = ["czkawka_core/libavif"] 63 | fast_image_resize = ["czkawka_core/fast_image_resize"] 64 | -------------------------------------------------------------------------------- /krokiet/LICENSE_MIT_CODE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2025 Rafał Mikrut 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /krokiet/build.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | fn main() { 4 | if env::var("SLINT_STYLE").is_err() || env::var("SLINT_STYLE") == Ok(String::new()) { 5 | slint_build::compile_with_config("ui/main_window.slint", slint_build::CompilerConfiguration::new().with_style("fluent-dark".into())).expect("Unable to compile slint file"); 6 | } else { 7 | slint_build::compile("ui/main_window.slint").expect("Unable to compile slint file"); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /krokiet/i18n.toml: -------------------------------------------------------------------------------- 1 | # (Required) The language identifier of the language used in the 2 | # source code for gettext system, and the primary fallback language 3 | # (for which all strings must be present) when using the fluent 4 | # system. 5 | fallback_language = "en" 6 | 7 | # Use the fluent localization system. 8 | [fluent] 9 | # (Required) The path to the assets directory. 10 | # The paths inside the assets directory should be structured like so: 11 | # `assets_dir/{language}/{domain}.ftl` 12 | assets_dir = "i18n" 13 | 14 | -------------------------------------------------------------------------------- /krokiet/icons/krokiet_add.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 15 | 33 | 37 | 40 | 43 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /krokiet/icons/krokiet_delete.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /krokiet/icons/krokiet_dir.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /krokiet/icons/krokiet_info.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /krokiet/icons/krokiet_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qarmin/czkawka/2be42d9478501a90c36e8b1002fa3c7e5cb5ad2d/krokiet/icons/krokiet_logo.png -------------------------------------------------------------------------------- /krokiet/icons/krokiet_logo_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qarmin/czkawka/2be42d9478501a90c36e8b1002fa3c7e5cb5ad2d/krokiet/icons/krokiet_logo_small.png -------------------------------------------------------------------------------- /krokiet/icons/krokiet_manual_add.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 15 | 33 | 38 | 43 | 48 | 53 | 58 | 63 | 64 | -------------------------------------------------------------------------------- /krokiet/icons/krokiet_move.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /krokiet/icons/krokiet_remove.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 15 | 33 | 37 | 40 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /krokiet/icons/krokiet_rename.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /krokiet/icons/krokiet_save.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /krokiet/icons/krokiet_search.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /krokiet/icons/krokiet_select.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /krokiet/icons/krokiet_settings.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /krokiet/icons/krokiet_stop.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /krokiet/icons/krokiet_subsettings.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /krokiet/src/connect_open.rs: -------------------------------------------------------------------------------- 1 | use czkawka_core::common::get_config_cache_path; 2 | use log::error; 3 | use slint::ComponentHandle; 4 | 5 | use crate::{Callabler, MainWindow}; 6 | 7 | pub fn connect_open_items(app: &MainWindow) { 8 | app.global::().on_open_config_folder(move || { 9 | let Some(config_cache) = get_config_cache_path() else { 10 | error!("Failed to open config folder"); 11 | return; 12 | }; 13 | if let Err(e) = open::that(&config_cache.config_folder) { 14 | error!("Failed to open config folder \"{}\": {e}", config_cache.config_folder.to_string_lossy()); 15 | } 16 | }); 17 | 18 | app.global::().on_open_cache_folder(move || { 19 | let Some(config_cache) = get_config_cache_path() else { 20 | error!("Failed to open cache folder"); 21 | return; 22 | }; 23 | if let Err(e) = open::that(&config_cache.cache_folder) { 24 | error!("Failed to open cache folder \"{}\": {e}", config_cache.cache_folder.to_string_lossy()); 25 | } 26 | }); 27 | 28 | app.global::().on_open_link(move |link| { 29 | match open::that(link.as_str()) { 30 | Ok(()) => {} 31 | Err(e) => { 32 | error!("Failed to open link: {e}"); 33 | } 34 | }; 35 | }); 36 | } 37 | -------------------------------------------------------------------------------- /krokiet/src/connect_rename.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use std::path::{MAIN_SEPARATOR, Path}; 3 | 4 | use czkawka_core::common_messages::Messages; 5 | use slint::{ComponentHandle, ModelRc, VecModel}; 6 | 7 | use crate::common::{get_is_header_mode, get_tool_model, set_tool_model}; 8 | use crate::connect_row_selection::reset_selection; 9 | use crate::model_operations::{collect_path_name_and_proper_extension_from_model, deselect_all_items, filter_out_checked_items}; 10 | use crate::{Callabler, CurrentTab, GuiState, MainListModel, MainWindow, flk}; 11 | 12 | pub fn connect_rename(app: &MainWindow) { 13 | let a = app.as_weak(); 14 | app.global::().on_rename_files(move || { 15 | let app = a.upgrade().expect("Failed to upgrade app :("); 16 | let active_tab = app.global::().get_active_tab(); 17 | let current_model = get_tool_model(&app, active_tab); 18 | 19 | let (errors, new_model) = rename_operation(¤t_model, active_tab); 20 | if let Some(new_model) = new_model { 21 | set_tool_model(&app, active_tab, new_model); 22 | } 23 | app.global::().set_info_text(Messages::new_from_errors(errors).create_messages_text().into()); 24 | reset_selection(&app, true); 25 | }); 26 | } 27 | 28 | fn rename_operation(items: &ModelRc, active_tab: CurrentTab) -> (Vec, Option>) { 29 | assert_eq!(active_tab, CurrentTab::BadExtensions); 30 | let (entries_to_move, mut entries_left) = filter_out_checked_items(items, get_is_header_mode(active_tab)); 31 | 32 | if !entries_to_move.is_empty() { 33 | let vec_items_to_rename = collect_path_name_and_proper_extension_from_model(&entries_to_move, active_tab); 34 | let errors = rename_selected_items(vec_items_to_rename); 35 | deselect_all_items(&mut entries_left); 36 | 37 | let r = ModelRc::new(VecModel::from(entries_left)); 38 | return (errors, Some(r)); 39 | } 40 | (vec![], None) 41 | } 42 | 43 | fn rename_selected_items(files_with_new_extensions: Vec<(String, String, String)>) -> Vec { 44 | let mut errors = vec![]; 45 | for (folder, file_name, new_extension) in files_with_new_extensions { 46 | let file_stem = Path::new(&file_name).file_stem().map(|e| e.to_string_lossy().to_string()).unwrap_or_default(); 47 | let new_full_path = format!("{folder}{MAIN_SEPARATOR}{file_stem}.{new_extension}"); 48 | let old_full_path = format!("{folder}{MAIN_SEPARATOR}{file_name}"); 49 | if let Err(e) = fs::rename(&old_full_path, &new_full_path) { 50 | errors.push(flk!( 51 | "rust_failed_to_rename_file", 52 | old_path = old_full_path, 53 | new_path = new_full_path, 54 | error = e.to_string() 55 | )); 56 | } 57 | } 58 | errors 59 | } 60 | -------------------------------------------------------------------------------- /krokiet/src/connect_save.rs: -------------------------------------------------------------------------------- 1 | use std::sync::{Arc, Mutex}; 2 | 3 | use rfd::FileDialog; 4 | use slint::ComponentHandle; 5 | 6 | use crate::shared_models::SharedModels; 7 | use crate::{Callabler, GuiState, MainWindow}; 8 | 9 | pub fn connect_save(app: &MainWindow, shared_models: Arc>) { 10 | let a = app.as_weak(); 11 | app.global::().on_save_results(move || { 12 | let app = a.upgrade().expect("Failed to upgrade app :("); 13 | let active_tab = app.global::().get_active_tab(); 14 | 15 | let file_dialog = FileDialog::new(); 16 | let Some(folder) = file_dialog.pick_folder() else { 17 | return; 18 | }; 19 | let folder_str = folder.to_string_lossy(); 20 | if let Err(e) = shared_models.lock().unwrap().save_results(active_tab, &folder_str) { 21 | app.global::().set_info_text(e.into()); 22 | } 23 | }); 24 | } 25 | -------------------------------------------------------------------------------- /krokiet/src/connect_show_preview.rs: -------------------------------------------------------------------------------- 1 | use std::path::Path; 2 | use std::time::{Duration, Instant}; 3 | 4 | use czkawka_core::common_image::{check_if_can_display_image, get_dynamic_image_from_path}; 5 | use image::DynamicImage; 6 | use log::{debug, error}; 7 | use slint::ComponentHandle; 8 | 9 | use crate::{Callabler, CurrentTab, GuiState, MainWindow, Settings}; 10 | 11 | pub type ImageBufferRgba = image::ImageBuffer, Vec>; 12 | 13 | pub fn connect_show_preview(app: &MainWindow) { 14 | let a = app.as_weak(); 15 | app.global::().on_load_image_preview(move |image_path| { 16 | let app = a.upgrade().expect("Failed to upgrade app :("); 17 | 18 | let settings = app.global::(); 19 | let gui_state = app.global::(); 20 | 21 | let active_tab = gui_state.get_active_tab(); 22 | 23 | if !((active_tab == CurrentTab::SimilarImages && settings.get_similar_images_show_image_preview()) 24 | || (active_tab == CurrentTab::DuplicateFiles && settings.get_duplicate_image_preview())) 25 | { 26 | set_preview_visible(&gui_state, None); 27 | return; 28 | } 29 | 30 | if !check_if_can_display_image(&image_path) { 31 | set_preview_visible(&gui_state, None); 32 | return; 33 | } 34 | 35 | // Do not load the same image again 36 | if image_path == gui_state.get_preview_image_path() { 37 | return; 38 | } 39 | 40 | let path = Path::new(image_path.as_str()); 41 | 42 | let res = load_image(path); 43 | if let Some((load_time, img)) = res { 44 | let start_timer_convert_time = Instant::now(); 45 | let slint_image = convert_into_slint_image(&img); 46 | let convert_time = start_timer_convert_time.elapsed(); 47 | 48 | let start_set_time = Instant::now(); 49 | gui_state.set_preview_image(slint_image); 50 | let set_time = start_set_time.elapsed(); 51 | 52 | debug!("Loading image took: {load_time:?}, converting image took: {convert_time:?}, setting image took: {set_time:?}"); 53 | set_preview_visible(&gui_state, Some(image_path.as_str())); 54 | } else { 55 | set_preview_visible(&gui_state, None); 56 | } 57 | }); 58 | } 59 | 60 | fn set_preview_visible(gui_state: &GuiState, preview: Option<&str>) { 61 | if let Some(preview) = preview { 62 | gui_state.set_preview_image_path(preview.into()); 63 | gui_state.set_preview_visible(true); 64 | } else { 65 | gui_state.set_preview_image_path("".into()); 66 | gui_state.set_preview_visible(false); 67 | } 68 | } 69 | 70 | fn convert_into_slint_image(img: &DynamicImage) -> slint::Image { 71 | let image_buffer: ImageBufferRgba = img.to_rgba8(); 72 | let buffer = slint::SharedPixelBuffer::::clone_from_slice(image_buffer.as_raw(), image_buffer.width(), image_buffer.height()); 73 | slint::Image::from_rgba8(buffer) 74 | } 75 | 76 | fn load_image(image_path: &Path) -> Option<(Duration, DynamicImage)> { 77 | if !image_path.is_file() { 78 | return None; 79 | } 80 | 81 | let load_img_start_timer = Instant::now(); 82 | 83 | let img = match get_dynamic_image_from_path(&image_path.to_string_lossy()) { 84 | Ok(img) => img, 85 | Err(e) => { 86 | error!("Failed to load image: {e}"); 87 | return None; 88 | } 89 | }; 90 | Some((load_img_start_timer.elapsed(), img)) 91 | } 92 | -------------------------------------------------------------------------------- /krokiet/src/connect_stop.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | use std::sync::atomic::AtomicBool; 3 | 4 | use crate::MainWindow; 5 | 6 | pub fn connect_stop_button(app: &MainWindow, stop_sender: Arc) { 7 | app.on_scan_stopping(move || { 8 | stop_sender.store(true, std::sync::atomic::Ordering::Relaxed); 9 | }); 10 | } 11 | -------------------------------------------------------------------------------- /krokiet/src/localizer_krokiet.rs: -------------------------------------------------------------------------------- 1 | use i18n_embed::fluent::{FluentLanguageLoader, fluent_language_loader}; 2 | use i18n_embed::{DefaultLocalizer, LanguageLoader, Localizer}; 3 | use once_cell::sync::Lazy; 4 | use rust_embed::RustEmbed; 5 | 6 | #[derive(RustEmbed)] 7 | #[folder = "i18n/"] 8 | struct Localizations; 9 | 10 | pub static LANGUAGE_LOADER_KROKIET: Lazy = Lazy::new(|| { 11 | let loader: FluentLanguageLoader = fluent_language_loader!(); 12 | 13 | loader.load_fallback_language(&Localizations).expect("Error while loading fallback language"); 14 | 15 | loader 16 | }); 17 | 18 | #[macro_export] 19 | macro_rules! flk { 20 | ($message_id:literal) => {{ 21 | i18n_embed_fl::fl!($crate::localizer_krokiet::LANGUAGE_LOADER_KROKIET, $message_id) 22 | }}; 23 | 24 | ($message_id:literal, $($args:expr_2021),*) => {{ 25 | i18n_embed_fl::fl!($crate::localizer_krokiet::LANGUAGE_LOADER_KROKIET, $message_id, $($args), *) 26 | }}; 27 | } 28 | 29 | // Get the `Localizer` to be used for localizing this library. 30 | pub fn localizer_krokiet() -> Box { 31 | Box::from(DefaultLocalizer::new(&*LANGUAGE_LOADER_KROKIET, &Localizations)) 32 | } 33 | -------------------------------------------------------------------------------- /krokiet/src/set_initial_gui_info.rs: -------------------------------------------------------------------------------- 1 | // use czkawka_core::common::get_all_available_threads; 2 | // use slint::{ComponentHandle, VecModel}; 3 | // 4 | // use crate::settings::StringComboBoxItems; 5 | // use crate::{GuiState, MainWindow, Settings}; 6 | // 7 | // // Some info needs to be send to gui at the start like available thread number in OS. 8 | // pub fn set_initial_gui_infos(app: &MainWindow) { 9 | // let threads = get_all_available_threads(); 10 | // let settings = app.global::(); 11 | // app.global::().set_maximum_threads(threads as f32); 12 | // 13 | // let collected_items = StringComboBoxItems::get_items(); 14 | // 15 | // settings.set_languages_list(VecModel::from_slice(&StringComboBoxItems::get_display_names(&collected_items.languages))); 16 | // settings.set_similar_images_sub_available_hash_size(VecModel::from_slice(&StringComboBoxItems::get_display_names(&collected_items.hash_size))); 17 | // settings.set_similar_images_sub_available_resize_algorithm(VecModel::from_slice(&StringComboBoxItems::get_display_names(&collected_items.resize_algorithm))); 18 | // settings.set_similar_images_sub_available_hash_type(VecModel::from_slice(&StringComboBoxItems::get_display_names(&collected_items.image_hash_alg))); 19 | // settings.set_biggest_files_sub_method(VecModel::from_slice(&StringComboBoxItems::get_display_names(&collected_items.biggest_files_method))); 20 | // settings.set_duplicates_sub_check_method(VecModel::from_slice(&StringComboBoxItems::get_display_names(&collected_items.duplicates_check_method))); 21 | // settings.set_duplicates_sub_available_hash_type(VecModel::from_slice(&StringComboBoxItems::get_display_names(&collected_items.duplicates_hash_type))); 22 | // } 23 | -------------------------------------------------------------------------------- /krokiet/src/test_common.rs: -------------------------------------------------------------------------------- 1 | use slint::{ModelRc, VecModel}; 2 | 3 | use crate::MainListModel; 4 | 5 | pub fn get_main_list_model() -> MainListModel { 6 | MainListModel { 7 | selected_row: false, 8 | val_int: Default::default(), 9 | checked: false, 10 | filled_header_row: false, 11 | header_row: false, 12 | val_str: Default::default(), 13 | } 14 | } 15 | pub fn get_model_vec(items: usize) -> Vec { 16 | (0..items).map(|_| get_main_list_model()).collect::>() 17 | } 18 | pub fn create_model_from_model_vec(model_vec: &[T]) -> ModelRc { 19 | ModelRc::new(VecModel::from(model_vec.to_owned())) 20 | } 21 | -------------------------------------------------------------------------------- /krokiet/ui/about.slint: -------------------------------------------------------------------------------- 1 | import { Button } from "std-widgets.slint"; 2 | import { Callabler } from "callabler.slint"; 3 | import { Translations } from "translations.slint"; 4 | 5 | export component About inherits VerticalLayout { 6 | preferred-height: 300px; 7 | preferred-width: 400px; 8 | 9 | img := Image { 10 | source: @image-url("../icons/krokiet_logo.png"); 11 | image-fit: ImageFit.contain; 12 | } 13 | 14 | Text { 15 | text: "9.0.0"; 16 | horizontal-alignment: center; 17 | font-size: max(min(img.width / 20, 17px), 10px); 18 | } 19 | 20 | VerticalLayout { 21 | spacing: 10px; 22 | padding-bottom: 10px; 23 | Text { 24 | text: "2020 - 2025 Rafał Mikrut(qarmin)"; 25 | horizontal-alignment: center; 26 | font-size: 15px; 27 | } 28 | 29 | Text { 30 | text <=> Translations.motto_text; 31 | horizontal-alignment: center; 32 | font-size: 13px; 33 | } 34 | 35 | Text { 36 | text <=> Translations.unicorn_text; 37 | horizontal-alignment: center; 38 | font-size: 13px; 39 | } 40 | } 41 | 42 | HorizontalLayout { 43 | spacing: 5px; 44 | Button { 45 | text <=> Translations.repository_text; 46 | clicked => { 47 | Callabler.open_link("https://github.com/qarmin/czkawka"); 48 | } 49 | } 50 | 51 | Button { 52 | text <=> Translations.instruction_text; 53 | clicked => { 54 | Callabler.open_link("https://github.com/qarmin/czkawka/blob/master/instructions/Instruction.md"); 55 | } 56 | } 57 | 58 | Button { 59 | text <=> Translations.donation_text; 60 | clicked => { 61 | Callabler.open_link("https://github.com/sponsors/qarmin"); 62 | } 63 | } 64 | 65 | Button { 66 | text <=> Translations.translation_text; 67 | clicked => { 68 | Callabler.open_link("https://crwd.in/czkawka"); 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /krokiet/ui/callabler.slint: -------------------------------------------------------------------------------- 1 | import { SelectMode, SortMode } from "common.slint"; 2 | import { CurrentTab } from "common.slint"; 3 | import { Palette } from "std-widgets.slint"; 4 | import { Settings } from "settings.slint"; 5 | 6 | export global Callabler { 7 | // Bottom panel operations 8 | callback remove_item_directories(bool); 9 | callback added_manual_directories(bool, string); 10 | 11 | // Row selecting 12 | callback reset_selection(CurrentTab); 13 | 14 | callback row_select_all(); 15 | callback row_reverse_single_unique_item(int); 16 | callback row_reverse_item_selection(int); 17 | callback row_select_items_with_shift(int, int); 18 | 19 | callback row_open_selected_item(); 20 | callback row_open_parent_of_selected_item(); 21 | 22 | callback row_reverse_checked_selection(); 23 | callback row_open_item_with_index(int); 24 | 25 | // Right click or middle click opener 26 | callback open_item(string); 27 | callback open_selected_item(CurrentTab); 28 | 29 | callback delete_selected_items(); 30 | callback select_items(SelectMode); 31 | callback sort_items(SortMode); 32 | 33 | // Preview 34 | callback load_image_preview(string); 35 | 36 | // Settings 37 | callback changed_settings_preset(); 38 | callback save_current_preset(); 39 | callback load_current_preset(); 40 | callback reset_current_preset(); 41 | callback changed_language(); 42 | 43 | callback tab_changed(); 44 | 45 | // Dialogs 46 | callback save_results(); 47 | callback move_items(bool, bool, string); 48 | callback rename_files(); 49 | 50 | // Only Slint 51 | callback open_select_popup(); 52 | 53 | callback open_config_folder(); 54 | callback open_cache_folder(); 55 | 56 | callback open_link(string); 57 | 58 | callback theme_changed(); 59 | theme_changed => { 60 | Palette.color-scheme = Settings.dark_theme ? ColorScheme.dark : ColorScheme.light; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /krokiet/ui/color_palette.slint: -------------------------------------------------------------------------------- 1 | import { Settings } from "settings.slint"; 2 | 3 | export global ColorPalette { 4 | // Tabs at left side 5 | in-out property tab_selected_color: Settings.dark_theme ? #353535 : #5e5e5e; 6 | in-out property tab_hovered_color: Settings.dark_theme ? #49494926 : #80808014; 7 | // ListView 8 | in-out property list_view_item_color: Settings.dark_theme ? #222222 : #dddddd; 9 | in-out property list_view_item_hovered_color: Settings.dark_theme ? #333333 : #d2d2d2; 10 | in-out property list_view_item_selected_color: Settings.dark_theme ? #444444 : #cccccc; 11 | in-out property list_view_item_selected_hovered_color: Settings.dark_theme ? #555555 : #bbbbbb; 12 | 13 | in-out property list_view_header_color: Settings.dark_theme ? #111111 : #888888; 14 | in-out property list_view_clicked_header_color: Settings.dark_theme ? #1a1a1a : #808080; 15 | 16 | // Popup 17 | in-out property popup_background: Settings.dark_theme ? #353535 : #cecece; 18 | in-out property popup_background_border: Settings.dark_theme ? #222222 : #808080; 19 | in-out property popup_background_title_line: Settings.dark_theme ? #252525 : #9e9e9e; 20 | in-out property popup_border_color: Settings.dark_theme ? #000000 : #808080; 21 | 22 | public pure function get_listview_color(selected: bool, hovered: bool) -> color { 23 | if (selected) { 24 | return hovered ? self.list_view_item_selected_hovered_color : self.list_view_item_selected_color; 25 | } else { 26 | return hovered ? self.list_view_item_hovered_color : self.list_view_item_color; 27 | } 28 | } 29 | public pure function get_listview_color_with_header(selected: bool, hovered: bool, header: bool) -> color { 30 | if (header) { 31 | return selected ? self.list_view_clicked_header_color : self.list_view_header_color; 32 | } else { 33 | return self.get_listview_color(selected, hovered); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /krokiet/ui/common.slint: -------------------------------------------------------------------------------- 1 | export enum CurrentTab { 2 | DuplicateFiles, 3 | EmptyFolders, 4 | BigFiles, 5 | EmptyFiles, 6 | TemporaryFiles, 7 | SimilarImages, 8 | SimilarVideos, 9 | SimilarMusic, 10 | InvalidSymlinks, 11 | BrokenFiles, 12 | BadExtensions, 13 | Settings, 14 | About 15 | } 16 | 17 | export enum TypeOfOpenedItem { 18 | CurrentItem, 19 | ParentItem, 20 | } 21 | 22 | export struct ProgressToSend { 23 | current_progress: int, 24 | current_progress_size: int, 25 | all_progress: int, 26 | step_name: string, 27 | } 28 | 29 | export struct MainListModel { 30 | checked: bool, 31 | header_row: bool, 32 | filled_header_row: bool, 33 | selected_row: bool, 34 | val_str: [string], 35 | val_int: [int] 36 | } 37 | 38 | export enum BottomPanelVisibility { 39 | NotVisible, 40 | TextErrors, 41 | Directories 42 | } 43 | 44 | export struct IncludedDirectoriesModel { 45 | path: string, 46 | referenced_folder: bool, 47 | selected_row: bool, 48 | } 49 | 50 | export struct ExcludedDirectoriesModel { 51 | path: string, 52 | selected_row: bool, 53 | } 54 | 55 | export enum SelectMode { 56 | SelectAll, 57 | UnselectAll, 58 | InvertSelection, 59 | SelectTheBiggestSize, 60 | SelectTheBiggestResolution, 61 | SelectTheSmallestSize, 62 | SelectTheSmallestResolution, 63 | SelectNewest, 64 | SelectOldest, 65 | } 66 | 67 | export struct SelectModel { 68 | data: SelectMode, 69 | name: string 70 | } 71 | 72 | export enum SortMode { 73 | ItemName, 74 | ParentName, 75 | FullName, 76 | Size, 77 | ModificationDate, 78 | Selection, 79 | Reverse, 80 | Checked, 81 | } 82 | 83 | export struct SortModel { 84 | data: SortMode, 85 | name: string 86 | } 87 | -------------------------------------------------------------------------------- /krokiet/ui/gui_state.slint: -------------------------------------------------------------------------------- 1 | import { CurrentTab } from "common.slint"; 2 | import { SelectModel, SortModel, SelectMode, SortMode, BottomPanelVisibility } from "common.slint"; 3 | import { Translations } from "translations.slint"; 4 | 5 | // State Gui state that shows the current state of the GUI 6 | // It extends Settings global state with settings that are not saved to the settings file 7 | export global GuiState { 8 | in-out property app_width; 9 | in-out property app_height; 10 | 11 | in-out property info_text: "Nothing to report"; 12 | in-out property preview_visible; 13 | in-out property preview_image; 14 | in-out property preview_image_path; 15 | 16 | in-out property left_panel_width: 120px; 17 | 18 | in-out property maximum_threads: 40; 19 | 20 | in-out property choosing_include_directories; 21 | in-out property visible_tool_settings; 22 | 23 | in-out property available_subsettings: active_tab == CurrentTab.SimilarImages || active_tab == CurrentTab.DuplicateFiles || active_tab == CurrentTab.SimilarVideos || active_tab == CurrentTab.SimilarMusic || active_tab == CurrentTab.BigFiles || active_tab == CurrentTab.BrokenFiles; 24 | in-out property active_tab: CurrentTab.DuplicateFiles; 25 | in-out property is_tool_tab_active: active_tab != CurrentTab.Settings && active_tab != CurrentTab.About; 26 | 27 | in-out property <[SelectModel]> select_results_list: [ 28 | { data: SelectMode.SelectAll, name: Translations.selection_all_text }, 29 | { data: SelectMode.UnselectAll, name: Translations.selection_deselect_all_text }, 30 | { 31 | data: SelectMode.SelectTheSmallestResolution, 32 | name: Translations.selection_the_smallest_resolution_text 33 | } 34 | ]; 35 | 36 | in-out property <[SortModel]> sort_results_list: [ 37 | { data: SortMode.ItemName, name: Translations.sort_by_item_name_text }, 38 | { data: SortMode.ParentName, name: Translations.sort_by_parent_name_text }, 39 | { data: SortMode.FullName, name: Translations.sort_by_full_name_text }, 40 | { data: SortMode.Size, name: Translations.sort_by_size_text }, 41 | { data: SortMode.ModificationDate, name: Translations.sort_by_modification_date_text }, 42 | { data: SortMode.Selection, name: Translations.sort_by_selection_text }, 43 | { data: SortMode.Reverse, name: Translations.sort_reverse_text } 44 | ]; 45 | 46 | in-out property <[{name: string, tab: CurrentTab}]> tools_model: [ 47 | { name: Translations.tool_duplicate_files_text, tab: CurrentTab.DuplicateFiles }, 48 | { name: Translations.tool_empty_folders_text, tab: CurrentTab.EmptyFolders }, 49 | { name: Translations.tool_big_files_text, tab: CurrentTab.BigFiles }, 50 | { name: Translations.tool_empty_files_text, tab: CurrentTab.EmptyFiles }, 51 | { name: Translations.tool_temporary_files_text, tab: CurrentTab.TemporaryFiles }, 52 | { name: Translations.tool_similar_images_text, tab: CurrentTab.SimilarImages }, 53 | { name: Translations.tool_similar_videos_text, tab: CurrentTab.SimilarVideos }, 54 | { name: Translations.tool_music_duplicates_text, tab: CurrentTab.SimilarMusic }, 55 | { name: Translations.tool_invalid_symlinks_text, tab: CurrentTab.InvalidSymlinks }, 56 | { name: Translations.tool_broken_files_text, tab: CurrentTab.BrokenFiles }, 57 | { name: Translations.tool_bad_extensions_text, tab: CurrentTab.BadExtensions } 58 | ]; 59 | 60 | in-out property bottom_panel_visibility: BottomPanelVisibility.Directories; 61 | } 62 | -------------------------------------------------------------------------------- /krokiet/ui/popup_base.slint: -------------------------------------------------------------------------------- 1 | import { Button } from "std-widgets.slint"; 2 | import { ColorPalette } from "color_palette.slint"; 3 | import { Translations } from "translations.slint"; 4 | 5 | export component PopupBase inherits PopupWindow { 6 | in-out property title_text: "TODO - needs to be changed"; 7 | in-out property ok_text <=> Translations.ok_button_text; 8 | in-out property cancel_text <=> Translations.cancel_button_text; 9 | in-out property enabled_ok_button: true; 10 | 11 | callback ok_clicked(); 12 | callback cancel_clicked(); 13 | 14 | close-policy: PopupClosePolicy.no-auto-close; 15 | rect := Rectangle { 16 | width: parent.width; 17 | height: parent.height; 18 | border-radius: 10px; 19 | border-color: ColorPalette.popup_border_color; 20 | border-width: 2px; 21 | background: ColorPalette.popup_background; 22 | clip: true; 23 | VerticalLayout { 24 | Rectangle { 25 | width: rect.width; 26 | background: ColorPalette.popup_background_title_line; 27 | 28 | Text { 29 | vertical-stretch: 0.0; 30 | min-height: 30px; 31 | text <=> title_text; 32 | vertical-alignment: center; 33 | horizontal-alignment: center; 34 | font-size: 13px; 35 | } 36 | } 37 | 38 | @children 39 | 40 | HorizontalLayout { 41 | padding: 10px; 42 | Button { 43 | enabled <=> enabled_ok_button; 44 | text <=> ok_text; 45 | clicked => { 46 | root.close(); 47 | ok_clicked(); 48 | } 49 | } 50 | 51 | Rectangle { } 52 | 53 | Button { 54 | text <=> cancel_text; 55 | clicked => { 56 | root.close(); 57 | } 58 | } 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /krokiet/ui/popup_centered_text.slint: -------------------------------------------------------------------------------- 1 | export component PopupCenteredText inherits Text { 2 | vertical-stretch: 1.0; 3 | vertical-alignment: center; 4 | horizontal-alignment: center; 5 | font-size: 13px; 6 | padding: 10px; 7 | wrap: TextWrap.word-wrap; 8 | } 9 | -------------------------------------------------------------------------------- /krokiet/ui/popup_delete.slint: -------------------------------------------------------------------------------- 1 | import { Callabler } from "callabler.slint"; 2 | import { Translations } from "translations.slint"; 3 | import { PopupBase } from "popup_base.slint"; 4 | import { PopupCenteredText } from "popup_centered_text.slint"; 5 | 6 | export component PopupDelete inherits Rectangle { 7 | out property popup_width: 350px; 8 | out property popup_height: 150px; 9 | callback show_popup(); 10 | 11 | popup_window := PopupBase { 12 | width: popup_width; 13 | height: popup_height; 14 | title_text <=> Translations.delete_text; 15 | 16 | VerticalLayout { 17 | PopupCenteredText { 18 | text <=> Translations.delete_confirmation_text; 19 | } 20 | } 21 | 22 | ok_clicked => { 23 | Callabler.delete_selected_items(); 24 | } 25 | } 26 | 27 | show_popup() => { 28 | popup_window.show(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /krokiet/ui/popup_move_folders.slint: -------------------------------------------------------------------------------- 1 | import { CheckBox } from "std-widgets.slint"; 2 | import { Callabler } from "callabler.slint"; 3 | import { Translations } from "translations.slint"; 4 | import { PopupBase } from "popup_base.slint"; 5 | import { PopupCenteredText } from "popup_centered_text.slint"; 6 | 7 | export component PopupMoveFolders inherits Rectangle { 8 | out property popup_width: 500px; 9 | out property popup_height: 150px; 10 | in-out property folder_name: ""; 11 | callback show_popup(); 12 | 13 | popup_window := PopupBase { 14 | width: popup_width; 15 | height: popup_height; 16 | title_text <=> Translations.popup_move_title_text; 17 | 18 | VerticalLayout { 19 | PopupCenteredText { 20 | text: Translations.popup_move_message_text + "\n" + folder_name; 21 | } 22 | 23 | Rectangle {height: 5px;} 24 | 25 | VerticalLayout { 26 | HorizontalLayout { 27 | alignment: center; 28 | copy_checkbox := CheckBox { 29 | text <=> Translations.popup_move_copy_checkbox_text; 30 | } 31 | } 32 | Rectangle {height: 5px;} 33 | 34 | HorizontalLayout { 35 | alignment: center; 36 | preserve_folder_checkbox := CheckBox { 37 | text <=> Translations.popup_move_preserve_folder_checkbox_text; 38 | } 39 | } 40 | } 41 | Rectangle {height: 20px;} 42 | 43 | PopupCenteredText { 44 | text: Translations.are_you_want_to_continue_text; 45 | } 46 | } 47 | 48 | ok_clicked => { 49 | Callabler.move_items(preserve_folder_checkbox.checked, copy_checkbox.checked, folder_name); 50 | } 51 | } 52 | 53 | show_popup() => { 54 | popup_window.show(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /krokiet/ui/popup_new_directories.slint: -------------------------------------------------------------------------------- 1 | import { TextEdit } from "std-widgets.slint"; 2 | import { Callabler } from "callabler.slint"; 3 | import { Translations } from "translations.slint"; 4 | import { PopupBase } from "popup_base.slint"; 5 | import { GuiState } from "gui_state.slint"; 6 | 7 | export component PopupNewDirectories inherits Rectangle { 8 | out property popup_width: 350px; 9 | out property popup_height: 200px; 10 | callback show_popup(); 11 | 12 | property included_directories; 13 | private property text_data; 14 | 15 | popup_window := PopupBase { 16 | width: popup_width; 17 | height: popup_height; 18 | title_text <=> Translations.popup_new_directories_title_text; 19 | enabled_ok_button: text_data != ""; 20 | 21 | VerticalLayout { 22 | TextEdit { 23 | vertical-stretch: 1.0; 24 | text <=> text_data; 25 | } 26 | } 27 | 28 | ok_clicked => { 29 | Callabler.added_manual_directories(GuiState.choosing_include_directories, text_data); 30 | } 31 | } 32 | 33 | show_popup() => { 34 | popup_window.show(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /krokiet/ui/popup_rename_files.slint: -------------------------------------------------------------------------------- 1 | import { Callabler } from "callabler.slint"; 2 | import { Translations } from "translations.slint"; 3 | import { PopupBase } from "popup_base.slint"; 4 | import { PopupCenteredText } from "popup_centered_text.slint"; 5 | 6 | export component PopupRenameFiles inherits Rectangle { 7 | out property popup_width: 500px; 8 | out property popup_height: 150px; 9 | callback show_popup(); 10 | 11 | in-out property folder_name: ""; 12 | 13 | popup_window := PopupBase { 14 | width: popup_width; 15 | height: popup_height; 16 | title_text <=> Translations.popup_rename_title_text; 17 | 18 | VerticalLayout { 19 | PopupCenteredText { 20 | text: Translations.popup_rename_message_text + "\n\n" + Translations.are_you_want_to_continue_text; 21 | } 22 | } 23 | 24 | ok_clicked => { 25 | Callabler.rename_files(); 26 | } 27 | } 28 | 29 | show_popup() => { 30 | popup_window.show(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /krokiet/ui/popup_save.slint: -------------------------------------------------------------------------------- 1 | import { Callabler } from "callabler.slint"; 2 | import { Translations } from "translations.slint"; 3 | import { PopupBase } from "popup_base.slint"; 4 | import { PopupCenteredText } from "popup_centered_text.slint"; 5 | 6 | export component PopupSave inherits Rectangle { 7 | out property popup_width: 500px; 8 | out property popup_height: 150px; 9 | callback show_popup(); 10 | 11 | popup_window := PopupBase { 12 | width: popup_width; 13 | height: popup_height; 14 | title_text <=> Translations.popup_save_title_text; 15 | 16 | VerticalLayout { 17 | PopupCenteredText { 18 | text: Translations.popup_save_message_text + "\n\n" + Translations.are_you_want_to_continue_text; 19 | } 20 | } 21 | 22 | ok_clicked => { 23 | Callabler.save_results(); 24 | } 25 | } 26 | 27 | show_popup() => { 28 | popup_window.show(); 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /krokiet/ui/popup_select_results.slint: -------------------------------------------------------------------------------- 1 | import { Button } from "std-widgets.slint"; 2 | import { SelectModel } from "common.slint"; 3 | import { Callabler } from "callabler.slint"; 4 | import { ColorPalette } from "color_palette.slint"; 5 | import { GuiState } from "gui_state.slint"; 6 | 7 | export component PopupSelectResults inherits Rectangle { 8 | callback show_popup(); 9 | property <[SelectModel]> model: GuiState.select_results_list; 10 | property item_height: 30px; 11 | out property item_width: 200px; 12 | out property all_items_height: item_height * model.length; 13 | 14 | popup_window := PopupWindow { 15 | width: item_width; 16 | height: all_items_height; 17 | 18 | close-policy: PopupClosePolicy.close-on-click-outside; 19 | Rectangle { 20 | width: parent.width; 21 | height: parent.height; 22 | border-radius: 5px; 23 | background: ColorPalette.popup_background; 24 | VerticalLayout { 25 | for i in model: Button { 26 | text: i.name; 27 | height: item_height; 28 | width: item_width; 29 | clicked => { 30 | Callabler.select_items(i.data); 31 | popup_window.close(); 32 | } 33 | } 34 | } 35 | } 36 | } 37 | 38 | show_popup() => { 39 | popup_window.show(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /krokiet/ui/popup_sort.slint: -------------------------------------------------------------------------------- 1 | import { Button } from "std-widgets.slint"; 2 | import { SortModel } from "common.slint"; 3 | import { Callabler } from "callabler.slint"; 4 | import { ColorPalette } from "color_palette.slint"; 5 | import { GuiState } from "gui_state.slint"; 6 | 7 | export component PopupSortResults inherits Rectangle { 8 | callback show_popup(); 9 | property <[SortModel]> model: GuiState.sort_results_list; 10 | property item_height: 30px; 11 | out property item_width: 200px; 12 | out property all_items_height: item_height * model.length; 13 | 14 | popup_window := PopupWindow { 15 | width: item_width; 16 | height: all_items_height; 17 | 18 | close-policy: PopupClosePolicy.close-on-click-outside; 19 | Rectangle { 20 | width: parent.width; 21 | height: parent.height; 22 | border-radius: 5px; 23 | background: ColorPalette.popup_background; 24 | VerticalLayout { 25 | for i in model: Button { 26 | text: i.name; 27 | height: item_height; 28 | width: item_width; 29 | clicked => { 30 | Callabler.sort_items(i.data); 31 | popup_window.close(); 32 | } 33 | } 34 | } 35 | } 36 | } 37 | 38 | show_popup() => { 39 | popup_window.show(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /krokiet/ui/preview.slint: -------------------------------------------------------------------------------- 1 | export component Preview inherits Image { 2 | image-rendering: ImageRendering.smooth; 3 | } 4 | -------------------------------------------------------------------------------- /krokiet/ui/progress.slint: -------------------------------------------------------------------------------- 1 | import { ProgressToSend } from "common.slint"; 2 | import { ProgressIndicator } from "std-widgets.slint"; 3 | import { Translations } from "translations.slint"; 4 | 5 | export component Progress { 6 | in-out property progress_datas; 7 | preferred-width: 400px; 8 | preferred-height: 40px; 9 | VerticalLayout { 10 | Text { 11 | text: progress-datas.step_name; 12 | horizontal-alignment: TextHorizontalAlignment.center; 13 | } 14 | 15 | HorizontalLayout { 16 | spacing: 5px; 17 | VerticalLayout { 18 | spacing: 5px; 19 | Text { 20 | vertical-alignment: TextVerticalAlignment.center; 21 | text: Translations.stage_current_text; 22 | } 23 | 24 | Text { 25 | vertical-alignment: TextVerticalAlignment.center; 26 | text: Translations.stage_all_text; 27 | } 28 | } 29 | 30 | VerticalLayout { 31 | spacing: 5px; 32 | VerticalLayout { 33 | alignment: LayoutAlignment.center; 34 | ProgressIndicator { 35 | visible: progress_datas.current_progress >= -0.001; 36 | height: 8px; 37 | progress: progress_datas.current_progress_size == -1 ? progress_datas.current_progress / 100.0 : progress_datas.current_progress_size / 100.0; 38 | } 39 | } 40 | 41 | VerticalLayout { 42 | alignment: LayoutAlignment.center; 43 | ProgressIndicator { 44 | height: 8px; 45 | progress: progress_datas.all_progress / 100.0; 46 | } 47 | } 48 | } 49 | 50 | VerticalLayout { 51 | visible: progress_datas.all_progress > -0.001; 52 | spacing: 5px; 53 | Text { 54 | visible: progress_datas.current_progress >= -0.001; 55 | vertical-alignment: TextVerticalAlignment.center; 56 | text: (progress_datas.current_progress_size == -1 ? progress_datas.current_progress : progress_datas.current_progress_size) + "%"; 57 | } 58 | 59 | Text { 60 | vertical-alignment: TextVerticalAlignment.center; 61 | text: progress_datas.all_progress + "%"; 62 | } 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /misc/.idea/czkawka.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /misc/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /misc/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /misc/cargo/PublishCore.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | NUMBER="9.0.0" 3 | CZKAWKA_PATH="/home/rafal" 4 | 5 | cd "$CZKAWKA_PATH" 6 | CZKAWKA_PATH="$CZKAWKA_PATH/czkawka" 7 | rm -rf $CZKAWKA_PATH 8 | git clone https://github.com/qarmin/czkawka.git "$CZKAWKA_PATH" 9 | cd $CZKAWKA_PATH 10 | git checkout "$NUMBER" 11 | 12 | cd "$CZKAWKA_PATH/czkawka_core" 13 | cargo package 14 | if [ $(echo $?) != "0" ] 15 | then 16 | echo "Cargo package failed CORE" 17 | exit 1 18 | fi 19 | git reset --hard 20 | 21 | cd "$CZKAWKA_PATH/czkawka_core" 22 | cargo publish 23 | git reset --hard 24 | 25 | -------------------------------------------------------------------------------- /misc/cargo/PublishOther.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | NUMBER="9.0.0" 3 | CZKAWKA_PATH="/home/rafal" 4 | 5 | cd "$CZKAWKA_PATH" 6 | CZKAWKA_PATH="$CZKAWKA_PATH/czkawka" 7 | rm -rf $CZKAWKA_PATH 8 | git clone https://github.com/qarmin/czkawka.git "$CZKAWKA_PATH" 9 | cd $CZKAWKA_PATH 10 | git checkout "$NUMBER" 11 | 12 | 13 | cd "$CZKAWKA_PATH/czkawka_cli" 14 | cargo package 15 | if [ $(echo $?) != "0" ] 16 | then 17 | echo "Cargo package failed CLI" 18 | exit 1 19 | fi 20 | git reset --hard 21 | 22 | 23 | cd "$CZKAWKA_PATH/czkawka_gui" 24 | cargo package 25 | if [ $(echo $?) != "0" ] 26 | then 27 | echo "Cargo package failed GUI" 28 | exit 1 29 | fi 30 | git reset --hard 31 | 32 | cd "$CZKAWKA_PATH/krokiet" 33 | cargo package 34 | if [ $(echo $?) != "0" ] 35 | then 36 | echo "Cargo package failed krokiet" 37 | exit 1 38 | fi 39 | git reset --hard 40 | 41 | 42 | 43 | 44 | cd "$CZKAWKA_PATH/czkawka_cli" 45 | # sed -i "s/{ path = \"..\/czkawka_core\" }/\"=$NUMBER\"/g" "$CZKAWKA_PATH/czkawka_cli/Cargo.toml" 46 | cargo publish # --allow-dirty 47 | git reset --hard 48 | 49 | cd "$CZKAWKA_PATH/czkawka_gui" 50 | # sed -i "s/{ path = \"..\/czkawka_core\" }/\"=$NUMBER\"/g" "$CZKAWKA_PATH/czkawka_gui/Cargo.toml" 51 | cargo publish # --allow-dirty 52 | git reset --hard 53 | 54 | cd "$CZKAWKA_PATH/krokiet" 55 | # sed -i "s/{ path = \"..\/czkawka_core\" }/\"=$NUMBER\"/g" "$CZKAWKA_PATH/czkawka_gui/Cargo.toml" 56 | cargo publish # --allow-dirty 57 | git reset --hard 58 | -------------------------------------------------------------------------------- /misc/czkawka-appimage-recipe.yml: -------------------------------------------------------------------------------- 1 | app: Czkawka 2 | 3 | ingredients: 4 | script: 5 | - mkdir -p czkawka 6 | 7 | script: 8 | - pwd 9 | - cp ../../czkawka_gui ./usr/bin/czkawka_gui 10 | - cp ../../data/com.github.qarmin.czkawka.desktop . 11 | - cp ../../data/icons/com.github.qarmin.czkawka.svg . 12 | -------------------------------------------------------------------------------- /misc/delete_unused_krokiet_slint_imports.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | 4 | script_path = os.path.dirname(os.path.abspath(__file__)) 5 | ui_path = f"{script_path}/../krokiet/ui" 6 | 7 | collected_files = [ 8 | os.path.join(root, file) 9 | for root, _, files in os.walk(ui_path) 10 | for file in files if file.endswith(".slint") 11 | ] 12 | 13 | for file_path in collected_files: 14 | with open(file_path, "r", encoding="utf-8") as file: 15 | content = file.read() 16 | lines = content.splitlines() 17 | 18 | non_import_lines = [] 19 | imports_to_check = [] 20 | updated_lines = [] 21 | 22 | for line in lines: 23 | if line.startswith("import"): 24 | imports_to_check.append(line) 25 | else: 26 | if len(non_import_lines) == 0 and len(line.strip()) == 0: 27 | continue 28 | non_import_lines.append(line) 29 | 30 | non_imported_content = "\n".join(non_import_lines) 31 | 32 | for import_line in imports_to_check: 33 | imported_items = [i.strip() for i in import_line.split("{")[1].split("}")[0].split(",") if len(i.strip()) > 0] 34 | if not imported_items: 35 | continue 36 | 37 | from_file = import_line.split("from")[1].strip() 38 | 39 | used_items = [] 40 | for item in imported_items: 41 | regex = rf"\b{item}\b" 42 | if len(re.findall(regex, non_imported_content)) >= 1: 43 | used_items.append(item) 44 | 45 | if used_items: 46 | updated_line = f"import {{ {', '.join(used_items)} }} from {from_file}" 47 | updated_line = updated_line.replace(";;", ";") 48 | updated_lines.append(updated_line) 49 | 50 | if len(updated_lines) != 0: 51 | updated_lines.append("") 52 | 53 | updated_lines.extend(non_import_lines) 54 | if len(updated_lines) > 0 and len(updated_lines[-1].strip()) > 0: 55 | updated_lines.append("") 56 | 57 | with open(file_path, "w", encoding="utf-8") as file: 58 | file.write("\n".join(updated_lines)) -------------------------------------------------------------------------------- /misc/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | 3 | # curl is needed by Rust update tool 4 | RUN apt-get update \ 5 | && apt-get install -y curl build-essential libgtk-4-dev \ 6 | && apt-get clean ; rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/* 7 | 8 | RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y # Download the latest stable Rust 9 | 10 | ENV PATH="/root/.cargo/bin:${PATH}" 11 | 12 | RUN cargo --version 13 | -------------------------------------------------------------------------------- /misc/flathub.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | pip3 install aiohttp toml 3 | wget https://raw.githubusercontent.com/flatpak/flatpak-builder-tools/master/cargo/flatpak-cargo-generator.py 4 | mkdir flatpak 5 | python3 flatpak-cargo-generator.py ./Cargo.lock -o flatpak/cargo-sources.json 6 | rm flatpak-cargo-generator.py 7 | -------------------------------------------------------------------------------- /misc/generate_krokiet_translations.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | script_path = os.path.dirname(os.path.abspath(__file__)) 4 | 5 | translations_slint_path = f"{script_path}/../krokiet/ui/translations.slint" 6 | 7 | start_item = " in-out property " 8 | 9 | rust_items = [] 10 | translation_items = [] 11 | # in-out property scan_button_text: "Scan"; 12 | # translation.set_scan_button_text(flk!("scan_button").into()); 13 | 14 | with open(translations_slint_path, "r", encoding="utf-8") as file: 15 | for line in file: 16 | if line.startswith(start_item): 17 | line = line[len(start_item):] 18 | value = line.split("\"")[1] 19 | line = line.split(":")[0].strip() 20 | assert line.endswith("_text"), line 21 | item = line[:-5] 22 | rust_items.append(f" translation.set_{item}_text(flk!(\"{item}\").into());") 23 | translation_items.append(f"{item} = {value}") 24 | elif "property" in line: 25 | assert False 26 | 27 | for item in rust_items: 28 | print(item) 29 | 30 | print("##############################################################") 31 | 32 | for item in translation_items: 33 | print(item) -------------------------------------------------------------------------------- /misc/test_image_perf/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "test_image_perf" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | walkdir = "2.5.0" 8 | humansize = "2.1.3" 9 | rayon = "1.10.0" 10 | strum = { version = "0.26.3", features = ["strum_macros", "derive"] } 11 | image_hasher = "3.0.0" 12 | image = "0.25.5" 13 | rawloader = "0.37.1" 14 | imagepipe = "0.5.0" 15 | log = "0.4.25" 16 | os_info = "3.10.0" 17 | handsome_logger = "0.8.0" 18 | 19 | [features] 20 | fast_image_resize = ["image_hasher/fast_resize_unstable"] -------------------------------------------------------------------------------- /misc/test_read_perf/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "test_read_perf" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | czkawka_core = { path = "../../czkawka_core", default-features = false } 8 | walkdir = "2.5.0" 9 | humansize = "2.1" 10 | rayon = "1.10.0" 11 | strum = { version = "0.26.3", features = ["strum_macros", "derive"] } --------------------------------------------------------------------------------