#![deny(missing_docs, missing_debug_implementations, unsafe_code)]
use chrono::{DateTime, Utc};
use serde::Serialize;
use crate::response::SeriesID;
use crate::serialization as ser;
#[derive(Debug)]
pub enum SearchBy<S> {
Name(S),
IMDbID(S),
Zap2itID(S),
Slug(S),
}
impl<S> SearchBy<S>
where
S: AsRef<str>,
{
pub(crate) fn query_param(&self) -> [(&str, &str); 1] {
use SearchBy::*;
match self {
Name(name) => [("name", name.as_ref())],
IMDbID(id) => [("imdbId", id.as_ref())],
Zap2itID(id) => [("zap2itId", id.as_ref())],
Slug(slug) => [("slug", slug.as_ref())],
}
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct EpisodeParams {
pub(crate) series_id: SeriesID,
pub(crate) page: u16,
}
impl EpisodeParams {
pub fn new<I>(series_id: I) -> Self
where
I: Into<SeriesID>,
{
let series_id = series_id.into();
Self { series_id, page: 1 }
}
pub fn with_page<I>(series_id: I, page: u16) -> Self
where
I: Into<SeriesID>,
{
let series_id = series_id.into();
Self { series_id, page }
}
pub fn page(mut self, page: u16) -> Self {
self.page = page;
self
}
}
pub trait GetEpisodeParams<'a> {
fn series_id(&'a self) -> SeriesID;
fn episode_params(&'a self) -> EpisodeParams {
EpisodeParams::new(self.series_id())
}
fn episode_params_page(&'a self, page: u16) -> EpisodeParams {
EpisodeParams::with_page(self.series_id(), page)
}
}
impl<'a, T> GetEpisodeParams<'a> for T
where
T: 'a,
SeriesID: From<&'a T>,
{
fn series_id(&'a self) -> SeriesID {
SeriesID::from(self)
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct EpisodeQuery {
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) absolute_number: Option<u16>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) aired_season: Option<u16>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) aired_episode: Option<u16>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) dvd_season: Option<u16>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) dvd_episode: Option<u16>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) imdb_id: Option<String>,
}
#[derive(Debug, PartialEq, Eq)]
pub struct EpisodeQueryParams {
pub(crate) params: EpisodeParams,
pub(crate) query: EpisodeQuery,
}
impl EpisodeQueryParams {
pub fn new<I>(series_id: I) -> Self
where
I: Into<SeriesID>,
{
Self {
params: EpisodeParams::new(series_id),
query: Default::default(),
}
}
pub fn with_page<I>(series_id: I, page: u16) -> Self
where
I: Into<SeriesID>,
{
Self {
params: EpisodeParams::with_page(series_id, page),
query: Default::default(),
}
}
pub(crate) fn with_page_query<I>(series_id: I, page: u16, query: EpisodeQuery) -> Self
where
I: Into<SeriesID>,
{
Self {
params: EpisodeParams::with_page(series_id, page),
query,
}
}
pub fn page(mut self, page: u16) -> Self {
self.params.page = page;
self
}
pub fn absolute_number(mut self, number: u16) -> Self {
self.query.absolute_number = Some(number);
self
}
pub fn aired_season(mut self, season: u16) -> Self {
self.query.aired_season = Some(season);
self
}
pub fn aired_episode(mut self, episode: u16) -> Self {
self.query.aired_episode = Some(episode);
self
}
pub fn dvd_season(mut self, season: u16) -> Self {
self.query.dvd_season = Some(season);
self
}
pub fn dvd_episode(mut self, episode: u16) -> Self {
self.query.dvd_episode = Some(episode);
self
}
pub fn imdb_id<S>(mut self, id: S) -> Self
where
S: Into<String>,
{
self.query.imdb_id = Some(id.into());
self
}
}
pub trait GetEpisodeQueryParams<'a> {
fn series_id(&'a self) -> SeriesID;
fn episode_query_params(&'a self) -> EpisodeQueryParams {
EpisodeQueryParams::new(self.series_id())
}
fn episode_query_params_page(&'a self, page: u16) -> EpisodeQueryParams {
EpisodeQueryParams::with_page(self.series_id(), page)
}
}
impl<'a, T> GetEpisodeQueryParams<'a> for T
where
T: 'a,
SeriesID: From<&'a T>,
{
fn series_id(&'a self) -> SeriesID {
self.into()
}
}
#[derive(Debug)]
pub struct SeriesFilterKeys {
pub(crate) keys_query: String,
}
impl SeriesFilterKeys {
const FULL_CAPACITY: usize = 221;
pub fn new() -> Self {
Self {
keys_query: String::with_capacity(Self::FULL_CAPACITY),
}
}
pub fn network_id(self) -> Self {
self.push_key("networkId")
}
pub fn last_updated(self) -> Self {
self.push_key("lastUpdated")
}
pub fn airs_time(self) -> Self {
self.push_key("airsTime")
}
pub fn site_rating(self) -> Self {
self.push_key("siteRating")
}
pub fn series_name(self) -> Self {
self.push_key("seriesName")
}
pub fn first_aired(self) -> Self {
self.push_key("firstAired")
}
pub fn runtime(self) -> Self {
self.push_key("runtime")
}
pub fn overview(self) -> Self {
self.push_key("overview")
}
pub fn banner(self) -> Self {
self.push_key("banner")
}
pub fn genre(self) -> Self {
self.push_key("genre")
}
pub fn airs_day_of_week(self) -> Self {
self.push_key("airsDayOfWeek")
}
pub fn imdb_id(self) -> Self {
self.push_key("imdbId")
}
pub fn added_by(self) -> Self {
self.push_key("addedBy")
}
pub fn site_rating_count(self) -> Self {
self.push_key("siteRatingCount")
}
pub fn id(self) -> Self {
self.push_key("id")
}
pub fn status(self) -> Self {
self.push_key("status")
}
pub fn network(self) -> Self {
self.push_key("network")
}
pub fn rating(self) -> Self {
self.push_key("rating")
}
pub fn zap2it_id(self) -> Self {
self.push_key("zap2itId")
}
pub fn added(self) -> Self {
self.push_key("added")
}
pub fn slug(self) -> Self {
self.push_key("slug")
}
pub fn aliases(self) -> Self {
self.push_key("aliases")
}
pub fn season(self) -> Self {
self.push_key("season")
}
pub fn poster(self) -> Self {
self.push_key("poster")
}
pub fn fanart(self) -> Self {
self.push_key("fanart")
}
pub fn language(self) -> Self {
self.push_key("language")
}
pub fn is_empty(&self) -> bool {
self.keys_query.is_empty()
}
#[cfg(test)]
pub(crate) fn is_at_full_capacity(&self) -> bool {
self.keys_query.len() == Self::FULL_CAPACITY
}
fn push_key(mut self, key: &str) -> Self {
if !self.keys_query.is_empty() {
self.keys_query.push(',');
}
self.keys_query.push_str(key);
self
}
}
impl Default for SeriesFilterKeys {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ImageQueryParams {
#[serde(skip_serializing_if = "Option::is_none")]
key_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
resolution: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
sub_key: Option<String>,
}
impl ImageQueryParams {
pub fn with_key_type<S>(key_type: S) -> Self
where
S: Into<String>,
{
Self {
key_type: Some(key_type.into()),
..Default::default()
}
}
pub fn with_resolution<S>(resolution: S) -> Self
where
S: Into<String>,
{
Self {
resolution: Some(resolution.into()),
..Default::default()
}
}
pub fn with_sub_key<S>(sub_key: S) -> Self
where
S: Into<String>,
{
Self {
sub_key: Some(sub_key.into()),
..Default::default()
}
}
pub fn key_type<S>(mut self, key_type: S) -> Self
where
S: Into<String>,
{
self.key_type = Some(key_type.into());
self
}
pub fn resolution<S>(mut self, resolution: S) -> Self
where
S: Into<String>,
{
self.resolution = Some(resolution.into());
self
}
pub fn sub_key<S>(mut self, sub_key: S) -> Self
where
S: Into<String>,
{
self.sub_key = Some(sub_key.into());
self
}
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UpdatedParams {
#[serde(serialize_with = "chrono::serde::ts_seconds::serialize")]
from_time: DateTime<Utc>,
#[serde(skip_serializing_if = "Option::is_none")]
to_time: Option<ser::Timestamp>,
}
impl UpdatedParams {
pub fn new<D>(from: D) -> Self
where
D: Into<DateTime<Utc>>,
{
Self {
from_time: from.into(),
to_time: None,
}
}
pub fn with_to_time<D>(from: D, to: D) -> Self
where
D: Into<DateTime<Utc>>,
{
Self {
from_time: from.into(),
to_time: Some(ser::Timestamp(to.into())),
}
}
#[allow(clippy::wrong_self_convention)]
pub fn to_time<D>(mut self, to: D) -> Self
where
D: Into<DateTime<Utc>>,
{
self.to_time = Some(ser::Timestamp(to.into()));
self
}
}
#[cfg(test)]
mod tests;