imdb-async 0.12.2

Opinionated and unopinionated async wrappers to efficiently retrieve and parse IMDB's dataset
Documentation
use arrayvec::ArrayVec;
use compact_str::CompactString;
use serde::de::Unexpected;
use serde::Deserialize;
use serde::Deserializer;
use serde::Serialize;
use serde_repr::Deserialize_repr;
use serde_repr::Serialize_repr;

use crate::genre::Genre;

#[derive(Debug, Deserialize, Serialize)]
/// Represents a single title in IMDB; a "title" can be a show, an episode of a show, a movie, etc.  See [TitleType] for a list.
pub struct Title {
	/// ID from IMDB, with the leading "tt" removed
	pub imdb_id: u32,
	pub title_type: TitleType,
	pub primary_title: CompactString,
	pub original_title: CompactString,
	pub is_adult: bool,
	pub start_year: Option<u16>,
	pub end_year: Option<u16>,
	pub runtime_minutes: Option<u16>,
	pub genres: ArrayVec<Genre, 3>
}

impl From<TitleFromImdb> for Title /* {{{ */ {
	#[inline]
	fn from(input: TitleFromImdb) -> Self {
		Self{
			imdb_id: input.imdb_id,
			title_type: input.title_type.into(),
			primary_title: input.primary_title,
			original_title: input.original_title,
			is_adult: input.is_adult != 0,
			start_year: input.start_year,
			end_year: input.end_year,
			runtime_minutes: input.runtime_minutes,
			genres: input.genres
		}
	}
} // }}}

#[derive(Clone, Copy, Debug, Deserialize_repr, Eq, PartialEq, Serialize_repr, strum::IntoStaticStr)]
#[repr(u8)]
/// Identifies the type of a [Title].  IMDB has more possible values that, because this crate is opinionated, we collapse down.
///
/// For example, "episode", "tvEpisode", and "tvPilot" all become TitleType::Episode.
pub enum TitleType {
	Short = 0,
	Movie = 1,
	Episode = 2,
	TVSeries = 3,
	TVShort = 4,
	TVSpecial = 5,
	Video = 6,
	VideoGame = 7,
	Audiobook = 8,
	RadioSeries = 9,
	RadioEpisode = 10
}

impl From<TitleTypeFromImdb> for TitleType /* {{{ */ {
	#[inline]
	fn from(input: TitleTypeFromImdb) -> Self {
		match input {
			TitleTypeFromImdb::Short => Self::Short,
			TitleTypeFromImdb::Movie => Self::Movie,
			TitleTypeFromImdb::Episode => Self::Episode,
			TitleTypeFromImdb::TVSeries => Self::TVSeries,
			TitleTypeFromImdb::TVShort => Self::TVShort,
			TitleTypeFromImdb::TVSpecial => Self::TVSpecial,
			TitleTypeFromImdb::Video => Self::Video,
			TitleTypeFromImdb::VideoGame => Self::VideoGame,
			TitleTypeFromImdb::Audiobook => Self::Audiobook,
			TitleTypeFromImdb::RadioSeries => Self::RadioSeries,
			TitleTypeFromImdb::RadioEpisode => Self::RadioEpisode
		}
	}
} // }}}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct TitleFromImdb {
	#[serde(rename = "tconst", deserialize_with = "crate::util::parse_imdb_id")]
	pub imdb_id: u32,
	pub title_type: TitleTypeFromImdb,
	pub primary_title: CompactString,
	pub original_title: CompactString,
	pub is_adult: u8,
	#[serde(deserialize_with = "crate::util::parse_janky_tsv_option")]
	pub start_year: Option<u16>,
	#[serde(deserialize_with = "crate::util::parse_janky_tsv_option")]
	pub end_year: Option<u16>,
	#[serde(deserialize_with = "crate::util::parse_janky_tsv_option")]
	pub runtime_minutes: Option<u16>,
	#[serde(deserialize_with = "crate::genre::deserialize")]
	pub genres: ArrayVec<Genre, 3>
}

#[derive(Debug, Eq, PartialEq)]
pub(crate) enum TitleTypeFromImdb {
	Short,
	Movie,
	Episode,
	TVSeries,
	TVShort,
	TVSpecial,
	Video,
	VideoGame,
	Audiobook,
	RadioSeries,
	RadioEpisode
}

impl<'de> Deserialize<'de> for TitleTypeFromImdb {
	#[inline]
	fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
		let s: &str = Deserialize::deserialize(deserializer)?;
		Ok(match s {
			"short" => Self::Short,
			"episode" | "tvEpisode" | "tvPilot" => Self::Episode,
			"movie" | "tvMovie" => Self::Movie,
			"tvSeries" | "tvMiniSeries" => Self::TVSeries,
			"tvShort" => Self::TVShort,
			"tvSpecial" => Self::TVSpecial,
			"video" => Self::Video,
			"videoGame" => Self::VideoGame,
			"audiobook" => Self::Audiobook,
			"radioSeries" => Self::RadioSeries,
			"radioEpisode" => Self::RadioEpisode,
			s => return Err(serde::de::Error::invalid_value(Unexpected::Str(s), &"'short', 'episode', 'tvEpisode', 'tvPilot', 'movie', 'tvMovie', 'tvSeries', 'tvMiniSeries', 'tvShort', 'tvSpecial', 'video', 'videoGame', 'audiobook', 'radioSeries', 'radioEpisode'"))
		})
	}
}