Enumerate show episodes lazily and don't cache the results

This commit is contained in:
xenofem 2023-07-01 18:58:27 -04:00
parent 3113a50169
commit 4081056224
2 changed files with 51 additions and 65 deletions

View file

@ -27,7 +27,14 @@ async fn main() {
loop { loop {
let (title, show) = shows.iter().choose(&mut rng).expect("No shows found!"); let (title, show) = shows.iter().choose(&mut rng).expect("No shows found!");
let (num, file) = show.episodes.iter().choose(&mut rng).unwrap(); let episodes = match show.episodes() {
Ok(eps) => eps,
Err(e) => {
error!("Failed to get episodes for {}: {}", title, e);
continue;
}
};
let (num, file) = episodes.iter().choose(&mut rng).unwrap();
let descriptor = format!( let descriptor = format!(
"{}{}", "{}{}",

View file

@ -6,7 +6,7 @@ use serde::Deserialize;
mod enumeration; mod enumeration;
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct ShowSpec { pub struct Show {
pub path: PathBuf, pub path: PathBuf,
pub tags: Vec<String>, pub tags: Vec<String>,
} }
@ -20,71 +20,50 @@ pub enum EpisodeNumber {
type Episodes = HashMap<EpisodeNumber, PathBuf>; type Episodes = HashMap<EpisodeNumber, PathBuf>;
pub struct Show {
pub episodes: Episodes,
pub tags: Vec<String>,
}
pub fn load(shows_file: PathBuf) -> HashMap<String, Show> { pub fn load(shows_file: PathBuf) -> HashMap<String, Show> {
let show_specs: HashMap<String, ShowSpec> = serde_yaml::from_reader(fs::File::open(shows_file).expect("Failed to open shows file"))
serde_yaml::from_reader(fs::File::open(shows_file).expect("Failed to open shows file")) .expect("Failed to parse YAML from shows file")
.expect("Failed to parse YAML from shows file");
show_specs
.into_iter()
.filter_map(|(name, show)| {
debug!("Enumerating show {}: {}", name, show.path.display());
load_path(show.path)
.map_err(|e| {
error!("Error processing {}: {}", name, e);
})
.ok()
.map(|eps| {
(
name,
Show {
episodes: eps,
tags: show.tags,
},
)
})
})
.collect()
} }
fn load_path(path: PathBuf) -> std::io::Result<Episodes> { impl Show {
let metadata = fs::metadata(&path)?; pub fn episodes(&self) -> std::io::Result<Episodes> {
if metadata.is_file() { let path = &self.path;
debug!("{} is a file, standalone", path.display()); let metadata = fs::metadata(path)?;
Ok(HashMap::from([(EpisodeNumber::Standalone, path)])) if metadata.is_file() {
} else if metadata.is_dir() { debug!("{} is a file, standalone", path.display());
debug!("{} is a directory, enumerating episodes", path.display()); Ok(HashMap::from([(
let files: Vec<PathBuf> = fs::read_dir(&path)? EpisodeNumber::Standalone,
.map(|entry| { path.to_path_buf(),
let entry = entry?; )]))
if !entry.file_type()?.is_file() { } else if metadata.is_dir() {
debug!("Skipping {}, not a file", entry.path().display()); debug!("{} is a directory, enumerating episodes", path.display());
return Ok(None); let files: Vec<PathBuf> = fs::read_dir(path)?
} .map(|entry| {
if entry.file_name().into_string().is_err() { let entry = entry?;
debug!( if !entry.file_type()?.is_file() {
"Skipping {}, contains invalid unicode", debug!("Skipping {}, not a file", entry.path().display());
entry.path().display() return Ok(None);
); }
return Ok(None); if entry.file_name().into_string().is_err() {
} error!(
Ok(Some(entry.path())) "Path {} contains invalid unicode, skipping",
}) entry.path().display()
.filter_map(|r| r.transpose()) );
.collect::<std::io::Result<Vec<PathBuf>>>()?; return Ok(None);
enumeration::enumerate_episodes(files).ok_or(std::io::Error::new( }
ErrorKind::InvalidData, Ok(Some(entry.path()))
"No valid prefixes found", })
)) .filter_map(|r| r.transpose())
} else { .collect::<std::io::Result<Vec<PathBuf>>>()?;
Err(std::io::Error::new( enumeration::enumerate_episodes(files).ok_or(std::io::Error::new(
ErrorKind::InvalidInput, ErrorKind::InvalidData,
format!("Invalid file type for {}", path.display()), "No valid prefixes found",
)) ))
} else {
Err(std::io::Error::new(
ErrorKind::InvalidInput,
format!("Invalid file type for {}", path.display()),
))
}
} }
} }