aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2026-02-21 03:46:30 +0100
committermetamuffin <metamuffin@disroot.org>2026-02-21 03:46:30 +0100
commit356bc5fe6913e85b18a2cb355f30019cdfd6b146 (patch)
treeb6d2ea73498c04d740291c8670fff1ec81d1a886
parenta7e9d52efd1dba23a43f13d0eb9bb2236d1de74c (diff)
downloadjellything-356bc5fe6913e85b18a2cb355f30019cdfd6b146.tar
jellything-356bc5fe6913e85b18a2cb355f30019cdfd6b146.tar.bz2
jellything-356bc5fe6913e85b18a2cb355f30019cdfd6b146.tar.zst
Also use source ranks for nested attributes
-rw-r--r--common/object/src/lib.rs15
-rw-r--r--common/object/src/value.rs22
-rw-r--r--import/src/plugins/acoustid.rs2
-rw-r--r--import/src/plugins/infojson.rs8
-rw-r--r--import/src/plugins/musicbrainz.rs14
-rw-r--r--import/src/plugins/omdb.rs2
-rw-r--r--import/src/plugins/tags.rs6
-rw-r--r--import/src/plugins/tmdb.rs4
-rw-r--r--import/src/plugins/trakt.rs20
-rw-r--r--locale/en.ini44
-rw-r--r--ui/src/components/node_page.rs9
11 files changed, 86 insertions, 60 deletions
diff --git a/common/object/src/lib.rs b/common/object/src/lib.rs
index a73de08..98e4834 100644
--- a/common/object/src/lib.rs
+++ b/common/object/src/lib.rs
@@ -160,7 +160,7 @@ impl<'a> Object<'a> {
}
#[inline]
pub fn get_typed<T: ValueLoad<'a>>(&self, index: usize) -> Option<T> {
- if T::ALIGNED {
+ if T::TYPE.is_aligned() {
T::load_aligned(self.get_aligned(index)?)
} else {
T::load_unaligned(self.get_unaligned(index)?)
@@ -326,13 +326,18 @@ pub struct EntriesIter<'a, T> {
impl<'a, T: ValueLoad<'a>> Iterator for EntriesIter<'a, T> {
type Item = (Tag, T);
fn next(&mut self) -> Option<Self::Item> {
- if self.index >= self.object.tags.len() {
- return None;
- } else {
+ loop {
+ if self.index >= self.object.tags.len() {
+ return None;
+ }
+ if T::TYPE != self.object.offset_type(self.index) {
+ self.index += 1;
+ continue;
+ }
let value = self.object.get_typed(self.index)?;
let tag = self.object.tags[self.index];
self.index += 1;
- Some((Tag(tag), value))
+ return Some((Tag(tag), value));
}
}
}
diff --git a/common/object/src/value.rs b/common/object/src/value.rs
index 8371a79..9b9a438 100644
--- a/common/object/src/value.rs
+++ b/common/object/src/value.rs
@@ -8,7 +8,7 @@ use crate::{Object, ObjectBuffer, Tag};
use std::{borrow::Cow, fmt::Display, str::FromStr};
pub trait ValueLoad<'a>: ValueStore + Sized {
- const ALIGNED: bool;
+ const TYPE: ValueType;
fn load_aligned(buf: &'a [u32]) -> Option<Self> {
let _ = buf;
unimplemented!()
@@ -33,7 +33,7 @@ pub enum ValueType {
impl ValueType {
#[inline]
- pub fn is_aligned(self) -> bool {
+ pub const fn is_aligned(self) -> bool {
match self {
ValueType::Binary | ValueType::String => false,
_ => true,
@@ -133,7 +133,7 @@ pub trait ValueStore {
fn size(&self) -> usize;
}
impl<'a> ValueLoad<'a> for &'a str {
- const ALIGNED: bool = false;
+ const TYPE: ValueType = ValueType::String;
fn load_unaligned(buf: &'a [u8]) -> Option<Self> {
str::from_utf8(buf).ok()
}
@@ -150,7 +150,7 @@ impl ValueStore for &str {
}
}
impl ValueLoad<'_> for u32 {
- const ALIGNED: bool = true;
+ const TYPE: ValueType = ValueType::UInt;
fn load_aligned(buf: &[u32]) -> Option<Self> {
buf.get(0).copied().map(u32::from_be)
}
@@ -167,7 +167,7 @@ impl ValueStore for u32 {
}
}
impl ValueLoad<'_> for Tag {
- const ALIGNED: bool = true;
+ const TYPE: ValueType = ValueType::Tag;
fn load_aligned(buf: &[u32]) -> Option<Self> {
buf.get(0).copied().map(u32::from_be).map(Tag)
}
@@ -184,7 +184,7 @@ impl ValueStore for Tag {
}
}
impl ValueLoad<'_> for u64 {
- const ALIGNED: bool = true;
+ const TYPE: ValueType = ValueType::UInt;
fn load_aligned(buf: &[u32]) -> Option<Self> {
let hi = u32::from_be(*buf.get(0)?) as u64;
let lo = u32::from_be(*buf.get(1)?) as u64;
@@ -204,7 +204,7 @@ impl ValueStore for u64 {
}
}
impl ValueLoad<'_> for f64 {
- const ALIGNED: bool = true;
+ const TYPE: ValueType = ValueType::Float;
fn load_aligned(buf: &[u32]) -> Option<Self> {
if buf.len() < 2 {
return None;
@@ -230,7 +230,7 @@ impl ValueStore for f64 {
}
}
impl ValueLoad<'_> for i64 {
- const ALIGNED: bool = true;
+ const TYPE: ValueType = ValueType::Int;
fn load_aligned(buf: &[u32]) -> Option<Self> {
u64::load_aligned(buf).map(|x| x as i64)
}
@@ -247,7 +247,7 @@ impl ValueStore for i64 {
}
}
impl<'a> ValueLoad<'a> for Object<'a> {
- const ALIGNED: bool = true;
+ const TYPE: ValueType = ValueType::Object;
fn load_aligned(buf: &'a [u32]) -> Option<Self> {
Self::load(buf)
}
@@ -278,7 +278,7 @@ impl ValueStore for ObjectBuffer {
}
}
impl<'a> ValueLoad<'a> for &'a [u8] {
- const ALIGNED: bool = false;
+ const TYPE: ValueType = ValueType::Binary;
fn load_unaligned(buf: &'a [u8]) -> Option<Self> {
Some(buf)
}
@@ -295,7 +295,7 @@ impl ValueStore for &[u8] {
}
}
impl<'a> ValueLoad<'a> for () {
- const ALIGNED: bool = true;
+ const TYPE: ValueType = ValueType::Int;
fn load_aligned(_buf: &'a [u32]) -> Option<Self> {
Some(())
}
diff --git a/import/src/plugins/acoustid.rs b/import/src/plugins/acoustid.rs
index c829aac..411f9d1 100644
--- a/import/src/plugins/acoustid.rs
+++ b/import/src/plugins/acoustid.rs
@@ -199,7 +199,7 @@ impl ImportPlugin for AcoustID {
ct.ic.update_node(node, |node| {
node.as_object().update(NO_IDENTIFIERS, |ids| {
- ids.insert(IDENT_ACOUST_ID_TRACK, &atid)
+ ids.insert_s(ct.is, IDENT_ACOUST_ID_TRACK, &atid)
.as_object()
.insert_s(ct.is, IDENT_MUSICBRAINZ_RECORDING, &mbid)
})
diff --git a/import/src/plugins/infojson.rs b/import/src/plugins/infojson.rs
index 6905e57..8a3ba5d 100644
--- a/import/src/plugins/infojson.rs
+++ b/import/src/plugins/infojson.rs
@@ -198,7 +198,7 @@ impl ImportPlugin for Infojson {
}
if let Some(followers) = data.channel_follower_count {
node = node.as_object().update(NO_RATINGS, |rat| {
- rat.insert(RTYP_YOUTUBE_SUBSCRIBERS, followers as f64)
+ rat.insert_s(ct.is, RTYP_YOUTUBE_SUBSCRIBERS, followers as f64)
});
}
@@ -274,13 +274,15 @@ impl ImportPlugin for Infojson {
rat.insert_s(ct.is, IDENT_YOUTUBE_VIDEO, &infojson.id)
});
node = node.as_object().update(NO_RATINGS, |rat| {
- rat.insert(
+ rat.insert_s(
+ ct.is,
RTYP_YOUTUBE_VIEWS,
infojson.view_count.unwrap_or_default() as f64,
)
});
node = node.as_object().update(NO_RATINGS, |rat| {
- rat.insert(
+ rat.insert_s(
+ ct.is,
RTYP_YOUTUBE_LIKES,
infojson.like_count.unwrap_or_default() as f64,
)
diff --git a/import/src/plugins/musicbrainz.rs b/import/src/plugins/musicbrainz.rs
index 454c562..ec44d11 100644
--- a/import/src/plugins/musicbrainz.rs
+++ b/import/src/plugins/musicbrainz.rs
@@ -402,7 +402,7 @@ impl MusicBrainz {
let mut artist_node = txn.get(artist_row)?.unwrap();
artist_node = artist_node.as_object().update(NO_IDENTIFIERS, |ids| {
- ids.insert(IDENT_MUSICBRAINZ_ARTIST, &artist.id)
+ ids.insert_s(ct.is, IDENT_MUSICBRAINZ_ARTIST, &artist.id)
});
artist_node = artist_node.as_object().insert(NO_KIND, KIND_PERSON);
txn.update(artist_row, artist_node)?;
@@ -449,18 +449,18 @@ impl MusicBrainz {
if let Some(url) = url
&& let Some(id) = url.strip_prefix("https://www.wikidata.org/wiki/")
{
- node = node
- .as_object()
- .update(NO_IDENTIFIERS, |ids| ids.insert(IDENT_WIKIDATA, id))
+ node = node.as_object().update(NO_IDENTIFIERS, |ids| {
+ ids.insert_s(ct.is, IDENT_WIKIDATA, id)
+ })
}
}
VGMDB => {
if let Some(url) = url
&& let Some(id) = url.strip_prefix("https://vgmdb.net/artist/")
{
- node = node
- .as_object()
- .update(NO_IDENTIFIERS, |ids| ids.insert(IDENT_VGMDB_ARTIST, id))
+ node = node.as_object().update(NO_IDENTIFIERS, |ids| {
+ ids.insert_s(ct.is, IDENT_VGMDB_ARTIST, id)
+ })
}
}
_ => (),
diff --git a/import/src/plugins/omdb.rs b/import/src/plugins/omdb.rs
index 20fb933..3b97a9d 100644
--- a/import/src/plugins/omdb.rs
+++ b/import/src/plugins/omdb.rs
@@ -167,7 +167,7 @@ impl ImportPlugin for Omdb {
if let Some(x) = val {
node = node
.as_object()
- .update(NO_RATINGS, |rts| rts.insert(typ, x));
+ .update(NO_RATINGS, |rts| rts.insert_s(ct.is, typ, x));
}
}
node
diff --git a/import/src/plugins/tags.rs b/import/src/plugins/tags.rs
index b60ef37..c27ea70 100644
--- a/import/src/plugins/tags.rs
+++ b/import/src/plugins/tags.rs
@@ -69,9 +69,9 @@ impl ImportPlugin for Tags {
"BARCODE" => IDENT_BARCODE,
_ => continue,
};
- node = node
- .as_object()
- .update(NO_IDENTIFIERS, |idents| idents.insert(idty, &value));
+ node = node.as_object().update(NO_IDENTIFIERS, |idents| {
+ idents.insert_s(ct.is, idty, &value)
+ });
}
}
}
diff --git a/import/src/plugins/tmdb.rs b/import/src/plugins/tmdb.rs
index db336fe..39f8115 100644
--- a/import/src/plugins/tmdb.rs
+++ b/import/src/plugins/tmdb.rs
@@ -246,7 +246,7 @@ impl Tmdb {
.as_object()
.insert_s(ct.is, NO_DESCRIPTION, &details.overview);
node = node.as_object().update(NO_RATINGS, |rat| {
- rat.insert(RTYP_TMDB, details.vote_average)
+ rat.insert_s(ct.is, RTYP_TMDB, details.vote_average)
});
if let Some(poster) = &poster {
node = node
@@ -312,7 +312,7 @@ impl Tmdb {
.insert_s(ct.is, NO_RELEASEDATE, release_date)
}
node = node.as_object().update(NO_RATINGS, |rat| {
- rat.insert(RTYP_TMDB, details.vote_average)
+ rat.insert_s(ct.is, RTYP_TMDB, details.vote_average)
});
if let Some(cover) = &cover {
node = node.as_object().update(NO_PICTURES, |picts| {
diff --git a/import/src/plugins/trakt.rs b/import/src/plugins/trakt.rs
index cc3b119..bb4a1b0 100644
--- a/import/src/plugins/trakt.rs
+++ b/import/src/plugins/trakt.rs
@@ -483,13 +483,13 @@ impl Trakt {
node = node.as_object().insert_s(ct.is, NO_TAGLINE, &tagline);
}
if let Some(x) = details.ids.imdb.clone() {
- node = node
- .as_object()
- .update(NO_IDENTIFIERS, |idents| idents.insert(IDENT_IMDB, &x));
+ node = node.as_object().update(NO_IDENTIFIERS, |idents| {
+ idents.insert_s(ct.is, IDENT_IMDB, &x)
+ });
}
if let Some(x) = details.ids.tvdb.clone() {
node = node.as_object().update(NO_IDENTIFIERS, |idents| {
- idents.insert(IDENT_TVDB, &x.to_string())
+ idents.insert_s(ct.is, IDENT_TVDB, &x.to_string())
});
}
if let Some(x) = details.ids.tmdb.clone() {
@@ -530,12 +530,14 @@ impl Trakt {
c = c.as_object().update(NO_IDENTIFIERS, |ids| {
let mut ids = ids.insert(IDENT_TRAKT_PERSON, &traktid.to_string());
if let Some(tmdbid) = ap.person.ids.tmdb {
- ids = ids
- .as_object()
- .insert(IDENT_TMDB_PERSON, &tmdbid.to_string());
+ ids = ids.as_object().insert_s(
+ ct.is,
+ IDENT_TMDB_PERSON,
+ &tmdbid.to_string(),
+ );
}
if let Some(imdbid) = &ap.person.ids.imdb {
- ids = ids.as_object().insert(IDENT_IMDB_PERSON, imdbid);
+ ids = ids.as_object().insert_s(ct.is, IDENT_IMDB_PERSON, imdbid);
}
ids
});
@@ -604,7 +606,7 @@ impl Trakt {
if let Some(r) = episode.rating {
node = node
.as_object()
- .update(NO_RATINGS, |rats| rats.insert(RTYP_TRAKT, r));
+ .update(NO_RATINGS, |rats| rats.insert_s(ct.is, RTYP_TRAKT, r));
}
node
})?;
diff --git a/locale/en.ini b/locale/en.ini
index 229907e..1e901ef 100644
--- a/locale/en.ini
+++ b/locale/en.ini
@@ -88,6 +88,8 @@ tag.cred.kind.vfx1=VFX
tag.cred.kind.voca=Vocals
tag.cred.kind.writ=Writing
tag.cred=Credit
+tag.desc=Description
+tag.durn=Duration
tag.iden.actr=AcoustID Track
tag.iden.barc=Barcode
tag.iden.bcmp=Bandcamp
@@ -113,7 +115,7 @@ tag.iden.wkdt=Wikidata
tag.iden.ytc1=YouTube Channel
tag.iden.ytch=YouTube Channel Handle
tag.iden.ytvi=YouTube Video
-tag.iden=Identifiers
+tag.iden=Identifier
tag.kind.chnl=Channel
tag.kind.coll=Collection
tag.kind.epsd=Episode
@@ -125,29 +127,37 @@ tag.kind.sfvi=Short Form Video
tag.kind.show=Show
tag.kind.unkn=Unknown
tag.kind.vide=Video
-tag.msrc.trkt=Trakt
+tag.kind=Kind
+tag.msrc.acid=AcoustID
+tag.msrc.expl=Manually specified
+tag.msrc.iatt=Image attachment
tag.msrc.infj=Embedded info.json
-tag.msrc.tmdb=TMDB
+tag.msrc.mbrz=Musicbrainz
+tag.msrc.medi=Media
tag.msrc.omdb=OMDB
+tag.msrc.tags=File tags
+tag.msrc.tmdb=TMDB
+tag.msrc.trkt=Trakt
tag.msrc.vgmd=VGMDB
tag.msrc.wkdt=Wikidata / Wikimedia Commons
-tag.msrc.mbrz=Musicbrainz
-tag.msrc.tags=File tags
-tag.msrc.iatt=Image attachment
-tag.msrc.acid=AcoustID
-tag.msrc.medi=Media
-tag.msrc.expl=Manually specified
-tag.kind=Kind
-tag.desc=Description
-tag.titl=Title
-tag.tgln=Tagline
tag.msrc=Metadata Sources
-tag.stsz=Size on Filesystem
+tag.pict.bkdr=Backdrop
+tag.pict.covr=Cover
+tag.pict=Image
tag.rldt=Release date
-tag.durn=Duration
+tag.rtng.imdb=IMDb
+tag.rtng.mcri=Metascore
+tag.rtng.rtom=Rotten Tomatoes
+tag.rtng.tmdb=TMDB
+tag.rtng.trkt=Trakt
+tag.rtng.ytli=Youtube Likes
+tag.rtng.ytsu=Youtube Subscribers
+tag.rtng.ytvi=Youtube Video ID
+tag.rtng=Rating
tag.sbtl=Subtitle
-tag.pict.covr=Cover
-tag.pict.bkdr=Backdrop
+tag.stsz=Size on Filesystem
+tag.tgln=Tagline
+tag.titl=Title
theme.dark=Dark
theme.light=Light
diff --git a/ui/src/components/node_page.rs b/ui/src/components/node_page.rs
index 9be20f2..7deaf61 100644
--- a/ui/src/components/node_page.rs
+++ b/ui/src/components/node_page.rs
@@ -143,8 +143,15 @@ markup::define! {
tr { th {"Attribute"} th {"Source"} }
@for (key, source) in node.get(NO_METASOURCE).unwrap_or_default().entries::<Tag>() { tr {
td { @tr(ri.lang, &format!("tag.{key}")) }
- td { @tr(ri.lang, &format!("tag.msrc.{source}")) }
+ td { @tr(ri.lang, &format!("tag.msrc.{source}")) }
}}
+ @for nkey in [NO_PICTURES, NO_IDENTIFIERS, NO_RATINGS] {
+ @let nob = node.get(nkey).unwrap_or_default();
+ @for (key, source) in nob.get(NO_METASOURCE).unwrap_or_default().entries::<Tag>() { tr {
+ td { @tr(ri.lang, &format!("tag.{nkey}")) ": " @tr(ri.lang, &format!("tag.{nkey}.{key}")) }
+ td { @tr(ri.lang, &format!("tag.msrc.{source}")) }
+ }}
+ }
}
}
}