From 1c70f3d967b79cc4d9a8ee645921c53e95b096b1 Mon Sep 17 00:00:00 2001 From: metamuffin Date: Wed, 5 Feb 2025 16:23:09 +0100 Subject: generic node flags and show meta import --- import/src/lib.rs | 249 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 160 insertions(+), 89 deletions(-) (limited to 'import/src/lib.rs') diff --git a/import/src/lib.rs b/import/src/lib.rs index 125b20b..eee7a42 100644 --- a/import/src/lib.rs +++ b/import/src/lib.rs @@ -3,7 +3,7 @@ which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2025 metamuffin */ -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, bail, Context, Result}; use infojson::YVideo; use jellybase::{ assetfed::AssetInner, @@ -15,7 +15,7 @@ use jellybase::{ CONF, SECRETS, }; use jellyclient::{Appearance, PeopleGroup, TmdbKind, TraktKind, Visibility}; -use log::{info, warn}; +use log::info; use matroska::matroska_metadata; use rayon::iter::{ParallelBridge, ParallelIterator}; use std::{ @@ -114,12 +114,13 @@ fn import_traverse( }; let id = NodeID::from_slug(&slug); + // Some flags need to applied immediatly because they are inherited if let Ok(content) = read_to_string(path.join("flags")) { for flag in content.lines() { match flag.trim() { "hidden" => visibility = visibility.min(Visibility::Hidden), "reduced" => visibility = visibility.min(Visibility::Reduced), - _ => warn!("unknown flag {flag:?}"), + _ => (), } } } @@ -213,6 +214,12 @@ fn import_file( Ok(()) })?; } + "flags" => { + let content = read_to_string(path)?; + for flag in content.lines() { + apply_node_flag(db, rthandle, apis, parent, flag.trim())?; + } + } "children" => { info!("import children at {path:?}"); for line in read_to_string(path)?.lines() { @@ -295,67 +302,8 @@ fn import_media_file( .to_string_lossy() .to_string(); - let mut backdrop = None; - let mut poster = None; - let mut trakt_data = None; - let mut tmdb_data = None; - let mut filename_toks = filename.split("."); let filepath_stem = filename_toks.next().unwrap(); - for tok in filename_toks { - if let Some(trakt_id) = tok.strip_prefix("trakt-") { - let trakt_id: u64 = trakt_id.parse().context("parse trakt id")?; - if let (Some(trakt), Some(tmdb)) = (&apis.trakt, &apis.tmdb) { - let data = rthandle - .block_on(trakt.lookup(TraktKind::Movie, trakt_id, true)) - .context("trakt lookup")?; - let people = rthandle - .block_on(trakt.people(TraktKind::Movie, trakt_id, true)) - .context("trakt people lookup")?; - - let mut people_map = BTreeMap::>::new(); - for p in people.cast.iter() { - people_map.entry(PeopleGroup::Cast).or_default().push(p.a()) - } - for (group, people) in people.crew.iter() { - for p in people { - people_map.entry(group.a()).or_default().push(p.a()) - } - } - - if let Some(tmdb_id) = data.ids.tmdb { - let data = rthandle - .block_on(tmdb.details(TmdbKind::Movie, tmdb_id)) - .context("tmdb details")?; - tmdb_data = Some(data.clone()); - - if let Some(path) = &data.backdrop_path { - let im = rthandle - .block_on(tmdb.image(path)) - .context("tmdb backdrop image")?; - backdrop = Some(AssetInner::Cache(im).ser()); - } - if let Some(path) = &data.poster_path { - let im = rthandle - .block_on(tmdb.image(path)) - .context("tmdb poster image")?; - poster = Some(AssetInner::Cache(im).ser()); - } - - for p in people_map.values_mut().flatten() { - if let Some(id) = p.person.ids.tmdb { - let k = rthandle.block_on(tmdb.person_image(id))?; - if let Some(prof) = k.profiles.first() { - let im = rthandle.block_on(tmdb.image(&prof.file_path))?; - p.person.headshot = Some(AssetInner::Cache(im).ser()); - } - } - } - } - trakt_data = Some((data.clone(), people_map)); - } - } - } let slug = m .infojson @@ -363,12 +311,13 @@ fn import_media_file( .map(|ij| format!("youtube-{}", ij.id)) .unwrap_or(make_kebab(&filepath_stem)); - db.update_node_init(NodeID::from_slug(&slug), |node| { + let node = NodeID::from_slug(&slug); + + db.update_node_init(node, |node| { node.slug = slug; node.title = info.title; node.visibility = visibility; - node.poster = m.cover.clone().or(poster); - node.backdrop = backdrop; + node.poster = m.cover.clone(); node.description = tags.remove("DESCRIPTION").or(tags.remove("SYNOPSIS")); node.tagline = tags.remove("COMMENT"); node.parents.insert(parent); @@ -381,30 +330,6 @@ fn import_media_file( } } - if let Some(data) = tmdb_data { - node.title = data.title.clone(); - node.tagline = data.tagline.clone(); - node.description = Some(data.overview.clone()); - node.ratings.insert(Rating::Tmdb, data.vote_average); - if let Some(date) = data.release_date.clone() { - node.release_date = tmdb::parse_release_date(&date)?; - } - } - if let Some((data, people)) = trakt_data { - node.title = Some(data.title.clone()); - node.kind = NodeKind::Movie; // TODO - if let Some(overview) = &data.overview { - node.description = Some(overview.clone()) - } - if let Some(tagline) = &data.tagline { - node.tagline = Some(tagline.clone()) - } - if let Some(rating) = &data.rating { - node.ratings.insert(Rating::Trakt, *rating); - } - node.people.extend(people); - } - let tracks = tracks .entries .into_iter() @@ -515,6 +440,152 @@ fn import_media_file( Ok(()) })?; + for tok in filename_toks { + apply_node_flag(db, rthandle, apis, node, tok)?; + } + + Ok(()) +} + +fn apply_node_flag( + db: &Database, + rthandle: &Handle, + apis: &Apis, + node: NodeID, + flag: &str, +) -> Result<()> { + if let Some(value) = flag.strip_prefix("trakt-").or(flag.strip_prefix("trakt=")) { + let (kind, id) = value.split_once(":").unwrap_or(("", value)); + let kind = match kind { + "movie" | "" => TraktKind::Movie, + "show" => TraktKind::Show, + "season" => TraktKind::Season, + _ => bail!("unknown trakt kind"), + }; + apply_trakt_tmdb(db, rthandle, apis, node, kind, id)?; + } + if flag == "hidden" { + db.update_node_init(node, |node| { + node.visibility = node.visibility.min(Visibility::Hidden); + Ok(()) + })?; + } + if flag == "reduced" { + db.update_node_init(node, |node| { + node.visibility = node.visibility.min(Visibility::Reduced); + Ok(()) + })?; + } + Ok(()) +} + +fn apply_trakt_tmdb( + db: &Database, + rthandle: &Handle, + apis: &Apis, + node: NodeID, + trakt_kind: TraktKind, + trakt_id: &str, +) -> Result<()> { + let trakt_id: u64 = trakt_id.parse().context("parse trakt id")?; + if let (Some(trakt), Some(tmdb)) = (&apis.trakt, &apis.tmdb) { + let data = rthandle + .block_on(trakt.lookup(trakt_kind, trakt_id, true)) + .context("trakt lookup")?; + let people = rthandle + .block_on(trakt.people(trakt_kind, trakt_id, true)) + .context("trakt people lookup")?; + + let mut people_map = BTreeMap::>::new(); + for p in people.cast.iter() { + people_map.entry(PeopleGroup::Cast).or_default().push(p.a()) + } + for (group, people) in people.crew.iter() { + for p in people { + people_map.entry(group.a()).or_default().push(p.a()) + } + } + + let mut tmdb_data = None; + let mut backdrop = None; + let mut poster = None; + if let Some(tmdb_id) = data.ids.tmdb { + let data = rthandle + .block_on(tmdb.details( + match trakt_kind { + TraktKind::Movie => TmdbKind::Movie, + TraktKind::Show => TmdbKind::Tv, + _ => TmdbKind::Movie, + }, + tmdb_id, + )) + .context("tmdb details")?; + tmdb_data = Some(data.clone()); + + if let Some(path) = &data.backdrop_path { + let im = rthandle + .block_on(tmdb.image(path)) + .context("tmdb backdrop image")?; + backdrop = Some(AssetInner::Cache(im).ser()); + } + if let Some(path) = &data.poster_path { + let im = rthandle + .block_on(tmdb.image(path)) + .context("tmdb poster image")?; + poster = Some(AssetInner::Cache(im).ser()); + } + + for p in people_map.values_mut().flatten() { + if let Some(id) = p.person.ids.tmdb { + let k = rthandle.block_on(tmdb.person_image(id))?; + if let Some(prof) = k.profiles.first() { + let im = rthandle.block_on(tmdb.image(&prof.file_path))?; + p.person.headshot = Some(AssetInner::Cache(im).ser()); + } + } + } + } + + db.update_node_init(node, |node| { + node.title = Some(data.title.clone()); + node.people.extend(people_map); + node.kind = match trakt_kind { + TraktKind::Movie => NodeKind::Movie, + TraktKind::Show => NodeKind::Show, + TraktKind::Season => NodeKind::Season, + TraktKind::Episode => NodeKind::Episode, + TraktKind::Person => NodeKind::Channel, + TraktKind::User => NodeKind::Channel, + }; + if let Some(overview) = &data.overview { + node.description = Some(overview.clone()) + } + if let Some(tagline) = &data.tagline { + node.tagline = Some(tagline.clone()) + } + if let Some(rating) = &data.rating { + node.ratings.insert(Rating::Trakt, *rating); + } + if let Some(poster) = poster { + node.poster = Some(poster); + } + if let Some(backdrop) = backdrop { + node.backdrop = Some(backdrop); + } + if let Some(data) = tmdb_data { + node.title = data.title.clone().or(node.title.clone()); + node.tagline = data.tagline.clone().or(node.tagline.clone()); + node.description = Some(data.overview.clone()); + node.ratings.insert(Rating::Tmdb, data.vote_average); + if let Some(date) = data.release_date.clone() { + if let Ok(date) = tmdb::parse_release_date(&date) { + node.release_date = date; + } + } + } + Ok(()) + })?; + } Ok(()) } -- cgit v1.2.3-70-g09d2