diff options
Diffstat (limited to 'import/src/plugins/tmdb.rs')
| -rw-r--r-- | import/src/plugins/tmdb.rs | 170 |
1 files changed, 111 insertions, 59 deletions
diff --git a/import/src/plugins/tmdb.rs b/import/src/plugins/tmdb.rs index 206781b..6b70d46 100644 --- a/import/src/plugins/tmdb.rs +++ b/import/src/plugins/tmdb.rs @@ -4,12 +4,14 @@ Copyright (C) 2026 metamuffin <metamuffin.org> */ use crate::{ - NodeID, USER_AGENT, + USER_AGENT, plugins::{ImportContext, ImportPlugin, PluginInfo}, }; use anyhow::{Context, Result, anyhow, bail}; +use chrono::{Utc, format::Parsed}; use jellycache::{EscapeKey, HashKey, cache_memory, cache_store}; -use jellycommon::jellyobject::Object; +use jellycommon::*; +use jellydb::table::RowNum; use log::info; use reqwest::{ Client, ClientBuilder, @@ -107,7 +109,7 @@ impl Tmdb { }) .context("tmdb person images") } - pub fn image(&self, path: &str, rt: &Handle) -> Result<Asset> { + pub fn image(&self, path: &str, rt: &Handle) -> Result<String> { cache_store( format!("ext/tmdb/image/{}.image", EscapeKey(path)), move || { @@ -126,14 +128,13 @@ impl Tmdb { }, ) .context("tmdb image download") - .map(Asset) } pub fn episode_details( &self, series_id: u64, - season: usize, - episode: usize, + season: u64, + episode: u64, rt: &Handle, ) -> Result<Arc<TmdbEpisode>> { cache_memory(&format!("ext/tmdb/episode-details/{series_id}-S{season}-E{episode}.json"), move || { @@ -161,37 +162,46 @@ impl ImportPlugin for Tmdb { ..Default::default() } } - fn process(&self, ct: &ImportContext, node: NodeID, data: Object) -> Result<()> { - self.process_primary(ct, node, data)?; - self.process_episode(ct, node, data)?; + fn process(&self, ct: &ImportContext, node: RowNum) -> Result<()> { + self.process_primary(ct, node)?; + self.process_episode(ct, node)?; Ok(()) } } impl Tmdb { - fn process_primary(&self, ct: &ImportContext, node: NodeID, data: Object) -> Result<()> { - let (tmdb_kind, tmdb_id): (_, u64) = - if let Some(id) = data.identifiers.get(&IdentifierType::TmdbSeries) { - (TmdbKind::Tv, id.parse()?) - } else if let Some(id) = data.identifiers.get(&IdentifierType::TmdbMovie) { - (TmdbKind::Movie, id.parse()?) - } else { - return Ok(()); - }; + fn process_primary(&self, ct: &ImportContext, node: RowNum) -> Result<()> { + let data = ct.dba.get_node(node)?.unwrap(); + let data = data.as_object(); + + let (tmdb_kind, tmdb_id): (_, u64) = if let Some(id) = data + .get(NO_IDENTIFIERS) + .unwrap_or_default() + .get(IDENT_TMDB_SERIES) + { + (TmdbKind::Tv, id.parse()?) + } else if let Some(id) = data + .get(NO_IDENTIFIERS) + .unwrap_or_default() + .get(IDENT_TMDB_MOVIE) + { + (TmdbKind::Movie, id.parse()?) + } else { + return Ok(()); + }; let details = self.details(tmdb_kind, tmdb_id, ct.rt)?; - let mut images = Vec::new(); - if let Some(path) = &details.backdrop_path { - images.push(( - PictureSlot::Backdrop, - self.image(path, ct.rt).context("backdrop image")?, - )); - } - if let Some(path) = &details.poster_path { - images.push(( - PictureSlot::Cover, - self.image(path, ct.rt).context("poster image")?, - )); - } + let backdrop = details + .backdrop_path + .as_ref() + .map(|path| self.image(&path, ct.rt)) + .transpose() + .context("backdrop image")?; + let poster = details + .poster_path + .as_ref() + .map(|path| self.image(&path, ct.rt)) + .transpose() + .context("poster image")?; let release_date = details .release_date @@ -200,46 +210,88 @@ impl Tmdb { .transpose()? .flatten(); - ct.dba.update_node_by_nodeid(node, |node| { - node.title = details.title.clone().or(node.title.clone()); - node.tagline = details.tagline.clone().or(node.tagline.clone()); - node.description = Some(details.overview.clone()); - node.ratings.insert(RatingType::Tmdb, details.vote_average); - node.pictures.extend(images); - node.release_date = release_date.or(node.release_date); + ct.dba.update_node(node, |mut node| { + if let Some(title) = &details.title { + node = node.as_object().insert(NO_TITLE, &title); + } + if let Some(tagline) = &details.tagline { + node = node.as_object().insert(NO_TAGLINE, &tagline); + } + node = node.as_object().insert(NO_DESCRIPTION, &details.overview); + node = node.as_object().update(NO_RATINGS, |rat| { + rat.insert(RTYP_TMDB, details.vote_average) + }); + if let Some(poster) = &poster { + node = node + .as_object() + .update(NO_PICTURES, |rat| rat.insert(PICT_COVER, &poster)); + } + if let Some(backdrop) = &backdrop { + node = node + .as_object() + .update(NO_PICTURES, |rat| rat.insert(PICT_BACKDROP, &backdrop)); + } + if let Some(releasedate) = release_date { + node = node.as_object().insert(NO_RELEASEDATE, releasedate); + } + node })?; Ok(()) } - fn process_episode(&self, ct: &ImportContext, node: NodeID, data: &Node) -> Result<()> { - let (Some(episode), Some(season)) = (data.index, data.season_index) else { + fn process_episode(&self, ct: &ImportContext, node: RowNum) -> Result<()> { + let data = ct.dba.get_node(node)?.unwrap(); + let data = data.as_object(); + + let (Some(episode), Some(season)) = (data.get(NO_INDEX), data.get(NO_SEASON_INDEX)) else { return Ok(()); }; let mut series_id = None; - for &parent in &data.parents { - let parent_data = ct.db.get_node(parent)?.ok_or(anyhow!("parent missing"))?; - if let Some(id) = parent_data.identifiers.get(&IdentifierType::TmdbSeries) { - series_id = Some(id.parse::<u64>()?); - break; + ct.dba.db.read_transaction(&mut |txn| { + for parent in data.iter(NO_PARENT) { + let parent_data = ct + .dba + .nodes + .get(txn, parent)? + .ok_or(anyhow!("parent missing"))?; + if let Some(id) = parent_data + .as_object() + .get(NO_IDENTIFIERS) + .unwrap_or_default() + .get(IDENT_TMDB_SERIES) + { + series_id = Some(id.parse::<u64>()?); + break; + } } - } + Ok(()) + })?; let Some(series_id) = series_id else { return Ok(()); }; let details = self.episode_details(series_id, season, episode, ct.rt)?; - let mut images = Vec::new(); - if let Some(path) = &details.still_path { - images.push((PictureSlot::Cover, self.image(path, ct.rt)?)) - } - + let cover = details + .still_path + .as_ref() + .map(|path| self.image(&path, ct.rt)) + .transpose() + .context("still image download")?; let release_date = parse_release_date(&details.air_date)?; - ct.db.update_node_init(node, |node| { - node.title = Some(details.name.clone()); - node.description = Some(details.overview.clone()); - node.release_date = release_date.or(node.release_date); - node.ratings.insert(RatingType::Tmdb, details.vote_average); - node.pictures.extend(images); - })?; - Ok(()) + ct.dba.update_node(node, |mut node| { + node = node.as_object().insert(NO_TITLE, &details.name); + node = node.as_object().insert(NO_DESCRIPTION, &details.overview); + if let Some(release_date) = release_date { + node = node.as_object().insert(NO_RELEASEDATE, release_date) + } + node = node.as_object().update(NO_RATINGS, |rat| { + rat.insert(RTYP_TMDB, details.vote_average) + }); + if let Some(cover) = &cover { + node = node + .as_object() + .update(NO_PICTURES, |picts| picts.insert(PICT_COVER, &cover)); + } + node + }) } } |