diff options
| author | metamuffin <metamuffin@disroot.org> | 2026-03-18 17:44:58 +0100 |
|---|---|---|
| committer | metamuffin <metamuffin@disroot.org> | 2026-03-18 17:44:58 +0100 |
| commit | 53b0268eaa850d0a7250c94373d76906a7b28250 (patch) | |
| tree | 16cb09376d8446b1bb7edb60ee0f162b93ab1a92 | |
| parent | 3c541b7487a93d627f87d4fc1a5385cc57d5ee45 (diff) | |
| download | jellything-53b0268eaa850d0a7250c94373d76906a7b28250.tar jellything-53b0268eaa850d0a7250c94373d76906a7b28250.tar.bz2 jellything-53b0268eaa850d0a7250c94373d76906a7b28250.tar.zst | |
filter by kind without filter parser
| -rw-r--r-- | common/src/api.rs | 5 | ||||
| -rw-r--r-- | database/src/kv/mod.rs | 6 | ||||
| -rw-r--r-- | database/src/lib.rs | 2 | ||||
| -rw-r--r-- | server/src/routes/node.rs | 77 | ||||
| -rw-r--r-- | ui/src/components/filter.rs | 23 | ||||
| -rw-r--r-- | ui/src/components/mod.rs | 4 | ||||
| -rw-r--r-- | ui/src/components/node_list.rs | 47 | ||||
| -rw-r--r-- | ui/src/components/node_page.rs | 18 |
8 files changed, 123 insertions, 59 deletions
diff --git a/common/src/api.rs b/common/src/api.rs index 061ff09..709e407 100644 --- a/common/src/api.rs +++ b/common/src/api.rs @@ -30,3 +30,8 @@ pub struct StatsBin { pub max_size: u64, pub max_size_node: String, } + +#[derive(Debug, Clone)] +pub struct NodeFilter { + pub kind: Option<Tag>, +} diff --git a/database/src/kv/mod.rs b/database/src/kv/mod.rs index 0ce4683..816dc9f 100644 --- a/database/src/kv/mod.rs +++ b/database/src/kv/mod.rs @@ -14,7 +14,7 @@ pub mod prefix_iterator; pub mod tests; use crate::{ - Database, Query, RowNum, Transaction, + Database, Filter, Query, RowNum, Transaction, kv::{ helpers::{read_counter, write_counter}, index::{iter_index, read_count_index, test_index_identical, update_index}, @@ -135,9 +135,9 @@ impl Transaction for &mut dyn jellykv::Transaction { fn query_single(&mut self, query: Query) -> Result<Option<RowNum>> { Ok(self.query(query)?.next().transpose()?.map(|(e, _)| e)) } - fn count(&mut self, query: Query) -> Result<u64> { + fn count(&mut self, filter: Filter) -> Result<u64> { let mut total = 0; - for (binning, mut prefix) in query.filter.get_bins() { + for (binning, mut prefix) in filter.get_bins() { let ik = IndexKey(binning, SortKey::Count); let is = get_or_create_index(*self, &ik)?; prefix.splice(0..0, is.to_be_bytes()); diff --git a/database/src/lib.rs b/database/src/lib.rs index 9bd4c06..da58003 100644 --- a/database/src/lib.rs +++ b/database/src/lib.rs @@ -33,7 +33,7 @@ pub trait Transaction { query: Query, ) -> Result<Box<dyn Iterator<Item = Result<(RowNum, Vec<u8>)>> + 'a>>; fn query_single(&mut self, query: Query) -> Result<Option<RowNum>>; - fn count(&mut self, query: Query) -> Result<u64>; + fn count(&mut self, filter: Filter) -> Result<u64>; } #[derive(Debug, Default, Clone, PartialEq)] diff --git a/server/src/routes/node.rs b/server/src/routes/node.rs index 506d771..240486e 100644 --- a/server/src/routes/node.rs +++ b/server/src/routes/node.rs @@ -12,7 +12,10 @@ use jellycommon::{ *, }; use jellydb::{Filter, MultiBehaviour, Query, Sort, SortOrder, Transaction, ValueSort}; -use jellyui::components::node_page::NodePage; +use jellyui::components::{ + node_list::{NodeFilterInfo, NodeListData}, + node_page::NodePage, +}; use rocket::{get, response::content::RawHtml}; use std::{borrow::Cow, collections::BTreeMap}; @@ -20,8 +23,10 @@ use std::{borrow::Cow, collections::BTreeMap}; pub fn r_node(ri: RequestInfo<'_>, slug: &str) -> MyResult<RawHtml<String>> { ri.require_user()?; + let filter = NodeFilter { kind: None }; + let mut nku = None; - let mut children = Vec::new(); + let mut children = None; let mut credits = Vec::new(); let mut credited = Vec::new(); ri.state.database.transaction(&mut |txn| { @@ -31,13 +36,13 @@ pub fn r_node(ri: RequestInfo<'_>, slug: &str) -> MyResult<RawHtml<String>> { })? { let n = txn.get(row)?.unwrap(); nku = Some(create_nku(txn, row)?); - children = c_children(txn, row, &n)?; + children = Some(c_children(txn, filter.clone(), row, &n)?); credits = c_credits(txn, &n)?; credited = c_credited(txn, row)?; } Ok(()) })?; - let Some(nku) = nku else { + let (Some(nku), Some(children)) = (nku, children) else { Err(anyhow!("no such node"))? }; @@ -50,7 +55,25 @@ pub fn r_node(ri: RequestInfo<'_>, slug: &str) -> MyResult<RawHtml<String>> { })) } -fn c_children(txn: &mut dyn Transaction, row: u64, node: &Object) -> Result<Vec<Nku<'static>>> { +const KINDS_TAB_ORDER: &[Tag] = &[ + KIND_COLLECTION, + KIND_MOVIE, + KIND_SHOW, + KIND_SERIES, + KIND_SEASON, + KIND_EPISODE, + KIND_CHANNEL, + KIND_VIDEO, + KIND_SHORTFORMVIDEO, + KIND_MUSIC, +]; + +fn c_children( + txn: &mut dyn Transaction, + mut filter: NodeFilter, + row: u64, + node: &Object, +) -> Result<NodeListData<'static>> { let kind = node.get(NO_KIND).unwrap_or(KIND_COLLECTION); let (order, path) = match kind { KIND_CHANNEL => (SortOrder::Descending, Path(vec![NO_RELEASEDATE.0])), @@ -58,6 +81,28 @@ fn c_children(txn: &mut dyn Transaction, row: u64, node: &Object) -> Result<Vec< _ => (SortOrder::Ascending, Path(vec![NO_TITLE.0])), }; + let mut filter_kinds = Vec::new(); + for &kind in KINDS_TAB_ORDER { + let count = txn.count(Filter::All(vec![ + Filter::Match(Path(vec![NO_VISIBILITY.0]), VISI_VISIBLE.into()), + Filter::Match(Path(vec![NO_PARENT.0]), row.into()), + Filter::Match(Path(vec![NO_KIND.0]), kind.into()), + ]))?; + if count > 0 { + filter_kinds.push((kind, count)); + } + } + if filter.kind.is_none() { + filter.kind = filter_kinds.first().map(|(t, _)| *t); + } + + let mut filters = vec![ + Filter::Match(Path(vec![NO_VISIBILITY.0]), VISI_VISIBLE.into()), + Filter::Match(Path(vec![NO_PARENT.0]), row.into()), + ]; + if let Some(kind) = filter.kind { + filters.push(Filter::Match(Path(vec![NO_KIND.0]), kind.into())) + } let children_rows = txn .query(Query { sort: Sort::Value(ValueSort { @@ -66,19 +111,22 @@ fn c_children(txn: &mut dyn Transaction, row: u64, node: &Object) -> Result<Vec< order, path, }), - filter: Filter::All(vec![ - Filter::Match(Path(vec![NO_VISIBILITY.0]), VISI_VISIBLE.into()), - Filter::Match(Path(vec![NO_PARENT.0]), row.into()), - ]), + filter: Filter::All(filters), ..Default::default() })? .collect::<Result<Vec<_>>>()?; - let mut list = Vec::new(); + let mut items = Vec::new(); for (row, _) in children_rows { - list.push(create_nku(txn, row)?); + items.push(create_nku(txn, row)?); } - Ok(list) + Ok(NodeListData { + filter_info: NodeFilterInfo { + cur: filter, + kinds: filter_kinds, + }, + items, + }) } fn c_credits(txn: &mut dyn Transaction, node: &Object) -> Result<Vec<(Tag, Vec<Nku<'static>>)>> { @@ -136,10 +184,7 @@ fn c_credited(txn: &mut dyn Transaction, row: u64) -> Result<Vec<Nku<'static>>> } pub fn create_nku(txn: &mut dyn Transaction, row: u64) -> Result<Nku<'static>> { - let child_count = txn.count(Query { - filter: Filter::Match(Path(vec![NO_PARENT.0]), row.into()), - ..Default::default() - })?; + let child_count = txn.count(Filter::Match(Path(vec![NO_PARENT.0]), row.into()))?; Ok(Nku { node: Cow::Owned(txn.get(row)?.unwrap()), role: None, diff --git a/ui/src/components/filter.rs b/ui/src/components/filter.rs deleted file mode 100644 index cd2b63c..0000000 --- a/ui/src/components/filter.rs +++ /dev/null @@ -1,23 +0,0 @@ -/* - This file is part of jellything (https://codeberg.org/metamuffin/jellything) - which is licensed under the GNU Affero General Public License (version 3); see /COPYING. - Copyright (C) 2026 metamuffin <metamuffin.org> -*/ - -use crate::RenderInfo; -use jellycommon::jellyobject::Tag; -use jellyui_locale::tr; - -pub struct FilterInfo { - kinds: Vec<(Tag, u64)>, -} - -markup::define! { - Filter<'a>(ri: &'a RenderInfo<'a>, info: &'a FilterInfo) { .filter { - ul.kinds { - @for (k, count) in &info.kinds { - li { a[href=format!("?fk={k}")] { @tr(ri.lang, &format!("tag.kind.{k}")) ": " @count } } - } - } - }} -} diff --git a/ui/src/components/mod.rs b/ui/src/components/mod.rs index 5c90a26..28d09f2 100644 --- a/ui/src/components/mod.rs +++ b/ui/src/components/mod.rs @@ -11,9 +11,9 @@ pub mod items; pub mod login; pub mod message; pub mod node_card; +pub mod node_list; pub mod node_page; pub mod props; +pub mod search; pub mod stats; pub mod user; -pub mod search; -pub mod filter; diff --git a/ui/src/components/node_list.rs b/ui/src/components/node_list.rs new file mode 100644 index 0000000..906deae --- /dev/null +++ b/ui/src/components/node_list.rs @@ -0,0 +1,47 @@ +/* + This file is part of jellything (https://codeberg.org/metamuffin/jellything) + which is licensed under the GNU Affero General Public License (version 3); see /COPYING. + Copyright (C) 2026 metamuffin <metamuffin.org> +*/ + +use crate::{ + RenderInfo, + components::node_card::{NodeCard, NodeCardWide}, +}; +use jellycommon::{Nku, NodeFilter, jellyobject::Tag, *}; +use jellyui_locale::tr; + +pub struct NodeFilterInfo { + pub cur: NodeFilter, + pub kinds: Vec<(Tag, u64)>, +} + +pub struct NodeListData<'a> { + pub filter_info: NodeFilterInfo, + pub items: Vec<Nku<'a>>, +} + +markup::define! { + NodeList<'a>(ri: &'a RenderInfo<'a>, kind: Tag, data: &'a NodeListData<'a>) { + @if !data.items.is_empty() { + @Filter { ri, info: &data.filter_info } + @if matches!(*kind, KIND_SHOW | KIND_SEASON) { + ul.nl.list { @for nku in &data.items { + li { @NodeCardWide { ri, nku } } + }} + } else { + ul.nl.grid { @for nku in &data.items { + li { @NodeCard { ri, nku } } + }} + } + } + } + + Filter<'a>(ri: &'a RenderInfo<'a>, info: &'a NodeFilterInfo) { .filter { + ul.kinds { + @for (k, count) in &info.kinds { + li { a[href=format!("?fk={k}")] { @tr(ri.lang, &format!("tag.kind.{k}")) ": " @count } } + } + } + }} +} diff --git a/ui/src/components/node_page.rs b/ui/src/components/node_page.rs index 29fb6b9..bcee525 100644 --- a/ui/src/components/node_page.rs +++ b/ui/src/components/node_page.rs @@ -7,7 +7,8 @@ use crate::{ RenderInfo, components::{ - node_card::{NodeCard, NodeCardWide}, + node_card::NodeCard, + node_list::{NodeList, NodeListData}, props::Props, }, format::format_duration, @@ -40,7 +41,7 @@ markup::define! { NodePage<'a>( ri: &'a RenderInfo<'a>, nku: Nku<'a>, - children: &'a [Nku<'a>], + children: &'a NodeListData<'a>, credits: &'a [(Tag, Vec<Nku<'a>>)], credited: &'a [Nku<'a>] ) { @@ -183,18 +184,7 @@ markup::define! { li { @NodeCard { ri, nku } } }} } - @if !children.is_empty() { - // @Filter { ri, info } - @if matches!(node.get(NO_KIND).unwrap_or(KIND_COLLECTION), KIND_SHOW | KIND_SEASON) { - ul.nl.list { @for nku in *children { - li { @NodeCardWide { ri, nku } } - }} - } else { - ul.nl.grid { @for nku in *children { - li { @NodeCard { ri, nku } } - }} - } - } + @NodeList { ri, data: children, kind: node.get(NO_KIND).unwrap_or(KIND_COLLECTION) } } Player<'a>(ri: &'a RenderInfo<'a>, nku: Nku<'a>) { |