mod parameters; use std::path::{Path}; use walkdir::{WalkDir, DirEntry}; use smartstring::alias::String; use structopt::StructOpt; use std::fs::File; use std::io; use std::io::Read; use mime_guess; use xdg_mime::SharedMimeInfo; use mime_guess::Mime; // TODO: test if this actually works on a windows machine #[cfg(windows)] fn is_hidden(entry: &DirEntry) -> bool { use std::os::windows::prelude::*; use std::fs; fs::metadata(entry) // try to get metadata for file .map_or( false, // if getting metadata/attributes fails, assume it's not hidden |f| f.file_attributes() & 0x2 // flag for hidden - https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants ) } #[cfg(not(windows))] fn is_hidden(entry: &DirEntry) -> bool { entry.file_name().to_str().map_or(false, |f| f.starts_with(".")) } fn ext_match(args: ¶meters::Parameters, entry: &DirEntry) -> bool { if entry.file_type().is_dir() { return true; } if !args.scan_hidden && is_hidden(entry) { return false; } let path = Path::new(entry.file_name()); if let Some(extensions) = &args.extensions { return match path.extension() { None => true, Some(ext) => { extensions.contains(&ext.to_string_lossy().into()) } } } false } fn mime_type(db: &SharedMimeInfo, filepath: &Path) -> io::Result, > { let mut buffer = [0; 1024]; // attempt to read up to the first kilobyte of the file let mut file = File::open(filepath)?; file.read(&mut buffer)?; Ok(db.get_mime_type_for_data(&buffer).map(|m| m.0)) } fn get_ext_from_mime(mime: &Mime) -> Option { match mime_guess::get_mime_extensions(mime) // get a list of possible extensions for this mime type .map(|g| g[0]) { // take the first option in the list and return it as a string // jpeg files are given the primary extension "jpe", due to the extension list being stored in alphabetical order. // to handle this particular case, swap "jpe" out for "jpg", and leave everything else the same, making sure we // convert the &strs to Strings. Some("jpe") => Some(String::from("jpg")), Some(ext) => Some(String::from(ext)), None => None } } fn main() { let args = parameters::Parameters::from_args(); let db = xdg_mime::SharedMimeInfo::new(); println!("{:#?}", args); // println!("{:#?}", args.dirs); println!("=====\nIterating directory: {:?}\n=====", args.dirs); let stepper = WalkDir::new(&args.dirs).into_iter(); for entry in stepper.filter_entry(|e| ext_match(&args, e)) { let entry = entry.unwrap(); if !entry.file_type().is_file() { println!("{} is not a file", entry.path().display()); continue } // let result = tree_magic_mini::from_filepath(entry.path()).unwrap_or("???"); let result = mime_type(&db, entry.path()).unwrap().unwrap(); println!( "{} has type {}, extension should be {:?}", entry.path().display(), result, get_ext_from_mime(&result) ); } // println!("WEBP CHECK: {:#?}", tree_magic_mini::match_filepath( // "image/webp", // Path::new("imgs/true_webp_lossless.webp")) // ); }