Compare commits
28 Commits
a12596e1a2
...
v0.35.0
Author | SHA1 | Date | |
---|---|---|---|
ff2e274e5e | |||
7c821d541a | |||
7aca5791b1 | |||
8b3783096b | |||
59b702aa15 | |||
edf0109095 | |||
ecf0f91464 | |||
a5a5cbb734 | |||
5117af4137 | |||
394e975724 | |||
a67cbb99a6 | |||
ededa849f4 | |||
1d8b6f58fb | |||
4c6a71171b | |||
846377b586 | |||
2dbcc071a6 | |||
9a7da3abce | |||
7fa37e48d5 | |||
a6f901c094 | |||
afad65f204 | |||
c12da45059 | |||
1132d73975 | |||
8ece7562ec | |||
08e463fd44 | |||
ec11a5511b | |||
3caa0592f3 | |||
190c92339e | |||
17c7738d6e |
@ -14,6 +14,8 @@ REDLIB_PUSHSHIFT_FRONTEND=undelete.pullpush.io
|
||||
# Default user settings
|
||||
# Set the default theme (options: system, light, dark, black, dracula, nord, laserwave, violet, gold, rosebox, gruvboxdark, gruvboxlight)
|
||||
REDLIB_DEFAULT_THEME=system
|
||||
# Set the default mascot
|
||||
REDLIB_DEFAULT_MASCOT=none
|
||||
# Set the default front page (options: default, popular, all)
|
||||
REDLIB_DEFAULT_FRONT_PAGE=default
|
||||
# Set the default layout (options: card, clean, compact)
|
||||
|
3
.github/workflows/build-artifacts.yaml
vendored
3
.github/workflows/build-artifacts.yaml
vendored
@ -7,6 +7,8 @@ on:
|
||||
- "compose.*"
|
||||
branches:
|
||||
- "main"
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
@ -60,7 +62,6 @@ jobs:
|
||||
|
||||
- name: Upload release
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: github.base_ref != 'main' && github.event_name == 'release'
|
||||
with:
|
||||
tag_name: ${{ steps.version.outputs.VERSION }}
|
||||
name: ${{ steps.version.outputs.VERSION }} - ${{ github.event.head_commit.message }}
|
||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -2,3 +2,7 @@
|
||||
.env
|
||||
# Idea Files
|
||||
.idea/
|
||||
|
||||
# nix files
|
||||
.direnv/
|
||||
result
|
||||
|
37
CREDITS
37
CREDITS
@ -2,7 +2,9 @@
|
||||
674Y3r <87250374+674Y3r@users.noreply.github.com>
|
||||
accountForIssues <52367365+accountForIssues@users.noreply.github.com>
|
||||
Adrian Lebioda <adrianlebioda@gmail.com>
|
||||
Akanksh Chitimalla <55909985+Akanksh12@users.noreply.github.com>
|
||||
alefvanoon <53198048+alefvanoon@users.noreply.github.com>
|
||||
Ales Lerch <13370338+axeII@users.noreply.github.com>
|
||||
Alexandre Iooss <erdnaxe@crans.org>
|
||||
alyaeanyx <alexandra.hollmeier@mailbox.org>
|
||||
AndreVuillemot160 <84594011+AndreVuillemot160@users.noreply.github.com>
|
||||
@ -11,58 +13,90 @@ Artemis <51862164+artemislena@users.noreply.github.com>
|
||||
arthomnix <35371030+arthomnix@users.noreply.github.com>
|
||||
Arya K <73596856+gi-yt@users.noreply.github.com>
|
||||
Austin Huang <im@austinhuang.me>
|
||||
Ayaka <ayaka@kitty.community>
|
||||
backfire-monism-net <development.0extl@simplelogin.com>
|
||||
Basti <pred2k@users.noreply.github.com>
|
||||
Ben Sherman <bennettmsherman@gmail.com>
|
||||
Ben Smith <37027883+smithbm2316@users.noreply.github.com>
|
||||
beucismis <beucismis@tutamail.com>
|
||||
BobIsMyManager <ahoumatt@yahoo.com>
|
||||
Butter Cat <butteredcats@protonmail.com>
|
||||
Butter Cat <ButteredCats@protonmail.com>
|
||||
Carbrex <95964955+Carbrex@users.noreply.github.com>
|
||||
ccuser44 <68124053+ccuser44@users.noreply.github.com>
|
||||
Connor Holloway <c.holloway314@outlook.com>
|
||||
curlpipe <11898833+curlpipe@users.noreply.github.com>
|
||||
dacousb <53299044+dacousb@users.noreply.github.com>
|
||||
Daniel Nathan Gray <dng@disroot.org>
|
||||
Daniel Valentine <Daniel-Valentine@users.noreply.github.com>
|
||||
Daniel Valentine <daniel@vielle.ws>
|
||||
dbrennand <52419383+dbrennand@users.noreply.github.com>
|
||||
Dean Sallinen <deza604@gmail.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>
|
||||
Éli Marshal <835958+EMarshal@users.noreply.github.com>
|
||||
elliot <75391956+ellieeet123@users.noreply.github.com>
|
||||
erdnaxe <erdnaxe@users.noreply.github.com>
|
||||
Esmail EL BoB <github.defilable@simplelogin.co>
|
||||
fawn <fawn@envs.net>
|
||||
FireMasterK <20838718+FireMasterK@users.noreply.github.com>
|
||||
George Roubos <cowkingdom@hotmail.com>
|
||||
git-bruh <e817509a-8ee9-4332-b0ad-3a6bdf9ab63f@aleeas.com>
|
||||
gmnsii <95436780+gmnsii@users.noreply.github.com>
|
||||
gmnsii <github.gmnsii@pm.me>
|
||||
gmnsii <gmnsii@void.noreply>
|
||||
Gonçalo Valério <dethos@users.noreply.github.com>
|
||||
guaddy <67671414+guaddy@users.noreply.github.com>
|
||||
Harsh Mishra <erbeusgriffincasper@gmail.com>
|
||||
hinto.janai <hinto.janai@protonmail.com>
|
||||
igna <igna@intent.cool>
|
||||
imabritishcow <bcow@protonmail.com>
|
||||
invakid404 <invakid404@riseup.net>
|
||||
İsmail Karslı <ismail@karsli.net>
|
||||
Johannes Schleifenbaum <johannes@js-webcoding.de>
|
||||
Jonathan Dahan <git@jonathan.is>
|
||||
Josiah <70736638+fres7h@users.noreply.github.com>
|
||||
JPyke3 <pyke.jacob1@gmail.com>
|
||||
Kavin <20838718+FireMasterK@users.noreply.github.com>
|
||||
Kazi <kzshantonu@users.noreply.github.com>
|
||||
Kieran <42723993+EnderDev@users.noreply.github.com>
|
||||
Kieran <kieran@dothq.co>
|
||||
Kirk1984 <christoph-m@posteo.de>
|
||||
kuanhulio <66286575+kuanhulio@users.noreply.github.com>
|
||||
Kyle Roth <kylrth@gmail.com>
|
||||
laazyCmd <laazy.pr00gramming@protonmail.com>
|
||||
Laurențiu Nicola <lnicola@users.noreply.github.com>
|
||||
Lena <102762572+MarshDeer@users.noreply.github.com>
|
||||
Leopardus <leopardus3@pm.me>
|
||||
Macic <46872282+Macic-Dev@users.noreply.github.com>
|
||||
Mario A <10923513+Midblyte@users.noreply.github.com>
|
||||
Márton <marton2@gmail.com>
|
||||
Mathew Davies <ThePixelDeveloper@users.noreply.github.com>
|
||||
Matthew Crossman <matt@crossman.page>
|
||||
Matthew E <matt@matthew.science>
|
||||
Matthew Esposito <matt@matthew.science>
|
||||
Mennaruuk <52135169+Mennaruuk@users.noreply.github.com>
|
||||
Midou36O <midou@midou.dev>
|
||||
mikupls <93015331+mikupls@users.noreply.github.com>
|
||||
Myzel394 <50424412+Myzel394@users.noreply.github.com>
|
||||
Nainar <nainar.mb@gmail.com>
|
||||
Nathan Moos <moosingin3space@gmail.com>
|
||||
Nazar <63452145+Tokarak@users.noreply.github.com>
|
||||
Nicholas Christopher <nchristopher@tuta.io>
|
||||
Nick Lowery <ClockVapor@users.noreply.github.com>
|
||||
Nico <github@dr460nf1r3.org>
|
||||
NKIPSC <15067635+NKIPSC@users.noreply.github.com>
|
||||
nohoster <136514837+nohoster@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>
|
||||
Ondřej Pešek <iTzBoboCz@users.noreply.github.com>
|
||||
perennial <mail@perennialte.ch>
|
||||
Peter Sawyer <petersawyer314@gmail.com>
|
||||
pin <90570748+0323pin@users.noreply.github.com>
|
||||
potatoesAreGod <118043038+potatoesAreGod@users.noreply.github.com>
|
||||
RiversideRocks <59586759+RiversideRocks@users.noreply.github.com>
|
||||
@ -86,11 +120,14 @@ TheCultLeader666 <65368815+TheCultLeader666@users.noreply.github.com>
|
||||
TheFrenchGhosty <47571719+TheFrenchGhosty@users.noreply.github.com>
|
||||
The TwilightBlood <hwengerstickel@protonmail.com>
|
||||
tirz <36501933+tirz@users.noreply.github.com>
|
||||
tmak2002 <torben@tmak2002.dev>
|
||||
Tokarak <63452145+Tokarak@users.noreply.github.com>
|
||||
Tsvetomir Bonev <invakid404@riseup.net>
|
||||
Vivek <vivek@revankar.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>
|
||||
Yaroslav Chvanov <yaroslav.chvanov@gmail.com>
|
||||
Zach <72994911+zachjmurphy@users.noreply.github.com>
|
||||
|
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1041,7 +1041,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "redsunlib"
|
||||
version = "0.34.0"
|
||||
version = "0.35.0"
|
||||
dependencies = [
|
||||
"askama",
|
||||
"base64",
|
||||
|
@ -3,7 +3,7 @@ name = "redsunlib"
|
||||
description = " Alternative private front-end to Reddit"
|
||||
license = "AGPL-3.0"
|
||||
repository = "https://git.stardust.wtf/iridium/redlib"
|
||||
version = "0.34.0"
|
||||
version = "0.35.0"
|
||||
authors = [
|
||||
"Matthew Esposito <matt+cargo@matthew.science>",
|
||||
"spikecodes <19519553+spikecodes@users.noreply.github.com>",
|
||||
|
@ -181,12 +181,6 @@ docker logs -f redlib
|
||||
|
||||
### Docker CLI
|
||||
|
||||
> [!IMPORTANT]
|
||||
> If deploying on:
|
||||
>
|
||||
> - an `arm64` platform, use the `quay.io/redlib/redlib:latest-arm` image instead.
|
||||
> - an `armv7` platform, use the `quay.io/redlib/redlib:latest-armv7` image instead.
|
||||
|
||||
Deploy Redlib:
|
||||
|
||||
```bash
|
||||
|
106
flake.lock
generated
Normal file
106
flake.lock
generated
Normal file
@ -0,0 +1,106 @@
|
||||
{
|
||||
"nodes": {
|
||||
"crane": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1717025063,
|
||||
"narHash": "sha256-dIubLa56W9sNNz0e8jGxrX3CAkPXsq7snuFA/Ie6dn8=",
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"rev": "480dff0be03dac0e51a8dfc26e882b0d123a450e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1717112898,
|
||||
"narHash": "sha256-7R2ZvOnvd9h8fDd65p0JnB7wXfUvreox3xFdYWd1BnY=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "6132b0f6e344ce2fe34fc051b72fb46e34f668e0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"crane": "crane",
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-overlay": "rust-overlay"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"flake-utils": [
|
||||
"flake-utils"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1717121863,
|
||||
"narHash": "sha256-/3sxIe7MZqF/jw1RTQCSmgTjwVod43mmrk84m50MJQ4=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "2a7b53172ed08f856b8382d7dcfd36a4e0cbd866",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
71
flake.nix
Normal file
71
flake.nix
Normal file
@ -0,0 +1,71 @@
|
||||
{
|
||||
description = "Redlib: Private front-end for Reddit";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
|
||||
crane = {
|
||||
url = "github:ipetkov/crane";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
|
||||
rust-overlay = {
|
||||
url = "github:oxalica/rust-overlay";
|
||||
inputs = {
|
||||
nixpkgs.follows = "nixpkgs";
|
||||
flake-utils.follows = "flake-utils";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
outputs = { nixpkgs, crane, flake-utils, rust-overlay, ... }:
|
||||
flake-utils.lib.eachSystem [ "x86_64-linux" ] (system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [ (import rust-overlay) ];
|
||||
};
|
||||
|
||||
inherit (pkgs) lib;
|
||||
|
||||
rustToolchain = pkgs.rust-bin.stable.latest.default.override {
|
||||
targets = [ "x86_64-unknown-linux-musl" ];
|
||||
};
|
||||
|
||||
craneLib = (crane.mkLib pkgs).overrideToolchain rustToolchain;
|
||||
|
||||
|
||||
src = lib.cleanSourceWith {
|
||||
src = craneLib.path ./.;
|
||||
filter = path: type:
|
||||
(lib.hasInfix "/templates/" path) ||
|
||||
(lib.hasInfix "/static/" path) ||
|
||||
(craneLib.filterCargoSources path type);
|
||||
};
|
||||
|
||||
redlib = craneLib.buildPackage {
|
||||
inherit src;
|
||||
strictDeps = true;
|
||||
doCheck = false;
|
||||
|
||||
CARGO_BUILD_TARGET = "x86_64-unknown-linux-musl";
|
||||
CARGO_BUILD_RUSTFLAGS = "-C target-feature=+crt-static";
|
||||
};
|
||||
in
|
||||
{
|
||||
checks = {
|
||||
my-crate = redlib;
|
||||
};
|
||||
|
||||
packages.default = redlib;
|
||||
packages.docker = pkgs.dockerTools.buildImage {
|
||||
name = "quay.io/redlib/redlib";
|
||||
tag = "latest";
|
||||
created = "now";
|
||||
copyToRoot = with pkgs.dockerTools; [ caCertificates fakeNss ];
|
||||
config.Cmd = "${redlib}/bin/redlib";
|
||||
};
|
||||
});
|
||||
}
|
@ -28,6 +28,10 @@ pub struct Config {
|
||||
#[serde(alias = "LIBREDDIT_DEFAULT_THEME")]
|
||||
pub(crate) default_theme: Option<String>,
|
||||
|
||||
#[serde(rename = "REDLIB_DEFAULT_MASCOT")]
|
||||
#[serde(alias = "LIBREDDIT_DEFAULT_MASCOT")]
|
||||
pub(crate) default_mascot: Option<String>,
|
||||
|
||||
#[serde(rename = "REDLIB_DEFAULT_FRONT_PAGE")]
|
||||
#[serde(alias = "LIBREDDIT_DEFAULT_FRONT_PAGE")]
|
||||
pub(crate) default_front_page: Option<String>,
|
||||
@ -125,6 +129,7 @@ impl Config {
|
||||
Self {
|
||||
sfw_only: parse("REDLIB_SFW_ONLY"),
|
||||
default_theme: parse("REDLIB_DEFAULT_THEME"),
|
||||
default_mascot: parse("REDLIB_DEFAULT_MASCOT"),
|
||||
default_front_page: parse("REDLIB_DEFAULT_FRONT_PAGE"),
|
||||
default_layout: parse("REDLIB_DEFAULT_LAYOUT"),
|
||||
default_post_sort: parse("REDLIB_DEFAULT_POST_SORT"),
|
||||
@ -151,6 +156,7 @@ fn get_setting_from_config(name: &str, config: &Config) -> Option<String> {
|
||||
match name {
|
||||
"REDLIB_SFW_ONLY" => config.sfw_only.clone(),
|
||||
"REDLIB_DEFAULT_THEME" => config.default_theme.clone(),
|
||||
"REDLIB_DEFAULT_MASCOT" => config.default_mascot.clone(),
|
||||
"REDLIB_DEFAULT_FRONT_PAGE" => config.default_front_page.clone(),
|
||||
"REDLIB_DEFAULT_LAYOUT" => config.default_layout.clone(),
|
||||
"REDLIB_DEFAULT_COMMENT_SORT" => config.default_comment_sort.clone(),
|
||||
@ -162,7 +168,7 @@ fn get_setting_from_config(name: &str, config: &Config) -> Option<String> {
|
||||
"REDLIB_DEFAULT_HIDE_HLS_NOTIFICATION" => config.default_hide_hls_notification.clone(),
|
||||
"REDLIB_DEFAULT_WIDE" => config.default_wide.clone(),
|
||||
"REDLIB_DEFAULT_HIDE_AWARDS" => config.default_hide_awards.clone(),
|
||||
"REDLIB_DEFAULT_HIDE_SIDEBAR_AND_SUMMARY" => config.default_hide_awards.clone(),
|
||||
"REDLIB_DEFAULT_HIDE_SIDEBAR_AND_SUMMARY" => config.default_hide_sidebar_and_summary.clone(),
|
||||
"REDLIB_DEFAULT_HIDE_SCORE" => config.default_hide_score.clone(),
|
||||
"REDLIB_DEFAULT_SUBSCRIPTIONS" => config.default_subscriptions.clone(),
|
||||
"REDLIB_DEFAULT_DISABLE_VISIT_REDDIT_CONFIRMATION" => config.default_disable_visit_reddit_confirmation.clone(),
|
||||
|
@ -136,6 +136,7 @@ impl InstanceInfo {
|
||||
["Hide awards", &convert(&self.config.default_hide_awards)],
|
||||
["Hide score", &convert(&self.config.default_hide_score)],
|
||||
["Theme", &convert(&self.config.default_theme)],
|
||||
["Mascot", &convert(&self.config.default_mascot)],
|
||||
["Front page", &convert(&self.config.default_front_page)],
|
||||
["Layout", &convert(&self.config.default_layout)],
|
||||
["Wide", &convert(&self.config.default_wide)],
|
||||
@ -168,6 +169,7 @@ impl InstanceInfo {
|
||||
Hide awards: {:?}\n
|
||||
Hide score: {:?}\n
|
||||
Default theme: {:?}\n
|
||||
Default mascot: {:?}\n
|
||||
Default front page: {:?}\n
|
||||
Default layout: {:?}\n
|
||||
Default wide: {:?}\n
|
||||
@ -190,6 +192,7 @@ impl InstanceInfo {
|
||||
self.config.default_hide_awards,
|
||||
self.config.default_hide_score,
|
||||
self.config.default_theme,
|
||||
self.config.default_mascot,
|
||||
self.config.default_front_page,
|
||||
self.config.default_layout,
|
||||
self.config.default_wide,
|
||||
|
25
src/main.rs
25
src/main.rs
@ -26,7 +26,7 @@ use client::{canonical_path, proxy};
|
||||
use log::info;
|
||||
use once_cell::sync::Lazy;
|
||||
use server::RequestExt;
|
||||
use utils::{error, redirect, ThemeAssets};
|
||||
use utils::{error, redirect, ThemeAssets, MascotAssets};
|
||||
|
||||
use crate::client::OAUTH_CLIENT;
|
||||
|
||||
@ -122,6 +122,20 @@ async fn style() -> Result<Response<Body>, String> {
|
||||
)
|
||||
}
|
||||
|
||||
/// Serve mascot
|
||||
async fn mascot_image(req: Request<Body>) -> Result<Response<Body>, String> {
|
||||
let res = MascotAssets::get(&req.param("name").unwrap())
|
||||
.unwrap_or(MascotAssets::get("redsunlib.png").unwrap());
|
||||
Ok(
|
||||
Response::builder()
|
||||
.status(200)
|
||||
.header("content-type", "image/png")
|
||||
.header("Cache-Control", "public, max-age=1209600, s-maxage=86400")
|
||||
.body(res.data.into())
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
// Load environment variables
|
||||
@ -200,7 +214,7 @@ async fn main() {
|
||||
"Referrer-Policy" => "no-referrer",
|
||||
"X-Content-Type-Options" => "nosniff",
|
||||
"X-Frame-Options" => "DENY",
|
||||
"Content-Security-Policy" => "default-src 'none'; font-src 'self'; script-src 'self' blob:; manifest-src 'self'; media-src 'self' data: blob: about:; style-src 'self' 'unsafe-inline'; base-uri 'none'; img-src 'self' data:; form-action 'self'; frame-ancestors 'none'; connect-src 'self'; worker-src blob:;"
|
||||
"Content-Security-Policy" => "default-src 'none'; font-src 'self'; script-src 'self' 'wasm-unsafe-eval' blob:; manifest-src 'self'; media-src 'self' data: blob: about:; style-src 'self' 'unsafe-inline'; base-uri 'none'; img-src 'self' data:; form-action 'self'; frame-ancestors 'none'; connect-src 'self'; worker-src 'self' blob:;"
|
||||
};
|
||||
|
||||
if let Some(expire_time) = hsts {
|
||||
@ -235,8 +249,8 @@ async fn main() {
|
||||
app.at("/touch-icon-iphone.png").get(|_| iphone_logo().boxed());
|
||||
app.at("/apple-touch-icon.png").get(|_| iphone_logo().boxed());
|
||||
app
|
||||
.at("/playHLSVideo.js")
|
||||
.get(|_| resource(include_str!("../static/playHLSVideo.js"), "text/javascript", false).boxed());
|
||||
.at("/videoUtils.js")
|
||||
.get(|_| resource(include_str!("../static/videoUtils.js"), "text/javascript", false).boxed());
|
||||
app
|
||||
.at("/hls.min.js")
|
||||
.get(|_| resource(include_str!("../static/hls.min.js"), "text/javascript", false).boxed());
|
||||
@ -296,6 +310,9 @@ async fn main() {
|
||||
app.at("/settings/restore").get(|r| settings::restore(r).boxed());
|
||||
app.at("/settings/update").get(|r| settings::update(r).boxed());
|
||||
|
||||
// Mascots
|
||||
app.at("/mascot/:name").get(|r| mascot_image(r).boxed());
|
||||
|
||||
// Subreddit services
|
||||
app
|
||||
.at("/r/:sub")
|
||||
|
@ -19,8 +19,9 @@ struct SettingsTemplate {
|
||||
|
||||
// CONSTANTS
|
||||
|
||||
const PREFS: [&str; 17] = [
|
||||
const PREFS: [&str; 18] = [
|
||||
"theme",
|
||||
"mascot",
|
||||
"front_page",
|
||||
"layout",
|
||||
"wide",
|
||||
@ -82,7 +83,7 @@ pub async fn set(req: Request<Body>) -> Result<Response<Body>, String> {
|
||||
Some(value) => response.insert_cookie(
|
||||
Cookie::build((name.to_owned(), value.clone()))
|
||||
.path("/")
|
||||
.http_only(true)
|
||||
.http_only(name != "ffmpeg_video_downloads")
|
||||
.expires(OffsetDateTime::now_utc() + Duration::weeks(52))
|
||||
.into(),
|
||||
),
|
||||
|
16
src/utils.rs
16
src/utils.rs
@ -570,7 +570,9 @@ pub struct Params {
|
||||
#[derive(Default)]
|
||||
pub struct Preferences {
|
||||
pub available_themes: Vec<String>,
|
||||
pub available_mascots: Vec<String>,
|
||||
pub theme: String,
|
||||
pub mascot: String,
|
||||
pub front_page: String,
|
||||
pub layout: String,
|
||||
pub wide: String,
|
||||
@ -596,6 +598,11 @@ pub struct Preferences {
|
||||
#[include = "*.css"]
|
||||
pub struct ThemeAssets;
|
||||
|
||||
#[derive(RustEmbed)]
|
||||
#[folder = "static/mascots/"]
|
||||
#[include = "*.png"]
|
||||
pub struct MascotAssets;
|
||||
|
||||
impl Preferences {
|
||||
// Build preferences from cookies
|
||||
pub fn new(req: &Request<Body>) -> Self {
|
||||
@ -606,9 +613,18 @@ impl Preferences {
|
||||
let chunks: Vec<&str> = file.as_ref().split(".css").collect();
|
||||
themes.push(chunks[0].to_owned());
|
||||
}
|
||||
// Read available mascot names from embedded png files.
|
||||
// Always make default "none" option available.
|
||||
let mut mascots = vec!["none".to_string()];
|
||||
for file in MascotAssets::iter() {
|
||||
let chunks: Vec<&str> = file.as_ref().split(".png").collect();
|
||||
mascots.push(chunks[0].to_owned());
|
||||
}
|
||||
Self {
|
||||
available_themes: themes,
|
||||
available_mascots: mascots,
|
||||
theme: setting(req, "theme"),
|
||||
mascot: setting(req, "mascot"),
|
||||
front_page: setting(req, "front_page"),
|
||||
layout: setting(req, "layout"),
|
||||
wide: setting(req, "wide"),
|
||||
|
1
static/hls.min.js
vendored
1
static/hls.min.js
vendored
File diff suppressed because one or more lines are too long
BIN
static/mascots/BoymoderBlahaj.png
Normal file
BIN
static/mascots/BoymoderBlahaj.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.5 KiB |
BIN
static/mascots/redsunlib.png
Normal file
BIN
static/mascots/redsunlib.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.8 KiB |
@ -1,110 +0,0 @@
|
||||
// @license http://www.gnu.org/licenses/agpl-3.0.html AGPL-3.0
|
||||
(function () {
|
||||
if (Hls.isSupported()) {
|
||||
var videoSources = document.querySelectorAll("video source[type='application/vnd.apple.mpegurl']");
|
||||
videoSources.forEach(function (source) {
|
||||
var playlist = source.src;
|
||||
|
||||
var oldVideo = source.parentNode;
|
||||
var autoplay = oldVideo.classList.contains("hls_autoplay");
|
||||
|
||||
// If HLS is supported natively then don't use hls.js
|
||||
if (oldVideo.canPlayType(source.type) === "probably") {
|
||||
if (autoplay) {
|
||||
oldVideo.play();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Replace video with copy that will have all "source" elements removed
|
||||
var newVideo = oldVideo.cloneNode(true);
|
||||
var allSources = newVideo.querySelectorAll("source");
|
||||
allSources.forEach(function (source) {
|
||||
source.remove();
|
||||
});
|
||||
|
||||
// Empty source to enable play event
|
||||
newVideo.src = "about:blank";
|
||||
|
||||
oldVideo.parentNode.replaceChild(newVideo, oldVideo);
|
||||
|
||||
function initializeHls() {
|
||||
newVideo.removeEventListener('play', initializeHls);
|
||||
var hls = new Hls({ autoStartLoad: false });
|
||||
hls.loadSource(playlist);
|
||||
hls.attachMedia(newVideo);
|
||||
hls.on(Hls.Events.MANIFEST_PARSED, function () {
|
||||
hls.loadLevel = hls.levels.length - 1;
|
||||
var availableLevels = hls.levels.map(function(level) {
|
||||
return {
|
||||
height: level.height,
|
||||
width: level.width,
|
||||
bitrate: level.bitrate,
|
||||
};
|
||||
});
|
||||
|
||||
addQualitySelector(newVideo, hls, availableLevels);
|
||||
|
||||
hls.startLoad();
|
||||
newVideo.play();
|
||||
});
|
||||
|
||||
hls.on(Hls.Events.ERROR, function (event, data) {
|
||||
var errorType = data.type;
|
||||
var errorFatal = data.fatal;
|
||||
if (errorFatal) {
|
||||
switch (errorType) {
|
||||
case Hls.ErrorType.NETWORK_ERROR:
|
||||
hls.startLoad();
|
||||
break;
|
||||
case Hls.ErrorType.MEDIA_ERROR:
|
||||
hls.recoverMediaError();
|
||||
break;
|
||||
default:
|
||||
hls.destroy();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
console.error("HLS error", data);
|
||||
});
|
||||
}
|
||||
|
||||
function addQualitySelector(videoElement, hlsInstance, availableLevels) {
|
||||
var qualitySelector = document.createElement('select');
|
||||
qualitySelector.classList.add('quality-selector');
|
||||
var last = availableLevels.length - 1;
|
||||
availableLevels.forEach(function (level, index) {
|
||||
var option = document.createElement('option');
|
||||
option.value = index.toString();
|
||||
var bitrate = (level.bitrate / 1_000).toFixed(0);
|
||||
option.text = level.height + 'p (' + bitrate + ' kbps)';
|
||||
if (index === last) {
|
||||
option.selected = "selected";
|
||||
}
|
||||
qualitySelector.appendChild(option);
|
||||
});
|
||||
qualitySelector.selectedIndex = availableLevels.length - 1;
|
||||
qualitySelector.addEventListener('change', function () {
|
||||
var selectedIndex = qualitySelector.selectedIndex;
|
||||
hlsInstance.nextLevel = selectedIndex;
|
||||
hlsInstance.startLoad();
|
||||
});
|
||||
|
||||
videoElement.parentNode.appendChild(qualitySelector);
|
||||
}
|
||||
|
||||
newVideo.addEventListener('play', initializeHls);
|
||||
|
||||
if (autoplay) {
|
||||
newVideo.play();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
var videos = document.querySelectorAll("video.hls_autoplay");
|
||||
videos.forEach(function (video) {
|
||||
video.setAttribute("autoplay", "");
|
||||
});
|
||||
}
|
||||
})();
|
||||
// @license-end
|
119
static/style.css
119
static/style.css
@ -34,6 +34,7 @@
|
||||
font-family: 'Inter';
|
||||
src: url('/Inter.var.woff2') format('woff2-variations');
|
||||
font-style: normal;
|
||||
font-weight: 100 900;
|
||||
}
|
||||
|
||||
/* Automatic theme selection */
|
||||
@ -1325,83 +1326,6 @@ summary.comment_data {
|
||||
|
||||
/* Layouts */
|
||||
|
||||
.old .post {
|
||||
border-radius: 5px;
|
||||
background: var(--post);
|
||||
box-shadow: var(--shadow);
|
||||
display: grid;
|
||||
transition: 0.2s background;
|
||||
grid-template: "post_score post_thumbnail post_header" auto
|
||||
"post_score post_thumbnail post_title" 1fr
|
||||
"post_score post_thumbnail post_media" auto
|
||||
"post_score post_thumbnail post_body" auto
|
||||
"post_score post_thumbnail post_poll" auto
|
||||
"post_score post_thumbnail post_notification" auto
|
||||
"post_score post_thumbnail post_footer" auto
|
||||
/ 4.5em minmax(0, 140px) fit-content(min(90%, 90%))
|
||||
}
|
||||
|
||||
/* .old .post_thumbnail {
|
||||
margin-left: 20px;
|
||||
} */
|
||||
|
||||
.old .post_score {
|
||||
background-color: #ff93da08;
|
||||
border-radius: 8px;
|
||||
align-self: center;
|
||||
width: 53px;
|
||||
padding-left: 5px; /* REMINDER:pls compact testing only */
|
||||
border-top-width: 0px;
|
||||
border-top-style: solid;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
padding-right: 5px;
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.old .post_media_content {
|
||||
max-width: calc(65% - 40px);
|
||||
}
|
||||
|
||||
.old .highlighted > .post_score {
|
||||
background-color: unset;
|
||||
align-self: unset;
|
||||
margin-top: 20px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.old .post_score .label {
|
||||
display: block;
|
||||
text-align: center;
|
||||
text-anchor: middle;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.old .post_preview {
|
||||
max-height: 72px;
|
||||
}
|
||||
|
||||
.old #column_one {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.old #commentQueryForms {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
justify-self: start;
|
||||
}
|
||||
|
||||
.old .commentQuery {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
|
||||
.old main {
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
.compact .post:not(.highlighted) {
|
||||
border-radius: 0;
|
||||
margin: 0;
|
||||
@ -1836,18 +1760,53 @@ td, th {
|
||||
}
|
||||
}
|
||||
|
||||
.quality-selector {
|
||||
.video-options {
|
||||
border: 2px var(--outside) solid;
|
||||
margin-top: 8px;
|
||||
float: right;
|
||||
border-radius: 5px;
|
||||
height: 35px;
|
||||
height: 35px;
|
||||
margin: 2px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.quality-selector option {
|
||||
.video-options option {
|
||||
background-color: var(--background);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.quality-selector option:hover {
|
||||
.video-options option:hover {
|
||||
background-color: var(--accent);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.mascot {
|
||||
position: fixed;
|
||||
right: 1em;
|
||||
bottom: 1em;
|
||||
pointer-events: none;
|
||||
opacity: 0.5;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.mascot > img {
|
||||
max-width: 20em;
|
||||
}
|
||||
.download {
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
font-size: 20px;
|
||||
font-weight: 900;
|
||||
color: var(--accent);
|
||||
background-color: var(--outside);
|
||||
}
|
||||
|
||||
.download:hover {
|
||||
background-color: var(--foreground);
|
||||
/*color: var(--);*/
|
||||
}
|
||||
|
||||
.download:active {
|
||||
background-color: var(--background);
|
||||
}
|
228
static/videoUtils.js
Normal file
228
static/videoUtils.js
Normal file
@ -0,0 +1,228 @@
|
||||
// @license http://www.gnu.org/licenses/agpl-3.0.html AGPL-3.0
|
||||
let ffmpeg = null;
|
||||
(function () {
|
||||
if (Hls.isSupported()) {
|
||||
|
||||
var downloadsEnabled = document.cookie.split("; ").find((row) => row.startsWith("ffmpeg_video_downloads="))?.split("=")[1] == "on";
|
||||
|
||||
var videoSources = document.querySelectorAll("video source[type='application/vnd.apple.mpegurl']");
|
||||
videoSources.forEach(function (source) {
|
||||
var playlist = source.src;
|
||||
|
||||
var oldVideo = source.parentNode;
|
||||
var autoplay = oldVideo.classList.contains("hls_autoplay");
|
||||
|
||||
// If HLS is supported natively then don't use hls.js
|
||||
if (oldVideo.canPlayType(source.type) === "probably") {
|
||||
if (autoplay) {
|
||||
oldVideo.play();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Replace video with copy that will have all "source" elements removed
|
||||
var newVideo = oldVideo.cloneNode(true);
|
||||
var allSources = newVideo.querySelectorAll("source");
|
||||
allSources.forEach(function (source) {
|
||||
source.remove();
|
||||
});
|
||||
|
||||
// Empty source to enable play event
|
||||
newVideo.src = "about:blank";
|
||||
|
||||
oldVideo.parentNode.replaceChild(newVideo, oldVideo);
|
||||
|
||||
function initializeHls() {
|
||||
newVideo.removeEventListener('play', initializeHls);
|
||||
var hls = new Hls({ autoStartLoad: false });
|
||||
hls.loadSource(playlist);
|
||||
hls.attachMedia(newVideo);
|
||||
hls.on(Hls.Events.MANIFEST_PARSED, function () {
|
||||
hls.loadLevel = hls.levels.length - 1;
|
||||
var availableLevels = hls.levels.map(function(level) {
|
||||
return {
|
||||
height: level.height,
|
||||
width: level.width,
|
||||
bitrate: level.bitrate,
|
||||
};
|
||||
});
|
||||
|
||||
addQualitySelector(newVideo, hls, availableLevels);
|
||||
if (downloadsEnabled){ addVideoDownload(newVideo, hls); }
|
||||
hls.startLoad();
|
||||
newVideo.play();
|
||||
});
|
||||
|
||||
hls.on(Hls.Events.ERROR, function (event, data) {
|
||||
var errorType = data.type;
|
||||
var errorFatal = data.fatal;
|
||||
if (errorFatal) {
|
||||
switch (errorType) {
|
||||
case Hls.ErrorType.NETWORK_ERROR:
|
||||
hls.startLoad();
|
||||
break;
|
||||
case Hls.ErrorType.MEDIA_ERROR:
|
||||
hls.recoverMediaError();
|
||||
break;
|
||||
default:
|
||||
hls.destroy();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
console.error("HLS error", data);
|
||||
});
|
||||
}
|
||||
|
||||
if (downloadsEnabled){
|
||||
const { fetchFile } = FFmpegUtil;
|
||||
const { FFmpeg } = FFmpegWASM;
|
||||
|
||||
function addVideoDownload(videoElement, hlsInstance) {
|
||||
var mediaStream = [];
|
||||
var downloadButton = document.createElement('button');
|
||||
downloadButton.classList.add('video-options','download');
|
||||
downloadButton.innerText = "⏳"
|
||||
const mergeStreams = async () => {
|
||||
if (ffmpeg === null) {
|
||||
ffmpeg = new FFmpeg();
|
||||
await ffmpeg.load({
|
||||
coreURL: "/ffmpeg/ffmpeg-core.js",
|
||||
});
|
||||
ffmpeg.on("log", ({ message }) => {
|
||||
console.log(message); // This is quite noisy but i will include it
|
||||
})
|
||||
ffmpeg.on("progress", ({ progress, time }) => { // Progress TODO: show progress ring around button not just ⏳
|
||||
// console.log("ffmpeg prog:",progress * 100)
|
||||
});
|
||||
}
|
||||
// Combine Video Audio Streams
|
||||
await ffmpeg.writeFile("video", await fetchFile(concatBlob(mediaStream['video'])));
|
||||
await ffmpeg.writeFile("audio", await fetchFile(concatBlob(mediaStream['audio'])));
|
||||
console.time('ffmpeg-exec');
|
||||
await ffmpeg.exec(['-i', "video", '-i', "audio",'-c:v', "copy", '-c:a', "aac", 'output.mp4']);
|
||||
console.timeEnd('ffmpeg-exec')
|
||||
|
||||
// Save
|
||||
const toSlug = (str) => {
|
||||
return str
|
||||
.normalize('NFD')
|
||||
.replace(/[\u0300-\u036f]/g, '')
|
||||
.replace(/[\W_]+/g, '-')
|
||||
.toLowerCase()
|
||||
.replace(/^-+|-+$/g, '');
|
||||
}
|
||||
|
||||
var filename = toSlug(videoElement.parentNode.parentNode.id || document.title)
|
||||
const data = await ffmpeg.readFile('output.mp4');
|
||||
saveAs(new Blob([data.buffer]),filename);
|
||||
return
|
||||
}
|
||||
function saveAs(blob, filename) { // Yeah ok...
|
||||
var url = URL.createObjectURL(blob);
|
||||
var a = document.createElement("a");
|
||||
document.body.appendChild(a);
|
||||
a.style = "display: none";
|
||||
a.href = url;
|
||||
a.download = filename;
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
}
|
||||
function concatBlob(inputArray) {
|
||||
var totalLength = inputArray.reduce(function (prev, cur) {
|
||||
return prev + cur.length
|
||||
}, 0);
|
||||
var result = new Uint8Array(totalLength);
|
||||
var offset = 0;
|
||||
inputArray.forEach(function (element) {
|
||||
result.set(element, offset);
|
||||
offset += element.length;
|
||||
});
|
||||
return new Blob([result], {
|
||||
type: 'application/octet-stream'
|
||||
});
|
||||
}
|
||||
function getStreams() {
|
||||
var video = document.createElement('video');
|
||||
video.autoplay = true;
|
||||
var dataStreams = {
|
||||
'video': [],
|
||||
'audio': []
|
||||
};
|
||||
mediaStream = dataStreams; // Update stream
|
||||
|
||||
hlsInstance.on(Hls.Events.BUFFER_APPENDING, function (event, data) {
|
||||
dataStreams[data.type].push(data.data);
|
||||
});
|
||||
var isDownloading = false
|
||||
function startDownload() {
|
||||
if (!isDownloading) { isDownloading = true } else { return }
|
||||
downloadButton.innerText = "⏳"
|
||||
mergeStreams()
|
||||
.then(_ => {
|
||||
isDownloading = false
|
||||
downloadButton.innerText = "⭳"
|
||||
});
|
||||
}
|
||||
|
||||
function waitForLoad() {
|
||||
const poll = resolve => {
|
||||
if(hlsInstance._media.buffered.length === 1 &&
|
||||
hlsInstance._media.buffered.start(0) === 0 &&
|
||||
hlsInstance._media.buffered.end(0) === hlsInstance._media.duration)
|
||||
resolve();
|
||||
else setTimeout(_ => poll(resolve), 400);
|
||||
}
|
||||
return new Promise(poll);
|
||||
}
|
||||
|
||||
waitForLoad(_ => flag === true)
|
||||
.then(_ => {
|
||||
downloadButton.innerText = "⭳"
|
||||
downloadButton.addEventListener('click', startDownload);
|
||||
});
|
||||
}
|
||||
|
||||
videoElement.parentNode.appendChild(downloadButton);
|
||||
getStreams()
|
||||
}
|
||||
}
|
||||
|
||||
function addQualitySelector(videoElement, hlsInstance, availableLevels) {
|
||||
var qualitySelector = document.createElement('select');
|
||||
qualitySelector.classList.add('video-options');
|
||||
var last = availableLevels.length - 1;
|
||||
availableLevels.forEach(function (level, index) {
|
||||
var option = document.createElement('option');
|
||||
option.value = index.toString();
|
||||
var bitrate = (level.bitrate / 1_000).toFixed(0);
|
||||
option.text = level.height + 'p (' + bitrate + ' kbps)';
|
||||
if (index === last) {
|
||||
option.selected = "selected";
|
||||
}
|
||||
qualitySelector.appendChild(option);
|
||||
});
|
||||
qualitySelector.selectedIndex = availableLevels.length - 1;
|
||||
qualitySelector.addEventListener('change', function () {
|
||||
var selectedIndex = qualitySelector.selectedIndex;
|
||||
hlsInstance.nextLevel = selectedIndex;
|
||||
hlsInstance.startLoad();
|
||||
});
|
||||
|
||||
videoElement.parentNode.appendChild(qualitySelector);
|
||||
}
|
||||
|
||||
newVideo.addEventListener('play', initializeHls);
|
||||
|
||||
if (autoplay) {
|
||||
newVideo.play();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
var videos = document.querySelectorAll("video.hls_autoplay");
|
||||
videos.forEach(function (video) {
|
||||
video.setAttribute("autoplay", "");
|
||||
});
|
||||
}
|
||||
})();
|
||||
// @license-end
|
@ -28,7 +28,7 @@
|
||||
</head>
|
||||
<body class="
|
||||
{% if prefs.layout != "" %}{{ prefs.layout }}{% endif %}
|
||||
{% if prefs.wide == "on" && prefs.layout != "old" %} wide{% endif %}
|
||||
{% if prefs.wide == "on" %} wide{% endif %}
|
||||
{% if prefs.theme != "system" %} {{ prefs.theme }}{% endif %}
|
||||
{% if prefs.fixed_navbar == "on" %} fixed_navbar{% endif %}">
|
||||
<!-- NAVIGATION BAR -->
|
||||
@ -59,6 +59,13 @@
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{% if prefs.mascot != "none" && prefs.mascot != "" %}
|
||||
<!-- MASCOT -->
|
||||
<div class="mascot">
|
||||
<img src="/mascot/{{ prefs.mascot }}.png">
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- MAIN CONTENT -->
|
||||
{% block body %}
|
||||
|
@ -97,9 +97,13 @@
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if prefs.use_hls == "on" %}
|
||||
{% if prefs.ffmpeg_video_downloads == "on" %}
|
||||
<script src="/ffmpeg/ffmpeg.js"></script>
|
||||
<script src="/ffmpeg/ffmpeg-util.js"></script>
|
||||
{% endif %}
|
||||
{% if prefs.use_hls == "on" || prefs.ffmpeg_video_downloads == "on" %}
|
||||
<script src="/hls.min.js"></script>
|
||||
<script src="/playHLSVideo.js"></script>
|
||||
<script src="/videoUtils.js"></script>
|
||||
{% endif %}
|
||||
|
||||
{% if params.typed != "sr_user" %}
|
||||
|
@ -19,6 +19,12 @@
|
||||
{% call utils::options(prefs.theme, prefs.available_themes, "system") %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="prefs-group">
|
||||
<label for="mascot">Mascot:</label>
|
||||
<select name="mascot" id="mascot">
|
||||
{% call utils::options(prefs.mascot, prefs.available_mascots, "system") %}
|
||||
</select>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Interface</legend>
|
||||
@ -31,14 +37,13 @@
|
||||
<div class="prefs-group">
|
||||
<label for="layout">Layout:</label>
|
||||
<select name="layout" id="layout">
|
||||
{% call utils::options(prefs.layout, ["card", "clean", "compact","old"], "card") %}
|
||||
{% call utils::options(prefs.layout, ["card", "clean", "compact"], "card") %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="prefs-group">
|
||||
<label for="wide">Wide UI:</label>
|
||||
<input type="hidden" value="off" name="wide">
|
||||
<input type="checkbox" name="wide" id="wide" {% if prefs.layout == "old" %}disabled{% endif %} {% if prefs.wide == "on" || prefs.layout == "old" %}checked{% endif %}>
|
||||
{% if prefs.layout == "old" %}<span>ⓘ Wide UI is always enabled with this layout</span>{% endif %}
|
||||
<input type="checkbox" name="wide" id="wide" {% if prefs.wide == "on" %}checked{% endif %}>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
@ -84,12 +89,15 @@
|
||||
</div>
|
||||
<div class="prefs-group">
|
||||
<label for="use_hls">Use HLS for videos</label>
|
||||
{% if prefs.ffmpeg_video_downloads != "on" %}
|
||||
<details id="feeds">
|
||||
<summary>Why?</summary>
|
||||
<div id="feed_list" class="helper">Reddit videos require JavaScript (via HLS.js) to be enabled to be played with audio. Therefore, this toggle lets you either use Redlib JS-free or utilize this feature.</div>
|
||||
</details>
|
||||
{% endif %}
|
||||
{% if prefs.ffmpeg_video_downloads == "on" %}<u>ⓘ HLS is required for downloads</u>{% endif %}
|
||||
<input type="hidden" value="off" name="use_hls">
|
||||
<input type="checkbox" name="use_hls" id="use_hls" {% if prefs.use_hls == "on" %}checked{% endif %}>
|
||||
<input type="checkbox" name="use_hls" id="use_hls" {% if prefs.ffmpeg_video_downloads == "on" %}disabled{% endif %} {% if prefs.use_hls == "on" || prefs.ffmpeg_video_downloads == "on" %}checked{% endif %}>
|
||||
</div>
|
||||
<div class="prefs-group">
|
||||
<label for="ffmpeg_video_downloads">Use FFmpeg to download videos</label>
|
||||
@ -157,7 +165,7 @@
|
||||
|
||||
<div id="settings_note">
|
||||
<p><b>Note:</b> settings and subscriptions are saved in browser cookies. Clearing your cookies will reset them.</p><br>
|
||||
<p>You can restore your current settings and subscriptions after clearing your cookies using <a href="/settings/restore/?theme={{ prefs.theme }}&front_page={{ prefs.front_page }}&layout={{ prefs.layout }}&wide={{ prefs.wide }}&post_sort={{ prefs.post_sort }}&comment_sort={{ prefs.comment_sort }}&show_nsfw={{ prefs.show_nsfw }}&use_hls={{ prefs.use_hls }}&ffmpeg_video_downloads={{ prefs.ffmpeg_video_downloads }}&hide_hls_notification={{ prefs.hide_hls_notification }}&hide_awards={{ prefs.hide_awards }}&fixed_navbar={{ prefs.fixed_navbar }}&subscriptions={{ prefs.subscriptions.join("%2B") }}&filters={{ prefs.filters.join("%2B") }}">this link</a>.</p>
|
||||
<p>You can restore your current settings and subscriptions after clearing your cookies using <a href="/settings/restore/?theme={{ prefs.theme }}&mascot={{ prefs.mascot }}&front_page={{ prefs.front_page }}&layout={{ prefs.layout }}&wide={{ prefs.wide }}&post_sort={{ prefs.post_sort }}&comment_sort={{ prefs.comment_sort }}&show_nsfw={{ prefs.show_nsfw }}&use_hls={{ prefs.use_hls }}&ffmpeg_video_downloads={{ prefs.ffmpeg_video_downloads }}&hide_hls_notification={{ prefs.hide_hls_notification }}&hide_awards={{ prefs.hide_awards }}&fixed_navbar={{ prefs.fixed_navbar }}&hide_sidebar_and_summary={{ prefs.hide_sidebar_and_summary}}&subscriptions={{ prefs.subscriptions.join("%2B") }}&filters={{ prefs.filters.join("%2B") }}">this link</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -64,9 +64,13 @@
|
||||
{% call utils::post_in_list(post) %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if prefs.use_hls == "on" %}
|
||||
{% if prefs.ffmpeg_video_downloads == "on" %}
|
||||
<script src="/ffmpeg/ffmpeg.js"></script>
|
||||
<script src="/ffmpeg/ffmpeg-util.js"></script>
|
||||
{% endif %}
|
||||
{% if prefs.use_hls == "on" || prefs.ffmpeg_video_downloads == "on" %}
|
||||
<script src="/hls.min.js"></script>
|
||||
<script src="/playHLSVideo.js"></script>
|
||||
<script src="/videoUtils.js"></script>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
@ -71,9 +71,13 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if prefs.use_hls == "on" %}
|
||||
{% if prefs.ffmpeg_video_downloads == "on" %}
|
||||
<script src="/ffmpeg/ffmpeg.js"></script>
|
||||
<script src="/ffmpeg/ffmpeg-util.js"></script>
|
||||
{% endif %}
|
||||
{% if prefs.use_hls == "on" || prefs.ffmpeg_video_downloads == "on" %}
|
||||
<script src="/hls.min.js"></script>
|
||||
<script src="/playHLSVideo.js"></script>
|
||||
<script src="/videoUtils.js"></script>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
@ -117,7 +117,11 @@
|
||||
</a>
|
||||
</div>
|
||||
{% else if post.post_type == "video" || post.post_type == "gif" %}
|
||||
{% if prefs.use_hls == "on" && !post.media.alt_url.is_empty() %}
|
||||
{% if prefs.ffmpeg_video_downloads == "on" %}
|
||||
<script src="/ffmpeg/ffmpeg.js"></script>
|
||||
<script src="/ffmpeg/ffmpeg-util.js"></script>
|
||||
{% endif %}
|
||||
{% if prefs.use_hls == "on" && !post.media.alt_url.is_empty() || prefs.ffmpeg_video_downloads == "on" && !post.media.alt_url.is_empty() %}
|
||||
<script src="/hls.min.js"></script>
|
||||
<div class="post_media_content">
|
||||
<video class="post_media_video short {% if prefs.autoplay_videos == "on" %}hls_autoplay{% endif %}" {% if post.media.width > 0 && post.media.height > 0 %}width="{{ post.media.width }}" height="{{ post.media.height }}"{% endif %} poster="{{ post.media.poster }}" preload="none" controls>
|
||||
@ -125,7 +129,7 @@
|
||||
<source src="{{ post.media.url }}" type="video/mp4" />
|
||||
</video>
|
||||
</div>
|
||||
<script src="/playHLSVideo.js"></script>
|
||||
<script src="/videoUtils.js"></script>
|
||||
{% else %}
|
||||
<div class="post_media_content">
|
||||
<video class="post_media_video" src="{{ post.media.url }}" controls {% if prefs.autoplay_videos == "on" %}autoplay{% endif %} loop><a href={{ post.media.url }}>Video</a></video>
|
||||
@ -250,7 +254,7 @@
|
||||
<video class="post_media_video short {%if post.flags.nsfw && prefs.blur_nsfw=="on" %}post_nsfw_blur{% endif %}" src="{{ post.media.url }}" {% if post.media.width > 0 && post.media.height > 0 %}width="{{ post.media.width }}" height="{{ post.media.height }}"{% endif %} poster="{{ post.media.poster }}" preload="none" controls loop {% if prefs.autoplay_videos == "on" %}autoplay{% endif %}><a href={{ post.media.url }}>Video</a></video>
|
||||
</div>
|
||||
{% else if (prefs.layout.is_empty() || prefs.layout == "card") && post.post_type == "video" %}
|
||||
{% if prefs.use_hls == "on" && !post.media.alt_url.is_empty() %}
|
||||
{% if prefs.use_hls == "on" && !post.media.alt_url.is_empty() || prefs.ffmpeg_video_downloads == "on" && !post.media.alt_url.is_empty() %}
|
||||
<div class="post_media_content">
|
||||
<video class="post_media_video short {%if post.flags.nsfw && prefs.blur_nsfw=="on" %}post_nsfw_blur{% endif %} {% if prefs.autoplay_videos == "on" %}hls_autoplay{% endif %}" {% if post.media.width > 0 && post.media.height > 0 %}width="{{ post.media.width }}" height="{{ post.media.height }}"{% endif %} poster="{{ post.media.poster }}" controls preload="none">
|
||||
<source src="{{ post.media.alt_url }}" type="application/vnd.apple.mpegurl" />
|
||||
|
Reference in New Issue
Block a user