use crate::config::Config;
use crate::config::RelatedMode;
use anyhow::Context;
use anyhow::Result;
use kodik_parser::KodikApiResponse;
use kodik_parser::TranslationType;
use kodik_shiki::Anime;
use reqwest::cookie::CookieStore;
use reqwest::{Client, Url, cookie::Jar};
pub async fn resolve_shiki(client: &Client, url: &Url, config: &Config, jar: &Jar) -> Result<Vec<String>> {
let shikimori_id = kodik_utils::extract_anime_id(url.as_str())?
.parse()
.with_context(|| format!("bad shikimori id in {url}"))?;
let has_cookies = jar.cookies(url).is_some();
if config.cookies.is_some() && !has_cookies {
log::warn!("cookies not found for: {url}");
}
let shiki_api_animes = if has_cookies || config.related_mode.is_some() {
Some(Anime::fetch(client, url.as_str()).await?)
} else {
None
};
if let Some(ref mode) = config.related_mode {
if let Some(shiki_api_animes) = shiki_api_animes.as_ref() {
let Some(franchise) = shiki_api_animes.franchise.as_deref() else {
return shiki_helper(client, url, config, shikimori_id, Some(shiki_api_animes)).await;
};
let domain = url.domain().context("url have no domain")?;
let mut related = match mode {
RelatedMode::All => kodik_shiki::Franchise::fetch(client, franchise, domain, &[]).await?,
RelatedMode::Essential => {
let not_anime_ids = kodik_shiki::fetch_not_anime_ids(client, franchise)
.await?
.context("there are no 'not anime ids (just log::warn)'")?;
kodik_shiki::Franchise::fetch(client, franchise, domain, not_anime_ids).await?
}
};
related.sort_by_chrono();
let mut links = Vec::new();
for anime in &related.animes {
links.append(&mut shiki_helper(client, url, config, anime.id, Some(shiki_api_animes)).await?);
}
return Ok(links);
}
} else {
return shiki_helper(client, url, config, shikimori_id, shiki_api_animes.as_ref()).await;
}
Ok(vec![])
}
async fn shiki_helper(
client: &Client,
url: &Url,
config: &Config,
shikimori_id: usize,
shiki_api_animes: Option<&Anime>,
) -> Result<Vec<String>> {
let kodik_api_resp = KodikApiResponse::fetch_shiki(client, shikimori_id).await?;
let search_result = kodik_api_resp
.find_result(
config.translation_title.as_deref(),
config.translation_type.map(TranslationType::from),
)?
.to_owned();
let skip = shiki_api_animes.map_or(0, |shiki_api_animes| {
shiki_api_animes.user_rate.as_ref().map_or_else(
|| {
if config.cookies.is_some() {
log::warn!("user rate not found for: {url}, defaulting to first episode");
}
0
},
|user_rate| user_rate.episodes,
)
});
let mut links = Vec::new();
if let Some(seasons) = search_result.seasons {
let (_, season) = seasons.into_iter().next_back().context("season not found")?;
for (_, link) in season.episodes.into_iter().skip(skip) {
links.push(link);
}
} else {
if skip > 0 {
return Ok(links);
}
let link = search_result.link;
links.push(link);
}
Ok(links)
}