/* 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 */ use jellycommon::{ api::{FilterProperty, NodeFilterSort, SortOrder, SortProperty}, helpers::SortAnyway, user::NodeUserData, Node, NodeKind, Rating, }; use rocket::{ http::uri::fmt::{Query, UriDisplay}, FromForm, FromFormField, UriDisplayQuery, }; use std::sync::Arc; pub fn filter_and_sort_nodes( f: &NodeFilterSort, default_sort: (SortProperty, SortOrder), nodes: &mut Vec<(Arc, 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(&Rating::RottenTomatoes).unwrap_or(&0.)) }), SortProperty::RatingMetacritic => nodes.sort_by_cached_key(|(n, _)| { SortAnyway(*n.ratings.get(&Rating::Metacritic).unwrap_or(&0.)) }), SortProperty::RatingImdb => nodes .sort_by_cached_key(|(n, _)| SortAnyway(*n.ratings.get(&Rating::Imdb).unwrap_or(&0.))), SortProperty::RatingTmdb => nodes .sort_by_cached_key(|(n, _)| SortAnyway(*n.ratings.get(&Rating::Tmdb).unwrap_or(&0.))), SortProperty::RatingYoutubeViews => nodes.sort_by_cached_key(|(n, _)| { SortAnyway(*n.ratings.get(&Rating::YoutubeViews).unwrap_or(&0.)) }), SortProperty::RatingYoutubeLikes => nodes.sort_by_cached_key(|(n, _)| { SortAnyway(*n.ratings.get(&Rating::YoutubeLikes).unwrap_or(&0.)) }), SortProperty::RatingYoutubeFollowers => nodes.sort_by_cached_key(|(n, _)| { SortAnyway(*n.ratings.get(&Rating::YoutubeFollowers).unwrap_or(&0.)) }), SortProperty::RatingLikesDivViews => nodes.sort_by_cached_key(|(n, _)| { SortAnyway( *n.ratings.get(&Rating::YoutubeLikes).unwrap_or(&0.) / (1. + *n.ratings.get(&Rating::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(), } }