Compare commits

...

14 Commits

Author SHA1 Message Date
9f8d36cb00 Prevent post previews from overflowing on Chromium 2021-11-22 08:40:36 -08:00
25e641e7b3 Don't run GitHub Workflow when README.md changes 2021-11-21 22:46:01 -08:00
4faa9d46d6 Fix HTTPS connector 2021-11-21 22:44:05 -08:00
7220190811 Link subscriptions in settings to their respective feeds 2021-11-21 22:30:44 -08:00
768820cd4c Render markdown correctly in text post previews by using selftext_html. (#335)
* Render markdown correctly in text post previews by using selftext_html.

I was mistakenly under the impression that we somehow render markdown ourselves, but turns out we just take whatever HTML reddit gives us, and we also need to do this for text previews.

Use CSS to limit the size of the previews instead of truncating in the template.

Fix table CSS.

* Fix post_body padding and trim post_previews

Co-authored-by: spikecodes <19519553+spikecodes@users.noreply.github.com>
2021-11-21 23:17:52 +00:00
2ef7957a66 Create feature parity issue template 2021-11-21 19:48:48 +00:00
7df8e7b4c6 Tweak feature request template 2021-11-21 19:27:33 +00:00
67d3be06e1 Fix Jamie's instance address 2021-11-21 04:17:06 +00:00
6be5eb8991 Update README.md 2021-11-21 04:15:35 +00:00
5d9c320a7e Format post and comment votes with a decimal place, like vanilla reddit does. (#324)
* Format post and comment votes with a decimal place, like vanilla reddit does.

Before this change, a vote count of 1999 was displayed as 1k, which is a pretty big gap. The displayed count also differed from what Reddit does. Now, the behaviour is consistent.

Added some tests for format_num.

* Provide more space for post scores

Co-authored-by: spikecodes <19519553+spikecodes@users.noreply.github.com>
2021-11-21 04:07:45 +00:00
f7de5285e4 Hide post preview in compact mode. (#329) 2021-11-21 02:05:37 +00:00
c2053524c7 Add text post previews. (#328)
* Add text post previews.

* Add mask gradient over post preview text

* Increase post title font weight for contrast

Co-authored-by: spikecodes <19519553+spikecodes@users.noreply.github.com>
2021-11-20 21:13:50 +00:00
3a9e6b4ca0 Add mutahar.rocks instance 2021-11-20 17:29:27 +00:00
731a407466 Collapse (sticky) bot comments by default. (#321)
* Collapse bot comments by default.

Comments are considered bot comments if they are posted by a moderator and are stickied. Some false positives are expected.

* Remove unneeded String conversion

Co-authored-by: spikecodes <19519553+spikecodes@users.noreply.github.com>
2021-11-19 05:42:53 +00:00
13 changed files with 167 additions and 66 deletions

View File

@ -0,0 +1,28 @@
---
name: ✨ Feature parity
about: Suggest implementing a feature into Libreddit that is found in Reddit.com
title: ''
labels: feature parity
assignees: ''
---
## How does this feature work on Reddit?
<!--
A clear and concise description of what the feature is.
-->
## Describe the implementation into Libreddit
<!--
A clear and concise description of what you want to happen.
-->
## Describe alternatives you've considered
<!--
A clear and concise description of any alternative solutions or features you've considered.
-->
## Additional context
<!--
Add any other context or screenshots about the feature parity request here.
-->

View File

@ -1,6 +1,6 @@
---
name: 💡 Feature request
about: Suggest an idea for this project
about: Suggest a feature for Libreddit that is not found in Reddit
title: ''
labels: enhancement
assignees: ''

View File

@ -2,9 +2,10 @@ name: Rust
on:
push:
branches: [master]
pull_request:
branches: [master]
paths-ignore:
- "**.md"
branches:
- master
env:
CARGO_TERM_COLOR: always

79
Cargo.lock generated
View File

@ -125,9 +125,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitvec"
version = "0.19.5"
version = "0.19.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321"
checksum = "55f93d0ef3363c364d5976646a38f04cf67cfe1d4c8d160cdea02cab2c116b33"
dependencies = [
"funty",
"radium",
@ -236,15 +236,6 @@ version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
[[package]]
name = "ct-logs"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1a816186fa68d9e426e3cb4ae4dff1fcd8e4a2c34b781bf7a822574a0d0aac8"
dependencies = [
"sct",
]
[[package]]
name = "darling"
version = "0.13.0"
@ -496,15 +487,15 @@ checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503"
[[package]]
name = "httpdate"
version = "1.0.1"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440"
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
[[package]]
name = "hyper"
version = "0.14.14"
version = "0.14.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b91bb1f221b6ea1f1e4371216b70f40748774c2fb5971b450c07773fb92d26b"
checksum = "436ec0091e4f20e655156a30a0df3770fe2900aa301e548e08446ec794b6953c"
dependencies = [
"bytes",
"futures-channel",
@ -526,19 +517,17 @@ dependencies = [
[[package]]
name = "hyper-rustls"
version = "0.22.1"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64"
checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac"
dependencies = [
"ct-logs",
"futures-util",
"http",
"hyper",
"log",
"rustls",
"rustls-native-certs",
"tokio",
"tokio-rustls",
"webpki",
]
[[package]]
@ -613,13 +602,13 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.107"
version = "0.2.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219"
checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119"
[[package]]
name = "libreddit"
version = "0.17.0"
version = "0.18.1"
dependencies = [
"askama",
"async-recursion",
@ -877,11 +866,10 @@ dependencies = [
[[package]]
name = "rustls"
version = "0.19.1"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7"
checksum = "d37e5e2290f3e040b594b1a9e04377c2c671f1a1cfd9bfdef82106ac1c113f84"
dependencies = [
"base64",
"log",
"ring",
"sct",
@ -890,16 +878,25 @@ dependencies = [
[[package]]
name = "rustls-native-certs"
version = "0.5.0"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a07b7c1885bd8ed3831c289b7870b13ef46fe0e856d288c30d9cc17d75a2092"
checksum = "5ca9ebdfa27d3fc180e42879037b5338ab1c040c06affd00d8338598e7800943"
dependencies = [
"openssl-probe",
"rustls",
"rustls-pemfile",
"schannel",
"security-framework",
]
[[package]]
name = "rustls-pemfile"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9"
dependencies = [
"base64",
]
[[package]]
name = "ryu"
version = "1.0.5"
@ -924,9 +921,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "sct"
version = "0.6.1"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce"
checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
dependencies = [
"ring",
"untrusted",
@ -992,9 +989,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.70"
version = "1.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e277c495ac6cd1a01a58d0a0c574568b4d1ddf14f59965c6a58b8d96400b54f3"
checksum = "063bf466a64011ac24040a49009724ee60a57da1b437617ceb32e53ad61bfb19"
dependencies = [
"itoa",
"ryu",
@ -1195,9 +1192,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "tokio"
version = "1.13.0"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "588b2d10a336da58d877567cd8fb8a14b463e2104910f8132cd054b4b96e29ee"
checksum = "70e992e41e0d2fb9f755b37446f20900f64446ef54874f40a60c78f021ac6144"
dependencies = [
"autocfg",
"bytes",
@ -1215,9 +1212,9 @@ dependencies = [
[[package]]
name = "tokio-macros"
version = "1.5.1"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "114383b041aa6212c579467afa0075fbbdd0718de036100bc0ba7961d8cb9095"
checksum = "c9efc1aba077437943f7515666aa2b882dfabfbfdf89c819ea75a8d6e9eaba5e"
dependencies = [
"proc-macro2",
"quote",
@ -1226,9 +1223,9 @@ dependencies = [
[[package]]
name = "tokio-rustls"
version = "0.22.0"
version = "0.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6"
checksum = "4baa378e417d780beff82bf54ceb0d195193ea6a00c14e22359e7f39456b5689"
dependencies = [
"rustls",
"tokio",
@ -1414,9 +1411,9 @@ dependencies = [
[[package]]
name = "webpki"
version = "0.21.4"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea"
checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
dependencies = [
"ring",
"untrusted",

View File

@ -3,7 +3,7 @@ name = "libreddit"
description = " Alternative private front-end to Reddit"
license = "AGPL-3.0"
repository = "https://github.com/spikecodes/libreddit"
version = "0.17.0"
version = "0.18.1"
authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"]
edition = "2018"
@ -16,10 +16,10 @@ regex = "1.5.4"
serde = { version = "1.0.130", features = ["derive"] }
cookie = "0.15.1"
futures-lite = "1.12.0"
hyper = { version = "0.14.14", features = ["full"] }
hyper-rustls = "0.22.1"
hyper = { version = "0.14.15", features = ["full"] }
hyper-rustls = "0.23.0"
route-recognizer = "0.3.1"
serde_json = "1.0.70"
tokio = { version = "1.13.0", features = ["full"] }
serde_json = "1.0.71"
tokio = { version = "1.14.0", features = ["full"] }
time = "0.2.7"
url = "2.2.2"

View File

@ -40,7 +40,7 @@ Feel free to [open an issue](https://github.com/spikecodes/libreddit/issues/new)
| [libreddit.exonip.de](https://libreddit.exonip.de) | 🇩🇪 DE | |
| [libreddit.domain.glass](https://libreddit.domain.glass) | 🇺🇸 US | ✅ |
| [libreddit.sugoma.tk](https://libreddit.sugoma.tk) | 🇺🇸 US | |
| [libreddit.trevorthalacker.com](https://libreddit.trevorthalacker.com) | 🇺🇸 US | ✅ |
| [libreddit.jamiethalacker.dev](https://libreddit.jamiethalacker.dev) | 🇺🇸 US | ✅ |
| [reddit.artemislena.eu](https://reddit.artemislena.eu) | 🇩🇪 DE | |
| [r.nf](https://r.nf) | 🇩🇪 DE | ✅ |
| [libreddit.awesomehub.io](https://libreddit.awesomehub.io) | 🇫🇮 FI | |
@ -55,6 +55,7 @@ Feel free to [open an issue](https://github.com/spikecodes/libreddit/issues/new)
| [lr.oversold.host](https://lr.oversold.host) | 🇱🇺 LU | |
| [libreddit.de](https://libreddit.de) | 🇩🇪 DE | |
| [libreddit.pussthecat.org](https://libreddit.pussthecat.org) | 🇩🇪 DE | |
| [libreddit.mutahar.rocks](https://libreddit.mutahar.rocks) | 🇫🇷 FR | |
| [spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion](http://spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion) | 🇮🇳 IN | |
| [fwhhsbrbltmrct5hshrnqlqygqvcgmnek3cnka55zj4y7nuus5muwyyd.onion](http://fwhhsbrbltmrct5hshrnqlqygqvcgmnek3cnka55zj4y7nuus5muwyyd.onion) | 🇩🇪 DE | |
| [kphht2jcflojtqte4b4kyx7p2ahagv4debjj32nre67dxz7y57seqwyd.onion](http://kphht2jcflojtqte4b4kyx7p2ahagv4debjj32nre67dxz7y57seqwyd.onion) | 🇳🇱 NL | |

View File

@ -23,7 +23,7 @@ async fn stream(url: &str, req: &Request<Body>) -> Result<Response<Body>, String
let url = Uri::from_str(url).map_err(|_| "Couldn't parse URL".to_string())?;
// Prepare the HTTPS connector.
let https = hyper_rustls::HttpsConnector::with_native_roots();
let https = hyper_rustls::HttpsConnectorBuilder::new().with_native_roots().https_only().enable_http1().build();
// Build the hyper client from the HTTPS connector.
let client: client::Client<_, hyper::Body> = client::Client::builder().build(https);
@ -63,7 +63,7 @@ async fn stream(url: &str, req: &Request<Body>) -> Result<Response<Body>, String
fn request(url: String, quarantine: bool) -> Boxed<Result<Response<Body>, String>> {
// Prepare the HTTPS connector.
let https = hyper_rustls::HttpsConnector::with_native_roots();
let https = hyper_rustls::HttpsConnectorBuilder::new().with_native_roots().https_or_http().enable_http1().build();
// Construct the hyper client from the HTTPS connector.
let client: client::Client<_, hyper::Body> = client::Client::builder().build(https);

View File

@ -184,6 +184,14 @@ fn parse_comments(json: &serde_json::Value, post_link: &str, post_author: &str,
let id = val(&comment, "id");
let highlighted = id == highlighted_comment;
// Many subreddits have a default comment posted about the sub's rules etc.
// Many libreddit users do not wish to see this kind of comment by default.
// Reddit does not tell us which users are "bots", so a good heuristic is to
// collapse stickied moderator comments.
let is_moderator_comment = data["distinguished"].as_str().unwrap_or_default() == "moderator";
let is_stickied = data["stickied"].as_bool().unwrap_or_default();
let collapsed = is_moderator_comment && is_stickied;
Comment {
id,
kind,
@ -216,6 +224,7 @@ fn parse_comments(json: &serde_json::Value, post_link: &str, post_author: &str,
edited,
replies,
highlighted,
collapsed,
}
})
.collect()

View File

@ -251,11 +251,17 @@ impl Post {
// Determine the type of media along with the media URL
let (post_type, media, gallery) = Media::parse(data).await;
// selftext_html is set for text posts when browsing.
let mut body = rewrite_urls(&val(post, "selftext_html"));
if body == "" {
body = rewrite_urls(&val(post, "body_html"))
}
posts.push(Self {
id: val(post, "id"),
title: esc!(if title.is_empty() { fallback_title.clone() } else { title }),
community: val(post, "subreddit"),
body: rewrite_urls(&val(post, "body_html")),
body,
author: Author {
name: val(post, "author"),
flair: Flair {
@ -334,6 +340,7 @@ pub struct Comment {
pub edited: (String, String),
pub replies: Vec<Comment>,
pub highlighted: bool,
pub collapsed: bool,
}
#[derive(Template)]
@ -534,12 +541,14 @@ pub fn rewrite_urls(input_text: &str) -> String {
})
}
// Append `m` and `k` for millions and thousands respectively
// Format vote count to a string that will be displayed.
// Append `m` and `k` for millions and thousands respectively, and
// round to the nearest tenth.
pub fn format_num(num: i64) -> (String, String) {
let truncated = if num >= 1_000_000 || num <= -1_000_000 {
format!("{}m", num / 1_000_000)
format!("{:.1}m", num as f64 / 1_000_000.0)
} else if num >= 1000 || num <= -1000 {
format!("{}k", num / 1_000)
format!("{:.1}k", num as f64 / 1_000.0)
} else {
num.to_string()
};
@ -618,3 +627,32 @@ pub async fn error(req: Request<Body>, msg: String) -> Result<Response<Body>, St
Ok(Response::builder().status(404).header("content-type", "text/html").body(body.into()).unwrap_or_default())
}
#[cfg(test)]
mod tests {
use super::format_num;
#[test]
fn format_num_works() {
assert_eq!(
format_num(567),
("567".to_string(), "567".to_string())
);
assert_eq!(
format_num(1234),
("1.2k".to_string(), "1234".to_string())
);
assert_eq!(
format_num(1999),
("2.0k".to_string(), "1999".to_string())
);
assert_eq!(
format_num(1001),
("1.0k".to_string(), "1001".to_string())
);
assert_eq!(
format_num(1_999_999),
("2.0m".to_string(), "1999999".to_string())
);
}
}

View File

@ -697,12 +697,12 @@ a.search_subreddit:hover {
.post_score {
padding-top: 16px;
padding-left: 12px;
font-size: 13px;
font-weight: bold;
text-align: end;
color: var(--accent);
grid-area: post_score;
text-align: end;
text-align: center;
border-radius: 5px 0 0 5px;
transition: 0.2s background;
}
@ -712,7 +712,7 @@ a.search_subreddit:hover {
}
.post_header {
margin: 15px 20px 5px 15px;
margin: 15px 20px 5px 12px;
grid-area: post_header;
}
@ -722,8 +722,9 @@ a.search_subreddit:hover {
.post_title {
font-size: 16px;
font-weight: 500;
line-height: 1.5;
margin: 5px 15px;
margin: 5px 15px 5px 12px;
grid-area: post_title;
}
@ -837,11 +838,20 @@ a.search_subreddit:hover {
.post_body {
opacity: 0.9;
font-weight: normal;
margin: 5px 15px;
padding: 5px 15px 5px 12px;
grid-area: post_body;
width: calc(100% - 30px);
}
/* Used only for text post preview */
.post_preview {
-webkit-mask-image: linear-gradient(180deg,#000 60%,transparent);;
mask-image: linear-gradient(180deg,#000 60%,transparent);
opacity: 0.8;
max-height: 250px;
overflow: hidden;
}
.post_footer {
display: flex;
justify-content: space-between;
@ -1070,7 +1080,7 @@ summary.comment_data {
}
.compact .post_header {
margin: 15px 15px 2.5px 15px;
margin: 15px 15px 2.5px 12px;
font-size: 14px;
}
@ -1078,6 +1088,10 @@ summary.comment_data {
margin: 2.5px 15px;
}
.compact .post_preview {
display: none;
}
.compact .post_media {
max-width: calc(100% - 30px);
margin: 2.5px auto;
@ -1133,6 +1147,10 @@ summary.comment_data {
margin-top: 10px;
}
.prefs > p {
font-weight: 500;
}
.prefs select {
border-radius: 5px;
box-shadow: var(--shadow);
@ -1161,6 +1179,10 @@ input[type="submit"] {
margin-left: 30px;
}
#settings_subs a {
color: var(--accent);
}
/* Markdown */
.md {
@ -1213,7 +1235,6 @@ input[type="submit"] {
.md table {
margin: 5px;
display: block;
overflow-x: auto;
}

View File

@ -8,7 +8,7 @@
<p class="comment_score" title="{{ score.1 }}">{{ score.0 }}</p>
<div class="line"></div>
</div>
<details class="comment_right" open>
<details class="comment_right" {% if collapsed == false %}open{% endif %}>
<summary class="comment_data">
<a class="comment_author {{ author.distinguished }} {% if author.name == post_author %}op{% endif %}" href="/user/{{ author.name }}">u/{{ author.name }}</a>
{% if author.flair.flair_parts.len() > 0 %}

View File

@ -77,7 +77,9 @@
<p>Subscribed Feeds</p>
{% for sub in prefs.subscriptions %}
<div>
<span>{% if sub.starts_with("u_") -%}{{ format!("u/{}", &sub[2..]) }}{% else -%}{{ format!("r/{}", sub) }}{% endif -%}</span>
{% let feed -%}
{% if sub.starts_with("u_") -%}{% let feed = format!("u/{}", &sub[2..]) -%}{% else -%}{% let feed = format!("r/{}", sub) -%}{% endif -%}
<a href="/{{ feed }}">{{ feed }}</a>
<form action="/r/{{ sub }}/unsubscribe/?redirect=settings" method="POST">
<button class="unsubscribe">Unsubscribe</button>
</form>

View File

@ -130,6 +130,10 @@
{% endif %}
<div class="post_score" title="{{ post.score.1 }}">{{ post.score.0 }}<span class="label"> Upvotes</span></div>
<div class="post_body post_preview">
<!-- preview of selfposts when browsing subreddits -->
{{ post.body }}
</div>
<div class="post_footer">
<a href="{{ post.permalink }}" class="post_comments" title="{{ post.comments.1 }} comments">{{ post.comments.0 }} comments</a>
</div>