feat: CLI progress bar with indicatif

- Progress bar shows scan progress with file count and ETA
- Split scan_images into collect_image_paths + process_image
- Added indicatif crate
This commit is contained in:
admin
2026-04-28 01:10:53 +00:00
parent 5714c999bc
commit 2bc9a9c99c
4 changed files with 207 additions and 3 deletions

View File

@@ -76,6 +76,48 @@ pub fn scan_images(root: &Path) -> Result<Vec<ImageEntry>> {
Ok(out)
}
pub fn collect_image_paths(root: &Path) -> Result<Vec<PathBuf>> {
let mut paths = Vec::new();
for entry in WalkDir::new(root).follow_links(true) {
let entry = entry?;
if entry.file_type().is_file() && is_image_path(entry.path()) {
paths.push(entry.path().to_path_buf());
}
}
Ok(paths)
}
pub fn process_image(path: &Path) -> Option<ImageEntry> {
let bytes = match fs::read(path) {
Ok(b) => b,
Err(e) => {
eprintln!("warning: skipping {}: {e}", path.display());
return None;
}
};
let sha256 = format!("{:x}", Sha256::digest(&bytes));
let img = match ImageReader::new(Cursor::new(&bytes)).with_guessed_format() {
Ok(reader) => match reader.decode() {
Ok(i) => i,
Err(e) => {
eprintln!("warning: skipping {}: {e}", path.display());
return None;
}
},
Err(e) => {
eprintln!("warning: skipping {}: {e}", path.display());
return None;
}
};
let dhash = compute_dhash(&img);
Some(ImageEntry {
path: path.to_path_buf(),
sha256,
dhash,
file_size: bytes.len() as u64,
})
}
pub fn compute_dhash(img: &image::DynamicImage) -> u64 {
let gray = img
.grayscale()

View File

@@ -1,5 +1,6 @@
use deduper::{find_duplicate_groups, scan_images, DuplicateKind};
use deduper::{find_duplicate_groups, collect_image_paths, process_image, DuplicateKind};
use deduper::ignore_db;
use indicatif::{ProgressBar, ProgressStyle};
use std::env;
use std::path::Path;
@@ -49,7 +50,8 @@ fn main() {
};
let root = Path::new(&config.root);
let entries = match scan_images(root) {
let paths = match collect_image_paths(root) {
Ok(v) => v,
Err(e) => {
eprintln!("scan error: {e}");
@@ -57,6 +59,21 @@ fn main() {
}
};
let pb = ProgressBar::new(paths.len() as u64);
pb.set_style(ProgressStyle::default_bar()
.template("{spinner:.red} [{bar:40.cyan/blue}] {pos}/{len} images ({eta})")
.unwrap()
.progress_chars("=>-"));
let mut entries = Vec::with_capacity(paths.len());
for path in &paths {
if let Some(entry) = process_image(path) {
entries.push(entry);
}
pb.inc(1);
}
pb.finish_with_message(format!("{} images processed", entries.len()));
let mut groups = find_duplicate_groups(&entries, config.threshold);
// Filter out ignored groups