use std::collections::HashMap;
use futures::stream::StreamExt;
use crate::EpisodeLink;
use crate::Error;
use crate::Title;
use crate::TitleType;
use crate::get_episodes_filtered;
use crate::stream_titles_filtered;
pub async fn get_shows_filtered(ids: &[u64]) -> Result<Vec<Show>, Error> {
let mut episode_links = get_episodes_filtered(ids).await?;
let all_ids = {
let mut v = Vec::from(ids);
v.extend(episode_links.iter().map(|(id, _)| id));
v
};
let mut episodes_by_show = HashMap::new();
let mut shows = Vec::with_capacity(ids.len());
let mut stream = stream_titles_filtered(&all_ids).await?;
while let Some(result) = stream.next().await {
let title = result?;
if let Some(link) = episode_links.remove(&title.imdb_id) {
let series_id = link.series_imdb_id;
if let Some(result) = Episode::from_title_and_link(title, link) {
let episode = result?;
let episodes = episodes_by_show.entry(series_id).or_insert_with(|| Vec::new());
episodes.push(episode);
}
continue;
}
shows.push(match Show::from_title(&title) {
Some(Ok(v)) => v,
Some(Err(e)) => return Err(e),
None => continue
});
}
for show in shows.iter_mut() {
show.episodes = match episodes_by_show.remove(&show.imdb_id) {
Some(v) => v,
None => Vec::new()
};
}
Ok(shows)
}
#[derive(Debug)]
pub struct Show {
pub imdb_id: u64,
pub title: String,
pub is_adult: bool,
pub start_year: u16,
pub end_year: Option<u16>,
pub runtime_minutes: Option<u16>,
pub genres: Vec<String>,
pub episodes: Vec<Episode>
}
impl Show {
pub(crate) fn from_title(input: &Title) -> Option<Result<Self, Error>> {
match input.title_type {
TitleType::TVSeries => Some(Ok(Self{
imdb_id: input.imdb_id,
title: input.primary_title.clone(),
is_adult: input.is_adult != 0,
start_year: match input.start_year {
Some(v) => v,
None => return Some(Err(Error::YearMissing.into()))
},
end_year: input.end_year,
runtime_minutes: input.runtime_minutes,
genres: input.genres.clone(),
episodes: Vec::new()
})),
_ => None
}
}
fn from_wrapped_title(input: Result<Title, Error>) -> Option<Result<Self, Error>> {
match input {
Ok(t) => Self::from_title(&t),
Err(e) => Some(Err(e))
}
}
}
#[derive(Debug)]
pub struct Episode {
pub season: u16,
pub episode: u16,
pub imdb_id: u64,
pub title: String,
pub runtime_minutes: Option<u16>
}
impl Episode {
pub(crate) fn from_title_and_link(title: Title, link: EpisodeLink) -> Option<Result<Self, Error>> {
match title.title_type {
TitleType::Episode => Some(Ok(Self{
season: match link.season {
Some(v) => v,
None => return Some(Err(Error::SeasonMissing.into()))
},
episode: match link.episode {
Some(v) => v,
None => return Some(Err(Error::EpisodeMissing.into()))
},
imdb_id: title.imdb_id,
title: title.primary_title,
runtime_minutes: title.runtime_minutes
})),
_ => None
}
}
}