diff options
| author | metamuffin <metamuffin@disroot.org> | 2026-02-19 12:44:54 +0100 |
|---|---|---|
| committer | metamuffin <metamuffin@disroot.org> | 2026-02-19 12:44:54 +0100 |
| commit | b732b3022e931cd49ebee64fa140aeec3ae55cbc (patch) | |
| tree | bc87d4ac8670ade2ee31fa7a470916cd8d5eaec1 | |
| parent | a197ab4dc250311255056d4b36a6da8653e1040c (diff) | |
| download | jellything-b732b3022e931cd49ebee64fa140aeec3ae55cbc.tar jellything-b732b3022e931cd49ebee64fa140aeec3ae55cbc.tar.bz2 jellything-b732b3022e931cd49ebee64fa140aeec3ae55cbc.tar.zst | |
remove old logic crate
| -rw-r--r-- | Cargo.lock | 17 | ||||
| -rw-r--r-- | Cargo.toml | 13 | ||||
| -rw-r--r-- | logic/Cargo.toml | 17 | ||||
| -rw-r--r-- | logic/src/assets.rs | 57 | ||||
| -rw-r--r-- | logic/src/filter_sort.rs | 95 | ||||
| -rw-r--r-- | logic/src/home.rs | 138 | ||||
| -rw-r--r-- | logic/src/items.rs | 36 | ||||
| -rw-r--r-- | logic/src/lib.rs | 59 | ||||
| -rw-r--r-- | logic/src/login.rs | 23 | ||||
| -rw-r--r-- | logic/src/node.rs | 163 |
10 files changed, 6 insertions, 612 deletions
@@ -1850,23 +1850,6 @@ dependencies = [ ] [[package]] -name = "jellylogic" -version = "0.1.0" -dependencies = [ - "anyhow", - "bincode", - "env_logger", - "jellycommon", - "jellydb", - "jellyimport", - "jellytranscoder", - "log", - "rand 0.9.2", - "serde", - "tokio", -] - -[[package]] name = "jellyobject" version = "0.1.0" dependencies = [ @@ -1,24 +1,23 @@ [workspace] members = [ "cache", + "cache/tools", "common", + "common/object", "database", "ebml_derive", "import", "import/fallback_generator", - "logic", + "kv", + "remuxer", "server", - "tool", - "transcoder", "stream", "stream/types", + "tool", + "transcoder", "ui", "ui/client-scripts", "ui/client-style", - "remuxer", - "common/object", - "kv", - "cache/tools", ] resolver = "3" default-members = ["server"] diff --git a/logic/Cargo.toml b/logic/Cargo.toml deleted file mode 100644 index 883fe5e..0000000 --- a/logic/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "jellylogic" -version = "0.1.0" -edition = "2024" - -[dependencies] -jellyimport = { path = "../import" } -jellycommon = { path = "../common" } -jellydb = { path = "../database" } -jellytranscoder = { path = "../transcoder" } -log = "0.4.28" -anyhow = "1.0.100" -serde = { version = "1.0.228", features = ["derive", "rc"] } -bincode = { version = "2.0.1", features = ["serde", "derive"] } -rand = "0.9.2" -env_logger = "0.11.8" -tokio = { workspace = true } diff --git a/logic/src/assets.rs b/logic/src/assets.rs deleted file mode 100644 index 462c8bf..0000000 --- a/logic/src/assets.rs +++ /dev/null @@ -1,57 +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::{DATABASE, session::Session}; -use anyhow::{Result, anyhow}; - -pub async fn get_node_thumbnail(_session: &Session, id: NodeID, t: f64) -> Result<Asset> { - let node = DATABASE - .get_node(id)? - .ok_or(anyhow!("node does not exist"))?; - - let media = node.media.as_ref().ok_or(anyhow!("no media"))?; - let (thumb_track_index, _thumb_track) = media - .tracks - .iter() - .enumerate() - .find(|(_i, t)| matches!(t.kind, SourceTrackKind::Video { .. })) - .ok_or(anyhow!("no video track to create a thumbnail of"))?; - let source = media - .tracks - .get(thumb_track_index) - .ok_or(anyhow!("no source"))?; - let thumb_track_source = source.source.clone(); - - if t < 0. || t > media.duration { - Err(anyhow!("thumbnail instant not within media duration"))? - } - - let step = 8.; - let t = (t / step).floor() * step; - - Ok(match thumb_track_source { - TrackSource::Local(path, _) => { - Asset(jellytranscoder::thumbnail::create_thumbnail(&path, t)?) - } - TrackSource::Remote(_) => { - // // TODO in the new system this is preferrably a property of node ext for regular fed - // let session = fed - // .get_session( - // thumb_track - // .federated - // .last() - // .ok_or(anyhow!("federation broken"))?, - // ) - // .await?; - - // async_cache_file("fed-thumb", (id.0, t as i64), |out| { - // session.node_thumbnail(out, id.0.into(), 2048, t) - // }) - // .await? - todo!() - } - }) -} diff --git a/logic/src/filter_sort.rs b/logic/src/filter_sort.rs deleted file mode 100644 index afa36f8..0000000 --- a/logic/src/filter_sort.rs +++ /dev/null @@ -1,95 +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 std::sync::Arc; - -pub fn filter_and_sort_nodes( - f: &NodeFilterSort, - default_sort: (SortProperty, SortOrder), - nodes: &mut Vec<(Arc<Node>, NodeUserData)>, -) { - let sort_prop = f.sort_by.unwrap_or(default_sort.0); - nodes.retain(|(node, _udata)| { - let mut o = true; - if let Some(prop) = &f.filter_kind { - o = false; - for p in prop { - o |= match p { - // FilterProperty::FederationLocal => node.federated.is_none(), - // FilterProperty::FederationRemote => node.federated.is_some(), - FilterProperty::KindMovie => node.kind == NodeKind::Movie, - FilterProperty::KindVideo => node.kind == NodeKind::Video, - FilterProperty::KindShortFormVideo => node.kind == NodeKind::ShortFormVideo, - FilterProperty::KindMusic => node.kind == NodeKind::Music, - FilterProperty::KindCollection => node.kind == NodeKind::Collection, - FilterProperty::KindChannel => node.kind == NodeKind::Channel, - FilterProperty::KindShow => node.kind == NodeKind::Show, - FilterProperty::KindSeries => node.kind == NodeKind::Series, - FilterProperty::KindSeason => node.kind == NodeKind::Season, - FilterProperty::KindEpisode => node.kind == NodeKind::Episode, - // FilterProperty::Watched => udata.watched == WatchedState::Watched, - // FilterProperty::Unwatched => udata.watched == WatchedState::None, - // FilterProperty::WatchProgress => { - // matches!(udata.watched, WatchedState::Progress(_)) - // } - _ => false, // TODO - } - } - } - match sort_prop { - SortProperty::ReleaseDate => o &= node.release_date.is_some(), - SortProperty::Duration => o &= node.media.is_some(), - _ => (), - } - o - }); - match sort_prop { - SortProperty::Duration => { - nodes.sort_by_key(|(n, _)| (n.media.as_ref().unwrap().duration * 1000.) as i64) - } - SortProperty::ReleaseDate => { - nodes.sort_by_key(|(n, _)| n.release_date.expect("asserted above")) - } - SortProperty::Title => nodes.sort_by(|(a, _), (b, _)| a.title.cmp(&b.title)), - SortProperty::Index => nodes.sort_by(|(a, _), (b, _)| { - a.index - .unwrap_or(usize::MAX) - .cmp(&b.index.unwrap_or(usize::MAX)) - }), - SortProperty::RatingRottenTomatoes => nodes.sort_by_cached_key(|(n, _)| { - SortAnyway(*n.ratings.get(&RatingType::RottenTomatoes).unwrap_or(&0.)) - }), - SortProperty::RatingMetacritic => nodes.sort_by_cached_key(|(n, _)| { - SortAnyway(*n.ratings.get(&RatingType::Metacritic).unwrap_or(&0.)) - }), - SortProperty::RatingImdb => nodes.sort_by_cached_key(|(n, _)| { - SortAnyway(*n.ratings.get(&RatingType::Imdb).unwrap_or(&0.)) - }), - SortProperty::RatingTmdb => nodes.sort_by_cached_key(|(n, _)| { - SortAnyway(*n.ratings.get(&RatingType::Tmdb).unwrap_or(&0.)) - }), - SortProperty::RatingYoutubeViews => nodes.sort_by_cached_key(|(n, _)| { - SortAnyway(*n.ratings.get(&RatingType::YoutubeViews).unwrap_or(&0.)) - }), - SortProperty::RatingYoutubeLikes => nodes.sort_by_cached_key(|(n, _)| { - SortAnyway(*n.ratings.get(&RatingType::YoutubeLikes).unwrap_or(&0.)) - }), - SortProperty::RatingYoutubeFollowers => nodes.sort_by_cached_key(|(n, _)| { - SortAnyway(*n.ratings.get(&RatingType::YoutubeFollowers).unwrap_or(&0.)) - }), - SortProperty::RatingLikesDivViews => nodes.sort_by_cached_key(|(n, _)| { - SortAnyway( - *n.ratings.get(&RatingType::YoutubeLikes).unwrap_or(&0.) - / (1. + *n.ratings.get(&RatingType::YoutubeViews).unwrap_or(&0.)), - ) - }), - SortProperty::RatingUser => nodes.sort_by_cached_key(|(_, u)| u.rating), - } - - match f.sort_order.unwrap_or(default_sort.1) { - SortOrder::Ascending => (), - SortOrder::Descending => nodes.reverse(), - } -} diff --git a/logic/src/home.rs b/logic/src/home.rs deleted file mode 100644 index 73fc182..0000000 --- a/logic/src/home.rs +++ /dev/null @@ -1,138 +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::{DATABASE, node::DatabaseNodeUserDataExt, session::Session}; -use anyhow::{Context, Result}; - -pub fn home(session: &Session) -> Result<ApiHomeResponse> { - let mut items = DATABASE.list_nodes_with_udata(&session.user.name)?; - - let mut toplevel = DATABASE - .get_node_children(NodeID::from_slug("library")) - .context("root node missing")? - .into_iter() - .map(|n| DATABASE.get_node_with_userdata(n, session)) - .collect::<anyhow::Result<Vec<_>>>()?; - toplevel.sort_by_key(|(n, _)| n.index.unwrap_or(usize::MAX)); - - let mut categories = Vec::<(String, Vec<_>)>::new(); - - categories.push(( - "home.bin.continue_watching".to_string(), - items - .iter() - .filter(|(_, u)| matches!(u.watched, WatchedState::Progress(_))) - .cloned() - .collect(), - )); - categories.push(( - "home.bin.watchlist".to_string(), - items - .iter() - .filter(|(_, u)| matches!(u.watched, WatchedState::Pending)) - .cloned() - .collect(), - )); - - items.retain(|(n, _)| matches!(n.visibility, Visibility::Visible)); - - items.sort_by_key(|(n, _)| n.release_date.map(|d| -d).unwrap_or(i64::MAX)); - - categories.push(( - "home.bin.latest_video".to_string(), - items - .iter() - .filter(|(n, _)| matches!(n.kind, NodeKind::Video)) - .take(16) - .cloned() - .collect(), - )); - categories.push(( - "home.bin.latest_music".to_string(), - items - .iter() - .filter(|(n, _)| matches!(n.kind, NodeKind::Music)) - .take(16) - .cloned() - .collect(), - )); - categories.push(( - "home.bin.latest_short_form".to_string(), - items - .iter() - .filter(|(n, _)| matches!(n.kind, NodeKind::ShortFormVideo)) - .take(16) - .cloned() - .collect(), - )); - - items.sort_by_key(|(n, _)| { - n.ratings - .get(&RatingType::Trakt) - .map(|x| (*x * -1000.) as i32) - .unwrap_or(0) - }); - - categories.push(( - "home.bin.max_rating".to_string(), - items - .iter() - .filter(|(n, _)| n.ratings.contains_key(&RatingType::Trakt)) - .filter(|(n, _)| matches!(n.kind, NodeKind::Movie | NodeKind::Show)) - .take(16) - .cloned() - .collect(), - )); - - items.retain(|(n, _)| { - matches!( - n.kind, - NodeKind::Video | NodeKind::Movie | NodeKind::Episode | NodeKind::Music - ) - }); - - categories.push(( - "home.bin.daily_random".to_string(), - (0..16) - .flat_map(|i| Some(items[cheap_daily_random(i).checked_rem(items.len())?].clone())) - .collect(), - )); - - { - let mut items = items.clone(); - items.retain(|(_, u)| matches!(u.watched, WatchedState::Watched)); - categories.push(( - "home.bin.watch_again".to_string(), - (0..16) - .flat_map(|i| Some(items[cheap_daily_random(i).checked_rem(items.len())?].clone())) - .collect(), - )); - } - - items.retain(|(n, _)| matches!(n.kind, NodeKind::Music)); - categories.push(( - "home.bin.daily_random_music".to_string(), - (0..16) - .flat_map(|i| Some(items[cheap_daily_random(i).checked_rem(items.len())?].clone())) - .collect(), - )); - - Ok(ApiHomeResponse { - toplevel, - categories, - }) -} - -fn cheap_daily_random(i: usize) -> usize { - xorshift(xorshift(Utc::now().num_days_from_ce() as u64) + i as u64) as usize -} - -fn xorshift(mut x: u64) -> u64 { - x ^= x << 13; - x ^= x >> 7; - x ^= x << 17; - x -} diff --git a/logic/src/items.rs b/logic/src/items.rs deleted file mode 100644 index c618b9b..0000000 --- a/logic/src/items.rs +++ /dev/null @@ -1,36 +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::{DATABASE, filter_sort::filter_and_sort_nodes, session::Session}; -use anyhow::Result; - -pub fn all_items( - session: &Session, - page: Option<usize>, - filter: NodeFilterSort, -) -> Result<ApiItemsResponse> { - let mut items = DATABASE.list_nodes_with_udata(session.user.name.as_str())?; - - items.retain(|(n, _)| matches!(n.visibility, Visibility::Visible)); - - filter_and_sort_nodes( - &filter, - (SortProperty::Title, SortOrder::Ascending), - &mut items, - ); - - let page_size = 100; - let page = page.unwrap_or(0); - let offset = page * page_size; - let from = offset.min(items.len()); - let to = (offset + page_size).min(items.len()); - let max_page = items.len().div_ceil(page_size); - Ok(ApiItemsResponse { - count: items.len(), - pages: max_page, - items: items[from..to].to_vec(), - }) -} diff --git a/logic/src/lib.rs b/logic/src/lib.rs deleted file mode 100644 index 7a1bf46..0000000 --- a/logic/src/lib.rs +++ /dev/null @@ -1,59 +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> -*/ -#![feature(duration_constructors)] - -pub mod assets; -pub mod filter_sort; -pub mod home; -pub mod items; -pub mod login; -pub mod node; -pub mod permission; -pub mod session; -pub mod stats; - -use anyhow::Context; -use anyhow::Result; -use serde::{Deserialize, Serialize}; -use std::path::PathBuf; -use std::sync::LazyLock; -use std::sync::Mutex; - -#[rustfmt::skip] -#[derive(Debug, Deserialize, Serialize, Default)] -pub struct Config { - login_expire: i64, - session_key: Option<String>, - admin_username:Option<String>, - admin_password:Option<String>, - database_path: PathBuf, -} - -pub static CONF_PRELOAD: Mutex<Option<Config>> = Mutex::new(None); -static CONF: LazyLock<Config> = LazyLock::new(|| { - CONF_PRELOAD - .lock() - .unwrap() - .take() - .expect("logic config not preloaded. logic error") -}); - -static DATABASE_PRELOAD: Mutex<Option<Database>> = Mutex::new(None); -static DATABASE: LazyLock<Database> = LazyLock::new(|| { - DATABASE_PRELOAD - .lock() - .unwrap() - .take() - .expect("database not preloaded. logic error") -}); - -pub fn init_database() -> Result<()> { - let database = Database::open(&CONF.database_path) - .context("opening database") - .unwrap(); - *DATABASE_PRELOAD.lock().unwrap() = Some(database); - Ok(()) -} diff --git a/logic/src/login.rs b/logic/src/login.rs deleted file mode 100644 index 0d616ff..0000000 --- a/logic/src/login.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::{CONF, DATABASE, session::create}; -use anyhow::{Result, anyhow}; -use argon2::{Argon2, PasswordHasher, password_hash::Salt}; -use log::info; -use std::{collections::HashSet, time::Duration}; - -pub fn create_admin_account() -> Result<()> { - if let Some(username) = &CONF.admin_username - && let Some(password) = &CONF.admin_password - { - DATABASE - .create_admin_user(username, hash_password(username, password)) - .unwrap(); - } else { - info!("admin account disabled") - } - Ok(()) -} diff --git a/logic/src/node.rs b/logic/src/node.rs deleted file mode 100644 index 723b2f7..0000000 --- a/logic/src/node.rs +++ /dev/null @@ -1,163 +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::{DATABASE, filter_sort::filter_and_sort_nodes, session::Session}; -use anyhow::{Result, anyhow}; -use std::{cmp::Reverse, collections::BTreeMap, sync::Arc}; - -pub fn get_node( - session: &Session, - id: NodeID, - children: bool, - parents: bool, - filter: NodeFilterSort, -) -> Result<ApiNodeResponse> { - let (node, udata) = DATABASE.get_node_with_userdata(id, session)?; - - let mut children = if children { - DATABASE - .get_node_children(id)? - .into_iter() - .map(|c| DATABASE.get_node_with_userdata(c, session)) - .collect::<anyhow::Result<Vec<_>>>()? - } else { - Vec::new() - }; - - let mut parents = if parents { - node.parents - .iter() - .map(|pid| DATABASE.get_node_with_userdata(*pid, session)) - .collect::<anyhow::Result<Vec<_>>>()? - } else { - Vec::new() - }; - - let mut similar = get_similar_media(session, &node)?; - - 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(session: &Session, node: &Node) -> 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 = DATABASE.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, _)| DATABASE.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(), - )) - } -} - -pub fn get_nodes_modified_since(_session: &Session, since: u64) -> Result<Vec<NodeID>> { - let mut nodes = DATABASE.get_nodes_modified_since(since)?; - nodes.retain(|id| { - DATABASE.get_node(*id).is_ok_and(|n| { - n.as_ref() - .is_some_and(|n| n.visibility >= Visibility::Reduced) - }) - }); - Ok(nodes) -} - -pub fn get_node_by_eid( - _session: &Session, - ty: IdentifierType, - value: &str, -) -> Result<Option<NodeID>> { - DATABASE.get_node_by_identifier(ty, value) -} -pub fn node_id_to_slug(_session: &Session, id: NodeID) -> Result<String> { - Ok(DATABASE - .get_node(id)? - .ok_or(anyhow!("node does not exist"))? - .slug - .to_owned()) -} - -pub fn update_node_userdata_watched( - session: &Session, - node: NodeID, - state: WatchedState, -) -> Result<()> { - // TODO perm - DATABASE.update_node_udata(node, &session.user.name, |udata| { - udata.watched = state; - Ok(()) - }) -} -pub fn update_node_userdata_watched_progress( - session: &Session, - node: NodeID, - time: f64, -) -> Result<()> { - // TODO perm - DATABASE.update_node_udata(node, &session.user.name, |udata| { - udata.watched = match udata.watched { - WatchedState::None | WatchedState::Pending | WatchedState::Progress(_) => { - WatchedState::Progress(time) - } - WatchedState::Watched => WatchedState::Watched, - }; - Ok(()) - }) -} -pub fn update_node_userdata_rating(session: &Session, node: NodeID, rating: i32) -> Result<()> { - // TODO perm - DATABASE.update_node_udata(node, &session.user.name, |udata| { - udata.rating = rating; - Ok(()) - }) -} |