diff options
Diffstat (limited to 'import/src/lib.rs')
| -rw-r--r-- | import/src/lib.rs | 149 |
1 files changed, 80 insertions, 69 deletions
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()); |