diff options
| author | metamuffin <metamuffin@disroot.org> | 2025-11-29 13:32:52 +0100 |
|---|---|---|
| committer | metamuffin <metamuffin@disroot.org> | 2025-11-29 13:32:52 +0100 |
| commit | 5db15c323d76dca9ae71b0204d63dcb09fbbcbc5 (patch) | |
| tree | 4f69e58c9b6825b7b602712893950673abf9c286 /import/src | |
| parent | bac47e456085ea153ae6ae1b1e28e41868693c9c (diff) | |
| download | jellything-5db15c323d76dca9ae71b0204d63dcb09fbbcbc5.tar jellything-5db15c323d76dca9ae71b0204d63dcb09fbbcbc5.tar.bz2 jellything-5db15c323d76dca9ae71b0204d63dcb09fbbcbc5.tar.zst | |
remove asset token; db json
Diffstat (limited to 'import/src')
| -rw-r--r-- | import/src/acoustid.rs | 7 | ||||
| -rw-r--r-- | import/src/infojson.rs | 15 | ||||
| -rw-r--r-- | import/src/lib.rs | 149 | ||||
| -rw-r--r-- | import/src/tmdb.rs | 22 | ||||
| -rw-r--r-- | import/src/trakt.rs | 124 |
5 files changed, 195 insertions, 122 deletions
diff --git a/import/src/acoustid.rs b/import/src/acoustid.rs index a328146..c35708d 100644 --- a/import/src/acoustid.rs +++ b/import/src/acoustid.rs @@ -5,7 +5,6 @@ */ use crate::USER_AGENT; use anyhow::{Context, Result}; -use bincode::{Decode, Encode}; use jellycache::async_cache_memory; use log::info; use reqwest::{ @@ -39,18 +38,18 @@ pub(crate) struct FpCalcOutput { fingerprint: String, } -#[derive(Serialize, Deserialize, Encode, Decode)] +#[derive(Serialize, Deserialize)] pub(crate) struct AcoustIDLookupResultRecording { id: String, } -#[derive(Serialize, Deserialize, Encode, Decode)] +#[derive(Serialize, Deserialize)] pub(crate) struct AcoustIDLookupResult { id: String, score: f32, #[serde(default)] recordings: Vec<AcoustIDLookupResultRecording>, } -#[derive(Serialize, Deserialize, Encode, Decode)] +#[derive(Serialize, Deserialize)] pub(crate) struct AcoustIDLookupResponse { status: String, results: Vec<AcoustIDLookupResult>, diff --git a/import/src/infojson.rs b/import/src/infojson.rs index e0ebc43..ada6c3a 100644 --- a/import/src/infojson.rs +++ b/import/src/infojson.rs @@ -4,12 +4,11 @@ Copyright (C) 2025 metamuffin <metamuffin.org> */ use anyhow::Context; -use bincode::{Decode, Encode}; use jellycommon::chrono::{format::Parsed, Utc}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; -#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct YVideo { pub id: String, pub title: String, @@ -64,7 +63,7 @@ pub struct YVideo { pub epoch: usize, } -#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct YCaption { pub url: Option<String>, pub ext: String, //"vtt" | "json3" | "srv1" | "srv2" | "srv3" | "ttml", @@ -72,7 +71,7 @@ pub struct YCaption { pub name: Option<String>, } -#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct YFormat { pub format_id: String, pub format_note: Option<String>, @@ -97,13 +96,13 @@ pub struct YFormat { pub format: String, } -#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct YFragment { pub url: Option<String>, pub duration: Option<f64>, } -#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct YThumbnail { pub url: String, pub preference: Option<i32>, @@ -113,14 +112,14 @@ pub struct YThumbnail { pub resolution: Option<String>, } -#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct YChapter { pub start_time: f64, pub end_time: f64, pub title: String, } -#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct YHeatmapSample { pub start_time: f64, pub end_time: f64, diff --git a/import/src/lib.rs b/import/src/lib.rs index 1a1d5ad..d12913f 100644 --- a/import/src/lib.rs +++ b/import/src/lib.rs @@ -15,16 +15,16 @@ pub mod wikidata; pub mod wikimedia_commons; use jellydb::Database; -pub use jellyimport_asset_token as asset_token; -use jellyimport_asset_token::AssetInner; +use crate::{tmdb::TmdbKind, trakt::TraktKind}; use acoustid::{acoustid_fingerprint, AcoustID}; use anyhow::{anyhow, bail, Context, Result}; use infojson::YVideo; use jellycache::{cache_file, cache_memory}; use jellycommon::{ - Appearance, Chapter, LocalTrack, MediaInfo, Node, NodeID, NodeKind, ObjectIds, PeopleGroup, - Person, RatingType, SourceTrack, SourceTrackKind, TmdbKind, TrackSource, TraktKind, Visibility, + Appearance, Asset, Chapter, CreditCategory, IdentifierType, LocalTrack, MediaInfo, Node, + NodeID, NodeKind, PictureSlot, RatingType, SourceTrack, SourceTrackKind, TrackSource, + Visibility, }; use jellyimport_fallback_generator::generate_fallback; use jellyremuxer::{ @@ -39,7 +39,7 @@ use serde::{Deserialize, Serialize}; use std::{ collections::{BTreeMap, HashMap}, fs::{read_to_string, File}, - io::{BufReader, Write}, + io::{self, BufReader, Write}, path::{Path, PathBuf}, sync::{Arc, LazyLock, Mutex}, time::UNIX_EPOCH, @@ -262,15 +262,23 @@ fn import_file( match filename.as_ref() { "poster.jpeg" | "poster.webp" | "poster.png" => { info!("import poster at {path:?}"); + let path = cache_file("picture-file", path, |mut f| { + io::copy(&mut File::open(path)?, &mut f)?; + Ok(()) + })?; db.update_node_init(parent, |node| { - node.poster = Some(AssetInner::Media(path.to_owned()).ser()); + node.pictures.insert(PictureSlot::Poster, Asset(path.0)); Ok(()) })?; } "backdrop.jpeg" | "backdrop.webp" | "backdrop.png" => { info!("import backdrop at {path:?}"); + let path = cache_file("picture-file", path, |mut f| { + io::copy(&mut File::open(path)?, &mut f)?; + Ok(()) + })?; db.update_node_init(parent, |node| { - node.backdrop = Some(AssetInner::Media(path.to_owned()).ser()); + node.pictures.insert(PictureSlot::Backdrop, Asset(path.0)); Ok(()) })?; } @@ -291,7 +299,6 @@ fn import_file( merge_option(&mut node.description, data.description); merge_option(&mut node.index, data.index); merge_option(&mut node.release_date, data.release_date); - node.identifiers.extend(data.identifiers); Ok(()) })?; @@ -323,11 +330,11 @@ fn import_file( node.kind = NodeKind::Channel; node.title = Some(clean_uploader_name(&data.title).to_owned()); if let Some(cid) = data.channel_id { - node.identifiers.insert("youtube.channel".to_string(), cid); + node.identifiers.insert(IdentifierType::YoutubeChannel, cid); } if let Some(uid) = data.uploader_id { node.identifiers - .insert("youtube.channelname".to_string(), uid); + .insert(IdentifierType::YoutubeChannelHandle, uid); } if let Some(desc) = data.description { node.description = Some(desc); @@ -455,27 +462,27 @@ fn import_media_file( let node = NodeID::from_slug(&slug); let meta = path.metadata()?; - let mut eids = BTreeMap::new(); + let mut eids = BTreeMap::<IdentifierType, String>::new(); for (key, value) in &tags { match key.as_str() { "MUSICBRAINZ_TRACKID" => { - eids.insert("musicbrainz.recording".to_string(), value.to_owned()) + eids.insert(IdentifierType::MusicbrainzRecording, value.to_owned()) } "MUSICBRAINZ_ARTISTID" => { - eids.insert("musicbrainz.artist".to_string(), value.to_owned()) + eids.insert(IdentifierType::MusicbrainzArtist, value.to_owned()) } "MUSICBRAINZ_ALBUMID" => { - eids.insert("musicbrainz.release".to_string(), value.to_owned()) + eids.insert(IdentifierType::MusicbrainzRelease, value.to_owned()) } "MUSICBRAINZ_ALBUMARTISTID" => { - eids.insert("musicbrainz.albumartist".to_string(), value.to_owned()) + None //? ignore this? } "MUSICBRAINZ_RELEASEGROUPID" => { - eids.insert("musicbrainz.releasegroup".to_string(), value.to_owned()) + eids.insert(IdentifierType::MusicbrainzReleaseGroup, value.to_owned()) } - "ISRC" => eids.insert("isrc".to_string(), value.to_owned()), - "BARCODE" => eids.insert("barcode".to_string(), value.to_owned()), + "ISRC" => eids.insert(IdentifierType::Isrc, value.to_owned()), + "BARCODE" => eids.insert(IdentifierType::Barcode, value.to_owned()), _ => None, }; } @@ -488,20 +495,18 @@ fn import_media_file( .ok_or(anyhow!("need acoustid"))? .get_atid_mbid(&fp), )? { - eids.insert("acoustid.track".to_string(), atid); - eids.insert("musicbrainz.recording".to_string(), mbid); + eids.insert(IdentifierType::AcoustIdTrack, atid); + eids.insert(IdentifierType::MusicbrainzRecording, mbid); }; } - let mbrec = eids.get("musicbrainz.recording").cloned(); + let mbrec = eids.get(&IdentifierType::MusicbrainzRecording).cloned(); db.update_node_init(node, |node| { node.slug = slug; node.title = m.info.title.clone().or(node.title.clone()); node.visibility = iflags.visibility; - node.poster = cover - .map(|a| AssetInner::Cache(a).ser()) - .or(node.poster.clone()); + node.description = tags .remove("DESCRIPTION") .or(tags.remove("SYNOPSIS")) @@ -511,6 +516,10 @@ fn import_media_file( node.identifiers.extend(eids); + if let Some(cover) = cover { + node.pictures.insert(PictureSlot::Cover, Asset(cover.0)); + } + if let Some(ct) = tags.get("CONTENT_TYPE") { node.kind = match ct.to_lowercase().trim() { "movie" | "documentary" | "film" => NodeKind::Movie, @@ -545,13 +554,7 @@ fn import_media_file( } else { SourceTrackKind::Subtitle }, - source: TrackSource::Local( - AssetInner::LocalTrack(LocalTrack { - path: path.to_owned(), - track: track.track_number as usize, - }) - .ser(), - ), + source: TrackSource::Local(path.to_owned(), track.track_number), }) .collect::<Vec<_>>(); @@ -593,7 +596,7 @@ fn import_media_file( match infojson.extractor.as_str() { "youtube" => { node.identifiers - .insert("youtube.video".to_string(), infojson.id); + .insert(IdentifierType::YoutubeVideo, infojson.id); node.ratings.insert( RatingType::YoutubeViews, infojson.view_count.unwrap_or_default() as f64, @@ -602,7 +605,10 @@ fn import_media_file( node.ratings.insert(RatingType::YoutubeLikes, lc as f64); } } - "Bandcamp" => drop(node.identifiers.insert("bandcamp".to_string(), infojson.id)), + "Bandcamp" => drop( + node.identifiers + .insert(IdentifierType::Bandcamp, infojson.id), + ), _ => (), } } @@ -669,8 +675,7 @@ fn import_media_file( let tmdb_details = rthandle.block_on(tmdb.episode_details(tmdb_id, season, episode))?; if let Some(still) = &tmdb_details.still_path { - poster = - Some(AssetInner::Cache(rthandle.block_on(tmdb.image(still))?).ser()) + poster = Some(Asset(rthandle.block_on(tmdb.image(still))?.0)) } } } @@ -679,7 +684,9 @@ fn import_media_file( node.kind = NodeKind::Episode; node.index = Some(episode.number); node.title = Some(episode.title.clone()); - node.poster = poster.or(node.poster.clone()); + if let Some(poster) = poster { + node.pictures.insert(PictureSlot::Poster, poster); + } node.description = episode.overview.clone().or(node.description.clone()); node.ratings.insert(RatingType::Trakt, episode.rating); Ok(()) @@ -766,11 +773,11 @@ fn apply_musicbrainz_recording( db.update_node_init(node, |node| { node.title = Some(rec.title.clone()); node.identifiers - .insert("musicbrainz.recording".to_string(), rec.id.to_string()); + .insert(IdentifierType::MusicbrainzRecording, rec.id.to_string()); if let Some(a) = rec.artist_credit.first() { node.subtitle = Some(a.artist.name.clone()); node.identifiers - .insert("musicbrainz.artist".to_string(), a.artist.id.to_string()); + .insert(IdentifierType::MusicbrainzArtist, a.artist.id.to_string()); } // // TODO proper dedup @@ -779,12 +786,14 @@ fn apply_musicbrainz_recording( for rel in &rec.relations { use musicbrainz::reltypes::*; let a = match rel.type_id.as_str() { - INSTRUMENT => Some(("", PeopleGroup::Instrument)), - VOCAL => Some(("", PeopleGroup::Vocal)), - PRODUCER => Some(("", PeopleGroup::Producer)), - MIX => Some(("mix ", PeopleGroup::Engineer)), - PHONOGRAPHIC_COPYRIGHT => Some(("phonographic copyright ", PeopleGroup::Engineer)), - PROGRAMMING => Some(("programming ", PeopleGroup::Engineer)), + INSTRUMENT => Some(("", CreditCategory::Instrument)), + VOCAL => Some(("", CreditCategory::Vocal)), + PRODUCER => Some(("", CreditCategory::Producer)), + MIX => Some(("mix ", CreditCategory::Engineer)), + PHONOGRAPHIC_COPYRIGHT => { + Some(("phonographic copyright ", CreditCategory::Engineer)) + } + PROGRAMMING => Some(("programming ", CreditCategory::Engineer)), _ => None, }; @@ -808,7 +817,7 @@ fn apply_musicbrainz_recording( let path = rthandle.block_on( apis.wikimedia_commons.image_by_filename(filename), )?; - image_1 = Some(AssetInner::Cache(path).ser()); + image_1 = Some(Asset(path.0)); } } } @@ -819,7 +828,7 @@ fn apply_musicbrainz_recording( if let Some(path) = rthandle.block_on(apis.vgmdb.get_artist_image(id))? { - image_2 = Some(AssetInner::Cache(path).ser()); + image_2 = Some(Asset(path.0)); } } } @@ -834,27 +843,26 @@ fn apply_musicbrainz_recording( let headshot = match image_1.or(image_2) { Some(x) => x, - None => AssetInner::Cache(cache_file( - "person-headshot-fallback", - &artist.sort_name, - |mut file| { + None => Asset( + cache_file("person-headshot-fallback", &artist.sort_name, |mut file| { generate_fallback(&artist.sort_name, &mut file)?; Ok(()) - }, - )?) - .ser(), + })? + .0, + ), }; node.credits.entry(group).or_default().push(Appearance { jobs, characters: vec![], + node: NodeID([0; 32]), // TODO }); } } for isrc in &rec.isrcs { node.identifiers - .insert("isrc".to_string(), isrc.to_string()); + .insert(IdentifierType::Isrc, isrc.to_string()); } Ok(()) })?; @@ -878,9 +886,12 @@ fn apply_trakt_tmdb( .block_on(trakt.people(trakt_kind, trakt_id)) .context("trakt people lookup")?; - let mut people_map = BTreeMap::<PeopleGroup, Vec<Appearance>>::new(); + let mut people_map = BTreeMap::<CreditCategory, Vec<Appearance>>::new(); for p in people.cast.iter() { - people_map.entry(PeopleGroup::Cast).or_default().push(p.a()) + people_map + .entry(CreditCategory::Cast) + .or_default() + .push(p.a()) } for (group, people) in people.crew.iter() { for p in people { @@ -908,24 +919,24 @@ fn apply_trakt_tmdb( let im = rthandle .block_on(tmdb.image(path)) .context("tmdb backdrop image")?; - backdrop = Some(AssetInner::Cache(im).ser()); + backdrop = Some(Asset(im.0)); } 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()); + poster = Some(Asset(im.0)); } - 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()); - } - } - } + // 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| { @@ -949,10 +960,10 @@ fn apply_trakt_tmdb( node.ratings.insert(RatingType::Trakt, *rating); } if let Some(poster) = poster { - node.poster = Some(poster); + node.pictures.insert(PictureSlot::Poster, poster); } if let Some(backdrop) = backdrop { - node.backdrop = Some(backdrop); + node.pictures.insert(PictureSlot::Backdrop, backdrop); } if let Some(data) = tmdb_data { node.title = data.title.clone().or(node.title.clone()); diff --git a/import/src/tmdb.rs b/import/src/tmdb.rs index ad99fde..414058f 100644 --- a/import/src/tmdb.rs +++ b/import/src/tmdb.rs @@ -6,17 +6,14 @@ use crate::USER_AGENT; use anyhow::{anyhow, bail, Context}; use jellycache::{async_cache_file, async_cache_memory, CachePath}; -use jellycommon::{ - chrono::{format::Parsed, Utc}, - TmdbKind, -}; +use jellycommon::chrono::{format::Parsed, Utc}; use log::info; use reqwest::{ header::{HeaderMap, HeaderName, HeaderValue}, Client, ClientBuilder, }; use serde::{Deserialize, Serialize}; -use std::sync::Arc; +use std::{fmt::Display, sync::Arc}; use tokio::io::AsyncWriteExt; pub struct Tmdb { @@ -164,6 +161,15 @@ pub fn parse_release_date(d: &str) -> anyhow::Result<Option<i64>> { Ok(Some(p.to_datetime_with_timezone(&Utc)?.timestamp_millis())) } +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", + }) + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TmdbEpisode { pub air_date: String, @@ -176,6 +182,12 @@ pub struct TmdbEpisode { pub vote_count: usize, } +#[derive(Debug, Clone, Copy, Hash, Serialize, Deserialize)] +pub enum TmdbKind { + Tv, + Movie, +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TmdbPersonImage { pub id: u64, diff --git a/import/src/trakt.rs b/import/src/trakt.rs index f25fa9e..3f0ad47 100644 --- a/import/src/trakt.rs +++ b/import/src/trakt.rs @@ -5,9 +5,8 @@ */ use crate::USER_AGENT; use anyhow::Context; -use bincode::{Decode, Encode}; use jellycache::async_cache_memory; -use jellycommon::{Appearance, ObjectIds, PeopleGroup, Person, TraktKind}; +use jellycommon::{Appearance, CreditCategory, NodeID}; use log::info; use reqwest::{ header::{HeaderMap, HeaderName, HeaderValue}, @@ -120,10 +119,10 @@ impl Trakt { } } -#[derive(Debug, Clone, Deserialize, Serialize, Default, Encode, Decode)] +#[derive(Debug, Clone, Deserialize, Serialize, Default)] pub struct TraktSeason { pub number: usize, - pub ids: ObjectIds, + pub ids: TraktIds, pub rating: f64, pub votes: usize, pub episode_count: usize, @@ -133,12 +132,12 @@ pub struct TraktSeason { pub network: String, } -#[derive(Debug, Clone, Deserialize, Serialize, Default, Encode, Decode)] +#[derive(Debug, Clone, Deserialize, Serialize, Default)] pub struct TraktEpisode { pub season: Option<usize>, pub number: usize, pub number_abs: Option<usize>, - pub ids: ObjectIds, + pub ids: TraktIds, pub rating: f64, pub votes: usize, pub title: String, @@ -149,7 +148,7 @@ pub struct TraktEpisode { pub episode_type: String, } -#[derive(Debug, Clone, Deserialize, Serialize, Default, Encode, Decode)] +#[derive(Debug, Clone, Deserialize, Serialize, Default)] pub struct TraktPeople { #[serde(default)] pub cast: Vec<TraktAppearance>, @@ -157,7 +156,7 @@ pub struct TraktPeople { pub crew: BTreeMap<TraktPeopleGroup, Vec<TraktAppearance>>, } -#[derive(Debug, Clone, Deserialize, Serialize, Default, Encode, Decode)] +#[derive(Debug, Clone, Deserialize, Serialize, Default)] pub struct TraktAppearance { #[serde(default)] pub jobs: Vec<String>, @@ -166,13 +165,13 @@ pub struct TraktAppearance { pub person: TraktPerson, } -#[derive(Debug, Clone, Deserialize, Serialize, Default, Encode, Decode)] +#[derive(Debug, Clone, Deserialize, Serialize, Default)] pub struct TraktPerson { pub name: String, - pub ids: ObjectIds, + pub ids: TraktIds, } -#[derive(Debug, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Serialize, Deserialize)] pub struct TraktSearchResult { pub r#type: TraktKind, pub score: f64, @@ -180,7 +179,7 @@ pub struct TraktSearchResult { pub inner: TraktKindObject, } -#[derive(Debug, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum TraktKindObject { Movie(TraktMediaObject), @@ -204,9 +203,7 @@ impl TraktKindObject { } } -#[derive( - Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Encode, Decode, Clone, Copy, -)] +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] pub enum TraktPeopleGroup { #[serde(rename = "production")] Production, @@ -234,20 +231,20 @@ pub enum TraktPeopleGroup { CreatedBy, } impl TraktPeopleGroup { - pub fn a(self) -> PeopleGroup { + pub fn a(self) -> CreditCategory { match self { - TraktPeopleGroup::Production => PeopleGroup::Production, - TraktPeopleGroup::Art => PeopleGroup::Art, - TraktPeopleGroup::Crew => PeopleGroup::Crew, - TraktPeopleGroup::CostumeMakeup => PeopleGroup::CostumeMakeup, - TraktPeopleGroup::Directing => PeopleGroup::Directing, - TraktPeopleGroup::Writing => PeopleGroup::Writing, - TraktPeopleGroup::Sound => PeopleGroup::Sound, - TraktPeopleGroup::Camera => PeopleGroup::Camera, - TraktPeopleGroup::VisualEffects => PeopleGroup::Vfx, - TraktPeopleGroup::Lighting => PeopleGroup::Lighting, - TraktPeopleGroup::Editing => PeopleGroup::Editing, - TraktPeopleGroup::CreatedBy => PeopleGroup::CreatedBy, + TraktPeopleGroup::Production => CreditCategory::Production, + TraktPeopleGroup::Art => CreditCategory::Art, + TraktPeopleGroup::Crew => CreditCategory::Crew, + TraktPeopleGroup::CostumeMakeup => CreditCategory::CostumeMakeup, + TraktPeopleGroup::Directing => CreditCategory::Directing, + TraktPeopleGroup::Writing => CreditCategory::Writing, + TraktPeopleGroup::Sound => CreditCategory::Sound, + TraktPeopleGroup::Camera => CreditCategory::Camera, + TraktPeopleGroup::VisualEffects => CreditCategory::Vfx, + TraktPeopleGroup::Lighting => CreditCategory::Lighting, + TraktPeopleGroup::Editing => CreditCategory::Editing, + TraktPeopleGroup::CreatedBy => CreditCategory::CreatedBy, } } } @@ -256,20 +253,20 @@ impl TraktAppearance { Appearance { jobs: self.jobs.to_owned(), characters: self.characters.to_owned(), - person: Person { - name: self.person.name.to_owned(), - headshot: None, - ids: self.person.ids.to_owned(), - }, + node: NodeID([0; 32]), // person: Person { + // name: self.person.name.to_owned(), + // headshot: None, + // ids: self.person.ids.to_owned(), + // }, } } } -#[derive(Debug, Serialize, Deserialize, Encode, Decode, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct TraktMediaObject { pub title: String, pub year: Option<u32>, - pub ids: ObjectIds, + pub ids: TraktIds, pub tagline: Option<String>, pub overview: Option<String>, @@ -287,10 +284,19 @@ pub struct TraktMediaObject { pub genres: Option<Vec<String>>, } +#[derive(Debug, Serialize, Deserialize, Clone, Default)] +pub struct TraktIds { + pub trakt: Option<u64>, + pub slug: Option<String>, + pub tvdb: Option<u64>, + pub imdb: Option<String>, + pub tmdb: Option<u64>, +} + impl Display for TraktSearchResult { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_fmt(format_args!( - "{} ({}) \x1b[2m{} [{}]\x1b[0m", + "{} ({}) \x1b[2m{} [{:?}]\x1b[0m", self.inner.inner().title, self.inner.inner().year.unwrap_or(0), self.r#type, @@ -298,3 +304,49 @@ impl Display for TraktSearchResult { )) } } + +#[derive(Debug, Serialize, Deserialize, Clone, Copy, Hash, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum TraktKind { + Movie, + Show, + Season, + Episode, + Person, + User, +} + +impl TraktKind { + pub fn singular(self) -> &'static str { + match self { + TraktKind::Movie => "movie", + TraktKind::Show => "show", + TraktKind::Season => "season", + TraktKind::Episode => "episode", + TraktKind::Person => "person", + TraktKind::User => "user", + } + } + pub fn plural(self) -> &'static str { + match self { + TraktKind::Movie => "movies", + TraktKind::Show => "shows", + TraktKind::Season => "seasons", + TraktKind::Episode => "episodes", + TraktKind::Person => "people", + TraktKind::User => "users", // //! not used in API + } + } +} +impl Display for TraktKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(match self { + TraktKind::Movie => "Movie", + TraktKind::Show => "Show", + TraktKind::Season => "Season", + TraktKind::Episode => "Episode", + TraktKind::Person => "Person", + TraktKind::User => "User", + }) + } +} |