aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/src/helpers.rs20
-rw-r--r--common/src/lib.rs20
-rw-r--r--import/src/main.rs7
-rw-r--r--server/src/routes/ui/node.rs19
-rw-r--r--server/src/routes/ui/sort.rs51
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 {