aboutsummaryrefslogtreecommitdiff
path: root/logic/src/node.rs
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-04-28 18:27:03 +0200
committermetamuffin <metamuffin@disroot.org>2025-04-28 18:27:03 +0200
commit51761cbdefa39107b9e1f931f1aa8df6aebb2a94 (patch)
tree957ca180786ece777e6e1153ada91da741d845ec /logic/src/node.rs
parent80d28b764c95891551e28c395783f5ff9d065743 (diff)
downloadjellything-51761cbdefa39107b9e1f931f1aa8df6aebb2a94.tar
jellything-51761cbdefa39107b9e1f931f1aa8df6aebb2a94.tar.bz2
jellything-51761cbdefa39107b9e1f931f1aa8df6aebb2a94.tar.zst
many much more generic refactor
Diffstat (limited to 'logic/src/node.rs')
-rw-r--r--logic/src/node.rs112
1 files changed, 112 insertions, 0 deletions
diff --git a/logic/src/node.rs b/logic/src/node.rs
new file mode 100644
index 0000000..8a53bec
--- /dev/null
+++ b/logic/src/node.rs
@@ -0,0 +1,112 @@
+/*
+ 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) 2025 metamuffin <metamuffin.org>
+*/
+use crate::{filter_sort::filter_and_sort_nodes, session::Session};
+use anyhow::{Result, anyhow};
+use jellybase::database::Database;
+use jellycommon::{
+ Node, NodeID, NodeKind, Visibility,
+ api::{ApiNodeResponse, NodeFilterSort, SortOrder, SortProperty},
+ user::NodeUserData,
+};
+use std::{cmp::Reverse, collections::BTreeMap, sync::Arc};
+
+pub fn get_node(
+ db: &Database,
+ id: NodeID,
+ session: &Session,
+ children: bool,
+ parents: bool,
+ filter: NodeFilterSort,
+) -> Result<ApiNodeResponse> {
+ let (node, udata) = db.get_node_with_userdata(id, &session)?;
+
+ let mut children = if children {
+ db.get_node_children(id)?
+ .into_iter()
+ .map(|c| db.get_node_with_userdata(c, &session))
+ .collect::<anyhow::Result<Vec<_>>>()?
+ } else {
+ Vec::new()
+ };
+
+ let mut parents = if parents {
+ node.parents
+ .iter()
+ .map(|pid| db.get_node_with_userdata(*pid, &session))
+ .collect::<anyhow::Result<Vec<_>>>()?
+ } else {
+ Vec::new()
+ };
+
+ let mut similar = get_similar_media(&node, db, &session)?;
+
+ similar.retain(|(n, _)| n.visibility >= Visibility::Reduced);
+ children.retain(|(n, _)| n.visibility >= Visibility::Reduced);
+ parents.retain(|(n, _)| n.visibility >= Visibility::Reduced);
+
+ filter_and_sort_nodes(
+ &filter,
+ match node.kind {
+ NodeKind::Channel => (SortProperty::ReleaseDate, SortOrder::Descending),
+ NodeKind::Season | NodeKind::Show => (SortProperty::Index, SortOrder::Ascending),
+ _ => (SortProperty::Title, SortOrder::Ascending),
+ },
+ &mut children,
+ );
+
+ Ok(ApiNodeResponse {
+ children,
+ parents,
+ node,
+ userdata: udata,
+ })
+}
+
+pub fn get_similar_media(
+ node: &Node,
+ db: &Database,
+ session: &Session,
+) -> Result<Vec<(Arc<Node>, NodeUserData)>> {
+ let this_id = NodeID::from_slug(&node.slug);
+ let mut ranking = BTreeMap::<NodeID, usize>::new();
+ for tag in &node.tags {
+ let nodes = db.get_tag_nodes(tag)?;
+ let weight = 1_000_000 / nodes.len();
+ for n in nodes {
+ if n != this_id {
+ *ranking.entry(n).or_default() += weight;
+ }
+ }
+ }
+ let mut ranking = ranking.into_iter().collect::<Vec<_>>();
+ ranking.sort_by_key(|(_, k)| Reverse(*k));
+ ranking
+ .into_iter()
+ .take(32)
+ .map(|(pid, _)| db.get_node_with_userdata(pid, session))
+ .collect::<anyhow::Result<Vec<_>>>()
+}
+
+pub trait DatabaseNodeUserDataExt {
+ fn get_node_with_userdata(
+ &self,
+ id: NodeID,
+ session: &Session,
+ ) -> Result<(Arc<Node>, NodeUserData)>;
+}
+impl DatabaseNodeUserDataExt for Database {
+ fn get_node_with_userdata(
+ &self,
+ id: NodeID,
+ session: &Session,
+ ) -> Result<(Arc<Node>, NodeUserData)> {
+ Ok((
+ self.get_node(id)?.ok_or(anyhow!("node does not exist"))?,
+ self.get_node_udata(id, &session.user.name)?
+ .unwrap_or_default(),
+ ))
+ }
+}