aboutsummaryrefslogtreecommitdiff
path: root/import/src
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2026-01-15 02:57:31 +0100
committermetamuffin <metamuffin@disroot.org>2026-01-15 02:57:31 +0100
commitc836b650eaf4ba33b1cfd2b475971b3ccc9f69b7 (patch)
tree2ea722aff33252ff2e3662faee63cabb223339c3 /import/src
parent8c0ee6d17fe0dbd7748e7b60ff01a0e8f25faa51 (diff)
downloadjellything-c836b650eaf4ba33b1cfd2b475971b3ccc9f69b7.tar
jellything-c836b650eaf4ba33b1cfd2b475971b3ccc9f69b7.tar.bz2
jellything-c836b650eaf4ba33b1cfd2b475971b3ccc9f69b7.tar.zst
new update_node_init
Diffstat (limited to 'import/src')
-rw-r--r--import/src/lib.rs75
-rw-r--r--import/src/plugins/acoustid.rs4
-rw-r--r--import/src/plugins/infojson.rs8
-rw-r--r--import/src/plugins/media_info.rs1
-rw-r--r--import/src/plugins/misc.rs15
-rw-r--r--import/src/plugins/mod.rs19
-rw-r--r--import/src/plugins/tags.rs1
-rw-r--r--import/src/plugins/tmdb.rs4
-rw-r--r--import/src/plugins/trakt.rs1
-rw-r--r--import/src/plugins/vgmdb.rs1
-rw-r--r--import/src/plugins/wikimedia_commons.rs4
11 files changed, 85 insertions, 48 deletions
diff --git a/import/src/lib.rs b/import/src/lib.rs
index aab0c70..ad929fa 100644
--- a/import/src/lib.rs
+++ b/import/src/lib.rs
@@ -14,8 +14,12 @@ use crate::{
};
use anyhow::{Context, Result, anyhow};
use jellycache::{HashKey, cache_memory, cache_store};
-use jellycommon::{NodeID, Visibility};
-use jellydb::Database;
+use jellycommon::jellyobject::{self, Object, ObjectBuffer, Tag, TypedTag};
+use jellydb::{
+ backends::Database,
+ query::{Filter, Query, Sort},
+ table::{RowNum, Table},
+};
use jellyremuxer::{
demuxers::create_demuxer_autodetect,
matroska::{self, AttachedFile, Segment},
@@ -29,6 +33,7 @@ use serde::{Deserialize, Serialize};
use std::{
collections::HashSet,
fs::{File, read_to_string},
+ marker::PhantomData,
mem::swap,
path::{Path, PathBuf},
sync::{Arc, LazyLock, Mutex},
@@ -76,7 +81,49 @@ pub fn is_importing() -> bool {
IMPORT_SEM.available_permits() == 0
}
-pub async fn import_wrap(db: Database, incremental: bool) -> Result<()> {
+pub struct NodeID(pub String);
+
+const NODE_ID: TypedTag<&str> = TypedTag(Tag(0x8123), PhantomData);
+
+struct DatabaseTables {
+ db: Arc<dyn Database>,
+ nodes: Table,
+}
+
+fn node_id_query(node: &NodeID) -> Query {
+ Query {
+ filter: Filter::Match(
+ jellyobject::Path(vec![NODE_ID.0]),
+ node.0.as_bytes().to_vec(),
+ ),
+ sort: Sort::None,
+ }
+}
+
+impl DatabaseTables {
+ pub fn update_node_init(
+ &self,
+ node: NodeID,
+ mut update: impl FnMut(Object) -> Option<ObjectBuffer>,
+ ) -> Result<()> {
+ self.db.write_transaction(&mut |txn| {
+ let node = match self.nodes.query_single(txn, node_id_query(&node)) {
+ Some(r) => r,
+ None => self
+ .nodes
+ .insert(txn, ObjectBuffer::new(&mut [(NODE_ID.0, &node.0.as_str())]))?,
+ };
+ let ob = self.nodes.get(txn, node)?.unwrap();
+ if let Some(changed) = update(ob.as_object()) {
+ self.nodes.update(txn, node, changed)?;
+ }
+ Ok(())
+ })?;
+ Ok(())
+ }
+}
+
+pub async fn import_wrap(db: DatabaseTables, incremental: bool) -> Result<()> {
let _sem = IMPORT_SEM.try_acquire().context("already importing")?;
let rt = Handle::current();
@@ -86,9 +133,9 @@ pub async fn import_wrap(db: Database, incremental: bool) -> Result<()> {
.build()?;
let jh = spawn_blocking(move || {
- tp.install(|| {
+ tp.install(move || {
reporting::start_import();
- reporting::catch(import(&db, &rt, incremental));
+ reporting::catch(import(db, &rt, incremental));
reporting::end_import();
})
});
@@ -98,7 +145,7 @@ pub async fn import_wrap(db: Database, incremental: bool) -> Result<()> {
Ok(())
}
-fn import(db: &Database, rt: &Handle, incremental: bool) -> Result<()> {
+fn import(db: DatabaseTables, rt: &Handle, incremental: bool) -> Result<()> {
let plugins = init_plugins(&CONF.api);
let files = Mutex::new(Vec::new());
import_traverse(
@@ -165,11 +212,11 @@ impl Default for InheritedFlags {
fn import_traverse(
path: &Path,
- db: &Database,
+ db: DatabaseTables,
incremental: bool,
- parent: NodeID,
+ parent: Option<RowNum>,
mut iflags: InheritedFlags,
- out: &Mutex<Vec<(PathBuf, NodeID, InheritedFlags)>>,
+ out: &Mutex<Vec<(PathBuf, RowNum, InheritedFlags)>>,
) -> Result<()> {
if path.is_dir() {
reporting::set_task(format!("indexing {path:?}"));
@@ -244,7 +291,7 @@ fn import_file(
db,
rt,
iflags,
- nodes,
+ pending_nodes: nodes,
};
let filename = path.file_name().unwrap().to_string_lossy();
if filename == "flags" {
@@ -343,7 +390,7 @@ fn import_file(
}
fn process_node(
- db: &Database,
+ dba: DatabaseTables,
rt: &Handle,
plugins: &[Box<dyn ImportPlugin>],
nodes: &Mutex<HashSet<NodeID>>,
@@ -369,10 +416,10 @@ fn process_node(
reporting::catch(
p.process(
&ImportContext {
- db,
+ dba,
rt,
iflags: InheritedFlags::default(),
- nodes,
+ pending_nodes: nodes,
},
node,
&data,
@@ -383,7 +430,7 @@ fn process_node(
}
}
-fn update_mtime(db: &Database, path: &Path) -> Result<()> {
+fn update_mtime(db: DatabaseTables, path: &Path) -> Result<()> {
let meta = path.metadata()?;
let mtime = meta.modified()?.duration_since(UNIX_EPOCH)?.as_secs();
db.set_import_file_mtime(path, mtime)?;
diff --git a/import/src/plugins/acoustid.rs b/import/src/plugins/acoustid.rs
index 55c2123..b93533a 100644
--- a/import/src/plugins/acoustid.rs
+++ b/import/src/plugins/acoustid.rs
@@ -9,7 +9,7 @@ use crate::{
};
use anyhow::{Context, Result};
use jellycache::{HashKey, cache_memory};
-use jellycommon::{IdentifierType, NodeID};
+use jellydb::table::RowNum;
use jellyremuxer::matroska::Segment;
use log::info;
use reqwest::{
@@ -166,7 +166,7 @@ impl ImportPlugin for AcoustID {
..Default::default()
}
}
- fn media(&self, ct: &ImportContext, node: NodeID, path: &Path, _seg: &Segment) -> Result<()> {
+ fn media(&self, ct: &ImportContext, node: RowNum, path: &Path, _seg: &Segment) -> Result<()> {
if !ct.iflags.use_acoustid {
return Ok(());
}
diff --git a/import/src/plugins/infojson.rs b/import/src/plugins/infojson.rs
index 3aac3ec..fd15e03 100644
--- a/import/src/plugins/infojson.rs
+++ b/import/src/plugins/infojson.rs
@@ -4,11 +4,9 @@
Copyright (C) 2026 metamuffin <metamuffin.org>
*/
use anyhow::{Context, Result, anyhow};
+use chrono::{Utc, format::Parsed};
use jellycache::cache_read;
-use jellycommon::{
- IdentifierType, NodeID, NodeKind, RatingType,
- chrono::{Utc, format::Parsed},
-};
+use jellydb::table::RowNum;
use jellyremuxer::matroska::{AttachedFile, Segment};
use log::info;
use serde::{Deserialize, Serialize};
@@ -168,7 +166,7 @@ impl ImportPlugin for Infojson {
..Default::default()
}
}
- fn file(&self, ct: &ImportContext, parent: NodeID, path: &Path) -> Result<()> {
+ fn file(&self, ct: &ImportContext, parent: RowNum, path: &Path) -> Result<()> {
let filename = path.file_name().unwrap().to_string_lossy();
if filename != "channel.info.json" {
return Ok(());
diff --git a/import/src/plugins/media_info.rs b/import/src/plugins/media_info.rs
index d2aa5af..da445a3 100644
--- a/import/src/plugins/media_info.rs
+++ b/import/src/plugins/media_info.rs
@@ -6,7 +6,6 @@
use crate::plugins::{ImportContext, ImportPlugin, PluginInfo};
use anyhow::{Result, anyhow};
-use jellycommon::{Chapter, NodeID, SourceTrack, SourceTrackKind, TrackSource};
use jellyremuxer::matroska::Segment;
use std::path::Path;
diff --git a/import/src/plugins/misc.rs b/import/src/plugins/misc.rs
index 8a95b97..43bd118 100644
--- a/import/src/plugins/misc.rs
+++ b/import/src/plugins/misc.rs
@@ -6,7 +6,8 @@
use crate::plugins::{ImportContext, ImportPlugin, PluginInfo};
use anyhow::{Context, Result, bail};
use jellycache::{HashKey, cache_store};
-use jellycommon::{Asset, NodeID, NodeKind, PictureSlot, Visibility};
+use jellycommon::{PICT_BACKDROP, PICT_COVER};
+use jellydb::table::RowNum;
use jellyremuxer::matroska::{AttachedFile, Segment};
use log::info;
use regex::Regex;
@@ -26,14 +27,14 @@ impl ImportPlugin for ImageFiles {
..Default::default()
}
}
- fn file(&self, ct: &ImportContext, parent: NodeID, path: &Path) -> Result<()> {
+ fn file(&self, ct: &ImportContext, parent: RowNum, path: &Path) -> Result<()> {
let filename = path.file_name().unwrap().to_string_lossy();
let slot = match filename.as_ref() {
- "poster.jpeg" | "poster.webp" | "poster.png" => PictureSlot::Cover,
- "backdrop.jpeg" | "backdrop.webp" | "backdrop.png" => PictureSlot::Backdrop,
+ "poster.jpeg" | "poster.webp" | "poster.png" => PICT_COVER,
+ "backdrop.jpeg" | "backdrop.webp" | "backdrop.png" => PICT_BACKDROP,
_ => return Ok(()),
};
- info!("import {slot} at {path:?}");
+ info!("import {} at {path:?}", slot);
let asset = Asset(cache_store(
format!("media/literal/{}-{slot}.image", HashKey(path)),
|| {
@@ -141,7 +142,7 @@ impl ImportPlugin for Children {
..Default::default()
}
}
- fn file(&self, ct: &ImportContext, parent: NodeID, path: &Path) -> Result<()> {
+ fn file(&self, ct: &ImportContext, parent: RowNum, path: &Path) -> Result<()> {
let filename = path.file_name().unwrap().to_string_lossy();
if filename.as_ref() == "children" {
info!("import children at {path:?}");
@@ -172,7 +173,7 @@ impl ImportPlugin for EpisodeIndex {
..Default::default()
}
}
- fn media(&self, ct: &ImportContext, node: NodeID, path: &Path, _seg: &Segment) -> Result<()> {
+ fn media(&self, ct: &ImportContext, node: RowNum, path: &Path, _seg: &Segment) -> Result<()> {
let filename = path.file_name().unwrap().to_string_lossy();
if let Some(cap) = RE_EPISODE_FILENAME.captures(&filename) {
if let Some(episode) = cap.name("episode").map(|m| m.as_str()) {
diff --git a/import/src/plugins/mod.rs b/import/src/plugins/mod.rs
index 3aeefdf..095fd39 100644
--- a/import/src/plugins/mod.rs
+++ b/import/src/plugins/mod.rs
@@ -15,19 +15,20 @@ pub mod vgmdb;
pub mod wikidata;
pub mod wikimedia_commons;
-use crate::{ApiSecrets, InheritedFlags};
+use crate::{ApiSecrets, DatabaseTables, InheritedFlags};
use anyhow::Result;
-use jellycommon::{Node, NodeID};
-use jellydb::Database;
+use jellycommon::jellyobject::Object;
+use jellydb::table::{RowNum, Table};
use jellyremuxer::matroska::Segment;
use std::{collections::HashSet, path::Path, sync::Mutex};
use tokio::runtime::Handle;
pub struct ImportContext<'a> {
- pub db: &'a Database,
+ pub dba: DatabaseTables,
+ pub nodes: &'a Table,
pub rt: &'a Handle,
pub iflags: InheritedFlags,
- pub nodes: &'a Mutex<HashSet<NodeID>>,
+ pub pending_nodes: &'a Mutex<HashSet<RowNum>>,
}
#[derive(Default, Clone, Copy)]
@@ -41,19 +42,19 @@ pub struct PluginInfo {
pub trait ImportPlugin: Send + Sync {
fn info(&self) -> PluginInfo;
- fn file(&self, ct: &ImportContext, parent: NodeID, path: &Path) -> Result<()> {
+ fn file(&self, ct: &ImportContext, parent: RowNum, path: &Path) -> Result<()> {
let _ = (ct, parent, path);
Ok(())
}
- fn media(&self, ct: &ImportContext, node: NodeID, path: &Path, seg: &Segment) -> Result<()> {
+ fn media(&self, ct: &ImportContext, node: RowNum, path: &Path, seg: &Segment) -> Result<()> {
let _ = (ct, node, path, seg);
Ok(())
}
- fn instruction(&self, ct: &ImportContext, node: NodeID, line: &str) -> Result<()> {
+ fn instruction(&self, ct: &ImportContext, node: RowNum, line: &str) -> Result<()> {
let _ = (ct, node, line);
Ok(())
}
- fn process(&self, ct: &ImportContext, node: NodeID, data: &Node) -> Result<()> {
+ fn process(&self, ct: &ImportContext, node: RowNum, data: Object<'_>) -> Result<()> {
let _ = (ct, node, data);
Ok(())
}
diff --git a/import/src/plugins/tags.rs b/import/src/plugins/tags.rs
index 9fa5ea9..07e40cc 100644
--- a/import/src/plugins/tags.rs
+++ b/import/src/plugins/tags.rs
@@ -6,7 +6,6 @@
use crate::plugins::{ImportContext, ImportPlugin, PluginInfo};
use anyhow::Result;
-use jellycommon::{IdentifierType, NodeID, NodeKind};
use jellyremuxer::matroska::Segment;
use std::{collections::HashMap, path::Path};
diff --git a/import/src/plugins/tmdb.rs b/import/src/plugins/tmdb.rs
index 5527b8b..ce9ae59 100644
--- a/import/src/plugins/tmdb.rs
+++ b/import/src/plugins/tmdb.rs
@@ -9,10 +9,6 @@ use crate::{
};
use anyhow::{Context, Result, anyhow, bail};
use jellycache::{EscapeKey, HashKey, cache_memory, cache_store};
-use jellycommon::{
- Asset, IdentifierType, Node, NodeID, PictureSlot, RatingType,
- chrono::{Utc, format::Parsed},
-};
use log::info;
use reqwest::{
Client, ClientBuilder,
diff --git a/import/src/plugins/trakt.rs b/import/src/plugins/trakt.rs
index c8ff52a..7981713 100644
--- a/import/src/plugins/trakt.rs
+++ b/import/src/plugins/trakt.rs
@@ -9,7 +9,6 @@ use crate::{
};
use anyhow::{Context, Result, anyhow, bail};
use jellycache::{HashKey, cache_memory};
-use jellycommon::{Appearance, CreditCategory, IdentifierType, Node, NodeID, NodeKind, RatingType};
use log::info;
use reqwest::{
Client, ClientBuilder,
diff --git a/import/src/plugins/vgmdb.rs b/import/src/plugins/vgmdb.rs
index 83f677d..734c7af 100644
--- a/import/src/plugins/vgmdb.rs
+++ b/import/src/plugins/vgmdb.rs
@@ -10,7 +10,6 @@ use crate::{
};
use anyhow::{Context, Result};
use jellycache::{HashKey, cache, cache_store};
-use jellycommon::Asset;
use log::info;
use regex::Regex;
use reqwest::{
diff --git a/import/src/plugins/wikimedia_commons.rs b/import/src/plugins/wikimedia_commons.rs
index 58a28ae..c849b61 100644
--- a/import/src/plugins/wikimedia_commons.rs
+++ b/import/src/plugins/wikimedia_commons.rs
@@ -10,7 +10,6 @@ use crate::{
};
use anyhow::{Context, Result};
use jellycache::{EscapeKey, cache_store};
-use jellycommon::Asset;
use reqwest::{
Client, ClientBuilder,
header::{HeaderMap, HeaderName, HeaderValue},
@@ -40,7 +39,7 @@ impl WikimediaCommons {
Self { client }
}
- pub fn image_by_filename(&self, filename: String, rt: &Handle) -> Result<Asset> {
+ pub fn image_by_filename(&self, filename: String, rt: &Handle) -> Result<String> {
cache_store(
format!("ext/wikimedia-commons/image/{}.image", EscapeKey(&filename)),
move || {
@@ -61,7 +60,6 @@ impl WikimediaCommons {
},
)
.context("mediawiki image by filename")
- .map(Asset)
}
}