cameo 0.1.1

Unified movie/TV show database SDK for Rust
Documentation
use super::{CameoClient, CameoClientError};
#[cfg(feature = "cache")]
use crate::cache::CacheKey;
#[cfg(all(feature = "cache", feature = "tmdb"))]
use crate::cache::MediaType;
use crate::{
    core::pagination::PaginatedResponse,
    unified::{
        models::{UnifiedMovie, UnifiedTvShow},
        traits::RecommendationProvider,
    },
};

impl RecommendationProvider for CameoClient {
    type Error = CameoClientError;

    async fn movie_recommendations(
        &self,
        id: i32,
        page: Option<u32>,
    ) -> Result<PaginatedResponse<UnifiedMovie>, CameoClientError> {
        let _ = (id, page);
        #[cfg(feature = "cache")]
        let endpoint = format!("recommendations:movie:{id}");

        #[cfg(feature = "cache")]
        let page_num = page.unwrap_or(1);

        #[cfg(feature = "cache")]
        {
            let discovery_key = CacheKey::Discovery {
                endpoint: endpoint.clone(),
                page: page_num,
            };
            if let Some(cache) = self.cache.as_ref()
                && let Some(cached) = cache
                    .get::<PaginatedResponse<UnifiedMovie>>(&discovery_key)
                    .await
            {
                tracing::debug!(id, page = page_num, "cache hit: movie_recommendations");
                return Ok(cached);
            }
            if self.cache.is_some() {
                tracing::debug!(id, page = page_num, "cache miss: movie_recommendations");
            }
        }

        #[cfg(feature = "tmdb")]
        if let Some(client) = &self.tmdb {
            tracing::debug!(id, page = ?page, "dispatching movie_recommendations to tmdb");
            let unified = client.movie_recommendations(id, page).await?;

            #[cfg(feature = "cache")]
            if let Some(cache) = self.cache.as_ref() {
                let discovery_key = CacheKey::Discovery {
                    endpoint,
                    page: page_num,
                };
                cache.set(discovery_key, &unified, cache.ttl.discovery);
                for item in &unified.results {
                    let k = CacheKey::Item {
                        media_type: MediaType::Movie,
                        provider_id: item.provider_id.clone(),
                    };
                    cache.set(k, item, cache.ttl.items);
                }
            }

            return Ok(unified);
        }

        Err(CameoClientError::NoProviders)
    }

    async fn tv_recommendations(
        &self,
        id: i32,
        page: Option<u32>,
    ) -> Result<PaginatedResponse<UnifiedTvShow>, CameoClientError> {
        let _ = (id, page);
        #[cfg(feature = "cache")]
        let endpoint = format!("recommendations:tv:{id}");

        #[cfg(feature = "cache")]
        let page_num = page.unwrap_or(1);

        #[cfg(feature = "cache")]
        {
            let discovery_key = CacheKey::Discovery {
                endpoint: endpoint.clone(),
                page: page_num,
            };
            if let Some(cache) = self.cache.as_ref()
                && let Some(cached) = cache
                    .get::<PaginatedResponse<UnifiedTvShow>>(&discovery_key)
                    .await
            {
                tracing::debug!(id, page = page_num, "cache hit: tv_recommendations");
                return Ok(cached);
            }
            if self.cache.is_some() {
                tracing::debug!(id, page = page_num, "cache miss: tv_recommendations");
            }
        }

        #[cfg(feature = "tmdb")]
        if let Some(client) = &self.tmdb {
            tracing::debug!(id, page = ?page, "dispatching tv_recommendations to tmdb");
            let page_resp = client.tv_recommendations(id, page).await?;
            let unified: PaginatedResponse<UnifiedTvShow> = PaginatedResponse {
                page: page_resp.page,
                total_pages: page_resp.total_pages,
                total_results: page_resp.total_results,
                results: page_resp.results.into_iter().map(Into::into).collect(),
            };

            #[cfg(feature = "cache")]
            if let Some(cache) = self.cache.as_ref() {
                let discovery_key = CacheKey::Discovery {
                    endpoint,
                    page: page_num,
                };
                cache.set(discovery_key, &unified, cache.ttl.discovery);
                for item in &unified.results {
                    let k = CacheKey::Item {
                        media_type: MediaType::TvShow,
                        provider_id: item.provider_id.clone(),
                    };
                    cache.set(k, item, cache.ttl.items);
                }
            }

            return Ok(unified);
        }

        Err(CameoClientError::NoProviders)
    }

