Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
f62f7bf200 | |||
aece392a86 | |||
aeeb066e47 | |||
51cdf574f7 | |||
af6722c053 | |||
412ce8f1f3 | |||
dfa57c890d | |||
01f9907aaf | |||
bf19ff513f | |||
ffc9ca2e98 | |||
cef9266648 | |||
d3b4f4e379 | |||
b90b41c009 | |||
0eccb9bcf2 | |||
eb07a2ce7c | |||
0b39d4f059 | |||
58fa213be8 | |||
5e03d701e4 | |||
e3df3a9470 | |||
35504eda14 |
4
CREDITS
4
CREDITS
@ -21,6 +21,7 @@ Daniel Valentine <daniel@vielle.ws>
|
|||||||
dbrennand <52419383+dbrennand@users.noreply.github.com>
|
dbrennand <52419383+dbrennand@users.noreply.github.com>
|
||||||
dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
|
dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
|
||||||
Diego Magdaleno <38844659+DiegoMagdaleno@users.noreply.github.com>
|
Diego Magdaleno <38844659+DiegoMagdaleno@users.noreply.github.com>
|
||||||
|
domve <domve@posteo.net>
|
||||||
Dyras <jevwmguf@duck.com>
|
Dyras <jevwmguf@duck.com>
|
||||||
Edward <101938856+EdwardLangdon@users.noreply.github.com>
|
Edward <101938856+EdwardLangdon@users.noreply.github.com>
|
||||||
elliot <75391956+ellieeet123@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>
|
Nick Lowery <ClockVapor@users.noreply.github.com>
|
||||||
Nico <github@dr460nf1r3.org>
|
Nico <github@dr460nf1r3.org>
|
||||||
NKIPSC <15067635+NKIPSC@users.noreply.github.com>
|
NKIPSC <15067635+NKIPSC@users.noreply.github.com>
|
||||||
|
o69mar <119129086+o69mar@users.noreply.github.com>
|
||||||
obeho <71698631+obeho@users.noreply.github.com>
|
obeho <71698631+obeho@users.noreply.github.com>
|
||||||
obscurity <z@x4.pm>
|
obscurity <z@x4.pm>
|
||||||
Om G <34579088+OxyMagnesium@users.noreply.github.com>
|
Om G <34579088+OxyMagnesium@users.noreply.github.com>
|
||||||
|
pin <90570748+0323pin@users.noreply.github.com>
|
||||||
potatoesAreGod <118043038+potatoesAreGod@users.noreply.github.com>
|
potatoesAreGod <118043038+potatoesAreGod@users.noreply.github.com>
|
||||||
RiversideRocks <59586759+RiversideRocks@users.noreply.github.com>
|
RiversideRocks <59586759+RiversideRocks@users.noreply.github.com>
|
||||||
robin <8597693+robrobinbin@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>
|
Vladislav Nepogodin <nepogodin.vlad@gmail.com>
|
||||||
Walkx <walkxnl@gmail.com>
|
Walkx <walkxnl@gmail.com>
|
||||||
Wichai <1482605+Chengings@users.noreply.github.com>
|
Wichai <1482605+Chengings@users.noreply.github.com>
|
||||||
|
wsy2220 <wsy@dogben.com>
|
||||||
xatier <xatierlike@gmail.com>
|
xatier <xatierlike@gmail.com>
|
||||||
Zach <72994911+zachjmurphy@users.noreply.github.com>
|
Zach <72994911+zachjmurphy@users.noreply.github.com>
|
||||||
|
103
Cargo.lock
generated
103
Cargo.lock
generated
@ -336,6 +336,27 @@ dependencies = [
|
|||||||
"crypto-common",
|
"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]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "1.8.0"
|
version = "1.8.0"
|
||||||
@ -624,6 +645,16 @@ dependencies = [
|
|||||||
"cfg-if",
|
"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]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.5"
|
version = "1.0.5"
|
||||||
@ -673,7 +704,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libreddit"
|
name = "libreddit"
|
||||||
version = "0.29.2"
|
version = "0.30.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"askama",
|
"askama",
|
||||||
"brotli",
|
"brotli",
|
||||||
@ -701,6 +732,12 @@ dependencies = [
|
|||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-raw-sys"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lipsum"
|
name = "lipsum"
|
||||||
version = "0.8.2"
|
version = "0.8.2"
|
||||||
@ -767,7 +804,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"wasi",
|
"wasi",
|
||||||
"windows-sys",
|
"windows-sys 0.42.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -843,7 +880,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"windows-sys",
|
"windows-sys 0.42.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -950,15 +987,6 @@ version = "0.6.28"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
|
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]]
|
[[package]]
|
||||||
name = "ring"
|
name = "ring"
|
||||||
version = "0.16.20"
|
version = "0.16.20"
|
||||||
@ -1021,6 +1049,20 @@ dependencies = [
|
|||||||
"walkdir",
|
"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]]
|
[[package]]
|
||||||
name = "rustls"
|
name = "rustls"
|
||||||
version = "0.20.8"
|
version = "0.20.8"
|
||||||
@ -1087,7 +1129,7 @@ version = "0.1.21"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3"
|
checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys",
|
"windows-sys 0.42.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1265,16 +1307,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.3.0"
|
version = "3.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
|
checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"libc",
|
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"remove_dir_all",
|
"rustix",
|
||||||
"winapi",
|
"windows-sys 0.42.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1358,7 +1399,7 @@ dependencies = [
|
|||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tokio-macros",
|
"tokio-macros",
|
||||||
"windows-sys",
|
"windows-sys 0.42.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1665,6 +1706,30 @@ dependencies = [
|
|||||||
"windows_x86_64_msvc",
|
"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]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "windows_aarch64_gnullvm"
|
||||||
version = "0.42.1"
|
version = "0.42.1"
|
||||||
|
@ -3,7 +3,7 @@ name = "libreddit"
|
|||||||
description = " Alternative private front-end to Reddit"
|
description = " Alternative private front-end to Reddit"
|
||||||
license = "AGPL-3.0"
|
license = "AGPL-3.0"
|
||||||
repository = "https://github.com/spikecodes/libreddit"
|
repository = "https://github.com/spikecodes/libreddit"
|
||||||
version = "0.29.2"
|
version = "0.30.1"
|
||||||
authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"]
|
authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
35
README.md
35
README.md
@ -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.
|
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
|
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).
|
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**
|
> **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.
|
> 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` |
|
| `USE_HLS` | `["on", "off"]` | `off` |
|
||||||
| `HIDE_HLS_NOTIFICATION` | `["on", "off"]` | `off` |
|
| `HIDE_HLS_NOTIFICATION` | `["on", "off"]` | `off` |
|
||||||
| `AUTOPLAY_VIDEOS` | `["on", "off"]` | `off` |
|
| `AUTOPLAY_VIDEOS` | `["on", "off"]` | `off` |
|
||||||
|
| `SUBSCRIPTIONS` | `+`-delimited list of subreddits (`sub1+sub2+sub3+...`) | _(none)_ |
|
||||||
| `HIDE_AWARDS` | `["on", "off"]` | `off`
|
| `HIDE_AWARDS` | `["on", "off"]` | `off`
|
||||||
| `DISABLE_VISIT_REDDIT_CONFIRMATION` | `["on", "off"]` | `off` |
|
| `DISABLE_VISIT_REDDIT_CONFIRMATION` | `["on", "off"]` | `off` |
|
||||||
|
|
||||||
|
3
app.json
3
app.json
@ -50,6 +50,9 @@
|
|||||||
"LIBREDDIT_BANNER": {
|
"LIBREDDIT_BANNER": {
|
||||||
"required": false
|
"required": false
|
||||||
},
|
},
|
||||||
|
"LIBREDDIT_DEFAULT_SUBSCRIPTIONS": {
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
"LIBREDDIT_DEFAULT_DISABLE_VISIT_REDDIT_CONFIRMATION": {
|
"LIBREDDIT_DEFAULT_DISABLE_VISIT_REDDIT_CONFIRMATION": {
|
||||||
"required": false
|
"required": false
|
||||||
}
|
}
|
||||||
|
8
build.rs
8
build.rs
@ -1,7 +1,13 @@
|
|||||||
use std::{
|
use std::{
|
||||||
os::unix::process::ExitStatusExt,
|
|
||||||
process::{Command, ExitStatus, Output},
|
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() {
|
fn main() {
|
||||||
let output = String::from_utf8(
|
let output = String::from_utf8(
|
||||||
Command::new("git")
|
Command::new("git")
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
use cached::proc_macro::cached;
|
use cached::proc_macro::cached;
|
||||||
use futures_lite::{future::Boxed, FutureExt};
|
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 libflate::gzip;
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
use percent_encoding::{percent_encode, CONTROLS};
|
use percent_encoding::{percent_encode, CONTROLS};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::{io, result::Result};
|
use std::{io, result::Result};
|
||||||
@ -11,6 +14,11 @@ use crate::server::RequestExt;
|
|||||||
|
|
||||||
const REDDIT_URL_BASE: &str = "https://www.reddit.com";
|
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
|
/// 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`.
|
/// 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).
|
// First parameter is target URL (mandatory).
|
||||||
let uri = url.parse::<Uri>().map_err(|_| "Couldn't parse URL".to_string())?;
|
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.
|
// 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);
|
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.
|
// Build Reddit URL from path.
|
||||||
let url = format!("{}{}", REDDIT_URL_BASE, 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.
|
// 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.
|
// Build request to Reddit. When making a GET, request gzip compression.
|
||||||
// (Reddit doesn't do brotli yet.)
|
// (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-Encoding", if method == Method::GET { "gzip" } else { "identity" })
|
||||||
.header("Accept-Language", "en-US,en;q=0.5")
|
.header("Accept-Language", "en-US,en;q=0.5")
|
||||||
.header("Connection", "keep-alive")
|
.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());
|
.body(Body::empty());
|
||||||
|
|
||||||
async move {
|
async move {
|
||||||
|
@ -52,6 +52,12 @@ pub struct Config {
|
|||||||
#[serde(rename = "LIBREDDIT_DEFAULT_HIDE_AWARDS")]
|
#[serde(rename = "LIBREDDIT_DEFAULT_HIDE_AWARDS")]
|
||||||
pub(crate) default_hide_awards: Option<String>,
|
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")]
|
#[serde(rename = "LIBREDDIT_BANNER")]
|
||||||
pub(crate) banner: Option<String>,
|
pub(crate) banner: Option<String>,
|
||||||
}
|
}
|
||||||
@ -81,6 +87,8 @@ impl Config {
|
|||||||
default_use_hls: parse("LIBREDDIT_DEFAULT_USE_HLS"),
|
default_use_hls: parse("LIBREDDIT_DEFAULT_USE_HLS"),
|
||||||
default_hide_hls_notification: parse("LIBREDDIT_DEFAULT_HIDE_HLS"),
|
default_hide_hls_notification: parse("LIBREDDIT_DEFAULT_HIDE_HLS"),
|
||||||
default_hide_awards: parse("LIBREDDIT_DEFAULT_HIDE_AWARDS"),
|
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"),
|
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_HIDE_HLS_NOTIFICATION" => config.default_hide_hls_notification.clone(),
|
||||||
"LIBREDDIT_DEFAULT_WIDE" => config.default_wide.clone(),
|
"LIBREDDIT_DEFAULT_WIDE" => config.default_wide.clone(),
|
||||||
"LIBREDDIT_DEFAULT_HIDE_AWARDS" => config.default_hide_awards.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(),
|
"LIBREDDIT_BANNER" => config.banner.clone(),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
@ -142,3 +152,8 @@ fn test_alt_env_config_precedence() {
|
|||||||
write("libreddit.toml", config_to_write).unwrap();
|
write("libreddit.toml", config_to_write).unwrap();
|
||||||
assert_eq!(get_setting("LIBREDDIT_DEFAULT_COMMENT_SORT"), Some("top".into()))
|
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()));
|
||||||
|
}
|
||||||
|
@ -210,9 +210,9 @@ pub async fn item(req: Request<Body>) -> Result<Response<Body>, String> {
|
|||||||
|
|
||||||
// Process error.
|
// Process error.
|
||||||
Err(msg) => {
|
Err(msg) => {
|
||||||
if msg == "quarantined" {
|
if msg == "quarantined" || msg == "gated" {
|
||||||
let sub = req.param("sub").unwrap_or_default();
|
let sub = req.param("sub").unwrap_or_default();
|
||||||
quarantine(req, sub)
|
quarantine(req, sub, msg)
|
||||||
} else {
|
} else {
|
||||||
error(req, msg).await
|
error(req, msg).await
|
||||||
}
|
}
|
||||||
|
@ -139,6 +139,7 @@ impl InstanceInfo {
|
|||||||
["Blur NSFW", &convert(&self.config.default_blur_nsfw)],
|
["Blur NSFW", &convert(&self.config.default_blur_nsfw)],
|
||||||
["Use HLS", &convert(&self.config.default_use_hls)],
|
["Use HLS", &convert(&self.config.default_use_hls)],
|
||||||
["Hide HLS notification", &convert(&self.config.default_hide_hls_notification)],
|
["Hide HLS notification", &convert(&self.config.default_hide_hls_notification)],
|
||||||
|
["Subscriptions", &convert(&self.config.default_subscriptions)],
|
||||||
])
|
])
|
||||||
.with_header_row(["Default preferences"]),
|
.with_header_row(["Default preferences"]),
|
||||||
);
|
);
|
||||||
@ -153,10 +154,10 @@ impl InstanceInfo {
|
|||||||
Deploy date: {}\n
|
Deploy date: {}\n
|
||||||
Deploy timestamp: {}\n
|
Deploy timestamp: {}\n
|
||||||
Compile mode: {}\n
|
Compile mode: {}\n
|
||||||
|
SFW only: {:?}\n
|
||||||
Config:\n
|
Config:\n
|
||||||
Banner: {:?}\n
|
Banner: {:?}\n
|
||||||
Hide awards: {:?}\n
|
Hide awards: {:?}\n
|
||||||
SFW only: {:?}\n
|
|
||||||
Default theme: {:?}\n
|
Default theme: {:?}\n
|
||||||
Default front page: {:?}\n
|
Default front page: {:?}\n
|
||||||
Default layout: {:?}\n
|
Default layout: {:?}\n
|
||||||
@ -166,15 +167,16 @@ impl InstanceInfo {
|
|||||||
Default show NSFW: {:?}\n
|
Default show NSFW: {:?}\n
|
||||||
Default blur NSFW: {:?}\n
|
Default blur NSFW: {:?}\n
|
||||||
Default use HLS: {:?}\n
|
Default use HLS: {:?}\n
|
||||||
Default hide HLS notification: {:?}\n",
|
Default hide HLS notification: {:?}\n
|
||||||
|
Default subscriptions: {:?}\n",
|
||||||
self.crate_version,
|
self.crate_version,
|
||||||
self.git_commit,
|
self.git_commit,
|
||||||
self.deploy_date,
|
self.deploy_date,
|
||||||
self.deploy_unix_ts,
|
self.deploy_unix_ts,
|
||||||
self.compile_mode,
|
self.compile_mode,
|
||||||
|
self.config.sfw_only,
|
||||||
self.config.banner,
|
self.config.banner,
|
||||||
self.config.default_hide_awards,
|
self.config.default_hide_awards,
|
||||||
self.config.sfw_only,
|
|
||||||
self.config.default_theme,
|
self.config.default_theme,
|
||||||
self.config.default_front_page,
|
self.config.default_front_page,
|
||||||
self.config.default_layout,
|
self.config.default_layout,
|
||||||
@ -184,7 +186,8 @@ impl InstanceInfo {
|
|||||||
self.config.default_show_nsfw,
|
self.config.default_show_nsfw,
|
||||||
self.config.default_blur_nsfw,
|
self.config.default_blur_nsfw,
|
||||||
self.config.default_use_hls,
|
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(),
|
StringType::Html => self.to_table(),
|
||||||
|
@ -161,7 +161,7 @@ async fn main() {
|
|||||||
let mut app = server::Server::new();
|
let mut app = server::Server::new();
|
||||||
|
|
||||||
// Force evaluation of statics. In instance_info case, we need to evaluate
|
// 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.
|
// evaluate the configuration to avoid paying penalty at first request.
|
||||||
|
|
||||||
Lazy::force(&config::CONFIG);
|
Lazy::force(&config::CONFIG);
|
||||||
|
12
src/post.rs
12
src/post.rs
@ -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
|
// If the Reddit API returns an error, exit and send error page to user
|
||||||
Err(msg) => {
|
Err(msg) => {
|
||||||
if msg == "quarantined" {
|
if msg == "quarantined" || msg == "gated" {
|
||||||
let sub = req.param("sub").unwrap_or_default();
|
let sub = req.param("sub").unwrap_or_default();
|
||||||
quarantine(req, sub)
|
quarantine(req, sub, msg)
|
||||||
} else {
|
} else {
|
||||||
error(req, msg).await
|
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);
|
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
|
// If this comment contains replies, handle those too
|
||||||
let replies: Vec<Comment> = if data["replies"].is_object() {
|
let replies: Vec<Comment> = if data["replies"].is_object() {
|
||||||
parse_comments(&data["replies"], post_link, post_author, highlighted_comment, filters, req)
|
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,
|
awards,
|
||||||
collapsed,
|
collapsed,
|
||||||
is_filtered,
|
is_filtered,
|
||||||
|
more_count,
|
||||||
prefs: Preferences::new(req),
|
prefs: Preferences::new(req),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -145,9 +145,9 @@ pub async fn find(req: Request<Body>) -> Result<Response<Body>, String> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
Err(msg) => {
|
Err(msg) => {
|
||||||
if msg == "quarantined" {
|
if msg == "quarantined" || msg == "gated" {
|
||||||
let sub = req.param("sub").unwrap_or_default();
|
let sub = req.param("sub").unwrap_or_default();
|
||||||
quarantine(req, sub)
|
quarantine(req, sub, msg)
|
||||||
} else {
|
} else {
|
||||||
error(req, msg).await
|
error(req, msg).await
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,7 @@ pub async fn community(req: Request<Body>) -> Result<Response<Body>, String> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
Err(msg) => match msg.as_str() {
|
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,
|
"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,
|
"banned" => error(req, format!("r/{} has been banned from Reddit", sub_name)).await,
|
||||||
_ => error(req, msg).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 {
|
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(),
|
msg: "Please click the button below to continue to this subreddit.".to_string(),
|
||||||
url: req.uri().to_string(),
|
url: req.uri().to_string(),
|
||||||
sub,
|
sub,
|
||||||
@ -323,8 +323,8 @@ pub async fn wiki(req: Request<Body>) -> Result<Response<Body>, String> {
|
|||||||
url,
|
url,
|
||||||
}),
|
}),
|
||||||
Err(msg) => {
|
Err(msg) => {
|
||||||
if msg == "quarantined" {
|
if msg == "quarantined" || msg == "gated" {
|
||||||
quarantine(req, sub)
|
quarantine(req, sub, msg)
|
||||||
} else {
|
} else {
|
||||||
error(req, msg).await
|
error(req, msg).await
|
||||||
}
|
}
|
||||||
@ -361,8 +361,8 @@ pub async fn sidebar(req: Request<Body>) -> Result<Response<Body>, String> {
|
|||||||
url,
|
url,
|
||||||
}),
|
}),
|
||||||
Err(msg) => {
|
Err(msg) => {
|
||||||
if msg == "quarantined" {
|
if msg == "quarantined" || msg == "gated" {
|
||||||
quarantine(req, sub)
|
quarantine(req, sub, msg)
|
||||||
} else {
|
} else {
|
||||||
error(req, msg).await
|
error(req, msg).await
|
||||||
}
|
}
|
||||||
|
10
src/utils.rs
10
src/utils.rs
@ -204,10 +204,17 @@ impl GalleryMedia {
|
|||||||
// For each image in gallery
|
// For each image in gallery
|
||||||
let media_id = item["media_id"].as_str().unwrap_or_default();
|
let media_id = item["media_id"].as_str().unwrap_or_default();
|
||||||
let image = &metadata[media_id]["s"];
|
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
|
// Construct gallery items
|
||||||
Self {
|
Self {
|
||||||
url: format_url(image["u"].as_str().unwrap_or_default()),
|
url: format_url(url),
|
||||||
width: image["x"].as_i64().unwrap_or_default(),
|
width: image["x"].as_i64().unwrap_or_default(),
|
||||||
height: image["y"].as_i64().unwrap_or_default(),
|
height: image["y"].as_i64().unwrap_or_default(),
|
||||||
caption: item["caption"].as_str().unwrap_or_default().to_string(),
|
caption: item["caption"].as_str().unwrap_or_default().to_string(),
|
||||||
@ -370,6 +377,7 @@ pub struct Comment {
|
|||||||
pub awards: Awards,
|
pub awards: Awards,
|
||||||
pub collapsed: bool,
|
pub collapsed: bool,
|
||||||
pub is_filtered: bool,
|
pub is_filtered: bool,
|
||||||
|
pub more_count: i64,
|
||||||
pub prefs: Preferences,
|
pub prefs: Preferences,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,8 @@
|
|||||||
--popup-goback-background: var(--popup-red);
|
--popup-goback-background: var(--popup-red);
|
||||||
--popup-goback-text: #222;
|
--popup-goback-text: #222;
|
||||||
--popup-border: 1px solid var(--popup-red);
|
--popup-border: 1px solid var(--popup-red);
|
||||||
|
|
||||||
|
--footer-height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
@ -99,6 +101,9 @@ body {
|
|||||||
background: var(--background);
|
background: var(--background);
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
padding-top: 60px;
|
padding-top: 60px;
|
||||||
|
padding-bottom: var(--footer-height);
|
||||||
|
min-height: calc(100vh - 60px);
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
nav {
|
nav {
|
||||||
@ -142,12 +147,6 @@ nav #links svg {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
nav #version {
|
|
||||||
opacity: 50%;
|
|
||||||
vertical-align: -2px;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav #libreddit {
|
nav #libreddit {
|
||||||
vertical-align: -2px;
|
vertical-align: -2px;
|
||||||
}
|
}
|
||||||
@ -270,6 +269,7 @@ main {
|
|||||||
max-width: 1000px;
|
max-width: 1000px;
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
padding-bottom: 4em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wide main {
|
.wide main {
|
||||||
@ -292,22 +292,22 @@ main {
|
|||||||
body > footer {
|
body > footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin: 20px;
|
align-items: center;
|
||||||
|
width: 100vw;
|
||||||
|
background: var(--post);
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-button {
|
.footer-button {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-radius: .25rem;
|
border-radius: .25rem;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
font-size: 150%;
|
padding-left: 1em;
|
||||||
padding: 0.5em;
|
opacity: 0.8;
|
||||||
}
|
|
||||||
|
|
||||||
.info-button > a:hover {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* / Body footer. */
|
/* / Body footer. */
|
||||||
@ -1508,7 +1508,10 @@ td, th {
|
|||||||
/* Mobile */
|
/* Mobile */
|
||||||
|
|
||||||
@media screen and (max-width: 800px) {
|
@media screen and (max-width: 800px) {
|
||||||
body { padding-top: 120px }
|
body {
|
||||||
|
padding-top: 120px;
|
||||||
|
padding-bottom: var(--footer-height);
|
||||||
|
}
|
||||||
|
|
||||||
main {
|
main {
|
||||||
flex-direction: column-reverse;
|
flex-direction: column-reverse;
|
||||||
@ -1550,8 +1553,10 @@ td, th {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 480px) {
|
@media screen and (max-width: 480px) {
|
||||||
body { padding-top: 100px; }
|
body {
|
||||||
#version { display: none; }
|
padding-top: 100px;
|
||||||
|
padding-bottom: var(--footer-height);
|
||||||
|
}
|
||||||
|
|
||||||
.post {
|
.post {
|
||||||
grid-template: "post_header post_header post_thumbnail" auto
|
grid-template: "post_header post_header post_thumbnail" auto
|
||||||
@ -1613,10 +1618,9 @@ td, th {
|
|||||||
|
|
||||||
.popup {
|
.popup {
|
||||||
width: auto;
|
width: auto;
|
||||||
bottom: 10vh;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.popup-inner > a, h1, p, img {
|
.popup-inner {
|
||||||
width: 100%;
|
max-width: 80%;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -32,7 +32,6 @@
|
|||||||
<nav>
|
<nav>
|
||||||
<div id="logo">
|
<div id="logo">
|
||||||
<a id="libreddit" href="/"><span id="lib">lib</span><span id="reddit">reddit.</span></a>
|
<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 %}
|
{% block subscriptions %}{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
{% block search %}{% endblock %}
|
{% 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"/>
|
<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>
|
</svg>
|
||||||
</a>
|
</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>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
@ -71,10 +63,16 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
</main>
|
</main>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
<!-- FOOTER -->
|
||||||
{% block footer %}
|
{% block footer %}
|
||||||
<footer>
|
<footer>
|
||||||
<div class="info-button">
|
<p id="version">v{{ env!("CARGO_PKG_VERSION") }}</p>
|
||||||
<a href="/info" title="View instance information">ⓘ</a>
|
<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"><> Code</a>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{% import "utils.html" as utils %}
|
{% import "utils.html" as utils %}
|
||||||
|
|
||||||
{% if kind == "more" && parent_kind == "t1" %}
|
{% if kind == "more" && parent_kind == "t1" %}
|
||||||
<a class="deeper_replies" href="{{ post_link }}{{ parent_id }}">→ More replies</a>
|
<a class="deeper_replies" href="{{ post_link }}{{ parent_id }}">→ More replies ({{ more_count }})</a>
|
||||||
{% else if kind == "t1" %}
|
{% else if kind == "t1" %}
|
||||||
<div id="{{ id }}" class="comment">
|
<div id="{{ id }}" class="comment">
|
||||||
<div class="comment_left">
|
<div class="comment_left">
|
||||||
|
@ -99,13 +99,13 @@
|
|||||||
{% if params.typed != "sr_user" %}
|
{% if params.typed != "sr_user" %}
|
||||||
<footer>
|
<footer>
|
||||||
{% if params.before != "" %}
|
{% 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 }}
|
&sort={{ params.sort }}&t={{ params.t }}
|
||||||
&before={{ params.before }}" accesskey="P">PREV</a>
|
&before={{ params.before }}" accesskey="P">PREV</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if params.after != "" %}
|
{% 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 }}
|
&sort={{ params.sort }}&t={{ params.t }}
|
||||||
&after={{ params.after }}" accesskey="N">NEXT</a>
|
&after={{ params.after }}" accesskey="N">NEXT</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
Reference in New Issue
Block a user