use cursive::utils::Counter; use failure::Error; use std::collections::HashSet; use std::fs::File; use std::io::prelude::*; use std::path::PathBuf; use walkdir::{DirEntry, WalkDir}; #[derive(Default)] pub struct Registry { pub device: String, pub base_path: PathBuf, pub albums_fs: HashSet, pub albums_list: HashSet, pub selected_albums: HashSet, } impl Registry { pub fn load_albums_fs(&mut self, counter: &Counter) -> Result<(), Error> { let dir_walker = WalkDir::new(self.base_path.clone()) .sort_by(|a, b| a.path().cmp(b.path())) .min_depth(2) .max_depth(2); let dir_filter = |entry: &DirEntry| { // The entry should be a directory and its name should not start with "extra" entry.metadata().map(|e| e.is_dir()).unwrap_or(false) && !entry .file_name() .to_str() .map(|s| s.starts_with("extra")) .unwrap_or(true) }; for entry in dir_walker.into_iter().filter_entry(dir_filter) { self.albums_fs.insert( entry? .path() .strip_prefix(self.base_path.clone())? .to_path_buf(), ); counter.tick(1); } counter.set(self.albums_fs.len()); Ok(()) } pub fn load_albums_file(&mut self) -> Result<(), Error> { let mut file = File::open(format!("{}.list", self.device))?; let mut contents = String::new(); file.read_to_string(&mut contents)?; let line_filter = |line: &&str| line.ends_with("***"); for line in contents.lines().filter(line_filter) { let path = line.trim_left_matches('#').trim_right_matches("/***"); if !line.starts_with('#') { self.selected_albums.insert(PathBuf::from(path)); } self.albums_list.insert(PathBuf::from(path)); } Ok(()) } pub fn save_albums_file(&self) -> Result<(), Error> { let mut file = File::create(format!("{}.list.new", self.device))?; let mut cur_artist = PathBuf::new(); let mut albums: Vec<&PathBuf> = self.albums_fs.iter().collect(); albums.sort(); for album in albums { let artist = album.parent().unwrap(); if artist != cur_artist { let artist_str = format!("{}/", artist.to_str().unwrap()); // FIXME: Make this way more efficient! if self .selected_albums .iter() .any(|ref path| path.starts_with(&artist_str)) { writeln!(file, "{}", artist_str)?; } else { writeln!(file, "#{}", artist_str)?; } cur_artist = artist.to_path_buf(); } let album_str = album.to_str().unwrap(); if self.selected_albums.contains(album) { writeln!(file, "{}/***", album_str)?; } else { writeln!(file, "#{}/***", album_str)?; } } Ok(()) } pub fn added_albums(&self) -> Vec<&PathBuf> { let mut result: Vec<&PathBuf> = self.albums_fs.difference(&self.albums_list).collect(); result.sort(); result } pub fn existing_albums(&self) -> Vec<&PathBuf> { let mut result: Vec<&PathBuf> = self.albums_fs.intersection(&self.albums_list).collect(); result.sort(); result } pub fn removed_albums(&self) -> Vec<&PathBuf> { let mut result: Vec<&PathBuf> = self.albums_list.difference(&self.albums_fs).collect(); result.sort(); result } pub fn select_album(&mut self, album_path: &PathBuf, result: bool) { if result { self.selected_albums.insert(album_path.clone()); } else { self.selected_albums.remove(album_path); } } }