cameo 0.1.1

Unified movie/TV show database SDK for Rust
Documentation
use super::{CameoClient, CameoClientError};
#[cfg(feature = "cache")]
use crate::cache::{CacheKey, MediaType};
use crate::unified::{
    models::{UnifiedMovieDetails, UnifiedPersonDetails, UnifiedTvShowDetails},
    traits::DetailProvider,
};

impl DetailProvider for CameoClient {
    type Error = CameoClientError;

    async fn movie_details(&self, id: i32) -> Result<UnifiedMovieDetails, CameoClientError> {
        let _ = id;
        #[cfg(feature = "tmdb")]
        if let Some(client) = &self.tmdb {
            #[cfg(feature = "cache")]
            let provider_id = format!("tmdb:{id}");

            #[cfg(feature = "cache")]
            {
                let detail_key = CacheKey::Detail {
                    media_type: MediaType::Movie,
                    provider_id: provider_id.clone(),
                };
                if let Some(cache) = self.cache.as_ref()
                    && let Some(cached) = cache.get::<UnifiedMovieDetails>(&detail_key).await
                {
                    tracing::debug!(id, "cache hit: movie_details (tmdb)");
                    return Ok(cached);
                }
                if self.cache.is_some() {
                    tracing::debug!(id, "cache miss: movie_details (tmdb)");
                }
            }

            tracing::debug!(id, "dispatching movie_details to tmdb");
            let details: UnifiedMovieDetails = client.movie_details(id).await?.into();

            #[cfg(feature = "cache")]
            if let Some(cache) = self.cache.as_ref() {
                let detail_ttl = cache.ttl.movie_details_ttl(
                    details.movie.release_date.as_deref(),
                    details.status.as_deref(),
                );
                let detail_key = CacheKey::Detail {
                    media_type: MediaType::Movie,
                    provider_id: provider_id.clone(),
                };
                cache.set(detail_key, &details, detail_ttl);
                let item_key = CacheKey::Item {
                    media_type: MediaType::Movie,
                    provider_id,
                };
                cache.set(item_key, &details.movie, cache.ttl.items);
            }

            return Ok(details);
        }

        #[cfg(feature = "anilist")]
        if let Some(client) = &self.anilist {
            #[cfg(feature = "cache")]
            let provider_id = format!("anilist:{id}");

            #[cfg(feature = "cache")]
            {
                let detail_key = CacheKey::Detail {
                    media_type: MediaType::Movie,
                    provider_id: provider_id.clone(),
                };
                if let Some(cache) = self.cache.as_ref()
                    && let Some(cached) = cache.get::<UnifiedMovieDetails>(&detail_key).await
                {
                    tracing::debug!(id, "cache hit: movie_details (anilist)");
                    return Ok(cached);
                }
                if self.cache.is_some() {
                    tracing::debug!(id, "cache miss: movie_details (anilist)");
                }
            }

            tracing::debug!(id, "dispatching movie_details to anilist");
            let details = client.movie_details(id).await?;

            #[cfg(feature = "cache")]
            if let Some(cache) = self.cache.as_ref() {
                let detail_ttl = cache.ttl.movie_details_ttl(
                    details.movie.release_date.as_deref(),
                    details.status.as_deref(),
                );
                let detail_key = CacheKey::Detail {
                    media_type: MediaType::Movie,
                    provider_id: provider_id.clone(),
                };
                cache.set(detail_key, &details, detail_ttl);
                let item_key = CacheKey::Item {
                    media_type: MediaType::Movie,
                    provider_id,
                };
                cache.set(item_key, &details.movie, cache.ttl.items);
            }

            return Ok(details);
        }

        Err(CameoClientError::NoProviders)
    }

