Compare commits
54 Commits
Author | SHA1 | Date | |
---|---|---|---|
34ea679519 | |||
0f7ba3c61d | |||
2486347b14 | |||
c298109a7b | |||
a0509890b7 | |||
5644d621f7 | |||
1fc5bda486 | |||
b3255c22cf | |||
1d4ea50a45 | |||
546c8a4cda | |||
03336ecafd | |||
957e1c7728 | |||
09053ef0ad | |||
aff030fc3a | |||
97555dbfdd | |||
32360e5165 | |||
350b796571 | |||
567556711b | |||
1ff725ba2e | |||
6a4191f3b5 | |||
668493b72c | |||
db04dcb238 | |||
cc0a1e0324 | |||
e073fc87aa | |||
982f57efd9 | |||
52a1b45014 | |||
6f88fdfc75 | |||
015d0b3414 | |||
b41eabecf7 | |||
5cb5f46fa2 | |||
a900339529 | |||
41b3dc5739 | |||
b3b5782373 | |||
5c753ee171 | |||
229518c40b | |||
45a5778571 | |||
be253d40dd | |||
e571cc3b1e | |||
345f8e7b80 | |||
a190890239 | |||
ee51ce1a76 | |||
81a2df98cb | |||
e79a4b704a | |||
56998b8332 | |||
5418303b08 | |||
5ab41c4e6e | |||
807b3ffeca | |||
85deb4947d | |||
d2002c9027 | |||
f84f4c0326 | |||
ca3f6c0579 | |||
decc9e5139 | |||
d27bd782ce | |||
4defb58f2a |
39
.github/workflows/docker-armv7.yml
vendored
Normal file
39
.github/workflows/docker-armv7.yml
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
name: Docker ARM V7 Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths-ignore:
|
||||||
|
- "**.md"
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-docker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Set up QEMU
|
||||||
|
id: qemu
|
||||||
|
uses: docker/setup-qemu-action@v1
|
||||||
|
with:
|
||||||
|
platforms: all
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
id: buildx
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
- name: Login to DockerHub
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
- name: Build and push
|
||||||
|
id: build_push
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./Dockerfile.armv7
|
||||||
|
platforms: linux/arm/v7
|
||||||
|
push: true
|
||||||
|
tags: spikecodes/libreddit:armv7
|
37
.github/workflows/docker.yml
vendored
Normal file
37
.github/workflows/docker.yml
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
name: Docker amd64 Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths-ignore:
|
||||||
|
- "**.md"
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-docker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v1
|
||||||
|
with:
|
||||||
|
platforms: all
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
id: buildx
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
- name: Login to DockerHub
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
- name: Build and push
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./Dockerfile
|
||||||
|
platforms: linux/amd64
|
||||||
|
push: true
|
||||||
|
tags: spikecodes/libreddit:latest
|
||||||
|
|
2
.github/workflows/rust.yml
vendored
2
.github/workflows/rust.yml
vendored
@ -49,7 +49,5 @@ jobs:
|
|||||||
libreddit.sha512
|
libreddit.sha512
|
||||||
body: |
|
body: |
|
||||||
- ${{ github.event.head_commit.message }} ${{ github.sha }}
|
- ${{ github.event.head_commit.message }} ${{ github.sha }}
|
||||||
|
|
||||||
See full list of changes [here](https://github.com/spikecodes/libreddit/compare/${{ steps.version.outputs.tag }}...${{ steps.version.outputs.version }}).
|
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
349
Cargo.lock
generated
349
Cargo.lock
generated
@ -79,10 +79,20 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-trait"
|
name = "async-rwlock"
|
||||||
version = "0.1.50"
|
version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b98e84bbb4cbcdd97da190ba0c58a1bb0de2c1fdf67d159e192ed766aeca722"
|
checksum = "261803dcc39ba9e72760ba6e16d0199b1eef9fc44e81bffabbebb9f5aea3906c"
|
||||||
|
dependencies = [
|
||||||
|
"async-mutex",
|
||||||
|
"event-listener",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-trait"
|
||||||
|
version = "0.1.51"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -109,9 +119,9 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.2.1"
|
version = "1.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitvec"
|
name = "bitvec"
|
||||||
@ -127,23 +137,24 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.6.1"
|
version = "3.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe"
|
checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.0.1"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040"
|
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cached"
|
name = "cached"
|
||||||
version = "0.23.0"
|
version = "0.26.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5e2afe73808fbaac302e39c9754bfc3c4b4d0f99c9c240b9f4e4efc841ad1b74"
|
checksum = "c2bc2fd249a24a9cdd4276f3a3e0461713271ab63b0e9e656e200e8e21c8c927"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-mutex",
|
"async-mutex",
|
||||||
|
"async-rwlock",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"cached_proc_macro",
|
"cached_proc_macro",
|
||||||
"cached_proc_macro_types",
|
"cached_proc_macro_types",
|
||||||
@ -154,11 +165,10 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cached_proc_macro"
|
name = "cached_proc_macro"
|
||||||
version = "0.6.0"
|
version = "0.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bf857ae42d910aede5c5186e62684b0d7a597ce2fe3bd14448ab8f7ef439848c"
|
checksum = "ac3531903b39df48a378a7ed515baee7c1fff32488489c7d0725eb1749b22a91"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-mutex",
|
|
||||||
"cached_proc_macro_types",
|
"cached_proc_macro_types",
|
||||||
"darling",
|
"darling",
|
||||||
"quote",
|
"quote",
|
||||||
@ -173,9 +183,9 @@ checksum = "3a4f925191b4367301851c6d99b09890311d74b0d43f274c0b34c86d308a3663"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.67"
|
version = "1.0.72"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
|
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
@ -202,9 +212,9 @@ checksum = "f92cfa0fd5690b3cf8c1ef2cabbd9b7ef22fa53cf5e1f92b05103f6d5d1cf6e7"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cookie"
|
name = "cookie"
|
||||||
version = "0.15.0"
|
version = "0.15.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ffdf8865bac3d9a3bde5bde9088ca431b11f5d37c7a578b8086af77248b76627"
|
checksum = "d5f1c7727e460397e56abc4bddc1d49e07a1ad78fc98eb2e1c8f032a58a2f80d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"time",
|
"time",
|
||||||
"version_check",
|
"version_check",
|
||||||
@ -212,9 +222,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.9.1"
|
version = "0.9.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62"
|
checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"core-foundation-sys",
|
"core-foundation-sys",
|
||||||
"libc",
|
"libc",
|
||||||
@ -222,9 +232,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation-sys"
|
name = "core-foundation-sys"
|
||||||
version = "0.8.2"
|
version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b"
|
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ct-logs"
|
name = "ct-logs"
|
||||||
@ -237,9 +247,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "darling"
|
name = "darling"
|
||||||
version = "0.10.2"
|
version = "0.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858"
|
checksum = "757c0ded2af11d8e739c4daea1ac623dd1624b06c844cf3f5a39f1bdbd99bb12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling_core",
|
"darling_core",
|
||||||
"darling_macro",
|
"darling_macro",
|
||||||
@ -247,9 +257,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "darling_core"
|
name = "darling_core"
|
||||||
version = "0.10.2"
|
version = "0.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b"
|
checksum = "2c34d8efb62d0c2d7f60ece80f75e5c63c1588ba68032740494b0b9a996466e3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fnv",
|
"fnv",
|
||||||
"ident_case",
|
"ident_case",
|
||||||
@ -261,9 +271,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "darling_macro"
|
name = "darling_macro"
|
||||||
version = "0.10.2"
|
version = "0.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72"
|
checksum = "ade7bff147130fe5e6d39f089c6bd49ec0250f35d70b2eebf72afdfc919f15cc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling_core",
|
"darling_core",
|
||||||
"quote",
|
"quote",
|
||||||
@ -284,9 +294,9 @@ checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "1.4.1"
|
version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "77b705829d1e87f762c2df6da140b26af5839e1033aa84aa5f56bb688e4e1bdb"
|
checksum = "b394ed3d285a429378d3b384b9eb1285267e7df4b166df24b7a6939a04dc392e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"instant",
|
"instant",
|
||||||
]
|
]
|
||||||
@ -315,9 +325,9 @@ checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures"
|
name = "futures"
|
||||||
version = "0.3.15"
|
version = "0.3.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0e7e43a803dae2fa37c1f6a8fe121e1f7bf9548b4dfc0522a42f34145dadfc27"
|
checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
@ -330,9 +340,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-channel"
|
name = "futures-channel"
|
||||||
version = "0.3.15"
|
version = "0.3.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e682a68b29a882df0545c143dc3646daefe80ba479bcdede94d5a703de2871e2"
|
checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
@ -340,15 +350,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-core"
|
name = "futures-core"
|
||||||
version = "0.3.15"
|
version = "0.3.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0402f765d8a89a26043b889b26ce3c4679d268fa6bb22cd7c6aad98340e179d1"
|
checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-executor"
|
name = "futures-executor"
|
||||||
version = "0.3.15"
|
version = "0.3.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "badaa6a909fac9e7236d0620a2f57f7664640c56575b71a7552fbd68deafab79"
|
checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-task",
|
"futures-task",
|
||||||
@ -357,15 +367,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-io"
|
name = "futures-io"
|
||||||
version = "0.3.15"
|
version = "0.3.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "acc499defb3b348f8d8f3f66415835a9131856ff7714bf10dadfc4ec4bdb29a1"
|
checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-lite"
|
name = "futures-lite"
|
||||||
version = "1.11.3"
|
version = "1.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4481d0cd0de1d204a4fa55e7d45f07b1d958abcb06714b3446438e2eff695fb"
|
checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
@ -378,9 +388,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-macro"
|
name = "futures-macro"
|
||||||
version = "0.3.15"
|
version = "0.3.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a4c40298486cdf52cc00cd6d6987892ba502c7656a16a4192a9992b1ccedd121"
|
checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"proc-macro-hack",
|
"proc-macro-hack",
|
||||||
@ -391,21 +401,21 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-sink"
|
name = "futures-sink"
|
||||||
version = "0.3.15"
|
version = "0.3.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a57bead0ceff0d6dde8f465ecd96c9338121bb7717d3e7b108059531870c4282"
|
checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-task"
|
name = "futures-task"
|
||||||
version = "0.3.15"
|
version = "0.3.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8a16bef9fc1a4dddb5bee51c989e3fbba26569cbb0e31f5b303c184e3dd33dae"
|
checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-util"
|
name = "futures-util"
|
||||||
version = "0.3.15"
|
version = "0.3.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "feb5c238d27e2bf94ffdfd27b2c29e3df4a68c4193bb6427384259e2bf191967"
|
checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
@ -424,9 +434,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h2"
|
name = "h2"
|
||||||
version = "0.3.3"
|
version = "0.3.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "825343c4eef0b63f541f8903f395dc5beb362a979b5799a84062527ef1e37726"
|
checksum = "7fd819562fcebdac5afc5c113c3ec36f902840b70fd4fc458799c8ce4607ae55"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"fnv",
|
"fnv",
|
||||||
@ -443,24 +453,24 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.9.1"
|
version = "0.11.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
|
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.1.18"
|
version = "0.1.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
|
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "0.2.4"
|
version = "0.2.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11"
|
checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"fnv",
|
"fnv",
|
||||||
@ -469,9 +479,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http-body"
|
name = "http-body"
|
||||||
version = "0.4.2"
|
version = "0.4.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "60daa14be0e0786db0f03a9e57cb404c9d756eed2b6c62b9ea98ec5743ec75a9"
|
checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"http",
|
"http",
|
||||||
@ -480,21 +490,21 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "httparse"
|
name = "httparse"
|
||||||
version = "1.4.1"
|
version = "1.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f3a87b616e37e93c22fb19bcd386f02f3af5ea98a25670ad0fce773de23c5e68"
|
checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "httpdate"
|
name = "httpdate"
|
||||||
version = "1.0.0"
|
version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "05842d0d43232b23ccb7060ecb0f0626922c21f30012e97b767b30afd4a5d4b9"
|
checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "0.14.7"
|
version = "0.14.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1e5f105c494081baa3bf9e200b279e27ec1623895cd504c7dbef8d0b080fcf54"
|
checksum = "2b91bb1f221b6ea1f1e4371216b70f40748774c2fb5971b450c07773fb92d26b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
@ -506,7 +516,7 @@ dependencies = [
|
|||||||
"httparse",
|
"httparse",
|
||||||
"httpdate",
|
"httpdate",
|
||||||
"itoa",
|
"itoa",
|
||||||
"pin-project",
|
"pin-project-lite",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
@ -550,9 +560,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "1.6.2"
|
version = "1.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3"
|
checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
@ -560,24 +570,24 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "instant"
|
name = "instant"
|
||||||
version = "0.1.9"
|
version = "0.1.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec"
|
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "0.4.7"
|
version = "0.4.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
|
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.51"
|
version = "0.3.55"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062"
|
checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
@ -603,13 +613,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.94"
|
version = "0.2.107"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
|
checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libreddit"
|
name = "libreddit"
|
||||||
version = "0.14.3"
|
version = "0.17.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"askama",
|
"askama",
|
||||||
"async-recursion",
|
"async-recursion",
|
||||||
@ -630,9 +640,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
version = "0.4.4"
|
version = "0.4.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb"
|
checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"scopeguard",
|
"scopeguard",
|
||||||
]
|
]
|
||||||
@ -648,21 +658,21 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "matches"
|
name = "matches"
|
||||||
version = "0.1.8"
|
version = "0.1.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.4.0"
|
version = "2.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
|
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "0.7.11"
|
version = "0.7.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf80d3e903b34e0bd7282b218398aec54e082c840d9baf8339e0080a0c542956"
|
checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
@ -714,9 +724,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.7.2"
|
version = "1.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
|
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-probe"
|
name = "openssl-probe"
|
||||||
@ -732,9 +742,9 @@ checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.11.1"
|
version = "0.11.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb"
|
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"instant",
|
"instant",
|
||||||
"lock_api",
|
"lock_api",
|
||||||
@ -743,9 +753,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot_core"
|
name = "parking_lot_core"
|
||||||
version = "0.8.3"
|
version = "0.8.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018"
|
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"instant",
|
"instant",
|
||||||
@ -761,31 +771,11 @@ version = "2.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pin-project"
|
|
||||||
version = "1.0.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c7509cc106041c40a4518d2af7a61530e1eed0e6285296a3d8c5472806ccc4a4"
|
|
||||||
dependencies = [
|
|
||||||
"pin-project-internal",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pin-project-internal"
|
|
||||||
version = "1.0.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "48c950132583b500556b1efd71d45b319029f2b71518d979fcc208e16b42426f"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.6"
|
version = "0.2.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905"
|
checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-utils"
|
name = "pin-utils"
|
||||||
@ -807,18 +797,18 @@ checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.26"
|
version = "1.0.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
|
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.9"
|
version = "1.0.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
|
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
@ -831,9 +821,9 @@ checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.2.8"
|
version = "0.2.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc"
|
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
@ -872,9 +862,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "route-recognizer"
|
name = "route-recognizer"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "824172f0afccf3773c3905f5550ac94572144efe0deaf49a1f22bbca188d193e"
|
checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc_version"
|
name = "rustc_version"
|
||||||
@ -944,9 +934,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "security-framework"
|
name = "security-framework"
|
||||||
version = "2.2.0"
|
version = "2.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3670b1d2fdf6084d192bc71ead7aabe6c06aa2ea3fbd9cc3ac111fa5c2b1bd84"
|
checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"core-foundation",
|
"core-foundation",
|
||||||
@ -957,9 +947,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "security-framework-sys"
|
name = "security-framework-sys"
|
||||||
version = "2.2.0"
|
version = "2.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3676258fd3cfe2c9a0ec99ce3038798d847ce3e4bb17746373eb9f0f1ac16339"
|
checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"core-foundation-sys",
|
"core-foundation-sys",
|
||||||
"libc",
|
"libc",
|
||||||
@ -982,18 +972,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.126"
|
version = "1.0.130"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
|
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.126"
|
version = "1.0.130"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
|
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -1002,9 +992,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.64"
|
version = "1.0.70"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
|
checksum = "e277c495ac6cd1a01a58d0a0c574568b4d1ddf14f59965c6a58b8d96400b54f3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
@ -1019,30 +1009,30 @@ checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook-registry"
|
name = "signal-hook-registry"
|
||||||
version = "1.3.0"
|
version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6"
|
checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.3"
|
version = "0.4.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527"
|
checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
version = "1.6.1"
|
version = "1.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
|
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.4.0"
|
version = "0.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2"
|
checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"winapi",
|
"winapi",
|
||||||
@ -1120,15 +1110,15 @@ checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.9.3"
|
version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.72"
|
version = "1.0.81"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
|
checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -1152,9 +1142,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.2.26"
|
version = "0.2.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "08a8cbfbf47955132d0202d1662f49b2423ae35862aee471f3ba4b133358f372"
|
checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"const_fn",
|
"const_fn",
|
||||||
"libc",
|
"libc",
|
||||||
@ -1177,9 +1167,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time-macros-impl"
|
name = "time-macros-impl"
|
||||||
version = "0.1.1"
|
version = "0.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e5c3be1edfad6027c69f5491cf4cb310d1a71ecd6af742788c6ff8bced86b8fa"
|
checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro-hack",
|
"proc-macro-hack",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@ -1190,9 +1180,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinyvec"
|
name = "tinyvec"
|
||||||
version = "1.2.0"
|
version = "1.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342"
|
checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"tinyvec_macros",
|
"tinyvec_macros",
|
||||||
]
|
]
|
||||||
@ -1205,9 +1195,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.6.0"
|
version = "1.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bd3076b5c8cc18138b8f8814895c11eb4de37114a5d127bafdc5e55798ceef37"
|
checksum = "588b2d10a336da58d877567cd8fb8a14b463e2104910f8132cd054b4b96e29ee"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"bytes",
|
"bytes",
|
||||||
@ -1225,9 +1215,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-macros"
|
name = "tokio-macros"
|
||||||
version = "1.2.0"
|
version = "1.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c49e3df43841dafb86046472506755d8501c5615673955f6aa17181125d13c37"
|
checksum = "114383b041aa6212c579467afa0075fbbdd0718de036100bc0ba7961d8cb9095"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -1247,9 +1237,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-util"
|
name = "tokio-util"
|
||||||
version = "0.6.7"
|
version = "0.6.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1caa0b0c8d94a049db56b5acf8cba99dc0623aab1b26d5b5f5e2d945846b3592"
|
checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
@ -1267,9 +1257,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing"
|
name = "tracing"
|
||||||
version = "0.1.26"
|
version = "0.1.29"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d"
|
checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
@ -1278,9 +1268,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-core"
|
name = "tracing-core"
|
||||||
version = "0.1.18"
|
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 = "a9ff14f98b1a4b289c6248a023c1c2fa1491062964e9fed67ab29c4e4da4a052"
|
checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
]
|
]
|
||||||
@ -1293,27 +1283,24 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-bidi"
|
name = "unicode-bidi"
|
||||||
version = "0.3.5"
|
version = "0.3.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0"
|
checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
|
||||||
dependencies = [
|
|
||||||
"matches",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-normalization"
|
name = "unicode-normalization"
|
||||||
version = "0.1.17"
|
version = "0.1.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef"
|
checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"tinyvec",
|
"tinyvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-width"
|
name = "unicode-width"
|
||||||
version = "0.1.8"
|
version = "0.1.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
@ -1363,9 +1350,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.74"
|
version = "0.2.78"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd"
|
checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"wasm-bindgen-macro",
|
"wasm-bindgen-macro",
|
||||||
@ -1373,9 +1360,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-backend"
|
name = "wasm-bindgen-backend"
|
||||||
version = "0.2.74"
|
version = "0.2.78"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900"
|
checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
@ -1388,9 +1375,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.74"
|
version = "0.2.78"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4"
|
checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"wasm-bindgen-macro-support",
|
"wasm-bindgen-macro-support",
|
||||||
@ -1398,9 +1385,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro-support"
|
name = "wasm-bindgen-macro-support"
|
||||||
version = "0.2.74"
|
version = "0.2.78"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97"
|
checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -1411,15 +1398,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-shared"
|
name = "wasm-bindgen-shared"
|
||||||
version = "0.2.74"
|
version = "0.2.78"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f"
|
checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "web-sys"
|
name = "web-sys"
|
||||||
version = "0.3.51"
|
version = "0.3.55"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e828417b379f3df7111d3a2a9e5753706cae29c41f7c4029ee9fd77f3e09e582"
|
checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
|
20
Cargo.toml
20
Cargo.toml
@ -3,23 +3,23 @@ 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.14.3"
|
version = "0.17.0"
|
||||||
authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"]
|
authors = ["spikecodes <19519553+spikecodes@users.noreply.github.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
askama = { version = "0.10.5", default-features = false }
|
askama = { version = "0.10.5", default-features = false }
|
||||||
async-recursion = "0.3.2"
|
async-recursion = "0.3.2"
|
||||||
cached = "0.23.0"
|
cached = "0.26.2"
|
||||||
clap = { version = "2.33.3", default-features = false }
|
clap = { version = "2.33.3", default-features = false }
|
||||||
regex = "1.5.4"
|
regex = "1.5.4"
|
||||||
serde = { version = "1.0.126", features = ["derive"] }
|
serde = { version = "1.0.130", features = ["derive"] }
|
||||||
cookie = "0.15.0"
|
cookie = "0.15.1"
|
||||||
futures-lite = "1.11.3"
|
futures-lite = "1.12.0"
|
||||||
hyper = { version = "0.14.7", features = ["full"] }
|
hyper = { version = "0.14.14", features = ["full"] }
|
||||||
hyper-rustls = "0.22.1"
|
hyper-rustls = "0.22.1"
|
||||||
route-recognizer = "0.3.0"
|
route-recognizer = "0.3.1"
|
||||||
serde_json = "1.0.64"
|
serde_json = "1.0.70"
|
||||||
tokio = { version = "1.6.0", features = ["full"] }
|
tokio = { version = "1.13.0", features = ["full"] }
|
||||||
time = "0.2.26"
|
time = "0.2.7"
|
||||||
url = "2.2.2"
|
url = "2.2.2"
|
||||||
|
43
Dockerfile.armv7
Normal file
43
Dockerfile.armv7
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
####################################################################################################
|
||||||
|
## Builder
|
||||||
|
####################################################################################################
|
||||||
|
FROM --platform=$BUILDPLATFORM rust:slim AS builder
|
||||||
|
|
||||||
|
ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_MUSLEABIHF_LINKER=arm-linux-gnueabihf-gcc
|
||||||
|
ENV CC_armv7_unknown_linux_musleabihf=arm-linux-gnueabihf-gcc
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get -y install gcc-arm-linux-gnueabihf \
|
||||||
|
binutils-arm-linux-gnueabihf \
|
||||||
|
musl-tools
|
||||||
|
|
||||||
|
RUN rustup target add armv7-unknown-linux-musleabihf
|
||||||
|
|
||||||
|
WORKDIR /libreddit
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN cargo build --target armv7-unknown-linux-musleabihf --release
|
||||||
|
|
||||||
|
####################################################################################################
|
||||||
|
## Final image
|
||||||
|
####################################################################################################
|
||||||
|
FROM alpine:latest
|
||||||
|
|
||||||
|
# Import ca-certificates from builder
|
||||||
|
COPY --from=builder /usr/share/ca-certificates /usr/share/ca-certificates
|
||||||
|
COPY --from=builder /etc/ssl/certs /etc/ssl/certs
|
||||||
|
|
||||||
|
# Copy our build
|
||||||
|
COPY --from=builder /libreddit/target/armv7-unknown-linux-musleabihf/release/libreddit /usr/local/bin/libreddit
|
||||||
|
|
||||||
|
# Use an unprivileged user.
|
||||||
|
RUN adduser --home /nonexistent --no-create-home --disabled-password libreddit
|
||||||
|
USER libreddit
|
||||||
|
|
||||||
|
# Tell Docker to expose port 8080
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
# Run a healthcheck every minute to make sure Libreddit is functional
|
||||||
|
HEALTHCHECK --interval=1m --timeout=3s CMD wget --spider --q http://localhost:8080/settings || exit 1
|
||||||
|
|
||||||
|
CMD ["libreddit"]
|
75
README.md
75
README.md
@ -29,21 +29,39 @@ Feel free to [open an issue](https://github.com/spikecodes/libreddit/issues/new)
|
|||||||
|-|-|-|
|
|-|-|-|
|
||||||
| [libredd.it](https://libredd.it) (official) | 🇺🇸 US | |
|
| [libredd.it](https://libredd.it) (official) | 🇺🇸 US | |
|
||||||
| [libreddit.spike.codes](https://libreddit.spike.codes) (official) | 🇺🇸 US | |
|
| [libreddit.spike.codes](https://libreddit.spike.codes) (official) | 🇺🇸 US | |
|
||||||
| [libreddit.dothq.co](https://libreddit.dothq.co) | 🇺🇸 US | |
|
| [libreddit.dothq.co](https://libreddit.dothq.co) | 🇩🇪 DE | ✅ |
|
||||||
| [libreddit.kavin.rocks](https://libreddit.kavin.rocks) | 🇮🇳 IN | ✅ |
|
| [libreddit.kavin.rocks](https://libreddit.kavin.rocks) | 🇮🇳 IN | |
|
||||||
| [libreddit.bcow.xyz](https://libreddit.bcow.xyz) | 🇺🇸 US | |
|
|
||||||
| [libreddit.40two.app](https://libreddit.40two.app) | 🇳🇱 NL | |
|
| [libreddit.40two.app](https://libreddit.40two.app) | 🇳🇱 NL | |
|
||||||
| [reddit.invak.id](https://reddit.invak.id) | 🇧🇬 BG | |
|
| [reddit.invak.id](https://reddit.invak.id) | 🇧🇬 BG | |
|
||||||
| [reddit.phii.me](https://reddit.phii.me) | 🇺🇸 US | |
|
| [reddit.phii.me](https://reddit.phii.me) | 🇺🇸 US | |
|
||||||
| [lr.riverside.rocks](https://lr.riverside.rocks) | 🇺🇸 US | |
|
| [lr.riverside.rocks](https://lr.riverside.rocks) | 🇺🇸 US | |
|
||||||
| [libreddit.silkky.cloud](https://libreddit.silkky.cloud) | 🇫🇮 FI | |
|
| [libreddit.silkky.cloud](https://libreddit.silkky.cloud) | 🇫🇮 FI | ✅ |
|
||||||
| [libreddit.database.red](https://libreddit.database.red) | 🇺🇸 US | ✅ |
|
| [libreddit.database.red](https://libreddit.database.red) | 🇺🇸 US | ✅ |
|
||||||
| [libreddit.exonip.de](https://libreddit.exonip.de) | 🇩🇪 DE | |
|
| [libreddit.exonip.de](https://libreddit.exonip.de) | 🇩🇪 DE | |
|
||||||
| [libreddit.domain.glass](https://libreddit.domain.glass) | 🇺🇸 US | ✅ |
|
| [libreddit.domain.glass](https://libreddit.domain.glass) | 🇺🇸 US | ✅ |
|
||||||
|
| [libreddit.sugoma.tk](https://libreddit.sugoma.tk) | 🇺🇸 US | |
|
||||||
|
| [libreddit.trevorthalacker.com](https://libreddit.trevorthalacker.com) | 🇺🇸 US | ✅ |
|
||||||
|
| [reddit.artemislena.eu](https://reddit.artemislena.eu) | 🇩🇪 DE | |
|
||||||
|
| [r.nf](https://r.nf) | 🇩🇪 DE | ✅ |
|
||||||
|
| [libreddit.awesomehub.io](https://libreddit.awesomehub.io) | 🇫🇮 FI | |
|
||||||
|
| [libreddit.some-things.org](https://libreddit.some-things.org) | 🇨🇭 CH | |
|
||||||
|
| [reddit.stuehieyr.com](https://reddit.stuehieyr.com) | 🇩🇪 DE | |
|
||||||
|
| [lr.mint.lgbt](https://lr.mint.lgbt) | 🇨🇦 CA | |
|
||||||
|
| [libreddit.alefvanoon.xyz](https://libreddit.alefvanoon.xyz) | 🇺🇸 US | ✅ |
|
||||||
|
| [libreddit.igna.rocks](https://libreddit.igna.rocks) | 🇺🇸 US | |
|
||||||
|
| [libreddit.autarkic.org](https://libreddit.autarkic.org) | 🇺🇸 US | |
|
||||||
|
| [libreddit.flux.industries](https://libreddit.flux.industries) | 🇩🇪 DE | ✅ |
|
||||||
|
| [libreddit.drivet.xyz](https://libreddit.drivet.xyz) | 🇫🇮 FI | ✅ |
|
||||||
|
| [lr.oversold.host](https://lr.oversold.host) | 🇱🇺 LU | |
|
||||||
|
| [libreddit.de](https://libreddit.de) | 🇩🇪 DE | |
|
||||||
|
| [libreddit.pussthecat.org](https://libreddit.pussthecat.org) | 🇩🇪 DE | |
|
||||||
| [spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion](http://spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion) | 🇮🇳 IN | |
|
| [spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion](http://spjmllawtheisznfs7uryhxumin26ssv2draj7oope3ok3wuhy43eoyd.onion) | 🇮🇳 IN | |
|
||||||
| [fwhhsbrbltmrct5hshrnqlqygqvcgmnek3cnka55zj4y7nuus5muwyyd.onion](http://fwhhsbrbltmrct5hshrnqlqygqvcgmnek3cnka55zj4y7nuus5muwyyd.onion) | 🇩🇪 DE | |
|
| [fwhhsbrbltmrct5hshrnqlqygqvcgmnek3cnka55zj4y7nuus5muwyyd.onion](http://fwhhsbrbltmrct5hshrnqlqygqvcgmnek3cnka55zj4y7nuus5muwyyd.onion) | 🇩🇪 DE | |
|
||||||
| [dflv6yjt7il3n3tggf4qhcmkzbti2ppytqx3o7pjrzwgntutpewscyid.onion](http://dflv6yjt7il3n3tggf4qhcmkzbti2ppytqx3o7pjrzwgntutpewscyid.onion/) | 🇺🇸 US | |
|
| [kphht2jcflojtqte4b4kyx7p2ahagv4debjj32nre67dxz7y57seqwyd.onion](http://kphht2jcflojtqte4b4kyx7p2ahagv4debjj32nre67dxz7y57seqwyd.onion) | 🇳🇱 NL | |
|
||||||
| [kphht2jcflojtqte4b4kyx7p2ahagv4debjj32nre67dxz7y57seqwyd.onion](http://kphht2jcflojtqte4b4kyx7p2ahagv4debjj32nre67dxz7y57seqwyd.onion/) | 🇳🇱 NL | |
|
| [inytumdgnri7xsqtvpntjevaelxtgbjqkuqhtf6txxhwbll2fwqtakqd.onion](http://inytumdgnri7xsqtvpntjevaelxtgbjqkuqhtf6txxhwbll2fwqtakqd.onion) | 🇨🇭 CH | |
|
||||||
|
| [liredejj74h5xjqr2dylnl5howb2bpikfowqoveub55ru27x43357iid.onion](http://liredejj74h5xjqr2dylnl5howb2bpikfowqoveub55ru27x43357iid.onion) | 🇩🇪 DE | |
|
||||||
|
| [kzhfp3nvb4qp575vy23ccbrgfocezjtl5dx66uthgrhu7nscu6rcwjyd.onion](http://kzhfp3nvb4qp575vy23ccbrgfocezjtl5dx66uthgrhu7nscu6rcwjyd.onion) | 🇺🇸 US | |
|
||||||
|
|
||||||
|
|
||||||
A checkmark in the "Cloudflare" category here refers to the use of the reverse proxy, [Cloudflare](https://cloudflare). The checkmark will not be listed for a site which uses Cloudflare DNS but rather the proxying service which grants Cloudflare the ability to monitor traffic to the website.
|
A checkmark in the "Cloudflare" category here refers to the use of the reverse proxy, [Cloudflare](https://cloudflare). The checkmark will not be listed for a site which uses Cloudflare DNS but rather the proxying service which grants Cloudflare the ability to monitor traffic to the website.
|
||||||
|
|
||||||
@ -162,6 +180,8 @@ docker run -d --name libreddit -p 80:8080 spikecodes/libreddit
|
|||||||
|
|
||||||
To deploy on `arm64` platforms, simply replace `spikecodes/libreddit` in the commands above with `spikecodes/libreddit:arm`.
|
To deploy on `arm64` platforms, simply replace `spikecodes/libreddit` in the commands above with `spikecodes/libreddit:arm`.
|
||||||
|
|
||||||
|
To deploy on `armv7` platforms, simply replace `spikecodes/libreddit` in the commands above with `spikecodes/libreddit:armv7`.
|
||||||
|
|
||||||
## 3) AUR
|
## 3) AUR
|
||||||
|
|
||||||
For ArchLinux users, Libreddit is available from the AUR as [`libreddit-git`](https://aur.archlinux.org/packages/libreddit-git).
|
For ArchLinux users, Libreddit is available from the AUR as [`libreddit-git`](https://aur.archlinux.org/packages/libreddit-git).
|
||||||
@ -184,6 +204,10 @@ If you're on Linux and none of these methods work for you, you can grab a Linux
|
|||||||
|
|
||||||
In the web preview (defaults to top right), you should see your instance hosted where you can assign a [custom domain](https://docs.replit.com/repls/web-hosting#custom-domains).
|
In the web preview (defaults to top right), you should see your instance hosted where you can assign a [custom domain](https://docs.replit.com/repls/web-hosting#custom-domains).
|
||||||
|
|
||||||
|
## 6) Heroku
|
||||||
|
|
||||||
|
[](https://heroku.com/deploy?template=https://github.com/spikecodes/libreddit)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Deployment
|
# Deployment
|
||||||
@ -199,16 +223,16 @@ libreddit
|
|||||||
Assign a default value for each setting by passing environment variables to Libreddit in the format `LIBREDDIT_DEFAULT_{X}`. Replace `{X}` with the setting name (see list below) in capital letters.
|
Assign a default value for each setting by passing environment variables to Libreddit in the format `LIBREDDIT_DEFAULT_{X}`. Replace `{X}` with the setting name (see list below) in capital letters.
|
||||||
|
|
||||||
| Name | Possible values | Default value |
|
| Name | Possible values | Default value |
|
||||||
|-----------------------|----------------------------------------------------------------------------------------|---------------|
|
|-------------------------|------------------------------------------------------------------------------------------|---------------|
|
||||||
| theme | ["system", "light", "dark", "black", "dracula", "nord", "laserwave", "violet", "gold"] | system |
|
| `THEME` | `["system", "light", "dark", "black", "dracula", "nord", "laserwave", "violet", "gold"]` | `system` |
|
||||||
| front_page | ["default", "popular", "all"] | default |
|
| `FRONT_PAGE` | `["default", "popular", "all"]` | `default` |
|
||||||
| layout | ["card", "clean", "compact"] | card |
|
| `LAYOUT` | `["card", "clean", "compact"]` | `card` |
|
||||||
| wide | ["on", "off"] | off |
|
| `WIDE` | `["on", "off"]` | `off` |
|
||||||
| comment_sort | ["hot", "new", "top", "rising", "controversial"] | hot |
|
| `COMMENT_SORT` | `["hot", "new", "top", "rising", "controversial"]` | `hot` |
|
||||||
| post_sort | ["confidence", "top", "new", "controversial", "old"] | confidence |
|
| `POST_SORT` | `["confidence", "top", "new", "controversial", "old"]` | `confidence` |
|
||||||
| show_nsfw | ["on", "off"] | off |
|
| `SHOW_NSFW` | `["on", "off"]` | `off` |
|
||||||
| use_hls | ["on", "off"] | off |
|
| `USE_HLS` | `["on", "off"]` | `off` |
|
||||||
| hide_hls_notification | ["on", "off"] | off |
|
| `HIDE_HLS_NOTIFICATION` | `["on", "off"]` | `off` |
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
@ -228,6 +252,25 @@ proxy_http_version 1.1;
|
|||||||
```
|
```
|
||||||
to your NGINX configuration file above your `proxy_pass` line.
|
to your NGINX configuration file above your `proxy_pass` line.
|
||||||
|
|
||||||
|
## systemd
|
||||||
|
|
||||||
|
You can use the systemd service available in `contrib/libreddit.service`
|
||||||
|
(install it on `/etc/systemd/system/libreddit.service`).
|
||||||
|
|
||||||
|
That service can be optionally configured in terms of environment variables by
|
||||||
|
creating a file in `/etc/libreddit.conf`. Use the `contrib/libreddit.conf` as a
|
||||||
|
template. You can also add the `LIBREDDIT_DEFAULT__{X}` settings explained
|
||||||
|
above.
|
||||||
|
|
||||||
|
When "Proxying using NGINX" where the proxy is on the same machine, you should
|
||||||
|
guarantee nginx waits for this service to start. Edit
|
||||||
|
`/etc/systemd/system/libreddit.service.d/reverse-proxy.conf`:
|
||||||
|
|
||||||
|
```conf
|
||||||
|
[Unit]
|
||||||
|
Before=nginx.service
|
||||||
|
```
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
```
|
```
|
||||||
|
42
app.json
Normal file
42
app.json
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"name": "Libreddit",
|
||||||
|
"description": "Private front-end for Reddit",
|
||||||
|
"buildpacks": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/emk/heroku-buildpack-rust"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "emk/rust"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stack": "container",
|
||||||
|
"env": {
|
||||||
|
"LIBREDDIT_DEFAULT_THEME": {
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
"LIBREDDIT_DEFAULT_FRONT_PAGE": {
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
"LIBREDDIT_DEFAULT_LAYOUT": {
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
"LIBREDDIT_DEFAULT_WIDE": {
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
"LIBREDDIT_DEFAULT_COMMENT_SORT": {
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
"LIBREDDIT_DEFAULT_POST_SORT": {
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
"LIBREDDIT_DEFAULT_SHOW_NSFW": {
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
"LIBREDDIT_USE_HLS": {
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
"LIBREDDIT_HIDE_HLS_NOTIFICATION": {
|
||||||
|
"required": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
contrib/libreddit.conf
Normal file
2
contrib/libreddit.conf
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
ADDRESS=localhost
|
||||||
|
PORT=12345
|
15
contrib/libreddit.service
Normal file
15
contrib/libreddit.service
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=libreddit daemon
|
||||||
|
After=network.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
DynamicUser=yes
|
||||||
|
# Default Values
|
||||||
|
Environment=ADDRESS=0.0.0.0
|
||||||
|
Environment=PORT=8080
|
||||||
|
# Optional Override
|
||||||
|
EnvironmentFile=-/etc/libreddit.conf
|
||||||
|
ExecStart=/usr/bin/libreddit -a ${ADDRESS} -p ${PORT}
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
@ -8,6 +8,6 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- 8080:8080
|
- 8080:8080
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:8080/settings"]
|
test: ["CMD", "wget", "--spider", "-q", "--tries=1", "http://localhost:8080/settings"]
|
||||||
interval: 5m
|
interval: 5m
|
||||||
timeout: 3s
|
timeout: 3s
|
3
heroku.yml
Normal file
3
heroku.yml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
build:
|
||||||
|
docker:
|
||||||
|
web: Dockerfile
|
@ -9,7 +9,9 @@ use crate::server::RequestExt;
|
|||||||
pub async fn proxy(req: Request<Body>, format: &str) -> Result<Response<Body>, String> {
|
pub async fn proxy(req: Request<Body>, format: &str) -> Result<Response<Body>, String> {
|
||||||
let mut url = format!("{}?{}", format, req.uri().query().unwrap_or_default());
|
let mut url = format!("{}?{}", format, req.uri().query().unwrap_or_default());
|
||||||
|
|
||||||
|
// For each parameter in request
|
||||||
for (name, value) in req.params().iter() {
|
for (name, value) in req.params().iter() {
|
||||||
|
// Fill the parameter value in the url
|
||||||
url = url.replace(&format!("{{{}}}", name), value);
|
url = url.replace(&format!("{{{}}}", name), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,14 +31,13 @@ async fn stream(url: &str, req: &Request<Body>) -> Result<Response<Body>, String
|
|||||||
let mut builder = Request::get(url);
|
let mut builder = Request::get(url);
|
||||||
|
|
||||||
// Copy useful headers from original request
|
// Copy useful headers from original request
|
||||||
let headers = req.headers();
|
|
||||||
for &key in &["Range", "If-Modified-Since", "Cache-Control"] {
|
for &key in &["Range", "If-Modified-Since", "Cache-Control"] {
|
||||||
if let Some(value) = headers.get(key) {
|
if let Some(value) = req.headers().get(key) {
|
||||||
builder = builder.header(key, value);
|
builder = builder.header(key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let stream_request = builder.body(Body::default()).expect("stream");
|
let stream_request = builder.body(Body::empty()).map_err(|_| "Couldn't build empty body in stream".to_string())?;
|
||||||
|
|
||||||
client
|
client
|
||||||
.request(stream_request)
|
.request(stream_request)
|
||||||
@ -64,9 +65,10 @@ fn request(url: String, quarantine: bool) -> Boxed<Result<Response<Body>, String
|
|||||||
// Prepare the HTTPS connector.
|
// Prepare the HTTPS connector.
|
||||||
let https = hyper_rustls::HttpsConnector::with_native_roots();
|
let https = hyper_rustls::HttpsConnector::with_native_roots();
|
||||||
|
|
||||||
// Build 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::Client::builder().build(https);
|
||||||
|
|
||||||
|
// Build request
|
||||||
let builder = Request::builder()
|
let builder = Request::builder()
|
||||||
.method("GET")
|
.method("GET")
|
||||||
.uri(&url)
|
.uri(&url)
|
||||||
@ -120,6 +122,8 @@ pub async fn json(path: String, quarantine: bool) -> Result<Value, String> {
|
|||||||
// Fetch the url...
|
// Fetch the url...
|
||||||
match request(url.clone(), quarantine).await {
|
match request(url.clone(), quarantine).await {
|
||||||
Ok(response) => {
|
Ok(response) => {
|
||||||
|
let status = response.status();
|
||||||
|
|
||||||
// asynchronously aggregate the chunks of the body
|
// asynchronously aggregate the chunks of the body
|
||||||
match hyper::body::aggregate(response).await {
|
match hyper::body::aggregate(response).await {
|
||||||
Ok(body) => {
|
Ok(body) => {
|
||||||
@ -144,7 +148,13 @@ pub async fn json(path: String, quarantine: bool) -> Result<Value, String> {
|
|||||||
Ok(json)
|
Ok(json)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => err("Failed to parse page JSON data", e.to_string()),
|
Err(e) => {
|
||||||
|
if status.is_server_error() {
|
||||||
|
Err("Reddit is having issues, check if there's an outage".to_string())
|
||||||
|
} else {
|
||||||
|
err("Failed to parse page JSON data", e.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => err("Failed receiving body from Reddit", e.to_string()),
|
Err(e) => err("Failed receiving body from Reddit", e.to_string()),
|
||||||
|
30
src/main.rs
30
src/main.rs
@ -3,11 +3,10 @@
|
|||||||
#![warn(clippy::pedantic, clippy::all)]
|
#![warn(clippy::pedantic, clippy::all)]
|
||||||
#![allow(
|
#![allow(
|
||||||
clippy::needless_pass_by_value,
|
clippy::needless_pass_by_value,
|
||||||
clippy::match_wildcard_for_single_variants,
|
|
||||||
clippy::cast_possible_truncation,
|
clippy::cast_possible_truncation,
|
||||||
clippy::similar_names,
|
|
||||||
clippy::cast_possible_wrap,
|
clippy::cast_possible_wrap,
|
||||||
clippy::find_map
|
clippy::manual_find_map,
|
||||||
|
clippy::unused_async
|
||||||
)]
|
)]
|
||||||
|
|
||||||
// Reference local files
|
// Reference local files
|
||||||
@ -97,6 +96,13 @@ async fn main() {
|
|||||||
let matches = cli::new("Libreddit")
|
let matches = cli::new("Libreddit")
|
||||||
.version(env!("CARGO_PKG_VERSION"))
|
.version(env!("CARGO_PKG_VERSION"))
|
||||||
.about("Private front-end for Reddit written in Rust ")
|
.about("Private front-end for Reddit written in Rust ")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("redirect-https")
|
||||||
|
.short("r")
|
||||||
|
.long("redirect-https")
|
||||||
|
.help("Redirect all HTTP requests to HTTPS (no longer functional)")
|
||||||
|
.takes_value(false),
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("address")
|
Arg::with_name("address")
|
||||||
.short("a")
|
.short("a")
|
||||||
@ -115,13 +121,6 @@ async fn main() {
|
|||||||
.default_value("8080")
|
.default_value("8080")
|
||||||
.takes_value(true),
|
.takes_value(true),
|
||||||
)
|
)
|
||||||
.arg(
|
|
||||||
Arg::with_name("redirect-https")
|
|
||||||
.short("r")
|
|
||||||
.long("redirect-https")
|
|
||||||
.help("Redirect all HTTP requests to HTTPS (no longer functional)")
|
|
||||||
.takes_value(false),
|
|
||||||
)
|
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("hsts")
|
Arg::with_name("hsts")
|
||||||
.short("H")
|
.short("H")
|
||||||
@ -134,10 +133,11 @@ async fn main() {
|
|||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
let address = matches.value_of("address").unwrap_or("0.0.0.0");
|
let address = matches.value_of("address").unwrap_or("0.0.0.0");
|
||||||
let port = matches.value_of("port").unwrap_or("8080");
|
let port = std::env::var("PORT")
|
||||||
|
.unwrap_or_else(|_| matches.value_of("port").unwrap_or("8080").to_string());
|
||||||
let hsts = matches.value_of("hsts");
|
let hsts = matches.value_of("hsts");
|
||||||
|
|
||||||
let listener = format!("{}:{}", address, port);
|
let listener = [address, ":", &port].concat();
|
||||||
|
|
||||||
println!("Starting Libreddit...");
|
println!("Starting Libreddit...");
|
||||||
|
|
||||||
@ -163,7 +163,9 @@ async fn main() {
|
|||||||
app
|
app
|
||||||
.at("/manifest.json")
|
.at("/manifest.json")
|
||||||
.get(|_| resource(include_str!("../static/manifest.json"), "application/json", false).boxed());
|
.get(|_| resource(include_str!("../static/manifest.json"), "application/json", false).boxed());
|
||||||
app.at("/robots.txt").get(|_| resource("User-agent: *\nAllow: /", "text/plain", true).boxed());
|
app
|
||||||
|
.at("/robots.txt")
|
||||||
|
.get(|_| resource("User-agent: *\nDisallow: /u/\nDisallow: /user/", "text/plain", true).boxed());
|
||||||
app.at("/favicon.ico").get(|_| favicon().boxed());
|
app.at("/favicon.ico").get(|_| favicon().boxed());
|
||||||
app.at("/logo.png").get(|_| pwa_logo().boxed());
|
app.at("/logo.png").get(|_| pwa_logo().boxed());
|
||||||
app.at("/Inter.var.woff2").get(|_| font().boxed());
|
app.at("/Inter.var.woff2").get(|_| font().boxed());
|
||||||
@ -258,7 +260,7 @@ async fn main() {
|
|||||||
|
|
||||||
app.at("/:id").get(|req: Request<Body>| match req.param("id").as_deref() {
|
app.at("/:id").get(|req: Request<Body>| match req.param("id").as_deref() {
|
||||||
// Sort front page
|
// Sort front page
|
||||||
Some("best") | Some("hot") | Some("new") | Some("top") | Some("rising") | Some("controversial") => subreddit::community(req).boxed(),
|
Some("best" | "hot" | "new" | "top" | "rising" | "controversial") => subreddit::community(req).boxed(),
|
||||||
// Short link for post
|
// Short link for post
|
||||||
Some(id) if id.len() > 4 && id.len() < 7 => post::item(req).boxed(),
|
Some(id) if id.len() > 4 && id.len() < 7 => post::item(req).boxed(),
|
||||||
// Error message for unknown pages
|
// Error message for unknown pages
|
||||||
|
41
src/post.rs
41
src/post.rs
@ -7,8 +7,6 @@ use crate::utils::{error, format_num, format_url, param, rewrite_urls, setting,
|
|||||||
|
|
||||||
use hyper::{Body, Request, Response};
|
use hyper::{Body, Request, Response};
|
||||||
|
|
||||||
use async_recursion::async_recursion;
|
|
||||||
|
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
|
|
||||||
// STRUCTS
|
// STRUCTS
|
||||||
@ -20,6 +18,7 @@ struct PostTemplate {
|
|||||||
sort: String,
|
sort: String,
|
||||||
prefs: Preferences,
|
prefs: Preferences,
|
||||||
single_thread: bool,
|
single_thread: bool,
|
||||||
|
url: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn item(req: Request<Body>) -> Result<Response<Body>, String> {
|
pub async fn item(req: Request<Body>) -> Result<Response<Body>, String> {
|
||||||
@ -52,10 +51,11 @@ pub async fn item(req: Request<Body>) -> Result<Response<Body>, String> {
|
|||||||
// Send a request to the url, receive JSON in response
|
// Send a request to the url, receive JSON in response
|
||||||
match json(path, quarantined).await {
|
match json(path, quarantined).await {
|
||||||
// Otherwise, grab the JSON output from the request
|
// Otherwise, grab the JSON output from the request
|
||||||
Ok(res) => {
|
Ok(response) => {
|
||||||
// Parse the JSON into Post and Comment structs
|
// Parse the JSON into Post and Comment structs
|
||||||
let post = parse_post(&res[0]).await;
|
let post = parse_post(&response[0]).await;
|
||||||
let comments = parse_comments(&res[1], &post.permalink, &post.author.name, highlighted_comment).await;
|
let comments = parse_comments(&response[1], &post.permalink, &post.author.name, highlighted_comment);
|
||||||
|
let url = req.uri().to_string();
|
||||||
|
|
||||||
// Use the Post and Comment structs to generate a website to show users
|
// Use the Post and Comment structs to generate a website to show users
|
||||||
template(PostTemplate {
|
template(PostTemplate {
|
||||||
@ -64,6 +64,7 @@ pub async fn item(req: Request<Body>) -> Result<Response<Body>, String> {
|
|||||||
sort,
|
sort,
|
||||||
prefs: Preferences::new(req),
|
prefs: Preferences::new(req),
|
||||||
single_thread,
|
single_thread,
|
||||||
|
url,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 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
|
||||||
@ -151,35 +152,28 @@ async fn parse_post(json: &serde_json::Value) -> Post {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// COMMENTS
|
// COMMENTS
|
||||||
#[async_recursion]
|
fn parse_comments(json: &serde_json::Value, post_link: &str, post_author: &str, highlighted_comment: &str) -> Vec<Comment> {
|
||||||
async fn parse_comments(json: &serde_json::Value, post_link: &str, post_author: &str, highlighted_comment: &str) -> Vec<Comment> {
|
// Parse the comment JSON into a Vector of Comments
|
||||||
// Separate the comment JSON into a Vector of comments
|
let comments = json["data"]["children"].as_array().map_or(Vec::new(), std::borrow::ToOwned::to_owned);
|
||||||
let comment_data = match json["data"]["children"].as_array() {
|
|
||||||
Some(f) => f.to_owned(),
|
|
||||||
None => Vec::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut comments: Vec<Comment> = Vec::new();
|
|
||||||
|
|
||||||
// For each comment, retrieve the values to build a Comment object
|
// For each comment, retrieve the values to build a Comment object
|
||||||
for comment in comment_data {
|
comments
|
||||||
|
.into_iter()
|
||||||
|
.map(|comment| {
|
||||||
let kind = comment["kind"].as_str().unwrap_or_default().to_string();
|
let kind = comment["kind"].as_str().unwrap_or_default().to_string();
|
||||||
let data = &comment["data"];
|
let data = &comment["data"];
|
||||||
|
|
||||||
let unix_time = data["created_utc"].as_f64().unwrap_or_default();
|
let unix_time = data["created_utc"].as_f64().unwrap_or_default();
|
||||||
let (rel_time, created) = time(unix_time);
|
let (rel_time, created) = time(unix_time);
|
||||||
|
|
||||||
let edited = match data["edited"].as_f64() {
|
let edited = data["edited"].as_f64().map_or((String::new(), String::new()), time);
|
||||||
Some(stamp) => time(stamp),
|
|
||||||
None => (String::new(), String::new()),
|
|
||||||
};
|
|
||||||
|
|
||||||
let score = data["score"].as_i64().unwrap_or(0);
|
let score = data["score"].as_i64().unwrap_or(0);
|
||||||
let body = rewrite_urls(&val(&comment, "body_html"));
|
let body = rewrite_urls(&val(&comment, "body_html"));
|
||||||
|
|
||||||
// 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).await
|
parse_comments(&data["replies"], post_link, post_author, highlighted_comment)
|
||||||
} else {
|
} else {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
};
|
};
|
||||||
@ -190,7 +184,7 @@ async fn parse_comments(json: &serde_json::Value, post_link: &str, post_author:
|
|||||||
let id = val(&comment, "id");
|
let id = val(&comment, "id");
|
||||||
let highlighted = id == highlighted_comment;
|
let highlighted = id == highlighted_comment;
|
||||||
|
|
||||||
comments.push(Comment {
|
Comment {
|
||||||
id,
|
id,
|
||||||
kind,
|
kind,
|
||||||
parent_id: parent_info[1].to_string(),
|
parent_id: parent_info[1].to_string(),
|
||||||
@ -222,8 +216,7 @@ async fn parse_comments(json: &serde_json::Value, post_link: &str, post_author:
|
|||||||
edited,
|
edited,
|
||||||
replies,
|
replies,
|
||||||
highlighted,
|
highlighted,
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
comments
|
.collect()
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// CRATES
|
// CRATES
|
||||||
use crate::utils::{catch_random, error, format_num, format_url, param, setting, template, val, Post, Preferences};
|
use crate::utils::{catch_random, error, format_num, format_url, param, redirect, setting, template, val, Post, Preferences};
|
||||||
use crate::{
|
use crate::{
|
||||||
client::json,
|
client::json,
|
||||||
subreddit::{can_access_quarantine, quarantine},
|
subreddit::{can_access_quarantine, quarantine},
|
||||||
@ -42,20 +42,23 @@ struct SearchTemplate {
|
|||||||
pub async fn find(req: Request<Body>) -> Result<Response<Body>, String> {
|
pub async fn find(req: Request<Body>) -> Result<Response<Body>, String> {
|
||||||
let nsfw_results = if setting(&req, "show_nsfw") == "on" { "&include_over_18=on" } else { "" };
|
let nsfw_results = if setting(&req, "show_nsfw") == "on" { "&include_over_18=on" } else { "" };
|
||||||
let path = format!("{}.json?{}{}", req.uri().path(), req.uri().query().unwrap_or_default(), nsfw_results);
|
let path = format!("{}.json?{}{}", req.uri().path(), req.uri().query().unwrap_or_default(), nsfw_results);
|
||||||
|
let query = param(&path, "q").unwrap_or_default();
|
||||||
|
|
||||||
|
if query.is_empty() {
|
||||||
|
return Ok(redirect("/".to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
let sub = req.param("sub").unwrap_or_default();
|
let sub = req.param("sub").unwrap_or_default();
|
||||||
let quarantined = can_access_quarantine(&req, &sub);
|
let quarantined = can_access_quarantine(&req, &sub);
|
||||||
// Handle random subreddits
|
// Handle random subreddits
|
||||||
if let Ok(random) = catch_random(&sub, "/find").await {
|
if let Ok(random) = catch_random(&sub, "/find").await {
|
||||||
return Ok(random);
|
return Ok(random);
|
||||||
}
|
}
|
||||||
let query = param(&path, "q").unwrap_or_default();
|
|
||||||
|
|
||||||
let sort = param(&path, "sort").unwrap_or_else(|| "relevance".to_string());
|
let sort = param(&path, "sort").unwrap_or_else(|| "relevance".to_string());
|
||||||
|
|
||||||
let subreddits = match param(&path, "restrict_sr") {
|
// If search is not restricted to this subreddit, show other subreddits in search results
|
||||||
None => search_subreddits(&query).await,
|
let subreddits = param(&path, "restrict_sr").map_or(search_subreddits(&query).await, |_| Vec::new());
|
||||||
Some(_) => Vec::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let url = String::from(req.uri().path_and_query().map_or("", |val| val.as_str()));
|
let url = String::from(req.uri().path_and_query().map_or("", |val| val.as_str()));
|
||||||
|
|
||||||
@ -90,21 +93,17 @@ async fn search_subreddits(q: &str) -> Vec<Subreddit> {
|
|||||||
let subreddit_search_path = format!("/subreddits/search.json?q={}&limit=3", q.replace(' ', "+"));
|
let subreddit_search_path = format!("/subreddits/search.json?q={}&limit=3", q.replace(' ', "+"));
|
||||||
|
|
||||||
// Send a request to the url
|
// Send a request to the url
|
||||||
match json(subreddit_search_path, false).await {
|
json(subreddit_search_path, false).await.unwrap_or_default()["data"]["children"]
|
||||||
// If success, receive JSON in response
|
.as_array()
|
||||||
Ok(response) => {
|
.map(ToOwned::to_owned)
|
||||||
match response["data"]["children"].as_array() {
|
.unwrap_or_default()
|
||||||
// For each subreddit from subreddit list
|
|
||||||
Some(list) => list
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|subreddit| {
|
.map(|subreddit| {
|
||||||
|
// For each subreddit from subreddit list
|
||||||
// Fetch subreddit icon either from the community_icon or icon_img value
|
// Fetch subreddit icon either from the community_icon or icon_img value
|
||||||
let community_icon: &str = subreddit["data"]["community_icon"].as_str().map_or("", |s| s.split('?').collect::<Vec<&str>>()[0]);
|
let icon = subreddit["data"]["community_icon"]
|
||||||
let icon = if community_icon.is_empty() {
|
.as_str()
|
||||||
val(&subreddit, "icon_img")
|
.map_or_else(|| val(subreddit, "icon_img"), ToString::to_string);
|
||||||
} else {
|
|
||||||
community_icon.to_string()
|
|
||||||
};
|
|
||||||
|
|
||||||
Subreddit {
|
Subreddit {
|
||||||
name: val(subreddit, "display_name_prefixed"),
|
name: val(subreddit, "display_name_prefixed"),
|
||||||
@ -114,11 +113,5 @@ async fn search_subreddits(q: &str) -> Vec<Subreddit> {
|
|||||||
subscribers: format_num(subreddit["data"]["subscribers"].as_f64().unwrap_or_default() as i64),
|
subscribers: format_num(subreddit["data"]["subscribers"].as_f64().unwrap_or_default() as i64),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<Subreddit>>(),
|
.collect::<Vec<Subreddit>>()
|
||||||
_ => Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If the Reddit API returns an error, exit this function
|
|
||||||
_ => Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ pub trait ResponseExt {
|
|||||||
|
|
||||||
impl RequestExt for Request<Body> {
|
impl RequestExt for Request<Body> {
|
||||||
fn params(&self) -> Params {
|
fn params(&self) -> Params {
|
||||||
self.extensions().get::<Params>().unwrap_or(&Params::new()).to_owned()
|
self.extensions().get::<Params>().unwrap_or(&Params::new()).clone()
|
||||||
// self.extensions()
|
// self.extensions()
|
||||||
// .get::<RequestMeta>()
|
// .get::<RequestMeta>()
|
||||||
// .and_then(|meta| meta.route_params())
|
// .and_then(|meta| meta.route_params())
|
||||||
@ -69,29 +69,31 @@ impl RequestExt for Request<Body> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn cookies(&self) -> Vec<Cookie> {
|
fn cookies(&self) -> Vec<Cookie> {
|
||||||
let mut cookies = Vec::new();
|
self.headers().get("Cookie").map_or(Vec::new(), |header| {
|
||||||
if let Some(header) = self.headers().get("Cookie") {
|
header
|
||||||
for cookie in header.to_str().unwrap_or_default().split("; ") {
|
.to_str()
|
||||||
cookies.push(Cookie::parse(cookie).unwrap_or_else(|_| Cookie::named("")));
|
.unwrap_or_default()
|
||||||
}
|
.split("; ")
|
||||||
}
|
.map(|cookie| Cookie::parse(cookie).unwrap_or_else(|_| Cookie::named("")))
|
||||||
cookies
|
.collect()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cookie(&self, name: &str) -> Option<Cookie> {
|
fn cookie(&self, name: &str) -> Option<Cookie> {
|
||||||
self.cookies().iter().find(|c| c.name() == name).map(std::borrow::ToOwned::to_owned)
|
self.cookies().into_iter().find(|c| c.name() == name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResponseExt for Response<Body> {
|
impl ResponseExt for Response<Body> {
|
||||||
fn cookies(&self) -> Vec<Cookie> {
|
fn cookies(&self) -> Vec<Cookie> {
|
||||||
let mut cookies = Vec::new();
|
self.headers().get("Cookie").map_or(Vec::new(), |header| {
|
||||||
for header in self.headers().get_all("Cookie") {
|
header
|
||||||
if let Ok(cookie) = Cookie::parse(header.to_str().unwrap_or_default()) {
|
.to_str()
|
||||||
cookies.push(cookie);
|
.unwrap_or_default()
|
||||||
}
|
.split("; ")
|
||||||
}
|
.map(|cookie| Cookie::parse(cookie).unwrap_or_else(|_| Cookie::named("")))
|
||||||
cookies
|
.collect()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_cookie(&mut self, cookie: Cookie) {
|
fn insert_cookie(&mut self, cookie: Cookie) {
|
||||||
@ -144,6 +146,7 @@ impl Server {
|
|||||||
|
|
||||||
pub fn listen(self, addr: String) -> Boxed<Result<(), hyper::Error>> {
|
pub fn listen(self, addr: String) -> Boxed<Result<(), hyper::Error>> {
|
||||||
let make_svc = make_service_fn(move |_conn| {
|
let make_svc = make_service_fn(move |_conn| {
|
||||||
|
// For correct borrowing, these values need to be borrowed
|
||||||
let router = self.router.clone();
|
let router = self.router.clone();
|
||||||
let default_headers = self.default_headers.clone();
|
let default_headers = self.default_headers.clone();
|
||||||
|
|
||||||
@ -159,7 +162,7 @@ impl Server {
|
|||||||
let mut path = req.uri().path().replace("//", "/");
|
let mut path = req.uri().path().replace("//", "/");
|
||||||
|
|
||||||
// Remove trailing slashes
|
// Remove trailing slashes
|
||||||
if path.ends_with('/') && path != "/" {
|
if path != "/" && path.ends_with('/') {
|
||||||
path.pop();
|
path.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,7 +171,7 @@ impl Server {
|
|||||||
// If a route was configured for this path
|
// If a route was configured for this path
|
||||||
Ok(found) => {
|
Ok(found) => {
|
||||||
let mut parammed = req;
|
let mut parammed = req;
|
||||||
parammed.set_params(found.params().to_owned());
|
parammed.set_params(found.params().clone());
|
||||||
|
|
||||||
// Run the route's function
|
// Run the route's function
|
||||||
let func = (found.handler().to_owned().to_owned())(parammed);
|
let func = (found.handler().to_owned().to_owned())(parammed);
|
||||||
@ -198,17 +201,15 @@ impl Server {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Build SocketAddr from provided address
|
||||||
let address = &addr.parse().unwrap_or_else(|_| panic!("Cannot parse {} as address (example format: 0.0.0.0:8080)", addr));
|
let address = &addr.parse().unwrap_or_else(|_| panic!("Cannot parse {} as address (example format: 0.0.0.0:8080)", addr));
|
||||||
|
|
||||||
let server = HyperServer::bind(address).serve(make_svc);
|
// Bind server to address specified above. Gracefully shut down if CTRL+C is pressed
|
||||||
|
let server = HyperServer::bind(address).serve(make_svc).with_graceful_shutdown(async {
|
||||||
let graceful = server.with_graceful_shutdown(shutdown_signal());
|
|
||||||
|
|
||||||
graceful.boxed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn shutdown_signal() {
|
|
||||||
// Wait for the CTRL+C signal
|
// Wait for the CTRL+C signal
|
||||||
tokio::signal::ctrl_c().await.expect("Failed to install CTRL+C signal handler");
|
tokio::signal::ctrl_c().await.expect("Failed to install CTRL+C signal handler");
|
||||||
|
});
|
||||||
|
|
||||||
|
server.boxed()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,11 +14,12 @@ use time::{Duration, OffsetDateTime};
|
|||||||
#[template(path = "settings.html")]
|
#[template(path = "settings.html")]
|
||||||
struct SettingsTemplate {
|
struct SettingsTemplate {
|
||||||
prefs: Preferences,
|
prefs: Preferences,
|
||||||
|
url: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
// CONSTANTS
|
// CONSTANTS
|
||||||
|
|
||||||
const PREFS: [&str; 9] = [
|
const PREFS: [&str; 10] = [
|
||||||
"theme",
|
"theme",
|
||||||
"front_page",
|
"front_page",
|
||||||
"layout",
|
"layout",
|
||||||
@ -28,13 +29,18 @@ const PREFS: [&str; 9] = [
|
|||||||
"show_nsfw",
|
"show_nsfw",
|
||||||
"use_hls",
|
"use_hls",
|
||||||
"hide_hls_notification",
|
"hide_hls_notification",
|
||||||
|
"autoplay_videos",
|
||||||
];
|
];
|
||||||
|
|
||||||
// FUNCTIONS
|
// FUNCTIONS
|
||||||
|
|
||||||
// Retrieve cookies from request "Cookie" header
|
// Retrieve cookies from request "Cookie" header
|
||||||
pub async fn get(req: Request<Body>) -> Result<Response<Body>, String> {
|
pub async fn get(req: Request<Body>) -> Result<Response<Body>, String> {
|
||||||
template(SettingsTemplate { prefs: Preferences::new(req) })
|
let url = req.uri().to_string();
|
||||||
|
template(SettingsTemplate {
|
||||||
|
prefs: Preferences::new(req),
|
||||||
|
url,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set cookies using response "Set-Cookie" header
|
// Set cookies using response "Set-Cookie" header
|
||||||
@ -43,12 +49,12 @@ pub async fn set(req: Request<Body>) -> Result<Response<Body>, String> {
|
|||||||
let (parts, mut body) = req.into_parts();
|
let (parts, mut body) = req.into_parts();
|
||||||
|
|
||||||
// Grab existing cookies
|
// Grab existing cookies
|
||||||
let mut cookies = Vec::new();
|
let _cookies: Vec<Cookie> = parts
|
||||||
for header in parts.headers.get_all("Cookie") {
|
.headers
|
||||||
if let Ok(cookie) = Cookie::parse(header.to_str().unwrap_or_default()) {
|
.get_all("Cookie")
|
||||||
cookies.push(cookie);
|
.iter()
|
||||||
}
|
.filter_map(|header| Cookie::parse(header.to_str().unwrap_or_default()).ok())
|
||||||
}
|
.collect();
|
||||||
|
|
||||||
// Aggregate the body...
|
// Aggregate the body...
|
||||||
// let whole_body = hyper::body::aggregate(req).await.map_err(|e| e.to_string())?;
|
// let whole_body = hyper::body::aggregate(req).await.map_err(|e| e.to_string())?;
|
||||||
@ -62,22 +68,22 @@ pub async fn set(req: Request<Body>) -> Result<Response<Body>, String> {
|
|||||||
|
|
||||||
let form = url::form_urlencoded::parse(&body_bytes).collect::<HashMap<_, _>>();
|
let form = url::form_urlencoded::parse(&body_bytes).collect::<HashMap<_, _>>();
|
||||||
|
|
||||||
let mut res = redirect("/settings".to_string());
|
let mut response = redirect("/settings".to_string());
|
||||||
|
|
||||||
for &name in &PREFS {
|
for &name in &PREFS {
|
||||||
match form.get(name) {
|
match form.get(name) {
|
||||||
Some(value) => res.insert_cookie(
|
Some(value) => response.insert_cookie(
|
||||||
Cookie::build(name.to_owned(), value.to_owned())
|
Cookie::build(name.to_owned(), value.clone())
|
||||||
.path("/")
|
.path("/")
|
||||||
.http_only(true)
|
.http_only(true)
|
||||||
.expires(OffsetDateTime::now_utc() + Duration::weeks(52))
|
.expires(OffsetDateTime::now_utc() + Duration::weeks(52))
|
||||||
.finish(),
|
.finish(),
|
||||||
),
|
),
|
||||||
None => res.remove_cookie(name.to_string()),
|
None => response.remove_cookie(name.to_string()),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(res)
|
Ok(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_cookies_method(req: Request<Body>, remove_cookies: bool) -> Response<Body> {
|
fn set_cookies_method(req: Request<Body>, remove_cookies: bool) -> Response<Body> {
|
||||||
@ -85,12 +91,12 @@ fn set_cookies_method(req: Request<Body>, remove_cookies: bool) -> Response<Body
|
|||||||
let (parts, _) = req.into_parts();
|
let (parts, _) = req.into_parts();
|
||||||
|
|
||||||
// Grab existing cookies
|
// Grab existing cookies
|
||||||
let mut cookies = Vec::new();
|
let _cookies: Vec<Cookie> = parts
|
||||||
for header in parts.headers.get_all("Cookie") {
|
.headers
|
||||||
if let Ok(cookie) = Cookie::parse(header.to_str().unwrap_or_default()) {
|
.get_all("Cookie")
|
||||||
cookies.push(cookie);
|
.iter()
|
||||||
}
|
.filter_map(|header| Cookie::parse(header.to_str().unwrap_or_default()).ok())
|
||||||
}
|
.collect();
|
||||||
|
|
||||||
let query = parts.uri.query().unwrap_or_default().as_bytes();
|
let query = parts.uri.query().unwrap_or_default().as_bytes();
|
||||||
|
|
||||||
@ -101,12 +107,12 @@ fn set_cookies_method(req: Request<Body>, remove_cookies: bool) -> Response<Body
|
|||||||
None => "/".to_string(),
|
None => "/".to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut res = redirect(path);
|
let mut response = redirect(path);
|
||||||
|
|
||||||
for name in [PREFS.to_vec(), vec!["subscriptions"]].concat() {
|
for name in [PREFS.to_vec(), vec!["subscriptions"]].concat() {
|
||||||
match form.get(name) {
|
match form.get(name) {
|
||||||
Some(value) => res.insert_cookie(
|
Some(value) => response.insert_cookie(
|
||||||
Cookie::build(name.to_owned(), value.to_owned())
|
Cookie::build(name.to_owned(), value.clone())
|
||||||
.path("/")
|
.path("/")
|
||||||
.http_only(true)
|
.http_only(true)
|
||||||
.expires(OffsetDateTime::now_utc() + Duration::weeks(52))
|
.expires(OffsetDateTime::now_utc() + Duration::weeks(52))
|
||||||
@ -114,13 +120,13 @@ fn set_cookies_method(req: Request<Body>, remove_cookies: bool) -> Response<Body
|
|||||||
),
|
),
|
||||||
None => {
|
None => {
|
||||||
if remove_cookies {
|
if remove_cookies {
|
||||||
res.remove_cookie(name.to_string())
|
response.remove_cookie(name.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
res
|
response
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set cookies using response "Set-Cookie" header
|
// Set cookies using response "Set-Cookie" header
|
||||||
|
119
src/subreddit.rs
119
src/subreddit.rs
@ -26,6 +26,7 @@ struct WikiTemplate {
|
|||||||
wiki: String,
|
wiki: String,
|
||||||
page: String,
|
page: String,
|
||||||
prefs: Preferences,
|
prefs: Preferences,
|
||||||
|
url: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
@ -51,10 +52,10 @@ pub async fn community(req: Request<Body>) -> Result<Response<Body>, String> {
|
|||||||
if subscribed.is_empty() {
|
if subscribed.is_empty() {
|
||||||
"popular".to_string()
|
"popular".to_string()
|
||||||
} else {
|
} else {
|
||||||
subscribed.to_owned()
|
subscribed.clone()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
front_page.to_owned()
|
front_page.clone()
|
||||||
});
|
});
|
||||||
let quarantined = can_access_quarantine(&req, &sub) || root;
|
let quarantined = can_access_quarantine(&req, &sub) || root;
|
||||||
|
|
||||||
@ -133,20 +134,20 @@ pub fn quarantine(req: Request<Body>, sub: String) -> Result<Response<Body>, Str
|
|||||||
pub async fn add_quarantine_exception(req: Request<Body>) -> Result<Response<Body>, String> {
|
pub async fn add_quarantine_exception(req: Request<Body>) -> Result<Response<Body>, String> {
|
||||||
let subreddit = req.param("sub").ok_or("Invalid URL")?;
|
let subreddit = req.param("sub").ok_or("Invalid URL")?;
|
||||||
let redir = param(&format!("?{}", req.uri().query().unwrap_or_default()), "redir").ok_or("Invalid URL")?;
|
let redir = param(&format!("?{}", req.uri().query().unwrap_or_default()), "redir").ok_or("Invalid URL")?;
|
||||||
let mut res = redirect(redir);
|
let mut response = redirect(redir);
|
||||||
res.insert_cookie(
|
response.insert_cookie(
|
||||||
Cookie::build(&format!("allow_quaran_{}", subreddit.to_lowercase()), "true")
|
Cookie::build(&format!("allow_quaran_{}", subreddit.to_lowercase()), "true")
|
||||||
.path("/")
|
.path("/")
|
||||||
.http_only(true)
|
.http_only(true)
|
||||||
.expires(cookie::Expiration::Session)
|
.expires(cookie::Expiration::Session)
|
||||||
.finish(),
|
.finish(),
|
||||||
);
|
);
|
||||||
Ok(res)
|
Ok(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn can_access_quarantine(req: &Request<Body>, sub: &str) -> bool {
|
pub fn can_access_quarantine(req: &Request<Body>, sub: &str) -> bool {
|
||||||
// Determine if the subreddit can be accessed
|
// Determine if the subreddit can be accessed
|
||||||
setting(&req, &format!("allow_quaran_{}", sub.to_lowercase())).parse().unwrap_or_default()
|
setting(req, &format!("allow_quaran_{}", sub.to_lowercase())).parse().unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sub or unsub by setting subscription cookie using response "Set-Cookie" header
|
// Sub or unsub by setting subscription cookie using response "Set-Cookie" header
|
||||||
@ -196,7 +197,7 @@ pub async fn subscriptions(req: Request<Body>) -> Result<Response<Body>, String>
|
|||||||
// Add each sub name to the subscribed list
|
// Add each sub name to the subscribed list
|
||||||
sub_list.push(part.to_owned());
|
sub_list.push(part.to_owned());
|
||||||
// Reorder sub names alphabettically
|
// Reorder sub names alphabettically
|
||||||
sub_list.sort_by_key(|a| a.to_lowercase())
|
sub_list.sort_by_key(|a| a.to_lowercase());
|
||||||
} else if action.contains(&"unsubscribe".to_string()) {
|
} else if action.contains(&"unsubscribe".to_string()) {
|
||||||
// Remove sub name from subscribed list
|
// Remove sub name from subscribed list
|
||||||
sub_list.retain(|s| s.to_lowercase() != part.to_lowercase());
|
sub_list.retain(|s| s.to_lowercase() != part.to_lowercase());
|
||||||
@ -211,13 +212,13 @@ pub async fn subscriptions(req: Request<Body>) -> Result<Response<Body>, String>
|
|||||||
format!("/r/{}", sub)
|
format!("/r/{}", sub)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut res = redirect(path);
|
let mut response = redirect(path);
|
||||||
|
|
||||||
// Delete cookie if empty, else set
|
// Delete cookie if empty, else set
|
||||||
if sub_list.is_empty() {
|
if sub_list.is_empty() {
|
||||||
res.remove_cookie("subscriptions".to_string());
|
response.remove_cookie("subscriptions".to_string());
|
||||||
} else {
|
} else {
|
||||||
res.insert_cookie(
|
response.insert_cookie(
|
||||||
Cookie::build("subscriptions", sub_list.join("+"))
|
Cookie::build("subscriptions", sub_list.join("+"))
|
||||||
.path("/")
|
.path("/")
|
||||||
.http_only(true)
|
.http_only(true)
|
||||||
@ -226,7 +227,7 @@ pub async fn subscriptions(req: Request<Body>) -> Result<Response<Body>, String>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(res)
|
Ok(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn wiki(req: Request<Body>) -> Result<Response<Body>, String> {
|
pub async fn wiki(req: Request<Body>) -> Result<Response<Body>, String> {
|
||||||
@ -239,6 +240,7 @@ pub async fn wiki(req: Request<Body>) -> Result<Response<Body>, String> {
|
|||||||
|
|
||||||
let page = req.param("page").unwrap_or_else(|| "index".to_string());
|
let page = req.param("page").unwrap_or_else(|| "index".to_string());
|
||||||
let path: String = format!("/r/{}/wiki/{}.json?raw_json=1", sub, page);
|
let path: String = format!("/r/{}/wiki/{}.json?raw_json=1", sub, page);
|
||||||
|
let url = req.uri().to_string();
|
||||||
|
|
||||||
match json(path, quarantined).await {
|
match json(path, quarantined).await {
|
||||||
Ok(response) => template(WikiTemplate {
|
Ok(response) => template(WikiTemplate {
|
||||||
@ -246,6 +248,7 @@ pub async fn wiki(req: Request<Body>) -> Result<Response<Body>, String> {
|
|||||||
wiki: rewrite_urls(response["data"]["content_html"].as_str().unwrap_or("<h3>Wiki not found</h3>")),
|
wiki: rewrite_urls(response["data"]["content_html"].as_str().unwrap_or("<h3>Wiki not found</h3>")),
|
||||||
page,
|
page,
|
||||||
prefs: Preferences::new(req),
|
prefs: Preferences::new(req),
|
||||||
|
url,
|
||||||
}),
|
}),
|
||||||
Err(msg) => {
|
Err(msg) => {
|
||||||
if msg == "quarantined" {
|
if msg == "quarantined" {
|
||||||
@ -260,6 +263,7 @@ pub async fn wiki(req: Request<Body>) -> Result<Response<Body>, String> {
|
|||||||
pub async fn sidebar(req: Request<Body>) -> Result<Response<Body>, String> {
|
pub async fn sidebar(req: Request<Body>) -> Result<Response<Body>, String> {
|
||||||
let sub = req.param("sub").unwrap_or_else(|| "reddit.com".to_string());
|
let sub = req.param("sub").unwrap_or_else(|| "reddit.com".to_string());
|
||||||
let quarantined = can_access_quarantine(&req, &sub);
|
let quarantined = can_access_quarantine(&req, &sub);
|
||||||
|
|
||||||
// Handle random subreddits
|
// Handle random subreddits
|
||||||
if let Ok(random) = catch_random(&sub, "/about/sidebar").await {
|
if let Ok(random) = catch_random(&sub, "/about/sidebar").await {
|
||||||
return Ok(random);
|
return Ok(random);
|
||||||
@ -267,19 +271,22 @@ pub async fn sidebar(req: Request<Body>) -> Result<Response<Body>, String> {
|
|||||||
|
|
||||||
// Build the Reddit JSON API url
|
// Build the Reddit JSON API url
|
||||||
let path: String = format!("/r/{}/about.json?raw_json=1", sub);
|
let path: String = format!("/r/{}/about.json?raw_json=1", sub);
|
||||||
|
let url = req.uri().to_string();
|
||||||
|
|
||||||
// Send a request to the url
|
// Send a request to the url
|
||||||
match json(path, quarantined).await {
|
match json(path, quarantined).await {
|
||||||
// If success, receive JSON in response
|
// If success, receive JSON in response
|
||||||
Ok(response) => template(WikiTemplate {
|
Ok(response) => template(WikiTemplate {
|
||||||
wiki: format!(
|
wiki: rewrite_urls(&val(&response, "description_html").replace("\\", "")),
|
||||||
"{}<hr><h1>Moderators</h1><br><ul>{}</ul>",
|
// wiki: format!(
|
||||||
rewrite_urls(&val(&response, "description_html").replace("\\", "")),
|
// "{}<hr><h1>Moderators</h1><br><ul>{}</ul>",
|
||||||
moderators(&sub, quarantined).await?.join(""),
|
// rewrite_urls(&val(&response, "description_html").replace("\\", "")),
|
||||||
),
|
// moderators(&sub, quarantined).await.unwrap_or(vec!["Could not fetch moderators".to_string()]).join(""),
|
||||||
|
// ),
|
||||||
sub,
|
sub,
|
||||||
page: "Sidebar".to_string(),
|
page: "Sidebar".to_string(),
|
||||||
prefs: Preferences::new(req),
|
prefs: Preferences::new(req),
|
||||||
|
url,
|
||||||
}),
|
}),
|
||||||
Err(msg) => {
|
Err(msg) => {
|
||||||
if msg == "quarantined" {
|
if msg == "quarantined" {
|
||||||
@ -291,40 +298,39 @@ pub async fn sidebar(req: Request<Body>) -> Result<Response<Body>, String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn moderators(sub: &str, quarantined: bool) -> Result<Vec<String>, String> {
|
// pub async fn moderators(sub: &str, quarantined: bool) -> Result<Vec<String>, String> {
|
||||||
// Retrieve and format the html for the moderators list
|
// // Retrieve and format the html for the moderators list
|
||||||
Ok(
|
// Ok(
|
||||||
moderators_list(sub, quarantined)
|
// moderators_list(sub, quarantined)
|
||||||
.await?
|
// .await?
|
||||||
.iter()
|
// .iter()
|
||||||
.map(|m| format!("<li><a style=\"color: var(--accent)\" href=\"/u/{name}\">{name}</a></li>", name = m))
|
// .map(|m| format!("<li><a style=\"color: var(--accent)\" href=\"/u/{name}\">{name}</a></li>", name = m))
|
||||||
.collect(),
|
// .collect(),
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
|
|
||||||
async fn moderators_list(sub: &str, quarantined: bool) -> Result<Vec<String>, String> {
|
// async fn moderators_list(sub: &str, quarantined: bool) -> Result<Vec<String>, String> {
|
||||||
// Build the moderator list URL
|
// // Build the moderator list URL
|
||||||
let path: String = format!("/r/{}/about/moderators.json?raw_json=1", sub);
|
// let path: String = format!("/r/{}/about/moderators.json?raw_json=1", sub);
|
||||||
|
|
||||||
// Retrieve response
|
// // Retrieve response
|
||||||
let response = json(path, quarantined).await?["data"]["children"].clone();
|
// json(path, quarantined).await.map(|response| {
|
||||||
Ok(
|
// // Traverse json tree and format into list of strings
|
||||||
// Traverse json tree and format into list of strings
|
// response["data"]["children"]
|
||||||
response
|
// .as_array()
|
||||||
.as_array()
|
// .unwrap_or(&Vec::new())
|
||||||
.unwrap_or(&Vec::new())
|
// .iter()
|
||||||
.iter()
|
// .filter_map(|moderator| {
|
||||||
.filter_map(|moderator| {
|
// let name = moderator["name"].as_str().unwrap_or_default();
|
||||||
let name = moderator["name"].as_str().unwrap_or_default();
|
// if name.is_empty() {
|
||||||
if name.is_empty() {
|
// None
|
||||||
None
|
// } else {
|
||||||
} else {
|
// Some(name.to_string())
|
||||||
Some(name.to_string())
|
// }
|
||||||
}
|
// })
|
||||||
})
|
// .collect::<Vec<_>>()
|
||||||
.collect::<Vec<_>>(),
|
// })
|
||||||
)
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
// SUBREDDIT
|
// SUBREDDIT
|
||||||
async fn subreddit(sub: &str, quarantined: bool) -> Result<Subreddit, String> {
|
async fn subreddit(sub: &str, quarantined: bool) -> Result<Subreddit, String> {
|
||||||
@ -332,9 +338,8 @@ async fn subreddit(sub: &str, quarantined: bool) -> Result<Subreddit, String> {
|
|||||||
let path: String = format!("/r/{}/about.json?raw_json=1", sub);
|
let path: String = format!("/r/{}/about.json?raw_json=1", sub);
|
||||||
|
|
||||||
// Send a request to the url
|
// Send a request to the url
|
||||||
match json(path, quarantined).await {
|
let res = json(path, quarantined).await?;
|
||||||
// If success, receive JSON in response
|
|
||||||
Ok(res) => {
|
|
||||||
// Metadata regarding the subreddit
|
// Metadata regarding the subreddit
|
||||||
let members: i64 = res["data"]["subscribers"].as_u64().unwrap_or_default() as i64;
|
let members: i64 = res["data"]["subscribers"].as_u64().unwrap_or_default() as i64;
|
||||||
let active: i64 = res["data"]["accounts_active"].as_u64().unwrap_or_default() as i64;
|
let active: i64 = res["data"]["accounts_active"].as_u64().unwrap_or_default() as i64;
|
||||||
@ -343,21 +348,15 @@ async fn subreddit(sub: &str, quarantined: bool) -> Result<Subreddit, String> {
|
|||||||
let community_icon: &str = res["data"]["community_icon"].as_str().unwrap_or_default();
|
let community_icon: &str = res["data"]["community_icon"].as_str().unwrap_or_default();
|
||||||
let icon = if community_icon.is_empty() { val(&res, "icon_img") } else { community_icon.to_string() };
|
let icon = if community_icon.is_empty() { val(&res, "icon_img") } else { community_icon.to_string() };
|
||||||
|
|
||||||
let sub = Subreddit {
|
Ok(Subreddit {
|
||||||
name: esc!(&res, "display_name"),
|
name: esc!(&res, "display_name"),
|
||||||
title: esc!(&res, "title"),
|
title: esc!(&res, "title"),
|
||||||
description: esc!(&res, "public_description"),
|
description: esc!(&res, "public_description"),
|
||||||
info: rewrite_urls(&val(&res, "description_html").replace("\\", "")),
|
info: rewrite_urls(&val(&res, "description_html").replace("\\", "")),
|
||||||
moderators: moderators_list(sub, quarantined).await?,
|
// moderators: moderators_list(sub, quarantined).await.unwrap_or_default(),
|
||||||
icon: format_url(&icon),
|
icon: format_url(&icon),
|
||||||
members: format_num(members),
|
members: format_num(members),
|
||||||
active: format_num(active),
|
active: format_num(active),
|
||||||
wiki: res["data"]["wiki_enabled"].as_bool().unwrap_or_default(),
|
wiki: res["data"]["wiki_enabled"].as_bool().unwrap_or_default(),
|
||||||
};
|
})
|
||||||
|
|
||||||
Ok(sub)
|
|
||||||
}
|
|
||||||
// If the Reddit API returns an error, exit this function
|
|
||||||
Err(msg) => return Err(msg),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
13
src/user.rs
13
src/user.rs
@ -61,9 +61,7 @@ async fn user(name: &str) -> Result<User, String> {
|
|||||||
let path: String = format!("/user/{}/about.json?raw_json=1", name);
|
let path: String = format!("/user/{}/about.json?raw_json=1", name);
|
||||||
|
|
||||||
// Send a request to the url
|
// Send a request to the url
|
||||||
match json(path, false).await {
|
json(path, false).await.map(|res| {
|
||||||
// If success, receive JSON in response
|
|
||||||
Ok(res) => {
|
|
||||||
// Grab creation date as unix timestamp
|
// Grab creation date as unix timestamp
|
||||||
let created: i64 = res["data"]["created"].as_f64().unwrap_or(0.0).round() as i64;
|
let created: i64 = res["data"]["created"].as_f64().unwrap_or(0.0).round() as i64;
|
||||||
|
|
||||||
@ -71,17 +69,14 @@ async fn user(name: &str) -> Result<User, String> {
|
|||||||
let about = |item| res["data"]["subreddit"][item].as_str().unwrap_or_default().to_string();
|
let about = |item| res["data"]["subreddit"][item].as_str().unwrap_or_default().to_string();
|
||||||
|
|
||||||
// Parse the JSON output into a User struct
|
// Parse the JSON output into a User struct
|
||||||
Ok(User {
|
User {
|
||||||
name: name.to_string(),
|
name: res["data"]["name"].as_str().unwrap_or(name).to_owned(),
|
||||||
title: esc!(about("title")),
|
title: esc!(about("title")),
|
||||||
icon: format_url(&about("icon_img")),
|
icon: format_url(&about("icon_img")),
|
||||||
karma: res["data"]["total_karma"].as_i64().unwrap_or(0),
|
karma: res["data"]["total_karma"].as_i64().unwrap_or(0),
|
||||||
created: OffsetDateTime::from_unix_timestamp(created).format("%b %d '%y"),
|
created: OffsetDateTime::from_unix_timestamp(created).format("%b %d '%y"),
|
||||||
banner: esc!(about("banner_img")),
|
banner: esc!(about("banner_img")),
|
||||||
description: about("public_description"),
|
description: about("public_description"),
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
|
||||||
// If the Reddit API returns an error, exit this function
|
|
||||||
Err(msg) => return Err(msg),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
60
src/utils.rs
60
src/utils.rs
@ -39,7 +39,7 @@ impl FlairPart {
|
|||||||
Self {
|
Self {
|
||||||
flair_part_type: value("e").to_string(),
|
flair_part_type: value("e").to_string(),
|
||||||
value: match value("e") {
|
value: match value("e") {
|
||||||
"text" => value("t").to_string(),
|
"text" => esc!(value("t")),
|
||||||
"emoji" => format_url(value("u")),
|
"emoji" => format_url(value("u")),
|
||||||
_ => String::new(),
|
_ => String::new(),
|
||||||
},
|
},
|
||||||
@ -52,7 +52,7 @@ impl FlairPart {
|
|||||||
"text" => match text_flair {
|
"text" => match text_flair {
|
||||||
Some(text) => vec![Self {
|
Some(text) => vec![Self {
|
||||||
flair_part_type: "text".to_string(),
|
flair_part_type: "text".to_string(),
|
||||||
value: text.to_string(),
|
value: esc!(text),
|
||||||
}],
|
}],
|
||||||
None => Vec::new(),
|
None => Vec::new(),
|
||||||
},
|
},
|
||||||
@ -249,11 +249,11 @@ impl Post {
|
|||||||
let title = esc!(post, "title");
|
let title = esc!(post, "title");
|
||||||
|
|
||||||
// Determine the type of media along with the media URL
|
// Determine the type of media along with the media URL
|
||||||
let (post_type, media, gallery) = Media::parse(&data).await;
|
let (post_type, media, gallery) = Media::parse(data).await;
|
||||||
|
|
||||||
posts.push(Self {
|
posts.push(Self {
|
||||||
id: val(post, "id"),
|
id: val(post, "id"),
|
||||||
title: esc!(if title.is_empty() { fallback_title.to_owned() } else { title }),
|
title: esc!(if title.is_empty() { fallback_title.clone() } else { title }),
|
||||||
community: val(post, "subreddit"),
|
community: val(post, "subreddit"),
|
||||||
body: rewrite_urls(&val(post, "body_html")),
|
body: rewrite_urls(&val(post, "body_html")),
|
||||||
author: Author {
|
author: Author {
|
||||||
@ -341,6 +341,7 @@ pub struct Comment {
|
|||||||
pub struct ErrorTemplate {
|
pub struct ErrorTemplate {
|
||||||
pub msg: String,
|
pub msg: String,
|
||||||
pub prefs: Preferences,
|
pub prefs: Preferences,
|
||||||
|
pub url: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
@ -362,7 +363,7 @@ pub struct Subreddit {
|
|||||||
pub title: String,
|
pub title: String,
|
||||||
pub description: String,
|
pub description: String,
|
||||||
pub info: String,
|
pub info: String,
|
||||||
pub moderators: Vec<String>,
|
// pub moderators: Vec<String>,
|
||||||
pub icon: String,
|
pub icon: String,
|
||||||
pub members: (String, String),
|
pub members: (String, String),
|
||||||
pub active: (String, String),
|
pub active: (String, String),
|
||||||
@ -388,6 +389,7 @@ pub struct Preferences {
|
|||||||
pub show_nsfw: String,
|
pub show_nsfw: String,
|
||||||
pub hide_hls_notification: String,
|
pub hide_hls_notification: String,
|
||||||
pub use_hls: String,
|
pub use_hls: String,
|
||||||
|
pub autoplay_videos: String,
|
||||||
pub comment_sort: String,
|
pub comment_sort: String,
|
||||||
pub post_sort: String,
|
pub post_sort: String,
|
||||||
pub subscriptions: Vec<String>,
|
pub subscriptions: Vec<String>,
|
||||||
@ -404,6 +406,7 @@ impl Preferences {
|
|||||||
show_nsfw: setting(&req, "show_nsfw"),
|
show_nsfw: setting(&req, "show_nsfw"),
|
||||||
use_hls: setting(&req, "use_hls"),
|
use_hls: setting(&req, "use_hls"),
|
||||||
hide_hls_notification: setting(&req, "hide_hls_notification"),
|
hide_hls_notification: setting(&req, "hide_hls_notification"),
|
||||||
|
autoplay_videos: setting(&req, "autoplay_videos"),
|
||||||
comment_sort: setting(&req, "comment_sort"),
|
comment_sort: setting(&req, "comment_sort"),
|
||||||
post_sort: setting(&req, "post_sort"),
|
post_sort: setting(&req, "post_sort"),
|
||||||
subscriptions: setting(&req, "subscriptions").split('+').map(String::from).filter(|s| !s.is_empty()).collect(),
|
subscriptions: setting(&req, "subscriptions").split('+').map(String::from).filter(|s| !s.is_empty()).collect(),
|
||||||
@ -424,7 +427,7 @@ pub fn param(path: &str, value: &str) -> Option<String> {
|
|||||||
.into_owned()
|
.into_owned()
|
||||||
.collect::<HashMap<_, _>>()
|
.collect::<HashMap<_, _>>()
|
||||||
.get(value)?
|
.get(value)?
|
||||||
.to_owned(),
|
.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -463,21 +466,17 @@ pub fn format_url(url: &str) -> String {
|
|||||||
if url.is_empty() || url == "self" || url == "default" || url == "nsfw" || url == "spoiler" {
|
if url.is_empty() || url == "self" || url == "default" || url == "nsfw" || url == "spoiler" {
|
||||||
String::new()
|
String::new()
|
||||||
} else {
|
} else {
|
||||||
match Url::parse(url) {
|
Url::parse(url).map_or(String::new(), |parsed| {
|
||||||
Ok(parsed) => {
|
|
||||||
let domain = parsed.domain().unwrap_or_default();
|
let domain = parsed.domain().unwrap_or_default();
|
||||||
|
|
||||||
let capture = |regex: &str, format: &str, segments: i16| {
|
let capture = |regex: &str, format: &str, segments: i16| {
|
||||||
Regex::new(regex)
|
Regex::new(regex).map_or(String::new(), |re| {
|
||||||
.map(|re| match re.captures(url) {
|
re.captures(url).map_or(String::new(), |caps| match segments {
|
||||||
Some(caps) => match segments {
|
|
||||||
1 => [format, &caps[1]].join(""),
|
1 => [format, &caps[1]].join(""),
|
||||||
2 => [format, &caps[1], "/", &caps[2]].join(""),
|
2 => [format, &caps[1], "/", &caps[2]].join(""),
|
||||||
_ => String::new(),
|
_ => String::new(),
|
||||||
},
|
|
||||||
None => String::new(),
|
|
||||||
})
|
})
|
||||||
.unwrap_or_default()
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
macro_rules! chain {
|
macro_rules! chain {
|
||||||
@ -516,30 +515,23 @@ pub fn format_url(url: &str) -> String {
|
|||||||
"www.redditstatic.com" => capture(r"https://www\.redditstatic\.com/(.*)", "/static/", 1),
|
"www.redditstatic.com" => capture(r"https://www\.redditstatic\.com/(.*)", "/static/", 1),
|
||||||
_ => String::new(),
|
_ => String::new(),
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
Err(_) => String::new(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rewrite Reddit links to Libreddit in body of text
|
// Rewrite Reddit links to Libreddit in body of text
|
||||||
pub fn rewrite_urls(input_text: &str) -> String {
|
pub fn rewrite_urls(input_text: &str) -> String {
|
||||||
let text1 = match Regex::new(r#"href="(https|http|)://(www.|old.|np.|amp.|)(reddit).(com)/"#) {
|
let text1 =
|
||||||
Ok(re) => re.replace_all(input_text, r#"href="/"#).to_string(),
|
Regex::new(r#"href="(https|http|)://(www\.|old\.|np\.|amp\.|)(reddit\.com|redd\.it)/"#).map_or(String::new(), |re| re.replace_all(input_text, r#"href="/"#).to_string());
|
||||||
Err(_) => String::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Rewrite external media previews to Libreddit
|
// Rewrite external media previews to Libreddit
|
||||||
match Regex::new(r"https://external-preview\.redd\.it(.*)[^?]") {
|
Regex::new(r"https://external-preview\.redd\.it(.*)[^?]").map_or(String::new(), |re| {
|
||||||
Ok(re) => {
|
|
||||||
if re.is_match(&text1) {
|
if re.is_match(&text1) {
|
||||||
re.replace_all(&text1, format_url(re.find(&text1).map(|x| x.as_str()).unwrap_or_default())).to_string()
|
re.replace_all(&text1, format_url(re.find(&text1).map(|x| x.as_str()).unwrap_or_default())).to_string()
|
||||||
} else {
|
} else {
|
||||||
text1
|
text1
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
Err(_) => String::new(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append `m` and `k` for millions and thousands respectively
|
// Append `m` and `k` for millions and thousands respectively
|
||||||
@ -580,27 +572,17 @@ pub fn val(j: &Value, k: &str) -> String {
|
|||||||
j["data"][k].as_str().unwrap_or_default().to_string()
|
j["data"][k].as_str().unwrap_or_default().to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Escape < and > to accurately render HTML
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! esc {
|
macro_rules! esc {
|
||||||
($f:expr) => {
|
($f:expr) => {
|
||||||
$f.replace('<', "<").replace('>', ">")
|
$f.replace('&', "&").replace('<', "<").replace('>', ">")
|
||||||
};
|
};
|
||||||
($j:expr, $k:expr) => {
|
($j:expr, $k:expr) => {
|
||||||
$j["data"][$k].as_str().unwrap_or_default().to_string().replace('<', "<").replace('>', ">")
|
$j["data"][$k].as_str().unwrap_or_default().to_string().replace('<', "<").replace('>', ">")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Escape < and > to accurately render HTML
|
|
||||||
// pub fn esc(j: &Value, k: &str) -> String {
|
|
||||||
// val(j,k)
|
|
||||||
// // .replace('&', "&")
|
|
||||||
// .replace('<', "<")
|
|
||||||
// .replace('>', ">")
|
|
||||||
// // .replace('"', """)
|
|
||||||
// // .replace('\'', "'")
|
|
||||||
// // .replace('/', "/")
|
|
||||||
// }
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// NETWORKING
|
// NETWORKING
|
||||||
//
|
//
|
||||||
@ -625,9 +607,11 @@ pub fn redirect(path: String) -> Response<Body> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn error(req: Request<Body>, msg: String) -> Result<Response<Body>, String> {
|
pub async fn error(req: Request<Body>, msg: String) -> Result<Response<Body>, String> {
|
||||||
|
let url = req.uri().to_string();
|
||||||
let body = ErrorTemplate {
|
let body = ErrorTemplate {
|
||||||
msg,
|
msg,
|
||||||
prefs: Preferences::new(req),
|
prefs: Preferences::new(req),
|
||||||
|
url,
|
||||||
}
|
}
|
||||||
.render()
|
.render()
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
--post: #161616;
|
--post: #161616;
|
||||||
--panel-border: 1px solid #333;
|
--panel-border: 1px solid #333;
|
||||||
--highlighted: #333;
|
--highlighted: #333;
|
||||||
|
--visited: #aaa;
|
||||||
--shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
|
--shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,6 +40,7 @@
|
|||||||
--post: #eee;
|
--post: #eee;
|
||||||
--panel-border: 1px solid #ccc;
|
--panel-border: 1px solid #ccc;
|
||||||
--highlighted: white;
|
--highlighted: white;
|
||||||
|
--visited: #555;
|
||||||
--shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
--shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -54,6 +56,7 @@
|
|||||||
--post: #eee;
|
--post: #eee;
|
||||||
--panel-border: 1px solid #ccc;
|
--panel-border: 1px solid #ccc;
|
||||||
--highlighted: white;
|
--highlighted: white;
|
||||||
|
--visited: #555;
|
||||||
--shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
--shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,6 +71,7 @@
|
|||||||
--post: black;
|
--post: black;
|
||||||
--panel-border: 2px solid #0f0f0f;
|
--panel-border: 2px solid #0f0f0f;
|
||||||
--highlighted: #0f0f0f;
|
--highlighted: #0f0f0f;
|
||||||
|
--visited: #aaa;
|
||||||
--shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
--shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,10 +82,11 @@
|
|||||||
--text: #f8f8f2;
|
--text: #f8f8f2;
|
||||||
--foreground: #3d4051;
|
--foreground: #3d4051;
|
||||||
--background: #282a36;
|
--background: #282a36;
|
||||||
--outside: #44475a;
|
--outside: #393c4d;
|
||||||
--post: #44475a;
|
--post: #333544;
|
||||||
--panel-border: 2px solid #44475a;
|
--panel-border: 2px solid #44475a;
|
||||||
--highlighted: #4e5267;
|
--highlighted: #4e5267;
|
||||||
|
--visited: #969692;
|
||||||
--shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
--shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,6 +101,7 @@
|
|||||||
--post: #434c5e;
|
--post: #434c5e;
|
||||||
--panel-border: 2px solid #4c566a;
|
--panel-border: 2px solid #4c566a;
|
||||||
--highlighted: #3b4252;
|
--highlighted: #3b4252;
|
||||||
|
--visited: #a3a5aa;
|
||||||
--shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
--shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,6 +116,7 @@
|
|||||||
--post: #3e3647;
|
--post: #3e3647;
|
||||||
--panel-border: 2px solid #2f2738;
|
--panel-border: 2px solid #2f2738;
|
||||||
--highlighted: #302a36;
|
--highlighted: #302a36;
|
||||||
|
--visited: #91889b;
|
||||||
--shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
--shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,6 +131,7 @@
|
|||||||
--post: #181c3a;
|
--post: #181c3a;
|
||||||
--panel-border: 1px solid #1F2347;
|
--panel-border: 1px solid #1F2347;
|
||||||
--highlighted: #1F2347;
|
--highlighted: #1F2347;
|
||||||
|
--visited: #aaa;
|
||||||
--shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
|
--shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,6 +146,7 @@
|
|||||||
--post: #1b2936;
|
--post: #1b2936;
|
||||||
--panel-border: 0px solid black;
|
--panel-border: 0px solid black;
|
||||||
--highlighted: #234;
|
--highlighted: #234;
|
||||||
|
--visited: #aaa;
|
||||||
--shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
|
--shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +165,7 @@ html, body, div, h1, h2, h3, h4, h5, h6, ul, ol, dl, li, dt, dd, p, blockquote,
|
|||||||
pre, form, fieldset, table, th, td, select, input {
|
pre, form, fieldset, table, th, td, select, input {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
font-family: "Inter";
|
font-family: "Inter", sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@ -218,10 +227,15 @@ nav #libreddit {
|
|||||||
|
|
||||||
#settings_link {
|
#settings_link {
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#reddit_link {
|
||||||
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
#code {
|
#code {
|
||||||
margin-left: 5px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
main {
|
main {
|
||||||
@ -713,6 +727,10 @@ a.search_subreddit:hover {
|
|||||||
grid-area: post_title;
|
grid-area: post_title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.post:not(.highlighted) .post_title a:visited {
|
||||||
|
color: var(--visited);
|
||||||
|
}
|
||||||
|
|
||||||
.post_notification {
|
.post_notification {
|
||||||
grid-area: post_notification;
|
grid-area: post_notification;
|
||||||
margin: 5px 15px;
|
margin: 5px 15px;
|
||||||
@ -968,6 +986,7 @@ a.search_subreddit:hover {
|
|||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
padding: 5px 5px;
|
padding: 5px 5px;
|
||||||
margin: 5px 0;
|
margin: 5px 0;
|
||||||
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment_body.highlighted {
|
.comment_body.highlighted {
|
||||||
@ -1013,6 +1032,10 @@ a.search_subreddit:hover {
|
|||||||
background: var(--foreground);
|
background: var(--foreground);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
summary.comment_data {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.moderator, .admin { opacity: 1; }
|
.moderator, .admin { opacity: 1; }
|
||||||
.op, .moderator, .admin { font-weight: bold; }
|
.op, .moderator, .admin { font-weight: bold; }
|
||||||
|
|
||||||
@ -1195,7 +1218,7 @@ input[type="submit"] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.md code {
|
.md code {
|
||||||
font-family: monospace;
|
font-family: monospace, sans-serif;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +35,12 @@
|
|||||||
</div>
|
</div>
|
||||||
{% block search %}{% endblock %}
|
{% block search %}{% endblock %}
|
||||||
<div id="links">
|
<div id="links">
|
||||||
|
<a id="reddit_link" href="https://www.reddit.com{{ url }}">
|
||||||
|
<span>reddit</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">
|
||||||
|
<path d="M23 12.0737C23 10.7308 21.9222 9.64226 20.5926 9.64226C19.9435 9.64226 19.3557 9.90274 18.923 10.3244C17.2772 9.12492 15.0099 8.35046 12.4849 8.26135L13.5814 3.05002L17.1643 3.8195C17.2081 4.73947 17.9539 5.47368 18.8757 5.47368C19.8254 5.47368 20.5951 4.69626 20.5951 3.73684C20.5951 2.77769 19.8254 2 18.8758 2C18.2001 2 17.6214 2.39712 17.3404 2.96952L13.3393 2.11066C13.2279 2.08679 13.1116 2.10858 13.016 2.17125C12.9204 2.23393 12.8533 2.33235 12.8295 2.44491L11.6051 8.25987C9.04278 8.33175 6.73904 9.10729 5.07224 10.3201C4.63988 9.90099 4.05398 9.64226 3.40757 9.64226C2.0781 9.64226 1 10.7308 1 12.0737C1 13.0618 1.58457 13.9105 2.4225 14.2909C2.38466 14.5342 2.36545 14.78 2.36505 15.0263C2.36505 18.7673 6.67626 21.8 11.9945 21.8C17.3131 21.8 21.6243 18.7673 21.6243 15.0263C21.6243 14.7794 21.6043 14.5359 21.5678 14.2957C22.4109 13.9175 23 13.0657 23 12.0737Z"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
<a id="settings_link" href="/settings">
|
<a id="settings_link" href="/settings">
|
||||||
<span>settings</span>
|
<span>settings</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">
|
<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">
|
||||||
|
@ -55,6 +55,7 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- POST MEDIA -->
|
<!-- POST MEDIA -->
|
||||||
|
<!-- post_type: {{ post.post_type }} -->
|
||||||
{% if post.post_type == "image" %}
|
{% if post.post_type == "image" %}
|
||||||
<a href="{{ post.media.url }}" class="post_media_image" >
|
<a href="{{ post.media.url }}" class="post_media_image" >
|
||||||
<svg
|
<svg
|
||||||
@ -63,27 +64,27 @@
|
|||||||
xmlns="http://www.w3.org/2000/svg">
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
<image width="100%" height="100%" href="{{ post.media.url }}"/>
|
<image width="100%" height="100%" href="{{ post.media.url }}"/>
|
||||||
<desc>
|
<desc>
|
||||||
<img alt="Post image" src="{{ post.media.url }}"/>
|
<img loading="lazy" alt="Post image" src="{{ post.media.url }}"/>
|
||||||
</desc>
|
</desc>
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
{% else if post.post_type == "video" || post.post_type == "gif" %}
|
{% else if post.post_type == "video" || post.post_type == "gif" %}
|
||||||
{% if prefs.use_hls == "on" && !post.media.alt_url.is_empty() %}
|
{% if prefs.use_hls == "on" && !post.media.alt_url.is_empty() %}
|
||||||
<script src="/hls.min.js"></script>
|
<script src="/hls.min.js"></script>
|
||||||
<video class="post_media_video short hls_autoplay" width="{{ post.media.width }}" height="{{ post.media.height }}" poster="{{ post.media.poster }}" controls preload="none">
|
<video class="post_media_video short hls_autoplay" width="{{ post.media.width }}" height="{{ post.media.height }}" poster="{{ post.media.poster }}" preload="none" controls {% if prefs.autoplay_videos == "on" %}autoplay{% endif %}>
|
||||||
<source src="{{ post.media.alt_url }}" type="application/vnd.apple.mpegurl" />
|
<source src="{{ post.media.alt_url }}" type="application/vnd.apple.mpegurl" />
|
||||||
<source src="{{ post.media.url }}" type="video/mp4" />
|
<source src="{{ post.media.url }}" type="video/mp4" />
|
||||||
</video>
|
</video>
|
||||||
<script src="/playHLSVideo.js"></script>
|
<script src="/playHLSVideo.js"></script>
|
||||||
{% else %}
|
{% else %}
|
||||||
<video class="post_media_video" src="{{ post.media.url }}" controls autoplay loop><a href={{ post.media.url }}>Video</a></video>
|
<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>
|
||||||
{% call utils::render_hls_notification(post.permalink[1..]) %}
|
{% call utils::render_hls_notification(post.permalink[1..]) %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% else if post.post_type == "gallery" %}
|
{% else if post.post_type == "gallery" %}
|
||||||
<div class="gallery">
|
<div class="gallery">
|
||||||
{% for image in post.gallery -%}
|
{% for image in post.gallery -%}
|
||||||
<figure>
|
<figure>
|
||||||
<a href="{{ image.url }}" ><img alt="Gallery image" src="{{ image.url }}"/></a>
|
<a href="{{ image.url }}" ><img loading="lazy" alt="Gallery image" src="{{ image.url }}"/></a>
|
||||||
<figcaption>
|
<figcaption>
|
||||||
<p>{{ image.caption }}</p>
|
<p>{{ image.caption }}</p>
|
||||||
{% if image.outbound_url.len() > 0 %}
|
{% if image.outbound_url.len() > 0 %}
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
<div id="search_subreddits">
|
<div id="search_subreddits">
|
||||||
{% for subreddit in subreddits %}
|
{% for subreddit in subreddits %}
|
||||||
<a href="{{ subreddit.url }}" class="search_subreddit">
|
<a href="{{ subreddit.url }}" class="search_subreddit">
|
||||||
<div class="search_subreddit_left">{% if subreddit.icon != "" %}<img src="{{ subreddit.icon }}" alt="r/{{ subreddit.name }} icon">{% endif %}</div>
|
<div class="search_subreddit_left">{% if subreddit.icon != "" %}<img loading="lazy" src="{{ subreddit.icon }}" alt="r/{{ subreddit.name }} icon">{% endif %}</div>
|
||||||
<div class="search_subreddit_right">
|
<div class="search_subreddit_right">
|
||||||
<p class="search_subreddit_header">
|
<p class="search_subreddit_header">
|
||||||
<span class="search_subreddit_name">{{ subreddit.name }}</span>
|
<span class="search_subreddit_name">{{ subreddit.name }}</span>
|
||||||
@ -68,6 +68,10 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
{% if prefs.use_hls == "on" %}
|
||||||
|
<script src="/hls.min.js"></script>
|
||||||
|
<script src="/playHLSVideo.js"></script>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
{% if params.before != "" %}
|
{% if params.before != "" %}
|
||||||
|
@ -54,6 +54,11 @@
|
|||||||
<input type="hidden" value="off" name="show_nsfw">
|
<input type="hidden" value="off" name="show_nsfw">
|
||||||
<input type="checkbox" name="show_nsfw" {% if prefs.show_nsfw == "on" %}checked{% endif %}>
|
<input type="checkbox" name="show_nsfw" {% if prefs.show_nsfw == "on" %}checked{% endif %}>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="autoplay_videos">
|
||||||
|
<label for="autoplay_videos">Autoplay videos</label>
|
||||||
|
<input type="hidden" value="off" name="autoplay_videos">
|
||||||
|
<input type="checkbox" name="autoplay_videos" {% if prefs.autoplay_videos == "on" %}checked{% endif %}>
|
||||||
|
</div>
|
||||||
<div id="use_hls">
|
<div id="use_hls">
|
||||||
<label for="use_hls">Use HLS for videos</label>
|
<label for="use_hls">Use HLS for videos</label>
|
||||||
<input type="hidden" value="off" name="use_hls">
|
<input type="hidden" value="off" name="use_hls">
|
||||||
|
@ -78,7 +78,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div id="sub_meta">
|
<div id="sub_meta">
|
||||||
<img id="sub_icon" src="{{ sub.icon }}" alt="Icon for r/{{ sub.name }}">
|
<img loading="lazy" id="sub_icon" src="{{ sub.icon }}" alt="Icon for r/{{ sub.name }}">
|
||||||
<p id="sub_title">{{ sub.title }}</p>
|
<p id="sub_title">{{ sub.title }}</p>
|
||||||
<p id="sub_name">r/{{ sub.name }}</p>
|
<p id="sub_name">r/{{ sub.name }}</p>
|
||||||
<p id="sub_description">{{ sub.description }}</p>
|
<p id="sub_description">{{ sub.description }}</p>
|
||||||
@ -105,14 +105,14 @@
|
|||||||
<summary id="sidebar_label">Sidebar</summary>
|
<summary id="sidebar_label">Sidebar</summary>
|
||||||
<div id="sidebar_contents">
|
<div id="sidebar_contents">
|
||||||
{{ sub.info }}
|
{{ sub.info }}
|
||||||
<hr>
|
{# <hr>
|
||||||
<h2>Moderators</h2>
|
<h2>Moderators</h2>
|
||||||
<br>
|
<br>
|
||||||
<ul>
|
<ul>
|
||||||
{% for moderator in sub.moderators %}
|
{% for moderator in sub.moderators %}
|
||||||
<li><a style="color: var(--accent)" href="/u/{{ moderator }}">{{ moderator }}</a></li>
|
<li><a style="color: var(--accent)" href="/u/{{ moderator }}">{{ moderator }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul> #}
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
</aside>
|
</aside>
|
||||||
|
@ -49,8 +49,11 @@
|
|||||||
</details>
|
</details>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
{% if prefs.use_hls == "on" %}
|
||||||
|
<script src="/hls.min.js"></script>
|
||||||
|
<script src="/playHLSVideo.js"></script>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
@ -65,7 +68,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<aside>
|
<aside>
|
||||||
<div class="panel" id="user">
|
<div class="panel" id="user">
|
||||||
<img id="user_icon" src="{{ user.icon }}" alt="User icon">
|
<img loading="lazy" id="user_icon" src="{{ user.icon }}" alt="User icon">
|
||||||
<p id="user_title">{{ user.title }}</p>
|
<p id="user_title">{{ user.title }}</p>
|
||||||
<p id="user_name">u/{{ user.name }}</p>
|
<p id="user_name">u/{{ user.name }}</p>
|
||||||
<div id="user_description">{{ user.description }}</div>
|
<div id="user_description">{{ user.description }}</div>
|
||||||
|
@ -94,21 +94,21 @@
|
|||||||
xmlns="http://www.w3.org/2000/svg">
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
<image width="100%" height="100%" href="{{ post.media.url }}"/>
|
<image width="100%" height="100%" href="{{ post.media.url }}"/>
|
||||||
<desc>
|
<desc>
|
||||||
<img alt="Post image" src="{{ post.media.url }}"/>
|
<img loading="lazy" alt="Post image" src="{{ post.media.url }}"/>
|
||||||
</desc>
|
</desc>
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
{% else if (prefs.layout.is_empty() || prefs.layout == "card") && post.post_type == "gif" %}
|
{% else if (prefs.layout.is_empty() || prefs.layout == "card") && post.post_type == "gif" %}
|
||||||
<video class="post_media_video short" src="{{ post.media.url }}" width="{{ post.media.width }}" height="{{ post.media.height }}" controls loop autoplay><a href={{ post.media.url }}>Video</a></video>
|
<video class="post_media_video short" src="{{ post.media.url }}" width="{{ post.media.width }}" height="{{ post.media.height }}" poster="{{ post.media.poster }}" preload="none" controls loop {% if prefs.autoplay_videos == "on" %}autoplay{% endif %}><a href={{ post.media.url }}>Video</a></video>
|
||||||
{% else if (prefs.layout.is_empty() || prefs.layout == "card") && post.post_type == "video" %}
|
{% 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() %}
|
||||||
<video class="post_media_video short" width="{{ post.media.width }}" height="{{ post.media.height }}" poster="{{ post.media.poster }}" controls preload="none">
|
<video class="post_media_video short" width="{{ post.media.width }}" height="{{ post.media.height }}" poster="{{ post.media.poster }}" controls preload="none" {% if prefs.autoplay_videos == "on" %}autoplay{% endif %}>
|
||||||
<source src="{{ post.media.alt_url }}" type="application/vnd.apple.mpegurl" />
|
<source src="{{ post.media.alt_url }}" type="application/vnd.apple.mpegurl" />
|
||||||
<source src="{{ post.media.url }}" type="video/mp4" />
|
<source src="{{ post.media.url }}" type="video/mp4" />
|
||||||
</video>
|
</video>
|
||||||
{% else %}
|
{% else %}
|
||||||
<video class="post_media_video short" src="{{ post.media.url }}" width="{{ post.media.width }}" height="{{ post.media.height }}" poster="{{ post.media.poster }}" preload="none" controls autoplay><a href={{ post.media.url }}>Video</a></video>
|
<video class="post_media_video short" src="{{ post.media.url }}" width="{{ post.media.width }}" height="{{ post.media.height }}" poster="{{ post.media.poster }}" preload="none" controls {% if prefs.autoplay_videos == "on" %}autoplay{% endif %}><a href={{ post.media.url }}>Video</a></video>
|
||||||
{% call render_hls_notification(format!("{}%23{}", &self.url[1..].replace("&", "%26"), post.id)) %}
|
{% call render_hls_notification(format!("{}%23{}", &self.url[1..].replace("&", "%26").replace("+", "%2B"), post.id)) %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% else if post.post_type != "self" %}
|
{% else if post.post_type != "self" %}
|
||||||
<a class="post_thumbnail {% if post.thumbnail.url.is_empty() %}no_thumbnail{% endif %}" href="{% if post.post_type == "link" %}{{ post.media.url }}{% else %}{{ post.permalink }}{% endif %}" rel="nofollow">
|
<a class="post_thumbnail {% if post.thumbnail.url.is_empty() %}no_thumbnail{% endif %}" href="{% if post.post_type == "link" %}{{ post.media.url }}{% else %}{{ post.permalink }}{% endif %}" rel="nofollow">
|
||||||
@ -121,7 +121,7 @@
|
|||||||
<svg width="{{ post.thumbnail.width }}px" height="{{ post.thumbnail.height }}px" xmlns="http://www.w3.org/2000/svg">
|
<svg width="{{ post.thumbnail.width }}px" height="{{ post.thumbnail.height }}px" xmlns="http://www.w3.org/2000/svg">
|
||||||
<image width="100%" height="100%" href="{{ post.thumbnail.url }}"/>
|
<image width="100%" height="100%" href="{{ post.thumbnail.url }}"/>
|
||||||
<desc>
|
<desc>
|
||||||
<img alt="Thumbnail" src="{{ post.thumbnail.url }}"/>
|
<img loading="lazy" alt="Thumbnail" src="{{ post.thumbnail.url }}"/>
|
||||||
</desc>
|
</desc>
|
||||||
</svg>
|
</svg>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
Reference in New Issue
Block a user