    async fn similar_movies(
        &self,
        id: i32,
        page: Option<u32>,
    ) -> Result<PaginatedResponse<UnifiedMovie>, CameoClientError> {
        let _ = (id, page);
        #[cfg(feature = "cache")]
        let endpoint = format!("similar:movie:{id}");

        #[cfg(feature = "cache")]
        let page_num = page.unwrap_or(1);

        #[cfg(feature = "cache")]
        {
            let discovery_key = CacheKey::Discovery {
                endpoint: endpoint.clone(),
                page: page_num,
            };
            if let Some(cache) = self.cache.as_ref()
                && let Some(cached) = cache
                    .get::<PaginatedResponse<UnifiedMovie>>(&discovery_key)
                    .await
            {
                tracing::debug!(id, page = page_num, "cache hit: similar_movies");
                return Ok(cached);
            }
            if self.cache.is_some() {
                tracing::debug!(id, page = page_num, "cache miss: similar_movies");
            }
        }

        #[cfg(feature = "tmdb")]
        if let Some(client) = &self.tmdb {
            tracing::debug!(id, page = ?page, "dispatching similar_movies to tmdb");
            let page_resp = client.similar_movies(id, page).await?;
            let unified: PaginatedResponse<UnifiedMovie> = PaginatedResponse {
                page: page_resp.page,
                total_pages: page_resp.total_pages,
                total_results: page_resp.total_results,
                results: page_resp.results.into_iter().map(Into::into).collect(),
            };

            #[cfg(feature = "cache")]
            if let Some(cache) = self.cache.as_ref() {
                let discovery_key = CacheKey::Discovery {
                    endpoint,
                    page: page_num,
                };
                cache.set(discovery_key, &unified, cache.ttl.discovery);
                for item in &unified.results {
                    let k = CacheKey::Item {
                        media_type: MediaType::Movie,
                        provider_id: item.provider_id.clone(),
                    };
                    cache.set(k, item, cache.ttl.items);
                }
            }

            return Ok(unified);
        }

        Err(CameoClientError::NoProviders)
    }

    async fn similar_tv_shows(
        &self,
        id: i32,
        page: Option<u32>,
    ) -> Result<PaginatedResponse<UnifiedTvShow>, CameoClientError> {
        let _ = (id, page);
        #[cfg(feature = "cache")]
        let endpoint = format!("similar:tv:{id}");

        #[cfg(feature = "cache")]
        let page_num = page.unwrap_or(1);

        #[cfg(feature = "cache")]
        {
            let discovery_key = CacheKey::Discovery {
                endpoint: endpoint.clone(),
                page: page_num,
            };
            if let Some(cache) = self.cache.as_ref()
                && let Some(cached) = cache
                    .get::<PaginatedResponse<UnifiedTvShow>>(&discovery_key)
                    .await
            {
                tracing::debug!(id, page = page_num, "cache hit: similar_tv_shows");
                return Ok(cached);
            }
            if self.cache.is_some() {
                tracing::debug!(id, page = page_num, "cache miss: similar_tv_shows");
            }
        }

        #[cfg(feature = "tmdb")]
        if let Some(client) = &self.tmdb {
            tracing::debug!(id, page = ?page, "dispatching similar_tv_shows to tmdb");
            let page_resp = client.similar_tv_shows(id, page).await?;
            let unified: PaginatedResponse<UnifiedTvShow> = PaginatedResponse {
                page: page_resp.page,
                total_pages: page_resp.total_pages,
                total_results: page_resp.total_results,
                results: page_resp.results.into_iter().map(Into::into).collect(),
            };

            #[cfg(feature = "cache")]
            if let Some(cache) = self.cache.as_ref() {
                let discovery_key = CacheKey::Discovery {
                    endpoint,
                    page: page_num,
                };
                cache.set(discovery_key, &unified, cache.ttl.discovery);
                for item in &unified.results {
                    let k = CacheKey::Item {
                        media_type: MediaType::TvShow,
                        provider_id: item.provider_id.clone(),
                    };
                    cache.set(k, item, cache.ttl.items);
                }
            }

            return Ok(unified);
        }

        Err(CameoClientError::NoProviders)
    }
}