diff options
author | metamuffin <metamuffin@disroot.org> | 2024-01-21 23:38:28 +0100 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2024-01-21 23:38:28 +0100 |
commit | b127ee51925f59b306b032dbacc11464ed175a60 (patch) | |
tree | b7097c20a560019f90394de9e21da4c498aadabb /import/src/tmdb.rs | |
parent | a8fe841aaefe904121d936e608572a1422191167 (diff) | |
download | jellything-b127ee51925f59b306b032dbacc11464ed175a60.tar jellything-b127ee51925f59b306b032dbacc11464ed175a60.tar.bz2 jellything-b127ee51925f59b306b032dbacc11464ed175a60.tar.zst |
refactor tmdb api, cast&crew, node ext
Diffstat (limited to 'import/src/tmdb.rs')
-rw-r--r-- | import/src/tmdb.rs | 194 |
1 files changed, 140 insertions, 54 deletions
diff --git a/import/src/tmdb.rs b/import/src/tmdb.rs index 95ebef4..b651223 100644 --- a/import/src/tmdb.rs +++ b/import/src/tmdb.rs @@ -1,3 +1,5 @@ +use std::{fmt::Display, sync::Arc}; + /* This file is part of jellything (https://codeberg.org/metamuffin/jellything) which is licensed under the GNU Affero General Public License (version 3); see /COPYING. @@ -5,11 +7,143 @@ */ use anyhow::Context; use bincode::{Decode, Encode}; -use jellycommon::chrono::{format::Parsed, Utc}; +use jellybase::cache::{async_cache_file, async_cache_memory}; +use jellycommon::{ + chrono::{format::Parsed, Utc}, + AssetLocation, +}; use log::info; +use reqwest::{ + header::{HeaderMap, HeaderName, HeaderValue}, + Client, ClientBuilder, +}; use serde::Deserialize; +use tokio::io::AsyncWriteExt; + +pub struct Tmdb { + client: Client, + key: String, +} + +impl Tmdb { + pub fn new(api_key: &str) -> Self { + let client = ClientBuilder::new() + .default_headers(HeaderMap::from_iter([( + HeaderName::from_static("accept"), + HeaderValue::from_static("application/json"), + )])) + .build() + .unwrap(); + Self { + client, + key: api_key.to_owned(), + } + } + pub async fn search(&self, kind: TmdbKind, query: &str) -> anyhow::Result<Arc<TmdbQuery>> { + async_cache_memory( + &["api-tmdb-search", query, &format!("{kind}")], + || async move { + info!("searching tmdb: {query:?}"); + Ok(self + .client + .get(&format!( + "https://api.themoviedb.org/3/search/{kind}?query={}?api_key={}", + query.replace(" ", "+"), + self.key + )) + .send() + .await? + .error_for_status()? + .json::<TmdbQuery>() + .await?) + }, + ) + .await + } + pub async fn details(&self, kind: TmdbKind, id: u64) -> anyhow::Result<Arc<TmdbDetails>> { + async_cache_memory( + &["api-tmdb-details", &format!("{kind} {id}")], + || async move { + info!("fetching details: {id:?}"); + Ok(self + .client + .get(&format!( + "https://api.themoviedb.org/3/{kind}/{id}?api_key={}", + self.key, + )) + .send() + .await? + .error_for_status()? + .json() + .await?) + }, + ) + .await + } + pub async fn person_image(&self, id: u64) -> anyhow::Result<Arc<TmdbPersonImage>> { + async_cache_memory(&["api-tmdb-search", &format!("{id}")], || async move { + Ok(self + .client + .get(&format!( + "https://api.themoviedb.org/3/person/{id}/images?api_key={}", + self.key, + )) + .send() + .await? + .error_for_status()? + .json() + .await?) + }) + .await + } + pub async fn image(&self, path: &str) -> anyhow::Result<AssetLocation> { + async_cache_file(&["api-tmdb-image", path], |mut file| async move { + info!("downloading image {path:?}"); + let mut res = reqwest::get(&format!("https://image.tmdb.org/t/p/original{path}")) + .await? + .error_for_status()?; + while let Some(chunk) = res.chunk().await? { + file.write_all(&chunk).await?; + } + Ok(()) + }) + .await + } +} + +pub fn parse_release_date(d: &str) -> anyhow::Result<i64> { + let (year, month, day) = (&d[0..4], &d[5..7], &d[8..10]); + let (year, month, day) = ( + year.parse().context("parsing year")?, + month.parse().context("parsing month")?, + day.parse().context("parsing day")?, + ); + + let mut p = Parsed::new(); + p.year = Some(year); + p.month = Some(month); + p.day = Some(day); + p.hour_div_12 = Some(0); + p.hour_mod_12 = Some(0); + p.minute = Some(0); + p.second = Some(0); + Ok(p.to_datetime_with_timezone(&Utc)?.timestamp_millis()) +} -#[derive(Debug, Clone, Deserialize)] +#[derive(Debug, Clone, Deserialize, Encode, Decode)] +pub struct TmdbPersonImage { + pub id: u64, + pub profiles: Vec<TmdbPersonImageProfile>, +} +#[derive(Debug, Clone, Deserialize, Encode, Decode)] +pub struct TmdbPersonImageProfile { + pub aspect_ratio: f64, + pub height: u32, + pub width: u32, + pub file_path: String, +} + +#[derive(Debug, Clone, Deserialize, Encode, Decode)] pub struct TmdbQuery { pub page: usize, pub results: Vec<TmdbQueryResult>, @@ -77,59 +211,11 @@ pub enum TmdbKind { Tv, Movie, } -impl TmdbKind { - pub fn as_str(&self) -> &'static str { - match self { +impl Display for TmdbKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(match self { TmdbKind::Tv => "tv", TmdbKind::Movie => "movie", - } + }) } } - -pub async fn tmdb_search(kind: TmdbKind, query: &str, key: &str) -> anyhow::Result<TmdbQuery> { - info!("searching tmdb: {query:?}"); - Ok(reqwest::get(&format!( - "https://api.themoviedb.org/3/search/{}?query={}&api_key={key}", - kind.as_str(), - query.replace(" ", "+") - )) - .await? - .json::<TmdbQuery>() - .await?) -} - -pub async fn tmdb_details(kind: TmdbKind, id: u64, key: &str) -> anyhow::Result<TmdbDetails> { - info!("fetching details: {id:?}"); - Ok(reqwest::get(&format!( - "https://api.themoviedb.org/3/{}/{id}?api_key={key}", - kind.as_str() - )) - .await? - .json() - .await?) -} - -pub async fn tmdb_image(path: &str) -> anyhow::Result<Vec<u8>> { - info!("downloading image {path:?}"); - let res = reqwest::get(&format!("https://image.tmdb.org/t/p/original{path}")).await?; - Ok(res.bytes().await?.to_vec()) -} - -pub fn parse_release_date(d: &str) -> anyhow::Result<i64> { - let (year, month, day) = (&d[0..4], &d[5..7], &d[8..10]); - let (year, month, day) = ( - year.parse().context("parsing year")?, - month.parse().context("parsing month")?, - day.parse().context("parsing day")?, - ); - - let mut p = Parsed::new(); - p.year = Some(year); - p.month = Some(month); - p.day = Some(day); - p.hour_div_12 = Some(0); - p.hour_mod_12 = Some(0); - p.minute = Some(0); - p.second = Some(0); - Ok(p.to_datetime_with_timezone(&Utc)?.timestamp_millis()) -} |