Compare commits

..

20 Commits

Author SHA1 Message Date
f62f7bf200 v0.30.1 2023-03-10 21:34:42 -07:00
aece392a86 Pad bottom of body to prevent footer collision (fixes #747) 2023-03-10 21:33:45 -07:00
aeeb066e47 Update README.md (#748)
* Remove duplicated config

Was accidentally introduced in  412ce8f1f3
2023-03-10 21:04:05 -07:00
51cdf574f7 v0.30.0 2023-03-08 22:15:31 -07:00
af6722c053 Move unimportant links to footer (#728) 2023-03-08 22:14:43 -07:00
412ce8f1f3 Fix default subscriptions (#732)
Co-authored-by: Daniel Valentine <daniel@vielle.ws>
2023-03-08 21:53:23 -07:00
dfa57c890d fix build error on windows (#741) 2023-03-08 21:32:41 -07:00
01f9907aaf show the count of 'more replies'. (#740)
Co-authored-by: Daniel Valentine <daniel@vielle.ws>
Co-authored-by: Matthew Esposito <matt@matthew.science>
2023-03-08 21:30:41 -07:00
bf19ff513f add support for gifs in galleries. (#744) 2023-03-08 21:04:26 -07:00
ffc9ca2e98 use the documented LIBREDDIT_DEFAULT_DISABLE_VISIT_REDDIT_CONFIRMATION config option. (#737) 2023-03-04 13:04:40 -07:00
cef9266648 Restructure section on Libreddit user privacy. 2023-02-26 03:35:36 -07:00
d3b4f4e379 Update tempfile to v3.4.0. 2023-02-26 03:11:17 -07:00
b90b41c009 v0.29.4 2023-02-26 03:01:35 -07:00
pin
0eccb9bcf2 Add NetBSD install (#720) 2023-02-26 01:13:56 -07:00
eb07a2ce7c Make gated subreddits accessible by treating them as quarantined (#722)
* Fix gated communities being unviewable by treating them as quarantined

* Show restriction reason in quarantine template

* Add `gated` checks for other requests
2023-02-26 00:40:32 -07:00
0b39d4f059 Mark search query as safe on Prev/Next button (#731)
Fixes: #677 again. Complement to #686.
2023-02-26 00:35:05 -07:00
58fa213be8 Reuse hyper client. (#727)
Making a new connection on every request is very slow and wasteful, espectially on slower network.

Fix this by reuse a hyper client which shares a connection pool.

I'm able to lower /r/popular loading time from 5s to 1.5s on my machine.
2023-02-26 00:33:55 -07:00
5e03d701e4 Revert "Move unimportant links to footer"
This reverts commit e3df3a9470.
2023-02-19 18:03:55 +00:00
e3df3a9470 Move unimportant links to footer 2023-02-19 18:00:56 +00:00
35504eda14 v0.29.3 -- fix layout bugs on mobile
Addresses the following layout bugs in mobile view:

* improper rendering of award images on posts
* upvote ratio no longer appearing on bottom-right corner of post as
  before
* Reddit warning pop-up background cut off at bottom of page

Fixes #713.
2023-02-14 20:19:19 -07:00
19 changed files with 236 additions and 90 deletions

View File

@ -21,6 +21,7 @@ Daniel Valentine <daniel@vielle.ws>
dbrennand <52419383+dbrennand@users.noreply.github.com>
dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Diego Magdaleno <38844659+DiegoMagdaleno@users.noreply.github.com>
domve <domve@posteo.net>
Dyras <jevwmguf@duck.com>
Edward <101938856+EdwardLangdon@users.noreply.github.com>
elliot <75391956+ellieeet123@users.noreply.github.com>
@ -58,9 +59,11 @@ Nicholas Christopher <nchristopher@tuta.io>
Nick Lowery <ClockVapor@users.noreply.github.com>
Nico <github@dr460nf1r3.org>
NKIPSC <15067635+NKIPSC@users.noreply.github.com>
o69mar <119129086+o69mar@users.noreply.github.com>
obeho <71698631+obeho@users.noreply.github.com>
obscurity <z@x4.pm>
Om G <34579088+OxyMagnesium@users.noreply.github.com>
pin <90570748+0323pin@users.noreply.github.com>
potatoesAreGod <118043038+potatoesAreGod@users.noreply.github.com>
RiversideRocks <59586759+RiversideRocks@users.noreply.github.com>
robin <8597693+robrobinbin@users.noreply.github.com>
@ -88,5 +91,6 @@ Tsvetomir Bonev <invakid404@riseup.net>
Vladislav Nepogodin <nepogodin.vlad@gmail.com>
Walkx <walkxnl@gmail.com>
Wichai <1482605+Chengings@users.noreply.github.com>
wsy2220 <wsy@dogben.com>
xatier <xatierlike@gmail.com>
Zach <72994911+zachjmurphy@users.noreply.github.com>

103
Cargo.lock generated
View File

@ -336,6 +336,27 @@ dependencies = [
"crypto-common",
]
[[package]]
name = "errno"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
dependencies = [
"errno-dragonfly",
"libc",
"winapi",
]
[[package]]
name = "errno-dragonfly"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "fastrand"
version = "1.8.0"
@ -624,6 +645,16 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "io-lifetimes"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3"
dependencies = [
"libc",
"windows-sys 0.45.0",
]
[[package]]
name = "itoa"
version = "1.0.5"
@ -673,7 +704,7 @@ dependencies = [
[[package]]
name = "libreddit"
version = "0.29.2"
version = "0.30.0"
dependencies = [
"askama",
"brotli",
@ -701,6 +732,12 @@ dependencies = [
"url",
]
[[package]]
name = "linux-raw-sys"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
[[package]]
name = "lipsum"
version = "0.8.2"
@ -767,7 +804,7 @@ dependencies = [
"libc",
"log",
"wasi",
"windows-sys",
"windows-sys 0.42.0",
]
[[package]]
@ -843,7 +880,7 @@ dependencies = [
"libc",
"redox_syscall",
"smallvec",
"windows-sys",
"windows-sys 0.42.0",
]
[[package]]
@ -950,15 +987,6 @@ version = "0.6.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
[[package]]
name = "remove_dir_all"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
dependencies = [
"winapi",
]
[[package]]
name = "ring"
version = "0.16.20"
@ -1021,6 +1049,20 @@ dependencies = [
"walkdir",
]
[[package]]
name = "rustix"
version = "0.36.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644"
dependencies = [
"bitflags",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys",
"windows-sys 0.45.0",
]
[[package]]
name = "rustls"
version = "0.20.8"
@ -1087,7 +1129,7 @@ version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3"
dependencies = [
"windows-sys",
"windows-sys 0.42.0",
]
[[package]]
@ -1265,16 +1307,15 @@ dependencies = [
[[package]]
name = "tempfile"
version = "3.3.0"
version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95"
dependencies = [
"cfg-if",
"fastrand",
"libc",
"redox_syscall",
"remove_dir_all",
"winapi",
"rustix",
"windows-sys 0.42.0",
]
[[package]]
@ -1358,7 +1399,7 @@ dependencies = [
"signal-hook-registry",
"socket2",
"tokio-macros",
"windows-sys",
"windows-sys 0.42.0",
]
[[package]]
@ -1665,6 +1706,30 @@ dependencies = [
"windows_x86_64_msvc",
]
[[package]]
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.1"

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.29.2"
version = "0.30.1"
authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"]
edition = "2021"

View File

@ -114,13 +114,21 @@ Results from Google PageSpeed Insights ([Libreddit Report](https://pagespeed.web
For transparency, I hope to describe all the ways Libreddit handles user privacy.
**Logging:** In production (when running the binary, hosting with docker, or using the official instances), Libreddit logs nothing. When debugging (running from source without `--release`), Libreddit logs post IDs fetched to aid with troubleshooting.
#### Server
**DNS:** Both official domains (`libredd.it` and `libreddit.spike.codes`) use Cloudflare as the DNS resolver. Though, the sites are not proxied through Cloudflare meaning Cloudflare doesn't have access to user traffic.
* **Logging:** In production (when running the binary, hosting with docker, or using the official instances), Libreddit logs nothing. When debugging (running from source without `--release`), Libreddit logs post IDs fetched to aid with troubleshooting.
**Cookies:** Libreddit uses optional cookies to store any configured settings in [the settings menu](https://libreddit.spike.codes/settings). These are not cross-site cookies and the cookies hold no personal data.
* **Cookies:** Libreddit uses optional cookies to store any configured settings in [the settings menu](https://libreddit.spike.codes/settings). These are not cross-site cookies and the cookies hold no personal data.
**Hosting:** The official instances are hosted on [Replit](https://replit.com/) which monitors usage to prevent abuse. I can understand if this invalidates certain users' threat models and therefore, self-hosting, using unofficial instances, and browsing through Tor are welcomed.
#### Official instance (libreddit.spike.codes)
The official instance is hosted at https://libreddit.spike.codes.
* **Server:** The official instance runs a production binary, and thus logs nothing.
* **DNS:** The domain for the official instance uses Cloudflare as the DNS resolver. However, this site is not proxied through Cloudflare, and thus Cloudflare doesn't have access to user traffic.
* **Hosting:** The official instance is hosted on [Replit](https://replit.com/), which monitors usage to prevent abuse. I can understand if this invalidates certain users' threat models, and therefore, self-hosting, using unofficial instances, and browsing through Tor are welcomed.
---
@ -159,12 +167,26 @@ For ArchLinux users, Libreddit is available from the AUR as [`libreddit-git`](ht
```
yay -S libreddit-git
```
## 4) NetBSD/pkgsrc
## 4) GitHub Releases
For NetBSD users, Libreddit is available from the official repositories.
```
pkgin install libreddit
```
Or, if you prefer to build from source
```
cd /usr/pkgsrc/libreddit
make install
```
## 5) GitHub Releases
If you're on Linux and none of these methods work for you, you can grab a Linux binary from [the newest release](https://github.com/libreddit/libreddit/releases/latest).
## 5) Replit/Heroku/Glitch
## 6) Replit/Heroku/Glitch
> **Warning**
> These are free hosting options but they are *not* private and will monitor server usage to prevent abuse. If you need a free and easy setup, this method may work best for you.
@ -209,6 +231,7 @@ Assign a default value for each user-modifiable setting by passing environment v
| `USE_HLS` | `["on", "off"]` | `off` |
| `HIDE_HLS_NOTIFICATION` | `["on", "off"]` | `off` |
| `AUTOPLAY_VIDEOS` | `["on", "off"]` | `off` |
| `SUBSCRIPTIONS` | `+`-delimited list of subreddits (`sub1+sub2+sub3+...`) | _(none)_ |
| `HIDE_AWARDS` | `["on", "off"]` | `off`
| `DISABLE_VISIT_REDDIT_CONFIRMATION` | `["on", "off"]` | `off` |

View File

@ -50,6 +50,9 @@
"LIBREDDIT_BANNER": {
"required": false
},
"LIBREDDIT_DEFAULT_SUBSCRIPTIONS": {
"required": false
},
"LIBREDDIT_DEFAULT_DISABLE_VISIT_REDDIT_CONFIRMATION": {
"required": false
}

View File

@ -1,7 +1,13 @@
use std::{
os::unix::process::ExitStatusExt,
process::{Command, ExitStatus, Output},
};
#[cfg(not(target_os = "windows"))]
use std::os::unix::process::ExitStatusExt;
#[cfg(target_os = "windows")]
use std::os::windows::process::ExitStatusExt;
fn main() {
let output = String::from_utf8(
Command::new("git")

View File

@ -1,7 +1,10 @@
use cached::proc_macro::cached;
use futures_lite::{future::Boxed, FutureExt};
use hyper::{body, body::Buf, client, header, Body, Method, Request, Response, Uri};
use hyper::client::HttpConnector;
use hyper::{body, body::Buf, client, header, Body, Client, Method, Request, Response, Uri};
use hyper_rustls::HttpsConnector;
use libflate::gzip;
use once_cell::sync::Lazy;
use percent_encoding::{percent_encode, CONTROLS};
use serde_json::Value;
use std::{io, result::Result};
@ -11,6 +14,11 @@ use crate::server::RequestExt;
const REDDIT_URL_BASE: &str = "https://www.reddit.com";
static CLIENT: Lazy<Client<HttpsConnector<HttpConnector>>> = Lazy::new(|| {
let https = hyper_rustls::HttpsConnectorBuilder::new().with_native_roots().https_only().enable_http1().build();
client::Client::builder().build(https)
});
/// Gets the canonical path for a resource on Reddit. This is accomplished by
/// making a `HEAD` request to Reddit at the path given in `path`.
///
@ -66,11 +74,8 @@ async fn stream(url: &str, req: &Request<Body>) -> Result<Response<Body>, String
// First parameter is target URL (mandatory).
let uri = url.parse::<Uri>().map_err(|_| "Couldn't parse URL".to_string())?;
// Prepare the HTTPS connector.
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);
let client: client::Client<_, hyper::Body> = CLIENT.clone();
let mut builder = Request::get(uri);
@ -123,11 +128,8 @@ fn request(method: &'static Method, path: String, redirect: bool, quarantine: bo
// Build Reddit URL from path.
let url = format!("{}{}", REDDIT_URL_BASE, path);
// Prepare the HTTPS connector.
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);
let client: client::Client<_, hyper::Body> = CLIENT.clone();
// Build request to Reddit. When making a GET, request gzip compression.
// (Reddit doesn't do brotli yet.)
@ -140,7 +142,14 @@ fn request(method: &'static Method, path: String, redirect: bool, quarantine: bo
.header("Accept-Encoding", if method == Method::GET { "gzip" } else { "identity" })
.header("Accept-Language", "en-US,en;q=0.5")
.header("Connection", "keep-alive")
.header("Cookie", if quarantine { "_options=%7B%22pref_quarantine_optin%22%3A%20true%7D" } else { "" })
.header(
"Cookie",
if quarantine {
"_options=%7B%22pref_quarantine_optin%22%3A%20true%2C%20%22pref_gated_sr_optin%22%3A%20true%7D"
} else {
""
},
)
.body(Body::empty());
async move {

View File

@ -52,6 +52,12 @@ pub struct Config {
#[serde(rename = "LIBREDDIT_DEFAULT_HIDE_AWARDS")]
pub(crate) default_hide_awards: Option<String>,
#[serde(rename = "LIBREDDIT_DEFAULT_SUBSCRIPTIONS")]
pub(crate) default_subscriptions: Option<String>,
#[serde(rename = "LIBREDDIT_DEFAULT_DISABLE_VISIT_REDDIT_CONFIRMATION")]
pub(crate) default_disable_visit_reddit_confirmation: Option<String>,
#[serde(rename = "LIBREDDIT_BANNER")]
pub(crate) banner: Option<String>,
}
@ -81,6 +87,8 @@ impl Config {
default_use_hls: parse("LIBREDDIT_DEFAULT_USE_HLS"),
default_hide_hls_notification: parse("LIBREDDIT_DEFAULT_HIDE_HLS"),
default_hide_awards: parse("LIBREDDIT_DEFAULT_HIDE_AWARDS"),
default_subscriptions: parse("LIBREDDIT_DEFAULT_SUBSCRIPTIONS"),
default_disable_visit_reddit_confirmation: parse("LIBREDDIT_DEFAULT_DISABLE_VISIT_REDDIT_CONFIRMATION"),
banner: parse("LIBREDDIT_BANNER"),
}
}
@ -100,6 +108,8 @@ fn get_setting_from_config(name: &str, config: &Config) -> Option<String> {
"LIBREDDIT_DEFAULT_HIDE_HLS_NOTIFICATION" => config.default_hide_hls_notification.clone(),
"LIBREDDIT_DEFAULT_WIDE" => config.default_wide.clone(),
"LIBREDDIT_DEFAULT_HIDE_AWARDS" => config.default_hide_awards.clone(),
"LIBREDDIT_DEFAULT_SUBSCRIPTIONS" => config.default_subscriptions.clone(),
"LIBREDDIT_DEFAULT_DISABLE_VISIT_REDDIT_CONFIRMATION" => config.default_disable_visit_reddit_confirmation.clone(),
"LIBREDDIT_BANNER" => config.banner.clone(),
_ => None,
}
@ -142,3 +152,8 @@ fn test_alt_env_config_precedence() {
write("libreddit.toml", config_to_write).unwrap();
assert_eq!(get_setting("LIBREDDIT_DEFAULT_COMMENT_SORT"), Some("top".into()))
}
#[test]
#[sealed_test(env = [("LIBREDDIT_DEFAULT_SUBSCRIPTIONS", "news+bestof")])]
fn test_default_subscriptions() {
assert_eq!(get_setting("LIBREDDIT_DEFAULT_SUBSCRIPTIONS"), Some("news+bestof".into()));
}

View File

@ -210,9 +210,9 @@ pub async fn item(req: Request<Body>) -> Result<Response<Body>, String> {
// Process error.
Err(msg) => {
if msg == "quarantined" {
if msg == "quarantined" || msg == "gated" {
let sub = req.param("sub").unwrap_or_default();
quarantine(req, sub)
quarantine(req, sub, msg)
} else {
error(req, msg).await
}

View File

@ -139,6 +139,7 @@ impl InstanceInfo {
["Blur NSFW", &convert(&self.config.default_blur_nsfw)],
["Use HLS", &convert(&self.config.default_use_hls)],
["Hide HLS notification", &convert(&self.config.default_hide_hls_notification)],
["Subscriptions", &convert(&self.config.default_subscriptions)],
])
.with_header_row(["Default preferences"]),
);
@ -153,10 +154,10 @@ impl InstanceInfo {
Deploy date: {}\n
Deploy timestamp: {}\n
Compile mode: {}\n
SFW only: {:?}\n
Config:\n
Banner: {:?}\n
Hide awards: {:?}\n
SFW only: {:?}\n
Default theme: {:?}\n
Default front page: {:?}\n
Default layout: {:?}\n
@ -166,15 +167,16 @@ impl InstanceInfo {
Default show NSFW: {:?}\n
Default blur NSFW: {:?}\n
Default use HLS: {:?}\n
Default hide HLS notification: {:?}\n",
Default hide HLS notification: {:?}\n
Default subscriptions: {:?}\n",
self.crate_version,
self.git_commit,
self.deploy_date,
self.deploy_unix_ts,
self.compile_mode,
self.config.sfw_only,
self.config.banner,
self.config.default_hide_awards,
self.config.sfw_only,
self.config.default_theme,
self.config.default_front_page,
self.config.default_layout,
@ -184,7 +186,8 @@ impl InstanceInfo {
self.config.default_show_nsfw,
self.config.default_blur_nsfw,
self.config.default_use_hls,
self.config.default_hide_hls_notification
self.config.default_hide_hls_notification,
self.config.default_subscriptions,
)
}
StringType::Html => self.to_table(),

View File

@ -161,7 +161,7 @@ async fn main() {
let mut app = server::Server::new();
// Force evaluation of statics. In instance_info case, we need to evaluate
// the timestamp so deploy date is accurate - in config case, we need to
// the timestamp so deploy date is accurate - in config case, we need to
// evaluate the configuration to avoid paying penalty at first request.
Lazy::force(&config::CONFIG);

View File

@ -78,9 +78,9 @@ pub async fn item(req: Request<Body>) -> Result<Response<Body>, String> {
}
// If the Reddit API returns an error, exit and send error page to user
Err(msg) => {
if msg == "quarantined" {
if msg == "quarantined" || msg == "gated" {
let sub = req.param("sub").unwrap_or_default();
quarantine(req, sub)
quarantine(req, sub, msg)
} else {
error(req, msg).await
}
@ -107,6 +107,13 @@ fn parse_comments(json: &serde_json::Value, post_link: &str, post_author: &str,
let score = data["score"].as_i64().unwrap_or(0);
// The JSON API only provides comments up to some threshold.
// Further comments have to be loaded by subsequent requests.
// The "kind" value will be "more" and the "count"
// shows how many more (sub-)comments exist in the respective nesting level.
// Note that in certain (seemingly random) cases, the count is simply wrong.
let more_count = data["count"].as_i64().unwrap_or_default();
// If this comment contains replies, handle those too
let replies: Vec<Comment> = if data["replies"].is_object() {
parse_comments(&data["replies"], post_link, post_author, highlighted_comment, filters, req)
@ -177,6 +184,7 @@ fn parse_comments(json: &serde_json::Value, post_link: &str, post_author: &str,
awards,
collapsed,
is_filtered,
more_count,
prefs: Preferences::new(req),
}
})

View File

@ -145,9 +145,9 @@ pub async fn find(req: Request<Body>) -> Result<Response<Body>, String> {
})
}
Err(msg) => {
if msg == "quarantined" {
if msg == "quarantined" || msg == "gated" {
let sub = req.param("sub").unwrap_or_default();
quarantine(req, sub)
quarantine(req, sub, msg)
} else {
error(req, msg).await
}

View File

@ -144,7 +144,7 @@ pub async fn community(req: Request<Body>) -> Result<Response<Body>, String> {
})
}
Err(msg) => match msg.as_str() {
"quarantined" => quarantine(req, sub_name),
"quarantined" | "gated" => quarantine(req, sub_name, msg),
"private" => error(req, format!("r/{} is a private community", sub_name)).await,
"banned" => error(req, format!("r/{} has been banned from Reddit", sub_name)).await,
_ => error(req, msg).await,
@ -153,9 +153,9 @@ pub async fn community(req: Request<Body>) -> Result<Response<Body>, String> {
}
}
pub fn quarantine(req: Request<Body>, sub: String) -> Result<Response<Body>, String> {
pub fn quarantine(req: Request<Body>, sub: String, restriction: String) -> Result<Response<Body>, String> {
let wall = WallTemplate {
title: format!("r/{} is quarantined", sub),
title: format!("r/{} is {}", sub, restriction),
msg: "Please click the button below to continue to this subreddit.".to_string(),
url: req.uri().to_string(),
sub,
@ -323,8 +323,8 @@ pub async fn wiki(req: Request<Body>) -> Result<Response<Body>, String> {
url,
}),
Err(msg) => {
if msg == "quarantined" {
quarantine(req, sub)
if msg == "quarantined" || msg == "gated" {
quarantine(req, sub, msg)
} else {
error(req, msg).await
}
@ -361,8 +361,8 @@ pub async fn sidebar(req: Request<Body>) -> Result<Response<Body>, String> {
url,
}),
Err(msg) => {
if msg == "quarantined" {
quarantine(req, sub)
if msg == "quarantined" || msg == "gated" {
quarantine(req, sub, msg)
} else {
error(req, msg).await
}

View File

@ -204,10 +204,17 @@ impl GalleryMedia {
// For each image in gallery
let media_id = item["media_id"].as_str().unwrap_or_default();
let image = &metadata[media_id]["s"];
let image_type = &metadata[media_id]["m"];
let url = if image_type == "image/gif" {
image["gif"].as_str().unwrap_or_default()
} else {
image["u"].as_str().unwrap_or_default()
};
// Construct gallery items
Self {
url: format_url(image["u"].as_str().unwrap_or_default()),
url: format_url(url),
width: image["x"].as_i64().unwrap_or_default(),
height: image["y"].as_i64().unwrap_or_default(),
caption: item["caption"].as_str().unwrap_or_default().to_string(),
@ -370,6 +377,7 @@ pub struct Comment {
pub awards: Awards,
pub collapsed: bool,
pub is_filtered: bool,
pub more_count: i64,
pub prefs: Preferences,
}

View File

@ -26,6 +26,8 @@
--popup-goback-background: var(--popup-red);
--popup-goback-text: #222;
--popup-border: 1px solid var(--popup-red);
--footer-height: 30px;
}
@font-face {
@ -99,6 +101,9 @@ body {
background: var(--background);
font-size: 15px;
padding-top: 60px;
padding-bottom: var(--footer-height);
min-height: calc(100vh - 60px);
position: relative;
}
nav {
@ -142,12 +147,6 @@ nav #links svg {
display: none;
}
nav #version {
opacity: 50%;
vertical-align: -2px;
margin-right: 10px;
}
nav #libreddit {
vertical-align: -2px;
}
@ -270,6 +269,7 @@ main {
max-width: 1000px;
padding: 10px 20px;
margin: 0 auto;
padding-bottom: 4em;
}
.wide main {
@ -292,22 +292,22 @@ main {
body > footer {
display: flex;
justify-content: center;
margin: 20px;
align-items: center;
width: 100vw;
background: var(--post);
position: absolute;
bottom: 0;
}
.info-button {
.footer-button {
align-items: center;
border-radius: .25rem;
box-sizing: border-box;
color: var(--text);
cursor: pointer;
display: inline-flex;
font-size: 150%;
padding: 0.5em;
}
.info-button > a:hover {
text-decoration: none;
padding-left: 1em;
opacity: 0.8;
}
/* / Body footer. */
@ -1508,7 +1508,10 @@ td, th {
/* Mobile */
@media screen and (max-width: 800px) {
body { padding-top: 120px }
body {
padding-top: 120px;
padding-bottom: var(--footer-height);
}
main {
flex-direction: column-reverse;
@ -1550,8 +1553,10 @@ td, th {
}
@media screen and (max-width: 480px) {
body { padding-top: 100px; }
#version { display: none; }
body {
padding-top: 100px;
padding-bottom: var(--footer-height);
}
.post {
grid-template: "post_header post_header post_thumbnail" auto
@ -1613,10 +1618,9 @@ td, th {
.popup {
width: auto;
bottom: 10vh;
}
.popup-inner > a, h1, p, img {
width: 100%;
.popup-inner {
max-width: 80%;
}
}
}

View File

@ -32,7 +32,6 @@
<nav>
<div id="logo">
<a id="libreddit" href="/"><span id="lib">lib</span><span id="reddit">reddit.</span></a>
<span id="version">v{{ env!("CARGO_PKG_VERSION") }}</span>
{% block subscriptions %}{% endblock %}
</div>
{% block search %}{% endblock %}
@ -54,13 +53,6 @@
<circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/>
</svg>
</a>
<a id="code" href="https://github.com/libreddit/libreddit" target="_blank" rel="noopener noreferrer">
<span>code</span>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<title>code</title>
<polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/>
</svg>
</a>
</div>
</nav>
@ -71,10 +63,16 @@
{% endblock %}
</main>
{% endblock %}
<!-- FOOTER -->
{% block footer %}
<footer>
<div class="info-button">
<a href="/info" title="View instance information">&#x24D8;</a>
<p id="version">v{{ env!("CARGO_PKG_VERSION") }}</p>
<div class="footer-button">
<a href="/info" title="View instance information">ⓘ View instance info</a>
</div>
<div class="footer-button">
<a href="https://github.com/libreddit/libreddit" title="View code on GitHub">&lt;&gt; Code</a>
</div>
</footer>
{% endblock %}

View File

@ -1,7 +1,7 @@
{% import "utils.html" as utils %}
{% if kind == "more" && parent_kind == "t1" %}
<a class="deeper_replies" href="{{ post_link }}{{ parent_id }}">&rarr; More replies</a>
<a class="deeper_replies" href="{{ post_link }}{{ parent_id }}">&rarr; More replies ({{ more_count }})</a>
{% else if kind == "t1" %}
<div id="{{ id }}" class="comment">
<div class="comment_left">

View File

@ -99,13 +99,13 @@
{% if params.typed != "sr_user" %}
<footer>
{% if params.before != "" %}
<a href="?q={{ params.q }}&restrict_sr={{ params.restrict_sr }}
<a href="?q={{ params.q|safe }}&restrict_sr={{ params.restrict_sr }}
&sort={{ params.sort }}&t={{ params.t }}
&before={{ params.before }}" accesskey="P">PREV</a>
{% endif %}
{% if params.after != "" %}
<a href="?q={{ params.q }}&restrict_sr={{ params.restrict_sr }}
<a href="?q={{ params.q|safe }}&restrict_sr={{ params.restrict_sr }}
&sort={{ params.sort }}&t={{ params.t }}
&after={{ params.after }}" accesskey="N">NEXT</a>
{% endif %}