    async fn tv_show_details(&self, id: i32) -> Result<UnifiedTvShowDetails, CameoClientError> {
        let _ = id;
        #[cfg(feature = "tmdb")]
        if let Some(client) = &self.tmdb {
            #[cfg(feature = "cache")]
            let provider_id = format!("tmdb:{id}");

            #[cfg(feature = "cache")]
            {
                let detail_key = CacheKey::Detail {
                    media_type: MediaType::TvShow,
                    provider_id: provider_id.clone(),
                };
                if let Some(cache) = self.cache.as_ref()
                    && let Some(cached) = cache.get::<UnifiedTvShowDetails>(&detail_key).await
                {
                    tracing::debug!(id, "cache hit: tv_show_details (tmdb)");
                    return Ok(cached);
                }
                if self.cache.is_some() {
                    tracing::debug!(id, "cache miss: tv_show_details (tmdb)");
                }
            }

            tracing::debug!(id, "dispatching tv_show_details to tmdb");
            let details: UnifiedTvShowDetails = client.tv_series_details(id).await?.into();

            #[cfg(feature = "cache")]
            if let Some(cache) = self.cache.as_ref() {
                let detail_ttl = cache.ttl.tv_show_details_ttl(
                    details.show.first_air_date.as_deref(),
                    details.last_air_date.as_deref(),
                    details.status.as_deref(),
                    details.in_production,
                );
                let detail_key = CacheKey::Detail {
                    media_type: MediaType::TvShow,
                    provider_id: provider_id.clone(),
                };
                cache.set(detail_key, &details, detail_ttl);
                let item_key = CacheKey::Item {
                    media_type: MediaType::TvShow,
                    provider_id,
                };
                cache.set(item_key, &details.show, cache.ttl.items);
            }

            return Ok(details);
        }

        #[cfg(feature = "anilist")]
        if let Some(client) = &self.anilist {
            #[cfg(feature = "cache")]
            let provider_id = format!("anilist:{id}");

            #[cfg(feature = "cache")]
            {
                let detail_key = CacheKey::Detail {
                    media_type: MediaType::TvShow,
                    provider_id: provider_id.clone(),
                };
                if let Some(cache) = self.cache.as_ref()
                    && let Some(cached) = cache.get::<UnifiedTvShowDetails>(&detail_key).await
                {
                    tracing::debug!(id, "cache hit: tv_show_details (anilist)");
                    return Ok(cached);
                }
                if self.cache.is_some() {
                    tracing::debug!(id, "cache miss: tv_show_details (anilist)");
                }
            }

            tracing::debug!(id, "dispatching tv_show_details to anilist");
            let details = client.tv_show_details(id).await?;

            #[cfg(feature = "cache")]
            if let Some(cache) = self.cache.as_ref() {
                let detail_ttl = cache.ttl.tv_show_details_ttl(
                    details.show.first_air_date.as_deref(),
                    details.last_air_date.as_deref(),
                    details.status.as_deref(),
                    details.in_production,
                );
                let detail_key = CacheKey::Detail {
                    media_type: MediaType::TvShow,
                    provider_id: provider_id.clone(),
                };
                cache.set(detail_key, &details, detail_ttl);
                let item_key = CacheKey::Item {
                    media_type: MediaType::TvShow,
                    provider_id,
                };
                cache.set(item_key, &details.show, cache.ttl.items);
            }

            return Ok(details);
        }

        Err(CameoClientError::NoProviders)
    }

    async fn person_details(&self, id: i32) -> Result<UnifiedPersonDetails, CameoClientError> {
        let _ = id;
        #[cfg(feature = "tmdb")]
        if let Some(client) = &self.tmdb {
            #[cfg(feature = "cache")]
            let provider_id = format!("tmdb:{id}");

            #[cfg(feature = "cache")]
            {
                let detail_key = CacheKey::Detail {
                    media_type: MediaType::Person,
                    provider_id: provider_id.clone(),
                };
                if let Some(cache) = self.cache.as_ref()
                    && let Some(cached) = cache.get::<UnifiedPersonDetails>(&detail_key).await
                {
                    tracing::debug!(id, "cache hit: person_details (tmdb)");
                    return Ok(cached);
                }
                if self.cache.is_some() {
                    tracing::debug!(id, "cache miss: person_details (tmdb)");
                }
            }

            tracing::debug!(id, "dispatching person_details to tmdb");
            let details: UnifiedPersonDetails = client.person_details(id).await?.into();

            #[cfg(feature = "cache")]
            if let Some(cache) = self.cache.as_ref() {
                let detail_key = CacheKey::Detail {
                    media_type: MediaType::Person,
                    provider_id: provider_id.clone(),
                };
                cache.set(detail_key, &details, cache.ttl.details);
                let item_key = CacheKey::Item {
                    media_type: MediaType::Person,
                    provider_id,
                };
                cache.set(item_key, &details.person, cache.ttl.items);
            }

            return Ok(details);
        }

        #[cfg(feature = "anilist")]
        if let Some(client) = &self.anilist {
            #[cfg(feature = "cache")]
            let provider_id = format!("anilist:staff:{id}");

            #[cfg(feature = "cache")]
            {
                let detail_key = CacheKey::Detail {
                    media_type: MediaType::Person,
                    provider_id: provider_id.clone(),
                };
                if let Some(cache) = self.cache.as_ref()
                    && let Some(cached) = cache.get::<UnifiedPersonDetails>(&detail_key).await
                {
                    tracing::debug!(id, "cache hit: person_details (anilist)");
                    return Ok(cached);
                }
                if self.cache.is_some() {
                    tracing::debug!(id, "cache miss: person_details (anilist)");
                }
            }

            tracing::debug!(id, "dispatching person_details to anilist");
            let details = client.person_details(id).await?;

            #[cfg(feature = "cache")]
            if let Some(cache) = self.cache.as_ref() {
                let detail_key = CacheKey::Detail {
                    media_type: MediaType::Person,
                    provider_id: provider_id.clone(),
                };
                cache.set(detail_key, &details, cache.ttl.details);
                let item_key = CacheKey::Item {
                    media_type: MediaType::Person,
                    provider_id,
                };
                cache.set(item_key, &details.person, cache.ttl.items);
            }

            return Ok(details);
        }

        Err(CameoClientError::NoProviders)
    }
}