use async_trait::async_trait;
use super::client::AniListClient;
use crate::{
core::{config::TimeWindow, error::ProviderError, pagination::Page},
unified::{
media_id::{MediaId, NativeId},
models::{
UnifiedMovie, UnifiedMovieDetails, UnifiedPerson, UnifiedPersonDetails,
UnifiedSearchResult, UnifiedTvShow, UnifiedTvShowDetails,
},
traits::{Capability, DetailProvider, DiscoveryProvider, Provider, SearchProvider},
},
};
const ANILIST_CAPABILITIES: &[Capability] = &[
Capability::Search,
Capability::Details,
Capability::Discovery,
];
impl Provider for AniListClient {
fn id(&self) -> &str {
"anilist"
}
fn capabilities(&self) -> &[Capability] {
ANILIST_CAPABILITIES
}
}
fn anilist_id(id: &MediaId) -> Result<i32, ProviderError> {
if id.provider() != "anilist" {
return Err(ProviderError::InvalidInput(format!(
"expected an anilist id, got {id}"
)));
}
let numeric = match id.native() {
NativeId::Num(n) => *n,
NativeId::Text(s) => s
.rsplit(':')
.next()
.and_then(|part| part.parse::<u64>().ok())
.ok_or_else(|| {
ProviderError::InvalidInput(format!("not a numeric AniList id: {id}"))
})?,
};
i32::try_from(numeric)
.map_err(|_| ProviderError::InvalidInput(format!("AniList id out of range: {id}")))
}
#[async_trait]
impl SearchProvider for AniListClient {
async fn search_movies(
&self,
query: &str,
page: Option<u32>,
) -> Result<Page<UnifiedMovie>, ProviderError> {
Ok(AniListClient::search_movies(self, query, page).await?)
}
async fn search_tv_shows(
&self,
query: &str,
page: Option<u32>,
) -> Result<Page<UnifiedTvShow>, ProviderError> {
Ok(AniListClient::search_tv_shows(self, query, page).await?)
}
async fn search_people(
&self,
query: &str,
page: Option<u32>,
) -> Result<Page<UnifiedPerson>, ProviderError> {
Ok(AniListClient::search_people(self, query, page).await?)
}
async fn search_multi(
&self,
query: &str,
page: Option<u32>,
) -> Result<Page<UnifiedSearchResult>, ProviderError> {
Ok(AniListClient::search_multi(self, query, page).await?)
}
}
#[async_trait]
impl DetailProvider for AniListClient {
async fn movie_details(&self, id: &MediaId) -> Result<UnifiedMovieDetails, ProviderError> {
Ok(AniListClient::movie_details(self, anilist_id(id)?).await?)
}
async fn tv_show_details(&self, id: &MediaId) -> Result<UnifiedTvShowDetails, ProviderError> {
Ok(AniListClient::tv_show_details(self, anilist_id(id)?).await?)
}
async fn person_details(&self, id: &MediaId) -> Result<UnifiedPersonDetails, ProviderError> {
Ok(AniListClient::person_details(self, anilist_id(id)?).await?)
}
}
#[async_trait]
impl DiscoveryProvider for AniListClient {
async fn trending_movies(
&self,
time_window: TimeWindow,
page: Option<u32>,
) -> Result<Page<UnifiedMovie>, ProviderError> {
Ok(AniListClient::trending_movies(self, time_window, page).await?)
}
async fn trending_tv_shows(
&self,
time_window: TimeWindow,
page: Option<u32>,
) -> Result<Page<UnifiedTvShow>, ProviderError> {
Ok(AniListClient::trending_tv(self, time_window, page).await?)
}
async fn popular_movies(&self, page: Option<u32>) -> Result<Page<UnifiedMovie>, ProviderError> {
Ok(AniListClient::popular_movies(self, page).await?)
}
async fn top_rated_movies(
&self,
page: Option<u32>,
) -> Result<Page<UnifiedMovie>, ProviderError> {
Ok(AniListClient::top_rated_movies(self, page).await?)
}
async fn popular_tv_shows(
&self,
page: Option<u32>,
) -> Result<Page<UnifiedTvShow>, ProviderError> {
Ok(AniListClient::popular_tv_shows(self, page).await?)
}
async fn top_rated_tv_shows(
&self,
page: Option<u32>,
) -> Result<Page<UnifiedTvShow>, ProviderError> {
Ok(AniListClient::top_rated_tv_shows(self, page).await?)
}
}