use std::collections::HashMap; use std::error::Error; use std::fmt; use std::fs::File; use std::io::BufReader; use std::path::Path; use glob::glob; use human_format::Formatter; use human_format::Scales; use serde::Deserialize; const MOVIE_DIR: &str = "/home/wathiede/Movies"; #[derive(Deserialize, Debug)] struct Resolution(usize, usize); impl fmt::Display for Resolution { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let v = format!("{}x{}", self.0, self.1); f.pad(&v) } } #[derive(Deserialize, Debug)] struct Metadata { size: usize, dimension: Resolution, duration_text: String, duration: f32, } #[derive(Deserialize, Debug)] struct MetadataFile { #[serde(flatten)] metadata: HashMap, } fn read_metadata_from_file>(path: P) -> Result> { // Open the file in read-only mode with buffer. let file = File::open(path)?; let reader = BufReader::new(file); // Read the JSON contents of the file as an instance of `User`. let md = serde_json::from_reader(reader)?; // Return the `User`. Ok(md) } fn main() -> Result<(), Box> { let mut movies = HashMap::new(); for md in glob(&format!("{}/*/metadata.json", MOVIE_DIR))? { match md { Ok(path) => { let mdf = read_metadata_from_file(&path)?; for (name, md) in mdf.metadata { movies.insert(name, md); } } Err(e) => eprintln!("{:?}", e), } } let mut names = movies.keys().collect::>(); names.sort(); let mut fmtr = Formatter::new(); fmtr.with_separator(""); fmtr.with_scales(Scales::Binary()); for name in names { let md = &movies[name]; println!( "{:>9} {:>8} {} {}", md.dimension, fmtr.format(md.size as f64), md.duration_text, &name[MOVIE_DIR.len() + 1..] ); } Ok(()) }