diff options
-rw-r--r-- | common/src/helpers.rs | 20 | ||||
-rw-r--r-- | common/src/lib.rs | 20 | ||||
-rw-r--r-- | import/src/main.rs | 7 | ||||
-rw-r--r-- | server/src/routes/ui/node.rs | 19 | ||||
-rw-r--r-- | server/src/routes/ui/sort.rs | 51 |
5 files changed, 90 insertions, 27 deletions
diff --git a/common/src/helpers.rs b/common/src/helpers.rs new file mode 100644 index 0000000..5150667 --- /dev/null +++ b/common/src/helpers.rs @@ -0,0 +1,20 @@ +use std::ops::Deref; + +#[derive(PartialEq, PartialOrd)] +pub struct SortAnyway<T>(pub T); + +impl<T: PartialEq> Eq for SortAnyway<T> { + fn assert_receiver_is_total_eq(&self) {} +} +impl<T: PartialOrd> Ord for SortAnyway<T> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.partial_cmp(&other).unwrap() + } +} + +impl<T> Deref for SortAnyway<T> { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/common/src/lib.rs b/common/src/lib.rs index 9d5a31e..b02f58c 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -4,12 +4,14 @@ Copyright (C) 2023 metamuffin <metamuffin.org> */ pub mod config; +pub mod helpers; pub mod r#impl; use bincode::{Decode, Encode}; +#[cfg(feature = "rocket")] use rocket::{FromFormField, UriDisplayQuery}; use serde::{Deserialize, Serialize}; -use std::path::PathBuf; +use std::{collections::BTreeMap, path::PathBuf}; #[derive(Debug, Clone, Deserialize, Serialize)] pub struct Node { @@ -38,7 +40,7 @@ pub struct NodePublic { #[serde(default)] pub description: Option<String>, #[serde(default)] pub index: Option<usize>, #[serde(default)] pub media: Option<MediaInfo>, - #[serde(default)] pub ratings: Vec<Rating>, + #[serde(default)] pub ratings: BTreeMap<Rating, f64>, #[serde(default)] pub federated: Option<String>, } @@ -107,15 +109,15 @@ pub struct SourceTrack { pub default_duration: Option<u64>, } -#[derive(Debug, Clone, Deserialize, Serialize)] +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord)] #[serde(rename_all = "snake_case")] pub enum Rating { - RottenTomatoes(u8), - Metacritic(u8), - Imdb(f32), - YoutubeViews(usize), - YoutubeLikes(usize), - YoutubeFollowers(usize), + RottenTomatoes, + Metacritic, + Imdb, + YoutubeViews, + YoutubeLikes, + YoutubeFollowers, } #[derive(Debug, Clone, Deserialize, Serialize)] diff --git a/import/src/main.rs b/import/src/main.rs index 26899bb..5d5e715 100644 --- a/import/src/main.rs +++ b/import/src/main.rs @@ -21,6 +21,7 @@ use jellyremuxer::import::{import_metadata, seek_index}; use log::{info, warn}; use rand::random; use std::{ + collections::BTreeMap, fs::{remove_file, File}, io::{stdin, Write}, path::PathBuf, @@ -306,17 +307,17 @@ fn main() -> anyhow::Result<()> { .flatten(); } - let mut ratings = Vec::new(); + let mut ratings = BTreeMap::new(); ratings.extend( infojson .as_ref() - .map(|i| Rating::YoutubeViews(i.view_count)), + .map(|i| (Rating::YoutubeViews, i.view_count as f64)), ); ratings.extend( infojson .as_ref() - .map(|i| i.like_count.map(Rating::YoutubeLikes)) + .map(|i| i.like_count.map(|l| (Rating::YoutubeLikes, l as f64))) .flatten(), ); diff --git a/server/src/routes/ui/node.rs b/server/src/routes/ui/node.rs index 13afbbe..e14a2af 100644 --- a/server/src/routes/ui/node.rs +++ b/server/src/routes/ui/node.rs @@ -33,12 +33,13 @@ pub fn r_library_node(id: String) { #[get("/n/<id>?<filter..>")] pub async fn r_library_node_filter( - _sess: Session, + session: Session, id: String, db: &State<Database>, aj: AcceptJson, filter: NodeFilterSort, ) -> Result<Either<DynLayoutPage<'_>, Json<NodePublic>>, MyError> { + drop(session); let node = db .node .get(&id) @@ -149,14 +150,14 @@ markup::define! { p { @format_duration(m.duration) } p { @m.resolution_name() } } - @for r in &node.ratings { - p { @match r { - Rating::YoutubeLikes(n) => { @format_count(*n) " Likes" } - Rating::YoutubeViews(n) => { @format_count(*n) " Views" } - Rating::YoutubeFollowers(n) => { @format_count(*n) " Subscribers" } - Rating::RottenTomatoes(n) => { @n " Tomatoes" } - Rating::Metacritic(n) => { "Metacritic Score: " @n } - Rating::Imdb(n) => { "IMDb Rating: " @n } + @for (kind, value) in &node.ratings { + p { @match kind { + Rating::YoutubeLikes => { @format_count(*value as usize) " Likes" } + Rating::YoutubeViews => { @format_count(*value as usize) " Views" } + Rating::YoutubeFollowers => { @format_count(*value as usize) " Subscribers" } + Rating::RottenTomatoes => { @value " Tomatoes" } + Rating::Metacritic => { "Metacritic Score: " @value } + Rating::Imdb => { "IMDb Rating: " @value } } } } } diff --git a/server/src/routes/ui/sort.rs b/server/src/routes/ui/sort.rs index 4db8f3d..3748a44 100644 --- a/server/src/routes/ui/sort.rs +++ b/server/src/routes/ui/sort.rs @@ -1,4 +1,4 @@ -use jellycommon::{NodeKind, NodePublic}; +use jellycommon::{helpers::SortAnyway, NodeKind, NodePublic, Rating}; use rocket::{ http::uri::fmt::{Query, UriDisplay}, FromForm, FromFormField, UriDisplayQuery, @@ -12,10 +12,32 @@ pub struct NodeFilterSort { } #[rustfmt::skip] -#[derive(FromFormField, UriDisplayQuery, Clone, Copy, PartialEq, Eq)] +#[derive(FromFormField, UriDisplayQuery, Clone, PartialEq, Eq)] enum SortProperty { #[field(value = "release_date")] ReleaseDate, #[field(value = "title")] Title, + #[field(value = "rating_rt")] RatingRottenTomatoes, + #[field(value = "rating_mc")] RatingMetacritic, + #[field(value = "rating_imdb")] RatingImdb, + #[field(value = "rating_yt_views")] RatingYoutubeViews, + #[field(value = "rating_yt_likes")] RatingYoutubeLikes, + #[field(value = "rating_yt_followers")] RatingYoutubeFollowers, +} + +impl SortProperty { + const ALL: &[(SortProperty, &'static str)] = { + use SortProperty::*; + &[ + (Title, "Title"), + (ReleaseDate, "Release Date"), + (RatingImdb, "IMDb Rating"), + (RatingMetacritic, "Metacritic Rating"), + (RatingRottenTomatoes, "Rotten Tomatoes"), + (RatingYoutubeFollowers, "Youtube Subscribers"), + (RatingYoutubeLikes, "Youtube Likes"), + (RatingYoutubeViews, "Youtube Views"), + ] + }; } #[rustfmt::skip] @@ -33,10 +55,28 @@ pub fn filter_and_sort_nodes(f: &NodeFilterSort, nodes: &mut Vec<(String, NodePu } o }); - if let Some(sort_prop) = f.sort_by { + if let Some(sort_prop) = &f.sort_by { match sort_prop { SortProperty::ReleaseDate => nodes.sort_by_key(|(_, _n)| 0), // TODO SortProperty::Title => nodes.sort_by(|(_, a), (_, b)| a.title.cmp(&b.title)), + 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::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.)) + }), } } match f.sort_order.unwrap_or(SortOrder::Ascending) { @@ -59,9 +99,8 @@ markup::define! { } fieldset.sortby { legend { "Sort By" } - @use SortProperty::*; - @for (value, label) in [(Title, "Title"), (ReleaseDate, "Release Date")] { - label { input[type="radio", name="sort_by", value=value, checked=Some(value)==f.sort_by]; @label } br; + @for (value, label) in SortProperty::ALL { + label { input[type="radio", name="sort_by", value=value, checked=Some(value)==f.sort_by.as_ref()]; @label } br; } } fieldset.sortorder { |