aboutsummaryrefslogtreecommitdiff
path: root/server/src/routes/ui/sort.rs
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-04-27 19:25:11 +0200
committermetamuffin <metamuffin@disroot.org>2025-04-27 19:25:11 +0200
commit11a585b3dbe620dcc8772e713b22f1d9ba80d598 (patch)
tree44f8d97137412aefc79a2425a489c34fa3e5f6c5 /server/src/routes/ui/sort.rs
parentd871aa7c5bba49ff55170b5d2dac9cd440ae7170 (diff)
downloadjellything-11a585b3dbe620dcc8772e713b22f1d9ba80d598.tar
jellything-11a585b3dbe620dcc8772e713b22f1d9ba80d598.tar.bz2
jellything-11a585b3dbe620dcc8772e713b22f1d9ba80d598.tar.zst
move files around
Diffstat (limited to 'server/src/routes/ui/sort.rs')
-rw-r--r--server/src/routes/ui/sort.rs290
1 files changed, 0 insertions, 290 deletions
diff --git a/server/src/routes/ui/sort.rs b/server/src/routes/ui/sort.rs
deleted file mode 100644
index 6d38e11..0000000
--- a/server/src/routes/ui/sort.rs
+++ /dev/null
@@ -1,290 +0,0 @@
-use jellybase::locale::Language;
-use jellycommon::{helpers::SortAnyway, user::NodeUserData, Node, NodeKind, Rating};
-use markup::RenderAttributeValue;
-use rocket::{
- http::uri::fmt::{Query, UriDisplay},
- FromForm, FromFormField, UriDisplayQuery,
-};
-use std::sync::Arc;
-
-use crate::routes::ui::layout::trs;
-
-#[derive(FromForm, UriDisplayQuery, Default, Clone)]
-pub struct NodeFilterSort {
- pub sort_by: Option<SortProperty>,
- pub filter_kind: Option<Vec<FilterProperty>>,
- pub sort_order: Option<SortOrder>,
-}
-
-macro_rules! form_enum {
- (enum $i:ident { $($vi:ident = $vk:literal),*, }) => {
- #[derive(Debug, FromFormField, UriDisplayQuery, Clone, Copy, PartialEq, Eq)]
- pub enum $i { $(#[field(value = $vk)] $vi),* }
- impl $i { #[allow(unused)] const ALL: &'static [$i] = &[$($i::$vi),*]; }
- };
-}
-
-form_enum!(
- enum FilterProperty {
- FederationLocal = "fed_local",
- FederationRemote = "fed_remote",
- Watched = "watched",
- Unwatched = "unwatched",
- WatchProgress = "watch_progress",
- KindMovie = "kind_movie",
- KindVideo = "kind_video",
- KindShortFormVideo = "kind_short_form_video",
- KindMusic = "kind_music",
- KindCollection = "kind_collection",
- KindChannel = "kind_channel",
- KindShow = "kind_show",
- KindSeries = "kind_series",
- KindSeason = "kind_season",
- KindEpisode = "kind_episode",
- }
-);
-
-form_enum!(
- enum SortProperty {
- ReleaseDate = "release_date",
- Title = "title",
- Index = "index",
- Duration = "duration",
- RatingRottenTomatoes = "rating_rt",
- RatingMetacritic = "rating_mc",
- RatingImdb = "rating_imdb",
- RatingTmdb = "rating_tmdb",
- RatingYoutubeViews = "rating_yt_views",
- RatingYoutubeLikes = "rating_yt_likes",
- RatingYoutubeFollowers = "rating_yt_followers",
- RatingUser = "rating_user",
- RatingLikesDivViews = "rating_loved",
- }
-);
-
-impl SortProperty {
- const CATS: &'static [(&'static str, &'static [(SortProperty, &'static str)])] = {
- use SortProperty::*;
- &[
- (
- "filter_sort.sort.general",
- &[(Title, "node.title"), (ReleaseDate, "node.release_date")],
- ),
- ("filter_sort.sort.media", &[(Duration, "media.runtime")]),
- (
- "filter_sort.sort.rating",
- &[
- (RatingImdb, "rating.imdb"),
- (RatingTmdb, "rating.tmdb"),
- (RatingMetacritic, "rating.metacritic"),
- (RatingRottenTomatoes, "rating.rotten_tomatoes"),
- (RatingYoutubeFollowers, "rating.youtube_followers"),
- (RatingYoutubeLikes, "rating.youtube_likes"),
- (RatingYoutubeViews, "rating.youtube_views"),
- (RatingUser, "filter_sort.sort.rating.user"),
- (
- RatingLikesDivViews,
- "filter_sort.sort.rating.likes_div_views",
- ),
- ],
- ),
- ]
- };
-}
-impl FilterProperty {
- const CATS: &'static [(&'static str, &'static [(FilterProperty, &'static str)])] = {
- use FilterProperty::*;
- &[
- (
- "filter_sort.filter.kind",
- &[
- (KindMovie, "kind.movie"),
- (KindVideo, "kind.video"),
- (KindShortFormVideo, "kind.short_form_video"),
- (KindMusic, "kind.music"),
- (KindCollection, "kind.collection"),
- (KindChannel, "kind.channel"),
- (KindShow, "kind.show"),
- (KindSeries, "kind.series"),
- (KindSeason, "kind.season"),
- (KindEpisode, "kind.episode"),
- ],
- ),
- (
- "filter_sort.filter.federation",
- &[(FederationLocal, "federation.local"), (FederationRemote, "federation.remote")],
- ),
- (
- "filter_sort.filter.watched",
- &[
- (Watched, "watched.watched"),
- (Unwatched, "watched.none"),
- (WatchProgress, "watched.progress"),
- ],
- ),
- ]
- };
-}
-
-impl NodeFilterSort {
- pub fn is_open(&self) -> bool {
- self.filter_kind.is_some() || self.sort_by.is_some()
- }
-}
-
-#[rustfmt::skip]
-#[derive(FromFormField, UriDisplayQuery, Clone, Copy, PartialEq, Eq)]
-pub enum SortOrder {
- #[field(value = "ascending")] Ascending,
- #[field(value = "descending")] Descending,
-}
-
-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(&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(),
- }
-}
-
-markup::define! {
- NodeFilterSortForm<'a>(f: &'a NodeFilterSort, lang: &'a Language) {
- details.filtersort[open=f.is_open()] {
- summary { "Filter and Sort" }
- form[method="GET", action=""] {
- fieldset.filter {
- legend { "Filter" }
- .categories {
- @for (cname, cat) in FilterProperty::CATS {
- .category {
- h3 { @trs(lang, cname) }
- @for (value, label) in *cat {
- label { input[type="checkbox", name="filter_kind", value=value, checked=f.filter_kind.as_ref().map(|k|k.contains(value)).unwrap_or(true)]; @trs(lang, label) } br;
- }
- }
- }
- }
- }
- fieldset.sortby {
- legend { "Sort" }
- .categories {
- @for (cname, cat) in SortProperty::CATS {
- .category {
- h3 { @trs(lang, cname) }
- @for (value, label) in *cat {
- label { input[type="radio", name="sort_by", value=value, checked=Some(value)==f.sort_by.as_ref()]; @trs(lang, label) } br;
- }
- }
- }
- }
- }
- fieldset.sortorder {
- legend { "Sort Order" }
- @use SortOrder::*;
- @for (value, label) in [(Ascending, "filter_sort.order.asc"), (Descending, "filter_sort.order.desc")] {
- label { input[type="radio", name="sort_order", value=value, checked=Some(value)==f.sort_order]; @trs(lang, label) } br;
- }
- }
- input[type="submit", value="Apply"]; a[href="?"] { "Clear" }
- }
- }
- }
-}
-
-impl markup::Render for SortProperty {
- fn render(&self, writer: &mut impl std::fmt::Write) -> std::fmt::Result {
- writer.write_fmt(format_args!("{}", self as &dyn UriDisplay<Query>))
- }
-}
-impl markup::Render for SortOrder {
- fn render(&self, writer: &mut impl std::fmt::Write) -> std::fmt::Result {
- writer.write_fmt(format_args!("{}", self as &dyn UriDisplay<Query>))
- }
-}
-impl markup::Render for FilterProperty {
- fn render(&self, writer: &mut impl std::fmt::Write) -> std::fmt::Result {
- writer.write_fmt(format_args!("{}", self as &dyn UriDisplay<Query>))
- }
-}
-impl RenderAttributeValue for SortOrder {}
-impl RenderAttributeValue for FilterProperty {}
-impl RenderAttributeValue for SortProperty {}