diff options
Diffstat (limited to 'import/src/plugins')
| -rw-r--r-- | import/src/plugins/acoustid.rs | 9 | ||||
| -rw-r--r-- | import/src/plugins/infojson.rs | 10 | ||||
| -rw-r--r-- | import/src/plugins/media_info.rs | 9 | ||||
| -rw-r--r-- | import/src/plugins/misc.rs | 60 | ||||
| -rw-r--r-- | import/src/plugins/mod.rs | 53 | ||||
| -rw-r--r-- | import/src/plugins/musicbrainz.rs | 14 | ||||
| -rw-r--r-- | import/src/plugins/tags.rs | 9 | ||||
| -rw-r--r-- | import/src/plugins/tmdb.rs | 22 | ||||
| -rw-r--r-- | import/src/plugins/trakt.rs | 11 | ||||
| -rw-r--r-- | import/src/plugins/vgmdb.rs | 20 | ||||
| -rw-r--r-- | import/src/plugins/wikidata.rs | 14 | ||||
| -rw-r--r-- | import/src/plugins/wikimedia_commons.rs | 18 |
12 files changed, 218 insertions, 31 deletions
diff --git a/import/src/plugins/acoustid.rs b/import/src/plugins/acoustid.rs index 154b0a2..bf07f90 100644 --- a/import/src/plugins/acoustid.rs +++ b/import/src/plugins/acoustid.rs @@ -5,7 +5,7 @@ */ use crate::{ USER_AGENT, - plugins::{ImportContext, ImportPlugin}, + plugins::{ImportContext, ImportPlugin, PluginInfo}, }; use anyhow::{Context, Result}; use jellycache::{HashKey, cache_memory}; @@ -159,6 +159,13 @@ pub(crate) fn acoustid_fingerprint(path: &Path) -> Result<Arc<Fingerprint>> { } impl ImportPlugin for AcoustID { + fn info(&self) -> PluginInfo { + PluginInfo { + name: "acoustid", + handle_media: true, + ..Default::default() + } + } fn media(&self, ct: &ImportContext, node: NodeID, path: &Path, _seg: &Segment) -> Result<()> { let fp = acoustid_fingerprint(path)?; if let Some((atid, mbid)) = self.get_atid_mbid(&fp, &ct.rt)? { diff --git a/import/src/plugins/infojson.rs b/import/src/plugins/infojson.rs index 4dceeb8..5c3645c 100644 --- a/import/src/plugins/infojson.rs +++ b/import/src/plugins/infojson.rs @@ -14,7 +14,7 @@ use log::info; use serde::{Deserialize, Serialize}; use std::{collections::HashMap, fs::File, io::BufReader, path::Path}; -use crate::plugins::{ImportContext, ImportPlugin}; +use crate::plugins::{ImportContext, ImportPlugin, PluginInfo}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct YVideo { @@ -160,6 +160,14 @@ pub fn is_info_json(a: &&AttachedFile) -> bool { } pub struct Infojson; impl ImportPlugin for Infojson { + fn info(&self) -> PluginInfo { + PluginInfo { + name: "infojson", + handle_file: true, + handle_media: true, + ..Default::default() + } + } fn file(&self, ct: &ImportContext, parent: NodeID, path: &Path) -> Result<()> { let filename = path.file_name().unwrap().to_string_lossy(); if filename != "channel.info.json" { diff --git a/import/src/plugins/media_info.rs b/import/src/plugins/media_info.rs index 1d4d627..43d76e8 100644 --- a/import/src/plugins/media_info.rs +++ b/import/src/plugins/media_info.rs @@ -4,7 +4,7 @@ Copyright (C) 2025 metamuffin <metamuffin.org> */ -use crate::plugins::{ImportContext, ImportPlugin}; +use crate::plugins::{ImportContext, ImportPlugin, PluginInfo}; use anyhow::{Result, anyhow}; use jellycommon::{Chapter, NodeID, SourceTrack, SourceTrackKind, TrackSource}; use jellyremuxer::matroska::Segment; @@ -12,6 +12,13 @@ use std::path::Path; pub struct MediaInfo; impl ImportPlugin for MediaInfo { + fn info(&self) -> PluginInfo { + PluginInfo { + name: "media-info", + handle_media: true, + ..Default::default() + } + } fn media(&self, ct: &ImportContext, node: NodeID, path: &Path, seg: &Segment) -> Result<()> { let tracks = seg .tracks diff --git a/import/src/plugins/misc.rs b/import/src/plugins/misc.rs index 4717753..6f2c18e 100644 --- a/import/src/plugins/misc.rs +++ b/import/src/plugins/misc.rs @@ -3,16 +3,27 @@ which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2025 metamuffin <metamuffin.org> */ -use crate::plugins::{ImportContext, ImportPlugin}; +use crate::plugins::{ImportContext, ImportPlugin, PluginInfo}; use anyhow::{Result, bail}; use jellycache::{HashKey, cache_store}; use jellycommon::{Asset, NodeID, NodeKind, PictureSlot, Visibility}; use jellyremuxer::matroska::{AttachedFile, Segment}; use log::info; -use std::{fs::File, io::Read, path::Path}; +use std::{ + fs::{File, read_to_string}, + io::Read, + path::Path, +}; pub struct ImageFiles; impl ImportPlugin for ImageFiles { + fn info(&self) -> PluginInfo { + PluginInfo { + name: "image-files", + handle_file: true, + ..Default::default() + } + } fn file(&self, ct: &ImportContext, parent: NodeID, path: &Path) -> Result<()> { let filename = path.file_name().unwrap().to_string_lossy(); let slot = match filename.as_ref() { @@ -42,6 +53,13 @@ pub fn is_cover(a: &&AttachedFile) -> bool { } pub struct ImageAttachments; impl ImportPlugin for ImageAttachments { + fn info(&self) -> PluginInfo { + PluginInfo { + name: "image-attachments", + handle_media: true, + ..Default::default() + } + } fn media(&self, ct: &ImportContext, node: NodeID, _path: &Path, seg: &Segment) -> Result<()> { let Some(cover) = seg .attachments @@ -63,7 +81,14 @@ impl ImportPlugin for ImageAttachments { pub struct General; impl ImportPlugin for General { - fn import_instruction(&self, ct: &ImportContext, node: NodeID, line: &str) -> Result<()> { + fn info(&self) -> PluginInfo { + PluginInfo { + name: "general", + handle_instruction: true, + ..Default::default() + } + } + fn instruction(&self, ct: &ImportContext, node: NodeID, line: &str) -> Result<()> { if line == "hidden" { ct.db.update_node_init(node, |node| { node.visibility = node.visibility.min(Visibility::Hidden); @@ -98,3 +123,32 @@ impl ImportPlugin for General { Ok(()) } } + +pub struct Children; +impl ImportPlugin for Children { + fn info(&self) -> PluginInfo { + PluginInfo { + name: "children", + handle_file: true, + ..Default::default() + } + } + fn file(&self, ct: &ImportContext, parent: NodeID, path: &Path) -> Result<()> { + let filename = path.file_name().unwrap().to_string_lossy(); + if filename.as_ref() == "children" { + info!("import children at {path:?}"); + for line in read_to_string(path)?.lines() { + let line = line.trim(); + if line.starts_with("#") || line.is_empty() { + continue; + } + ct.db.update_node_init(NodeID::from_slug(line), |n| { + n.slug = line.to_owned(); + n.parents.insert(parent); + Ok(()) + })?; + } + } + Ok(()) + } +} diff --git a/import/src/plugins/mod.rs b/import/src/plugins/mod.rs index 47fcfbf..a5cc3dc 100644 --- a/import/src/plugins/mod.rs +++ b/import/src/plugins/mod.rs @@ -5,6 +5,8 @@ */ pub mod acoustid; pub mod infojson; +pub mod media_info; +pub mod misc; pub mod musicbrainz; pub mod tags; pub mod tmdb; @@ -12,23 +14,32 @@ pub mod trakt; pub mod vgmdb; pub mod wikidata; pub mod wikimedia_commons; -pub mod media_info; -pub mod misc; - -use std::path::Path; use anyhow::Result; use jellycommon::NodeID; use jellydb::Database; use jellyremuxer::matroska::Segment; +use std::path::Path; use tokio::runtime::Handle; +use crate::ApiSecrets; + pub struct ImportContext { pub db: Database, pub rt: Handle, } -pub trait ImportPlugin { +#[derive(Default, Clone, Copy)] +pub struct PluginInfo { + name: &'static str, + handle_file: bool, + handle_media: bool, + handle_instruction: bool, + handle_process: bool, +} + +pub trait ImportPlugin: Send + Sync { + fn info(&self) -> PluginInfo; fn file(&self, ct: &ImportContext, parent: NodeID, path: &Path) -> Result<()> { let _ = (ct, parent, path); Ok(()) @@ -37,12 +48,40 @@ pub trait ImportPlugin { let _ = (ct, node, path, seg); Ok(()) } - fn import_instruction(&self, ct: &ImportContext, node: NodeID, line: &str) -> Result<()> { + fn instruction(&self, ct: &ImportContext, node: NodeID, line: &str) -> Result<()> { let _ = (ct, node, line); Ok(()) } - fn process_node(&self, ct: &ImportContext, node: NodeID) -> Result<()> { + fn process(&self, ct: &ImportContext, node: NodeID) -> Result<()> { let _ = (ct, node); Ok(()) } } + +pub fn init_plugins(secrets: &ApiSecrets) -> Vec<Box<dyn ImportPlugin>> { + let mut plugins = Vec::<Box<dyn ImportPlugin>>::new(); + + plugins.push(Box::new(misc::General)); + plugins.push(Box::new(misc::Children)); + plugins.push(Box::new(misc::ImageAttachments)); + plugins.push(Box::new(misc::ImageFiles)); + plugins.push(Box::new(tags::Tags)); + plugins.push(Box::new(media_info::MediaInfo)); + + if let Some(s) = &secrets.trakt { + plugins.push(Box::new(trakt::Trakt::new(&s))); + } + if let Some(s) = &secrets.tmdb { + plugins.push(Box::new(tmdb::Tmdb::new(&s))); // deps: trakt + } + + if let Some(s) = &secrets.acoustid { + plugins.push(Box::new(acoustid::AcoustID::new(&s))); + } + plugins.push(Box::new(musicbrainz::MusicBrainz::new())); // deps: acoustid + plugins.push(Box::new(wikidata::Wikidata::new())); // deps: musicbrainz + plugins.push(Box::new(wikimedia_commons::WikimediaCommons::new())); // deps: wikidata + plugins.push(Box::new(vgmdb::Vgmdb::new())); // deps: wikidata + + plugins +} diff --git a/import/src/plugins/musicbrainz.rs b/import/src/plugins/musicbrainz.rs index 44b2a06..305b03f 100644 --- a/import/src/plugins/musicbrainz.rs +++ b/import/src/plugins/musicbrainz.rs @@ -4,7 +4,10 @@ Copyright (C) 2025 metamuffin <metamuffin.org> */ -use crate::{USER_AGENT, plugins::ImportPlugin}; +use crate::{ + USER_AGENT, + plugins::{ImportPlugin, PluginInfo}, +}; use anyhow::{Context, Result}; use jellycache::cache_memory; use log::info; @@ -317,4 +320,11 @@ impl MusicBrainz { } } -impl ImportPlugin for MusicBrainz {} +impl ImportPlugin for MusicBrainz { + fn info(&self) -> PluginInfo { + PluginInfo { + name: "musicbrainz", + ..Default::default() + } + } +} diff --git a/import/src/plugins/tags.rs b/import/src/plugins/tags.rs index 8452aad..7e30504 100644 --- a/import/src/plugins/tags.rs +++ b/import/src/plugins/tags.rs @@ -4,7 +4,7 @@ Copyright (C) 2025 metamuffin <metamuffin.org> */ -use crate::plugins::{ImportContext, ImportPlugin}; +use crate::plugins::{ImportContext, ImportPlugin, PluginInfo}; use anyhow::Result; use jellycommon::{IdentifierType, NodeID, NodeKind}; use jellyremuxer::matroska::Segment; @@ -12,6 +12,13 @@ use std::{collections::HashMap, path::Path}; pub struct Tags; impl ImportPlugin for Tags { + fn info(&self) -> PluginInfo { + PluginInfo { + name: "tags", + handle_media: true, + ..Default::default() + } + } fn media(&self, ct: &ImportContext, node: NodeID, _path: &Path, seg: &Segment) -> Result<()> { let tags = seg .tags diff --git a/import/src/plugins/tmdb.rs b/import/src/plugins/tmdb.rs index 3d6e832..5980d53 100644 --- a/import/src/plugins/tmdb.rs +++ b/import/src/plugins/tmdb.rs @@ -3,17 +3,20 @@ which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2025 metamuffin <metamuffin.org> */ -use crate::USER_AGENT; -use anyhow::{anyhow, bail, Context, Result}; -use jellycache::{cache_memory, cache_store, EscapeKey, HashKey}; +use crate::{ + USER_AGENT, + plugins::{ImportPlugin, PluginInfo}, +}; +use anyhow::{Context, Result, anyhow, bail}; +use jellycache::{EscapeKey, HashKey, cache_memory, cache_store}; use jellycommon::{ - chrono::{format::Parsed, Utc}, Asset, + chrono::{Utc, format::Parsed}, }; use log::info; use reqwest::{ - header::{HeaderMap, HeaderName, HeaderValue}, Client, ClientBuilder, + header::{HeaderMap, HeaderName, HeaderValue}, }; use serde::{Deserialize, Serialize}; use std::{fmt::Display, sync::Arc}; @@ -153,6 +156,15 @@ impl Tmdb { } } +impl ImportPlugin for Tmdb { + fn info(&self) -> PluginInfo { + PluginInfo { + name: "tmdb", + ..Default::default() + } + } +} + pub fn parse_release_date(d: &str) -> Result<Option<i64>> { if d.is_empty() { return Ok(None); diff --git a/import/src/plugins/trakt.rs b/import/src/plugins/trakt.rs index 5a1aa8e..6d5b007 100644 --- a/import/src/plugins/trakt.rs +++ b/import/src/plugins/trakt.rs @@ -5,7 +5,7 @@ */ use crate::{ USER_AGENT, - plugins::{ImportContext, ImportPlugin}, + plugins::{ImportContext, ImportPlugin, PluginInfo}, }; use anyhow::{Context, Result, bail}; use jellycache::{HashKey, cache_memory}; @@ -383,7 +383,14 @@ impl Display for TraktKind { } impl ImportPlugin for Trakt { - fn import_instruction(&self, ct: &ImportContext, node: NodeID, line: &str) -> Result<()> { + fn info(&self) -> PluginInfo { + PluginInfo { + name: "takt", + handle_instruction: true, + ..Default::default() + } + } + fn instruction(&self, ct: &ImportContext, node: NodeID, line: &str) -> Result<()> { if let Some(value) = line.strip_prefix("trakt-").or(line.strip_prefix("trakt=")) { let (ty, id) = value.split_once(":").unwrap_or(("movie", value)); let ty = match ty { diff --git a/import/src/plugins/vgmdb.rs b/import/src/plugins/vgmdb.rs index 402fd90..a3928bd 100644 --- a/import/src/plugins/vgmdb.rs +++ b/import/src/plugins/vgmdb.rs @@ -4,15 +4,18 @@ Copyright (C) 2025 metamuffin <metamuffin.org> */ -use crate::USER_AGENT; +use crate::{ + USER_AGENT, + plugins::{ImportPlugin, PluginInfo}, +}; use anyhow::{Context, Result}; -use jellycache::{cache, cache_store, HashKey}; +use jellycache::{HashKey, cache, cache_store}; use jellycommon::Asset; use log::info; use regex::Regex; use reqwest::{ - header::{HeaderMap, HeaderName, HeaderValue}, Client, ClientBuilder, + header::{HeaderMap, HeaderName, HeaderValue}, }; use std::{ sync::{Arc, LazyLock}, @@ -21,7 +24,7 @@ use std::{ use tokio::{ runtime::Handle, sync::Semaphore, - time::{sleep_until, Instant}, + time::{Instant, sleep_until}, }; pub struct Vgmdb { @@ -125,3 +128,12 @@ impl Vgmdb { .context("vgmdb artist page scrape") } } + +impl ImportPlugin for Vgmdb { + fn info(&self) -> PluginInfo { + PluginInfo { + name: "vgmdb", + ..Default::default() + } + } +} diff --git a/import/src/plugins/wikidata.rs b/import/src/plugins/wikidata.rs index 358996e..095e4bd 100644 --- a/import/src/plugins/wikidata.rs +++ b/import/src/plugins/wikidata.rs @@ -4,7 +4,10 @@ Copyright (C) 2025 metamuffin <metamuffin.org> */ -use crate::USER_AGENT; +use crate::{ + USER_AGENT, + plugins::{ImportPlugin, PluginInfo}, +}; use anyhow::{Context, Result, bail}; use jellycache::{EscapeKey, cache_memory}; use log::info; @@ -127,3 +130,12 @@ impl Wikidata { .context("wikidata entity") } } + +impl ImportPlugin for Wikidata { + fn info(&self) -> PluginInfo { + PluginInfo { + name: "wikidata", + ..Default::default() + } + } +} diff --git a/import/src/plugins/wikimedia_commons.rs b/import/src/plugins/wikimedia_commons.rs index 86d934c..3d11d74 100644 --- a/import/src/plugins/wikimedia_commons.rs +++ b/import/src/plugins/wikimedia_commons.rs @@ -4,14 +4,17 @@ Copyright (C) 2025 metamuffin <metamuffin.org> */ -use crate::USER_AGENT; +use crate::{ + USER_AGENT, + plugins::{ImportPlugin, PluginInfo}, +}; use anyhow::{Context, Result}; -use jellycache::{cache_store, EscapeKey}; +use jellycache::{EscapeKey, cache_store}; use jellycommon::Asset; use reqwest::{ + Client, ClientBuilder, header::{HeaderMap, HeaderName, HeaderValue}, redirect::Policy, - Client, ClientBuilder, }; use tokio::runtime::Handle; @@ -61,3 +64,12 @@ impl WikimediaCommons { .map(Asset) } } + +impl ImportPlugin for WikimediaCommons { + fn info(&self) -> PluginInfo { + PluginInfo { + name: "wikimedia-commons", + ..Default::default() + } + } +} |