From bd413060c6aa687b4fa0c65d48ff63424d58bdc8 Mon Sep 17 00:00:00 2001 From: Diego Magdaleno <38844659+DiegoMagdaleno@users.noreply.github.com> Date: Wed, 24 Nov 2021 20:08:27 -0600 Subject: [PATCH] Support displaying awards (#168) * Initial implementation of award parsing * Posts: Implement awards as part of post * Posts: remove parse_awards dead code * Posts: initial implementation of displaying Awards at the post title * Posts: Proxy static award images * Client: i.redd.it should take path as argument not ID * Posts: Just like Reddit make award size 16px * Templates: limit the awards to 4 awards to increase performance * Comments: Make awards a property of comments and display them * Format and correct /img/:id * Update comment.html * [Optimization] Awards is not longer async * [Revert] Posts can now display more than 4 awards again * [Implementation] Awards not display on the frontpage * [Implementation] Display count on awards * Post: Start working on awards css * Awards: Move the image size to css * Awards: Start implementing tooltips * Refactor awards code and tweak CSS indentation * Unify Awards::new and Awards::parse * Use native tooltips and brighten awards background Co-authored-by: Spike <19519553+spikecodes@users.noreply.github.com> --- CODEOWNERS | 1 - src/main.rs | 2 +- src/post.rs | 11 ++++++-- src/utils.rs | 60 +++++++++++++++++++++++++++++++++++++++++- static/style.css | 25 ++++++++++++++++-- templates/comment.html | 8 ++++++ templates/post.html | 11 ++++++++ templates/utils.html | 7 +++++ 8 files changed, 118 insertions(+), 7 deletions(-) delete mode 100644 CODEOWNERS diff --git a/CODEOWNERS b/CODEOWNERS deleted file mode 100644 index 8d1ba42..0000000 --- a/CODEOWNERS +++ /dev/null @@ -1 +0,0 @@ -* @spikecodes diff --git a/src/main.rs b/src/main.rs index f311d3e..611c0c9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -180,7 +180,7 @@ async fn main() { // Proxy media through Libreddit app.at("/vid/:id/:size").get(|r| proxy(r, "https://v.redd.it/{id}/DASH_{size}").boxed()); app.at("/hls/:id/*path").get(|r| proxy(r, "https://v.redd.it/{id}/{path}").boxed()); - app.at("/img/:id").get(|r| proxy(r, "https://i.redd.it/{id}").boxed()); + app.at("/img/*path").get(|r| proxy(r, "https://i.redd.it/{path}").boxed()); app.at("/thumb/:point/:id").get(|r| proxy(r, "https://{point}.thumbs.redditmedia.com/{id}").boxed()); app.at("/emoji/:id/:name").get(|r| proxy(r, "https://emoji.redditmedia.com/{id}/{name}").boxed()); app.at("/preview/:loc/:id").get(|r| proxy(r, "https://{loc}view.redd.it/{id}").boxed()); diff --git a/src/post.rs b/src/post.rs index bde5c5b..6bdf409 100644 --- a/src/post.rs +++ b/src/post.rs @@ -3,8 +3,9 @@ use crate::client::json; use crate::esc; use crate::server::RequestExt; use crate::subreddit::{can_access_quarantine, quarantine}; -use crate::utils::{error, format_num, format_url, param, rewrite_urls, setting, template, time, val, Author, Comment, Flags, Flair, FlairPart, Media, Post, Preferences}; - +use crate::utils::{ + error, format_num, format_url, param, rewrite_urls, setting, template, time, val, Author, Awards, Comment, Flags, Flair, FlairPart, Media, Post, Preferences, +}; use hyper::{Body, Request, Response}; use askama::Template; @@ -93,6 +94,8 @@ async fn parse_post(json: &serde_json::Value) -> Post { // Determine the type of media along with the media URL let (post_type, media, gallery) = Media::parse(&post["data"]).await; + let awards: Awards = Awards::parse(&post["data"]["all_awardings"]); + // Build a post using data parsed from Reddit post API Post { id: val(post, "id"), @@ -148,6 +151,7 @@ async fn parse_post(json: &serde_json::Value) -> Post { created, comments: format_num(post["data"]["num_comments"].as_i64().unwrap_or_default()), gallery, + awards, } } @@ -178,6 +182,8 @@ fn parse_comments(json: &serde_json::Value, post_link: &str, post_author: &str, Vec::new() }; + let awards: Awards = Awards::parse(&data["all_awardings"]); + let parent_kind_and_id = val(&comment, "parent_id"); let parent_info = parent_kind_and_id.split('_').collect::>(); @@ -224,6 +230,7 @@ fn parse_comments(json: &serde_json::Value, post_link: &str, post_author: &str, edited, replies, highlighted, + awards, collapsed, } }) diff --git a/src/utils.rs b/src/utils.rs index 1e8e338..d6961ec 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -8,6 +8,7 @@ use hyper::{Body, Request, Response}; use regex::Regex; use serde_json::Value; use std::collections::HashMap; +use std::str::FromStr; use time::{Duration, OffsetDateTime}; use url::Url; @@ -213,6 +214,7 @@ pub struct Post { pub created: String, pub comments: (String, String), pub gallery: Vec, + pub awards: Awards, } impl Post { @@ -249,7 +251,8 @@ impl Post { let title = esc!(post, "title"); // Determine the type of media along with the media URL - let (post_type, media, gallery) = Media::parse(data).await; + let (post_type, media, gallery) = Media::parse(&data).await; + let awards = Awards::parse(&data["all_awardings"]); // selftext_html is set for text posts when browsing. let mut body = rewrite_urls(&val(post, "selftext_html")); @@ -315,6 +318,7 @@ impl Post { created, comments: format_num(data["num_comments"].as_i64().unwrap_or_default()), gallery, + awards, }); } @@ -340,9 +344,63 @@ pub struct Comment { pub edited: (String, String), pub replies: Vec, pub highlighted: bool, + pub awards: Awards, pub collapsed: bool, } +#[derive(Default, Clone)] +pub struct Award { + pub name: String, + pub icon_url: String, + pub description: String, + pub count: i64, +} + +impl std::fmt::Display for Award { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{} {} {}", self.name, self.icon_url, self.description) + } +} + +pub struct Awards(pub Vec); + +impl std::ops::Deref for Awards { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl std::fmt::Display for Awards { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + self.iter().fold(Ok(()), |result, award| result.and_then(|_| writeln!(f, "{}", award))) + } +} + +// Convert Reddit awards JSON to Awards struct +impl Awards { + pub fn parse(items: &Value) -> Self { + let parsed = items.as_array().unwrap_or(&Vec::new()).iter().fold(Vec::new(), |mut awards, item| { + let name = item["name"].as_str().unwrap_or_default().to_string(); + let icon_url = format_url(&item["icon_url"].as_str().unwrap_or_default().to_string()); + let description = item["description"].as_str().unwrap_or_default().to_string(); + let count: i64 = i64::from_str(&item["count"].to_string()).unwrap_or(1); + + awards.push(Award { + name, + icon_url, + description, + count, + }); + + awards + }); + + Self(parsed) + } +} + #[derive(Template)] #[template(path = "error.html", escape = "none")] pub struct ErrorTemplate { diff --git a/static/style.css b/static/style.css index 8a8a089..fefba1a 100644 --- a/static/style.css +++ b/static/style.css @@ -272,7 +272,7 @@ main { #column_one { max-width: 750px; border-radius: 5px; - overflow: hidden; + overflow: inherit; } footer { @@ -735,6 +735,7 @@ a.search_subreddit:hover { .post_header { margin: 15px 20px 5px 12px; grid-area: post_header; + line-height: 25px; } .post_subreddit { @@ -774,6 +775,26 @@ a.search_subreddit:hover { font-weight: bold; } +.awards { + background-color: var(--foreground); + border-radius: 5px; + margin: auto; + padding: 5px; +} + +.awards .award { + margin-right: 2px; +} + +.award { + position: relative; + display: inline-block; +} + +.award > img { + vertical-align: middle; +} + .author_flair:empty, .post_flair:empty { display: none; } @@ -1102,7 +1123,7 @@ summary.comment_data { } .compact .post_header { - margin: 15px 15px 2.5px 12px; + margin: 11px 15px 2.5px 12px; font-size: 14px; } diff --git a/templates/comment.html b/templates/comment.html index f019e0b..8734e2a 100644 --- a/templates/comment.html +++ b/templates/comment.html @@ -16,6 +16,14 @@ {% endif %} {{ rel_time }} {% if edited.0 != "".to_string() %}edited {{ edited.0 }}{% endif %} + {% if !awards.is_empty() %} + + {% for award in awards.clone() %} + + {{ award.name }} + + {% endfor %} + {% endif %}
{{ body }}
{% for c in replies -%}{{ c.render().unwrap() }}{%- endfor %} diff --git a/templates/post.html b/templates/post.html index 60d37aa..99a4065 100644 --- a/templates/post.html +++ b/templates/post.html @@ -43,6 +43,17 @@ {% endif %} {{ post.rel_time }} + {% if !post.awards.is_empty() %} + + + {% for award in post.awards.clone() %} + + {{ award.name }} + {{ award.count }} + + {% endfor %} + + {% endif %}

{{ post.title }} diff --git a/templates/utils.html b/templates/utils.html index 3745dea..e50b785 100644 --- a/templates/utils.html +++ b/templates/utils.html @@ -75,6 +75,13 @@ {{ post.rel_time }} + {% if !post.awards.is_empty() %} + {% for award in post.awards.clone() %} + + {{ award.name }} + + {% endfor %} + {% endif %}

{% if post.flair.flair_parts.len() > 0 %}